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

Functions

str slug (str value)
 Convert a selector value into the anchor slug its entry must use.
 
str strip_non_prose (str text)
 Remove fenced code blocks and HTML comments so anchors inside examples do not count.
 
list[str] check_generated_current ()
 Verify the committed inventory matches what the sources currently produce.
 
dict[str, dict] parity_by_kind (dict family)
 Index a family's parity records by source kind.
 
list[str] check_parity (dict family)
 Verify the public selector set agrees with every declared parity source.
 
list check_metadata (dict family, dict registry_entry)
 Verify declared value metadata is complete, well-typed, and matches the sources.
 
tuple check_coverage (dict family, dict registry_entry, list all_entries=None)
 Verify every public value has a Tier-2 entry carrying its required fields.
 
str entry_body (str prose, str anchor)
 Return the text of one capability entry, from its anchor to the next entry.
 
bool source_exists (str identifier)
 Check that one evidence source identifier names something that exists.
 
list measurement_records ()
 Every recorded measurement available as an evidence source.
 
list check_measurement_records ()
 Verify every recorded measurement carries what a reader needs to judge it.
 
str source_token (str identifier)
 The human-readable token a capability entry must cite for a declared source.
 
list[str] check_evidence (dict family, dict registry_entry, dict facets)
 Verify declared evidence sources exist and are cited by the capability entry.
 
list[str] check_scope_records ()
 Verify every known-defective scope record is disclosed where it claims to be.
 
list check_lifecycle_requirements (dict family, dict registry_entry)
 Enforce the documentation each lifecycle status owes.
 
int main ()
 Fail on capability parity breaks, metadata drift, or missing entries.
 

Variables

 REPO_ROOT = Path(__file__).resolve().parents[2]
 
str REGISTRY_PATH = REPO_ROOT / "tests" / "tooling" / "capability_families.json"
 
str INVENTORY_PATH = REPO_ROOT / "docs" / "generated" / "capability_inventory.json"
 
str GENERATOR = REPO_ROOT / "tests" / "tooling" / "generate_capability_inventory.py"
 
tuple CANONICAL_FIELDS
 
tuple ALIAS_FIELDS = ("Identity", "Status", "Migration")
 
str SCOPE_RECORDS_PATH = REPO_ROOT / "tests" / "tooling" / "capability_scope_records.json"
 
str MEASUREMENTS_PATH = REPO_ROOT / "tests" / "tooling" / "measurement_records.json"
 
tuple VALID_STATUSES
 
tuple NON_SELECTABLE_STATUSES = ("planned", "internal", "removed")
 
dict LIFECYCLE_REQUIREMENTS
 

Detailed Description

Enforce capability parity across the full source chain and Tier-2 documentation coverage.

Function Documentation

◆ slug()

str audit_capability_coverage.slug ( str  value)

Convert a selector value into the anchor slug its entry must use.

Parameters
[in]valuePublic selector value.
Returns
Lowercase underscore slug.

Definition at line 31 of file audit_capability_coverage.py.

31def slug(value: str) -> str:
32 """!
33 @brief Convert a selector value into the anchor slug its entry must use.
34 @param[in] value Public selector value.
35 @return Lowercase underscore slug.
36 """
37 return re.sub(r"[^a-z0-9]+", "_", value.lower()).strip("_")
38
39
Here is the caller graph for this function:

◆ strip_non_prose()

str audit_capability_coverage.strip_non_prose ( str  text)

Remove fenced code blocks and HTML comments so anchors inside examples do not count.

Parameters
[in]textRaw page text.
Returns
Page text with code fences and comments blanked out.

Definition at line 40 of file audit_capability_coverage.py.

40def strip_non_prose(text: str) -> str:
41 """!
42 @brief Remove fenced code blocks and HTML comments so anchors inside examples do not count.
43 @param[in] text Raw page text.
44 @return Page text with code fences and comments blanked out.
45 """
46 text = re.sub(r"<!--.*?-->", "", text, flags=re.S)
47 text = re.sub(r"^```.*?^```", "", text, flags=re.S | re.M)
48 return text
49
50
Here is the caller graph for this function:

◆ check_generated_current()

list[str] audit_capability_coverage.check_generated_current ( )

Verify the committed inventory matches what the sources currently produce.

Returns
Violation lines.

Definition at line 51 of file audit_capability_coverage.py.

