Skip to content

Scanner: the selection pane (spec 088) - #428

Open
plainprogrammer wants to merge 49 commits into
mainfrom
088-scanner-selection-pane
Open

plainprogrammer wants to merge 49 commits into
mainfrom
088-scanner-selection-pane

Conversation

@plainprogrammer

Copy link
Copy Markdown
Owner

Scanner: the selection pane (spec 088)

Closes #345.

After a capture the collector sees their capture beside what was read, a status band that says how sure the scanner is, a row of card images (swipe, or Previous and Next) with the best match centred, one details block for the centred card, and one add button per finish. A confident match is one tap; the band says in an icon and words when the scanner is less sure. The interim scrolling body, "What the scanner read", the candidates grid and the Other printings frame are gone. Nothing about how a card is read or ranked changed (ruled 2026-11-13).

Spec: docs/specs/088-scanner-selection-pane/spec.md (1.0.3, approved at Gate A; the maintainer ruled the seven scope questions as recommended). Plan: plan.md (approved at Gate B). Verification and the implementation review: verification.md.

What it does

  • Band, three states from today's evidence (no change to the ranking; one new predicate, Candidate#card_sure?): success with the evidence ("Matched by its collector line", "…, one digit corrected", "Matched by its artwork"); "Printing not confirmed. Swipe to check."; "Not sure of this card. Check it against your capture."; "Not the printing that was read" on any other printing. One persistent role="status" element, replaced in place from the centred panel's <template>; its hidden tail names the centred card so every swipe is announced.
  • Row: sure of the card: the matched printing first, then the card's other printings in Other printings order, 20 at a time ("1 of 14 printings", a "‹n› more printings" item with "Show 20 more", capped at 200); not sure: the candidate cards ("1 of 3 possible cards") with "All printings" per card. One Turbo Frame (scanner_selection) renders the row and its panels; a small selection Stimulus controller notes the centred card; Previous, Next, arrow keys and a tap on a neighbour do what a swipe does.
  • Strip: the capture's card box beside the name and collector line read ("nothing read" when blank), written as text.
  • Outcomes: nothing read and no match are said on the live camera's status line (no pane, retake at once); the catalog not ready and refusals are visible alerts in the pane's region; a send failure shows the strip with Send again / Sign in. "Done." plus the band's sentence is a visually hidden paragraph written once the pane shows.
  • Layout (decision 13, a visible design change the maintainer was told of): the images' floor is 96px (spec 080 had 160px) and a shell under 600px high has a 64px strip with a 52px picture whose label is visually hidden; the add buttons are in view for a confident match at 390 × 844, 360 × 640 and 360 × 560. The numbers live in two places only (--scan-image-min and one container block in additions.css), proved by the pane-fit examples. This supersedes spec 080 decision 7 and AC-4.7 for those two numbers (recorded both ways in the specs index).
  • Measured at rest (confident / not sure): 390 × 844 strip 144, images 288; 360 × 640 strip 96, images 160 / 122; 360 × 560 strip 64, images 112 / 96 (the not-sure body scrolls about 6px, the accepted limit).

Supersedes (specs index, both ways)

