generated from coulomb/repo-seed
feat(connectors): complete ATLAS-WP-0003 — discovery connectors (Phase 2)
Some checks failed
validate-registry / validate (push) Has been cancelled
Some checks failed
validate-registry / validate (push) Has been cancelled
T01 connector_base + docs/discovery-connectors.md (read-only/stateless, candidate->PR->promote; `candidate` added to schema status enum; candidates/ gitignored, excluded from gate). T02 connector_reposcoping (repo-scoping facts -> candidates; graceful degrade). T03 connector_gitconfig (deterministic scan; real .env -> secret-ref, no values; verified 4 real candidates from ~/state-hub). T04 connector_featurecontrol (feature-flag surfaces linking to feature-control keys, no eval logic; FR-12). T05 registry_health (unowned + stale detection). Make targets: connect-gitconfig/reposcoping/featurecontrol, registry-health. WP-0003 finished (5/5). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
84
tools/registry_health.py
Normal file
84
tools/registry_health.py
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Registry health: stale & unowned surface detection (ATLAS-WP-0003-T05).
|
||||
|
||||
Reports promoted surfaces that need attention:
|
||||
- unowned : missing owner, or owner not resolvable to a known identity
|
||||
- stale : evidence.last_seen older than --max-age-days (default 180), or absent
|
||||
|
||||
Ownership resolution uses reuse-surface's local-repo-roster as a stand-in for
|
||||
domain-tree identities (until domain-tree binding is wired, ATLAS-WP-0002 follow-up).
|
||||
|
||||
Usage:
|
||||
python3 tools/registry_health.py [--max-age-days N] [--strict]
|
||||
make registry-health
|
||||
Exit 0 normally; 1 when --strict and any issue is found.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime as _dt
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ImportError as exc: # pragma: no cover
|
||||
raise SystemExit(f"setup error: missing PyYAML ({exc})")
|
||||
|
||||
from effective_config import SURFACES_DIR, load_entry
|
||||
|
||||
ROSTER = Path.home() / "reuse-surface" / "registry" / "federation" / "local-repo-roster.yaml"
|
||||
|
||||
|
||||
def known_owners() -> set[str]:
|
||||
owners = {"custodian"} # State Hub domain identity not in the repo roster
|
||||
if ROSTER.exists():
|
||||
data = yaml.safe_load(ROSTER.read_text()) or {}
|
||||
owners |= {r.get("slug") for r in data.get("repos", []) if r.get("slug")}
|
||||
return owners
|
||||
|
||||
|
||||
def main(argv: list[str]) -> int:
|
||||
max_age = 180
|
||||
strict = "--strict" in argv
|
||||
if "--max-age-days" in argv:
|
||||
i = argv.index("--max-age-days")
|
||||
max_age = int(argv[i + 1])
|
||||
cutoff = _dt.date.today() - _dt.timedelta(days=max_age)
|
||||
owners = known_owners()
|
||||
|
||||
unowned: list[str] = []
|
||||
stale: list[str] = []
|
||||
for p in sorted(SURFACES_DIR.glob("*.md")):
|
||||
e = load_entry(p)
|
||||
sid = e.get("id", p.stem)
|
||||
owner = e.get("owner")
|
||||
if not owner:
|
||||
unowned.append(f"{sid}: missing owner")
|
||||
elif owner not in owners:
|
||||
unowned.append(f"{sid}: owner '{owner}' not resolvable to a known identity")
|
||||
seen = (e.get("evidence", {}) or {}).get("last_seen")
|
||||
if not seen:
|
||||
stale.append(f"{sid}: no evidence.last_seen")
|
||||
else:
|
||||
try:
|
||||
if _dt.date.fromisoformat(str(seen)) < cutoff:
|
||||
stale.append(f"{sid}: last_seen {seen} older than {max_age}d")
|
||||
except ValueError:
|
||||
stale.append(f"{sid}: unparseable last_seen '{seen}'")
|
||||
|
||||
total = len(list(SURFACES_DIR.glob("*.md")))
|
||||
print(f"registry health: {total} promoted surface(s)")
|
||||
print(f" unowned/unresolved: {len(unowned)}")
|
||||
for u in unowned:
|
||||
print(f" - {u}")
|
||||
print(f" stale (> {max_age}d): {len(stale)}")
|
||||
for s in stale:
|
||||
print(f" - {s}")
|
||||
if not unowned and not stale:
|
||||
print(" all surfaces owned and fresh.")
|
||||
return 1 if (strict and (unowned or stale)) else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
raise SystemExit(main(sys.argv[1:]))
|
||||
Reference in New Issue
Block a user