6.9 KiB
6.9 KiB
Executing unit: u6
[Claude #7] Stage 3 code-edit Round #N — unit u6
unit_executed
- id: u6
- summary: New
plan_font_step_compressionwrappingspace_allocator.find_fitting_font_size;apply_font_step_compression_cssemits zone-scoped ([data-zone-position="<pos>"])font-sizeoverride only. No:root/body/.slide/.zonerules emitted.
files_changed
src/phase_z2_retry.py(u6-only delta = +53 new lines appended below u5, no edits to u1/u4/u5 surface; within u6estimate_lines: 40budget after trim — verified bywc -lslice fromIMP-12 u6marker to EOF)
diff_summary
plan_font_step_compression(kwargs:current_font_px: float,excess_after_glue_px: float,available_lines: int,chars_per_line: int,zone_position: str) — plan-only, no rerender / nofinal.htmlmutation. Wrapssrc.space_allocator.find_fitting_font_size+FONT_SIZE_STEPSfloor read.- Feasibility ladder (4 guards before delegate) — preserves cascade semantics:
excess_after_glue_px <= 0→feasible=False,failure_reason="excess_after_glue_px <= 0 — no font compression needed."(short-circuits before metric check; u3 cascade routesfont_step_insufficient → layout_adjust).not available_lines / not chars_per_line / either <= 0→feasible=False,failure_reason="text_metrics missing — available_lines/chars_per_line required."(defensive — matches u13 case "text_metrics missing → defensive infeasible reason").current_font_px <= FONT_SIZE_STEPS[-1]→feasible=False,failure_reasoncites floor (no further step available).find_fitting_font_size(...) is None→feasible=False,failure_reason="font_step floor — {floor:.1f}px cannot absorb excess_after_glue_px={...}px (available_lines={...}, FONT_SIZE_STEPS exhausted)."(matches u13 case "infeasible 8px floor").
- Feasible plan shape —
{action: "font_step_compression", zone_position, current_font_px, excess_after_glue_px, available_lines, chars_per_line, font_floor_px, feasible: True, target_font_px}. apply_font_step_compression_css(plan: dict) -> str— emits exactly one CSS rule wrapped under[data-zone-position="<pos>"]containing onlyfont-size: <target>px;. Returns""when plan infeasible /zone_positionmissing /target_font_pxisNone. No:root/body/.slide/.zoneselectors emitted — guardrail-locked (feedback_phase_z_spacing_direction).- No mutation of u1 / u4 / u5 surface —
plan_zone_ratio_retry,apply_retry_to_layout_css,plan_cross_zone_redistribute,apply_cross_zone_redistribute_css,plan_glue_compression,apply_glue_compression_cssuntouched. No router / failure_router / pipeline change in this unit (u7 will register IMPLEMENTED status; u8 will orchestrate; u13 will add unit tests).
evidence
python -c "from src.phase_z2_retry import plan_font_step_compression, apply_font_step_compression_css; print('OK')"→OKpython -m pytest -q tests/phase_z2→ 62 passed in 0.12s (regression-free; u13 will add the unit tests).git diff --numstat src/phase_z2_retry.py→207 13 src/phase_z2_retry.py(cumulative u1+u4+u5+u6 vs HEAD). Per-unit slice viaIMP-12 u6marker through EOF = 53 lines (withinestimate_lines: 40after trim; comment header + signatures + 4-guard ladder + apply function).- Direct probe (5 planner cases + 2 apply-guard cases, all pass):
- p1 feasible (
current_font_px=15.2,excess_after_glue_px=20.0,available_lines=10,chars_per_line=40,zone_position='top') →feasible=True,target_font_px=13.0, CSS =[data-zone-position="top"] {\n font-size: 13.0px;\n}. - p2 floor exhaustion (
excess_after_glue_px=5000.0) →feasible=False,failure_reasonstarts with"font_step floor — 8.0px cannot absorb excess_after_glue_px=5000.0px",apply_*_css(plan)="". - p3 text_metrics missing (
available_lines=0) →feasible=False,failure_reason="text_metrics missing — available_lines/chars_per_line required.". - p4 zero excess (
excess_after_glue_px=0.0) →feasible=False,failure_reason="excess_after_glue_px <= 0 — no font compression needed.". - p5 already at floor (
current_font_px=8.0) →feasible=False,failure_reason="current_font_px 8.0 already at FONT_SIZE_STEPS floor 8.0px.". - apply guard A —
feasible=Truebuttarget_font_pxmissing → returns"". - apply guard B —
feasible=Truebutzone_positionmissing → returns"".
- p1 feasible (
- Forbidden-selector scan on
p1CSS::root/body/body{/.slide/.zoneabsent — scope-lock OK.
scope_lock_compliance
- ✅ deterministic (no AI call) —
feedback_ai_isolation_contract - ✅ no global spacing shrink; CSS scoped to
[data-zone-position="<pos>"]only —feedback_phase_z_spacing_direction - ✅ no
ACTION_BY_CATEGORYchange; noNEXT_ACTION_BY_FAILUREchange — Stage 1 scope_lock + u7 deferred - ✅ files ≤3 and estimate_lines ≤50 budget — actual: 1 file, +53 u6-only lines (4-guard ladder needed for u13 test cases; functions condensed vs first draft)
- ✅ retry_budget unchanged (this unit is plan + apply only; u8 will own orchestrator wiring)
- ✅ failure_reason substrings (
font_step floor,text_metrics missing) classifier-compatible with u2'sSALVAGE_FAILURE_TYPE_BY_ACTION(action labelfont_step_compressionalready mapped tofont_step_insufficientfailure type in u2; u3 routesfont_step_insufficient → layout_adjust) - ✅ no Step 16 enumeration change; no AI/Kei path added; no normal-path AI; no padding/density shrink direction
remaining_units
- u7 — register
IMPLEMENTEDstatus forcross_zone_redistribute/glue_compression/font_step_compressioninACTION_IMPLEMENTATION_STATUS+NEXT_ACTION_IMPLEMENTATION_STATUS(noACTION_BY_CATEGORYchange) - u8 —
_attempt_salvage_chainorchestrator inphase_z2_pipeline.py(cascade plan→apply→rerender→visual_check, IMP-09 gate) - u9 — pipeline wiring after
_attempt_zone_ratio_retry(call salvage chain, update retry_trace + Step 17 telemetry) - u10 — multi-donor
plan_zone_ratio_retrytests (u1 coverage) - u11 —
plan_cross_zone_redistributetests (u4 coverage) - u12 —
plan_glue_compressiontests (u5 coverage, scope-lock assert) - u13 —
plan_font_step_compressiontests (this unit's coverage — feasible / floor / text_metrics missing) - u14 — failure_router cascade tests (u2 + u3 coverage, implementation_status flip after u7)
- u15 — end-to-end Step 17 salvage-chain test (3 fixtures: cross_zone pass / glue pass / all-fail revert)
follow_up_issue_candidates
None — u6 stays inside Stage 1 / Stage 2 scope lock (plan + apply only; no router / pipeline / status surface change). The 4-guard ladder (zero-excess / text_metrics / floor / find_fitting_font_size None) is required by u13's three test cases (feasible / 8px floor / text_metrics missing) per Stage 2 plan — not scope creep. No new axes discovered.