This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
Executing unit: u14
|
||||
|
||||
[Claude #N] Stage 3 code-edit Round #N -- unit u14
|
||||
|
||||
### unit_executed
|
||||
u14 -- pytest coverage for `phase_z2_failure_router` cascade (u2/u3/u7 surface). Four deterministic cases per Stage 2 contract: donor_slack_insufficient → cross_zone_redistribute IMPLEMENTED, no_donor_candidates → cross_zone_redistribute IMPLEMENTED, three new salvage failure types route to expected next actions (cross_zone_insufficient→glue, glue→font, font→layout_adjust), rerender_still_fails → frame_reselect preserved.
|
||||
|
||||
### files_changed
|
||||
- tests/phase_z2/test_phase_z2_failure_router_cascade.py (new file, untracked -- single file scope, test-only)
|
||||
|
||||
### diff_summary
|
||||
- New test module exercises four Stage 2 cases against `src.phase_z2_failure_router.classify_retry_failure`, `route_retry_failure`, `enrich_retry_trace_with_failure_classification`, `NEXT_ACTION_BY_FAILURE`, `NEXT_ACTION_IMPLEMENTATION_STATUS`:
|
||||
|
||||
1. `test_donor_slack_insufficient_routes_to_cross_zone_redistribute_implemented` -- Stage 1 root cause. retry_trace with `plan.feasible=False` + failure_reason containing `primary donor 'bottom' slack 15px ... < target_added_px 70px` matches the substring contract at `src/phase_z2_failure_router.py:206-217`. Asserts `failure_type=="donor_slack_insufficient"`, `route_retry_failure(...).next_proposed_action=="cross_zone_redistribute"` and `next_action_implementation_status=="IMPLEMENTED"` (u7 lock at `src/phase_z2_failure_router.py:142-149`). Also exercises the enrichment wrapper end-to-end: `enrich_retry_trace_with_failure_classification(trace)` mutates trace adding both `failure_classification` and `next_action_proposal` fields.
|
||||
|
||||
2. `test_no_donor_candidates_routes_to_cross_zone_redistribute_implemented` -- second cascade entry. retry_trace with `plan.feasible=False` + failure_reason `"no donor candidates"` matches `src/phase_z2_failure_router.py:220-227`. Asserts `failure_type=="no_donor_candidates"` and `next_proposed_action=="cross_zone_redistribute"` with `IMPLEMENTED` status. Confirms both `donor_slack_insufficient` and `no_donor_candidates` share the same cascade entry point (Stage 2 design — both signal "exhausted within current frame, try cross-zone").
|
||||
|
||||
3. `test_three_new_salvage_failure_types_route_to_expected_cascade_actions` -- u2/u3/u7 lock. Verifies the locked `NEXT_ACTION_BY_FAILURE` table directly (3 assertions: `cross_zone_redistribute_insufficient→glue_compression`, `glue_absorption_insufficient→font_step_compression`, `font_step_insufficient→layout_adjust`) AND the `NEXT_ACTION_IMPLEMENTATION_STATUS` lock (`glue_compression`/`font_step_compression`=IMPLEMENTED, `layout_adjust`=MISSING -- since IMP-12 stops short of layout_adjust per Stage 1 scope_lock). Then iterates the three classifier paths via `salvage_steps[-1]`: for each `(action, expected_ftype, expected_next)` triple, constructs a retry_trace with `salvage_steps=[{action, passed:False, failure_reason}]` and asserts the classifier surfaces `expected_ftype` (per `SALVAGE_FAILURE_TYPE_BY_ACTION` at `src/phase_z2_failure_router.py:85-89`) and the router emits `expected_next`. End-to-end classify→route round-trip.
|
||||
|
||||
4. `test_rerender_still_fails_preserved_routes_to_frame_reselect` -- pre-cascade behavior preserved. retry_trace with `plan.feasible=True` + `rerender_attempted=True` + `retry_passed=False` hits `case 3` at `src/phase_z2_failure_router.py:240-246`. Asserts `failure_type=="rerender_still_fails"` and `next_proposed_action=="frame_reselect"` -- u3 cascade rewire did NOT clobber the pre-existing visual-fail path. Important regression guard since u3 added 3 new entries to `NEXT_ACTION_BY_FAILURE` without rewriting the rerender row.
|
||||
|
||||
- No source edits -- test-only unit; observes existing u2/u3/u7 contract on `src/phase_z2_failure_router.py`.
|
||||
- File metrics: 119 total lines (test module incl. docstring + 4 tests). Net diff = 119 added / 0 removed.
|
||||
- Helper-free design (function-arg API takes simple dicts). No shared fixtures introduced (single-test-file scope per Stage 2 scope_lock).
|
||||
|
||||
### verification
|
||||
- `python -m pytest -q tests/phase_z2/test_phase_z2_failure_router_cascade.py` -> **4 passed in 0.02s**.
|
||||
- Cross-checked classifier paths against `src/phase_z2_failure_router.py`:
|
||||
- case 0.7 (salvage_steps last failed) at lines 170-187 -- handles the 3 new types via `SALVAGE_FAILURE_TYPE_BY_ACTION`.
|
||||
- case 2 donor patterns at lines 199-237 -- donor substring + no-donor-candidates substring.
|
||||
- case 3 rerender at lines 239-246 -- preserved.
|
||||
- Confirmed u7 status lock at `src/phase_z2_failure_router.py:142-149`: `cross_zone_redistribute`/`glue_compression`/`font_step_compression`==IMPLEMENTED; `layout_adjust`==MISSING.
|
||||
- Scope-lock per `feedback_phase_z_spacing_direction`: not applicable -- this unit is router classifier only, no CSS emission.
|
||||
- Verified the planned cascade test module `test_phase_z2_failure_router_cascade.py` is present in `tests/phase_z2/`; only `test_phase_z2_step17_salvage_chain.py` (u15) remains.
|
||||
|
||||
### diff_summary (numeric)
|
||||
- `wc -l tests/phase_z2/test_phase_z2_failure_router_cascade.py` -> 119
|
||||
- `git status --short` shows the file as `?? tests/phase_z2/test_phase_z2_failure_router_cascade.py` (untracked, scope-lock holds).
|
||||
|
||||
### remaining_units
|
||||
- u15 (end-to-end Step 17 _attempt_salvage_chain test with 3 cascade fixtures: (a) zone_ratio fail + cross_zone pass; (b) cross_zone fail + glue pass; (c) all 3 fail → (b)-revert preserved).
|
||||
|
||||
### follow_up_issue_candidates
|
||||
- None observed this round. `layout_adjust` status remains MISSING in `NEXT_ACTION_IMPLEMENTATION_STATUS` -- that's the intended terminal state of the deterministic salvage cascade per Stage 1 scope_lock (out-of-scope for IMP-12). If/when implemented, it would belong to a separate axis (referenced in Stage 1 out_of_scope list).
|
||||
|
||||
=== EVIDENCE ===
|
||||
Commands run:
|
||||
- `python -m pytest -q tests/phase_z2/test_phase_z2_failure_router_cascade.py` -> 4 passed in 0.02s
|
||||
- `git status --short` -> file untracked, src/ files unchanged
|
||||
- `wc -l tests/phase_z2/test_phase_z2_failure_router_cascade.py` -> 119
|
||||
- `Read src/phase_z2_failure_router.py` (full file, 318 lines)
|
||||
- `Read src/phase_z2_router.py` (full file, 188 lines -- confirmed u7 status lock)
|
||||
|
||||
Files checked:
|
||||
- src/phase_z2_failure_router.py:85-89 (SALVAGE_FAILURE_TYPE_BY_ACTION)
|
||||
- src/phase_z2_failure_router.py:94-102 (NEXT_ACTION_BY_FAILURE locked table)
|
||||
- src/phase_z2_failure_router.py:142-149 (NEXT_ACTION_IMPLEMENTATION_STATUS)
|
||||
- src/phase_z2_failure_router.py:170-187 (case 0.7 salvage_steps classifier)
|
||||
- src/phase_z2_failure_router.py:199-246 (case 2/3 plan/rerender classifier)
|
||||
- src/phase_z2_failure_router.py:261-318 (route_retry_failure + enrich wrapper)
|
||||
- tests/phase_z2/test_phase_z2_failure_router_cascade.py (new, 119 lines)
|
||||
|
||||
Remaining units: [u15]
|
||||
Reference in New Issue
Block a user