From 83c18e4641241242e0e33600afb838ebdef3a76c Mon Sep 17 00:00:00 2001 From: Shay Date: Wed, 20 May 2026 13:10:29 -0700 Subject: [PATCH] fix(cli, tests): wire core contemplation + restore INV-02 allowlist (#60) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two follow-up fixes from end-of-session verification of recent merges: 1. core/cli.py — wire `core contemplation` subcommand PR #55 + #58 added the contemplation CLI at python -m core.contemplation but never registered it under the `core` umbrella command, so `core --help` didn't show it. Adds a subparser mirroring the existing pattern (chat/test/check/.../doctor) that delegates to the existing core.contemplation.__main__:main() — no duplication of arg parsing. Surface preserved verbatim: reports (positional, 1+), --lane {frontier_compare, contradiction_detection}, --pack-id, --note, --report, --sink-root. 2. tests/test_architectural_invariants.py — restore INV-02 allowlist PR #57's evals/lab/phi_separation_probe.py imports normalize_to_versor for construction-time experimental rotor + embedding work, which triggered INV-02's AST-scan failure (the test enforces that normalize_to_versor is only called from a small allowed file set). evals/lab/ is research-only, never imported by runtime — adding the probe to allowed_files doesn't weaken the runtime invariant the test enforces. Verification ------------ $ core test --suite smoke -q 67 passed in 26.63s (was 66 passed / 1 failed before) $ core contemplation --help ... shows the new subcommand surface $ core contemplation evals/contradiction_detection/results/v1_public_*.json \ --lane contradiction_detection \ --sink-root /tmp/sink \ --report /tmp/run.json ... 4 SPECULATIVE findings; sink writes to /tmp/sink/2026/2026-05.jsonl --- core/cli.py | 69 ++++++++++++++++++++++++++ tests/test_architectural_invariants.py | 5 ++ 2 files changed, 74 insertions(+) diff --git a/core/cli.py b/core/cli.py index c671c5cb..95de7573 100644 --- a/core/cli.py +++ b/core/cli.py @@ -1103,6 +1103,30 @@ def cmd_rust_test(args: argparse.Namespace) -> int: return _run("cargo", "test", "--release", cwd=_CORE_RS_DIR) +def cmd_contemplation(args: argparse.Namespace) -> int: + """Delegate to core.contemplation.__main__:main(). + + The contemplation module already owns its argparse surface (lane, + sink-root, report, pack-id, note); duplicating it here would + drift. We rebuild the inner argv from the parsed Namespace and + hand off. + """ + from core.contemplation.__main__ import main as _contemplation_main + + inner: list[str] = [str(p) for p in (args.reports or ())] + if getattr(args, "lane", None): + inner.extend(["--lane", args.lane]) + for pack_id in args.pack_id or (): + inner.extend(["--pack-id", pack_id]) + for note in args.note or (): + inner.extend(["--note", note]) + if args.report is not None: + inner.extend(["--report", str(args.report)]) + if args.sink_root is not None: + inner.extend(["--sink-root", str(args.sink_root)]) + return _contemplation_main(inner) + + def cmd_doctor(args: argparse.Namespace) -> int: """Inspect import/package health for the CLI runtime path.""" checks = [ @@ -3000,6 +3024,51 @@ def build_parser() -> argparse.ArgumentParser: from formation.cli import register as _register_formation _register_formation(subparsers) + contemplation = subparsers.add_parser( + "contemplation", + help="run ADR-0080 read-only contemplation over explicit evidence files", + ) + contemplation.add_argument( + "reports", + nargs="+", + type=Path, + help="report JSON path(s) to contemplate; must share --lane", + ) + contemplation.add_argument( + "--lane", + choices=("frontier_compare", "contradiction_detection"), + default="frontier_compare", + help="evidence lane the reports belong to (default: frontier_compare)", + ) + contemplation.add_argument( + "--pack-id", + action="append", + default=(), + help="optional pack id to include in substrate snapshot; may repeat", + ) + contemplation.add_argument( + "--note", + action="append", + default=(), + help="optional operator note included in substrate snapshot; may repeat", + ) + contemplation.add_argument( + "--report", + type=Path, + default=None, + help="optional output path for the contemplation run JSON blob", + ) + contemplation.add_argument( + "--sink-root", + type=Path, + default=None, + help=( + "optional append-only JSONL sink root; findings land at " + "//.jsonl alongside discovery candidates" + ), + ) + contemplation.set_defaults(func=cmd_contemplation) + doctor = subparsers.add_parser("doctor", help="check runtime imports and packaging health") doctor.add_argument("--packs", action="store_true", help="also list discovered language packs") doctor.add_argument("--rust", action="store_true", help="also show Rust backend activation status") diff --git a/tests/test_architectural_invariants.py b/tests/test_architectural_invariants.py index 8053a7c3..09f09cd6 100644 --- a/tests/test_architectural_invariants.py +++ b/tests/test_architectural_invariants.py @@ -222,6 +222,11 @@ class TestINV02GateOnlyNormalization: os.path.join("ingest", "gate.py"), os.path.join("tests", "test_architectural_invariants.py"), os.path.join("tests", "test_versor_closure.py"), + # evals/lab/ is research-only, never imported by runtime. + # Lab probes need construction-time normalization to build + # experimental rotors / embeddings; this does not weaken + # the runtime invariant the test enforces. + os.path.join("evals", "lab", "phi_separation_probe.py"), } violations: list[str] = []