Skip to content

fix: try the scale step on the selected page before spending the ISO and the sheet (#1338) - #1340

Merged
pzfreo merged 3 commits into
mainfrom
fix/issue-1338-scale-before-page-escalation
Aug 25, 2026
Merged

fix: try the scale step on the selected page before spending the ISO and the sheet (#1338)#1340
pzfreo merged 3 commits into
mainfrom
fix/issue-1338-scale-before-page-escalation

Conversation

@pzfreo

@pzfreo pzfreo commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Fixes #1338. Two commits: the fixture the tests need, then the fix.

The defect

The automatic ladder's only recovery order was drop the optional ISO, then escalate the
page
, so an incomplete plan could settle on a candidate strictly worse than one it never
reached. GRM-03 (28.7 × 10 × 10 mm) settled on 5:1/A3 without its ISO while
5:1/A4 is clean with it — same scale, smaller sheet, pictorial view retained.

Raising the drawing scale is how the ladder buys annotation room, and text height is fixed
in page mm — so every step up it shrinks the text relative to the part. Spending a sheet
size and an optional view before trying the cheaper move on the sheet already chosen was
the wrong order.

The fix

The bounded larger-scale trial on the already-selected page — the one #1155 added for a
conservative recovery detail — now also runs when the plan is incomplete, and runs first.
Both callers share one helper (_try_larger_scales_on_selected_page) instead of a second
copy of the loop.

Unchanged from #1155's contract: the hard two-candidate budget, confinement to the settled
page and arrangement, compilation through the ordinary pipeline, and a win only by passing
the same structural, required-outcome and (when the failure was axial) axial-coverage gates
the larger sheet would have had to pass. Every attempt, rejection and winner is still
recorded in the structured scale decision.

Measured

pmi="off", on the fixtures:

before after
plain grm03 fixture 5:1/A4, no ISO 5:1/A4, with ISO, no error/warning issues at all
grm03 AP242+PMI 5:1/A3, no ISO 5:1/A4, with ISO, same one code either way
five-step synthetic (#1299) 5:1/A3, no ISO 5:1/A4, with ISO, all five step lengths
explicit page="A4" incomplete 2:1 (2 shoulders unlocated) 5:1/A4, axial_length_missing gone

"Same one code either way" is the honest form, and CI is why this line reads as it does — see
below. The AP242 fixture and the five-step profile each carry one pre-existing
annotation_ink_overlap ('2' draws 2.2 mm of line-work through the label '0.5'), and it is
identical on the A3 fallback this change avoids. The recovery neither causes nor cures it —
it is the step-chain collision class tracked by #1331 / #1333. No candidate carries an error,
a dropped outcome, or a missing axial length.

An explicit page pins the sheet, not the scale, so the trial applies there too: it fills
the sheet the caller chose instead of returning an incomplete layout on it.

GRM-03 with pmi="annotate" is deliberately unchanged at 10:1/A1. The same-page trial is
attempted and rejected (recovery_detail_retained, then structural_error), so this does not
paper over #1336 — that issue is about what a single dropped callout may buy, and stays open.

Test expectations that moved

Ten tests failed on the first full run. Each new outcome was verified as the better drawing
before the expectation was rewritten — none was adjusted to whatever the code now prints:

New tests assert the precondition (2:1/A4 genuinely is axially incomplete, so the recovery
is exercised) and that relaxing the named mechanism changes the outcome — with
_AUTOMATIC_UPSCALE_TRIAL_LIMIT monkeypatched to 0 the same part falls back to the pre-#1338
A3-without-ISO result.

The first CI run failed — what it was

The first push failed one test on all five Linux legs: my own
test_automatic_recovers_on_a4_at_a_larger_scale_instead_of_escalating_the_sheet, on an
annotation_ink_overlap warning that does not exist in this repo at the commit I branched
from. It was not platform divergence, and not a defect in the fix.

main had advanced by two commits — #1322 (Lint the line-work drawn through a label…) and
#1335 — and GitHub tests the merge, so CI was running a lint rule my base didn't have. The
branch is now rebased onto those commits, and the drawing was measured against the new rule
both ways: the A4 recovery and the A3 fallback report the same single code, so the
overlap is pre-existing and sheet-independent.

The test asserted "no warnings at all", which was never what #1338 is about. It now asserts
the requirement — no errors, nothing dropped, no missing axial length — plus a direct
comparison of the recovered drawing's lint codes against the avoided sheet's, which is the
assertion that would actually catch the recovery making a drawing worse.

Gates

  • Full fast tier on the rebase: 4872 passed, 5 skipped, 2 xfailed, 99.06 s
    (-n auto --dist worksteal).
  • scripts/pr-check --static exits 0 (exit code read, not output grepped).

Architecture

ADR 0004 owns outer scale/page selection, so it carries a new amendment (2026-08-25) recording
the order and its constraints, alongside the 2026-08-23 amendment this generalises. The
amendment also records what it does not settle: scale remains the ladder's only lever for a
placement shortage, and bounding what one dropped annotation may buy is #1336.

The fixture commit

GRM03 in test_issue_1296 / _1298 / _1299 pointed at an absolute path on one developer's
disk, so four tests — including the one pinning #1336's 841×594/10:1 outcome — skipped in CI
and for every other contributor.
The file is now
tests/fixtures/grm03_thumbwheel_drive_screw_ap242_pmi.step (identical sha256, so the existing
SHA guards still hold) and the skipif markers are gone. A new module asserts the fixture's own
preconditions — 18 PMI records, the #2004 internal thread behind #1336's escalating callout,
and that this is a different solid from the plain grm03 fixture (28.7 mm / 16 faces vs
23.5 mm / 14 faces), so the pair is never mistaken for a pmi on/off comparison of one part. All
four checks were mutated and all four fail. The four un-skipped tests cost 5.34 s, 5.23 s,
2.13 s and 0.51 s.

Known limits, stated rather than hidden

  • The recovery branch is still gated on the plan having an optional ISO, so a plan without one
    gets no replan at all. Pre-existing; widening it is a separate decision with no evidence in
    hand.
  • Each accepted upscale is built through the explicit scale+page path, whose conservative
    _fits predictor logs Requested scale 5 on (297.0, 210.0) page may not fit the 4-view layout at WARNING on a drawing lint then measures clean. Pre-existing for GRM-04 auto layout leaves most of A4 unused while dropping the Ø2.4 callout #1155's trials
    (that path also ships candidates built this way), but more common now. Demoting a predictor
    that the measurement contradicts would mean threading a flag through builder → analysis →
    compose and changing a documented contract — maintainer's call.

🤖 Generated with Claude Code

https://claude.ai/code/session_015Lp1DcM175cph7KE2fm5HF

Paul Fremantle and others added 2 commits August 25, 2026 11:56
…r tests

`GRM03` in tests/test_issue_1296, _1298 and _1299 pointed at
/Users/paul/steps/GRM-03_thumbwheel_drive_screw_AP242_PMI.step, so four tests —
including the one pinning the 841x594 / 10:1 outcome now reported as #1336 — ran on
one machine and skipped in CI and for every other contributor. The file is copied in
as tests/fixtures/grm03_thumbwheel_drive_screw_ap242_pmi.step; its sha256 is
unchanged (4b6462b9...010a21), so the three modules' existing SHA guards still hold
and their `skipif(not GRM03.exists())` markers are gone.

Measured, not assumed: those four tests take 5.34 s, 5.23 s, 2.13 s and 0.51 s; the
three modules plus the new one run 82 passed in 19.45 s in the fast tier.

The new module asserts the fixture's own preconditions — the pinned sha, 18 PMI
records (10 dimension + 8 manufacturing_requirement, part21 ids #2000..#2028), the
#2004 internal thread whose "DIA 1.6 tapping drill" becomes the callout that drives
#1336's escalation, and the single o1.6 dimension record. It also records that this
fixture is NOT the plain grm03 fixture with annotations added: 28.7 mm / 16 faces
against 23.5 mm / 14 faces, so the pair is not a pmi on/off comparison of one part.
All four checks were mutated (repointed at the PMI-free fixture) and all four fail.

Refs #1336

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Lp1DcM175cph7KE2fm5HF
…and the sheet

The automatic ladder's only recovery order was "drop the optional ISO, then escalate the
page", so an incomplete plan could settle on a candidate strictly worse than one it never
reached. GRM-03 (28.7 x 10 x 10 mm) settled on 5:1/A3 WITHOUT its ISO while 5:1/A4 covers
the same stations WITH it; the synthetic five-step profile behind #1299 did the same.

The bounded larger-scale trial on the already-selected page — the one #1155 added for a
conservative recovery detail — now also runs when the plan is incomplete, and runs FIRST.
Both callers share one helper (`_try_larger_scales_on_selected_page`) rather than a second
copy of the loop; the trial keeps its hard two-candidate budget, stays on the settled page
and arrangement, and wins only through the same structural, required-outcome and (when the
failure was axial) axial-coverage gates the larger sheet would have had to pass.

Measured on the fixtures, pmi="off", against the lint set on main (ie. including #1322's
`annotation_ink_overlap`):

  plain grm03       5:1/A4 no ISO   -> 5:1/A4 with ISO, no error/warning issues at all
  grm03 AP242 PMI   5:1/A3 no ISO   -> 5:1/A4 with ISO, same one code either way
  five-step (#1299) 5:1/A3 no ISO   -> 5:1/A4 with ISO, all five step lengths
  explicit page=A4  incomplete 2:1  -> 5:1/A4, axial_length_missing gone

"Same one code either way" is the honest form and is asserted as such: the AP242 fixture and
the five-step profile each carry one pre-existing `annotation_ink_overlap` ('2' draws 2.2 mm
of line-work through the label '0.5'), and it is identical on the A3 fallback this change
avoids. The recovery neither causes nor cures it — it is the step-chain collision class
tracked by #1331/#1333. No candidate carries an error, a dropped outcome, or a missing axial
length.

An explicit page pins the SHEET, not the scale, so the trial applies there too — it fills
the sheet the caller chose instead of returning an incomplete layout on it.
`pmi="annotate"` on GRM-03 is deliberately unchanged at 10:1/A1: the same-page trial is
attempted and rejected (recovery_detail_retained, then structural_error), so this does not
paper over #1336.

Test expectations that moved, each verified as the better drawing before being rewritten
(not adjusted to whatever the code now prints):
- #443's two GRM-03 tests: the truthful step lengths — its actual requirement — still hold;
  what the replan spends to get them changed, so `"iso" not in views` became `"iso" in`.
- #1299's six ladder tests: the real-part ones now assert same-page recovery; the fakes gain
  the two rejected same-page trials, and one fake needed a (297, 210) page mapping.
- #1308's golden bbox dict gains `note_iso_nts`; all 16 other boxes are byte-identical.
- docs/multi-feature-object-reference-workflow.md no longer quotes the four `authored_views`
  lines: with the automatic plan intact the emitter authors no view block at all.

New tests assert the precondition (2:1/A4 really is axially incomplete, so the recovery is
exercised), that relaxing the named mechanism changes the outcome (with
`_AUTOMATIC_UPSCALE_TRIAL_LIMIT` monkeypatched to 0 the same part falls back to the
pre-#1338 A3-without-ISO result), and that the recovery introduces no new lint code —
the avoided sheet's code list is compared against the recovered drawing's.

Full fast tier on this rebase: 4872 passed, 5 skipped, 2 xfailed in 99.06s.
`scripts/pr-check --static` exits 0.

Known limits, stated rather than hidden: the recovery branch is still gated on the plan
having an optional ISO, so a plan without one gets no replan at all — pre-existing, and
widening it is a separate decision with no evidence in hand. And each accepted upscale is
built through the explicit scale+page path, whose conservative `_fits` predictor logs
"Requested scale 5 on (297.0, 210.0) page may not fit the 4-view layout" at WARNING on a
drawing lint then measures clean — pre-existing for #1155's trials, now more common.

Fixes #1338. Refs #1336, #1155, #1299, #443, #1333.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Lp1DcM175cph7KE2fm5HF
@pzfreo
pzfreo force-pushed the fix/issue-1338-scale-before-page-escalation branch from 79cada5 to 66555f2 Compare August 25, 2026 11:00
@codecov

codecov Bot commented Aug 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.67%. Comparing base (062d152) to head (fec7297).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1340      +/-   ##
==========================================
+ Coverage   93.59%   93.67%   +0.08%     
==========================================
  Files          61       62       +1     
  Lines       20803    21274     +471     
  Branches     3972     4083     +111     
==========================================
+ Hits        19470    19928     +458     
+ Misses        774      767       -7     
- Partials      559      579      +20     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@pzfreo
pzfreo enabled auto-merge (squash) August 25, 2026 11:43
@pzfreo
pzfreo merged commit 3565077 into main Aug 25, 2026
16 checks passed
@pzfreo
pzfreo deleted the fix/issue-1338-scale-before-page-escalation branch August 25, 2026 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scale/page escalation over-sizes a 29 mm part: 5:1/A4 is clean but automatic picks 5:1/A3

1 participant