Repository source: docs/plans/board_thumbnails/board_thumbnails_one_shot.md
Board and Recent image thumbnails
Cycle: v3/board_thumbnails; Mode: one-shot; Record/index: this file, plans index
Debug mode: enabled
Effort study: railspike-effort / v3/board_thumbnails; host ledger. Standing P2 enrollment.
Extended estimates: enabled
Cycle estimate: 0.50
Status: PR #28 open and thread reply posted; awaiting maintainer review, merge and deploy.
Original request
Maintainer, 2026-11-05: "let's please do the board thumbnails, and note that they've also been requested for the recent page"
Threads: board thumbnails ("this page (for now liked only) should have a small thumbnail that spans the entire height of an item that has an image attached"); Recent requests ("thumbnails for image posts"). Feedback item: PF-20261104-F60.
Authorization
The maintainer's message above (2026-11-05), following the thread-to-PR procedure in AGENTS.md. It authorizes one-shot execution of the outcome below, pushing the branch, opening the PR and replying in the board thread. It does not authorize merging or deploying. The maintainer also wants the result to serve as the About page's build example in v3/site_purpose; swapping it in is separate work after merge.
Outcome and work type
Application change. On the board and on Recent, every item whose post has an attached image shows a small thumbnail of that image, as tall as the item. Items without an image look as they do now. Clicking the thumbnail opens the thread, like the rest of the item.
Excluded: the other Recent requests in the same thread (longer summaries, a promote button); they stay follow-ups.
Approach and risks
To settle on inspection, before dependent work:
Which image an item shows: the thread root's first attached image is the likely reading. Record the choice.
Where the image reference comes from for a list: the listing query or read model may not carry attachments today. Prefer an existing field or join over a schema change.
High risk: list performance. Impact: slower board for everyone. Early validation: query timing on the local fixture. Mitigation: one indexed lookup per page, never per item, and lazy-loaded images.
Layout across 13 themes and phone width. Impact: crowded or broken cards. Early validation: phone screenshots in light, Word 97 and Chicago before finishing CSS. Mitigation: fixed small width, cropped with
object-fit, text keeps its place.Retracted or missing images. Impact: broken image icons. Mitigation: render only when the attachment record resolves.
Reuse decisions
Image data:
ImageReference::fromBody()andfilename(), the same parser post pages use; images are served by the existing/images/<sha256>.<type>route (ImageController), which still verifies the checksum.Presence: new
ImageStore::isPresent()checks the file exists at the referenced size.resolve()hashes the whole file, which is fine for one post page but too slow for 50 rows.Lookup: new
ForumRewrite\Images\ListThumbnails, onepostsquery per page by primary key, filtered to non-retracted bodies containingImage-v1:. No schema change:threads.body_previewholds only the first line and Recent truncates bodies at 1024 characters, so neither can carry the reference.Rows: both lists already share the
thread-rowgrid (partials/thread_row.php,partials/recent_entry.php); a newpartials/row_thumbnail.phpserves both, and.thread-row--thumbadds the first column inpublic/assets/site.css.Flag:
FORUM_IMAGE_CONTENT_ENABLED, as for post images.
Completion conditions
Normal entry: open
/and/recent(or the Recent route) on zenmemes.End-to-end: an image post shows its thumbnail in both lists; clicking it opens the thread.
Recovery: a missing or retracted image shows no thumbnail and no broken icon.
Release: PR open with checks recorded; deployment belongs to the maintainer.
Concepts touched
Post presentation: changed (adds list thumbnails). Recent conversation: used unchanged. Proposed: none.
Verification and recovery plan
Smoke set plus changed tests; a test fixture with an image post on both lists. Every theme at phone and desktop width. qdb and other profiles unchanged. Full suite not run, per AGENTS.md.
Starting revisions and branch
Branch feat/board-thumbnails from 822d6134692883e145728db96b1a9aa62f1ca496.
Planning commit: 42e93369.
Dated execution history
2026-11-05T16:44:35Z: record written before detailed inspection.
Planning commit
42e93369confirmed before implementation.Choice: each row shows the image of its own post. For the board that is the thread root; for Recent it is the contribution itself, so an image reply shows its image. The thumbnail repeats the title link and is hidden from the tab order and screen readers.
Discovery: the board row and Recent row cannot carry the image reference from existing columns (see Reuse decisions), so a per-page lookup was added instead of a read-model change.
Correction during work: the first CSS placed the thumbnail rules before the base row rules, which would have kept the excerpt in column 1; moved after them before any check.
Not changed: board search and profile pages also use
thread_row.php; they show no thumbnails because they do not run the lookup. Follow-up if wanted.
Study history
2026-11-05T16:44:35Z intake: 0.50 projected total for both lists. Single exposed Claude rater; board templates were seen earlier today in v3/site_purpose, but the attachment and listing code was not inspected. R1 hashes not re-verified. Extended estimates enabled.
2026-11-05T17:45:00Z closeout: delivered scope v1 in full. Projection 0.50 preserved; retrospective scope assessment 0.40, single exposed Claude rater, not independent. Maintainer comfortable-fit and acceptance pending.
Outcome
On zenmemes, board list rows and Recent rows for posts with a stored image show a small thumbnail, as tall as the row, linking where the title does. Other rows, other profiles and other pages are unchanged. Live deployment and the About example swap in v3/site_purpose remain.
Verification
./v3 test --smoke BoardListTest RecentPostTest ImageContentTest: 439 run, 439 passed. New testBoardListTest::testImagePostsShowAThumbnailOnTheBoardAndRecentcovers a stored image (thumbnail), a reference with no file (none), a text post (none), and images turned off (none), on both lists. Full suite not run, perAGENTS.md.Headless Chrome against a local zenmemes server seeded with three image posts, one text post and an image thread with a reply: board and Recent in all 13 themes at 390 and 1280 px. Every thumbnail loaded, filled the row's content height (73 to 122 px tall, 56 px wide), and the reply count stayed in its own column. Contact sheets reviewed by eye.
./v3 feedback check: 0 problems;./v3 feedback indexregenerated.Not verified:
tests/browser/recent.mjs, statically generated first pages on a real deployment, and the live site.
Final review
Diff covers 12 files within the outcome: controllers, one helper, one partial, row templates, CSS, test, concept, item and index. No schema or dependency change; playwright-core was installed from the existing lockfile for local checks only.
Commit/merge/publication status: completion commit acc161fc; branch feat/board-thumbnails pushed; PR #28 open; thread reply reply-20261105165352-caf2a99e posted as claude (new key, fingerprint awaiting approval). Not merged or deployed.
— Claude · 2026-11-05 UTC · Model: claude-opus-5-5