2"""Assemble bounded review packets from PICurv's declared routing registries."""
4from __future__
import annotations
13from functools
import lru_cache
14from pathlib
import Path
17REPO_ROOT = Path(__file__).resolve().parents[2]
18PAGES_DIR = REPO_ROOT /
"docs" /
"pages"
19TOOLING_DIR = Path(__file__).resolve().parent
20if str(TOOLING_DIR)
not in sys.path:
21 sys.path.insert(0, str(TOOLING_DIR))
23from generate_xref_index
import (
24 SCHEMA_VERSION
as XREF_SCHEMA_VERSION,
25 digest_files
as xref_digest_files,
26 file_digest
as xref_file_digest,
27 source_files
as xref_source_files,
31CONTRACTS = TOOLING_DIR /
"contract_registry.json"
32FRESHNESS = TOOLING_DIR /
"freshness_manifest.json"
33MEASUREMENTS = TOOLING_DIR /
"measurement_records.json"
34FAMILIES = TOOLING_DIR /
"capability_families.json"
35SUBSYSTEMS = TOOLING_DIR /
"subsystem_records.json"
36SCOPE = TOOLING_DIR /
"capability_scope_records.json"
37XREF = REPO_ROOT /
"docs_build" /
"xref.json"
39 "Doxygen provides source-reference edges, not a semantic call graph. Registry tables, "
40 "callbacks, function pointers, macros, PETSc dispatch, and runtime-selected paths may "
41 "require following intermediate symbols. No direct edge does not prove that a symbol is unused."
43COMPLETE =
"ROUTE: complete over declared registry data (not over code behavior)"
44INCOMPLETE =
"ROUTE: incomplete — declared identifier has unresolved routing"
45UNAVAILABLE =
"ROUTE: unavailable — required environment or metadata is absent"
48def records(path: Path, key: str) -> list[dict]:
50 @brief Read one registry list.
51 @param[in] path Registry JSON path.
52 @param[in] key Top-level list key.
53 @return Registry records.
56 return json.loads(path.read_text(encoding=
"utf-8"))[key]
61 @brief Resolve a page argument, accepting a number, stem, or filename.
62 @param[in] name Page identifier supplied on the command line.
63 @return Path to the page.
64 @throws SystemExit when no page matches.
67 candidates = sorted(PAGES_DIR.glob(
"*.md"))
68 for page
in candidates:
69 if name
in (page.name, page.stem)
or page.stem.startswith(f
"{name}_"):
71 print(f
"ROUTE: invalid — no page matches '{name}'.", file=sys.stderr)
72 print(
"Known pages:", file=sys.stderr)
73 for page
in candidates:
74 print(f
" {page.stem}", file=sys.stderr)
80 @brief Extract a repository path from a path-or-symbol source declaration.
81 @param[in] source Declared source string.
82 @return Repository-relative path portion.
85 return source.split(
"::", 1)[0]
90 @brief Convert a Python module identifier to its repository path.
92 @details A dotted name may address a package rather than a single file - the
93 storage surface is one - in which case the package directory is the
94 source, because that is what an importer resolves the name to.
95 @param[in] module Dotted Python module.
96 @return Repository-relative Python path.
99 relative = module.replace(
".",
"/")
100 if (REPO_ROOT / relative).is_dir():
102 return relative +
".py"
108 @brief Map both filenames and Doxygen page identifiers to published page stems.
109 @return Alias-to-page-stem mapping.
112 aliases: dict[str, str] = {}
113 for page
in PAGES_DIR.glob(
"*.md"):
114 aliases[page.stem] = page.stem
115 match = re.search(
r"(?:^|\n)\s*@page\s+(\S+)", page.read_text(encoding=
"utf-8"))
117 aliases[match.group(1)] = page.stem
123 @brief Resolve a registry page reference to its filename stem when declared by Doxygen id.
124 @param[in] reference Page stem or Doxygen page identifier.
125 @return Canonical filename stem, or the unresolved input.
133 @brief Recent history for a set of paths, for spotting what changed underneath a route.
134 @param[in] paths Repository-relative paths.
135 @return Formatted git log output.
139 return " (none declared)"
140 result = subprocess.run(
141 [
"git",
"-C", str(REPO_ROOT),
"log",
"--oneline",
"-8",
"--", *paths],
146 return "\n".join(f
" {line}" for line
in result.stdout.strip().splitlines())
or " (no history)"
151 @brief Invariant contracts that own or depend on a page.
152 @param[in] page_stem Page identifier without extension.
153 @return Matching contract records.
158 for contract
in records(CONTRACTS,
"contracts")
160 in contract.get(
"canonical_documentation", []) + contract.get(
"dependent_pages", [])
166 @brief Capability families whose entries live on a page.
167 @param[in] page_stem Page identifier without extension.
168 @return Matching family records.
171 return [family
for family
in records(FAMILIES,
"families")
if family[
"family_page"] == page_stem]
176 @brief Collect obligation and concern pages from a subsystem record.
177 @param[in] record Subsystem lifecycle record.
178 @return Page stems named by the record.
181 pages: set[str] = set()
182 for section
in (
"obligations",
"concerns"):
183 for value
in record.get(section, {}).values():
184 if isinstance(value, dict)
and value.get(
"page"):
191 @brief Find subsystem records routed through any supplied page.
192 @param[in] page_stems Page stems to match.
193 @return Matching subsystem records.
196 return [record
for record
in records(SUBSYSTEMS,
"subsystems")
if record_pages(record) & page_stems]
201 @brief Scope records that name a page as a disclosure or activation surface.
202 @param[in] page_stem Page identifier without extension.
203 @return Matching scope records.
206 if not SCOPE.is_file():
209 for record
in records(SCOPE,
"records"):
210 surfaces = record.get(
"disclosed_at", []) + record.get(
"activation_condition", {}).get(
"surfaces", [])
211 if any(page_stem
in surface
for surface
in surfaces):
212 matches.append(record)
218 @brief Freshness surfaces that route review to a page.
219 @param[in] page_stem Page identifier.
220 @return List of role and surface pairs.
223 found: list[tuple[str, dict]] = []
224 for surface
in records(FRESHNESS,
"surfaces"):
225 if page_stem
in surface.get(
"owning_pages", []):
226 found.append((
"owns", surface))
227 elif page_stem
in surface.get(
"dependent_pages", []):
228 found.append((
"depends on", surface))
234 @brief Return the artifact or watched paths that define a freshness surface.
235 @param[in] surface Freshness manifest record.
236 @return Repository-relative paths.
239 return [surface[
"artifact"]]
if surface[
"tier"] ==
"hard" else list(surface.get(
"watched_paths", []))
244 @brief Whether a surface is current, suspect, or never attested.
245 @param[in] surface One freshness manifest entry.
246 @return Human-readable state.
250 missing = [path
for path
in paths
if not (REPO_ROOT / path).exists()]
252 return f
"INTEGRITY FAILURE - missing {', '.join(missing)}"
253 attested = surface.get(
"attested_digest")
254 if attested
in (
None,
"unattested"):
255 return "never attested"
261 @brief Digest matching audit_freshness.digest_of.
262 @param[in] paths Repository-relative paths.
263 @return Hex digest with algorithm prefix.
266 accumulator = hashlib.sha256()
267 for relative
in sorted(paths):
268 accumulator.update(relative.encode(
"utf-8"))
269 accumulator.update(b
"\0")
270 accumulator.update((REPO_ROOT / relative).read_bytes())
271 accumulator.update(b
"\0")
272 return f
"sha256:{accumulator.hexdigest()}"
277 @brief Current uncommitted status for declared sources.
278 @param[in] paths Repository-relative paths.
279 @return Formatted status output.
283 return " (none declared)"
284 result = subprocess.run(
285 [
"git",
"-C", str(REPO_ROOT),
"status",
"--porcelain",
"--", *paths],
290 body = result.stdout.strip()
291 return "\n".join(f
" {line}" for line
in body.splitlines())
if body
else " (clean)"
296 @brief Resolve a capability family's declared source paths and symbols.
297 @param[in] family Capability family record.
298 @return Tuples of path, symbol, and source kind.
301 specs: list[tuple[str, str, str]] = []
302 surface = family.get(
"public_surface", {})
303 if surface.get(
"module")
and surface.get(
"symbol"):
304 specs.append((
module_path(surface[
"module"]), surface[
"symbol"], surface.get(
"kind",
"public")))
305 for parity
in family.get(
"parity_sources", []):
306 symbol = parity.get(
"function")
or parity.get(
"symbol")
or parity.get(
"prefix")
307 if parity.get(
"path")
and symbol:
308 specs.append((parity[
"path"], symbol, parity.get(
"kind",
"parity")))
314 @brief Named symbols a capability family depends on, rather than whole files.
315 @param[in] family Family record.
316 @return Symbol descriptions.
319 return [f
"{path}::{symbol} ({kind})" for path, symbol, kind
in family_source_specs(family)]
324 @brief Declared evidence sources across a family's values.
325 @param[in] family Family record.
326 @return Sorted source identifiers.
329 sources: set[str] = set()
330 for metadata
in family.get(
"value_metadata", {}).values():
331 for facet_sources
in (metadata.get(
"evidence")
or {}).values():
332 sources.update(facet_sources)
333 return sorted(sources)
338 @brief Measurement records cited by declared evidence sources.
339 @param[in] sources Declared evidence source identifiers.
340 @return Matching measurement records, in citation order.
343 wanted = [s.split(
":", 1)[1]
for s
in sources
if s.startswith(
"measurement:")]
344 if not wanted
or not MEASUREMENTS.is_file():
346 by_id = {r.get(
"id"): r
for r
in
347 json.loads(MEASUREMENTS.read_text(encoding=
"utf-8")).get(
"records", [])}
348 return [by_id[i]
for i
in wanted
if i
in by_id]
353 @brief Make targets named by declared evidence sources.
354 @param[in] sources Source identifiers.
355 @return Verification commands.
358 return [f
"make {source.split(':', 1)[1]}" for source
in sources
if source.startswith(
"make:")]
361def route_status(unresolved: list[str], unavailable: bool =
False) -> int:
363 @brief Print the fixed route state and any unresolved declarations.
364 @param[in] unresolved Problems found while joining declared registry data.
365 @param[in] unavailable Whether required environmental metadata is unavailable.
366 @return Route exit status.
371 for problem
in unresolved:
376 for problem
in unresolved:
385 @brief Report an invalid registry identifier with close matches and known ids.
386 @param[in] kind Identifier category.
387 @param[in] identifier Unknown value.
388 @param[in] known Valid values.
389 @return Invalid-argument status.
392 print(f
"ROUTE: invalid — unknown {kind} '{identifier}'.", file=sys.stderr)
393 close = difflib.get_close_matches(identifier, known, n=5)
395 print(f
"Close matches: {', '.join(close)}", file=sys.stderr)
396 print(
"Known ids:", file=sys.stderr)
398 print(f
" {value}", file=sys.stderr)
404 @brief Print freshness routing with current attestation state.
405 @param[in] surfaces Role and surface pairs.
406 @param[in] heading Section heading.
411 for role, surface
in surfaces:
412 blocking = surface.get(
"enforcement")
or (
"blocking" if surface[
"tier"] ==
"hard" else "report")
414 print(f
" [{surface['tier']}/{blocking}] {surface['id']} ({role}) - {state}")
417 if state !=
"current":
418 print(f
" after review: make attest-freshness ARGS=\"{surface['id']}\"")
420 print(
" (none - no declared freshness surface routes here)")
426 @brief Load the optional cross-reference index only when its dirty-byte stamp is current.
427 @return State (`current`, `missing`, or `stale`) and current index when available.
430 if not XREF.is_file():
431 return "missing",
None
433 index = json.loads(XREF.read_text(encoding=
"utf-8"))
434 current_sources = xref_source_files(REPO_ROOT)
435 current_digest = xref_digest_files(REPO_ROOT, current_sources)
436 doxyfile_digest = xref_file_digest(REPO_ROOT /
"docs" /
"Doxyfile")
437 except (OSError, ValueError, KeyError, TypeError):
440 index.get(
"schema_version") != XREF_SCHEMA_VERSION
441 or index.get(
"source_digest") != current_digest
442 or index.get(
"source_files") != [path.as_posix()
for path
in current_sources]
443 or index.get(
"doxyfile_digest") != doxyfile_digest
444 or not isinstance(index.get(
"symbols"), dict)
447 return "current", index
452 @brief Match a declared path and symbol to Doxygen member identifiers.
453 @param[in] index Current cross-reference index.
454 @param[in] path Expected definition path, or an empty string.
455 @param[in] symbol Expected unqualified or qualified symbol.
456 @return Matching member ids.
459 matches: list[str] = []
460 for refid, record
in index[
"symbols"].items():
461 name_match = record.get(
"name") == symbol
or record.get(
"qualified_name") == symbol
462 name_match = name_match
or str(record.get(
"qualified_name",
"")).endswith(f
"::{symbol}")
463 name_match = name_match
or str(record.get(
"qualified_name",
"")).endswith(f
".{symbol}")
464 path_match =
not path
or record.get(
"definition", {}).get(
"path") == path
465 if name_match
and path_match:
466 matches.append(refid)
467 return sorted(matches)
472 @brief Format one indexed symbol with its definition location.
473 @param[in] index Current cross-reference index.
474 @param[in] refid Doxygen member id.
475 @return Compact symbol and source location.
478 record = index[
"symbols"].get(refid, {})
479 location = record.get(
"definition", {})
480 line = f
":{location.get('line')}" if location.get(
"line")
else ""
481 return f
"{record.get('qualified_name', record.get('name', refid))} ({location.get('path', '?')}{line})"
486 @brief Print the measurements already recorded against this route.
487 @param[in] records Measurement records to render.
493 print(
"MEASUREMENTS ALREADY RECORDED (read before running anything expensive)")
494 for record
in records:
495 result = record.get(
"result")
or {}
496 verdict = result.get(
"verdict",
"?")
if isinstance(result, dict)
else "?"
497 print(f
" [{verdict}] {record.get('id')} - {record.get('question')}")
498 print(f
" taken {record.get('date')} at {record.get('commit')} on {record.get('environment')}")
499 print(f
" does not establish: {record.get('limitations')}")
503def print_xref(specs: list[tuple[str, str, str]], paths: list[str] |
None =
None) ->
None:
505 @brief Print bounded direct and two-hop Doxygen reference evidence for a route.
506 @param[in] specs Declared source path, symbol, and kind tuples.
507 @param[in] paths Optional paths whose connected definitions should seed the view.
511 print(
"OPTIONAL SOURCE CROSS-REFERENCES")
513 if state ==
"missing":
514 print(
"XREF: not built (optional)")
515 print(
" Registry routing below is unaffected.")
516 print(
" Run `make docs-xref` to add bounded source-reference evidence.")
517 print(f
" {XREF_CAVEAT}\n")
519 if state ==
"stale" or index
is None:
520 print(
"XREF: stale — run make docs-xref")
521 print(
" Stale edges are not displayed; registry routing remains available.")
522 print(f
" {XREF_CAVEAT}\n")
525 print(
"XREF: current")
526 print(f
" {XREF_CAVEAT}")
527 selected: list[tuple[str, str]] = []
528 for path, symbol, _
in specs:
530 selected.append((f
"{path}::{symbol}", refid))
532 path_set = set(paths)
534 (f
"definitions in {record.get('definition', {}).get('path')}", refid)
535 for refid, record
in index[
"symbols"].items()
536 if record.get(
"definition", {}).get(
"path")
in path_set
537 and (record.get(
"incoming")
or record.get(
"outgoing"))
539 selected.extend(sorted(connected, key=
lambda item:
format_xref_node(index, item[1]))[:8])
541 seen: set[str] = set()
543 for label, refid
in selected:
544 if refid
not in seen:
546 bounded.append((label, refid))
548 print(
" (no indexed definition matched the declared symbols or paths)\n")
550 for label, refid
in bounded[:8]:
551 record = index[
"symbols"].get(refid, {})
553 print(f
" definition: {format_xref_node(index, refid)}")
554 incoming = [edge
for edge
in record.get(
"incoming", [])
if edge
in index[
"symbols"]]
555 outgoing = [edge
for edge
in record.get(
"outgoing", [])
if edge
in index[
"symbols"]]
556 for edge
in incoming[:4]:
557 print(f
" direct caller: {format_xref_node(index, edge)}")
558 for edge
in outgoing[:4]:
559 print(f
" direct reference: {format_xref_node(index, edge)}")
563 for edge
in incoming[:8]
564 for second
in index[
"symbols"].get(edge, {}).get(
"incoming", [])
565 if second
in index[
"symbols"]
and second != refid
571 for edge
in outgoing[:8]
572 for second
in index[
"symbols"].get(edge, {}).get(
"outgoing", [])
573 if second
in index[
"symbols"]
and second != refid
576 for edge
in second_in[:3]:
577 print(f
" two-hop caller: {format_xref_node(index, edge)}")
578 for edge
in second_out[:3]:
579 print(f
" two-hop reference: {format_xref_node(index, edge)}")
580 if len(incoming) > 4
or len(outgoing) > 4
or len(second_in) > 3
or len(second_out) > 3:
581 print(
" (additional edges omitted; inspect docs_build/xref.json for this symbol)")
587 @brief Print a review packet for one invariant contract.
588 @param[in] contract_id Contract identifier.
589 @return Process status code.
592 known = {contract[
"id"]: contract
for contract
in records(CONTRACTS,
"contracts")}
593 contract = known.get(contract_id)
596 sources = [
source_path(source)
for source
in contract.get(
"authoritative_sources", [])]
599 for page
in contract.get(
"canonical_documentation", []) + contract.get(
"dependent_pages", [])
601 unresolved = [f
"missing source {path}" for path
in sources
if not (REPO_ROOT / path).exists()]
603 f
"missing page docs/pages/{page}.md" for page
in pages
if not (PAGES_DIR / f
"{page}.md").is_file()
606 print(f
"REVIEW PACKET: contract {contract['id']}")
608 print(f
" {contract['title']} [{contract['status']} / {contract['enforcement']}]\n")
609 if contract.get(
"note"):
611 print(f
" {contract['note']}\n")
612 print(
"AUTHORITATIVE SOURCES")
613 for source
in contract.get(
"authoritative_sources", [])
or [
"(none)"]:
615 print(
"\nCANONICAL DOCUMENTATION (owns the narrative)")
616 for page
in contract.get(
"canonical_documentation", [])
or [
"(none)"]:
617 print(f
" docs/pages/{page}.md")
618 print(
"\nDEPENDENT PAGES (review if this contract changes)")
619 for page
in contract.get(
"dependent_pages", [])
or [
"(none)"]:
620 print(f
" docs/pages/{page}.md")
623 if contract[
"id"].startswith(
"run.artifact"):
624 topology = json.loads((TOOLING_DIR /
"artifact_topology.json").read_text(encoding=
"utf-8"))
625 print(
"LOGICAL IDENTITIES")
626 for artifact
in topology[
"artifacts"]:
627 print(f
" {artifact['id']:26} {artifact['path_rule']}")
628 for entry
in topology.get(
"resolved_safety_history", {}).get(
"entries", []):
629 print(f
"\n RESOLVED SAFETY DEFECT: {entry['id']} ({entry['severity']}) - {entry['state']}")
630 print(f
" residual risk: {entry['resolution']['residual_risk'][:120]}")
634 for surface
in records(FRESHNESS,
"surfaces"):
635 if set(surface.get(
"owning_pages", [])) & set(contract.get(
"canonical_documentation", [])):
636 scoped.append((
"owns", surface))
641 checker = contract.get(
"checker")
642 print(f
" python3 {' '.join(checker)}" if checker
else " (no automated checker - human review)")
643 print(
" make audit-contracts\n")
644 print(
"UNCOMMITTED CHANGES TO DECLARED SOURCES")
646 print(
"\nRECENT HISTORY")
653 @brief Join one capability family across symbols, pages, contracts, evidence, and subsystems.
654 @param[in] capability_id Capability family id.
655 @return Process status code.
658 known = {family[
"id"]: family
for family
in records(FAMILIES,
"families")}
659 family = known.get(capability_id)
663 page = family[
"family_page"]
665 f
"missing declared source {path}" for path, _, _
in specs
666 if not (REPO_ROOT / path).exists()
669 unresolved.append(
"no public or parity source symbol is declared")
670 if not (PAGES_DIR / f
"{page}.md").is_file():
671 unresolved.append(f
"missing family page docs/pages/{page}.md")
673 related_subsystems = [
675 for subsystem
in records(SUBSYSTEMS,
"subsystems")
676 if capability_id
in subsystem.get(
"capability_families", [])
680 print(f
"REVIEW PACKET: capability {capability_id}")
682 mode =
"enforced" if family.get(
"coverage_enforced")
else "advisory"
683 print(f
" {family['title']} [{mode}; {len(family.get('value_metadata', {}))} values]")
684 print(f
" selector: {family.get('selector', '(not declared)')}\n")
685 print(
"SOURCE SYMBOLS")
686 for symbol
in symbols_for(family)
or [
"(none declared)"]:
688 print(
"\nFAMILY DOCUMENTATION")
689 print(f
" docs/pages/{page}.md")
690 print(
"\nINVARIANT CONTRACTS ON THAT PAGE")
691 for contract
in related_contracts
or [
None]:
692 print(f
" [{contract['status']}] {contract['id']}" if contract
else " (none)")
693 print(
"\nSUBSYSTEMS USING THIS FAMILY")
694 for subsystem
in related_subsystems
or [
None]:
695 print(f
" [{subsystem['status']}] {subsystem['id']}" if subsystem
else " (none declared)")
698 print(
"DECLARED EVIDENCE SOURCES")
699 for source
in evidence
or [
"(none declared)"]:
707 print(
" make audit-capability")
708 print(f
" make review-packet PAGE={page}")
714 @brief Join one subsystem across capability families, obligation pages, contracts, and evidence.
715 @param[in] subsystem_id Subsystem lifecycle id.
716 @return Process status code.
719 known = {record[
"id"]: record
for record
in records(SUBSYSTEMS,
"subsystems")}
720 subsystem = known.get(subsystem_id)
723 family_map = {family[
"id"]: family
for family
in records(FAMILIES,
"families")}
724 family_ids = subsystem.get(
"capability_families", [])
726 unresolved = [f
"unknown capability family {family_id}" for family_id
in family_ids
if family_id
not in family_map]
727 unresolved.extend(f
"missing page docs/pages/{page}.md" for page
in pages
if not (PAGES_DIR / f
"{page}.md").is_file())
728 families = [family_map[family_id]
for family_id
in family_ids
if family_id
in family_map]
731 (
"routes subsystem page", surface)
732 for surface
in records(FRESHNESS,
"surfaces")
733 if set(surface.get(
"owning_pages", []) + surface.get(
"dependent_pages", [])) & pages
735 related_contracts = [
737 for contract
in records(CONTRACTS,
"contracts")
738 if set(contract.get(
"canonical_documentation", []) + contract.get(
"dependent_pages", [])) & pages
740 evidence = sorted({source
for family
in families
for source
in evidence_sources(family)})
742 print(f
"REVIEW PACKET: subsystem {subsystem_id}")
744 print(f
" {subsystem['title']} [{subsystem['status']} / {subsystem.get('visibility', '?')}]\n")
745 print(
"CAPABILITY FAMILIES")
746 for family
in families
or [
None]:
747 print(f
" {family['id']} -> docs/pages/{family['family_page']}.md" if family
else " (none declared)")
748 print(
"\nOBLIGATION AND CONCERN PAGES")
749 for page
in sorted(pages)
or [
"(none declared)"]:
750 print(f
" docs/pages/{page}.md")
751 print(
"\nINVARIANT CONTRACTS ON THOSE PAGES")
752 for contract
in related_contracts
or [
None]:
753 print(f
" [{contract['status']}] {contract['id']}" if contract
else " (none)")
756 print(
"DECLARED EVIDENCE AND TEST TARGETS")
757 for source
in evidence
or [
"(none declared through capability families)"]:
764 print(
" make audit-subsystems")
770 @brief Join one freshness surface across watched paths, pages, contracts, families, and subsystems.
771 @param[in] surface_id Freshness surface id.
772 @return Process status code.
775 known = {surface[
"id"]: surface
for surface
in records(FRESHNESS,
"surfaces")}
776 surface = known.get(surface_id)
782 for page
in surface.get(
"owning_pages", []) + surface.get(
"dependent_pages", [])
785 f
"missing watched path {path}" for path
in paths
786 if not (REPO_ROOT / path).exists()
788 unresolved.extend(f
"missing page docs/pages/{page}.md" for page
in pages
if not (PAGES_DIR / f
"{page}.md").is_file())
789 families = [family
for family
in records(FAMILIES,
"families")
if family[
"family_page"]
in pages]
790 related_contracts = [
792 for contract
in records(CONTRACTS,
"contracts")
793 if set(contract.get(
"canonical_documentation", []) + contract.get(
"dependent_pages", [])) & pages
798 print(f
"REVIEW PACKET: surface {surface_id}")
800 print(f
" {surface['title']} [{surface['tier']}] - {freshness_state(surface)}\n")
801 print(
"WATCHED PATHS")
802 for path
in paths
or [
"(none declared)"]:
804 print(
"\nOWNING AND DEPENDENT PAGES")
805 for page
in sorted(pages)
or [
"(none declared)"]:
806 role =
"owns" if page
in surface.get(
"owning_pages", [])
else "depends on"
807 print(f
" {role}: docs/pages/{page}.md")
808 print(
"\nINVARIANT CONTRACTS")
809 for contract
in related_contracts
or [
None]:
810 print(f
" [{contract['status']}] {contract['id']}" if contract
else " (none)")
811 print(
"\nCAPABILITY FAMILIES")
812 for family
in families
or [
None]:
813 print(f
" {family['id']}" if family
else " (none routed through these pages)")
814 print(
"\nSUBSYSTEMS")
815 for subsystem
in subsystems
or [
None]:
816 print(f
" [{subsystem['status']}] {subsystem['id']}" if subsystem
else " (none routed through these pages)")
820 print(f
" make review-packet PAGE={next(iter(sorted(pages)), '<page>')}")
821 print(f
" make attest-freshness ARGS=\"{surface_id}\" # only after source comparison")
827 @brief Collect staged, unstaged, and untracked nonignored paths from Git.
828 @return Path-to-state mapping and whether Git metadata was available.
831 probe = subprocess.run(
832 [
"git",
"-C", str(REPO_ROOT),
"rev-parse",
"--is-inside-work-tree"],
837 if probe.returncode != 0:
840 "staged": [
"git",
"-C", str(REPO_ROOT),
"diff",
"--cached",
"--name-only",
"-z"],
841 "unstaged": [
"git",
"-C", str(REPO_ROOT),
"diff",
"--name-only",
"-z"],
842 "untracked": [
"git",
"-C", str(REPO_ROOT),
"ls-files",
"--others",
"--exclude-standard",
"-z"],
844 found: dict[str, set[str]] = {}
845 for state, command
in commands.items():
846 completed = subprocess.run(command, capture_output=
True, check=
False)
847 if completed.returncode != 0:
849 for raw
in completed.stdout.split(b
"\0"):
851 found.setdefault(raw.decode(
"utf-8", errors=
"replace"), set()).add(state)
857 @brief Classify a changed path for routing coverage.
858 @param[in] path Repository-relative changed path.
859 @return Category label excluding routed versus unrouted production state.
862 candidate = Path(path)
863 if path.startswith(
"docs/generated/")
or path.startswith(
"docs_build/"):
866 (candidate.parts
and candidate.parts[0] ==
"src" and candidate.suffix
in {
".c",
".h"})
867 or (candidate.parts
and candidate.parts[0] ==
"include" and candidate.suffix
in {
".h",
".hpp"})
868 or (candidate.parts
and candidate.parts[0] ==
"picurv_cli" and candidate.suffix ==
".py")
871 routed_roots = {
"docs",
"config",
"tests",
".github",
".agents",
".claude",
"examples"}
872 routed_files = {
"AGENTS.md",
"CLAUDE.md",
"CONTRIBUTING.md",
"README.md",
"Makefile",
".gitignore"}
873 if (candidate.parts
and candidate.parts[0]
in routed_roots)
or path
in routed_files:
874 return "documentation/configuration/test/tooling"
875 return "ignored/out of scope"
880 @brief Find declared capabilities, surfaces, contracts, and subsystems touching a path.
881 @param[in] path Repository-relative production path.
882 @return Nonempty routing categories and sorted identifiers.
887 for family
in records(FAMILIES,
"families")
895 for contract
in records(CONTRACTS,
"contracts")
896 if path
in {
source_path(source)
for source
in contract.get(
"authoritative_sources", [])}
898 pages: set[str] = set()
899 for family
in records(FAMILIES,
"families"):
900 if family[
"id"]
in family_hits:
901 pages.add(family[
"family_page"])
902 for surface
in records(FRESHNESS,
"surfaces"):
903 if surface[
"id"]
in surface_hits:
904 pages.update(surface.get(
"owning_pages", []) + surface.get(
"dependent_pages", []))
905 for contract
in records(CONTRACTS,
"contracts"):
906 if contract[
"id"]
in contract_hits:
907 pages.update(contract.get(
"canonical_documentation", []) + contract.get(
"dependent_pages", []))
910 "capability": sorted(family_hits),
911 "surface": sorted(surface_hits),
912 "contract": sorted(contract_hits),
913 "subsystem": sorted(subsystem_hits),
915 return {kind: values
for kind, values
in routes.items()
if values}
920 @brief Return the nearest existing directory guide for an unrouted production path.
921 @param[in] path Repository-relative path.
922 @return Guide path or root instruction fallback.
925 current = (REPO_ROOT / path).parent
926 while current != REPO_ROOT
and REPO_ROOT
in current.parents:
927 guide = current /
"guide.md"
929 return guide.relative_to(REPO_ROOT).as_posix()
930 current = current.parent
936 @brief Report declared routing coverage for current working-tree changes.
937 @param[in] value Supported selector, currently `working-tree`.
938 @return Process status code.
941 if value !=
"working-tree":
944 routed: dict[str, dict[str, list[str]]] = {}
945 unrouted: list[str] = []
946 categories: dict[str, str] = {}
947 for path
in sorted(paths):
949 if category ==
"production":
952 category =
"routed production"
953 routed[path] = declared
955 category =
"unrouted production"
956 unrouted.append(path)
957 categories[path] = category
959 print(
"REVIEW PACKET: changed working-tree")
960 problems = [f
"unrouted production path: {path}" for path
in unrouted]
961 status =
route_status(problems
if available
else [
"Git working-tree metadata is unavailable"],
not available)
962 print(
" Coverage is advisory and covers staged, unstaged, and untracked nonignored paths.")
963 print(
" Ignored files are intentionally excluded by Git.\n")
964 if not paths
and available:
965 print(
"CHANGED PATHS\n (working tree clean)")
967 print(
"CHANGED PATHS")
968 for path
in sorted(paths):
969 states =
", ".join(sorted(paths[path]))
970 print(f
" [{categories[path]}] {path} ({states})")
971 for kind, identifiers
in routed.get(path, {}).items():
972 print(f
" {kind}: {', '.join(identifiers)}")
973 if categories[path] ==
"unrouted production":
975 root = Path(path).parts[0]
976 print(f
" fallback guide: {guide}")
977 print(f
" targeted search: rg -n \"<responsibility-or-symbol>\" {root}")
983 @brief Print the original page-scoped review packet with explicit route status and xrefs.
984 @param[in] page_name Page number, stem, or filename.
985 @return Process status code.
993 sources: list[str] = []
994 specs: list[tuple[str, str, str]] = []
995 evidence: list[str] = []
996 for contract
in page_contracts:
997 sources.extend(
source_path(source)
for source
in contract.get(
"authoritative_sources", []))
998 for family
in families:
1000 specs.extend(family_specs)
1001 sources.extend(path
for path, _, _
in family_specs)
1003 sources = sorted(set(sources))
1004 evidence = sorted(set(evidence))
1005 unresolved = [f
"missing declared source {source}" for source
in sources
if not (REPO_ROOT / source).exists()]
1007 print(f
"REVIEW PACKET: {page.relative_to(REPO_ROOT)}")
1009 print(f
" {len(page.read_text(encoding='utf-8').splitlines())} lines\n")
1010 print(
"SOURCE SYMBOLS (read these, not whole files)")
1011 for symbol
in [f
"{path}::{symbol} ({kind})" for path, symbol, kind
in specs]
or [
"(none declared)"]:
1013 print(
"\nAUTHORITATIVE FILES")
1014 for source
in sources
or [
"(none declared)"]:
1017 if stem ==
"71_Invariant_Contracts":
1018 print(
"THIS PAGE DOCUMENTS THE WHOLE REGISTRY")
1019 for contract
in sorted(
records(CONTRACTS,
"contracts"), key=
lambda item: (item[
"status"], item[
"id"])):
1020 print(f
" [{contract['status']:8}] {contract['id']}")
1022 print(
"INVARIANT CONTRACTS")
1023 for contract
in page_contracts:
1024 role =
"owns" if stem
in contract.get(
"canonical_documentation", [])
else "depends on"
1025 print(f
" [{contract['status']}] {contract['id']} ({role} this page)")
1026 print(f
" inspect: make review-packet CONTRACT={contract['id']}")
1027 if not page_contracts:
1029 print(
"\nCAPABILITY FAMILIES ON THIS PAGE")
1030 for family
in families:
1031 mode =
"enforced" if family.get(
"coverage_enforced")
else "advisory"
1032 print(f
" {family['id']} ({mode}) - {len(family.get('value_metadata', {}))} declared values")
1037 print(
"DECLARED EVIDENCE SOURCES")
1038 for source
in evidence:
1042 print(
"SCOPE RECORDS NAMING THIS PAGE")
1043 for record
in scope_records:
1044 print(f
" [{record.get('status')}] {record['id']} ({record.get('publication_policy')})")
1048 print(
"UNCOMMITTED CHANGES TO DECLARED SOURCES")
1050 print(
"\nRECENT HISTORY")
1052 print(
"\nVERIFY WITH")
1054 print(f
" {command}")
1055 print(
" make audit-capability")
1056 print(
" make audit-contracts")
1057 print(
" make preview-docs")
1063 @brief Parse the mutually exclusive review-packet route selectors.
1064 @param[in] argv Arguments excluding the executable name.
1065 @return Parsed command-line namespace.
1068 parser = argparse.ArgumentParser(
1069 description=
"Assemble everything a reviewer needs for one declared PICurv route."
1071 group = parser.add_mutually_exclusive_group(required=
True)
1072 group.add_argument(
"page", nargs=
"?", help=
"Page number, stem, or filename (for example 44).")
1073 group.add_argument(
"--contract", help=
"Invariant contract id.")
1074 group.add_argument(
"--capability", help=
"Capability family id.")
1075 group.add_argument(
"--subsystem", help=
"Subsystem lifecycle id.")
1076 group.add_argument(
"--surface", help=
"Freshness surface id.")
1077 group.add_argument(
"--changed", help=
"Changed-set selector; currently working-tree.")
1078 return parser.parse_args(argv)
1081def main(argv: list[str] |
None =
None) -> int:
1083 @brief Dispatch the requested bounded route and preserve differentiated exit states.
1084 @param[in] argv Optional arguments excluding the executable name.
1085 @return Zero for complete, two for invalid, and three for incomplete or unavailable.
1088 args =
parse_args(sys.argv[1:]
if argv
is None else argv)
1102if __name__ ==
"__main__":
1103 raise SystemExit(
main())
int surface_mode(str surface_id)
Join one freshness surface across watched paths, pages, contracts, families, and subsystems.
list[dict] records(Path path, str key)
Read one registry list.
int changed_mode(str value)
Report declared routing coverage for current working-tree changes.
None print_measurements(list records)
Print the measurements already recorded against this route.
Path resolve_page(str name)
Resolve a page argument, accepting a number, stem, or filename.
str guide_fallback(str path)
Return the nearest existing directory guide for an unrouted production path.
str classify_path(str path)
Classify a changed path for routing coverage.
int subsystem_mode(str subsystem_id)
Join one subsystem across capability families, obligation pages, contracts, and evidence.
str canonical_page(str reference)
Resolve a registry page reference to its filename stem when declared by Doxygen id.
argparse.Namespace parse_args(list[str] argv)
Parse the mutually exclusive review-packet route selectors.
list[str] symbols_for(dict family)
Named symbols a capability family depends on, rather than whole files.
int contract_mode(str contract_id)
Print a review packet for one invariant contract.
str module_path(str module)
Convert a Python module identifier to its repository path.
list[dict] scope_records_for(str page_stem)
Scope records that name a page as a disclosure or activation surface.
list[dict] subsystems_for_pages(set[str] page_stems)
Find subsystem records routed through any supplied page.
str _freshness_digest(list[str] paths)
Digest matching audit_freshness.digest_of.
str format_xref_node(dict index, str refid)
Format one indexed symbol with its definition location.
tuple[dict[str, set[str]], bool] changed_paths()
Collect staged, unstaged, and untracked nonignored paths from Git.
None print_freshness(list[tuple[str, dict]] surfaces, str heading)
Print freshness routing with current attestation state.
int route_status(list[str] unresolved, bool unavailable=False)
Print the fixed route state and any unresolved declarations.
str source_path(str source)
Extract a repository path from a path-or-symbol source declaration.
set[str] record_pages(dict record)
Collect obligation and concern pages from a subsystem record.
list recorded_measurements(list[str] sources)
Measurement records cited by declared evidence sources.
str freshness_state(dict surface)
Whether a surface is current, suspect, or never attested.
int page_mode(str page_name)
Print the original page-scoped review packet with explicit route status and xrefs.
list[str] make_targets(list[str] sources)
Make targets named by declared evidence sources.
list[tuple[str, str, str]] family_source_specs(dict family)
Resolve a capability family's declared source paths and symbols.
tuple[str, dict|None] load_xref()
Load the optional cross-reference index only when its dirty-byte stamp is current.
int main(list[str]|None argv=None)
Dispatch the requested bounded route and preserve differentiated exit states.
list[str] freshness_paths(dict surface)
Return the artifact or watched paths that define a freshness surface.
str git_log(list[str] paths)
Recent history for a set of paths, for spotting what changed underneath a route.
None print_xref(list[tuple[str, str, str]] specs, list[str]|None paths=None)
Print bounded direct and two-hop Doxygen reference evidence for a route.
dict[str, str] page_aliases()
Map both filenames and Doxygen page identifiers to published page stems.
str uncommitted(list[str] paths)
Current uncommitted status for declared sources.
int capability_mode(str capability_id)
Join one capability family across symbols, pages, contracts, evidence, and subsystems.
list[str] xref_matches(dict index, str path, str symbol)
Match a declared path and symbol to Doxygen member identifiers.
list[dict] contracts_for(str page_stem)
Invariant contracts that own or depend on a page.
list[dict] families_for(str page_stem)
Capability families whose entries live on a page.
int unknown_identifier(str kind, str identifier, list[str] known)
Report an invalid registry identifier with close matches and known ids.
list[tuple[str, dict]] freshness_for(str page_stem)
Freshness surfaces that route review to a page.
list[str] evidence_sources(dict family)
Declared evidence sources across a family's values.
dict[str, list[str]] routes_for_path(str path)
Find declared capabilities, surfaces, contracts, and subsystems touching a path.
Head of a generic C-style linked list.