From 1910c6c2b910959d425efb35ca76933adf56458f Mon Sep 17 00:00:00 2001 From: James Thompson Date: Fri, 13 Nov 2026 19:17:21 -0500 Subject: [PATCH 01/47] docs(specs): draft spec 088, the scanner selection pane Draft for Gate A. Supersessions recorded both ways in the specs index (specs 009, 011, 080, 082). Co-Authored-By: Claude Sonnet 5.5 --- docs/specs/088-scanner-selection-pane/spec.md | 291 ++++++++++++++++++ docs/specs/README.md | 9 +- 2 files changed, 296 insertions(+), 4 deletions(-) create mode 100644 docs/specs/088-scanner-selection-pane/spec.md diff --git a/docs/specs/088-scanner-selection-pane/spec.md b/docs/specs/088-scanner-selection-pane/spec.md new file mode 100644 index 00000000..00c6e393 --- /dev/null +++ b/docs/specs/088-scanner-selection-pane/spec.md @@ -0,0 +1,291 @@ +# Feature 088: Scanner: the Selection Pane + +**Status:** Draft, for Gate A +**Version:** 0.1.0 +**Created:** 2026-11-13 +**Last Updated:** 2026-11-13 +**Depends on:** [spec 080](../080-phone-first-scanner-components/spec.md) (the pane, the band, the strip and the row, drawn with their CSS), [spec 082](../082-scanner-capture-always-in-view/spec.md) (the one-screen page, the sheets, the lines, "Scan again", decisions 10, 11 and 13), [the phone-first scanner design](../../superpowers/specs/2026-11-12-scanner-phone-first-design.md) (approved 2026-11-12; decisions 8 to 19), the scanner as built ([scanner](../../architecture/scanner.md) area doc; specs 009, 011, 040, 042, 047) +**Branch:** `088-scanner-selection-pane` +**Issue:** [#345](https://github.com/plainprogrammer/Collector/issues/345) (roadmap Theme D, the phone-first layout's third item) + +--- + +## Changelog + +| Version | Date | Change | +|---------|------|--------| +| 0.1.0 | 2026-11-13 | Draft from issue #345, specs 080 and 082 and the design. Decisions marked *(pending)* are my recommendations on the scope questions sent to the coordinator; every other decision is my call for Gate A | + +--- + +## Problem Statement + +Spec 082 made the scanner one screen, and a result opens in its pane. What the pane holds is still spec 009's page: "What the scanner read", a grid of up to three candidate tiles each with its own badge, add buttons and "Other printings" link, and a frame of printings below them, all in an interim scrolling body (`c-scanpane__results`, spec 082 decision 11). On a phone the add buttons sit below the fold, the capture isn't seen beside the match, and a wrong printing is reached through a link and a list. The maintainer saw those quirks at spec 082's sitting and expects this story to settle them. + +This spec builds what spec 080 drew and the design decided: after a capture the frozen picture shrinks into a strip beside what was read from it, and the pane slides up with a status band that says how sure the scanner is, a row of card images to swipe (or step with Previous and Next) with the best match centred, one details block for the centred card and one add button per finish under it. A confident match is added with one tap on a finish, a wrong printing is a swipe away, and the band says in words and an icon when the scanner is less sure. It removes the interim body and what it held, and it changes nothing about how a card is read or ranked (ruled 2026-11-13: reading accuracy is left to later scanner stories). + +> **Terms.** As specs 080 and 082: the *shell*, the *stage*, the *pane*, the *strip* (the capture strip: the capture's picture and, beside it, what was read), the *band* (`StatusBand`), the *row* (the swipe row of card images), a *panel* (`c-scanpane__card`: one card's details block and add buttons), the *main button*, the *status line*, the *after-add line*, the *frozen frame*. The *matched* printing is the ranking's first candidate's printing. A *selection* is the row with its panels, as one server-rendered Turbo Frame. *Sure of the card*, *printing confirmed* and *not sure* are decision 2's. + +## Goals + +- After a capture the collector sees their capture beside the match, and the pane's controls (band, Previous and Next, the add buttons) are in view without scrolling at 390 × 844, 360 × 640 and 360 × 560, for a confident match. +- A confident match is added with one tap on a finish; another printing is a swipe, or Previous and Next, away; the centred card is announced. +- The scanner being less sure is told in an icon and words: the card is right and the printing a guess, or the card itself is in doubt. +- The interim scrolling body, "What the scanner read", the candidates grid and the Other printings frame leave the page. + +## Non-Goals + +- A sitting's language (#58), look-up mode (#262), continuous capture (#54), detection on live frames (#53), Japanese cards (#55). +- Any change to how a card is read or ranked: the strips, the OCR settings, the detector, the art fingerprint, the evidence kinds and `Candidate#rank_key`. One new reading of them, a predicate over the evidence (decision 2), changes nothing the ranking does. +- Measurement mode's filing of retakes ([#419](https://github.com/plainprogrammer/Collector/issues/419)); the run sheet's row logic is not touched. Measurement mode keeps recording everything it records today (the reading's candidates, tier and overrule; add, Undo and Details events). +- New collector-owned data, a migration, a new export field, or a new ADR (decision 17). +- A mouse drag on the row (decision 7). + +## Decisions + +Decisions 2 to 4, 7, 8, 11 and 12 follow the recommendations sent to the coordinator on 2026-11-13 and are *(pending)* its answer. Decisions of the design are cited as "design decision N", of spec 080 as "spec 080 decision N", of spec 082 as "spec 082 decision N". + +1. **The pane is the band, the pane's region, the failure block and one result container** *(my call; supersedes spec 082 decision 11's interim body)*. `c-scanpane` holds, from the top: the band (`p#scanner_band.c-band`, `role="status"`, kept in the document and empty while no result shows), the pane's `#status` region (spec 082 decision 10, unchanged), the send-failure block (now only its explanation's buttons, "Send again" or "Sign in": the name and collector line read are in the strip), and `#scanner_result`, which holds the selection (`turbo-frame#scanner_selection.c-scanpane__body`). `c-scanpane__results` is removed. The strip (`c-scan__strip`) is a sibling of the pane in the stage, above it, rendered with the page: its capture canvas is drawn by the page, and "Read from the card", the name and the collector line are written by the page from the reading (`textContent`; "nothing read" for a blank text). `scan-shell` still sets `c-scan--result` from `#scanner_result`, the pane's `#status` and the failure block, and does not count the band. An empty band takes no space and stays rendered (`.c-band:empty`, as the other regions, spec 080 decision 8). +2. **Three states, from today's evidence** *(pending, question 1)*. The ranking's first candidate decides, with no change to the ranking: *printing confirmed* is `Candidate#printing_confirmed?` (collector-line evidence, or art that belongs to one printing: today's success badge); *sure of the card* is a new predicate, `Candidate#card_sure?`: collector-line evidence, confident art, or a strong name match. The band is: success with a check and the evidence ("Matched by its collector line", "Matched by its collector line, one digit corrected", "Matched by its artwork") when the printing is confirmed; warning with the alert triangle, "Printing not confirmed. Swipe to check.", when the card is sure and the printing is not; warning with the question mark in a circle, "Not sure of this card. Check it against your capture.", when it is not sure. Two colours, as design decision 13. +3. **What the row holds** *(pending, question 2)*. Sure of the card: the matched printing first, then the card's other English, non-retired printings in today's Other printings order (`Scanner::OtherPrintings`: shared artwork, read set and number, read set, read number, the rest; newest first), the position "1 of 14 printings". The other candidate cards are not in the row. Not sure: the candidate cards, up to three, each as its own printing, in ranked order, "1 of 3 possible cards" and Previous and Next named "Previous card" and "Next card"; each panel there also holds a ghost "All printings" button (44px, on the position line, which makes that state's line 44px) that navigates the selection frame to that printing's card: the card's printings with that printing first, its band by that printing's own evidence ("Printing not confirmed. Swipe to check." for a name match). Item *i* of a printings row but the first reads "Not the printing that was read" in warning with the alert triangle (design decision 14), also when the match was only a guess. Alternative: also keep cards 2 and 3 after the match, which breaks "1 of 14". +4. **Twenty printings at a time** *(pending, question 3)*. The selection renders the first `Scanner::OtherPrintings::SHOWN` (20) printings; the position counts all of them. With more, the row's last item is a "‹n› more printings" item whose panel (the card's name, "‹n› more printings", and a "Show 20 more" button in the adds' place) navigates the selection frame with `limit` raised by 20 and the centred printing named, so the frame renders again with more and the same card centred and focus on Next. This is the issue's "further printings arrive in a Turbo Frame": the row and the panels are siblings, so one frame holds both and is rendered whole by the server. The more item has no band of its own (the band stays as the previous item's) and no position. Alternative: a Turbo Stream that appends. +5. **The band is one element whose content is copied from the centred panel** *(spec 080 decision 8; my call for the mechanism)*. The server renders each panel with a `