Skip to content

Free to use and In decks on the card page (#50) - #333

Merged
plainprogrammer merged 34 commits into
mainfrom
073-card-page-deck-stats
Nov 12, 2026
Merged

plainprogrammer merged 34 commits into
mainfrom
073-card-page-deck-stats

Conversation

@plainprogrammer

Copy link
Copy Markdown
Owner

Closes #50

The card page shows how many owned copies are free to use and which decks hold the rest: the stats strip becomes Owned / In decks / Free to use, and a new In decks table after Printings lists the deck zones that hold a copy or a proxy of the card. Spec 073 (approved at Gate A and Gate B), plan, verification.md and the implementation review (Mode B, SPEC-ALIGNED after two rounds) are in docs/specs/073-card-page-deck-stats/.

What changes

  • Stats strip (c-stats--three, spec 057's design): Owned (as before), In decks ("in N decks"; decks holding at least one owned copy) and Free to use ("not in a deck"). Considering counts as in a deck. A proxy never changes any of the three.
  • "In decks" section: Deck (link to the deck page, format muted beside it), Zone, Owned, Proxy; one row per zone holding a copy or a proxy of the card, summed across printings; decks by comparison key, zones in the deck's order; a muted dash for no proxy; head count "4 copies in 2 decks · 2 proxy"; empty state "This card isn't in any of your decks." with an "Add to deck" link. Zone and the format fold under the deck name below 640px.
  • One definition of "free": Lot.free read through Lot::FreeCopies (specs 070 and 071). "In decks" is the card's other lots (Catalog::CardOverview#deck_lots), so Owned = In decks + Free to use and no page code tests a location's kind. Deck::CardUses reads the rows (four statements however many zones; none for a visitor).
  • Collector only: a visitor on an open catalog reads nothing (no statement against lots, locations, decks or deck_proxies). Another account's lots, decks and proxies never show (cross-account examples, each with a positive control).
  • No schema, migration or export change (format version 4 untouched), no ADR.

Two rulings to confirm (flagged at Gate A, approved)

  1. The Proxy column counts proxies of the card in any printing, matching the card-wide Owned.
  2. The empty state's "Add to deck" link, and the head count's words ("proxy" has no plural, as the deck pages say it).

CSS and markup (small, all scoped to the section)

Three rules under a (spec 073) heading in additions.css: a deck's name wraps (#in-decks td:first-child); below 640px the head count takes its own line (the deck pages' precedent: a cut count is information lost); the empty-state link stays on one line. "Your copies" takes spec 048's existing c-table__place class on a placed lot's Location cell, because a 60-character deck's "Deck › Zone" label made the page scroll sideways at 1280px (measured: 547px nowrap cell, page 1354px in a 1265px viewport).

Existing examples this changes (listed from a grep, in the spec)

entries_show_spec (spec 071 AC-1.4 rewritten; section order), quick_adds_spec, query_counts_spec (the zone example no longer includes the card page, which has its own bounded-statement example; the placed-lots example re-based, see verification.md), deck_additions_spec (system: two clicks scoped to the head, since the empty state adds a second link of the same name), zone_place_label_spec (the Zone column), deck_core_spec (65 files, including the card page's partials and CardOverview).

Evidence

Factory data, placeholder card images, headless Firefox. Light and dark; the phone shots are a 390px frame (page 375px beside the pinned classic scrollbar). The "before" shots are emulated by injecting the old rule, not built from main. All files are in docs/specs/073-card-page-deck-stats/screenshots/.

Card from the card page to its deck (desktop, phone):

card page to deck page, desktop

card page to deck page, phone

Some copies in decks (7 owned: 3 in two decks, Considering among them, 4 free; two proxies)

desktop, light desktop, dark
phone, light phone, dark

No decks (the empty state), all in decks (Free to use 0) and proxies only (Owned 0, a row with the proxy count), each in desktop and phone, light and dark:

state desktop light desktop dark phone light phone dark
no decks
all in decks
proxies only

Before and after of each CSS or markup fix (60-character deck name at 360px, "Your copies" at 1280px, the head count at 360px, the empty-state link at 390px; light and dark, all in screenshots/ as 05-wrap-*, 06-copies-*, 07-headcount-*, 08-empty-link-*). The head count before/after, 360px, dark and light:

before after

The 60-character deck name at 360px, before (runs off the table) and after (wraps), and "Your copies" at 1280px before (page 1378px wide) and after:

360px before 360px after
1280px before 1280px after

Tests

  • New: Deck::CardUses (7), CardOverview deck readers (3), DecksHelper#card_decks_count_line (2), the card page request examples (25), the card page system examples (20, headless Firefox: widths 360/390/640/1024/1280, both themes, the head count and link) and the no-script path from card to deck (rack_test, 1); guards: the statement-count example (bounded however many lots, decks, zones and proxies; shown red under a mutation), the visitor examples (no statement against the four tables, with a signed-in control), the core-names guard (65 files).
  • The suite has 4456 examples. The pre-push hook ran the full bin/ci (RuboCop, YARD, comment ratchet, Brakeman, bundler-audit, importmap audit, RSpec) on ff2e1646 and passed; GitHub CI is the second check.
  • Lessons from this run are in docs/lessons/ (and the distillation is committed: both area docs, the index row and the frozen line); the plan is retired after merge.

🤖 Generated with Claude Code

plainprogrammer and others added 30 commits November 11, 2026 21:59
Draft spec 0.2.0 after review round 1: three-stat strip, In decks table,
free read through Lot.free / Lot::FreeCopies, supersessions listed from a grep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Spec approved at Gate A, clarified from plan review; plan approved at Gate B.

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>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…c 073)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Red at this commit: the strip is still the single Owned stat.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The card page's stats strip is Owned, In decks and Free to use through the _stats partial. Examples this turns red are edited here: entries_show_spec (supersedes spec 071 AC-1.4), quick_adds_spec, and query_counts_spec's zone-minus-place example (the card page leaves it for its own example in Task 5.2).

query_counts_spec.rb:58 (placed lots, spec 032 NFR) was re-based: the plan said it stays green, but the card page now preloads the lots' places twice (CardOverview#lots and Lot::FreeCopies#lots), and with one placed lot both issue the same statement, so the second is a cached hit the counter skips (19 vs 20). The baseline is now two lots the two lists order differently.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Decision 5 and AC-2.6. Written test first: both examples failed with undefined method before the helper.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
17 section examples: 16 fail until the section exists (#in-decks absent). One example is a characterisation that passes at once: 'does not write to lots, locations, decks or deck proxies' (AC-3.4), since the page writes nothing today; it keeps guarding once the section reads.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The section, its show.html.erb line for a collector, and the one CSS rule under a (spec 073) heading. Also edits three existing examples: two no-script click_link 'Add to deck' in spec/system/deck_additions_spec.rb are scoped to .c-item__actions (the empty state adds a second link), and spec/requests/zone_place_label_spec.rb removes the In decks section before its zone-name-alone check.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
All three changes are characterisations that pass at once, because the section landed in the previous commit: the In decks h2 assertion, the In decks marker in the order example, and the new no-script 422 example (AC-3.2) comparing the refused page with a plain visit.

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

The new patterns and the count of 65 are a guard that passed on arrival: the card overview and the _stats and _decks partials already name no game, format or zone key. Shown able to fail: temporarily appending an ERB comment naming the format key modern to _decks.html.erb made 'never names a game...' fail naming that file; restored with git checkout, not committed.

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

A guard that passed on arrival (the page already runs a constant number of statements). Shown able to fail: temporarily changing Deck::CardUses to preload(:parent) and read each row's deck with Deck.find_by made the example fail (30 vs 50 statements); restored with git checkout, not committed. Deviation from the plan's example: a deck holding only a proxy is added to both runs, because with a single deck the overview's parent preload and CardUses' parent preload are the same statement and the second is a query-cache hit, so the baseline counted 26 against 27 (same trap as spec 070's lesson).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Guards that passed on arrival (a visitor's card page already reads no lots, locations, decks or deck_proxies and shows no In decks, Free to use or #in-decks). Shown able to fail: the new signed-in control example runs the same grep on a collector's card page and finds statements on all four tables, so the visitor example's pattern matches what the page reads when it does read them; the plan's code ran as written.

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

Expected red until the next commit: the two 1280px examples (light and dark) fail on the page-level overflow check. Measured at 1280px: Your copies' Location cell holds the 60-character deck's label, is white-space:nowrap and 547px wide, so the #copies table is 982px in a 1265px viewport and the page scrolls to 1354px. The other 13 examples pass.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A placed lot's Location cell takes spec 048's c-table__place class and a c-table__place-name span, so a 60-character deck's label wraps; an unplaced lot's No location stays on one line. Measured at 1280px: the cell went from 547px nowrap to 379px normal, the page scrollWidth from 1354 to 1265 (the viewport).

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

Prose verification cycle in place of a failing test: grepped each old sentence and confirmed it existed exactly once, edited, then grepped that the new text is present and the old text gone (only plan.md still quotes 'No new CSS'). The previews changed only the head count text (4 copies in 2 decks, 1 proxy: rows hold 3+1 copies and 1 proxy).

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

Prose verification cycle in place of a failing test: grepped each old sentence and confirmed it existed exactly once, edited, then grepped that the new text is present and the old gone. The card-page paragraph was re-read against Catalog::CardOverview, Deck::CardUses, DecksHelper#card_decks_count_line and the _stats and _decks partials; no new numeric constant. The 073 row's Status stays Approved until the pull request merges.

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

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ole on a phone (spec 073)

Below 640px of the page container the head count takes its own line (cut at 360px) and the empty state's Add to deck link stays on one line (broken at 390px); AC-5.5, AC-5.6.

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

Factory data, placeholder card images. Four states (no decks, some, all, proxies only) on desktop and a 390px frame in both themes, the wrap rule and the Your copies markup fix, the head count and the empty-state link, each before (emulated) and after, and a GIF from the card page to the deck page on desktop and on a phone.

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

The new example reads the private proxies_by_zone for each account and fails when the Deck::Proxy account_id filter is removed (it got {2 => 1, 6 => 8}, expected {2 => 1}); the existing example still passed under that mutation. The class comment now says four statements however many zones there are, one for a card in no deck and with no proxy, none for a nil account (checked with count_queries: 4 and 1).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The CSS fix 2e64c8c added the head count and empty-state link rules to the name-wrap rule; ItemPage, ItemPagePhone and collection-and-lots now describe all three (spec 073 decision 10, AC-5.5, AC-5.6).

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>

# Conflicts:
#	docs/specs/README.md
Two new lessons (a section head with a count; a scripted edit of a plan), paragraphs added to the supersession-list and statement-count lessons, and a line in the guards-that-go-red memory.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
plainprogrammer and others added 4 commits November 11, 2026 23:10
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…log core

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

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@plainprogrammer
plainprogrammer marked this pull request as ready for review November 12, 2026 04:44
@plainprogrammer plainprogrammer self-assigned this Nov 12, 2026
@plainprogrammer
plainprogrammer merged commit 5f14142 into main Nov 12, 2026
9 checks passed
@plainprogrammer
plainprogrammer deleted the 073-card-page-deck-stats branch November 12, 2026 11:58
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.

Show "Free to use" and "In decks" on the card page

1 participant