- K27 receipt presentation: full decision+evidence+effect packages, expandable sections, UNKNOWN-never-success in every dimension state, spine verdicts via evidence.Evaluate (read-only import) - 2.6-depth compaction: append-per-message (O(1) tail line, 198 bytes steady-state), compaction every 64 appends (512/channel hot), cool archives per memory-continuity contract, nothing deleted, exact-by-ID across compaction+restart+tamper, legacy checkpoints heal on load - K27 composer depth: 3-line input per old TUI contracts (§2.3 history walk, placeholder, stash/restore), deterministic natural-language resolution (40+ pinned phrases), palette natural-tier + ctrl+p bind, Accessibility profile (keyboard-only/no-color/reduced-motion) - K27 themes: 10 fixed Go theme tables (byte-exact from Textual 8.2.8, not guessed; nord/dracula-default/monokai/solarized/catppuccin/tokyo- night/flexoki/gruvbox), /theme command (mirrors _cmd_theme exactly), live-editor data shape (staged per-token preview overrides), base bg rgb(30,30,40), no-drift drift test anchoring Go to retiring Python - Sleight live wiring: operator._context_broker registers seventh contributor 'continuity' (bucket 2, fail-closed); K16 allowlist amended (memory_continuity.working_set); matrices now run against the live road; 102 tests green - .gitignore hygiene: directory-level traps fixed (internal/ re-includes .go/.json/.md only; root-anchored /index/ /journal/ /state/; fixtures + testdata re-included at any depth); 6-test frozen gate; unified_check member wired; real git add (no -f) proven on testmod/internal - Receipts, compaction, composer, themes, sleight-wiring, hygiene all under ADMIT contracts (101+ contracts, 0 research-gate violations) - main.go NOT landed (chat-live P1 wave owns it, still in flight)
850 lines
41 KiB
Python
850 lines
41 KiB
Python
#!/usr/bin/env python3
|
|
"""unified_check.py — phase 0C task 0.13: ONE command, the WHOLE test world.
|
|
|
|
D26 (owner directive: no two test worlds — test it as one). This runner
|
|
executes every member of the system's one test world and produces ONE
|
|
verdict; partial (single-language) green is structurally impossible:
|
|
|
|
members
|
|
─────────────────────────────────────────────────────────────────────
|
|
rust_suite cargo test in EVERY src/rust/*/ crate (the
|
|
workspace has no root manifest; per-crate is the
|
|
layout) — build failures count as failures
|
|
python_suite the pinned invocation
|
|
RUNE_CA_CORE=python RUNE_CM_CORE=python
|
|
PYTHONPATH=src python -m pytest tests/
|
|
with BASELINE discipline: the recorded known-fail
|
|
set (verification/unified-baseline.json) stays
|
|
AMBER-documented-green; any NEW failure = RED
|
|
go_suite COMPILE-FIRST go build (the shared-module law,
|
|
wave shared-build-integrity: a tui/ that does
|
|
not build is RED before any test runs — a
|
|
sibling's in-flight state never excuses it) then
|
|
go vet + go test -race (ALL tui packages — the
|
|
concurrent bridge/rail/lanes/ promote code runs
|
|
under the race detector; measured cost ~5s
|
|
module-wide, so no plain-test split) + gofmt -l
|
|
(unformatted file = RED) in tui/ when the Go
|
|
module exists; staticcheck runs WARNING-ONLY when
|
|
present in PATH, honest skip-note when absent;
|
|
explicit SKIP-with-reason when the module does
|
|
not exist (never a silent pass)
|
|
src_go_suite ONE merged per-module pass over EVERY src/go/*/
|
|
module (the independently-versioned modules whose
|
|
test files previously bypassed this gate
|
|
entirely): `go build -o /dev/null ./...` FIRST
|
|
(scripts/go_build_sweep.BUILD_CMD — a module that
|
|
fails to BUILD is RED, never AMBER, never
|
|
baseline-able: the fix is always 'fix the build',
|
|
never 'skip the gate'), then `go test ./...` in
|
|
the same pass. Test failures keep the rust_suite
|
|
baseline discipline: recorded known-fail modules
|
|
stay AMBER-documented, any NEW failing module is
|
|
RED
|
|
boundary_corpus_rust recorded corpus (schemas/boundary/corpus) parsed
|
|
into the GENERATED Rust types and re-serialized
|
|
to canonical JSON — bytes must equal input
|
|
boundary_corpus_go same corpus, the GENERATED Go side
|
|
boundary_codegen scripts/check_boundary_codegen.py (task 0.12:
|
|
one schema source, regeneration parity)
|
|
events_schema scripts/check_events_schema.py (task 0.5:
|
|
frozen typed-event vocabulary gate)
|
|
no_committed_binaries scripts/check_no_committed_binaries.py
|
|
(task 0.14 hygiene gate)
|
|
language_verdict_fixtures scripts/check_language_verdict.py
|
|
(task 0.10: manifest + regrowth fixtures +
|
|
quarantine expiry)
|
|
seam_registry scripts/check_seam_registry.py
|
|
(task 6.5: future seam + day-one socket registry —
|
|
record completeness, passing deletion test +
|
|
consumer fixture at named paths (missing = RED),
|
|
paper expiry = AMBER, no automatic renewal)
|
|
research_gate scripts/check_research_gate.py sweep (D30 owner
|
|
law: research-first admission — every building-
|
|
phase ADMIT contract must resolve to a research
|
|
artifact chain (registry docs/factory/
|
|
research-registry.json) or a DECLARED exemption
|
|
in its evidence; missing registry or unresolved
|
|
contract = RED, fail-closed)
|
|
domain_registry scripts/check_domain_registry.py (wave
|
|
wave-domain-registry: the owner-critique map —
|
|
docs/factory/domains.json must name EVERY tui/
|
|
package, src/go/ module, src/rust/ crate, and
|
|
src/rune/ module (or explicitly retirement-
|
|
pending); no phantom paths; frozen symptom
|
|
lookups resolve via scripts/query_domain.py;
|
|
a package without a domain row = RED)
|
|
migration_mutants src/go/parity-harness frozen suite (task 0.11
|
|
battery: key scope / receipt origin / recovery
|
|
ordering / launcher target each trip RED, plus
|
|
the row-12 end-to-end run, attestation and the
|
|
ledger promotion rule — landed with 7.2)
|
|
gitignore_hygiene scripts/check_gitignore_hygiene.py (wave
|
|
wave-gitignore-hygiene: the force-add era traps
|
|
closed mechanically — probe sources under
|
|
src/go/testmod/internal/ addable without -f,
|
|
probe binaries unaddable at module level AND
|
|
inside subpackage dirs, memory/index/ +
|
|
memory/journal/ new files not swallowed by the
|
|
root-anchored runtime rules, fixture stores
|
|
fully addable)
|
|
|
|
Verdict: GREEN (exit 0) only when every member is green; AMBER (exit 0)
|
|
when the only non-green is the Python baseline set (documented); RED
|
|
(exit 1) otherwise. Every SKIP must carry an explicit reason. A manifest
|
|
JSON (verification/unified-check-<git-sha>.json) records each member's
|
|
result — scripts/check_landing.py (task 0.15) refuses landings without a
|
|
fresh green one.
|
|
|
|
Usage:
|
|
python scripts/unified_check.py # run everything
|
|
python scripts/unified_check.py --members a,b # subset (explicit)
|
|
python scripts/unified_check.py --record-baseline [--force]
|
|
# (re)capture the known-failure baseline honestly
|
|
# (--rust-only / --src-go-only refresh one section)
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import concurrent.futures
|
|
import json
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import xml.etree.ElementTree as ET
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
VERIFICATION = REPO / "verification"
|
|
BASELINE_PATH = VERIFICATION / "unified-baseline.json"
|
|
|
|
# the shared-module build-integrity sweep (wave shared-build-integrity):
|
|
# one build law imported by both gates, never re-implemented
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
import go_build_sweep # noqa: E402
|
|
|
|
PINNED_PYTEST = {
|
|
"RUNE_CA_CORE": "python",
|
|
"RUNE_CM_CORE": "python",
|
|
"PYTHONPATH": "src",
|
|
}
|
|
PINNED_PYTEST_CMD = ("RUNE_CA_CORE=python RUNE_CM_CORE=python "
|
|
"PYTHONPATH=src python -m pytest tests/")
|
|
|
|
MEMBERS: dict[str, dict] = {
|
|
"boundary_codegen": {"run": True},
|
|
"events_schema": {"run": True},
|
|
"rust_suite": {"run": True},
|
|
"python_suite": {"run": True},
|
|
"go_suite": {"run": True},
|
|
"src_go_suite": {"run": True},
|
|
"boundary_corpus_rust": {"run": True},
|
|
"boundary_corpus_go": {"run": True},
|
|
"no_committed_binaries": {"run": True},
|
|
"language_verdict_fixtures": {"run": True},
|
|
"seam_registry": {"run": True},
|
|
"research_gate": {"run": True},
|
|
"domain_registry": {"run": True},
|
|
"migration_mutants": {"run": True},
|
|
"gitignore_hygiene": {"run": True},
|
|
}
|
|
|
|
|
|
# ── verdict law ────────────────────────────────────────────────────────────
|
|
|
|
|
|
def classify_failures(failed: list[str], baseline: list[str]) -> dict:
|
|
"""Baseline discipline: known failures stay AMBER-documented; a NEW
|
|
failure is RED. `baseline_only` = known failures that now pass
|
|
(improvement, recorded for the next baseline refresh)."""
|
|
failed_set, baseline_set = set(failed), set(baseline)
|
|
new = sorted(failed_set - baseline_set)
|
|
if new:
|
|
return {"verdict": "RED", "new_failures": new,
|
|
"baseline_only": sorted(baseline_set - failed_set)}
|
|
if failed_set:
|
|
return {"verdict": "AMBER", "new_failures": [],
|
|
"baseline_only": sorted(baseline_set - failed_set)}
|
|
return {"verdict": "GREEN", "new_failures": [],
|
|
"baseline_only": sorted(baseline_set - failed_set)}
|
|
|
|
|
|
def aggregate_verdict(members: dict) -> str:
|
|
"""Partial green is impossible: any RED member, any SKIP without an
|
|
explicit reason, or any MISSING declared member => RED."""
|
|
for name in MEMBERS:
|
|
if name not in members:
|
|
members[name] = {"status": "RED",
|
|
"detail": "declared member missing from results"}
|
|
for name, m in members.items():
|
|
status = m.get("status")
|
|
if status == "RED":
|
|
return "RED"
|
|
if status == "SKIP" and not (m.get("reason") or "").strip():
|
|
return "RED" # an unexplained skip is a failure, not a pass
|
|
if any(m.get("status") == "AMBER" for m in members.values()):
|
|
return "AMBER"
|
|
return "GREEN"
|
|
|
|
|
|
def write_manifest(path, *, sha: str, dirty: bool, verdict: str,
|
|
members: dict, baseline: dict | None) -> dict:
|
|
doc = {
|
|
"schema": 1,
|
|
"runner": "scripts/unified_check.py",
|
|
"generated_at": datetime.now(timezone.utc).isoformat(),
|
|
"git_sha": sha,
|
|
"git_dirty": dirty,
|
|
"verdict": verdict,
|
|
"members": members,
|
|
"baseline": baseline,
|
|
"exit_code": 0 if verdict in ("GREEN", "AMBER") else 1,
|
|
}
|
|
Path(path).write_text(json.dumps(doc, indent=1, sort_keys=True) + "\n")
|
|
return doc
|
|
|
|
|
|
# ── helpers ────────────────────────────────────────────────────────────────
|
|
|
|
|
|
def git_sha() -> tuple[str, bool]:
|
|
sha = subprocess.run(["git", "-C", str(REPO), "rev-parse", "HEAD"],
|
|
capture_output=True, text=True).stdout.strip()
|
|
dirty_r = subprocess.run(
|
|
["git", "-C", str(REPO), "status", "--porcelain"],
|
|
capture_output=True, text=True).stdout.strip()
|
|
return (sha or "unknown"), bool(dirty_r)
|
|
|
|
|
|
def _record(fn) -> dict:
|
|
t0 = time.monotonic()
|
|
try:
|
|
out = fn()
|
|
except Exception as exc: # a crashed member is a RED member
|
|
return {"status": "RED", "detail": f"member crashed: "
|
|
f"{type(exc).__name__}: {exc}"[:500], "duration_s": round(time.monotonic() - t0, 1)}
|
|
out["duration_s"] = round(time.monotonic() - t0, 1)
|
|
return out
|
|
|
|
|
|
def run_cmd(cmd: list[str], *, cwd: Path, env: dict | None = None,
|
|
timeout: int = 3600) -> subprocess.CompletedProcess:
|
|
full_env = dict(os.environ)
|
|
if env:
|
|
full_env.update(env)
|
|
return subprocess.run(cmd, cwd=str(cwd), env=full_env,
|
|
capture_output=True, text=True, timeout=timeout)
|
|
|
|
|
|
# ── member implementations ─────────────────────────────────────────────────
|
|
|
|
|
|
def member_boundary_codegen() -> dict:
|
|
r = run_cmd([sys.executable, str(REPO / "scripts/check_boundary_codegen.py")],
|
|
cwd=REPO, timeout=300)
|
|
detail = (r.stdout + r.stderr).strip().splitlines()
|
|
return {"status": "GREEN" if r.returncode == 0 else "RED",
|
|
"detail": detail[-1] if detail else ""}
|
|
|
|
|
|
def member_events_schema() -> dict:
|
|
r = run_cmd([sys.executable, str(REPO / "scripts/check_events_schema.py")],
|
|
cwd=REPO, timeout=300)
|
|
detail = (r.stdout + r.stderr).strip().splitlines()
|
|
return {"status": "GREEN" if r.returncode == 0 else "RED",
|
|
"detail": detail[-1] if detail else ""}
|
|
|
|
|
|
def member_rust_suite() -> dict:
|
|
crates = sorted(p.parent for p in REPO.glob("src/rust/*/Cargo.toml"))
|
|
if not crates:
|
|
return {"status": "RED", "detail": "no rust crates found"}
|
|
|
|
def test_crate(crate: Path) -> tuple[str, bool, str]:
|
|
r = run_cmd(["cargo", "test", "--quiet"], cwd=crate, timeout=1800)
|
|
tail = (r.stdout + r.stderr).strip().splitlines()
|
|
return crate.name, r.returncode == 0, tail[-1][:200] if tail else ""
|
|
|
|
failed: list[str] = []
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool:
|
|
for name, ok, tail in pool.map(test_crate, crates):
|
|
if not ok:
|
|
failed.append(name)
|
|
baseline_doc = _load_baseline_doc()
|
|
known = set(baseline_doc.get("rust_expected_failing_crates", {}))
|
|
new_failed = sorted(set(failed) - known)
|
|
baseline_only = sorted(known - set(failed))
|
|
data = {"crates": len(crates), "failed": failed,
|
|
"baseline_failed_crates": sorted(known),
|
|
"new_failed_crates": new_failed,
|
|
"baseline_only_crates": baseline_only}
|
|
if new_failed:
|
|
return {"status": "RED", "detail": f"cargo test failed in NEW crate(s) {', '.join(new_failed)} "
|
|
f"(known-failing baseline crates: {', '.join(failed and [c for c in failed if c not in new_failed] or []) or 'none'})",
|
|
"data": data}
|
|
if failed:
|
|
documented = "; ".join(
|
|
f"{c}: {baseline_doc['rust_expected_failing_crates'][c].get('diagnosis', 'unspecified')}"
|
|
for c in failed)
|
|
return {"status": "AMBER", "detail": f"cargo test green in {len(crates) - len(failed)}/{len(crates)} "
|
|
f"crates; known-failing (documented baseline): {documented}", "data": data}
|
|
return {"status": "GREEN", "detail": f"cargo test green in all {len(crates)} crates "
|
|
f"(baseline listed {len(known)})", "data": data}
|
|
|
|
|
|
def run_pinned_pytest(junit_path: Path) -> subprocess.CompletedProcess:
|
|
env = dict(PINNED_PYTEST)
|
|
env["PYTEST_ADDOPTS"] = f"--junit-xml={junit_path}"
|
|
return run_cmd([sys.executable, "-m", "pytest", "tests/", "-q", "--tb=no",
|
|
"-p", "no:cacheprovider"],
|
|
cwd=REPO, env=env, timeout=3600)
|
|
|
|
|
|
def parse_junit_failures(junit_path: Path) -> list[str]:
|
|
root = ET.parse(junit_path).getroot()
|
|
failed = []
|
|
for tc in root.iter("testcase"):
|
|
if tc.find("failure") is not None or tc.find("error") is not None:
|
|
failed.append(f"{tc.get('classname')}::{tc.get('name')}")
|
|
return sorted(set(failed))
|
|
|
|
|
|
def load_baseline(path: Path = BASELINE_PATH) -> list[str]:
|
|
doc = json.loads(Path(path).read_text())
|
|
return doc["expected_failures"]
|
|
|
|
|
|
def _load_baseline_doc() -> dict:
|
|
if not BASELINE_PATH.is_file():
|
|
return {}
|
|
return json.loads(BASELINE_PATH.read_text())
|
|
|
|
|
|
def member_python_suite() -> dict:
|
|
import tempfile
|
|
with tempfile.NamedTemporaryFile(suffix=".xml", delete=False) as tf:
|
|
junit = Path(tf.name)
|
|
try:
|
|
r = run_pinned_pytest(junit)
|
|
if not junit.exists():
|
|
return {"status": "RED",
|
|
"detail": f"pytest produced no junit output (rc={r.returncode}): "
|
|
f"{(r.stdout + r.stderr)[-500:]}"}
|
|
failed = parse_junit_failures(junit)
|
|
baseline = load_baseline()
|
|
res = classify_failures(failed, baseline)
|
|
data = {"command": PINNED_PYTEST_CMD,
|
|
"observed_failures": len(failed),
|
|
"baseline_count": len(baseline),
|
|
"new_failures": res["new_failures"][:50],
|
|
"baseline_only_count": len(res["baseline_only"]),
|
|
"exit_code": r.returncode}
|
|
detail = (f"{len(failed)} failing vs baseline {len(baseline)}; "
|
|
f"{len(res['new_failures'])} new")
|
|
if res["verdict"] == "RED":
|
|
return {"status": "RED",
|
|
"detail": detail + f" — NEW failures: {res['new_failures'][:10]}",
|
|
"data": data}
|
|
return {"status": res["verdict"], "detail": detail
|
|
+ (" (baseline-only: documented)" if res["verdict"] == "AMBER" else ""),
|
|
"data": data}
|
|
finally:
|
|
junit.unlink(missing_ok=True)
|
|
|
|
|
|
def record_baseline(force: bool, rust_only: bool = False,
|
|
src_go_only: bool = False) -> int:
|
|
existing = json.loads(BASELINE_PATH.read_text()) if BASELINE_PATH.exists() else {}
|
|
if existing and not force and not rust_only and not src_go_only:
|
|
print(f"refusing to overwrite {BASELINE_PATH} without --force")
|
|
return 1
|
|
|
|
doc = dict(existing)
|
|
if not rust_only and not src_go_only:
|
|
import tempfile
|
|
with tempfile.NamedTemporaryFile(suffix=".xml", delete=False) as tf:
|
|
junit = Path(tf.name)
|
|
try:
|
|
r = run_pinned_pytest(junit)
|
|
if not junit.exists():
|
|
print(f"RED: pytest produced no junit output (rc={r.returncode})")
|
|
return 1
|
|
failed = parse_junit_failures(junit)
|
|
finally:
|
|
junit.unlink(missing_ok=True)
|
|
doc.update({
|
|
"recorded_at": datetime.now(timezone.utc).isoformat(),
|
|
"command": PINNED_PYTEST_CMD,
|
|
"count": len(failed),
|
|
"expected_failures": failed,
|
|
})
|
|
|
|
# rust section: full per-crate sweep, crates that fail recorded with
|
|
# their failing tests + the diagnosed reason (documented, never absorbed)
|
|
if not src_go_only:
|
|
crates = sorted(p.parent for p in REPO.glob("src/rust/*/Cargo.toml"))
|
|
|
|
def test_crate(crate: Path):
|
|
r = run_cmd(["cargo", "test", "--quiet"], cwd=crate, timeout=1800)
|
|
return crate.name, r.returncode == 0, r.stdout + r.stderr
|
|
|
|
rust_failures: dict[str, dict] = {}
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool:
|
|
for name, ok, out in pool.map(test_crate, crates):
|
|
if not ok:
|
|
rust_failures[name] = {
|
|
"diagnosis": "pre-existing on HEAD (phase 0C first full "
|
|
"per-crate cargo-test sweep found it); "
|
|
"reported to the owner, fix is a separate "
|
|
"bounded repair",
|
|
"output_tail": out.strip().splitlines()[-3:],
|
|
}
|
|
doc["rust_expected_failing_crates"] = rust_failures
|
|
|
|
# src/go section: same law for the independently-versioned modules
|
|
# (go.work was tested and cannot resolve ./... without a root module;
|
|
# the per-module sweep is the layout)
|
|
if not rust_only:
|
|
go_modules = sorted(p.parent for p in REPO.glob("src/go/*/go.mod"))
|
|
|
|
def test_go_module(mod: Path):
|
|
r = run_cmd(["go", "test", "./..."], cwd=mod, timeout=1800)
|
|
return mod.name, r.returncode == 0, r.stdout + r.stderr
|
|
|
|
src_go_failures: dict[str, dict] = {}
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool:
|
|
for name, ok, out in pool.map(test_go_module, go_modules):
|
|
if not ok:
|
|
src_go_failures[name] = {
|
|
"diagnosis": "pre-existing on HEAD (wave J0 first full "
|
|
"src/go module sweep found it); reported "
|
|
"to the owner, fix is a separate bounded "
|
|
"repair",
|
|
"output_tail": out.strip().splitlines()[-3:],
|
|
}
|
|
doc["src_go_expected_failing_modules"] = src_go_failures
|
|
|
|
doc.setdefault("note", "phase 0C task 0.13 baseline: the pre-existing "
|
|
"failure sets on HEAD, recorded honestly; NEW failures "
|
|
"are RED, baseline-only is AMBER-documented-green")
|
|
VERIFICATION.mkdir(exist_ok=True)
|
|
BASELINE_PATH.write_text(json.dumps(doc, indent=1, sort_keys=True) + "\n")
|
|
print(f"baseline recorded: {doc.get('count', existing.get('count', 0))} expected "
|
|
f"python failures, {len(doc.get('rust_expected_failing_crates', {}))} known-failing "
|
|
f"rust crates, {len(doc.get('src_go_expected_failing_modules', {}))} known-failing "
|
|
f"src/go modules ({', '.join(doc.get('src_go_expected_failing_modules', {})) or 'none'}) "
|
|
f"→ {BASELINE_PATH}")
|
|
return 0
|
|
|
|
|
|
GO_TEST_RACE_CMD = ["go", "test", "-race", "./..."]
|
|
|
|
|
|
def gofmt_verdict(unformatted: list[str], err: str = "") -> dict:
|
|
"""Verdict over `gofmt -l` output: any listed file is RED, a crashed
|
|
gofmt is a toolchain RED, empty output is GREEN."""
|
|
if err:
|
|
return {"status": "RED", "detail": f"gofmt FAILED: {err}"}
|
|
if unformatted:
|
|
listed = ", ".join(unformatted[:10]) + (" …" if len(unformatted) > 10 else "")
|
|
return {"status": "RED",
|
|
"detail": f"gofmt: {len(unformatted)} unformatted file(s): {listed}"}
|
|
return {"status": "GREEN", "detail": "gofmt clean"}
|
|
|
|
|
|
def _staticcheck_warning(tui: Path) -> dict:
|
|
"""staticcheck is WARNING-ONLY and never gates: an absent tool is an
|
|
honestly-named skip, a present tool's findings ride along as warnings."""
|
|
if shutil.which("staticcheck") is None:
|
|
return {"staticcheck": "skipped: not in PATH "
|
|
"(warning-only tool, never gated)"}
|
|
scr = run_cmd(["staticcheck", "./..."], cwd=tui, timeout=600)
|
|
found = [l for l in (scr.stdout + scr.stderr).splitlines() if l.strip()]
|
|
return {"staticcheck": f"ran rc={scr.returncode}, {len(found)} finding(s) "
|
|
"— warning-only",
|
|
"staticcheck_findings": found[:20]}
|
|
|
|
|
|
def member_go_suite() -> dict:
|
|
tui = REPO / "tui"
|
|
if not (tui / "go.mod").is_file():
|
|
return {"status": "SKIP",
|
|
"reason": "tui/ Go module not yet created (pre-TUI runs "
|
|
"skip the Go member explicitly; it is never a "
|
|
"silent pass)"}
|
|
# COMPILE FIRST (the shared-module law, wave shared-build-integrity):
|
|
# the face module that does not build is RED before any test runs —
|
|
# a module nobody builds is the hole that once shipped a sibling's
|
|
# syntax error into the user's boot. -o /dev/null compiles every
|
|
# package while never dropping a binary into the tree (a stray
|
|
# built binary is working-tree state that flips other gates).
|
|
build = run_cmd(list(go_build_sweep.BUILD_CMD), cwd=tui, timeout=600)
|
|
if build.returncode != 0:
|
|
tail = " | ".join(l for l in (build.stdout + build.stderr)
|
|
.strip().splitlines() if l.strip())[:400]
|
|
return {"status": "RED",
|
|
"detail": f"tui BUILD FAILED (compile-first, cmd "
|
|
f"'{' '.join(go_build_sweep.BUILD_CMD)}'): {tail} "
|
|
"— vet/test/gofmt skipped (fail fast); fix the "
|
|
"build, the gate does not excuse it",
|
|
"data": {"build_cmd": " ".join(go_build_sweep.BUILD_CMD),
|
|
"build_rc": build.returncode}}
|
|
vet = run_cmd(["go", "vet", "./..."], cwd=tui, timeout=600)
|
|
# race detector on the WHOLE module: the concurrent bridge/rail/lanes/
|
|
# promote code is exactly what it exists for, and the measured cost
|
|
# (~5s) makes a race/plain package split unnecessary
|
|
test = run_cmd(GO_TEST_RACE_CMD, cwd=tui, timeout=3600)
|
|
|
|
go_files = [str(p.relative_to(tui)) for p in sorted(tui.rglob("*.go"))
|
|
if "vendor" not in p.parts]
|
|
fmt = run_cmd(["gofmt", "-l", *go_files], cwd=tui, timeout=300)
|
|
fmt_err = ("" if fmt.returncode == 0
|
|
else (fmt.stderr.strip() or f"rc={fmt.returncode}"))
|
|
unformatted = [l for l in fmt.stdout.splitlines() if l.strip()]
|
|
fmt_v = gofmt_verdict(unformatted, fmt_err)
|
|
staticcheck = _staticcheck_warning(tui)
|
|
|
|
ok = (vet.returncode == 0
|
|
and test.returncode == 0 and fmt_v["status"] == "GREEN")
|
|
return {"status": "GREEN" if ok else "RED",
|
|
"detail": f"build rc=0 (compile-first), go vet rc={vet.returncode}, "
|
|
f"test -race rc={test.returncode} (race detector on ALL "
|
|
f"tui packages incl. bridge/rail/lanes/promote); "
|
|
f"{fmt_v['detail']}; {staticcheck['staticcheck']}",
|
|
"data": {"build_cmd": " ".join(go_build_sweep.BUILD_CMD),
|
|
"build_rc": build.returncode,
|
|
"vet": vet.returncode,
|
|
"test_race": test.returncode,
|
|
"test_race_cmd": " ".join(GO_TEST_RACE_CMD),
|
|
"gofmt_unformatted": unformatted, **staticcheck}}
|
|
|
|
|
|
def member_src_go_suite() -> dict:
|
|
"""ONE merged per-module pass over EVERY src/go/*/ module: build
|
|
FIRST, then test (the shared-module law, wave shared-build-integrity
|
|
— a module that fails to BUILD is RED, never AMBER, never
|
|
baseline-able: a sibling's in-flight state does not excuse it, the
|
|
fix is always 'fix the build'). A go.work at src/go/ was tested and
|
|
rejected: the directory has no root module, so workspace mode
|
|
cannot resolve `./...` from there — the per-module loop is the
|
|
layout (exactly like rust_suite's per-crate loop)."""
|
|
modules = sorted(p.parent for p in REPO.glob("src/go/*/go.mod"))
|
|
if not modules:
|
|
return {"status": "RED", "detail": "no src/go modules found"}
|
|
baseline_doc = _load_baseline_doc()
|
|
known = sorted(baseline_doc.get("src_go_expected_failing_modules", {}))
|
|
|
|
def build_then_test_module(mod: Path) -> tuple[str, str, str]:
|
|
b = go_build_sweep.build_module(mod)
|
|
if b.returncode != 0:
|
|
tail = " | ".join(l for l in (b.stdout + b.stderr)
|
|
.strip().splitlines() if l.strip())[:200]
|
|
return mod.name, "build_failed", tail or f"rc={b.returncode}"
|
|
r = run_cmd(["go", "test", "./..."], cwd=mod, timeout=1800)
|
|
tail = (r.stdout + r.stderr).strip().splitlines()
|
|
return (mod.name,
|
|
"ok" if r.returncode == 0 else "test_failed",
|
|
tail[-1][:200] if tail else "")
|
|
|
|
build_failed: list[str] = []
|
|
failed: list[str] = []
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool:
|
|
for name, outcome, _tail in pool.map(build_then_test_module, modules):
|
|
if outcome == "build_failed":
|
|
build_failed.append(name)
|
|
elif outcome == "test_failed":
|
|
failed.append(name)
|
|
if build_failed:
|
|
# NOT baseline-able, by law: an unbuildable shared module is a
|
|
# dead end for every other wave and the user's boot — RED.
|
|
return {"status": "RED",
|
|
"detail": f"BUILD FAILED in module(s) {', '.join(sorted(build_failed))} "
|
|
f"(compile-first, cmd "
|
|
f"'{' '.join(go_build_sweep.BUILD_CMD)}' — NOT "
|
|
"baseline-able: fix the build, a sibling's "
|
|
"in-flight state does not excuse it)",
|
|
"data": {"modules": len(modules),
|
|
"build_failed": sorted(build_failed),
|
|
"build_cmd": " ".join(go_build_sweep.BUILD_CMD),
|
|
"failed": failed,
|
|
"baseline_failed_modules": known,
|
|
"new_failed_modules": [],
|
|
"baseline_only_modules": []}}
|
|
res = classify_failures(failed, known)
|
|
data = {"modules": len(modules), "build_failed": [],
|
|
"build_cmd": " ".join(go_build_sweep.BUILD_CMD),
|
|
"failed": failed,
|
|
"baseline_failed_modules": known,
|
|
"new_failed_modules": res["new_failures"],
|
|
"baseline_only_modules": res["baseline_only"]}
|
|
if res["verdict"] == "RED":
|
|
return {"status": "RED",
|
|
"detail": f"build green in all {len(modules)} modules; go test failed in NEW module(s) {', '.join(res['new_failures'])} "
|
|
f"(known-failing baseline modules: "
|
|
f"{', '.join(c for c in failed if c not in res['new_failures']) or 'none'})",
|
|
"data": data}
|
|
if failed:
|
|
documented = "; ".join(
|
|
f"{c}: {baseline_doc['src_go_expected_failing_modules'][c].get('diagnosis', 'unspecified')}"
|
|
for c in failed)
|
|
return {"status": "AMBER",
|
|
"detail": f"build green in all {len(modules)} modules; go test "
|
|
f"green in {len(modules) - len(failed)}/{len(modules)} "
|
|
f"src/go modules; known-failing (documented baseline): {documented}",
|
|
"data": data}
|
|
return {"status": "GREEN", "detail": f"build green + go test green in all "
|
|
f"{len(modules)} src/go modules (baseline listed {len(known)})",
|
|
"data": data}
|
|
|
|
|
|
def member_boundary_corpus_rust() -> dict:
|
|
crate = REPO / "src/rust/boundary_types"
|
|
if not (crate / "Cargo.toml").is_file():
|
|
return {"status": "SKIP",
|
|
"reason": "generated rust boundary crate not present — run "
|
|
"scripts/gen_boundary_types.py"}
|
|
r = run_cmd(["cargo", "test", "--quiet"], cwd=crate, timeout=1800,
|
|
env={"BOUNDARY_CORPUS_DIR": str(REPO / "schemas/boundary/corpus")})
|
|
return {"status": "GREEN" if r.returncode == 0 else "RED",
|
|
"detail": f"cargo test rc={r.returncode} (corpus round-trip in "
|
|
"generated Rust types)"}
|
|
|
|
|
|
def member_boundary_corpus_go() -> dict:
|
|
gen = REPO / "tui/boundary/gen"
|
|
if not (gen / "boundary_gen.go").is_file():
|
|
return {"status": "SKIP",
|
|
"reason": "generated go boundary package not present — run "
|
|
"scripts/gen_boundary_types.py"}
|
|
r = run_cmd(["go", "test", "./..."], cwd=REPO / "tui", timeout=1800,
|
|
env={"BOUNDARY_CORPUS_DIR": str(REPO / "schemas/boundary/corpus")})
|
|
return {"status": "GREEN" if r.returncode == 0 else "RED",
|
|
"detail": f"go test rc={r.returncode} (corpus round-trip in "
|
|
"generated Go types)"}
|
|
|
|
|
|
def member_no_committed_binaries() -> dict:
|
|
r = run_cmd([sys.executable,
|
|
str(REPO / "scripts/check_no_committed_binaries.py")],
|
|
cwd=REPO, timeout=300)
|
|
detail = (r.stdout + r.stderr).strip().splitlines()
|
|
return {"status": "GREEN" if r.returncode == 0 else "RED",
|
|
"detail": detail[-1] if detail else ""}
|
|
|
|
|
|
def member_language_verdict_fixtures() -> dict:
|
|
r = run_cmd([sys.executable,
|
|
str(REPO / "scripts/check_language_verdict.py")],
|
|
cwd=REPO, timeout=600)
|
|
detail = (r.stdout + r.stderr).strip().splitlines()
|
|
tail = detail[-1] if detail else ""
|
|
reds = [l for l in detail if l.startswith("RED ")]
|
|
if r.returncode != 0:
|
|
return {"status": "RED",
|
|
"detail": f"gate exit {r.returncode}: "
|
|
f"{'; '.join(reds[:5]) or tail}"}
|
|
return {"status": "GREEN", "detail": tail or "verdict GREEN"}
|
|
|
|
|
|
def member_seam_registry() -> dict:
|
|
"""task 6.5: the seam-registry gate. Its own verdicts map straight
|
|
through: RED = exit 1 (missing/failing deletion test, missing fixture,
|
|
completeness gap, renewal laundering), AMBER = exit 0 with expired
|
|
reviews (paper expiry is a documented warning), GREEN = exit 0."""
|
|
r = run_cmd([sys.executable, str(REPO / "scripts/check_seam_registry.py")],
|
|
cwd=REPO, timeout=900)
|
|
lines = (r.stdout + r.stderr).strip().splitlines()
|
|
verdict = next((l.split(":", 1)[1].strip() for l in lines
|
|
if l.startswith("VERDICT:")), "")
|
|
if verdict in ("GREEN", "AMBER"):
|
|
detail = next((l for l in lines if l.startswith(verdict)), "")
|
|
return {"status": verdict,
|
|
"detail": detail[len(verdict):][:200].strip()
|
|
or "seam registry lawful"}
|
|
reds = [l for l in lines if l.startswith("RED ")]
|
|
return {"status": "RED",
|
|
"detail": f"gate exit {r.returncode}: "
|
|
f"{'; '.join(r[:200] for r in reds[:3]) or (lines[-1] if lines else '')}"}
|
|
|
|
|
|
def member_research_gate() -> dict:
|
|
"""D30 owner law: research-first admission. Every building-phase ADMIT
|
|
contract must resolve to a research artifact chain (seeded registry)
|
|
or a DECLARED exemption in its evidence — the post-hoc counterpart of
|
|
scripts/check_research_gate.py admit, which dispatch scripts call
|
|
before minting. The gate's own verdict maps straight through: RED =
|
|
exit 1 (unresolved contract, unusable registry), GREEN = exit 0."""
|
|
r = run_cmd([sys.executable, str(REPO / "scripts/check_research_gate.py"),
|
|
"sweep"], cwd=REPO, timeout=600)
|
|
lines = (r.stdout + r.stderr).strip().splitlines()
|
|
verdict = next((l.split(":", 1)[1].strip() for l in lines
|
|
if l.startswith("VERDICT:")), "")
|
|
if verdict in ("GREEN", "AMBER"):
|
|
summary = next((l for l in lines if "building ADMIT contracts" in l), "")
|
|
return {"status": verdict,
|
|
"detail": summary[:200] or "research gate lawful"}
|
|
reds = [l for l in lines if l.startswith("RED ")]
|
|
return {"status": "RED",
|
|
"detail": f"gate exit {r.returncode}: "
|
|
f"{'; '.join(r[:200] for r in reds[:3]) or (lines[-1] if lines else '')}"}
|
|
|
|
|
|
def member_migration_mutants() -> dict:
|
|
"""task 0.11 battery (landed with 7.2): the src/go/parity-harness
|
|
frozen suite — the four named mutants (key scope, receipt origin,
|
|
recovery ordering, launcher target) each trip the parity harness
|
|
RED, the row-12 end-to-end run is GREEN, the attestation has teeth,
|
|
and the ledger promotion rule holds. Note: the mutant RED verdicts
|
|
are the harness's own (the tests assert them), so a green run here
|
|
is correct and is exactly the mutant-hardening proof."""
|
|
mod = REPO / "src/go/parity-harness"
|
|
if not (mod / "go.mod").is_file():
|
|
return {"status": "RED", "detail": "src/go/parity-harness missing — "
|
|
"the 0.11 mutant battery is declared but not present"}
|
|
r = run_cmd(["go", "test", "./..."], cwd=mod, timeout=1200)
|
|
tail = (r.stdout + r.stderr).strip().splitlines()
|
|
return {"status": "GREEN" if r.returncode == 0 else "RED",
|
|
"detail": f"go test rc={r.returncode} (0.11 mutant battery + "
|
|
f"row-12 parity harness suite); {tail[-1] if tail else ''}"}
|
|
|
|
|
|
def member_domain_registry() -> dict:
|
|
"""wave wave-domain-registry: the domain-registry gate. The map
|
|
(docs/factory/domains.json) that turns diagnosis from grep-exploration
|
|
into a lookup — completeness is the point: every tui/ Go package, every
|
|
src/go/ module, every src/rust/ crate, and every src/rune/ module must
|
|
appear in a domain row (or be explicitly retirement-pending with its
|
|
map row); registry-named paths must exist (a stale map is worse than
|
|
none); the three frozen symptom probes must resolve through
|
|
scripts/query_domain.py. Its own verdict maps straight through:
|
|
RED = exit 1, GREEN = exit 0."""
|
|
r = run_cmd([sys.executable, str(REPO / "scripts/check_domain_registry.py")],
|
|
cwd=REPO, timeout=300)
|
|
lines = (r.stdout + r.stderr).strip().splitlines()
|
|
verdict = next((l.split(":", 1)[1].strip() for l in lines
|
|
if l.startswith("VERDICT:")), "")
|
|
if verdict in ("GREEN", "AMBER"):
|
|
detail = next((l for l in lines if l.startswith(verdict)), "")
|
|
return {"status": verdict,
|
|
"detail": detail[len(verdict):][:200].strip()
|
|
or "domain registry complete"}
|
|
reds = [l for l in lines if l.startswith("RED ")]
|
|
return {"status": "RED",
|
|
"detail": f"gate exit {r.returncode}: "
|
|
f"{'; '.join(x[:120] for x in reds[:3]) or (lines[-1] if lines else '')}"}
|
|
|
|
def member_gitignore_hygiene() -> dict:
|
|
"""wave wave-gitignore-hygiene: the gitignore hygiene gate. Closes the
|
|
force-add era traps mechanically — probe sources under
|
|
src/go/testmod/internal/ addable without -f, probe binaries unaddable
|
|
(module level AND inside subpackage dirs), new files under the tracked
|
|
memory/index/ + memory/journal/ dirs not swallowed by the root-anchored
|
|
runtime rules, fixture stores (fixtures/ + testdata/) fully addable.
|
|
Its own verdict maps straight through: RED = exit 1, GREEN = exit 0."""
|
|
r = run_cmd([sys.executable, str(REPO / "scripts/check_gitignore_hygiene.py")],
|
|
cwd=REPO, timeout=300)
|
|
lines = (r.stdout + r.stderr).strip().splitlines()
|
|
verdict = next((l.split(":", 1)[1].strip() for l in lines
|
|
if l.startswith("VERDICT:")), "")
|
|
if verdict in ("GREEN", "AMBER"):
|
|
detail = next((l for l in lines if l.startswith(verdict)), "")
|
|
return {"status": verdict,
|
|
"detail": detail[len(verdict):][:200].strip()
|
|
or "gitignore hygiene lawful"}
|
|
reds = [l for l in lines if l.startswith(" - ")]
|
|
return {"status": "RED",
|
|
"detail": f"gate exit {r.returncode}: "
|
|
f"{'; '.join(x.strip()[:120] for x in reds[:3]) or (lines[-1] if lines else '')}"}
|
|
|
|
|
|
IMPL = {
|
|
"boundary_codegen": member_boundary_codegen,
|
|
"events_schema": member_events_schema,
|
|
"rust_suite": member_rust_suite,
|
|
"python_suite": member_python_suite,
|
|
"go_suite": member_go_suite,
|
|
"src_go_suite": member_src_go_suite,
|
|
"boundary_corpus_rust": member_boundary_corpus_rust,
|
|
"boundary_corpus_go": member_boundary_corpus_go,
|
|
"no_committed_binaries": member_no_committed_binaries,
|
|
"language_verdict_fixtures": member_language_verdict_fixtures,
|
|
"seam_registry": member_seam_registry,
|
|
"research_gate": member_research_gate,
|
|
"domain_registry": member_domain_registry,
|
|
"migration_mutants": member_migration_mutants,
|
|
"gitignore_hygiene": member_gitignore_hygiene,
|
|
}
|
|
|
|
|
|
def main(argv=None) -> int:
|
|
ap = argparse.ArgumentParser(description="unified check (task 0.13)")
|
|
ap.add_argument("--members", default="",
|
|
help="comma-separated subset (default: all)")
|
|
ap.add_argument("--record-baseline", action="store_true")
|
|
ap.add_argument("--force", action="store_true")
|
|
ap.add_argument("--rust-only", action="store_true",
|
|
help="with --record-baseline: re-record only the rust "
|
|
"crate section (keeps the pytest section)")
|
|
ap.add_argument("--src-go-only", action="store_true",
|
|
help="with --record-baseline: re-record only the src/go "
|
|
"module section (keeps pytest + rust sections)")
|
|
args = ap.parse_args(argv)
|
|
|
|
if args.record_baseline:
|
|
return record_baseline(force=args.force, rust_only=args.rust_only,
|
|
src_go_only=args.src_go_only)
|
|
|
|
wanted = ([m.strip() for m in args.members.split(",") if m.strip()]
|
|
or list(MEMBERS))
|
|
results: dict[str, dict] = {}
|
|
for name in wanted:
|
|
spec = MEMBERS.get(name)
|
|
if spec is None:
|
|
results[name] = {"status": "RED", "detail": f"unknown member {name}"}
|
|
elif spec.get("planned") and not spec.get("run"):
|
|
results[name] = {"status": "SKIP", "reason": spec["skip_reason"]}
|
|
else:
|
|
results[name] = _record(IMPL[name])
|
|
|
|
verdict = aggregate_verdict(results)
|
|
sha, dirty = git_sha()
|
|
baseline_info = None
|
|
if "python_suite" in results and "data" in results.get("python_suite", {}):
|
|
d = results["python_suite"]["data"]
|
|
baseline_info = {"observed": d["observed_failures"],
|
|
"baseline": d["baseline_count"],
|
|
"new": len(d["new_failures"])}
|
|
if "src_go_suite" in results and "data" in results.get("src_go_suite", {}):
|
|
d = results["src_go_suite"]["data"]
|
|
entry = {"observed": len(d["failed"]),
|
|
"baseline": len(d["baseline_failed_modules"]),
|
|
"new": len(d["new_failed_modules"])}
|
|
baseline_info = ({"python": baseline_info, "src_go": entry}
|
|
if baseline_info is not None else entry)
|
|
VERIFICATION.mkdir(exist_ok=True)
|
|
manifest = VERIFICATION / f"unified-check-{sha[:40]}.json"
|
|
write_manifest(manifest, sha=sha, dirty=dirty, verdict=verdict,
|
|
members=results, baseline=baseline_info)
|
|
|
|
print("=" * 72)
|
|
for name, res in results.items():
|
|
status = res["status"]
|
|
line = f" [{status:<5}] {name}"
|
|
if status == "SKIP":
|
|
line += f" — {res.get('reason', '')}"
|
|
elif res.get("detail"):
|
|
line += f" — {res['detail']}"
|
|
if res.get("duration_s") is not None:
|
|
line += f" ({res['duration_s']}s)"
|
|
print(line)
|
|
print("=" * 72)
|
|
print(f"VERDICT: {verdict} manifest: {manifest.relative_to(REPO)}")
|
|
return 0 if verdict in ("GREEN", "AMBER") else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|