Spec 009 (the candidates grid, the tiles' badges, the Other printings frame, "What the scanner read" on the page), spec 011 AC-7.1 to 7.5 as the page shows them, spec 080 decision 7 / AC-4.7's two numbers, spec 082's interim body and spoken "Done" sentence. Area doc: docs/architecture/scanner.md; design system: Scanner.md, StatusBand.md.

Screenshots (factory data; card images are placeholders: a tile with the name and set number)

Phone 390 × 844, light and dark: match · dark · swiped light dark · printing not confirmed light dark · not sure light dark · nothing read light dark · failure light dark · after an add light dark

Short phone 360 × 560: match light dark · not sure light dark

Desktop (a 480px column): light · dark

Flow (capture, result, Next, Previous, Add foil, after-add line):

capture, swipe, add

phone match, light
phone not sure, dark

The repository is private, so the links are pinned to the commit and need a signed-in reader. Every shot was looked at before the specs were trusted; the one defect found (a cramped 64px strip) is fixed.

Verification

  • bin/ci ran as the pre-push hook on 57504170 and passed; the suite has 5,205 examples (bin/rspec --dry-run). Scanner suites run green one at a time after each task; bin/ci checks passed after merging origin/main (spec 091's licence check made me list the two new icon files in config/third_party_licences.yml).
  • Implementation review (Opus 5.5): SPEC-ALIGNED WITH FINDINGS (0 blocking, 2 major, 7 minor), all fixed and re-proved; the 200 cap and "Send again" clearing the strip were the majors.
  • The scanner CSP pin (spec/requests/footer_spec.rb) and spec/scanner_sitting_core_spec.rb pass; every Turbo Stream string is escaped or from a partial; measurement mode's run-sheet row logic (Measurement mode: a retake files under the wrong card #419) is untouched.

Models

Spec and plan: main session (Sonnet 5.5; Opus 5.5 for a stretch the harness reported, trailers truthful). Spec reviews x2 and plan reviews x2: Fable 5.2, read-only. Implementers: Sonnet 5.5 (batches for Tasks 1 to 10, the screenshots, the strip fix, the review fixes). Implementation review: Opus 5.5.

Deviations from the plan

Red windows by design (named in each commit): Task 3 request specs until Task 5; the old scanner system specs from Task 5 until Task 8's migration. The spec was patched while building: 1.0.1 (a possible-cards row drops the year and lets its position wrap to fit 360px), 1.0.2 (AC-5.2's measured 6px scroll, not 22px), 1.0.3 (the compact strip hides its label). The plan's tests-first is visible in the history only where a task had its own test commit (58539866); others carry spec and code together and name the red run in the review fixes' bodies.

Owed to the maintainer

  • The screen-reader pass on a phone (a result opening, a swipe, Previous and Next, an add, a refused add; each sentence said once, a fling announcing once). The examples check the text and the element.
  • A look at the pane over the live camera with real card art (the shots use the substituted camera and placeholder images). No measured sitting is asked.
  • Decision 13's numbers were a design change they were told of; a different ruling is a change to the two places above and their examples.
  • Headless Selenium reads no console here, so "no console error" is not claimed; script/scanner/detector_parity.rb needs the spike corpus (the detector and photo path are unchanged).

🤖 Generated with Claude Code

plainprogrammer and others added 30 commits November 13, 2026 19:17
Draft for Gate A. Supersessions recorded both ways in the specs index
(specs 009, 011, 080, 082).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Questions 1 to 7 ruled as recommended; the trade of a confidently wrong
card and of a failed read with no capture is written down.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Hidden opening sentence, the refused-reading mechanism, add forms to the
top frame, the more item, focus fallbacks, the two layout steps and the
completed supersession list.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Request-spec selectors and setup, the fixed "Show 20 more" label, the
cards row without the year, the layout numbers moved into Task 9, the
missing and vacuous examples, gates and hardening. Spec patch 1.0.1.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Fix the render modifier in the selection partial, a readable flat photo
for the no-edge example, a name that is never strong for the not-sure
examples, and the not-sure pane at all three sizes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Approved by the coordinator under the maintainer delegation; the
not-sure name is asserted in a request spec and the AC-5.2 example has
no vacuous branch.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…d (spec 088)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
red window: request specs fail until Task 5, spec 088. The new examples name
markup (the selection frame, panels, band templates) that no view renders yet.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The readings answer and the printings frame render the one selection
partial; the interim result, candidate and printing partials are gone.

red window: the old scanner system specs fail from here until Task 8, spec 088

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… 088)

The page renders the capture strip and the selection pane (the band, the
status region, the failure buttons and the result container) and drops the
interim results body and the failure block's name and collector rows.

Red window: the strip and opening-sentence examples need Task 8, the old
scanner system specs fail until then, spec 088.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…088)

Red window: the first example (strip texts, capture size) needs Task 8, and
the old scanner system specs fail until then, spec 088.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…spec 088)

The reader draws the capture's box on the strip, writes what it read, and
says 'Done.' and the band's sentence once as hidden text in the pane's
region; the no-edge sentence follows it, a reading that opens no pane
drops the frozen frame, and Scan again clears the strip's texts. The
reading controller follows the selection frame's markup (All printings,
Show 20 more failures say so in the region). The flat: option of
pick_synthetic_photo gives a photo with no card edge.