51def check_generated_current() -> list[str]:
52 """!
53 @brief Verify the committed inventory matches what the sources currently produce.
54 @return Violation lines.
55 """
56 result = subprocess.run(
57 [sys.executable, str(GENERATOR), "--check"], capture_output=True, text=True, check=False
58 )
59 if result.returncode != 0:
60 detail = result.stderr.strip().replace("\n", "\n ")
61 return [f"generated capability inventory is stale or invalid; run 'make docs-inventory'\n {detail}"]
62 return []
63
64
Here is the caller graph for this function:

◆ parity_by_kind()

dict[str, dict] audit_capability_coverage.parity_by_kind ( dict  family)

Index a family's parity records by source kind.

Parameters
[in]familyInventory record for one family.
Returns
Mapping of source kind to its parity record.

Definition at line 65 of file audit_capability_coverage.py.

65def parity_by_kind(family: dict) -> dict[str, dict]:
66 """!
67 @brief Index a family's parity records by source kind.
68 @param[in] family Inventory record for one family.
69 @return Mapping of source kind to its parity record.
70 """
71 return {record["source"]["kind"]: record for record in family["parity"]}
72
73
Here is the caller graph for this function:

◆ check_parity()

list[str] audit_capability_coverage.check_parity ( dict  family)

Verify the public selector set agrees with every declared parity source.

Every declared source kind is handled explicitly; an unrecognized kind is a violation rather than a silent pass, because a source that is registered but never compared produces a false assurance of parity.

Parameters
[in]familyInventory record for one family.
Returns
Violation lines.

Definition at line 74 of file audit_capability_coverage.py.

74def check_parity(family: dict) -> list[str]:
75 """!
76 @brief Verify the public selector set agrees with every declared parity source.
77
78 Every declared source kind is handled explicitly; an unrecognized kind is a
79 violation rather than a silent pass, because a source that is registered but
80 never compared produces a false assurance of parity.
81 @param[in] family Inventory record for one family.
82 @return Violation lines.
83 """
84 violations: list[str] = []
85 public = set(family["public_values"])
86 records = parity_by_kind(family)
87 known = {"c_string_map", "c_token_map", "c_switch", "c_dispatch", "c_enum"}
88
89 for record in family["parity"]:
90 kind = record["source"]["kind"]
91 if kind not in known:
92 violations.append(
93 f"{family['id']}: parity source kind '{kind}' is registered but not verified by this audit"
94 )
95
96 # Link 1: every public value must be accepted by the C parser, and vice versa.
97 accepted: dict[str, str] = {}
98 for kind in ("c_string_map", "c_token_map"):
99 record = records.get(kind)
100 if not record:
101 continue
102 accepted = record.get("mapping", {})
103 path = record["source"]["path"]
104 if kind == "c_string_map":
105 expected = public
106 else:
107 expected = {spec.get("maps_to") for spec in family["public_values"].values()}
108 for missing in sorted(expected - set(accepted)):
109 violations.append(
110 f"{family['id']}: '{missing}' is produced by the validator but the C parser "
111 f"({path}) does not accept it"
112 )
113 legacy = set(record["source"].get("legacy_tokens", {}))
114 for token in sorted(legacy - set(accepted)):
115 violations.append(
116 f"{family['id']}: '{token}' is declared a legacy token but the C parser ({path}) "
117 f"no longer accepts it; remove the declaration"
118 )
119 for extra in sorted(set(accepted) - expected - legacy):
120 violations.append(
121 f"{family['id']}: the C parser ({path}) accepts '{extra}' but the validator "
122 f"never produces it; either expose it or remove it"
123 )
124
125 # Link 2: every enum a value resolves to must be dispatched at runtime.
126 for kind, label in (("c_switch", "factory"), ("c_dispatch", "runtime dispatch")):
127 record = records.get(kind)
128 if not record:
129 continue
130 handled = set(record["values"])
131 path = record["source"]["path"]
132 for token, enum in sorted(accepted.items()):
133 if enum not in handled:
134 violations.append(
135 f"{family['id']}: token '{token}' resolves to {enum}, which the {label} in "
136 f"{path} does not handle; selecting it would fail at runtime"
137 )
138
139 # Link 3: every resolved enum must exist in the declared enum type.
140 record = records.get("c_enum")
141 if record:
142 declared = set(record["values"])
143 path = record["source"]["path"]
144 for token, enum in sorted(accepted.items()):
145 if enum not in declared:
146 violations.append(
147 f"{family['id']}: token '{token}' resolves to {enum}, which is not a member of "
148 f"the enum declared in {path}"
149 )
150 return violations
151
152
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_metadata()

list audit_capability_coverage.check_metadata ( dict  family,
dict  registry_entry 
)

