This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
Executing unit: u10
|
||||
|
||||
[Claude #N] Stage 3 code-edit Round #N -- unit u10
|
||||
|
||||
### unit_executed
|
||||
u10 -- pytest coverage for `plan_zone_ratio_retry` multi-donor aggregation (u1 surface). Three deterministic cases per Stage 2 contract.
|
||||
|
||||
### files_changed
|
||||
- tests/phase_z2/test_phase_z2_retry_multi_donor.py (new file, untracked -- single file scope)
|
||||
|
||||
### diff_summary
|
||||
- New test module exercises three Stage 2 cases against `src.phase_z2_retry.plan_zone_ratio_retry`:
|
||||
1. `test_single_donor_sufficient_regression` -- single donor with abundant slack (200px) covers `target_added_px=24` (excess_y 20 + DEFAULT_SAFETY_MARGIN_PX 4). Asserts backward-compat fields preserved: `donor_zone_position`, `donor_reduced_px`, plus new fields `donors_used == [{position: bottom, reduced_px: 24, slack_before: 200, slack_after: 176}]`, `aggregate_slack_used=24`, `aggregate_slack_available=200`. Verifies `zones_after` math (top 200->224, bottom 400->376).
|
||||
2. `test_multi_donor_pass_primary_insufficient_secondary_covers` -- primary donor (middle, slack 50) insufficient for `target_added_px=70`, but aggregate (middle 50 + bottom 40 = 90) covers. Asserts greedy slack-desc order: primary takes full 50px, secondary takes remaining 20px. Verifies `donor_zone_position=middle` (primary lock = legacy router classifier substring stability), `donor_reduced_px=50`, `donors_used` ordering + per-donor `reduced_px`, and `zones_after` (top 300->370, middle 250->200 floor, bottom 240->220).
|
||||
3. `test_multi_donor_fail_aggregate_insufficient` -- all donors combined (middle 10 + bottom 15 = 25) cannot cover `target_added_px=70`. Asserts `feasible=False`, `donors_used==[]`, `aggregate_slack_used=0`, and primary-donor substring preservation in `failure_reason` (contains "donor", "slack", "<") -- ensures `classify_retry_failure` still routes through `donor_slack_insufficient` (failure_router substring contract at `src/phase_z2_failure_router.py:121-136`). Asserts `zones_after` unchanged on fail (revert-friendly).
|
||||
- Helper functions kept module-local (`_zone`, `_overflow_clean`, `_classification`) -- no shared fixture module added (single-test file scope, Stage 2 scope_lock).
|
||||
- No source edits -- test-only unit; observes existing u1 contract.
|
||||
|
||||
### verification
|
||||
- `python -m pytest -q tests/phase_z2/test_phase_z2_retry_multi_donor.py` -> **3 passed** in 0.02s.
|
||||
- Math check on case 2: `math.ceil(66.0) + 4 = 70`. `donor_candidates` sorted by slack desc = [middle(50), bottom(40)]. `aggregate=90 >= 70` -> feasible branch. Greedy: middle.take=min(50,70)=50, remaining=20; bottom.take=min(40,20)=20, remaining=0. Primary=middle, donor_reduced_px=50 OK.
|
||||
- Math check on case 3: `aggregate=25 < 70` -> infeasible branch at `src/phase_z2_retry.py:167-185`. `donor_candidates[0].position='bottom'` (slack 15 > 10), so `donor_zone_position='bottom'`. `failure_reason` substring includes `primary donor 'bottom' slack 15px (aggregate 25px ... ) < target_added_px 70px` -- all three substring checks pass.
|
||||
- File line count: 147 total (12-line module docstring + 3 helper fns + 3 test fns). Asserts-per-test density high to lock both legacy and new fields against future regression. Within Stage 2 single-file scope.
|
||||
- Pre-existing `tests/phase_z2/test_retry_gate.py` 4-test suite unaffected -- separate gate-surface coverage; u10 covers post-gate plan logic.
|
||||
|
||||
### remaining_units
|
||||
- u11 -- tests for `plan_cross_zone_redistribute` (multi-role feasible / single-role infeasible)
|
||||
- u12 -- tests for `plan_glue_compression` (scoped CSS lock + envelope insufficient)
|
||||
- u13 -- tests for `plan_font_step_compression` (feasible / 8px floor / missing text_metrics)
|
||||
- u14 -- tests for failure_router cascade routing + status registration
|
||||
- u15 -- end-to-end `_attempt_salvage_chain` (3 fixture cases including all-fail revert)
|
||||
|
||||
### follow_up_issue_candidates
|
||||
None -- u10 surface stays within Stage 2 scope_lock. No new axis observed.
|
||||
|
||||
=== EVIDENCE ===
|
||||
- `git diff --stat src/phase_z2_retry.py src/phase_z2_failure_router.py src/phase_z2_router.py src/phase_z2_pipeline.py` -> unchanged from u9 baseline (no source edit in u10).
|
||||
- `git status --short tests/phase_z2/` -> only `?? tests/phase_z2/test_phase_z2_retry_multi_donor.py` (single new file).
|
||||
- `python -m pytest -q tests/phase_z2/test_phase_z2_retry_multi_donor.py` -> 3 passed.
|
||||
- `wc -l tests/phase_z2/test_phase_z2_retry_multi_donor.py` -> 147 lines.
|
||||
- Source contract anchors: `src/phase_z2_retry.py:43-215` (multi-donor plan), `src/phase_z2_failure_router.py:121-136` (classifier substring lock).
|
||||
Reference in New Issue
Block a user