Red window: the other scanner system specs fail until the migration
commit, spec 088.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Candidate tiles become the centred card's panel, 'Done.' is the pane's
hidden sentence, nothing-read and no-match are the status line's sentence
with no pane, and a failure shows the strip and its buttons only. The
three 'scrolls a long result' examples go; the pane-fit examples of the
layout task replace them.

red window: scanner_sitting, scanner, page and measurement specs still pending, spec 088

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add buttons are 'Add nonfoil' and 'Add foil' in the centred card's panel.
'Other printings' becomes a swipe to the next printing (the one chosen is
added, not the matched one) and 'All printings' from a possible card, for
the sign-in and server-failure examples.

red window: scanner_sitting, scanner, page and measurement specs still pending, spec 088

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The reading's answer is the centred card's panel; the art status line in
the destination sheet and the sent fields are unchanged.

red window: scanner_sitting, scanner, page and measurement specs still pending, spec 088

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The no-edge example photographs readable text on a flat white photo
(pick_synthetic_photo flat: true): a photo with no text now reads as
nothing and opens no pane, so the old photo could not show the sentence.

red window: scanner_sitting, scanner, page and measurement specs still pending, spec 088

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The add and the printings request were already measured against the new
page (the accessible name and the route are unchanged); the frame header
and the wording follow the selection.

red window: scanner_sitting, scanner, page and measurement specs still pending, spec 088

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The one example that waited for a candidate tile waits for the centred
card's panel instead; every other example already added through the
unchanged accessible name of the add button.

red window: scanner, page and measurement specs pending, spec 088

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The three examples that waited for a candidate tile wait for the centred
card's panel, and the first reads the matched sentence from the band.

red window: page and measurement specs pending, spec 088

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…088)

The not-stored example waits for the centred card's panel. A new example
records the add of a swiped-to printing with the rank 'other' in the run
sheet's events, beside the existing rank 1 on the matched one.

The red window closes here: the scanner system specs are green again, spec 088

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…on 13)

The images' floor is read from `--scan-image-min` on `.c-scanpane` (96px,
spec 080's was 160px) and a shell under 600px high shows a 64px strip with a
52px picture, so a not-sure pane fits 360 x 640 and a confident one fits
360 x 560 with its add buttons above the bottom bar. These two values are the
only place the numbers live; their examples are in scanner_selection_spec.rb
and design_system_scanner_components_spec.rb, whose spec 080 examples whose
outcomes change are updated.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Scanner.md states the images' 96px floor and the 64px strip with a 52px
picture under 600px, and records that they supersede spec 080 decision 7 and
AC-4.7 for those two numbers. The previews' frames are all 844px high, so
none changes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… name no collectible (spec 088)

The touch-floor spec's page rules now name .c-scanpane__meta and .c-scanpane__add (the
stale .c-scanner__add is gone), and its row 14b draws the pane: Previous, Next, the add
buttons and "Show 20 more" in a confident answer, "All printings" in a not-sure one, at
1280px and 360px (spec 088 AC-5.6). No control was under 44px at a coarse pointer. The
sitting's core guard now reads the selection's model and seven partials (20 files).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Scanner::OtherPrintings#shown and #rest went with the Other printings frame; SHOWN stays,
as Scanner::Selection::STEP. The footer spec's frame-request header names scanner_selection.
Sitting report output is unchanged: rank "other" is still recorded for every printing but
the matched one, so its "Other printings" correction still counts; only a comment says so.

CSS rules removed from additions.css, each with no user left in app, spec or the design
system's previews: .c-scanner__read (with its dt and dd), .c-scanner__mono,
.c-scanner__result (with its .c-status__message + .c-grid rule), .c-scanner__candidate,
.c-scanner__evidence, .c-scanner__adds, .c-scanner__add (the one in the shared
.c-scanner__add .c-btn rule too) and .c-scanner__printings (its .c-list li and
.c-list__end rules). .c-scanner__undo, .c-scanner__sitting and the sitting's other rules stay.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
plainprogrammer and others added 19 commits November 13, 2026 22:08
…em (spec 088)

scanner.md: the pane, the band and its three states and wordings, the row's contents and
order, the panel and its adds, the selection frame and its params, the outcomes' places, the
hidden "Done." sentence and the six regions, focus rules, the layout numbers and measured
boxes in Named constants, the accepted limits and the supersessions in Sources; the old
"What the scanner read", candidates and Other printings text is gone. Scanner.md replaces
its two #345 sections with the pane as built; StatusBand.md and the README record the
band's first use; CLAUDE.md's scanner bullet names the pane.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ecision 13)