Verify declared value metadata is complete, well-typed, and matches the sources.

Fails closed on the status field. A canonical value with no status, or with a typo such as "suported", previously passed every check while generation quietly defaulted it to supported - so a defective capability could read as production-ready through an omission.

Parameters
[in]familyInventory record for one family.
[in]registry_entryRegistry entry carrying value metadata.
Returns
Violation lines.

Definition at line 153 of file audit_capability_coverage.py.

153def check_metadata(family: dict, registry_entry: dict) -> list:
154 """!
155 @brief Verify declared value metadata is complete, well-typed, and matches the sources.
156
157 @details Fails closed on the status field. A canonical value with no status, or with
158 a typo such as "suported", previously passed every check while generation
159 quietly defaulted it to supported - so a defective capability could read as
160 production-ready through an omission.
161 @param[in] family Inventory record for one family.
162 @param[in] registry_entry Registry entry carrying value metadata.
163 @return Violation lines.
164 """
165 # No early return on an absent metadata block: a family that exposes values but
166 # declares nothing must report every value as undeclared, not pass silently.
167 metadata = registry_entry.get("value_metadata", {})
168 public = set(family["public_values"])
169 violations = []
170 for stale in sorted(set(metadata) - public):
171 violations.append(
172 f"{family['id']}: metadata declares '{stale}', which is no longer a public value; "
173 f"remove it from capability_families.json"
174 )
175 for undeclared in sorted(public - set(metadata)):
176 violations.append(
177 f"{family['id']}: public value '{undeclared}' has no metadata entry; "
178 f"declare its status and whether it is canonical"
179 )
180 for name, spec in sorted(metadata.items()):
181 target = spec.get("alias_of") or spec.get("spelling_of")
182 if spec.get("canonical") is False and not target:
183 violations.append(
184 f"{family['id']}: '{name}' is marked non-canonical but names no alias_of or "
185 f"spelling_of target"
186 )
187 if target and target not in metadata:
188 violations.append(f"{family['id']}: '{name}' aliases '{target}', which is not a declared value")
189
190 if spec.get("spelling_of"):
191 # A spelling has no lifecycle of its own; it inherits one.
192 if "status" in spec:
193 violations.append(
194 f"{family['id']}: '{name}' is a spelling of '{spec['spelling_of']}' and must not "
195 f"declare its own status; it inherits one"
196 )
197 continue
198
199 status = spec.get("status")
200 if status is None:
201 violations.append(
202 f"{family['id']}: '{name}' declares no status; every canonical value and "
203 f"deprecated alias must declare one of {list(VALID_STATUSES)}"
204 )
205 continue
206 if status not in VALID_STATUSES:
207 violations.append(
208 f"{family['id']}: '{name}' has status '{status}', which is not in the closed "
209 f"vocabulary {list(VALID_STATUSES)}"
210 )
211 continue
212 if spec.get("alias_of") and status != "deprecated":
213 violations.append(
214 f"{family['id']}: '{name}' declares alias_of '{spec['alias_of']}' but status "
215 f"'{status}'; an alias is by definition deprecated"
216 )
217 if status in NON_SELECTABLE_STATUSES:
218 # Reachability is computed separately: a value the sources declare but no
219 # provider can satisfy is already marked latent, which is consistent with a
220 # non-selectable lifecycle. The contradiction is a non-selectable status on
221 # a value that IS reachable.
222 reachable = family["public_values"].get(name, {}).get("reachable", True)
223 if reachable:
224 violations.append(
225 f"{family['id']}: '{name}' has status '{status}' but is publicly selectable; "
226 f"a {status} capability must not be reachable"
227 )
228 return violations
229
230
Here is the caller graph for this function:

◆ check_coverage()

tuple audit_capability_coverage.check_coverage ( dict  family,
dict  registry_entry,
list   all_entries = None 
)

Verify every public value has a Tier-2 entry carrying its required fields.

Parameters
[in]familyInventory record for one family.
[in]registry_entryRegistry entry carrying anchor prefix and enforcement flag.
[in]all_entriesEvery registry entry, so anchors owned by a sibling family on the same page are not misreported as stale.
Returns
Blocking violations and advisory notes.

Definition at line 231 of file audit_capability_coverage.py.

