PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
Functions | Variables
audit_contracts Namespace Reference

Functions

dict load_registry ()
 Load the invariant-contract registry.
 
list[str] validate_records (list contracts, dict registry)
 Verify each contract record is complete, uses the closed vocabularies, and points at things that exist.
 
tuple run_checkers (list contracts)
 Execute each enforced contract's checker, honouring declared prerequisites.
 
int main ()
 Verify enforced invariant contracts and report the tracked ones.
 

Variables

 REPO_ROOT = Path(__file__).resolve().parents[2]
 
str REGISTRY_PATH = REPO_ROOT / "tests" / "tooling" / "contract_registry.json"
 
str PAGES_DIR = REPO_ROOT / "docs" / "pages"
 

Detailed Description

Run the invariant-contract registry: verify enforced contracts and report tracked ones.

Function Documentation

◆ load_registry()

dict audit_contracts.load_registry ( )

Load the invariant-contract registry.

Returns
Parsed registry mapping.

Definition at line 18 of file audit_contracts.py.

18def load_registry() -> dict:
19 """!
20 @brief Load the invariant-contract registry.
21 @return Parsed registry mapping.
22 """
23 return json.loads(REGISTRY_PATH.read_text(encoding="utf-8"))
24
25
Here is the caller graph for this function:

◆ validate_records()

list[str] audit_contracts.validate_records ( list  contracts,
dict  registry 
)

Verify each contract record is complete, uses the closed vocabularies, and points at things that exist.

This fails closed on purpose. A misspelled status such as "enfroced" previously dropped a contract out of enforcement and out of every report, so the registry silently shrank while still looking healthy.

Parameters
[in]contractsContract records.
[in]registryFull registry, carrying the vocabularies and required fields.
Returns
Violation lines.

Definition at line 26 of file audit_contracts.py.

26def validate_records(contracts: list, registry: dict) -> list[str]:
27 """!
28 @brief Verify each contract record is complete, uses the closed vocabularies, and
29 points at things that exist.
30
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.
37 """
38 vocab = registry["vocabularies"]
39 required = registry["required_fields"]
40 violations: list[str] = []
41 seen: set = set()
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")
46 elif cid in seen:
47 violations.append(f"{cid}: duplicate contract id")
48 seen.add(cid)
49
50 for field in required:
51 if field not in contract:
52 violations.append(f"{cid}: missing required field '{field}'")
53
54 for field in ("status", "kind", "enforcement"):
55 value = contract.get(field)
56 if value is not None and value not in vocab[field]:
57 violations.append(
58 f"{cid}: {field} '{value}' is not in the closed vocabulary {vocab[field]}"
59 )
60
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}'")
67
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")
78
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")
87 return violations
88
89
Here is the caller graph for this function:

◆ run_checkers()

tuple audit_contracts.run_checkers ( list  contracts)

Execute each enforced contract's checker, honouring declared prerequisites.

A checker that reads the generated HTML cannot run on a clean checkout. Skipping it with an explicit note is honest; running it and passing because a stale build happens to exist is not.

Parameters
[in]contractsContract records.
Returns
Failure lines, ids that passed, and skip notes.

Definition at line 90 of file audit_contracts.py.

90def run_checkers(contracts: list) -> tuple:
91 """!
92 @brief Execute each enforced contract's checker, honouring declared prerequisites.
93
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.
99 """
100 failures: list = []
101 passed: list = []
102 skipped: list = []
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:
107 continue
108 if contract.get("requires_built_docs") and not html_ready:
109 skipped.append(
110 f"{contract['id']}: requires the built site; run 'make build-docs' first"
111 )
112 continue
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}")
118 else:
119 passed.append(contract["id"])
120 return failures, passed, skipped
121
122
Here is the caller graph for this function:

◆ main()

int audit_contracts.main ( )

Verify enforced invariant contracts and report the tracked ones.

Returns
Process status code.

Definition at line 123 of file audit_contracts.py.

123def main() -> int:
124 """!
125 @brief Verify enforced invariant contracts and report the tracked ones.
126 @return Process status code.
127 """
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()
131
132 registry = load_registry()
133 contracts = registry["contracts"]
134
135 violations = validate_records(contracts, registry)
136 if args.list:
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
140
141 failures, passed, skipped = ([], [], []) if violations else run_checkers(contracts)
142
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'}")
149 print("")
150
151 if skipped:
152 print("Enforced contracts skipped (prerequisite missing):")
153 for note in skipped:
154 print(f" {note}")
155 print("")
156
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)
161 return 1
162
163 enforced_total = len([c for c in contracts if c["status"] == "enforced"])
164 print(
165 f"Invariant contract audit passed: {len(passed)}/{enforced_total} enforced contract(s) "
166 f"verified"
167 + (f", {len(skipped)} skipped" if skipped else "")
168 + f"; {len(tracked)} tracked, {len(planned)} planned (not verified)."
169 )
170 return 0
171
172
int main(int argc, char **argv)
Entry point for the postprocessor executable.
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ REPO_ROOT

audit_contracts.REPO_ROOT = Path(__file__).resolve().parents[2]

Definition at line 13 of file audit_contracts.py.

◆ REGISTRY_PATH

str audit_contracts.REGISTRY_PATH = REPO_ROOT / "tests" / "tooling" / "contract_registry.json"

Definition at line 14 of file audit_contracts.py.

◆ PAGES_DIR

str audit_contracts.PAGES_DIR = REPO_ROOT / "docs" / "pages"

Definition at line 15 of file audit_contracts.py.