In a shell under 600px high the 64px strip's text block filled it exactly, the label on its top edge and the collector line on the band. The label is now visually hidden there, so the name and the line are centred.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Phone and desktop shots in both themes and the capture-swipe-add GIF,
factory data with placeholder images; the measured boxes at three sizes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… 088 decision 4)

`more` was total minus rendered, so a card with more than 200 printings still
ended in "more printings" at the cap, whose "Show 20 more" re-rendered the
same 200. `more` is 0 and `more?` false when the limit is MAX; the position
still counts every printing.

red: selection_spec "ends the row at the cap" failed: more? expected false got
true, count expected 20 got 21.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…pec 088 decisions 9, 11)

send() hid the failure block before the answer, so the shell lost its result
state for the answer's frames: shellChanged cleared the strip's name and line
and the pane closed and reopened. The failure block now stays shown until the
answer renders and hides in the same render (turbo:before-stream-render), and
opened() waits for that.

red: scanner_result_spec "Send again" examples failed: .c-scan__read-name and
.c-scan__read-line were empty after the answer, and the pane had closed
(window.__paneClosed true).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…unce keeps the kept note (spec 088 AC-3.11)

announce replaced everything in #status, dropping measurement mode's
data-pane-keep note, and the "couldn't be loaded" alert outlived a retry that
loaded. announce now keeps [data-pane-keep] children, and turbo:frame-load of
scanner_selection removes the printings-failed alerts (marked
data-printings-failed) and only those.

red: scanner_selection_spec "drops the failed-load alert" failed twice: the
alert was still in #status after the retry, and the data-pane-keep note was gone.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…5.3)

The not-sure fit examples now compare the strip, band, row, details and adds
boxes in order, as the confident ones do; where the body scrolls (360 x 560)
only the strip, band and row.

green: this closes a coverage gap and passed on first run (no bug behind it).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…c 088 AC-2.3, AC-3.2, AC-3.8, AC-4.2)

Request example: three candidate cards (Lightning Bolt, Helix, Strike read as
"Lightning") answer a row of three with "1 of 3 possible cards", the not-sure
band and "Card n of 3" tails on every panel, Previous card and Next card, and
add ranks 1, 2, 3. System example: Next card steps through them. Request
example: a nonfoil, foil, etched printing offers Add nonfoil, Add foil and Add
etched with stars on the last two.

green: coverage gaps; these passed on first run (no bug behind them).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ssert (spec 088 AC-2.5, AC-6.1, AC-7.2, AC-7.4)

A swipe writes nothing to #status (AC-7.2); an add leaves the strip's texts
and #status empty (AC-7.4); a picked photo with no text says nothing read
with no pane and no no-edge sentence (AC-6.1); the band has role status and
its icon is aria-hidden (AC-2.5).

green: coverage gaps; these passed on first run (no bug behind them).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…age rule (spec 088)

Nothing renders a message directly in #scanner_result: a refusal goes to the
pane's #status region (styled by .c-scan__pane-status .c-status__message).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
SPEC-ALIGNED WITH FINDINGS (0 blocking, 2 major, 7 minor), by Opus 5.5;
the findings are fixed and re-proved.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A screenshots-workflow addendum and three lessons (a markup-derived pane
flickers when a part hides, an OCR example must not depend on the
reading, a design number belongs in the task that proves it).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The pane, the band, the row, the selection request and the layout numbers
with what proves them; the index row freezes spec 088 with its plan
retirement owed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The specs index kept both sides: spec 088 with its supersessions of rows
080 and 082, spec 081 as main has it, and the rows 089 and 091.
Spec 091's licence check, now on main, wants every icon file in an icons
entry: _chevron_right and _question join the Lucide entry, taken from
spec 080's previews like spec 082's two.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The specs index kept spec 088 and main's row of spec 089 with its
retired plan.
@plainprogrammer
plainprogrammer marked this pull request as ready for review November 14, 2026 04:17
@plainprogrammer plainprogrammer self-assigned this Nov 14, 2026
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.

Scanner: the selection pane

1 participant