231def check_coverage(family: dict, registry_entry: dict, all_entries: list = None) -> tuple:
232 """!
233 @brief Verify every public value has a Tier-2 entry carrying its required fields.
234 @param[in] family Inventory record for one family.
235 @param[in] registry_entry Registry entry carrying anchor prefix and enforcement flag.
236 @param[in] all_entries Every registry entry, so anchors owned by a sibling family on
237 the same page are not misreported as stale.
238 @return Blocking violations and advisory notes.
239 """
240 all_entries = all_entries or [registry_entry]
241 page = REPO_ROOT / "docs" / "pages" / f"{registry_entry['family_page']}.md"
242 if not page.is_file():
243 return ([f"{family['id']}: family page {page.name} does not exist"], [])
244 prose = strip_non_prose(page.read_text(encoding="utf-8"))
245 anchors = set(re.findall(r"^@anchor\s+([A-Za-z0-9_]+)\s*$", prose, re.M))
246 prefix = registry_entry["entry_anchor_prefix"]
247 metadata = registry_entry.get("value_metadata", {})
248
249 # Slug collisions would make two values share one entry.
250 seen: dict[str, str] = {}
251 problems: list[str] = []
252 for value in sorted(family["public_values"]):
253 key = slug(value)
254 if key in seen:
255 problems.append(
256 f"{family['id']}: '{value}' and '{seen[key]}' produce the same anchor slug "
257 f"'{prefix}{key}'; entries would collide"
258 )
259 seen[key] = value
260
261 # Latent values are declared but not selectable, so they owe no Tier-2 entry.
262 # Latent values are not selectable, and accepted spellings are mere synonyms of a
263 # canonical value; neither owes its own Tier-2 entry.
264 selectable = {
265 name: spec
266 for name, spec in family["public_values"].items()
267 if spec.get("reachability") != "latent" and not spec.get("spelling_of")
268 }
269 expected = {f"{prefix}{slug(v)}": v for v in selectable}
270 for anchor, value in sorted(expected.items()):
271 if anchor not in anchors:
272 problems.append(
273 f"{family['id']}: no Tier-2 entry for '{value}' (expected `@anchor {anchor}` in {page.name})"
274 )
275 continue
276 body = entry_body(prose, anchor)
277 spec = metadata.get(value, {})
278 required = ALIAS_FIELDS if spec.get("alias_of") else CANONICAL_FIELDS
279 for field in required:
280 if not re.search(rf"\*\*{re.escape(field)}", body):
281 problems.append(
282 f"{family['id']}: entry for '{value}' is missing the **{field}** part"
283 )
284
285 # Stale entries: an anchor with our prefix that no current value claims. A page may
286 # host several families, and one prefix can be a prefix of another (`p08_cap_` vs
287 # `p08_cap_conv_`), so an anchor belongs to this family only when no more specific
288 # registered prefix on the same page also matches it.
289 others = [
290 other["entry_anchor_prefix"]
291 for other in all_entries
292 if other is not registry_entry
293 and other["family_page"] == registry_entry["family_page"]
294 and other["entry_anchor_prefix"].startswith(prefix)
295 and other["entry_anchor_prefix"] != prefix
296 ]
297 for anchor in sorted(a for a in anchors if a.startswith(prefix)):
298 if any(anchor.startswith(other) for other in others):
299 continue
300 if anchor not in expected:
301 problems.append(
302 f"{family['id']}: {page.name} carries a stale entry `@anchor {anchor}` that no "
303 f"current public value claims; remove it or restore the capability"
304 )
305
306 if registry_entry.get("coverage_enforced"):
307 return (problems, [])
308 return ([], problems)
309
310
Here is the call graph for this function:
Here is the caller graph for this function:

◆ entry_body()

str audit_capability_coverage.entry_body ( str  prose,
str  anchor 
)

Return the text of one capability entry, from its anchor to the next entry.

Parameters
[in]prosePage text with code fences removed.
[in]anchorEntry anchor name.
Returns
Entry body text.

Definition at line 311 of file audit_capability_coverage.py.

311def entry_body(prose: str, anchor: str) -> str:
312 """!
313 @brief Return the text of one capability entry, from its anchor to the next entry.
314 @param[in] prose Page text with code fences removed.
315 @param[in] anchor Entry anchor name.
316 @return Entry body text.
317 """
318 match = re.search(rf"^@anchor\s+{re.escape(anchor)}\s*$", prose, re.M)
319 if not match:
320 return ""
321 rest = prose[match.end() :]
322 nxt = re.search(r"^@(?:subsection|section)\s", rest, re.M)
323 return rest[: nxt.start()] if nxt else rest
324
325
Here is the caller graph for this function:

◆ source_exists()

bool audit_capability_coverage.source_exists ( str  identifier)

