From 71321a5058700fc76018ecc6d9464c321a58e503 Mon Sep 17 00:00:00 2001 From: Shay Date: Fri, 22 May 2026 16:39:53 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20ADR-0123=20=E2=80=94=20re-map=20symboli?= =?UTF-8?q?c=5Flogic=20to=20inference=5Fshape=20(unblocks=20ADR-0122)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/capability/expert_demo.py | 3 +- .../ADR-0123-symbolic-logic-shape-remap.md | 71 +++++++++++++++++++ tests/test_adr_0122_deferral.py | 31 ++------ tests/test_expert_demo_contract.py | 2 +- tests/test_lane_shape_thresholds.py | 59 +++++++++++++++ 5 files changed, 139 insertions(+), 27 deletions(-) create mode 100644 docs/decisions/ADR-0123-symbolic-logic-shape-remap.md diff --git a/core/capability/expert_demo.py b/core/capability/expert_demo.py index c3a798a1..680f3be4 100644 --- a/core/capability/expert_demo.py +++ b/core/capability/expert_demo.py @@ -58,7 +58,7 @@ LANE_SHAPE_REGISTRY: dict[str, str] = { "cognition": "cognition_shape", "elementary_mathematics_ood": "accuracy_shape", "foundational_physics_ood": "accuracy_shape", - "symbolic_logic": "symbolic_logic_shape", + "symbolic_logic": "inference_shape", "hebrew_fluency": "accuracy_shape", "koine_greek_fluency": "accuracy_shape", "inference_closure": "inference_shape", @@ -160,7 +160,6 @@ def _check_refusal_shape(lane_id: str, metrics: Mapping[str, Any]) -> tuple[bool SHAPE_CHECKERS: dict[str, Any] = { "cognition_shape": _check_cognition_shape, "accuracy_shape": _check_accuracy_shape, - "symbolic_logic_shape": _check_accuracy_shape, "inference_shape": _check_inference_shape, "refusal_shape": _check_refusal_shape, } diff --git a/docs/decisions/ADR-0123-symbolic-logic-shape-remap.md b/docs/decisions/ADR-0123-symbolic-logic-shape-remap.md new file mode 100644 index 00000000..d5bc1140 --- /dev/null +++ b/docs/decisions/ADR-0123-symbolic-logic-shape-remap.md @@ -0,0 +1,71 @@ +# ADR-0123 — `symbolic_logic` Lane-Shape Remap (ADR-0109 Amendment) + +**Status:** Accepted +**Date:** 2026-05-22 +**Author:** CORE agents + reviewers +**Amends:** ADR-0109 +**Depends on:** ADR-0109, ADR-0122 + +--- + +## Context + +Under [ADR-0109](file:///Users/kaizenpro/.gemini/antigravity/worktrees/core/fix-symbolic-logic-shape/docs/decisions/ADR-0109-lane-shape-aware-thresholds.md), threshold verification rules are lane-shape-aware, mapping specific lane IDs to defined metric shapes. [ADR-0109](file:///Users/kaizenpro/.gemini/antigravity/worktrees/core/fix-symbolic-logic-shape/docs/decisions/ADR-0109-lane-shape-aware-thresholds.md) mapped the `symbolic_logic` lane to `symbolic_logic_shape`, which internally dispatched to the accuracy-shape threshold checker (`_check_accuracy_shape`). + +However, as documented in the deferred promotion of `systems_software` ([ADR-0122](file:///Users/kaizenpro/.gemini/antigravity/worktrees/core/fix-symbolic-logic-shape/docs/decisions/ADR-0122-systems-software-audit-passed-deferred.md)), the `symbolic_logic` lane output payload actually contains inference-style metrics (`all_pass_rate`, `replay_determinism`, and `overall_pass`) rather than accuracy-shape metrics (`accuracy` or `passed/total`). This mismatch caused the gate to fail closed with the error message: `lane 'symbolic_logic' missing accuracy (and no passed/total fallback)`. + +This amendment corrects the mapping to unblock the `systems_software` promotion. + +--- + +## Decision + +Re-map the `symbolic_logic` lane to `inference_shape` within the `LANE_SHAPE_REGISTRY` in [core/capability/expert_demo.py](file:///Users/kaizenpro/.gemini/antigravity/worktrees/core/fix-symbolic-logic-shape/core/capability/expert_demo.py): + +```python +LANE_SHAPE_REGISTRY["symbolic_logic"] = "inference_shape" +``` + +### Rationale +The `symbolic_logic` lane validates propositional inference closure. Because it checks deterministic symbolic inferences rather than approximate/statistical accuracy scalars, it naturally produces the standard inference-style metrics: +- `all_pass_rate` +- `replay_determinism` +- `overall_pass` + +Mapping it to `inference_shape` aligns the contract verification logic with the lane's actual runtime evidence schema. + +Additionally, because no other lane in the registry maps to `symbolic_logic_shape`, this shape checker is retired and removed from `SHAPE_CHECKERS` to preserve code cleanliness and avoid dead-shape drift. + +--- + +## Invariants + +### `inference_shape_thresholds_applied` +The existing `inference_shape` thresholds defined in [ADR-0109](file:///Users/kaizenpro/.gemini/antigravity/worktrees/core/fix-symbolic-logic-shape/docs/decisions/ADR-0109-lane-shape-aware-thresholds.md) now govern `symbolic_logic` verification: +- `all_pass_rate >= 0.95` +- `replay_determinism == 1.0` +- `overall_pass == True` + +--- + +## Acceptance Evidence + +Accepted when: +- The registry mapping in [core/capability/expert_demo.py](file:///Users/kaizenpro/.gemini/antigravity/worktrees/core/fix-symbolic-logic-shape/core/capability/expert_demo.py) is amended to map `symbolic_logic` to `inference_shape`. +- Unused `symbolic_logic_shape` is removed from `SHAPE_CHECKERS`. +- A unit test `TestSymbolicLogicShapeGate` in [tests/test_lane_shape_thresholds.py](file:///Users/kaizenpro/.gemini/antigravity/worktrees/core/fix-symbolic-logic-shape/tests/test_lane_shape_thresholds.py) asserts that: + - `resolve_lane_shape("symbolic_logic") == "inference_shape"` + - `symbolic_logic` results carrying compliant inference-style metrics pass the gate successfully. + +--- + +## Consequences + +- The contract blocker for `systems_software` is resolved: the lane gate now evaluates `symbolic_logic` outputs under the correct metric schema. +- The deferral in [ADR-0122](file:///Users/kaizenpro/.gemini/antigravity/worktrees/core/fix-symbolic-logic-shape/docs/decisions/ADR-0122-systems-software-audit-passed-deferred.md) can be resolved in a subsequent promotion attempt (likely ADR-0124) when a signed promotion claim is recorded. + +--- + +## Out of Scope + +- Actually signing the `systems_software` claim or updating the `audit_passed_claims` in `reviewers.yaml` (reserved for a follow-up promotion ADR). diff --git a/tests/test_adr_0122_deferral.py b/tests/test_adr_0122_deferral.py index 8d105596..eb20027d 100644 --- a/tests/test_adr_0122_deferral.py +++ b/tests/test_adr_0122_deferral.py @@ -37,26 +37,12 @@ class TestAdr0122Deferral: assert row["predicates"]["audit_passed"] is False def test_named_blocker_matches_gate_reason(self) -> None: - reviewer = Reviewer( - reviewer_id="shay-j", - display_name="Joshua Shay", - role="primary", - domains=("*",), - review_scope=("pack", "proposal", "chain", "eval"), - provenance="adr-0092:bootstrap:2026-05-21", - ) - claim = ExpertDemoClaim( - domain_id="systems_software", - evidence_lanes=_SYSTEMS_LANES, - evidence_revision="adr-0122:reviewed:2026-05-22", - signed_by="shay-j", - claim_digest="0" * 64, - ) - registry = ReviewerRegistry( - schema_version=1, - reviewers=(reviewer,), - expert_demo_claims=(claim,), - ) + from pathlib import Path + from core.capability.reviewers import load_reviewer_registry + from core.capability.sources import LEDGER_SOURCES + + repo_root = Path(__file__).resolve().parent.parent + registry = load_reviewer_registry(repo_root / LEDGER_SOURCES.reviewers) lane_results = materialise_lane_results(_SYSTEMS_LANES, fetch_split=_fetch) verdict = evaluate_expert_demo( @@ -68,7 +54,4 @@ class TestAdr0122Deferral: ) assert verdict.passed is False - assert ( - verdict.reason - == "lane 'symbolic_logic' missing accuracy (and no passed/total fallback) (split=public)" - ) + assert verdict.reason == "no audit_passed_claims entry for this domain" diff --git a/tests/test_expert_demo_contract.py b/tests/test_expert_demo_contract.py index 8078fbcd..892e4e9b 100644 --- a/tests/test_expert_demo_contract.py +++ b/tests/test_expert_demo_contract.py @@ -62,7 +62,7 @@ _SHAPE_FIXTURES = { "inference_closure": _INFERENCE_METRICS, "elementary_mathematics_ood": _ACCURACY_METRICS, "foundational_physics_ood": _ACCURACY_METRICS, - "symbolic_logic": _ACCURACY_METRICS, + "symbolic_logic": _INFERENCE_METRICS, "hebrew_fluency": _ACCURACY_METRICS, "koine_greek_fluency": _ACCURACY_METRICS, } diff --git a/tests/test_lane_shape_thresholds.py b/tests/test_lane_shape_thresholds.py index 23d19d34..5990dbca 100644 --- a/tests/test_lane_shape_thresholds.py +++ b/tests/test_lane_shape_thresholds.py @@ -162,3 +162,62 @@ class TestShapeThresholdValues: def test_inference_shape_minimums(self) -> None: assert ALL_PASS_RATE_MIN == 0.95 assert REPLAY_DETERMINISM_MIN == 1.0 + + +class TestSymbolicLogicShapeGate: + def test_symbolic_logic_resolves_to_inference_shape(self) -> None: + assert resolve_lane_shape("symbolic_logic") == "inference_shape" + + def test_symbolic_logic_with_inference_metrics_passes(self) -> None: + reviewer = Reviewer( + reviewer_id="shay-j", + display_name="Joshua Shay", + role="primary", + domains=("*",), + review_scope=("pack", "proposal", "chain", "eval"), + provenance="adr-0092:bootstrap:2026-05-21", + ) + + metrics = { + "all_pass_rate": 0.98, + "replay_determinism": 1.0, + "overall_pass": True, + } + + lane_results = { + "symbolic_logic": { + "public": metrics, + "holdout": metrics, + } + } + + from core.capability.expert_demo import derive_evidence_digest + digest = derive_evidence_digest( + domain_id="systems_software", + evidence_revision="rev1", + evidence_lanes=("symbolic_logic",), + lane_results=lane_results, + ) + + claim = ExpertDemoClaim( + domain_id="systems_software", + evidence_lanes=("symbolic_logic",), + evidence_revision="rev1", + signed_by="shay-j", + claim_digest=digest, + ) + + registry = ReviewerRegistry( + schema_version=1, reviewers=(reviewer,), expert_demo_claims=(claim,) + ) + + verdict = evaluate_expert_demo( + domain_id="systems_software", + reasoning_capable=True, + registry=registry, + domain_lanes=("symbolic_logic",), + lane_results=lane_results, + ) + assert verdict.passed is True + assert verdict.reason == "all audit-passed predicates satisfied" +