mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-24 12:42:49 +00:00
c000972ac9
Every subsystem must declare require_explicit_path_policy_coverage, so build_verification_requirements never falls back to a rule's default verification policy; an unmatched runtime file becomes a path-policy gap instead. The default test_prefixes and exact_files were therefore never consulted, yet 13 of 16 rules carried them (93 files and one prefix), and authors kept adding proofs there as if they counted. 92 of the 93 files were already proof on some path policy, and api-contracts' default prefix is on three of its own policies. The one orphan, internal/api/router_bench_test.go, benchmarks the api-contracts router rather than any performance-and-scalability runtime, so no policy should take it; it stays an owned file only. The registry drops the lists, registry_audit requires them empty and points authors at the path policy instead, and the canonical protocol says so. The protocol also stops promising same-subsystem tests "when the registry explicitly allows them", which the audit no longer permits. No verdict changes: build_verification_requirements returns identical requirements for all 2746 owned runtime paths, and for an uncovered path, under the old and new registry.
785 lines
32 KiB
Python
785 lines
32 KiB
Python
#!/usr/bin/env python3
|
|
"""Machine audit for the active release profile subsystem registry."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
from typing import Any
|
|
|
|
from canonical_completion_guard import (
|
|
REPO_ROOT,
|
|
is_ignored_runtime_file,
|
|
is_test_or_fixture,
|
|
path_policy_matches,
|
|
subsystem_matches_path,
|
|
)
|
|
from control_plane import DEFAULT_CONTROL_PLANE
|
|
from repo_file_io import canonical_repo_id, git_env, load_repo_json, repo_root_context
|
|
from status_audit import load_status_payload
|
|
|
|
|
|
REGISTRY_PATH = DEFAULT_CONTROL_PLANE["registry_path"]
|
|
REGISTRY_SCHEMA_PATH = DEFAULT_CONTROL_PLANE["registry_schema_path"]
|
|
LANE_RE = re.compile(r"^L[0-9]+$")
|
|
# Every subsystem requires explicit path-policy coverage, so the default
|
|
# verification policy is never consulted and a path policy's own proof routes
|
|
# are the whole requirement. Proofs listed on the default count for nothing,
|
|
# though authors kept adding them there as if they did; nearly all were
|
|
# already on a path policy. allow_same_subsystem_tests would widen a policy to
|
|
# every test the subsystem owns (any internal/ai test for ai-runtime's
|
|
# mutation-registry policy), and its reach would grow with ownership rather
|
|
# than with the policy. The commit guards ignored the flag from the v6 import
|
|
# until it was retired here, so false is the behaviour every commit has been
|
|
# held to.
|
|
SAME_SUBSYSTEM_TESTS_RETIRED = (
|
|
"it would accept any test the subsystem owns as proof for this policy; "
|
|
"list the accepted proofs in test_prefixes or exact_files instead"
|
|
)
|
|
DEFAULT_PROOFS_RETIRED = (
|
|
"explicit path-policy coverage never consults the subsystem default, so "
|
|
"proofs listed here count for nothing; list them on the path policy whose "
|
|
"runtime files they prove"
|
|
)
|
|
|
|
|
|
def load_registry_payload(*, staged: bool = False) -> dict[str, Any]:
|
|
return load_repo_json(REGISTRY_PATH, staged=staged)
|
|
|
|
|
|
def load_registry_schema(*, staged: bool = False) -> dict[str, Any]:
|
|
return load_repo_json(REGISTRY_SCHEMA_PATH, staged=staged)
|
|
|
|
|
|
def schema_required(schema: dict[str, Any], definition: str | None = None) -> set[str]:
|
|
target = schema if definition is None else schema["$defs"][definition]
|
|
return set(target["required"])
|
|
|
|
|
|
def registry_schema_contract(*, staged: bool = False) -> dict[str, Any]:
|
|
schema = load_registry_schema(staged=staged)
|
|
return {
|
|
"schema": schema,
|
|
"required_top_level_fields": schema_required(schema),
|
|
"required_subsystem_fields": schema_required(schema, "subsystem"),
|
|
"required_verification_fields": schema_required(schema, "verification"),
|
|
"required_path_policy_fields": schema_required(schema, "path_policy"),
|
|
"required_shared_ownership_fields": schema_required(schema, "shared_ownership"),
|
|
}
|
|
|
|
|
|
DEFAULT_REGISTRY_SCHEMA_CONTRACT = registry_schema_contract()
|
|
|
|
|
|
def sorted_casefold(values: list[str]) -> list[str]:
|
|
return sorted(values, key=lambda value: value.casefold())
|
|
|
|
|
|
def path_repository(
|
|
path: str,
|
|
*,
|
|
known_repo_ids: set[str],
|
|
local_repo: str,
|
|
) -> str:
|
|
"""Return the canonical repository that owns a registry path."""
|
|
qualifier, separator, _ = path.partition(":")
|
|
if separator and qualifier in known_repo_ids:
|
|
return qualifier
|
|
return local_repo
|
|
|
|
|
|
def path_is_in_scope(
|
|
path: str,
|
|
*,
|
|
audited_repo_ids: set[str] | None,
|
|
known_repo_ids: set[str],
|
|
local_repo: str,
|
|
) -> bool:
|
|
if audited_repo_ids is None:
|
|
return True
|
|
return path_repository(
|
|
path,
|
|
known_repo_ids=known_repo_ids,
|
|
local_repo=local_repo,
|
|
) in audited_repo_ids
|
|
|
|
|
|
def tracked_repo_files() -> set[str]:
|
|
local_repo = canonical_repo_id(REPO_ROOT)
|
|
return tracked_workspace_files(active_repos=[local_repo], local_repo=local_repo)
|
|
|
|
|
|
def tracked_workspace_files(*, active_repos: list[str], local_repo: str) -> set[str]:
|
|
files: set[str] = set()
|
|
context = repo_root_context(REPO_ROOT)
|
|
for repo_id in active_repos:
|
|
repo_root = context.execution_root if repo_id == local_repo else context.workspace_repos_root / repo_id
|
|
if not repo_root.exists():
|
|
continue
|
|
result = subprocess.run(
|
|
["git", "ls-files", "-z"],
|
|
cwd=repo_root,
|
|
check=True,
|
|
capture_output=True,
|
|
text=False,
|
|
env=git_env(repo_root, local_repo_root=REPO_ROOT),
|
|
)
|
|
for entry in result.stdout.split(b"\x00"):
|
|
if not entry:
|
|
continue
|
|
rel = entry.decode("utf-8")
|
|
files.add(rel if repo_id == local_repo else f"{repo_id}:{rel}")
|
|
|
|
# Governance files are filesystem-only (gitignored). Supplement with any
|
|
# files that exist on disk under the control-plane contracts directory so
|
|
# contract path references in the registry resolve correctly.
|
|
contracts_dir = Path(DEFAULT_CONTROL_PLANE["subsystems_dir_path"])
|
|
if contracts_dir.exists():
|
|
for f in contracts_dir.iterdir():
|
|
if f.is_file():
|
|
files.add(f.relative_to(REPO_ROOT).as_posix())
|
|
return files
|
|
|
|
|
|
def clean_relative_path(path: str) -> str:
|
|
return Path(path).as_posix()
|
|
|
|
|
|
def validate_path_reference(
|
|
path: str,
|
|
*,
|
|
context: str,
|
|
errors: list[str],
|
|
tracked_files: set[str],
|
|
require_file: bool = True,
|
|
audited_repo_ids: set[str] | None = None,
|
|
known_repo_ids: set[str] | None = None,
|
|
local_repo: str = "pulse",
|
|
) -> None:
|
|
normalized = clean_relative_path(path)
|
|
if normalized != path or path.startswith("../") or "/../" in path or Path(path).is_absolute():
|
|
errors.append(f"{context} must be a clean repo-relative path: {path!r}")
|
|
return
|
|
if not path_is_in_scope(
|
|
path,
|
|
audited_repo_ids=audited_repo_ids,
|
|
known_repo_ids=known_repo_ids or {local_repo},
|
|
local_repo=local_repo,
|
|
):
|
|
return
|
|
if require_file and path not in tracked_files:
|
|
errors.append(f"{context} missing tracked file {path!r}")
|
|
|
|
|
|
def validate_prefix(
|
|
prefix: str,
|
|
*,
|
|
context: str,
|
|
errors: list[str],
|
|
tracked_files: set[str],
|
|
audited_repo_ids: set[str] | None = None,
|
|
known_repo_ids: set[str] | None = None,
|
|
local_repo: str = "pulse",
|
|
) -> None:
|
|
normalized = clean_relative_path(prefix.rstrip("/"))
|
|
raw = prefix.rstrip("/")
|
|
if normalized != raw or raw.startswith("../") or "/../" in raw or Path(raw).is_absolute():
|
|
errors.append(f"{context} must be a clean repo-relative prefix: {prefix!r}")
|
|
return
|
|
if not path_is_in_scope(
|
|
prefix,
|
|
audited_repo_ids=audited_repo_ids,
|
|
known_repo_ids=known_repo_ids or {local_repo},
|
|
local_repo=local_repo,
|
|
):
|
|
return
|
|
if not any(path.startswith(prefix) for path in tracked_files):
|
|
errors.append(f"{context} does not match any tracked files: {prefix!r}")
|
|
|
|
|
|
def owned_runtime_files(rule: dict[str, Any], tracked_files: set[str]) -> list[str]:
|
|
return sorted(
|
|
path
|
|
for path in tracked_files
|
|
if subsystem_matches_path(rule, path)
|
|
if not is_test_or_fixture(path)
|
|
if not is_ignored_runtime_file(path)
|
|
)
|
|
|
|
|
|
def audit_registry_payload(
|
|
payload: dict[str, Any],
|
|
*,
|
|
tracked_files: set[str],
|
|
status_lane_ids: set[str],
|
|
schema_contract: dict[str, Any] | None = None,
|
|
audited_repo_ids: set[str] | None = None,
|
|
known_repo_ids: set[str] | None = None,
|
|
local_repo: str = "pulse",
|
|
) -> dict[str, Any]:
|
|
contract = schema_contract or DEFAULT_REGISTRY_SCHEMA_CONTRACT
|
|
schema = contract["schema"]
|
|
required_top_level_fields = set(contract["required_top_level_fields"])
|
|
required_subsystem_fields = set(contract["required_subsystem_fields"])
|
|
required_verification_fields = set(contract["required_verification_fields"])
|
|
required_path_policy_fields = set(contract["required_path_policy_fields"])
|
|
required_shared_ownership_fields = set(contract["required_shared_ownership_fields"])
|
|
errors: list[str] = []
|
|
warnings: list[str] = []
|
|
known_repos = known_repo_ids or {local_repo}
|
|
|
|
def in_scope(path: str) -> bool:
|
|
return path_is_in_scope(
|
|
path,
|
|
audited_repo_ids=audited_repo_ids,
|
|
known_repo_ids=known_repos,
|
|
local_repo=local_repo,
|
|
)
|
|
|
|
path_validation_scope = {
|
|
"audited_repo_ids": audited_repo_ids,
|
|
"known_repo_ids": known_repos,
|
|
"local_repo": local_repo,
|
|
}
|
|
|
|
for field in sorted(required_top_level_fields):
|
|
if field not in payload:
|
|
errors.append(f"registry.json missing required field {field}")
|
|
|
|
version = payload.get("version")
|
|
if version != schema["properties"]["version"]["const"]:
|
|
errors.append(f"registry.json version must be {schema['properties']['version']['const']}")
|
|
|
|
raw_subsystems = payload.get("subsystems")
|
|
if not isinstance(raw_subsystems, list) or not raw_subsystems:
|
|
errors.append("registry.json missing non-empty subsystems list")
|
|
return {"errors": errors, "warnings": warnings, "summary": {}}
|
|
|
|
raw_shared_ownerships = payload.get("shared_ownerships")
|
|
if not isinstance(raw_shared_ownerships, list):
|
|
errors.append("registry.json missing shared_ownerships list")
|
|
raw_shared_ownerships = []
|
|
|
|
seen_ids: set[str] = set()
|
|
seen_contracts: set[str] = set()
|
|
subsystem_summaries: list[dict[str, Any]] = []
|
|
subsystem_order: list[str] = []
|
|
|
|
for index, raw_subsystem in enumerate(raw_subsystems):
|
|
context = f"subsystems[{index}]"
|
|
if not isinstance(raw_subsystem, dict):
|
|
errors.append(f"{context} must be an object")
|
|
continue
|
|
|
|
for field in sorted(required_subsystem_fields):
|
|
if field not in raw_subsystem:
|
|
errors.append(f"{context} missing required field {field}")
|
|
|
|
subsystem_id = raw_subsystem.get("id")
|
|
if not isinstance(subsystem_id, str) or not subsystem_id.strip():
|
|
errors.append(f"{context} missing non-empty string id")
|
|
continue
|
|
if subsystem_id in seen_ids:
|
|
errors.append(f"{context} duplicates subsystem id {subsystem_id!r}")
|
|
seen_ids.add(subsystem_id)
|
|
subsystem_order.append(subsystem_id)
|
|
|
|
lane = raw_subsystem.get("lane")
|
|
if not isinstance(lane, str) or not LANE_RE.match(lane):
|
|
errors.append(f"{context} has invalid lane {lane!r}")
|
|
elif lane not in status_lane_ids:
|
|
errors.append(f"{context} references unknown status lane {lane!r}")
|
|
|
|
contract = raw_subsystem.get("contract")
|
|
if not isinstance(contract, str) or not contract.strip():
|
|
errors.append(f"{context} missing non-empty string contract")
|
|
else:
|
|
validate_path_reference(
|
|
contract,
|
|
context=f"{context}.contract",
|
|
errors=errors,
|
|
tracked_files=tracked_files,
|
|
**path_validation_scope,
|
|
)
|
|
if contract in seen_contracts:
|
|
errors.append(f"{context} duplicates contract path {contract!r}")
|
|
seen_contracts.add(contract)
|
|
|
|
owned_prefixes = raw_subsystem.get("owned_prefixes")
|
|
if not isinstance(owned_prefixes, list):
|
|
errors.append(f"{context}.owned_prefixes must be a list")
|
|
owned_prefixes = []
|
|
else:
|
|
if len(owned_prefixes) != len(set(owned_prefixes)):
|
|
errors.append(f"{context}.owned_prefixes must not contain duplicates")
|
|
if owned_prefixes != sorted_casefold(owned_prefixes):
|
|
errors.append(f"{context}.owned_prefixes must be sorted lexicographically")
|
|
for prefix_index, prefix in enumerate(owned_prefixes):
|
|
if not isinstance(prefix, str) or not prefix.strip():
|
|
errors.append(f"{context}.owned_prefixes[{prefix_index}] must be a non-empty string")
|
|
continue
|
|
validate_prefix(
|
|
prefix,
|
|
context=f"{context}.owned_prefixes[{prefix_index}]",
|
|
errors=errors,
|
|
tracked_files=tracked_files,
|
|
**path_validation_scope,
|
|
)
|
|
|
|
owned_files = raw_subsystem.get("owned_files")
|
|
if not isinstance(owned_files, list):
|
|
errors.append(f"{context}.owned_files must be a list")
|
|
owned_files = []
|
|
else:
|
|
if len(owned_files) != len(set(owned_files)):
|
|
errors.append(f"{context}.owned_files must not contain duplicates")
|
|
if owned_files != sorted_casefold(owned_files):
|
|
errors.append(f"{context}.owned_files must be sorted lexicographically")
|
|
for file_index, path in enumerate(owned_files):
|
|
if not isinstance(path, str) or not path.strip():
|
|
errors.append(f"{context}.owned_files[{file_index}] must be a non-empty string")
|
|
continue
|
|
validate_path_reference(
|
|
path,
|
|
context=f"{context}.owned_files[{file_index}]",
|
|
errors=errors,
|
|
tracked_files=tracked_files,
|
|
**path_validation_scope,
|
|
)
|
|
|
|
verification = raw_subsystem.get("verification")
|
|
if not isinstance(verification, dict):
|
|
errors.append(f"{context}.verification must be an object")
|
|
continue
|
|
for field in sorted(required_verification_fields):
|
|
if field not in verification:
|
|
errors.append(f"{context}.verification missing required field {field}")
|
|
|
|
if not isinstance(verification.get("allow_same_subsystem_tests"), bool):
|
|
errors.append(f"{context}.verification.allow_same_subsystem_tests must be a bool")
|
|
elif verification.get("allow_same_subsystem_tests") is True:
|
|
errors.append(
|
|
f"{context}.verification.allow_same_subsystem_tests must be false: "
|
|
+ SAME_SUBSYSTEM_TESTS_RETIRED
|
|
)
|
|
if not isinstance(verification.get("require_explicit_path_policy_coverage"), bool):
|
|
errors.append(f"{context}.verification.require_explicit_path_policy_coverage must be a bool")
|
|
elif verification.get("require_explicit_path_policy_coverage") is not True:
|
|
errors.append(f"{context}.verification.require_explicit_path_policy_coverage must be true")
|
|
|
|
for field in ("test_prefixes", "exact_files"):
|
|
default_proofs = verification.get(field)
|
|
if not isinstance(default_proofs, list):
|
|
errors.append(f"{context}.verification.{field} must be a list")
|
|
elif default_proofs:
|
|
errors.append(
|
|
f"{context}.verification.{field} must be empty: " + DEFAULT_PROOFS_RETIRED
|
|
)
|
|
|
|
path_policies = verification.get("path_policies")
|
|
if not isinstance(path_policies, list):
|
|
errors.append(f"{context}.verification.path_policies must be a list")
|
|
path_policies = []
|
|
|
|
seen_policy_ids: set[str] = set()
|
|
valid_policies: list[tuple[str, dict[str, Any]]] = []
|
|
for policy_index, raw_policy in enumerate(path_policies):
|
|
policy_context = f"{context}.verification.path_policies[{policy_index}]"
|
|
if not isinstance(raw_policy, dict):
|
|
errors.append(f"{policy_context} must be an object")
|
|
continue
|
|
|
|
for field in sorted(required_path_policy_fields):
|
|
if field not in raw_policy:
|
|
errors.append(f"{policy_context} missing required field {field}")
|
|
|
|
policy_id = raw_policy.get("id")
|
|
if not isinstance(policy_id, str) or not policy_id.strip():
|
|
errors.append(f"{policy_context} missing non-empty string id")
|
|
elif policy_id in seen_policy_ids:
|
|
errors.append(f"{policy_context} duplicates policy id {policy_id!r}")
|
|
else:
|
|
seen_policy_ids.add(policy_id)
|
|
|
|
label = raw_policy.get("label")
|
|
if not isinstance(label, str) or not label.strip():
|
|
errors.append(f"{policy_context} missing non-empty string label")
|
|
|
|
match_prefixes = raw_policy.get("match_prefixes")
|
|
if not isinstance(match_prefixes, list):
|
|
errors.append(f"{policy_context}.match_prefixes must be a list")
|
|
match_prefixes = []
|
|
else:
|
|
if len(match_prefixes) != len(set(match_prefixes)):
|
|
errors.append(f"{policy_context}.match_prefixes must not contain duplicates")
|
|
if match_prefixes != sorted_casefold(match_prefixes):
|
|
errors.append(f"{policy_context}.match_prefixes must be sorted lexicographically")
|
|
match_files = raw_policy.get("match_files")
|
|
if not isinstance(match_files, list):
|
|
errors.append(f"{policy_context}.match_files must be a list")
|
|
match_files = []
|
|
else:
|
|
if len(match_files) != len(set(match_files)):
|
|
errors.append(f"{policy_context}.match_files must not contain duplicates")
|
|
if match_files != sorted_casefold(match_files):
|
|
errors.append(f"{policy_context}.match_files must be sorted lexicographically")
|
|
if not match_prefixes and not match_files:
|
|
errors.append(f"{policy_context} must define at least one match_prefix or match_file")
|
|
|
|
for prefix_index, prefix in enumerate(match_prefixes):
|
|
if not isinstance(prefix, str) or not prefix.strip():
|
|
errors.append(f"{policy_context}.match_prefixes[{prefix_index}] must be a non-empty string")
|
|
continue
|
|
validate_prefix(
|
|
prefix,
|
|
context=f"{policy_context}.match_prefixes[{prefix_index}]",
|
|
errors=errors,
|
|
tracked_files=tracked_files,
|
|
**path_validation_scope,
|
|
)
|
|
|
|
for file_index, path in enumerate(match_files):
|
|
if not isinstance(path, str) or not path.strip():
|
|
errors.append(f"{policy_context}.match_files[{file_index}] must be a non-empty string")
|
|
continue
|
|
validate_path_reference(
|
|
path,
|
|
context=f"{policy_context}.match_files[{file_index}]",
|
|
errors=errors,
|
|
tracked_files=tracked_files,
|
|
**path_validation_scope,
|
|
)
|
|
|
|
if not isinstance(raw_policy.get("allow_same_subsystem_tests"), bool):
|
|
errors.append(f"{policy_context}.allow_same_subsystem_tests must be a bool")
|
|
elif raw_policy.get("allow_same_subsystem_tests") is True:
|
|
errors.append(
|
|
f"{policy_context}.allow_same_subsystem_tests must be false: "
|
|
+ SAME_SUBSYSTEM_TESTS_RETIRED
|
|
)
|
|
|
|
policy_test_prefixes = raw_policy.get("test_prefixes")
|
|
if not isinstance(policy_test_prefixes, list):
|
|
errors.append(f"{policy_context}.test_prefixes must be a list")
|
|
policy_test_prefixes = []
|
|
else:
|
|
if len(policy_test_prefixes) != len(set(policy_test_prefixes)):
|
|
errors.append(f"{policy_context}.test_prefixes must not contain duplicates")
|
|
if policy_test_prefixes != sorted_casefold(policy_test_prefixes):
|
|
errors.append(f"{policy_context}.test_prefixes must be sorted lexicographically")
|
|
for prefix_index, prefix in enumerate(policy_test_prefixes):
|
|
if not isinstance(prefix, str) or not prefix.strip():
|
|
errors.append(f"{policy_context}.test_prefixes[{prefix_index}] must be a non-empty string")
|
|
continue
|
|
validate_prefix(
|
|
prefix,
|
|
context=f"{policy_context}.test_prefixes[{prefix_index}]",
|
|
errors=errors,
|
|
tracked_files=tracked_files,
|
|
**path_validation_scope,
|
|
)
|
|
|
|
policy_exact_files = raw_policy.get("exact_files")
|
|
if not isinstance(policy_exact_files, list):
|
|
errors.append(f"{policy_context}.exact_files must be a list")
|
|
policy_exact_files = []
|
|
else:
|
|
if len(policy_exact_files) != len(set(policy_exact_files)):
|
|
errors.append(f"{policy_context}.exact_files must not contain duplicates")
|
|
if policy_exact_files != sorted_casefold(policy_exact_files):
|
|
errors.append(f"{policy_context}.exact_files must be sorted lexicographically")
|
|
for file_index, path in enumerate(policy_exact_files):
|
|
if not isinstance(path, str) or not path.strip():
|
|
errors.append(f"{policy_context}.exact_files[{file_index}] must be a non-empty string")
|
|
continue
|
|
validate_path_reference(
|
|
path,
|
|
context=f"{policy_context}.exact_files[{file_index}]",
|
|
errors=errors,
|
|
tracked_files=tracked_files,
|
|
**path_validation_scope,
|
|
)
|
|
|
|
valid_policies.append((policy_context, raw_policy))
|
|
|
|
owned_runtime = owned_runtime_files(raw_subsystem, tracked_files)
|
|
previous_policies: list[dict[str, Any]] = []
|
|
for policy_context, policy in valid_policies:
|
|
policy_match_paths = list(policy.get("match_prefixes", [])) + list(
|
|
policy.get("match_files", [])
|
|
)
|
|
if audited_repo_ids is not None and not any(in_scope(path) for path in policy_match_paths):
|
|
continue
|
|
policy_fully_in_scope = audited_repo_ids is None or all(
|
|
in_scope(path) for path in policy_match_paths
|
|
)
|
|
matched_owned_runtime = [path for path in owned_runtime if path_policy_matches(policy, path)]
|
|
if not matched_owned_runtime:
|
|
if policy_fully_in_scope:
|
|
errors.append(f"{policy_context} does not match any owned runtime files")
|
|
previous_policies.append(policy)
|
|
continue
|
|
if policy_fully_in_scope and previous_policies and all(
|
|
any(path_policy_matches(previous_policy, path) for previous_policy in previous_policies)
|
|
for path in matched_owned_runtime
|
|
):
|
|
errors.append(
|
|
f"{policy_context} is unreachable because earlier path policies already match all owned runtime files"
|
|
)
|
|
previous_policies.append(policy)
|
|
|
|
uncovered_owned_runtime = [
|
|
path
|
|
for path in owned_runtime
|
|
if not any(path_policy_matches(policy, path) for _, policy in valid_policies)
|
|
]
|
|
|
|
if uncovered_owned_runtime:
|
|
for path in uncovered_owned_runtime:
|
|
errors.append(
|
|
f"{context} requires explicit path policy coverage but {path!r} falls back to default verification"
|
|
)
|
|
|
|
subsystem_summaries.append(
|
|
{
|
|
"id": subsystem_id,
|
|
"lane": lane,
|
|
"owned_runtime_file_count": len(owned_runtime),
|
|
"default_fallback_count": len(uncovered_owned_runtime),
|
|
"path_policy_count": len(path_policies),
|
|
}
|
|
)
|
|
|
|
if subsystem_order != sorted_casefold(subsystem_order):
|
|
errors.append("registry.json subsystems must be sorted by subsystem id")
|
|
|
|
overlap_index: dict[str, list[str]] = {}
|
|
for raw_subsystem in raw_subsystems:
|
|
if not isinstance(raw_subsystem, dict):
|
|
continue
|
|
subsystem_id = raw_subsystem.get("id")
|
|
if not isinstance(subsystem_id, str) or not subsystem_id.strip():
|
|
continue
|
|
for path in owned_runtime_files(raw_subsystem, tracked_files):
|
|
overlap_index.setdefault(path, []).append(subsystem_id)
|
|
actual_shared_ownership = {
|
|
path: sorted_casefold(subsystems)
|
|
for path, subsystems in overlap_index.items()
|
|
if len(subsystems) > 1
|
|
}
|
|
|
|
seen_shared_paths: set[str] = set()
|
|
declared_shared_paths: list[str] = []
|
|
scoped_declared_shared_paths: list[str] = []
|
|
for index, raw_shared in enumerate(raw_shared_ownerships):
|
|
context = f"shared_ownerships[{index}]"
|
|
if not isinstance(raw_shared, dict):
|
|
errors.append(f"{context} must be an object")
|
|
continue
|
|
for field in sorted(required_shared_ownership_fields):
|
|
if field not in raw_shared:
|
|
errors.append(f"{context} missing required field {field}")
|
|
|
|
path = raw_shared.get("path")
|
|
if not isinstance(path, str) or not path.strip():
|
|
errors.append(f"{context}.path must be a non-empty string")
|
|
continue
|
|
declared_shared_paths.append(path)
|
|
if in_scope(path):
|
|
scoped_declared_shared_paths.append(path)
|
|
validate_path_reference(
|
|
path,
|
|
context=f"{context}.path",
|
|
errors=errors,
|
|
tracked_files=tracked_files,
|
|
**path_validation_scope,
|
|
)
|
|
if path in seen_shared_paths:
|
|
errors.append(f"{context}.path duplicates shared ownership entry for {path!r}")
|
|
seen_shared_paths.add(path)
|
|
|
|
rationale = raw_shared.get("rationale")
|
|
if not isinstance(rationale, str) or not rationale.strip():
|
|
errors.append(f"{context}.rationale must be a non-empty string")
|
|
|
|
subsystems = raw_shared.get("subsystems")
|
|
normalized_subsystems: list[str] = []
|
|
if not isinstance(subsystems, list):
|
|
errors.append(f"{context}.subsystems must be a list")
|
|
subsystems = []
|
|
else:
|
|
if len(subsystems) != len(set(subsystems)):
|
|
errors.append(f"{context}.subsystems must not contain duplicates")
|
|
for subsystem_index, subsystem_id in enumerate(subsystems):
|
|
if not isinstance(subsystem_id, str) or not subsystem_id.strip():
|
|
errors.append(f"{context}.subsystems[{subsystem_index}] must be a non-empty string")
|
|
continue
|
|
normalized_subsystems.append(subsystem_id)
|
|
if subsystem_id not in seen_ids:
|
|
errors.append(f"{context}.subsystems[{subsystem_index}] references unknown subsystem {subsystem_id!r}")
|
|
if normalized_subsystems != sorted_casefold(normalized_subsystems):
|
|
errors.append(f"{context}.subsystems must be sorted lexicographically")
|
|
|
|
if not in_scope(path):
|
|
continue
|
|
|
|
actual = actual_shared_ownership.get(path)
|
|
if actual is None:
|
|
errors.append(f"{context}.path = {path!r} is not an actual shared-owned runtime file")
|
|
elif normalized_subsystems and normalized_subsystems != actual:
|
|
errors.append(f"{context}.subsystems = {normalized_subsystems!r}, want {actual!r}")
|
|
|
|
if declared_shared_paths != sorted_casefold(declared_shared_paths):
|
|
errors.append("registry.json shared_ownerships must be sorted by path")
|
|
|
|
declared_shared_ownership = set(scoped_declared_shared_paths)
|
|
for path in sorted(set(actual_shared_ownership) - declared_shared_ownership, key=str.casefold):
|
|
errors.append(
|
|
f"registry.json missing shared ownership entry for {path!r} owned by {actual_shared_ownership[path]!r}"
|
|
)
|
|
for path in sorted(declared_shared_ownership - set(actual_shared_ownership), key=str.casefold):
|
|
errors.append(f"registry.json shared ownership entry for {path!r} is stale")
|
|
|
|
return {
|
|
"errors": errors,
|
|
"warnings": warnings,
|
|
"summary": {
|
|
"shared_ownership_count": len(actual_shared_ownership),
|
|
"subsystem_count": len(subsystem_summaries),
|
|
"explicit_coverage_subsystems": sum(
|
|
1
|
|
for subsystem in raw_subsystems
|
|
if isinstance(subsystem, dict)
|
|
and isinstance(subsystem.get("verification"), dict)
|
|
and subsystem["verification"].get("require_explicit_path_policy_coverage") is True
|
|
),
|
|
},
|
|
"subsystems": subsystem_summaries,
|
|
}
|
|
|
|
|
|
def parse_args(argv: list[str]) -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description="Audit the active release profile subsystem registry.")
|
|
parser.add_argument(
|
|
"--check",
|
|
action="store_true",
|
|
help="Exit non-zero if the registry audit finds any errors.",
|
|
)
|
|
parser.add_argument(
|
|
"--pretty",
|
|
action="store_true",
|
|
help="Print a concise human-readable summary instead of JSON.",
|
|
)
|
|
parser.add_argument(
|
|
"--staged",
|
|
action="store_true",
|
|
help="Read registry control files from the git index instead of the working tree.",
|
|
)
|
|
parser.add_argument(
|
|
"--repo-scope",
|
|
action="append",
|
|
default=[],
|
|
metavar="REPO_ID",
|
|
help=(
|
|
"Audit paths for one available repository. Repeat to audit multiple "
|
|
"repositories; the default audits the complete active profile."
|
|
),
|
|
)
|
|
return parser.parse_args(argv)
|
|
|
|
|
|
def render_pretty(report: dict[str, Any]) -> str:
|
|
lines: list[str] = []
|
|
summary = report.get("summary", {})
|
|
if summary:
|
|
lines.append(
|
|
"summary: "
|
|
f"subsystems={summary.get('subsystem_count', 0)} "
|
|
f"shared_ownerships={summary.get('shared_ownership_count', 0)} "
|
|
f"explicit_coverage={summary.get('explicit_coverage_subsystems', 0)}"
|
|
)
|
|
for subsystem in report.get("subsystems", []):
|
|
lines.append(
|
|
f"{subsystem['id']}: lane={subsystem['lane']} "
|
|
f"owned_runtime={subsystem['owned_runtime_file_count']} "
|
|
f"default_fallback={subsystem['default_fallback_count']} "
|
|
f"path_policies={subsystem['path_policy_count']}"
|
|
)
|
|
if report.get("warnings"):
|
|
lines.append("warnings:")
|
|
for warning in report["warnings"]:
|
|
lines.append(f" - {warning}")
|
|
if report.get("errors"):
|
|
lines.append("errors:")
|
|
for err in report["errors"]:
|
|
lines.append(f" - {err}")
|
|
return "\n".join(lines)
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
args = parse_args(list(argv or []))
|
|
status_payload = load_status_payload(staged=args.staged)
|
|
scope = status_payload.get("scope", {})
|
|
active_repos = [
|
|
repo_id
|
|
for repo_id in scope.get("active_repos", [])
|
|
if isinstance(repo_id, str) and repo_id.strip()
|
|
] or [canonical_repo_id(REPO_ROOT)]
|
|
local_repo = canonical_repo_id(REPO_ROOT)
|
|
requested_repos = args.repo_scope or active_repos
|
|
scope_errors: list[str] = []
|
|
if len(requested_repos) != len(set(requested_repos)):
|
|
scope_errors.append("--repo-scope must not contain duplicate repository ids")
|
|
unknown_repos = sorted(set(requested_repos) - set(active_repos), key=str.casefold)
|
|
if unknown_repos:
|
|
scope_errors.append(
|
|
"--repo-scope contains repositories outside the active profile: "
|
|
+ ", ".join(unknown_repos)
|
|
)
|
|
if local_repo not in requested_repos:
|
|
scope_errors.append(f"--repo-scope must include the local control-plane repository {local_repo!r}")
|
|
|
|
context = repo_root_context(REPO_ROOT)
|
|
missing_repos = [
|
|
repo_id
|
|
for repo_id in requested_repos
|
|
if not (
|
|
context.execution_root
|
|
if repo_id == local_repo
|
|
else context.workspace_repos_root / repo_id
|
|
).is_dir()
|
|
]
|
|
if missing_repos:
|
|
scope_errors.append(
|
|
"registry audit requires unavailable repository checkout(s): "
|
|
+ ", ".join(missing_repos)
|
|
)
|
|
lane_ids = {
|
|
lane.get("id")
|
|
for lane in status_payload.get("lanes", [])
|
|
if isinstance(lane, dict) and isinstance(lane.get("id"), str)
|
|
}
|
|
report = audit_registry_payload(
|
|
load_registry_payload(staged=args.staged),
|
|
tracked_files=tracked_workspace_files(active_repos=requested_repos, local_repo=local_repo),
|
|
status_lane_ids=lane_ids,
|
|
schema_contract=registry_schema_contract(staged=args.staged),
|
|
audited_repo_ids=set(requested_repos) if args.repo_scope else None,
|
|
known_repo_ids=set(active_repos),
|
|
local_repo=local_repo,
|
|
)
|
|
report["errors"] = scope_errors + report["errors"]
|
|
output = render_pretty(report) if args.pretty else json.dumps(report, indent=2, sort_keys=True)
|
|
print(output)
|
|
if args.check and report["errors"]:
|
|
return 1
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main(sys.argv[1:]))
|