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:
2026-03-03 08:16:00 +01:00
parent fc87e26b4b
commit 5c1b7e7e1d
3 changed files with 936 additions and 0 deletions

View File

@@ -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)
# ---------------------------------------------------------------------------