Skip to content

refactor: extract the canvas package, and make the interact transport injectable - #312

Open
ivanmkc wants to merge 4 commits into
lifeboard/00-test-envfrom
lifeboard/01-canvas
Open

refactor: extract the canvas package, and make the interact transport injectable#312
ivanmkc wants to merge 4 commits into
lifeboard/00-test-envfrom
lifeboard/01-canvas

Conversation

@ivanmkc

@ivanmkc ivanmkc commented Sep 2, 2026

Copy link
Copy Markdown
Owner

The stack

# PR What it adds Tests at this point
1 #311 A real localStorage for the test suite on Node 25 viewer 747
2 #312 @ivanmkc/termchart-canvas; injectable interact transport canvas 473 · viewer 278
3 #313 lifeboard PWA: fact log, boards, service worker lifeboard 36
4 #314 Shell, family profiles, tap layer lifeboard 82
5 #315 The agent turn, four providers, Connections lifeboard 142
6 #316 Packs, recipes, shopping-list arithmetic lifeboard 231
7 #317 Provenance and lineage lifeboard 257
8 #318 Calendar, Gmail, mail triage lifeboard 301
9 #319 The bridge and long jobs cli 314 · lifeboard 320
10 #310 Proactivity, scheduled boards, Google sign-in cli 320 · lifeboard 343
11 #320 Persistence audit fixes: multi-tab, stale builds, no-storage boot lifeboard 350
12 #321 User guide, bridge setup, QA guide, persistence audit lifeboard 350
13 #322 A plan for third-party integrations (docs only) unchanged
14 #323 A practice drill a board can define: audio + Q&A canvas 485 · lifeboard 372
15 #325 Export and restore lifeboard 389
16 #326 Draft a message, approve it, then send lifeboard 399
17 #327 Hand long work to the Mac lifeboard 406
18 #328 A Packs screen, and authoring one by describing it lifeboard 418
19 #329 Activity — what changed, who changed it, undo lifeboard 428

Every branch in the stack was checked out on its own and verified independently: npm install, tsc --noEmit for every package, npm test across the workspace, and the offline e2e where it exists. All nineteen are green — no branch depends on a later one to build or pass. Full viewer e2e (11 suites, 106 assertions) was run on #312 as the behaviour-preservation evidence for the extraction.


Stack position: 2 of 10. Base: lifeboard/00-test-env.

Extracts the renderers, registry and board lints out of packages/viewer into @ivanmkc/termchart-canvas, so the viewer and a second app render through one implementation rather than two that drift.

Behaviour-preserving. The 745 tests that passed before the move pass after it, split 468/277 across the two packages, plus the 3 new tests for the seam below.

Two things worth a reviewer's attention:

The package has two entry points, and the split is load-bearing. . is the browser barrel; ./lint exports only the patch appliers and the two lints. Without it the viewer's server bundle pulls renderInto → Leaflet → its CSS → a .png, and esbuild fails with "No loader configured for .png".

The interact transport is now injectable. A Checklist toggle used to POST the viewer's interact endpoint unconditionally; it now goes through setInteractTransport. This exists for correctness, not tidiness: an app with no such endpoint gets a silent 404 and the box stays ticked — the user sees a change that was never saved.

A note on grep. macOS grep treats flow-geometry.ts as binary and returns nothing for it; grep -a is needed. Two "orphaned" files were nearly left behind because of this.

Verified: canvas 473, viewer 278, typechecks clean.

🤖 Generated with Claude Code

ivanmkc and others added 4 commits September 2, 2026 07:50
First half of the canvas extraction: flow-patch, component-patch and panes-patch
have no dependencies outside their own set, so they move first and prove the
package wiring before React enters the picture. Their 36 tests pass unchanged in
the new home.

The viewer now imports them from the package. Four renderer files referenced
them as ../../ from client/renderers and were missed by the first pass; the
typecheck caught it.

Verified: viewer builds, and its suite reports 709 passing — the original 745
minus the 36 that moved. The two failures are pre-existing on Node 25, where a
native localStorage shadows happy-dom's; CI pins 20 and 22.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Completes the extraction. renderers/, registry, ansi, theme, interact and css.d
move from the viewer client, and flow-geometry, framing-lint and element-density
move from the viewer server, together with 25 tests.

Adds a node-safe subpath. The barrel exports renderInto, so a server importing
it dragged React, Leaflet and their CSS into a Node bundle and esbuild refused
on a .png. @ivanmkc/termchart-canvas/lint now carries the patch appliers and the
two lints alone, and the viewer server imports that.

Two claims in the plan were wrong, both from grep silently skipping a file it
treats as binary: element-density is not orphaned (flow-geometry imports it),
and three more tests belonged to the canvas rather than the viewer.

Verified: canvas 468 passing, viewer 277 passing — 745 together, exactly the
count before the move — plus the full viewer e2e suite, which is what proves the
lazy per-type chunking still works. The two remaining failures are the
pre-existing Node 25 localStorage ones.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A spike showed that with no server present, ticking a Checklist box appears to
succeed: the interact POST 404s and nothing visibly reverts, so the user sees a
change that was never saved. That makes this seam a correctness fix rather than
a convenience.

postInteract now delegates to an installed transport, defaulting to the viewer's
existing endpoint so nothing changes there. lifeboard will install one that
writes to its local store. Failure handling is unified: a non-2xx, a network
error and a throwing transport all drop the echo-guard entry, so the caller's
reverting re-render is never mistaken for a self-echo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The i18n test moved here with the renderers, and so did its dependence on a
working localStorage. Same setup file as the viewer's, for the same Node 25
reason.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant