generated from coulomb/repo-seed
feat(consistency): implement ADR-001 consistency checking engine (CUST-WP-0008)
Adds state-hub/scripts/consistency_check.py with C-01 through C-12 checks: bidirectional file↔DB validation, --fix for auto-fixable issues, --all for all repos, --json output, exit codes 0/1/2. MCP tool: check_repo_consistency(repo_slug, fix=False) Makefile: check-consistency, fix-consistency, check-consistency-all, fix-consistency-all Auto-fixes applied across all repos: - C-09: activity-core-foundation + activity-core-triggers-ops repo_id → activity-core - C-04: railiance phase-0-operational-baseline status → completed - C-05: railiance phase-0 title synced from file - C-10/C-11: task status drifts resolved; state_hub_task_id injected into CUST-WP-0006 and CUST-WP-0007 task blocks Remaining orphans reported for human review: repo-integration-activity-core, infospace-s3-closeout, testdrive-jsui-publication, staged-promotion-lifecycle, three-phoenix-ha-cluster, current-env-safety-net. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -859,6 +859,84 @@ def validate_repo_adr(repo_path: str, domain_slug: str | None = None) -> str:
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ADR-001 consistency checking engine
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@mcp.tool()
|
||||
def check_repo_consistency(repo_slug: str, fix: bool = False) -> str:
|
||||
"""Run ADR-001 consistency check for a registered repo.
|
||||
|
||||
Performs bidirectional checks between workplan files in the repo and the
|
||||
state-hub DB. The file is always authoritative: drift is reported with the
|
||||
file value as the expected value.
|
||||
|
||||
Checks: missing workplans/, parse errors, stale DB references, status/title
|
||||
drift, unlinked workplans, orphan DB workstreams, repo mismatches, task
|
||||
status drift, unlinked tasks, and orphan DB tasks.
|
||||
|
||||
Args:
|
||||
repo_slug: Registered repo slug (e.g. 'the-custodian', 'activity-core').
|
||||
fix: If True, apply auto-fixable issues: status drift (C-04), title drift
|
||||
(C-05), create missing DB workstreams (C-06), repo mismatch (C-09),
|
||||
task status drift (C-10), create unlinked tasks (C-11).
|
||||
"""
|
||||
import subprocess
|
||||
script = Path(__file__).parent.parent / "scripts" / "consistency_check.py"
|
||||
cmd = [sys.executable, str(script), "--repo", repo_slug, "--json",
|
||||
"--api-base", API_BASE]
|
||||
if fix:
|
||||
cmd.append("--fix")
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
try:
|
||||
data = json.loads(result.stdout)
|
||||
except json.JSONDecodeError:
|
||||
return f"Consistency check script error:\n{result.stderr or result.stdout or '(no output)'}"
|
||||
|
||||
issues = data.get("issues", [])
|
||||
summary = data.get("summary", {})
|
||||
overall = data.get("result", "unknown")
|
||||
fixes = data.get("fixes_applied", [])
|
||||
|
||||
failures = [i for i in issues if i["severity"] == "FAIL"]
|
||||
warnings = [i for i in issues if i["severity"] == "WARN"]
|
||||
infos = [i for i in issues if i["severity"] == "INFO"]
|
||||
|
||||
lines = [
|
||||
f"Consistency Check: {repo_slug}",
|
||||
f"Path: {data.get('repo_path', '?')}",
|
||||
"",
|
||||
]
|
||||
|
||||
for sev, group in (("FAIL", failures), ("WARN", warnings), ("INFO", infos)):
|
||||
if not group:
|
||||
continue
|
||||
lines.append(f"{sev}S ({len(group)}):")
|
||||
for i in group:
|
||||
loc = f" [{i['file_path']}]" if i.get("file_path") else ""
|
||||
fix_tag = " [fixable]" if i.get("fixable") else ""
|
||||
lines.append(f" {i['check_id']}{loc}{fix_tag}")
|
||||
lines.append(f" {i['message']}")
|
||||
lines.append("")
|
||||
|
||||
if fixes:
|
||||
lines.append(f"Fixes applied ({len(fixes)}):")
|
||||
for f in fixes:
|
||||
lines.append(f" {f}")
|
||||
lines.append("")
|
||||
|
||||
lines.append(
|
||||
f"Summary: {summary.get('fail', 0)} fail | "
|
||||
f"{summary.get('warn', 0)} warn | "
|
||||
f"{summary.get('info', 0)} info"
|
||||
)
|
||||
lines.append(
|
||||
f"Result: {'FAIL' if overall == 'fail' else 'PASS (with warnings)' if overall in ('warn',) else 'PASS'}"
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Contribution tracking (v0.3)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user