diff --git a/tests/test_phase_z2_v4_fallback.py b/tests/test_phase_z2_v4_fallback.py index a8a2f44..7268b05 100644 --- a/tests/test_phase_z2_v4_fallback.py +++ b/tests/test_phase_z2_v4_fallback.py @@ -20,6 +20,9 @@ from typing import Optional import pytest +import inspect + +from src import phase_z2_pipeline from src.phase_z2_pipeline import lookup_v4_match_with_fallback @@ -292,42 +295,25 @@ def test_existing_trace_shape_does_not_regress(patch_selector_deps): assert trace["selection_path"] == "rank_1" -# ─── Case 7 : Step 9 application_plan candidate_evidence + fallback_chain alias ─── +# ─── Case 7 : Step 9 production-source guard (Codex #20 blocker fix) ─── -def test_step9_candidate_evidence_field_and_alias_equality(): - """Codex #16 idea A + Codex #17 idea E + Claude #19 / #21 — Step 9 application_plan - must expose `candidate_evidence` as the primary per-unit evidence field, with - `fallback_chain` kept as a compat alias pointing to the same data. +def test_step9_production_emits_candidate_evidence_and_alias(): + """Temporary production-source guard for IMP-05 Step 9 evidence fields. - Both fields must reference the same selection_trace.candidates payload so - downstream readers (new = candidate_evidence, legacy = fallback_chain) see - identical data. + Step 9 application-plan unit assembly is currently inline, so this test + checks the exact production assignments until IMP-32 extracts a helper. + Once that helper exists, replace this source-string guard with a direct + helper-call test. """ - # Synthetic selection_trace.candidates shape — mirrors selector output (Step 9 input) - fake_candidates = [ - {"rank": 1, "template_id": "MOCK_template_direct_a", "v4_label": "use_as_is", - "decision": "selected", "reason": "primary_selected"}, - {"rank": 2, "template_id": "MOCK_template_direct_b", "v4_label": "use_as_is", - "decision": "skipped", "reason": None}, - ] + source = inspect.getsource(phase_z2_pipeline) + candidate_line = '"candidate_evidence": selection_trace.get("candidates", [])' + alias_line = '"fallback_chain": selection_trace.get("candidates", [])' - # Simulated Step 9 application_plan unit payload (post-Step-3 schema) - selection_trace = {"candidates": fake_candidates} - unit_payload = { - "candidate_evidence": selection_trace.get("candidates", []), - "fallback_chain": selection_trace.get("candidates", []), - } - - # candidate_evidence must be present as the primary field - assert "candidate_evidence" in unit_payload - assert unit_payload["candidate_evidence"] == fake_candidates - - # fallback_chain compat alias must reference the same data (no regression for legacy readers) - assert "fallback_chain" in unit_payload - assert unit_payload["fallback_chain"] == unit_payload["candidate_evidence"] - assert unit_payload["fallback_chain"] is unit_payload["candidate_evidence"] or \ - unit_payload["fallback_chain"] == unit_payload["candidate_evidence"] + assert candidate_line in source + assert alias_line in source + assert source.index(candidate_line) < source.index(alias_line) + assert "compat alias; prefer candidate_evidence" in source # ─── Case 8 : Step 20 slide-status qualifier fields presence + defensive default