def build_inventory(config: ArchgateConfig, result: GateResult) -> Inventory:
"""Measure the live gate result and fail if any baseline pin moved."""
arch_config = load_config(config.archcheck_config_path)
suppressed = (*result.archcheck.suppressed, *result.dry_suppressed)
layer_suppressed = [item for item in suppressed if item[0].rule == "layer-mapping"]
exception_counts = {
entry_id: sum(1 for _, matched_id in suppressed if matched_id == entry_id)
for entry_id in ("EXC-2026-001", "EXC-2026-004")
}
legacy_entry = entry(result, "EXC-2026-001")
package_counts = {
target: sum(
1
for violation, entry_id in layer_suppressed
if entry_id == legacy_entry.id and plain_target_matches(target, violation.modules)
)
for target in legacy_entry.targets
}
live_modules = set(result.archcheck.modules)
baseline_modules = _modules_at_commit(config.repo_root, PINNED_BASELINE.measured_commit)
excluded_modules = sorted(live_modules - baseline_modules)
removed_modules = sorted(baseline_modules - live_modules)
expected_excluded_modules = [
"symfonic.devtools.archgate.baseline",
"symfonic.devtools.archgate.inventory",
"symfonic.devtools.archgate.ratchet",
]
if excluded_modules != expected_excluded_modules:
raise BaselineMismatchError(
f"post-baseline modules {excluded_modules!r} disagree with expected "
f"additions {expected_excluded_modules!r}"
)
modules_scanned_at_baseline_intersection = len(live_modules & baseline_modules)
totals: dict[str, object] = {
"all_rule_total": len(suppressed),
"layer_mapping_total": len(layer_suppressed),
"modules_scanned_at_baseline_intersection": (
modules_scanned_at_baseline_intersection
),
"per_exception": exception_counts,
}
if totals != PINNED_BASELINE.as_totals():
raise BaselineMismatchError(
f"live suppression counts {totals!r} disagree with pins "
f"{PINNED_BASELINE.as_totals()!r}"
)
if package_counts != PINNED_BASELINE.exc_2026_001_per_package:
raise BaselineMismatchError(
f"live EXC-2026-001 package counts {package_counts!r} disagree with pins "
f"{PINNED_BASELINE.exc_2026_001_per_package!r}"
)
package_sum = sum(package_counts.values())
if package_sum != PINNED_BASELINE.exc_2026_001:
raise BaselineMismatchError(
f"EXC-2026-001 package sum {package_sum} disagrees with pin "
f"{PINNED_BASELINE.exc_2026_001}"
)
content_digests = {
"archcheck.toml": _digest(config.archcheck_config_path),
"dry-exception-registry.toml": _digest(config.registry_path),
"exception-registry.toml": _digest(arch_config.registry_path),
}
if content_digests != PINNED_BASELINE.content_digests:
raise BaselineMismatchError(
f"live input digests {content_digests!r} disagree with pins "
f"{PINNED_BASELINE.content_digests!r}"
)
return {
"schema_version": 2,
"baseline_date": "2026-08-21",
"baseline_measured_commit": PINNED_BASELINE.measured_commit,
"content_digests": content_digests,
"totals": totals,
"modules_scanned_live": len(live_modules),
"modules_excluded_post_baseline": excluded_modules,
"modules_removed_since_baseline": removed_modules,
"modules_scanned_at_baseline": len(baseline_modules),
"exc_2026_001_per_package": {
"counts": dict(sorted(package_counts.items())),
"sum": package_sum,
},
"unmapped_modules": sorted(
module
for module in result.archcheck.modules
if arch_config.layer_of(module) is None
),
}