28 @brief Verify each contract record is complete, uses the closed vocabularies, and
29 points at things that exist.
31 This fails closed on purpose. A misspelled status such as "enfroced" previously
32 dropped a contract out of enforcement *and* out of every report, so the registry
33 silently shrank while still looking healthy.
34 @param[in] contracts Contract records.
35 @param[in] registry Full registry, carrying the vocabularies and required fields.
36 @return Violation lines.
38 vocab = registry[
"vocabularies"]
39 required = registry[
"required_fields"]
40 violations: list[str] = []
42 for index, contract
in enumerate(contracts):
43 cid = contract.get(
"id")
or f
"<record {index}>"
44 if not contract.get(
"id"):
45 violations.append(f
"{cid}: record has no id")
47 violations.append(f
"{cid}: duplicate contract id")
50 for field
in required:
51 if field
not in contract:
52 violations.append(f
"{cid}: missing required field '{field}'")
54 for field
in (
"status",
"kind",
"enforcement"):
55 value = contract.get(field)
56 if value
is not None and value
not in vocab[field]:
58 f
"{cid}: {field} '{value}' is not in the closed vocabulary {vocab[field]}"
61 status = contract.get(
"status")
62 enforcement = contract.get(
"enforcement")
63 if status ==
"enforced" and enforcement !=
"blocking":
64 violations.append(f
"{cid}: status enforced requires enforcement 'blocking', got '{enforcement}'")
65 if status !=
"enforced" and enforcement ==
"blocking":
66 violations.append(f
"{cid}: enforcement 'blocking' requires status 'enforced', got '{status}'")
68 checker = contract.get(
"checker")
69 if status ==
"enforced" and not checker:
70 violations.append(f
"{cid}: status is enforced but no checker is registered")
71 if checker
is not None:
72 if not isinstance(checker, list)
or not checker
or not isinstance(checker[0], str):
73 violations.append(f
"{cid}: checker must be a non-empty list whose first element is a script path")
74 elif not (REPO_ROOT / checker[0]).is_file():
75 violations.append(f
"{cid}: checker script '{checker[0]}' does not exist")
76 elif not all(isinstance(part, str)
for part
in checker):
77 violations.append(f
"{cid}: checker command contains a non-string argument")
79 if status !=
"planned" and not contract.get(
"authoritative_sources"):
80 violations.append(f
"{cid}: names no authoritative sources")
81 for source
in contract.get(
"authoritative_sources", []):
82 if not (REPO_ROOT / source).exists():
83 violations.append(f
"{cid}: authoritative source '{source}' does not exist")
84 for page
in contract.get(
"canonical_documentation", []) + contract.get(
"dependent_pages", []):
85 if not (PAGES_DIR / f
"{page}.md").is_file():
86 violations.append(f
"{cid}: references page '{page}', which does not exist")
92 @brief Execute each enforced contract's checker, honouring declared prerequisites.
94 A checker that reads the generated HTML cannot run on a clean checkout. Skipping it
95 with an explicit note is honest; running it and passing because a stale build
96 happens to exist is not.
97 @param[in] contracts Contract records.
98 @return Failure lines, ids that passed, and skip notes.
103 html_ready = (REPO_ROOT /
"docs_build" /
"html" /
"index.html").is_file()
104 for contract
in contracts:
105 checker = contract.get(
"checker")
106 if contract[
"status"] !=
"enforced" or not checker:
108 if contract.get(
"requires_built_docs")
and not html_ready:
110 f
"{contract['id']}: requires the built site; run 'make build-docs' first"
113 command = [sys.executable, str(REPO_ROOT / checker[0]), *checker[1:]]
114 result = subprocess.run(command, cwd=REPO_ROOT, capture_output=
True, text=
True, check=
False)
115 if result.returncode != 0:
116 detail = (result.stderr
or result.stdout).strip().replace(
"\n",
"\n ")
117 failures.append(f
"{contract['id']}: checker failed\n {detail}")
119 passed.append(contract[
"id"])
120 return failures, passed, skipped
125 @brief Verify enforced invariant contracts and report the tracked ones.
126 @return Process status code.
128 parser = argparse.ArgumentParser(description=
"Run the invariant-contract registry.")
129 parser.add_argument(
"--list", action=
"store_true", help=
"List contracts without running checkers.")
130 args = parser.parse_args()
133 contracts = registry[
"contracts"]
137 for contract
in sorted(contracts, key=
lambda c: (c[
"status"], c[
"id"])):
138 print(f
" {contract['status']:10} {contract['kind']:18} {contract['id']}")
139 return 1
if violations
else 0
141 failures, passed, skipped = ([], [], [])
if violations
else run_checkers(contracts)
143 tracked = [c
for c
in contracts
if c[
"status"] ==
"tracked"]
144 planned = [c
for c
in contracts
if c[
"status"] ==
"planned"]
145 if tracked
or planned:
146 print(
"Invariant contracts without an automated checker (locatable, not verified):")
147 for contract
in tracked + planned:
148 print(f
" {contract['status']:8} {contract['id']} -> owns {', '.join(contract['canonical_documentation']) or 'nothing'}")
152 print(
"Enforced contracts skipped (prerequisite missing):")
157 if violations
or failures:
158 print(
"Invariant contract violations:", file=sys.stderr)
159 for line
in violations + failures:
160 print(f
" {line}", file=sys.stderr)
163 enforced_total = len([c
for c
in contracts
if c[
"status"] ==
"enforced"])
165 f
"Invariant contract audit passed: {len(passed)}/{enforced_total} enforced contract(s) "
167 + (f
", {len(skipped)} skipped" if skipped
else "")
168 + f
"; {len(tracked)} tracked, {len(planned)} planned (not verified)."
list[str] validate_records(list contracts, dict registry)
Verify each contract record is complete, uses the closed vocabularies, and points at things that exis...