1 line
6.7 KiB
JSON
1 line
6.7 KiB
JSON
{"body": "[Claude #7] Stage 3 code-edit — IMP-47B u3\n\nExecuting unit: u3\n\n■ unit_executed\n- id: u3\n- summary: Mark override-selected reject units provisional\n\n■ files_changed\n- src/phase_z2_pipeline.py\n- tests/test_imp47b_override_provisional.py\n\n■ diff_summary\n- src/phase_z2_pipeline.py\n - Extracted the per-unit override application logic at L3648-3662 into\n a new module-level helper `_apply_frame_override_to_unit(unit, new_tid, v4)`\n placed right after `lookup_v4_candidates` (so the helper sits next to\n its dependency `lookup_v4_all_judgments`). Returns the meta_source\n string for the override book-keeping. Three probe layers, in order:\n 1. `unit.v4_candidates` exact match (non-reject; existing path) →\n copies frame_id / frame_number / confidence / label and returns\n `\"v4_candidates\"`.\n 2. **(new)** Full 32 V4 judgments probe via `lookup_v4_all_judgments`\n on the unit's primary `source_section_ids[0]`. When the override\n target template_id matches a `label=\"reject\"` judgment, copy the\n frame metadata, set `unit.label = \"reject\"` + `unit.provisional\n = True`, and return `\"v4_reject_judgment_provisional\"`. This is\n the IMP-47B u3 promotion that lets Step 12 (u4) admit the user-\n picked reject frame to the AI repair path — `_imp05_route_hint\n (\"reject\") = \"ai_adaptation_required\"` after u1 + `step12.py`\n provisional gate after u2.\n 3. Raw fall-through. Updates only `frame_template_id`, returns\n `\"raw_template_id_only\"` (existing behaviour for unknown\n templates).\n - Replaced the inline `match = None; for cand in ...` block inside the\n `if override_frames:` loop at L3648-3662 with a single call to the\n helper. Book-keeping (`frame_overrides_applied`, `print`) and the\n upstream catalog-presence guard / no-op skip / `frame_overrides_skipped`\n branches are untouched. Net runtime behavior for non-reject overrides\n is byte-identical (same field assignments, same return string\n `\"v4_candidates\"` / `\"raw_template_id_only\"`).\n - Augmented the Step 7-A comment block at L3614-3621 with an IMP-47B u3\n note explaining the reject-as-provisional promotion and the AI\n isolation contract guarantee (frame visual / contract untouched,\n auto frame swap forbidden — `[[feedback_ai_isolation_contract]]`).\n\n- tests/test_imp47b_override_provisional.py (new file)\n - Synthetic `_StubCandidate` (V4Match-like surface) + `_StubUnit`\n (CompositionUnit-like surface) — duck-typed to the helper's\n attribute reads only. Convention mirrors\n `tests/test_phase_z2_imp30_first_render.py` (MOCK_ prefix; no real\n catalog / V4 yaml dependency).\n - `_v4_with_reject(section_id, target_tid)` fixture builds a minimal\n V4 dict (mdx_sections → judgments_full32) with two judgments: a\n use_as_is decoy + the reject target. Two entries so the assertion\n proves the helper picks the matching reject specifically (not just\n \"any reject\").\n - 3 tests:\n - `test_override_to_reject_judgment_marks_unit_provisional` — user\n picks the reject frame → meta=`\"v4_reject_judgment_provisional\"`,\n frame_id / frame_number / confidence sourced from the reject\n judgment, label=\"reject\", provisional=True.\n - `test_override_to_v4_candidate_keeps_non_provisional` — user picks\n a non-reject candidate → meta=`\"v4_candidates\"`, label copied\n from candidate (light_edit), provisional stays False (normal-path\n AI=0 contract intact for this unit). V4 dict is empty so the\n full-judgment probe MUST NOT be reached.\n - `test_override_unknown_template_falls_through_without_provisional`\n — unknown template_id (not in v4_candidates, not in\n judgments_full32) → meta=`\"raw_template_id_only\"`, only\n frame_template_id updated; frame_id / label unchanged; provisional\n remains False.\n\n■ verification (scope-qualified)\n- `pytest -q tests/test_imp47b_override_provisional.py tests/test_phase_z2_section_assignment_override.py tests/test_phase_z2_ai_fallback_config.py tests/test_phase_z2_v4_fallback.py`\n → 36 passed in 4.18s (u3 helper + override regression + u1 baseline).\n- `pytest -q tests/phase_z2_ai_fallback/ tests/test_phase_z2_imp30_first_render.py`\n → 237 passed in 0.40s (full Phase Z AI fallback suite + IMP-30 first-\n render slice unchanged downstream of the helper extraction).\n- Out of u3 scope: full-tree regression deferred until u4 (Step 12 AI\n wiring) lands — `gather_step12_ai_repair_proposals` is still not called\n from `run_phase_z2_mvp1`, so the provisional flag set by u3 has no\n runtime AI side-effect yet (default-off contract preserved at every\n layer: `src/config.py:19` `ai_fallback_enabled=False`, `router.py:61-65`\n flag-off short-circuit, `step12.py` provisional gate from u2).\n\n■ guardrail check\n- AI isolation contract: helper mutates only the unit's V4-evidence\n fields (`frame_template_id` / `frame_id` / `frame_number` /\n `confidence` / `label`) plus the `provisional` flag. No frame swap\n (the requested frame is the one applied), no contract / partial /\n visual mutation, no MDX text touch.\n- No hardcoding: probe uses `unit.source_section_ids[0]` and the v4\n dict's own keys; no sample-specific reject handling.\n- 1 turn = 1 step: u3 only. No drafting of u4+.\n- Factual verification: every cited path/line grep-verified before edit\n (`src/phase_z2_pipeline.py:3648-3662` original inline block,\n `lookup_v4_all_judgments` at L748, `_v4_match_from_judgment` at\n L511-521, `_apply_frame_override_to_unit` insertion site at L811).\n- Auto-pipeline first: helper returns the same `meta_source` enum\n surface already consumed by `frame_overrides_applied` book-keeping —\n no review_required / review_queue insertion. Frontend (u11) will\n surface the resulting provisional flag through the existing zone /\n slide_status data flow that IMP-30 u5/u6 already wired.\n\n■ remaining_units\n- [u4, u5, u6, u7, u8, u9, u10, u11, u12, u13]\n\n■ follow_up_issue_candidates\n- (none for u3; helper uses exact-match v4 section lookup. Alias-keyed\n sections (`MdxSection.v4_alias_keys`, e.g. legacy decimal `04-2.1` →\n canonical `04-2-sub-1`) would fall through to `\"raw_template_id_only\"`\n without provisional promotion. In practice\n `unit.source_section_ids[0]` is the canonical V4-resolved key for any\n unit whose `v4_candidates` is non-empty; the alias edge case only\n surfaces when v4 missed entirely for the section, which is a separate\n axis from u3. Surface as a follow-up only if an MDX with aliased\n reject overrides exercises it in IMP-47B u10 E2E.)\n"} |