feat: bind config launcher records on evidence

A launcher record citing a config, option or feature file binds only
when the platform's code installs the file (installs), its launch code
was read for what replaces it (overrides), and the emulator's profile
shows where the shipped build loads it and reads each key
(config_reads, read at pin_build). Unproven records place no file and
hand no directory. verify, cross_reference and the platform page list
them apart, outside severity and --strict.
This commit is contained in:
Abdessamad Derraz committed 2026-11-11 11:03:47 +01:00
1 parent 4f5951e2fb
commit 3129eaf10c
14 files changed
+872 -28

No files matched your search

+97
View File
@@ -1047,6 +1047,11 @@ class ProfileReport:
new_files_elided: dict[str, int] = field(default_factory=dict)
new_hashes: list[dict] | None = None
detection_skipped: str | None = None
# config_reads refs written for a build a platform ships, each read at
# that build (pin_build) rather than at source_commit: {platform,
# revision, ref, status, detail}. A status other than BUILD_OK is review
# work.
build_refs: list[dict] = field(default_factory=list)
# Skips that say the profile cannot be checked as written: a repository
# that no longer answers, no pin to read, a death the forge contradicts.
@@ -1070,6 +1075,7 @@ class ProfileReport:
+ len(self.orphaned)
+ len(self.stale_prose or ())
+ len(self.moved_repos)
+ sum(1 for ref in self.build_refs if ref["status"] != "BUILD_OK")
)
@@ -1603,6 +1609,81 @@ def moved_repositories(
return moved
def shipped_build_holders(profile: dict) -> dict[int, dict]:
"""The source_ref holders of config_reads entries naming platforms, by id.
Such an entry describes the build those platforms ship, so its refs are
read at their pin_build revision, never at source_commit.
"""
found: dict[int, dict] = {}
for read in profile.get("config_reads") or []:
if not isinstance(read, dict) or not read.get("platforms"):
continue
found[id(read)] = read
for key in read.get("keys") or []:
if isinstance(key, dict):
found[id(key)] = read
return found
def build_revision(profile: dict, platform: str) -> str | None:
"""The emulator revision a platform's pin_build entry names, None when
its value is no revision (a URL, a package name)."""
for build in profile.get("pin_build") or []:
if build.get("platform") != platform:
continue
value = str(build.get("value") or "").strip()
return value if value and re.fullmatch(r"[\w.+-]+", value) else None
return None
def _check_build_refs(
profile: dict,
deferred: list[tuple[Citation, dict]],
views: list[RepoView],
fetch: Callable[[upstream.Repo, str, str], list[str] | None],
) -> list[dict]:
"""Each deferred config_reads ref read at the build of its platforms.
The file must exist at that revision and every cited line lie inside
it. The entry declares no value to anchor on, so this is the check a
ref past the end of its file fails (BUILD_GONE), not a content match.
"""
results: list[dict] = []
for citation, read in deferred:
for platform in read.get("platforms") or []:
revision = str(read.get("revision") or "") or build_revision(profile, str(platform))
row = {"platform": str(platform), "revision": revision or "",
"ref": citation.ref, "field": citation.field}
if revision is None:
results.append({**row, "status": "BUILD_UNREAD",
"detail": "no pin_build revision for this platform"})
continue
problems: list[str] = []
for part in split_source_ref(citation.ref):
role, path = ref_role(part.path)
if " " in path:
# A project word in front (`ROCKNIX patches/x.patch:4`):
# a file of the platform's tree, read with the record.
continue
lines = next(
(found for view in views
if (not role or view.field == role)
and (found := fetch(view.repo, revision, path)) is not None),
None,
)
if lines is None:
problems.append(f"{part.path} absent at {revision[:12]}")
elif (part.end or part.start or 0) > len(lines):
problems.append(f"{part.raw} past the end ({len(lines)} lines)")
results.append({
**row,
"status": "BUILD_GONE" if problems else "BUILD_OK",
"detail": "; ".join(problems),
})
return results
def build_report(
name: str, profile: dict, cache_dir: str, offline: bool = False,
text: str | None = None,
@@ -1621,7 +1702,13 @@ def build_report(
)
modes = {mode for _, mode, _ in declared_repositories(profile) if mode}
refs = []
at_build = shipped_build_holders(profile)
deferred: list[tuple[Citation, dict]] = []
for citation in collect_citations(profile, text):
if citation.kind == "ref" and id(citation.holder) in at_build:
# Written for the build a platform ships: read at pin_build.
deferred.append((citation, at_build[id(citation.holder)]))
continue
if citation.kind == "ref":
entry = citation.entry
display = str(entry.get("name") or "") or citation.field
@@ -2204,6 +2291,8 @@ def build_report(
)
return result
report.build_refs = _check_build_refs(profile, deferred, views, fetch_from)
staged = []
for entry_name, ref, tokens, hashes, ref_parts, citation in refs:
flags = [self_checked(part, tokens) for part in ref_parts]
@@ -2335,6 +2424,14 @@ def format_report(report: ProfileReport, changed_only: bool = False) -> str:
lines.append(f" {len(report.entries)} refs: {summary}")
for line in report.stale_prose or ():
lines.append(f" prose under an older pin: {line}")
for ref in report.build_refs:
if changed_only and ref["status"] == "BUILD_OK":
continue
detail = f": {ref['detail']}" if ref["detail"] else ""
lines.append(
f" {ref['status']} at {ref['platform']} build "
f"{ref['revision'][:12] or '-'} {ref['ref']}{detail}"
)
lines.append(f" {report.needs_review()} to review")
return "\n".join(lines)