Check that one evidence source identifier names something that exists.

Parameters
[in]identifierSource identifier such as make:unit-boundaries.
Returns
True when the named artifact exists.

Definition at line 330 of file audit_capability_coverage.py.

330def source_exists(identifier: str) -> bool:
331 """!
332 @brief Check that one evidence source identifier names something that exists.
333 @param[in] identifier Source identifier such as `make:unit-boundaries`.
334 @return True when the named artifact exists.
335 """
336 kind, _, value = identifier.partition(":")
337 if kind == "make":
338 makefile = (REPO_ROOT / "Makefile").read_text(encoding="utf-8")
339 return re.search(rf"^{re.escape(value)}\s*:", makefile, re.M) is not None
340 if kind in {"example", "file"}:
341 return (REPO_ROOT / value).exists()
342 if kind == "measurement":
343 return value in {record.get("id") for record in measurement_records()}
344 return False
345
346
Here is the call graph for this function:
Here is the caller graph for this function:

◆ measurement_records()

list audit_capability_coverage.measurement_records ( )

Every recorded measurement available as an evidence source.

Returns
List of measurement records.

Definition at line 347 of file audit_capability_coverage.py.

347def measurement_records() -> list:
348 """!
349 @brief Every recorded measurement available as an evidence source.
350 @return List of measurement records.
351 """
352 if not MEASUREMENTS_PATH.is_file():
353 return []
354 return json.loads(MEASUREMENTS_PATH.read_text(encoding="utf-8")).get("records", [])
355
356
Here is the caller graph for this function:

◆ check_measurement_records()

list audit_capability_coverage.check_measurement_records ( )

Verify every recorded measurement carries what a reader needs to judge it.

A measurement is cited in place of a re-runnable artifact, so the record has to stand on its own: what was asked, at what revision, on what machine and configuration, what the verdict was, and what it does not establish. A verdict of not-met or inconclusive is a legitimate record; an absent or empty field is not.

Returns
Violation lines.

Definition at line 357 of file audit_capability_coverage.py.

357def check_measurement_records() -> list:
358 """!
359 @brief Verify every recorded measurement carries what a reader needs to judge it.
360
361 @details A measurement is cited in place of a re-runnable artifact, so the record
362 has to stand on its own: what was asked, at what revision, on what
363 machine and configuration, what the verdict was, and what it does not
364 establish. A verdict of `not-met` or `inconclusive` is a legitimate
365 record; an absent or empty field is not.
366 @return Violation lines.
367 """
368 violations: list = []
369 required = ("id", "question", "date", "commit", "environment", "configuration",
370 "result", "limitations")
371 seen: set = set()
372 for index, record in enumerate(measurement_records()):
373 label = record.get("id") or f"record #{index + 1}"
374 for field in required:
375 value = record.get(field)
376 if value is None or (isinstance(value, str) and not value.strip()):
377 violations.append(f"measurement {label}: '{field}' is required and must not be empty")
378 if record.get("id") in seen:
379 violations.append(f"measurement {label}: duplicate id")
380 seen.add(record.get("id"))
381 stated = str(record.get("limitations", "")).strip().lower()
382 if stated in {"none", "n/a", "na", "-"}:
383 violations.append(
384 f"measurement {label}: 'limitations' must say what the measurement does not "
385 "establish; 'none' is not an acceptable answer"
386 )
387 verdict = (record.get("result") or {}).get("verdict") if isinstance(record.get("result"), dict) else None
388 if verdict is not None and verdict not in {"met", "not-met", "inconclusive"}:
389 violations.append(
390 f"measurement {label}: result verdict '{verdict}' is not one of "
391 "met, not-met, inconclusive"
392 )
393 return violations
394
395
Here is the call graph for this function:
Here is the caller graph for this function:

◆ source_token()

str audit_capability_coverage.source_token ( str  identifier)

The human-readable token a capability entry must cite for a declared source.

Parameters
[in]identifierSource identifier such as make:unit-boundaries.
Returns
The bare target, example directory, or file path.

Definition at line 396 of file audit_capability_coverage.py.

396def source_token(identifier: str) -> str:
397 """!
398 @brief The human-readable token a capability entry must cite for a declared source.
399 @param[in] identifier Source identifier such as `make:unit-boundaries`.
400 @return The bare target, example directory, or file path.
401 """
402 _, _, value = identifier.partition(":")
403 return value
404
405
Here is the caller graph for this function:

◆ check_evidence()

list[str] audit_capability_coverage.check_evidence ( dict  family,
dict  registry_entry,
dict  facets 
)

