From 5d9e2d0748e8b642c5723d4002d6736608a7a607 Mon Sep 17 00:00:00 2001 From: Shay Date: Wed, 8 Jul 2026 07:54:53 -0700 Subject: [PATCH] test+feat: marker/fixture for depth packs; top-level node_depths+graph_anti_unify on CognitiveTurnResult; docstrings+pr draft; verifs captured - Addresses review items + goal plan acceptance. - Real tests committed driving shipped pipeline+result. - All per verification plan + checklist. --- chat/runtime.py | 2 +- core/cognition/pipeline.py | 12 ++++-- core/cognition/result.py | 14 +++++++ docs/3lang-depth-pr-plan.md | 77 +++++++++++++++++++++++++++++++++++++ pyproject.toml | 1 + tests/conftest.py | 51 ++++++++++++++++++++++++ tests/test_oov_pipeline.py | 29 ++++++++++++++ 7 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 docs/3lang-depth-pr-plan.md create mode 100644 tests/conftest.py diff --git a/chat/runtime.py b/chat/runtime.py index defd5fdf..2f427200 100644 --- a/chat/runtime.py +++ b/chat/runtime.py @@ -890,7 +890,7 @@ class ChatRuntime: if self.config.auto_contemplate and candidates_to_save: from teaching.contemplation import contemplate vault_probe = _vault_probe_for_context(self._context) if self._context else None - depth = getattr(self, '_last_node_depths', None) # from pipeline PropGraph depth (3-lang root propagation contract) + depth = getattr(self, '_last_node_depths', None) # from pipeline PropGraph depth (3-lang root propagation contract: see pipeline.py + CognitiveTurnResult docstring) candidates_to_save = [ contemplate(c, vault_probe=vault_probe, depth=depth) for c in candidates_to_save diff --git a/core/cognition/pipeline.py b/core/cognition/pipeline.py index 0017bf4c..7920c478 100644 --- a/core/cognition/pipeline.py +++ b/core/cognition/pipeline.py @@ -500,9 +500,11 @@ class CognitiveTurnPipeline: # Capture depths (post-enrich) to attrs for recognize chaining (AC1) + runtime contemplate depth= (real). # Propagation contract (3-lang depth on PropGraph spine): pipeline (after OOV/PropGraph construction) - # writes to runtime so that runtime.contemplate() and teaching paths can forward it without - # re-resolving packs. This is the current minimal cross-component channel; see review notes for - # future narrowing via explicit DepthCarrier or context object. + # writes _last_node_depths (and now also top-level on CognitiveTurnResult) so that + # runtime.contemplate(...) and teaching/contemplation paths forward depth= without + # re-resolving packs. Depths originate from pack_resolver + build_node_depths on GraphNode. + # This is the current minimal cross-component channel (observational). See docs/ and review. + if node_depths: self._current_node_depths = node_depths if effective_graph and effective_graph.nodes: @@ -723,6 +725,10 @@ class CognitiveTurnPipeline: authority_source=resolved.authority, substrate_hazard=substrate_hazard, oov_geometric_context=oov_geometric_context, + # 3-lang depth unification: surface the same data at top level on result + # (extracted from pre-computed node_depths var or oov_geometric_context to keep single source) + node_depths=node_depths if node_depths else None, + graph_anti_unify=(oov_geometric_context or {}).get("graph_anti_unify") if oov_geometric_context else None, ) # ------------------------------------------------------------------ diff --git a/core/cognition/result.py b/core/cognition/result.py index 6bc0e653..751dd5b6 100644 --- a/core/cognition/result.py +++ b/core/cognition/result.py @@ -33,6 +33,12 @@ class CognitiveTurnResult: substrate_hazard) so that the migration from hybrid legacy spine to the unified PropositionGraph substrate is completely inspectable and replay-diagnosable without ever breaking determinism or the 74 invariants. + + 3-lang depth fields (node_depths, graph_anti_unify) are populated for + he/grc PropGraph turns from the same data used for oov_geometric_context. + They are read-only / observational and never affect trace_hash or behavior. + The depth propagation contract (pipeline -> runtime _last_node_depths -> + contemplate(..., depth=) -> teaching) is documented alongside the code. """ # --- input layer --- @@ -189,3 +195,11 @@ class CognitiveTurnResult: # # Never folded into trace_hash in this phase. Never mutates field/vault. oov_geometric_context: dict | None = None + + # --- 3-lang depth PropGraph unification observability (read-only, not in trace_hash) --- + # Extracted from the same source as oov_geometric_context["node_depths"] / ["graph_anti_unify"] + # (or the pre-context data) during pipeline construction for he/grc root-aware paths. + # First-class optional fields so callers do not need to reach into the context dict. + # Never folded into trace_hash (observational only, like oov_geometric_context). + node_depths: dict | None = None + graph_anti_unify: dict | None = None diff --git a/docs/3lang-depth-pr-plan.md b/docs/3lang-depth-pr-plan.md new file mode 100644 index 00000000..a0fe4352 --- /dev/null +++ b/docs/3lang-depth-pr-plan.md @@ -0,0 +1,77 @@ +# PR Draft + Test Plan: 3-lang (he/grc) Depth PropositionGraph Unification + +## Branch +feat/3lang-depth-proposition-graph-unification + +## Summary of full commit history on branch (since integration) +- c1e723f1 feat: integrate 3-core-language depth into PropositionGraph spine for bidirectional unification +- 29284fae feat: implement phases 1-5 3-lang depth unification (antiunif root, default depth, contemplation prop, graph helper) +- 0dbcd63d feat: 3lang depth PropGraph unification - phase refinements, wiring, tests + session pickup cleanups/governance +- c57defdb chore: re-pin demo_* SHAs and regenerate CLAIMS.md for intentional 3lang depth spine changes +- 73bca055 chore: refresh canonical demo lane reports after 3lang depth re-pin +- c5dad6ac docs: update plan with 2026-07-08 pickup status + re-pin; archive Jul6 compact +- 3d08e103 chore: archive pickup seeds ... +- 05348e5a refactor: consolidate duplicate depth extraction — graph_planner.get_node_depths now delegates to build_node_depths +- 0e6dada0 chore(cleanup): complete post-pickup hygiene, consolidation, and review fixes for 3lang depth unification + +(See `git log --oneline c1e723f1..HEAD` and full `git log` for details.) + +## Key files changed (from git diff HEAD~6..HEAD and overall feature) +Core: +- recognition/depth_canonical.py (new pure canonicalize/build/enrich) +- recognition/anti_unifier.py +- core/cognition/pipeline.py (node_depths, graph_anti, attrs, result wiring, propagation) +- chat/pack_resolver.py (DEPTH_PACK_IDS) +- chat/runtime.py (depth reads + explicit attr) +- generate/graph_planner.py (GraphNode depth + get_node_depths delegation) +- generate/contemplation/pass_manager.py +- generate/problem_frame_contracts.py +- teaching/contemplation.py +- core/cognition/result.py (new node_depths, graph_anti_unify fields) +- tests/test_oov_pipeline.py (many depth tests + marker + new result fields test) +- tests/conftest.py (new, for requires_depth_packs fixture) +- pyproject.toml (marker registration) +- plan.md , docs/..., CLAIMS.md, scripts/verify_lane_shas.py, evals/demo_* reports (re-pin + docs) + +Full feature touched ~15-20 files; see `git diff --name-only c1e723f1..HEAD`. + +## Intentional demo SHA drifts story +- The two demo lanes (demo_composition, public_demo) intentionally drifted because we touched the spine: pipeline oov_geometric_context emission, runtime contemplate depth=, realizer-adjacent paths, GraphNode/PropositionGraph depth, anti-unif. +- All other 7/9 lanes remained stable (including post-CGA substrate). +- Re-pinned with `python scripts/verify_lane_shas.py --update` + `generate_claims.py` + refreshed reports (see commits c57defdb, 73bca055). +- Current: verify_lane_shas reports 9/9 match. +- This is expected/allowed per plan and compact: "only expected demo drifts". + +## 3-lang evidence (Hebrew roots, depths, gau) +- "define אמת" produces node_depths e.g. {'p0': {'language': 'he', 'root': 'א-מ-נ', ...}} +- graph_anti_unify: {'matched_roots': [('p0', 'א-מ-נ')], 'topology': ('p0',)} +- anti-unifier canonicalizes to root for he/grc agent slots (nid-keyed) +- contemplate depth= framing findings contain root +- teaching contemplation attaches depth_roots immutably +- Direct tests: test_anti_unifier_root_aware..., test_pipeline_..., test_graph_anti..., test_depth_canonical..., test_contemplate..., test_teaching... +- Captured in scratch + prior logs: root in proposition, ctx, gau, result top-level fields. +- All via real shipped entry points (ChatRuntime + CognitiveTurnPipeline + contemplate fns), not synth. + +## Test plan +- New/updated: marker @pytest.mark.requires_depth_packs + autouse fixture that does explicit skip (documenting DEPTH_PACK_IDS) if not resolvable. No silent no-depth branches for marked tests. +- New fields on CognitiveTurnResult proven by committed test + direct runs. +- Broader: verify_lane_shas 9/9; -k broad cognition/oov/anti/... pass. +- Smokes: multiple "define אמת" + teaching contemplate with depth produce consistent roots/matched. +- All changes preserve: frozen/immutable where appropriate, no trace_hash impact, exact recall, versor <1e-6. +- Run after edits: targeted depth tests + full verification plan steps. + +## How to verify locally +python3 scripts/verify_lane_shas.py +python -m pytest -q -m "requires_depth_packs" -k "depth_canonical or graph_anti or contemplate_depth" tests/test_oov_pipeline.py +python -m pytest -q --tb=no -k "cognition or oov or anti or construction or depth_canonical or graph_anti" tests/ +(plus direct python -c smokes as in plan) + +## Deviations / notes +None for this slice. Work followed plan acceptance + checklist. + +## References +- plan.md (full phases + pickup + cleanup sections) +- code review notes (MEDIUMs addressed: marker for tests, top-level fields on result, cleaned coupling + enrich) +- AGENTS.md invariants upheld. + +This is the draft for PR description + test plan. \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index e0982119..c8c237f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,4 +75,5 @@ markers = [ "quarantine: known-failing test tracked in conftest.py QUARANTINE registry when present; excluded from full-pytest CI gate. See docs/test-debt-quarantine.md.", "uses_default_engine_state: test intentionally exercises the process default engine-state directory; opt out of per-test default isolation. See docs/issues/default-engine-state-test-hygiene.md.", "slow: soak / bench / replay / proof / eval-matrix test that dominates suite wall-clock; classified in conftest.py SLOW_FILES/SLOW_TESTS (not in-file decorators). Fast lane: -m 'not quarantine and not slow'. See docs/testing-lanes.md.", + "requires_depth_packs: 3-lang (he/grc) depth tests require DEPTH_PACK_IDS packs to be resolvable/mounted; otherwise explicit skip with documented pack names. See plan for 3-lang unification.", ] diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..a8ee8d20 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,51 @@ +"""Project-wide pytest configuration and fixtures. + +Includes support for 3-lang depth pack requirements (he/grc via DEPTH_PACK_IDS). +""" + +from __future__ import annotations + +import pytest + + +def pytest_configure(config: pytest.Config) -> None: + """Register additional markers (also declared in pyproject.toml for docs).""" + config.addinivalue_line( + "markers", + "requires_depth_packs: 3-lang (he/grc) depth tests require DEPTH_PACK_IDS packs " + "to be resolvable/mounted; otherwise explicit skip with documented pack names. " + "See 3-lang depth PropGraph unification work and plan.md.", + ) + + +@pytest.fixture(autouse=True) +def _enforce_depth_packs_if_marked(request: pytest.FixtureRequest) -> None: + """If test is marked requires_depth_packs, verify at least one DEPTH_PACK can resolve a Hebrew term. + Produces explicit skip (with pack names) rather than silent no-depth execution path. + """ + if request.node.get_closest_marker("requires_depth_packs"): + try: + from chat.pack_resolver import DEPTH_PACK_IDS, resolve_entry + except Exception as e: # pragma: no cover - import guard + pytest.skip(f"requires_depth_packs: pack_resolver unavailable ({e}); packs={DEPTH_PACK_IDS if 'DEPTH_PACK_IDS' in dir() else 'unknown'}") + + if not DEPTH_PACK_IDS: + pytest.skip("requires_depth_packs: DEPTH_PACK_IDS is empty") + + # Use a known Hebrew term that the he depth packs should ground for root + term = "אמת" + available = False + for pid in DEPTH_PACK_IDS: + try: + if resolve_entry(term, pack_ids=(pid,)) is not None: + available = True + break + except Exception: + continue + + if not available: + pytest.skip( + f"requires_depth_packs: none of DEPTH_PACK_IDS={DEPTH_PACK_IDS} " + f"resolvable for term='{term}' (he/grc depth packs not mounted or not providing root data)" + ) + # else: proceed to run the test fully with real depth data diff --git a/tests/test_oov_pipeline.py b/tests/test_oov_pipeline.py index f3e41900..fb4334b6 100644 --- a/tests/test_oov_pipeline.py +++ b/tests/test_oov_pipeline.py @@ -254,6 +254,7 @@ def test_aggregator_missing_root_returns_empty(tmp_path: Path) -> None: # Direct unit test for shipped anti_unifier root-aware logic (AC1) +@pytest.mark.requires_depth_packs def test_anti_unifier_root_aware_with_depths(): """Direct test of derive_recognizer + recognize with depths for 3-lang root canonicalization. Root-equivalent (surface vs root form) must produce equivalent recognizers/outcomes. @@ -300,6 +301,7 @@ def test_anti_unifier_root_aware_with_depths(): assert "n1" in str(depths_he) # depths passed with node_id +@pytest.mark.requires_depth_packs def test_pipeline_node_depths_emission_with_resolver_3lang(): """Direct exercise of shipped pipeline OOV context emission using 3-lang depth from pack_resolver (changed code path).""" from chat.pack_resolver import resolve_entry, DEFAULT_RESOLVABLE_PACK_IDS, DEPTH_PACK_IDS @@ -340,6 +342,7 @@ def test_pipeline_node_depths_emission_with_resolver_3lang(): # Direct test for AC4 graph topology + depths anti-unif helper +@pytest.mark.requires_depth_packs def test_graph_anti_unify_with_depths(): from recognition.anti_unifier import graph_anti_unify topo = ("n1", "n2") @@ -352,6 +355,7 @@ def test_graph_anti_unify_with_depths(): # Direct committed tests for recognition/depth_canonical shipped functions +@pytest.mark.requires_depth_packs def test_depth_canonical_direct(): from recognition.depth_canonical import canonicalize_token, canonicalize_agent_slot, build_node_depths, enrich_assessments_with_depth from recognition.outcome import FeatureBundle, EvidenceSpan @@ -380,6 +384,7 @@ def test_depth_canonical_direct(): print("depth_canonical direct tests passed") +@pytest.mark.requires_depth_packs def test_contemplate_depth_framing(): """AC5: direct test for pass_manager depth framing (real call to contemplate with depth).""" from generate.contemplation.pass_manager import contemplate @@ -389,6 +394,7 @@ def test_contemplate_depth_framing(): print("contemplate depth framing test passed") +@pytest.mark.requires_depth_packs def test_teaching_contemplate_depth_real_propagation(): """Real teaching.contemplation depth receive (no placeholder): attaches roots immutably.""" from teaching.discovery import DiscoveryCandidate, DiscoveryTrigger @@ -408,6 +414,29 @@ def test_teaching_contemplate_depth_real_propagation(): print("teaching depth real attach:", pc.get("depth_roots")) +@pytest.mark.requires_depth_packs +def test_cognitive_turn_result_has_depth_fields(): + """Prove the shipped CognitiveTurnResult now exposes node_depths and graph_anti_unify + as first-class optionals (populated from 3-lang PropGraph path). + """ + from chat.runtime import ChatRuntime + from core.cognition.pipeline import CognitiveTurnPipeline + rt = ChatRuntime() + pl = CognitiveTurnPipeline(runtime=rt) + res = pl.run("define אמת", max_tokens=2) + assert hasattr(res, "node_depths"), "node_depths must be attr on CognitiveTurnResult" + assert hasattr(res, "graph_anti_unify"), "graph_anti_unify must be attr on CognitiveTurnResult" + assert res.node_depths, "node_depths populated for he 3-lang case" + assert "p0" in (res.node_depths or {}) + assert (res.node_depths or {}).get("p0", {}).get("root") in ("א-מ-ן", "א-מ-נ") + assert res.graph_anti_unify + assert "matched_roots" in (res.graph_anti_unify or {}) + # also still in ctx for compat + ctx = res.oov_geometric_context or {} + assert (ctx.get("node_depths") or {}).get("p0", {}).get("root") in ("א-מ-ן", "א-מ-נ") + print("CognitiveTurnResult depth fields present and populated:", bool(res.node_depths), bool(res.graph_anti_unify)) + + # --------------------------------------------------------------------------- # Promotion # ---------------------------------------------------------------------------