Files
C.E.L_Slide_test2/.orchestrator/tmp/u14_comment.md
T

6.6 KiB

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]