Implement option B card metadata (stacked on https://git.justinvisser.org/justinzeus/wolfskin/pulls/51) #54
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fm/tv-card-meta-build"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Outcome and stack
Implement revision-6 option B: compact card metadata, always-visible library captions and one opaque bottom state line. AI-assisted (fork-internal; not an upstream contribution).
Stacked on the TV loading/motion change: #51 . Base is
fm/tv-motion-build, including motion follow-upfdff85c8. This must merge after that motion change. Firstmate will retarget this PR tomainafter the motion change merges; this PR must not merge first.Review-ready, not merge-approved. The reported caption-relaunch and painted-skeleton-caption blockers are addressed by the scoped follow-up below. Design review classified the six retained visual differences as renderer/fixture artifacts, not approval blockers. Native A–Z sorting, existing screen chrome, platform typography and the previously approved Discover heading band were not changed to imitate stale fixture rendering.
Approved decision and bottom-pixel correction
Justin approved B, not A: watched is a 3 px accent line; resume remains 6 px proportional accent over the full-width
color.progressTracktrack.His additional note, verbatim:
TitleCardnow clips artwork out of the backing band before painting the opaquecolor.bgbacking. Merely overdrawing after rounded clipping left poster colour in antialiased corners; the native regression caught that. The line has zero left/right inset, 2 px bottom backing and a 2 px separator above its fill, inside the 16 px art radius. The separate 4 px focus ring remains above it and scales with the card at 1.08. The track is precomposited/quantised once from the canonical tokens to preserve the approved#3d3d3fpixels instead of Skia alpha-rounding differences.Some approved frames themselves leak artwork on their lowest row. Original Annie Hall rows contain white poster pixels; the focused Locke treatment row also varies with its artwork. The native build intentionally makes those rows solid. Original-frame samples: https://pages.justinvisser.org/wolfskin/tv-card-meta-build/approved-bottom-row.json .
Behaviour
Same-data native evidence
Gallery: https://pages.justinvisser.org/wolfskin/tv-card-meta-build/ . Each pair retains the full native 1920×1080 image and a 3840×1080 side-by-side against the frozen revision-6 renderer replayed with
treatment=B.Movies/Shows/pinned captures render
LibraryScreen; Home and Discover render their production shelf components beneath the production shell at the reference’s pinned anchor. Additional narrow/treatment widths exercise the shared card/caption/rating components. The source fixture records, capture harness and native text measurements are retained in the gallery; the throwaway capture harness/art copies are removed from the app worktree. All watch states are fixed illustrative inputs, not mutations of household data.Pixel proof
CardBottomPixelTestrenders white Annie Hall, dark Locke and two real colourful posters across three states, all-rest and individual 1.08 focus: 15 captures / 60 full-width bottom-row comparisons. Every bottom-row pixel, including rounded-corner coverage, must equal an art-free backing/ring reference. Straight-edge pixels and fill/track samples additionally assert exact state colours; no tolerance or different-data screenshot substitutes for that proof.#07070a#cc9fff#3d3d3f#cc9fff#07070a#cc9fff#3d3d3f#cc9fff#07070a#cc9fff#3d3d3f#cc9fff#07070a#cc9fff#3d3d3f#cc9fffRaw samples: https://pages.justinvisser.org/wolfskin/tv-card-meta-build/pixel-proof.json .
CardGeometryTestasserts actual native grid/shelf pitches 524 / 632 / 522 / 441 px, initial library rows 372 / 896, pinned rows 168 / 692 ending at 1076, ring clearances 20.48 / 26.48, 24×24 checks and 210/327 px fitting. Both loading/ready shelf heights match. It also covers always-visible unfocused filmography, no aggregate series runtime and no watched check on a resuming item.Retained renderer/fixture artifacts — disclosed, not approval blockers
Design review traced these differences to unchanged native behaviour or reference-renderer fixtures. None authorizes a new design deviation; unapproved design changes still block merge.
line-height:1.5; native follows the written 32 px title line with the same 28 px bottom inset. Design review classified this visible offset as a renderer artifact, consistent with the locked native base.The original 18-pair gallery remains frozen at
fe44a3c2; its original blocker wording predates this review classification. Existing native/reference frames are not regenerated by the follow-up.The solid lowest row is an explicitly requested correction, not a hidden deviation. In the treatment replay, the selected B root class applies B to both halves while the historical A/B explanatory labels are retained; only B ships.
Scoped review follow-up
Follow-up head:
c2f7ccc438a623ef2bff9b858ea6591a675ab481— one combined review-fix commit on the same stacked branch.>= 1is not resuming. A real-Annie-Hall pixel regression compares Home/library strips at 50%, 100% and 150%, including the 6 px → 3 px transition.make testormake apk-debugrerun was performed, per steering.CardBottomPixelTest.completedHomeProgressUsesTheSameWatchedStripAsLibraryCards: it compared 10 px even when the watched backing occupies only 7 px, including 3 px of artwork. The regression now compares the entire actual backing (10 px resume / 7 px watched), with exact state-colour assertions; the final 20-case gate passes.Follow-up native proof: focused Home title replacement, blank loading bands, completed Home/library strip parity, focused test counts.
Original full-suite / APK verification
Original full-suite/APK head:
fe44a3c24f5cdd6e857f43445ca3309466201f83. Final fetch/rebase confirmed the stacked branch was current before those gates. The scoped follow-up above was validated separately; the existing APK is not a build of the follow-up head.generate_tokens.py --check: passed.make testand one original-headmake apk-debugwere run. Gradle used the repository’s serialized wrapper; no optimized build was run.make testcomponentmake testexits nonzero because of these known order-sensitivePersonPickerSessionTesttimeouts, not a green full-suite claim. Firstmate’s steering identifies this family as fixed by the test-only sync change onmain, absent from the stacked motion base, and explicitly says not to chase it here. Every observed failing method is listed:org.justinvisser.wolfskin.tv.PersonPickerSessionTestlaunchRightThenOneOkKeepsPickerClosedfastLeftLeftOkKeepsPickerClosedavatarRightThenOneOkKeepsPickerClosedlaunchLeftThenOneOkKeepsPickerClosedavatarLeftThenOneOkKeepsPickerClosedNo other failing tests were observed in that original full-suite run. Machine-readable results/classification: https://pages.justinvisser.org/wolfskin/tv-card-meta-build/full-test-failures.json .
make apk-debug: passed (defaultDebug, application IDorg.justinvisser.wolfskin.tv.debug), producing the universal APK and armv7/arm64/x86_64 splits. Universal artifact:Wholphin-default-debug-1.1.0-153-gfe44a3c2-65.apk; SHA-2566b5d41da28dca13ac0c5dd42591c99773a68c20c10aa656a34047514a067c67f. Build-only proof; no installation or playback claim.On-device checklist — not run; TV stays off tonight
No ADB, installation, TV actions, optimized APK or on-device GPU timing measurement was performed.
Code review (claude), one round - verdict: BLOCK, 1 blocking finding. Reviewed head
fe44a3c24f5cdd6e857f43445ca3309466201f83. Read: full non-test Kotlin diff, token JSON diffs, spec/README diffs,CardBottomPixelTestandCardGeometryTestin full; ran onlygenerate_tokens.py --check(passes). No Gradle.Blocking - Home poster / Home landscape / Discover captions vanish after the first D-pad move inside a shelf. In
CardCaption(focus-only branch) the animation state isremember(title) { Animatable(0f) }but the effect isLaunchedEffect(focused, reduced).HomeShelfandDiscoverShelfuse a singleCardCaptionper shelf whosetitlechanges with the column and has nokey. After moving Right/Left, a fresh alpha-0Animatableis created and the effect does not relaunch, so the title/year/duration/check stay invisible until focus leaves and re-enters the shelf. The oldCaptionavoided this by keying the effect on theAnimatable(LaunchedEffect(alpha, visible, reduced)). Library grids (not focus-only) andTitleShelf(one caption per item) are unaffected. No test changes the title of a focused focus-only caption. Fix:LaunchedEffect(alpha, focused, reduced)(orkey(title)) plus a test that changes the title while focused and asserts the caption is visible.Verified OK: bottom strip clips art out of the backing band before the opaque
color.bgbacking, inside the 16 px rounded clip, ring and 1.08 scale on the outer modifier above it; all card kinds go throughTitleCard;CardBottomPixelTestcompares the full lowest row (corners included) of four real posters x 3 states x rest/focus by exact ARGB, no tolerance. Metadata rules (film/episode/series, no check when resuming/unwatched) and null/zero/huge runtime handling; card-width single-line ellipsis; grid pitch 524 / poster shelf 632 unchanged; skeletons reserve the same slots; removed tokens/code really unused; generated files consistent; no key/Back handling touched.Non-blocking notes:
CardGeometryTestusesdelta = 1fon pitch/ring/pinned-row assertions despite the "no tolerance" claim; tighten to ~0.1.tileCaptionBand/wideCaptionBandchanged 0 -> 32dp in tokens but nothing reads them (real value isCardMetadata.landscapeBand).LibraryTitle.availabilityis now dead data - worth telling Justin.TitleShelfnon-tile caption shows duration only forkind == "movie"; resume>0 with runtime 0 gives the watched line but no check.Full report: firstmate data
review-54-code/report.md.Design review (claude), one round - verdict: BLOCK, 1 blocking finding. Reviewed head
fe44a3c24f5cdd6e857f43445ca3309466201f83against the approved revision 6 option B frames (3 px accent watched line, 6 px accent resume fill, solid lowest row). I opened every one of the 18 native/reference pairs and measured the rasters (ffmpeg + numpy); no Gradle/make.Blocking - loading skeletons paint title/subtitle placeholder bars that no approved frame shows.
PosterCaptionSkeleton(LoadingSurface.kt:61, used byLibraryScreen.kt:124,HomeShelf.kt:57,DiscoverShelf.kt:69) draws a full-card-width 32 px bar and a half-width 26 px bar (surface2, 16 px radius) 38 px below every skeleton card. The approved loading reference (data/tv-v2/motion-2026-11-06/proto.js:59-75) is art-sized blocks only; the revision 6 frames contain no loading frame; the gallery has no skeleton capture. On Home posters, Home landscapes and Discover the ready state shows a caption only under the focused card, so the bars would vanish at ready under all the others. Heights/bands are fine (CardGeometryTestasserts loading = ready 632/522/441). Fix: reserve the band without painting bars (keeps every height), or publish native skeleton captures and get Justin's explicit approval for caption bars on the always-visible grids only. [INFERENCE] the bars render as written; I could not capture a skeleton without Gradle.Verified against the approved frames: rest cards end in two solid
#07070abacking rows on white, dark and colourful art (Home wide rest cards 480/480 px, where the reference leaks(229,218,212)art); strip stack identical row for row (2 px separator, 6 px fill/#3d3d3ftrack, fill ends at x=797 = 43% in both; watched 3 px#cc9fff); focused ring rows 770-773 unchanged above the strip; art rows 372/896, pinned 168/692..1075, Home poster 252/884 (632), Home wide 252/774 (522); caption title/meta glyph rows within +/-1 px (28/32, 24/26); checks 24x24; single-line ellipsis; metadata fits at 210/327 px.The five listed reference differences - classification (none is a deviation of the built card/caption/state-line design; none needs Justin's approval, but he should be told 2, 4b and the extra one):
sortNamesort, untouched by the PR. Cards 1-5 identical in both.discover-tokens.json:3(Justin's 2026-11-06 "heading-to-card gap 60 px", onmainsince9d2471c5); the frames' own "before" capture (rd3.png) pre-dates it. Do not change native.sh_movies.pnghas the native positions, toolbar glyphs and "films" label. No chrome file is in the diff.200752 vs 53.95 px,2h 56m79 vs 80.68): metadata ends 3 px earlier, one ellipsis one glyph earlier; line boxes exactly 28/32 and 24/26. (b) Plate 28 px vs 24 px: fixture artifact in unchanged code. The reference hard-codesfont-size:24px(frames.html:375); the shipped TV capture shows the same 24 px; the plate rule (28 px, shrink to the 24 px floor, then drop trailing entries) is unchanged, and this fixture has only 2 ratings, which fit at 28. Non-blocking: add one native capture with the real ratings set.Extra visible difference not listed in the PR (artifact, non-blocking): the on-art title on Home wide/tile cards sits 6 px lower in native (e.g. The White Lotus glyph rows 503-523 vs 497-517). The reference's
.ov binheritsbody{line-height:1.5}(42 px box) over the same 28 px bottom inset; native uses the README's 32 px title line (HomeShelf.kt:87).Non-blocking notes: (1) with the 3 px watched line, bright-art wide cards show a 3 px band of bare unscrimmed art above the 2 px separator (rows 548-550 on Desperate Housewives); it is in the approved B frame and reproduced exactly. (2) Gallery lacks a skeleton capture and a 4-rating plate capture. (3) The earlier code-review blocker (focus-only captions vanish after the first D-pad move) still stands; none of the 18 first-focus captures can show it.
Full report:
/root/.treehouse/firstmate-7bab20/2/firstmate/data/review-54-design/report.md. Evidence crops and measurement scripts:/root/.treehouse/firstmate-7bab20/2/firstmate/data/review-54-design/evidence/. Gallery inspected:/opt/stacks/pages/store/wolfskin/tv-card-meta-build/(https://pages.justinvisser.org/wolfskin/tv-card-meta-build/).Delta review of
c2f7ccc438against both blocking findings onfe44a3c2(read the full delta: 11 files, +248/-44).Code B1 (focus-only captions vanish after the first focus move) is fixed:
CardCaption'sLaunchedEffectis now keyed(alpha, focused, reduced), so a title change creates a new Animatable and relaunches the effect (same as the mergedCaption), with a newCardCaptionMotionTestthat changes the title of a focused focus-only caption. Also folded in: pitch/ring assertions tightened (0.1 instead of 1), the unusedtileCaptionBandandwideCaptionBandtokens removed (generator and checksums regenerated; drift check passes on the lane), and Home progress >= 1 now draws no resume bar, matching Library and Title.Design B1 (unapproved caption placeholder bars in loading skeletons) is fixed:
PosterCaptionSkeletonnow reserves the band with a spacer and paints nothing, heights unchanged (loading equals ready heights, still asserted). The five listed differences plus the extra one stay classified as renderer or fixture artifacts by the design review. No new blocking finding; review/code-claude and review/design-claude carried to this head.Still held for Justin: this PR is stacked on PR 51 and does not merge before it; also his call that the cards no longer show Discover owner and request-stage captions (option B drops that prose, only the poster badge remains).