Verify declared evidence sources exist and are cited by the capability entry.

This checks correspondence, not scientific validity. It establishes that a declared source names something real and that the entry a reader sees cites the same source the registry does. It cannot establish that the source actually demonstrates the claimed result - that remains a human review judgement, which is why these are described as declared evidence sources rather than verified evidence.

Parameters
[in]familyInventory record for one family.
[in]registry_entryRegistry entry carrying value metadata.
[in]facetsThe project-wide facet vocabulary.
Returns
Violation lines.

Definition at line 406 of file audit_capability_coverage.py.

406def check_evidence(family: dict, registry_entry: dict, facets: dict) -> list[str]:
407 """!
408 @brief Verify declared evidence sources exist and are cited by the capability entry.
409
410 This checks *correspondence*, not scientific validity. It establishes that a
411 declared source names something real and that the entry a reader sees cites the
412 same source the registry does. It cannot establish that the source actually
413 demonstrates the claimed result - that remains a human review judgement, which is
414 why these are described as declared evidence sources rather than verified evidence.
415 @param[in] family Inventory record for one family.
416 @param[in] registry_entry Registry entry carrying value metadata.
417 @param[in] facets The project-wide facet vocabulary.
418 @return Violation lines.
419 """
420 page = REPO_ROOT / "docs" / "pages" / f"{registry_entry['family_page']}.md"
421 prose = strip_non_prose(page.read_text(encoding="utf-8")) if page.is_file() else ""
422 violations: list[str] = []
423 for name, meta in sorted(registry_entry.get("value_metadata", {}).items()):
424 if meta.get("spelling_of") or meta.get("alias_of"):
425 if "evidence" in meta:
426 violations.append(
427 f"{family['id']}: '{name}' is a spelling/alias and must not carry its own evidence"
428 )
429 continue
430 evidence = meta.get("evidence")
431 if evidence is None:
432 violations.append(f"{family['id']}: '{name}' declares no evidence mapping (use {{}} for none)")
433 continue
434 for facet, sources in sorted(evidence.items()):
435 if facet not in facets:
436 violations.append(
437 f"{family['id']}: '{name}' claims unknown evidence facet '{facet}'; "
438 f"vocabulary is {sorted(facets)}"
439 )
440 continue
441 if not sources:
442 violations.append(f"{family['id']}: '{name}' claims '{facet}' with no source identifier")
443 for source in sources:
444 if not source_exists(source):
445 violations.append(
446 f"{family['id']}: '{name}' cites '{source}' for '{facet}', which does not exist"
447 )
448 # Correspondence: the entry a reader sees must cite the sources the registry
449 # declares, or the two records drift apart silently.
450 if evidence:
451 anchor = registry_entry["entry_anchor_prefix"] + slug(name)
452 body = entry_body(prose, anchor)
453 if body:
454 section = body.split("**Evidence.**", 1)
455 evidence_text = section[1] if len(section) > 1 else ""
456 for facet, sources in sorted(evidence.items()):
457 for source in sources:
458 token = source_token(source)
459 if token not in evidence_text:
460 violations.append(
461 f"{family['id']}: '{name}' declares '{source}' for '{facet}', "
462 f"but its entry's Evidence part does not cite '{token}'"
463 )
464 if meta.get("status") == "supported" and not evidence:
465 violations.append(
466 f"{family['id']}: '{name}' is marked supported but claims no evidence; "
467 f"either record a facet or lower the status"
468 )
469 return violations
470
471
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_scope_records()

list[str] audit_capability_coverage.check_scope_records ( )

Verify every known-defective scope record is disclosed where it claims to be.

A safety valve that nothing reads is not a safety valve. This makes the scope records load-bearing: a record marked known-defective must either name the pages that disclose it and have them actually say so, or be resolved.

Returns
Violation lines.

Definition at line 472 of file audit_capability_coverage.py.

