Repository navigation
Scanner: capture always in view (spec 082, #344) - #409
Merged
Merged
Conversation
Decision 1 ruled by the maintainer on 2026-11-13 (option C): no cards soon, so the live re-measure is the last gate and runs on a new corpus. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The paired re-measure is executable on one server (framing chosen on the measurement page, a run per framing), the live guide never shrinks below the shipped card size on a portrait stage, and a table places every answer's sentence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The framing lives in the session so every measurement write reaches its run; the guide sits below the lines and Use a photo moves into the destination sheet, so nothing covers the strips the collector aligns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ruling: the re-measure's bar is A, the paired run - maintainer, 2026-11-13. The other calls are confirmed as written. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…c 084 (#344) Ruling: the notice's partial is layouts/_notice_lines.html.erb with no locals, shared with spec 084, and a sheet always has a foot - coordinator, 2026-11-13. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ial (#344) Ruling: the shared notice partial and its consequences are accepted - maintainer, 2026-11-13. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Gate B approved by the coordinator under the maintainer's delegation, 2026-11-13, with patch 1.0.2 (measurement mode's stored notice and store failures). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds LIVE_GUIDE, shippedGuideWidth and liveGuideRect to the scanner's geometry module, and a rect parameter to guideInFrame; the shipped framing's guideRect, GUIDE and every reading setting are unchanged. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A live synthetic card is drawn where the stage's live guide maps into the 3:4 frame; a photo's card stays at the shipped guide. Selectors accept both the old and the new page's class names until Phase 3. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The footer's loop moves to layouts/_notice_lines, shared with spec 084, and layouts/_notice_foot gives a one-screen focused page's sheets a foot with the same lines. The footer's markup is unchanged. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ntence (#344) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…#344) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The scanner page renders spec 080's shell: top bar with the destination, stage, bottom bar with the main button, the pane, and the destination and list sheets. Adds the torch and chevron icons; deletes _summary (the after-add line replaces it); the measurement page keeps its own page and passes the shell's new heading local. Ruling: spec/requests/scanner/measurements_spec.rb:62 now looks for #scanner_picker select#sitting_condition — the control moved out of #scanner_sitting into the destination sheet — none if wrong. Ruling: spec/system/footer_spec.rb's sheet-foot example reads the two sheets with visible: :all instead of opening them — the sheets controller is T3.5's, nothing opens a dialog yet — T3.5 may switch it to open them. Red until T5 (sitting_stream renders _sitting with a `choices:` local it no longer takes, and the specs read the picker inside #scanner_sitting): spec/requests/scanner/sittings_spec.rb, spec/requests/scanner/sitting_entries_spec.rb, spec/requests/deck_zone_pickers_spec.rb. Red until T3.5: the scanner system specs that start the camera or read the old c-scanner selectors (scanner_spec, scanner_sitting_spec, scanner_adding_spec, scanner_art_spec, scanner_detection_spec, scanner_timing_spec, scanner_measurement_spec, small_controls_touch_floor_spec). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…e page (#344) T3.4 and T3.5: the spec 082 CSS block, scan_shell and sheets controllers, the camera's feed wrapper and live guide, the card reader's main button, pane sentences and picker targets, the scanner helpers and scanner_page_spec.rb. geometry.js's header no longer claims the CSS gives the stage 3:4: the live stage is the shell's, only the photo path keeps 3:4. footer_spec's sheet-foot example now opens each sheet instead of reading with visible: :all. The old "fits a 360px screen with the shutter in the bottom third" example is replaced by scanner_page_spec.rb's and deleted. card_reader#shellChanged is an empty stub for T4.2. AC-1.1 proof: with spec 080's .c-shell--focused rule removed, the three "is one screen" examples fail (scrollable, scrollY 16, top -8); restored, green. Green: scanner_page, scanner, scanner_detection, scanner_art, scanner_geometry, footer (system), requests/scanners, scanner_sitting_core, scanners_helper, design_system_scanner_components, design_system_files (69 examples, 0 failures in the last two runs of 61 and 69). Red until T5.3: spec/system/scanner_sitting_spec.rb (16), scanner_adding_spec.rb (4); scanner_timing_spec.rb is excluded (timing). Red until T7.2: scanner_measurement_spec.rb (1). Red until T6.3: select_touch_floor_spec.rb (4). Ruling: the "Done" sentence keeps its text ("...candidates are below.") and goes to the pane's #status as a c-status__message paragraph - existing specs assert it, T4.2 revisits the wording - cost: one string to edit. Ruling: the backdrop-close example dispatches a MouseEvent on the dialog, as the plan allows - cost: a real tap on the scrim is not exercised. Ruling: scanner_art_spec opens the destination sheet to assert the art line and closes it before capturing (modal sheets block the main button) - cost: none. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…eturns (#344) T4.1 and T4.2: a capture freezes on its frame (a canvas), the answer opens the pane, the main button reads "Scan again" while a result shows, and the pane's sentences are written once the pane shows ("Done. What the scanner read and its candidates are showing."). pick_photo and pick_synthetic_photo gain input:, expect_one_screen and hold_readings move into ScannerHelpers. Declared red: the three "keeps the main button in view ... " examples in scanner_page_spec.rb (390 x 844, 360 x 640, 360 x 560) reach the add step and fail on the sitting answer (unknown local choices) until T5.1. AC-4.1 proved by deleting `this.frozenTarget.hidden = false`: the freeze example failed ("canvas.c-scan__frozen:not([hidden])" not found); restored. Ruling: .c-scan__guide gets box-sizing:border-box in the spec 082 CSS block - spec 080's rule sets none, so the 2px border made the drawn guide 364 wide against the rule's 360 (AC-3.1) - cost if wrong: a 4px larger guide. Ruling: states_at is named expect_states_at - RSpec/NoExpectationExample only accepts expect_ helpers - cost if wrong: none. Ruling: expect_states_at waits for window.__release before calling it - the held request is made only after OCR, so the call raced - cost if wrong: a flaky example. Ruling: the photo examples wait for the picker to be enabled before picking - pick returns while the engine loads - cost if wrong: a flaky example. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
sitting_stream is replaced by sitting_redraw, picker_redraw, say_in and added_line (spec 082 decision 10's table). An add empties the pane and the status line and sets the after-add line with Undo; Set answers in the destination sheet; Undo answers in the list sheet and the after-add line. Request specs read the new targets, including an escaping check. Still red, not this task's: system specs of the sitting (T5.3), scanner_measurement_spec (T7.2), select_touch_floor_spec (T6.3). deck_zone_pickers_spec needed no change once the controllers answered. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
"heading" focuses the list sheet's title while that sheet is open, else the main button; "main" focuses the main button after an add. Asserted by T5.3's system examples. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The sitting, adding and timing system examples read the new regions: the destination and list sheets, the after-add line, the count button. Adds AC-5.1, AC-5.4, AC-2.4 and AC-4.8 examples. Ruling: the list sheet title's focus ring is :focus, not :focus-visible - Firefox gives programmatic focus no :focus-visible once the focused Undo button was replaced by the answer, so AC-2.4's ring was missing - none: the title is tabindex -1 and only focused by the redraw (a click on it shows a ring too). Remaining red, not this task's: scanner_measurement_spec (T7.2), select_touch_floor_spec (T6.3). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ne (#344) A page load shows the end of a sitting's summary with a link to the collection (AC-5.6), or a flash from a page the scanner was left for, with its Undo (AC-6.4), on the after-add line. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Decision 10's table writes the list sheet's region and the after-add line for an Undo, done or refused; the refusal branch wrote only the list's. Red first: the 422 answer had no scanner_added_text stream. Also rewraps the concern's header comment to the files' 130-character width. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Root cause of the eight red small-controls examples: not app code. The spec's settle waited on the removed .c-scanner__stage, and its scanner row named Done and Set under #scanner_sitting, which moved to the top bar and #scanner_picker. Both floors now wait on .c-scan__feed, show or open the sheets, and the new example measures the shell's controls at a fine pointer (AC-1.9). Ruling: the sheets' selects are not in AC-1.9's 44px list — spec 072 makes them 36px at a fine pointer and they meet the floor on a coarse one — cost if wrong: one more row to measure. Ruling: the AC-1.4 overlap example closes all sheets but the first (settle shows every sheet at once, and two open sheets overlap) — only the sheets' layout is measured, not their overlap with each other — cost if wrong: none a collector sees. Ruling: report_roots and scanner_sheets are methods, not a constant (no constants in a describe). Measurement mode's rows in both specs stay red until T7.2 builds its sheet and one main (declared). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The HTTPS and blocked-camera examples assert the reason inside .c-scan__notice:not([hidden]) and the notice's Use a photo; new examples show the engine's failure notice with the main button in view at three viewports, and the catalog-not-loaded line at the stage's foot. Ruling: the engine failure is made by serving no engine files under a fresh version path (stub_const of the version plus path_for returning nil), not by the plan's createWorker stub and retryEngine — the loaded worker is cached for the page's life so a retry after a good load never fails, and a stubbed path_for on the old version still loaded from the browser cache — cost if wrong: the example proves the first load's failure, not the retry button's reload. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
) Removed the rules whose class no view, script or spec uses: .c-scanner, .c-scanner__stage, .c-scanner [hidden], __video, __guide, __controls, __shutter, __torch, __unavailable and __note (the 44px rule keeps __photo, the flex rule keeps __failure). docs/design-system/components/Scanner.md still shows the old markup; Phase 8 rewrites it. Ruling: .c-scanner__status stays (the replay page uses it) and so does the .c-scanner * reduced-motion rule, which the frozen reduced-motion block's comment names; it matches nothing now and costs nothing — cost if wrong: one dead rule. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… session (#344) Ruling: the measurement panel's own heading is now an h3 "Run" inside the run sheet, whose h2 is "Measured run" — two headings both reading "Measured run" in one sheet repeats itself — none if wrong (a label). Ruling: render_panel also replaces the run button in the same response by a second turbo stream — the plan said the button is replaced with every answer and a stream response can carry two actions — none if wrong. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Ruling: the other run-scoring tasks read FRAMING (default full, empty for the configured directory itself) — measurement mode now writes under the framing's directory, so unset must score where captures land — a stale run in the bare directory needs FRAMING= to score. Ruling: the paired spec's cards are Lightning Bolt and Counterspell with explicit identities — a short name (Opt) was not a name candidate and the factory's default identity differs from the entry name — none if wrong (spec data). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…344) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The scanner area doc describes the page as built: the shell, the two sheets, the regions each answer writes and empties, the frozen frame, Scan again, the after-add and flash lines, the stage notices, the live guide's rule and numbers, the framing in the session and the paired findings, and what is still open (the re-measure). Catalog core records the notice's place on the scanner (spec 018 FR-2 superseded for it). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Scanner.md describes the one-screen page with its real ids and markup, the sheets, the lines, the stage notices and the interim pane body, and keeps only what #345 still replaces (the pane's band, row and details, the result partial). Sheet.md names the sheets controller's backdrop close and a live region per sheet; Footer.md and the README record the one-screen focused page that has no footer (spec 082). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Spec 082's row lists everything its Supersedes section names, and the Superseded by cells of specs 007, 009, 011, 018, 040, 042 and 047 each gain the part it replaces. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…loaded with Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…'s store failure Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… notice Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s boundaries (#344) The report now says per framing whether art matching was on (from a capture's art_ms or a recorded reading's art_status) and which user agents were seen (spec 082 AC-7.4). Boundary examples: right card first one below passes, two below fails; exact printing two below passes, three below fails. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…he markup (#344) AC-1.3: with a sitting open the top bar reads Back, the destination, Done. AC-1.4: a deck's zone reads "Deck › Zone" in the helper and on the page. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…roved in the browser (#344) AC-1.5 (main button takes the torch's room), AC-1.6 (Scan again where Capture was), AC-2.4 (a sheet's region is empty once it closes), AC-3.1 (the guide at three sizes and the status line clear of it), AC-4.2 (status text emptied), AC-4.3 (bars stay at the edges with the pane scrolled), AC-4.5 (network and server failures, Send again, Scan again), AC-4.6 (nothing read, no match, catalog not ready), AC-4.7 (add on the network). Broke to see red, then restored: AC-1.5 (.c-scan__main flex 0 1 auto), AC-2.4 (sheets#emptyRegions no longer empties), AC-4.5 (the failure block no longer shown, and Send again always hidden). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ent mode are proved (#344) AC-2.3, AC-2.5, AC-5.1, AC-5.3, AC-5.5, AC-5.6, AC-6.2 in the sitting's spec; AC-7.1 (hidden heading, framing buttons, a store failure in the pane) and AC-7.2 (a Skip stored under shipped, the shipped guide drawn) in measurement mode's. Broke to see red, then restored: AC-5.3 (the after-add action not redrawn after an Undo) and AC-5.3/AC-6.2 (the count redrawn one too high). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…side its live region (#344) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…answer replaces its sentence (#344) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…after-add line are proved at the three viewports (#344) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Two lessons (a modal sheet silences live regions outside it; the second branch to land owns the first branch's page lists), a memory on Turbo Stream strings being html_safe, and the headless-frame note for the one-screen scanner. Approved by the coordinator, 2026-11-13. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… area docs (#344) The area docs were written with the feature (231c8b8) and updated at the merge of spec 084; this adds their distillation log rows, marks spec 082 Frozen in part (all but Story 7's re-measure, owed) with its plan owed a retirement, and names spec 082 in CLAUDE.md's card scanner paragraph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…core area docs (spec 027 D4) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ck (#344) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to 082-scanner-capture-always-in-view (#344) Docs conflicts only: the architecture index keeps 081's rows and the scanner row's spec 082; catalog-core's log keeps #378 for spec 084 and adds spec 082's row; the specs index takes 081, 083 and 084 from main and keeps 084's Superseded-by entry for spec 082. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PR #409's CI (shard 2/4, seed 28861) called window.__release before the held readings request existed: the request is made after the OCR, which is slower on the runner. The example now waits for it, as the others that hold a reading do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… floor's layout check (#344) PR #409's CI (shard 2/4, seed 28861) reported the destination sheet's Close over the main button at 360px (AC-1.4). Diagnosed with a probe at 360 x 800: the main button is at y 721-785; the sheet's Close starts at y 809 when show() is called, is at 456 100ms into the 200ms rise and rests at 294 (the list sheet's at 460), so the check measured the head crossing the bar mid-rise, a slower runner landing in that window. At rest no sheet control overlaps the bar, and a collector's sheet is modal: the bar under it is covered and inert (elementFromPoint at the main button is not the button). Not a layout defect. The check now measures the page with the sheets closed, then each sheet alone after its rise has finished. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…aintainer (#344) Ruling: no shipped-framing pass and no bar; the full framing ships as built, and reading accuracy at the new framing is left to later scanner stories - maintainer, 2026-11-13, after the sitting (quoted in the changelog). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s) into 082-scanner-capture-always-in-view (#344) Spec 087's third sentence and link reach the scanner through the shared notice partial: the scanner's licence-line and footer examples expect them in each sheet's foot and the noscript notice. The two icon partials this branch adds (_chevron_down, _torch) join the Lucide entry of config/third_party_licences.yml, so spec 087's guard passes. Docs: the catalog-core scope, licence paragraph, sources and log keep both specs; spec 082's exception sentence replaces spec 087's 'to record if it merges second'; the specs index takes 081, 083, 085 to 087 from main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…structed (#344) A hand reconstruction of one unpaired pass, not a measured run as filed (13/40 as filed, an artefact of measurement mode, #419): 37 pairings certain, 3 by position. Three sets of figures side by side, no bar applied (the maintainer withdrew it, spec 082 1.1.0). The capture-to-card working is in research-captures.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dex and verification (#344) Story 7 owes no run since spec 082 1.1.0: the area doc's open item records the withdrawal and #419, LIVE_GUIDE's comment says it ships at its size, PairedReport's header says its bar was withdrawn, the index row reads Frozen (whole spec), and verification.md records AC-7.3's checks, AC-7.5 withdrawn, the sitting and what was not done (screen-reader pass, frozen frame, detector parity). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #344.
The re-measure was withdrawn after one pass. The maintainer's sitting (2026-11-13) captured 40 cards once at the full framing; the maintainer then withdrew the paired comparison and its bar (spec 082 1.1.0: "this isn't about improving the scanner. It's just about changing the presentation of the scanner"). The full framing ships as built; reading accuracy at the new framing is left to later scanner stories. The pass is a hand-reconstructed record in
research.md, not a pass of any bar: measurement mode filed in-place retakes under the wrong rows (13/40 as filed, meaningless), filed as #419 and not fixed here. Reconstructed, side by side and no bar applied: right card first 34/40, 33/39 without the tuning card C029, 34/37 with certain pairings; exact printing 29/32.What it does
On a phone the scanner is one screen that never scrolls (spec 082, spec, version 1.1.0):
<dialog>, modal) hold today's Condition and Location form and today's list; they keep the camera running. Each has its own live region (a modal makes the rest of the page inert) and ends with the small print; the scanner is the focused-page exception to spec 084's footer on every page (patch 1.0.3, recorded both ways in the index).rake scanner:paired_findingsfor the re-measure's bar A.Supersessions (specs 007, 009, 011, 018, 040, 042, 047 and 084) are in the spec and in
docs/specs/README.md, both directions. Area docs:docs/architecture/scanner.md,catalog-core.md; design system:Scanner.md,Sheet.md,Footer.md, the README.Evidence
bin/cigreen at57e3318f(pre-push; 5,047 examples), after mergingmain(specs 084 to 087, the Flaky: the deck page's Turbo cache restore reads scroll 0 after Back (menu_tab_bar_clearance_spec AC-1.13) #404 fix). Spec 087's licence line reaches the scanner's sheets through the shared partial; the two new icons are inconfig/third_party_licences.yml.verification.md.Phone (390 × 844)
Desktop (1280 × 900, a centred 480 px column)
Flows
Capture, result, Add foil, the after-add line:
The two sheets over the running camera:
Not done (owed to the maintainer)
object-fit: cover) lines up with the live picture.script/scanner/detector_parity.rb(needs the spike corpus and a dev server; the branch doesn't touch the detector or the shipped framing).🤖 Generated with Claude Code