Skip to content

feat(layout): show the unofficial-content notice and source attribution on every page - #67

Merged
plainprogrammer merged 17 commits into
mainfrom
018-content-notice-footer
Oct 12, 2026
Merged

plainprogrammer merged 17 commits into
mainfrom
018-content-notice-footer

Conversation

@plainprogrammer

@plainprogrammer plainprogrammer commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

What changed

Every page now ends with a footer carrying Wizards of the Coast's Fan Content Policy notice and the Scryfall attribution. Until now the app had no unofficial-content notice anywhere, and its only attribution was one line on the card page, while the collection, search results and the scanner showed card images with none. Research 016 lists both as gaps for any instance, and ruling 28 asked for this footer.

  • The wording belongs to the Magic catalog. A catalog source may supply its lines through a new optional hook, .content_notice; MTG::Scryfall::Source supplies the policy's notice (word for word, with "Collector" as the title) and "Card data and images provided by Scryfall." The core (Catalog::ContentNotice, the layout, the layouts/footer partial) names no collectible, source or rights holder, and spec/footer_core_spec.rb guards that (ADR 0018, updated here).
  • Links, no logo. "Fan Content Policy" links to Wizards' policy page and "Scryfall" to scryfall.com, in the same tab. A line is plain text plus the phrases that link out; a link is rendered only for an absolute https address on a phrase that occurs exactly once. The footer holds text and links only.
  • One place, every page. The application layout renders it after the page's main content, so pages do nothing to get it. The card page's own attribution line is removed. Requests answered without the layout (a Turbo-Frame request, a Turbo Stream, the health check) carry none.
  • Phones. The footer scrolls with the content and its last line stops above the fixed tab bar. The layout marks the shell c-shell--footed and the footer takes the bar's clearance from c-main, so there is no empty band before it.
  • Scanner pages. The footer needs no script or inline style, and the scanner's Content-Security-Policy is unchanged.
  • Design system. A new Footer pattern: its own block at the end of collector/additions.css, docs/design-system/components/Footer.md, and a README line.

Documents

  • Spec: spec.md (v1.2.1, approved, reviewed twice)
  • Plan: plan.md (approved with one change: a body class in place of a :has() selector)
  • Verification: verification.md

Verification

bin/ci passes: RuboCop, Brakeman, bundler-audit, importmap audit and RSpec with 1178 examples, 0 failures, 1 pending (the art-agreement check, which needs a local cache and is unrelated). Every acceptance criterion (AC-1.1 to AC-4.4) is met by a passing example; the table is in the verification document. A read-only implementation review found the code spec-aligned and identical to the plan.

Not covered by an example: a Turbo morph refresh, touch targets, and following a footer link from the scanner mid-sitting. The "runs no query" example counts queries at the model, not around a page render.

Owed from the maintainer

On a real phone, since headless Firefox has no safe-area inset and no touch:

  • Scroll a page with the tab bar to its end: the footer's last line stops above the bar, with the home indicator clear.
  • Tap both footer links: each opens in the same tab, and Back returns to the page.
  • With a card added to the sitting, follow a footer link from /scanner and come back: the camera starts again and the sitting still lists the card.

Expected conflicts with the spec 019 PR (issue #35, uncropped card images)

Both branches add adjacent lines in the same places. Keep both sides in each:

  • the end of app/assets/stylesheets/collector/additions.css (each appends its own block);
  • docs/design-system/README.md, after the spec 015 "App additions" line;
  • the pattern list in spec/design_system_files_spec.rb;
  • possibly the RSpec/DescribeClass list in .rubocop.yml.

This PR removes one line inside the card page's block of additions.css (.c-attribution) and one line of catalog/entries/show.html.erb; it touches no image rule.

Screenshots

From test data, so the cards show their names on blank cards. Phone shots are a 390 × 844 frame scrolled to the end of the page.

Sign-in, 1280px Card page end, 1280px
Sign-in Card page
Card page, 390px Scanner, 390px Collection, 390px, dark
Card page on a phone Scanner on a phone Collection on a phone, dark

Collection, 1280px, dark

Closes #34

🤖 Generated with Claude Code

plainprogrammer and others added 17 commits October 11, 2026 17:42
Issue #34.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fable, Mode A: needs revision, nothing blocking. The scanner policy is
compared by directives (its nonce differs per request), the footer sits
directly after short content, a type supplies its lines in display
order, and ADR 0018's consequence is updated with the card page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Maintainer's rulings of 2026-10-11, relayed by the coordinator: 'Fan
Content Policy' links to Wizards' policy page and 'Scryfall' to
scryfall.com, so a notice line carries link data; README.md is left
out of this PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fable, Mode A, second pass: nothing blocking. A phrase matches once
and exactly, an address is an absolute https URI, identical lines are
defined, and a footer link is a brand link with no target.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Approved by the maintainer on 2026-10-11, relayed by the coordinator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rendered from the per-phase commits of the local 018-plan-phases
branch, where each phase's specs and RuboCop were green.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fable, read-only: ready to execute, nothing blocking. The phone test
frame is shorter, a stale CSS comment goes, link phrases marked
html_safe stay plain text, and the scanner link case is listed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The maintainer approved the plan with one change: the shell is marked
c-shell--footed where the plan used a :has() selector. Phases 2 and 3
were re-proved red then green on the scratch branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plan 018, Phase 0: The contract and its collector. A source may supply
its footer lines through an optional .content_notice hook; a line is
plain text with the phrases of it that link out.

Ruling: executed in the session from the plan's tested phase commit,
not by a subagent - the brief allows reusing the scratch commits -
costs a re-run through subagents if that is wanted.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Plan 018, Phase 1: The Magic catalog's notice. The policy's wording
with Collector as the title, then the attribution, each with its link.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Plan 018, Phase 2: The footer on every page. The layout reads the
registered sources' lines once, marks the shell c-shell--footed when
there are any and renders one footer after the main content. The card
page's own attribution line and its rule go.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Plan 018, Phase 3: Presentation and the design-system pattern. Small
print under a divider on the page gutter, with brand links. Below
640px the footer takes the tab bar's clearance from c-main through the
shell's c-shell--footed class, so its last line stops above the bar.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Plan 018, Phase 4: Records. The card page's attribution is no longer a
core exception, and the footer's core spec is a second guard.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Plan 018, Phase 5: Integration Verification. bin/ci passed on 134ce3e
with 1178 examples, 0 failures, 1 pending. Three checks that need a
real phone are listed as owed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fable, Mode B: spec-aligned, nothing blocking. One count corrected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A layout-set class over :has() (maintainer's choice), one subagent per
phase even for a small plan (maintainer's feedback), how the prototype
branch was built, and three narrow-frame facts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Spec 018: four faults only a whole-suite run or a broken rule showed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@plainprogrammer
plainprogrammer marked this pull request as ready for review October 12, 2026 14:16
@plainprogrammer plainprogrammer self-assigned this Oct 12, 2026
@plainprogrammer
plainprogrammer merged commit 65cbefe into main Oct 12, 2026
4 checks passed
@plainprogrammer
plainprogrammer deleted the 018-content-notice-footer branch October 12, 2026 19:12
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 the unofficial-content notice and source attribution on every page

1 participant