472def check_scope_records() -> list[str]:
473 """!
474 @brief Verify every known-defective scope record is disclosed where it claims to be.
475
476 A safety valve that nothing reads is not a safety valve. This makes the scope
477 records load-bearing: a record marked known-defective must either name the pages
478 that disclose it and have them actually say so, or be resolved.
479 @return Violation lines.
480 """
481 if not SCOPE_RECORDS_PATH.is_file():
482 return []
483 records = json.loads(SCOPE_RECORDS_PATH.read_text(encoding="utf-8")).get("records", [])
484 violations: list[str] = []
485 for record in records:
486 if record.get("status") != "known-defective":
487 continue
488 policy = record.get("publication_policy")
489 if policy == "disclose-now":
490 surfaces = record.get("disclosed_at", [])
491 if not surfaces:
492 violations.append(
493 f"scope record '{record['id']}' is known-defective with policy disclose-now "
494 f"but names no disclosure surfaces"
495 )
496 for surface in surfaces:
497 path = REPO_ROOT / surface.split(" ")[0]
498 if not path.is_file():
499 violations.append(f"scope record '{record['id']}' names missing surface {path.name}")
500 elif "known-defective" not in path.read_text(encoding="utf-8"):
501 violations.append(
502 f"scope record '{record['id']}' claims disclosure in {path.name}, "
503 f"but that page contains no known-defective disclosure"
504 )
505 elif policy == "scope-only":
506 condition = record.get("activation_condition", {})
507 if not condition.get("surfaces"):
508 violations.append(
509 f"scope record '{record['id']}' is scope-only but names no activation surfaces"
510 )
511 else:
512 violations.append(
513 f"scope record '{record['id']}' has unknown publication_policy '{policy}'"
514 )
515 return violations
516
517
518# Closed lifecycle vocabulary. A status outside this set is a violation, not an
519# unrecognized value that silently loses its obligations.
Here is the caller graph for this function:

◆ check_lifecycle_requirements()

list audit_capability_coverage.check_lifecycle_requirements ( dict  family,
dict  registry_entry 
)

Enforce the documentation each lifecycle status owes.

Requirements grow with the status a capability claims: supported owes evidence, experimental and known-defective owe stated limitations, and deprecated owes migration guidance. The gate fires when a value claims a status, which is the moment the claim becomes readable.

Parameters
[in]familyInventory record for one family.
[in]registry_entryRegistry entry carrying value metadata and the page.
Returns
Violation lines.

Definition at line 537 of file audit_capability_coverage.py.

537def check_lifecycle_requirements(family: dict, registry_entry: dict) -> list:
538 """!
539 @brief Enforce the documentation each lifecycle status owes.
540
541 @details Requirements grow with the status a capability claims: `supported` owes
542 evidence, `experimental` and `known-defective` owe stated limitations, and
543 `deprecated` owes migration guidance. The gate fires when a value claims a
544 status, which is the moment the claim becomes readable.
545 @param[in] family Inventory record for one family.
546 @param[in] registry_entry Registry entry carrying value metadata and the page.
547 @return Violation lines.
548 """
549 page = REPO_ROOT / "docs" / "pages" / f"{registry_entry['family_page']}.md"
550 if not page.is_file():
551 return []
552 prose = strip_non_prose(page.read_text(encoding="utf-8"))
553 prefix = registry_entry["entry_anchor_prefix"]
554 violations: list = []
555 for name, meta in sorted(registry_entry.get("value_metadata", {}).items()):
556 if meta.get("spelling_of"):
557 continue
558 # Use the effective status the generated inventory displays, so the obligation
559 # and the rendered claim can never disagree.
560 effective = family["public_values"].get(name, {}).get("status") or meta.get("status")
561 required = LIFECYCLE_REQUIREMENTS.get(effective)
562 if not required:
563 continue
564 body = entry_body(prose, prefix + slug(name))
565 if not body:
566 continue # coverage check already reports a missing entry
567 for field in required:
568 if not re.search(rf"\*\*{re.escape(field)}", body):
569 violations.append(
570 f"{family['id']}: '{name}' is {effective} but its entry has no "
571 f"**{field}** part; that status owes it"
572 )
573 return violations
574
575
Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int audit_capability_coverage.main ( )

Fail on capability parity breaks, metadata drift, or missing entries.

Returns
Process status code.

Definition at line 576 of file audit_capability_coverage.py.

