Canvas: traced again from the app, and the tracer kept #218

Merged
Grandiras merged 2 commits from canvas-home-settings into main 2026-09-22 21:15:14 +00:00
Owner

Closes #206. Closes #208.

design/Ponente.free was behind the app in the places both issues list. Instead of patching frames by hand, every frame that draws a page the app serves is traced again from the running stack (with #213, #215 and #216 in).

Frames (45)

  • Home, all six: the for-you strip, a pin on every tile (the pinned one always drawn), tiles in the member's own order, Recently deleted under them, and the gear on hover. The tile details #206 asked to compare (Only you on a private board, 2px dashes at 72%, the phone row's count under the name) are simply what the app draws. The group caption is updated.
  • Board settings: Settings — General (with the delete confirmation showing), Columns, Tags and Access replace the four Admin — frames for pages that moved or were deleted.
  • Header menus: switcher + account menu. The Admin flyout is gone, and Members sits in the account menu's admin group. The phone menu sheet is re-traced the same way.
  • New: Admin — Board record and Board — Deleted (#196).
  • Re-traced: all three desktop board frames, both card dialogs, calendar month and timeline, members, profile, and the seven phone frames except the staged drag.
  • Kept as frames of their own: the two 2026-08-29 redesigns that haven't shipped, Admin — Members · redesign (not built) and Card Modal · assignee redesign (not built) (light and dark), restored from main's file so the trace didn't overwrite the spec. The board-card redesign did ship, and the traced board frames show it.
  • Untouched: the states, the drag, Toasts, the auth pages, Foundations, Components, Brand, the UX review.

Sample content is a seeded demo deployment (invented members and boards, one deleted board, one banned member), removed again afterwards. Avatars come out as empty circles, because the tracer doesn't carry images.

design/trace

The tracer that did this, kept so the next pass is a rerun: capture.mjs (Playwright drives each state), extract.js (DOM → boxes, text runs, SVG paths with computed styles), build.py (posts FREE-format frames to Lunacy's local API), frames.sh (which capture goes to which frame), and the seed/unseed for the demo data. README.md gives the run order. It resolves Playwright from tests/e2e, so there's no second install. out/ and the generated seed.sql are git-ignored.

Docs

docs/frontend.md's canvas section: the frame list, a paragraph on this retrace and how it was done, the redesign frames and why they're separate, and the Home frames tracing the app now (the "app overtook them" paragraph is closed). CLAUDE.md's frame list is updated to match. Unit tests (incl. DocumentationTests): 558/558.

🤖 Generated with Claude Code

Closes #206. Closes #208. `design/Ponente.free` was behind the app in the places both issues list. Instead of patching frames by hand, every frame that draws a page the app serves is traced again from the running stack (with #213, #215 and #216 in). ## Frames (45) - **Home**, all six: the for-you strip, a pin on every tile (the pinned one always drawn), tiles in the member's own order, *Recently deleted* under them, and the gear on hover. The tile details #206 asked to compare (*Only you* on a private board, 2px dashes at 72%, the phone row's count under the name) are simply what the app draws. The group caption is updated. - **Board settings**: *Settings — General* (with the delete confirmation showing), *Columns*, *Tags* and *Access* replace the four *Admin —* frames for pages that moved or were deleted. - **Header menus**: switcher + account menu. The Admin flyout is gone, and Members sits in the account menu's admin group. The phone menu sheet is re-traced the same way. - **New**: *Admin — Board record* and *Board — Deleted* (#196). - Re-traced: all three desktop board frames, both card dialogs, calendar month and timeline, members, profile, and the seven phone frames except the staged drag. - **Kept as frames of their own**: the two 2026-08-29 redesigns that haven't shipped, *Admin — Members · redesign (not built)* and *Card Modal · assignee redesign (not built)* (light and dark), restored from `main`'s file so the trace didn't overwrite the spec. The board-card redesign did ship, and the traced board frames show it. - Untouched: the states, the drag, Toasts, the auth pages, Foundations, Components, Brand, the UX review. Sample content is a seeded demo deployment (invented members and boards, one deleted board, one banned member), removed again afterwards. Avatars come out as empty circles, because the tracer doesn't carry images. ## `design/trace` The tracer that did this, kept so the next pass is a rerun: `capture.mjs` (Playwright drives each state), `extract.js` (DOM → boxes, text runs, SVG paths with computed styles), `build.py` (posts FREE-format frames to Lunacy's local API), `frames.sh` (which capture goes to which frame), and the seed/unseed for the demo data. `README.md` gives the run order. It resolves Playwright from `tests/e2e`, so there's no second install. `out/` and the generated `seed.sql` are git-ignored. ## Docs `docs/frontend.md`'s canvas section: the frame list, a paragraph on this retrace and how it was done, the redesign frames and why they're separate, and the Home frames tracing the app now (the "app overtook them" paragraph is closed). `CLAUDE.md`'s frame list is updated to match. Unit tests (incl. `DocumentationTests`): 558/558. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Canvas: traced again from the app, and the tracer kept
All checks were successful
CI / build (pull_request) Successful in 48s
6d5d245d96
Every frame that draws a page the app serves is redrawn from the running
stack: the home page with its strip, pins and recently deleted; board
settings in place of the four Admin frames for pages that moved; the header
menus without the Admin flyout; and new frames for the board record and a
deleted board. The two redesigns that have not shipped (the card dialog's
assignee panel, the members filter) are kept as frames of their own beside
the traced pages, so the trace did not overwrite the spec.

The tracer lives in design/trace so the next pass is a rerun: Playwright
drives each state, an extractor turns the DOM into boxes, text and paths,
and a builder posts them to Lunacy.

Closes #206. Closes #208.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator

🤖 Reviewing this PR — the review will link the full session transcript.

🤖 Reviewing this PR — the review will link the full session transcript. <!-- opencode-run:review -->
opencode-reviewer approved these changes 2026-09-22 21:11:34 +00:00
Dismissed
opencode-reviewer left a comment

✅ Verdict: approve — no blocking issues found.

Nice piece of work — the tracer is a real rerunnable pipeline, not a one-off script pile, and the schema assumptions all check out against the entities and migrations (Members.Role still in the table, Boards.Key nullable and backfilled by DatabaseInitializer, BoardVisibility 0/1 semantics, BoardOrders/Comments/join-table column lists). The empty-home scenario's grant save/restore runs in finally, and unseed.sql restores the deployment's own board row-for-row. Docs and CLAUDE.md match the new frame list. Two non-blocking notes below: a wrong claim in the seed docstring about what gets sealed at startup, and dead --style-from sources in frames.sh for a rerun.



⏱ 2m 33s · 14 steps · $0.0321 · tokens: 118.5k in / 4.2k out (+408.6k cache-read) · Go: 5h 64% · wk 32% · mo 49%
📜 Full session transcript

✅ **Verdict: approve** — no blocking issues found. Nice piece of work — the tracer is a real rerunnable pipeline, not a one-off script pile, and the schema assumptions all check out against the entities and migrations (`Members.Role` still in the table, `Boards.Key` nullable and backfilled by `DatabaseInitializer`, `BoardVisibility` 0/1 semantics, `BoardOrders`/`Comments`/join-table column lists). The empty-home scenario's grant save/restore runs in `finally`, and `unseed.sql` restores the deployment's own board row-for-row. Docs and CLAUDE.md match the new frame list. Two non-blocking notes below: a wrong claim in the seed docstring about what gets sealed at startup, and dead `--style-from` sources in `frames.sh` for a rerun. --- --- ⏱ 2m 33s · 14 steps · $0.0321 · tokens: 118.5k in / 4.2k out (+408.6k cache-read) · Go: 5h 64% · wk 32% · mo 49% 📜 [Full session transcript](https://git.grandiras.net/Grandiras/opencode-bot/src/branch/opencode-logs/transcripts/Grandiras/Ponente/pr-218/run-2026-09-22T21-09-01-573Z.md) <!-- opencode-reviewed-head:6d5d245d960303d36ede7176ca0d4fec8cefd546 --> <!-- opencode-verdict:approve -->
@ -0,0 +14,4 @@
b home-new "Desktop — Home · New board" 4760 1120
b home-empty "Desktop — Home · Empty" 6320 1120
b cal-month "Calendar — Month" 40 2780
b cal-timeline "Calendar — Timeline" 1600 2780
Collaborator

--style-from "Admin — Boards" (and "Admin — Board access", "Admin — Columns", "Admin — Tags") points at frames this PR deletes from the canvas. build.py silently skips a missing source, so on a rerun the Settings frames would lose their corner radius and shadow with no error. Point these at a surviving frame (e.g. "Admin — Members", which the script already uses for record/deleted) or at one of the traced frames.

`--style-from "Admin — Boards"` (and "Admin — Board access", "Admin — Columns", "Admin — Tags") points at frames this PR deletes from the canvas. `build.py` silently skips a missing source, so on a rerun the Settings frames would lose their corner radius and shadow with no error. Point these at a surviving frame (e.g. "Admin — Members", which the script already uses for `record`/`deleted`) or at one of the traced frames.
@ -0,0 +1,168 @@
"""Demo content for the canvas traces — plaintext, sealed by EncryptionMigrator
Collaborator

The docstring says everything it makes is "sealed by EncryptionMigrator on the next app start" — true for Handle/DisplayName/Board/Card/Tag/Comment columns, but not for BannedReason: it is deliberately absent from EncryptionMigrator.Targets (see the comment on Member.BannedReason — "the column is new, so no row can hold plaintext in it"). The seeded ban reason stays plaintext. Harmless here (local demo data, removed by unseed, and Decrypt passes non-envelope values through), but the claim is wrong as written — worth narrowing to the columns the migrator actually covers.

The docstring says everything it makes is "sealed by EncryptionMigrator on the next app start" — true for Handle/DisplayName/Board/Card/Tag/Comment columns, but **not** for `BannedReason`: it is deliberately absent from `EncryptionMigrator.Targets` (see the comment on `Member.BannedReason` — "the column is new, so no row can hold plaintext in it"). The seeded ban reason stays plaintext. Harmless here (local demo data, removed by unseed, and `Decrypt` passes non-envelope values through), but the claim is wrong as written — worth narrowing to the columns the migrator actually covers.
Review: frames take their style from the frame they replace; the seed's sealing claim narrowed
All checks were successful
CI / build (pull_request) Successful in 55s
de643a5fc5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Owner

Both notes fixed in the latest commit: frames.sh now takes each frame's corners and shadow from the frame it replaces (the dead Admin sources are gone), and seed.py's docstring says which columns get sealed and that the ban reason stays plaintext.

Both notes fixed in the latest commit: `frames.sh` now takes each frame's corners and shadow from the frame it replaces (the dead Admin sources are gone), and `seed.py`'s docstring says which columns get sealed and that the ban reason stays plaintext.
Collaborator

🤖 Reviewing this PR — the review will link the full session transcript.

🤖 Reviewing this PR — the review will link the full session transcript. <!-- opencode-run:review -->
opencode-reviewer left a comment

✅ Verdict: approve — no blocking issues found.

Re-review: both notes from the previous pass are fixed. The seed.py docstring now accurately says the ban reason is outside EncryptionMigrator.Targets and stays plaintext (with the why), and frames.sh no longer points --style-from at the four Admin frames this PR deletes — every line now sources style from the frame it replaces, which survives. The rest of the tracer, seed/unseed round-trip, and the docs/CLAUDE.md frame-list updates were verified in the earlier pass and are unchanged. Good to merge.



⏱ 0m 32s · 3 steps · $0.0108 · tokens: 62.7k in / 983 out (+29.7k cache-read) · Go: 5h 64% · wk 32% · mo 49%
📜 Full session transcript

✅ **Verdict: approve** — no blocking issues found. Re-review: both notes from the previous pass are fixed. The `seed.py` docstring now accurately says the ban reason is outside `EncryptionMigrator.Targets` and stays plaintext (with the why), and `frames.sh` no longer points `--style-from` at the four Admin frames this PR deletes — every line now sources style from the frame it replaces, which survives. The rest of the tracer, seed/unseed round-trip, and the docs/CLAUDE.md frame-list updates were verified in the earlier pass and are unchanged. Good to merge. --- --- ⏱ 0m 32s · 3 steps · $0.0108 · tokens: 62.7k in / 983 out (+29.7k cache-read) · Go: 5h 64% · wk 32% · mo 49% 📜 [Full session transcript](https://git.grandiras.net/Grandiras/opencode-bot/src/branch/opencode-logs/transcripts/Grandiras/Ponente/pr-218/run-2026-09-22T21-13-54-317Z.md) <!-- opencode-reviewed-head:de643a5fc5c9f483415f040708c644b4cd36ec22 --> <!-- opencode-verdict:approve -->
Grandiras deleted branch canvas-home-settings 2026-09-22 21:15:14 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Grandiras/Ponente!218
No description provided.