576def main() -> int:
577 """!
578 @brief Fail on capability parity breaks, metadata drift, or missing entries.
579 @return Process status code.
580 """
581 registry_doc = json.loads(REGISTRY_PATH.read_text(encoding="utf-8"))
582 registry = {f["id"]: f for f in registry_doc["families"]}
583 facets = registry_doc["evidence_facets"]
584 if not INVENTORY_PATH.is_file():
585 print("Capability inventory has not been generated; run 'make docs-inventory'.", file=sys.stderr)
586 return 1
587 inventory = json.loads(INVENTORY_PATH.read_text(encoding="utf-8"))
588
589 blocking = check_generated_current() + check_scope_records() + check_measurement_records()
590 advisory: list[str] = []
591 for family in inventory:
592 entry = registry[family["id"]]
593 blocking += check_parity(family)
594 blocking += check_metadata(family, entry)
595 blocking += check_evidence(family, entry, facets)
596 blocking += check_lifecycle_requirements(family, entry)
597 family_blocking, family_advisory = check_coverage(family, entry, list(registry.values()))
598 blocking += family_blocking
599 advisory += family_advisory
600
601 if advisory:
602 print("Capability documentation coverage (advisory, backfill pending):")
603 for note in advisory:
604 print(f" {note}")
605 print("")
606
607 if blocking:
608 print("Capability parity/coverage violations:", file=sys.stderr)
609 for violation in blocking:
610 print(f" {violation}", file=sys.stderr)
611 return 1
612
613 enforced = sorted(f["id"] for f in registry.values() if f.get("coverage_enforced"))
614 pending = sorted(f["id"] for f in registry.values() if not f.get("coverage_enforced"))
615 selectable = alias = spelling = latent = 0
616 for family in inventory:
617 for spec in family["public_values"].values():
618 if spec.get("reachability") == "latent":
619 latent += 1
620 elif spec.get("alias_of"):
621 alias += 1
622 elif spec.get("spelling_of"):
623 spelling += 1
624 else:
625 selectable += 1
626 print(
627 f"Capability audit passed: {len(inventory)} families; "
628 f"{selectable} canonical values, {spelling} accepted spelling, "
629 f"{alias} deprecated alias, {latent} latent; "
630 f"full-chain parity verified."
631 )
632 print(f" coverage enforced: {', '.join(enforced) or 'none'}")
633 if pending:
634 print(f" coverage advisory (backfill pending): {', '.join(pending)}")
635 return 0
636
637
int main(int argc, char **argv)
Entry point for the postprocessor executable.
Head of a generic C-style linked list.
Definition variables.h:475
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ REPO_ROOT

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

Definition at line 13 of file audit_capability_coverage.py.

◆ REGISTRY_PATH

str audit_capability_coverage.REGISTRY_PATH = REPO_ROOT / "tests" / "tooling" / "capability_families.json"

Definition at line 14 of file audit_capability_coverage.py.

◆ INVENTORY_PATH

str audit_capability_coverage.INVENTORY_PATH = REPO_ROOT / "docs" / "generated" / "capability_inventory.json"

Definition at line 15 of file audit_capability_coverage.py.

◆ GENERATOR

str audit_capability_coverage.GENERATOR = REPO_ROOT / "tests" / "tooling" / "generate_capability_inventory.py"

Definition at line 16 of file audit_capability_coverage.py.

◆ CANONICAL_FIELDS

tuple audit_capability_coverage.CANONICAL_FIELDS
Initial value:
1= (
2 "Identity",
3 "What it does",
4 "When to choose it",
5 "Parameters it owns",
6 "Interactions",
7 "Diagnostics",
8 "Evidence",
9 "Limitations",
10)

Definition at line 18 of file audit_capability_coverage.py.

◆ ALIAS_FIELDS

tuple audit_capability_coverage.ALIAS_FIELDS = ("Identity", "Status", "Migration")

Definition at line 28 of file audit_capability_coverage.py.

◆ SCOPE_RECORDS_PATH

str audit_capability_coverage.SCOPE_RECORDS_PATH = REPO_ROOT / "tests" / "tooling" / "capability_scope_records.json"

Definition at line 326 of file audit_capability_coverage.py.

◆ MEASUREMENTS_PATH

str audit_capability_coverage.MEASUREMENTS_PATH = REPO_ROOT / "tests" / "tooling" / "measurement_records.json"

Definition at line 327 of file audit_capability_coverage.py.

◆ VALID_STATUSES

tuple audit_capability_coverage.VALID_STATUSES
Initial value:
1= (
2 "supported", "experimental", "known-defective", "deprecated",
3 "planned", "internal", "removed",
4)

Definition at line 520 of file audit_capability_coverage.py.

◆ NON_SELECTABLE_STATUSES

tuple audit_capability_coverage.NON_SELECTABLE_STATUSES = ("planned", "internal", "removed")

Definition at line 527 of file audit_capability_coverage.py.

◆ LIFECYCLE_REQUIREMENTS

dict audit_capability_coverage.LIFECYCLE_REQUIREMENTS
Initial value:
1= {
2 "supported": ("Evidence",),
3 "experimental": ("Limitations",),
4 "known-defective": ("Limitations",),
5 "deprecated": ("Migration",),
6}

Definition at line 529 of file audit_capability_coverage.py.