Skip to content

v1.0 roadmap + P0: browser harness, embedded assets, honest CSP, SSE/backplane reliability#133

Merged
joaomdsg merged 9 commits into
mainfrom
claude/inspiring-cori-iw8qkb
Jun 12, 2026
Merged

v1.0 roadmap + P0: browser harness, embedded assets, honest CSP, SSE/backplane reliability#133
joaomdsg merged 9 commits into
mainfrom
claude/inspiring-cori-iw8qkb

Conversation

@joaomdsg

Copy link
Copy Markdown
Member

What this is

The ratified v1.0 roadmap (ROADMAP.md) plus the first slice of its
P0 phase ("stop the bleeding, stop the lying"). Every commit landed
test-first and the tree is green under go test -race ./...
including plugins/picocss, which was RED on a clean checkout before
this branch.

Roadmap

  • ROADMAP.md — five-phase plan (P0–P4) converged by a five-lens
    adversarial review panel over four debate rounds, ratified 5–0.
    50 items, each with concrete change/verify clauses and score-lift
    targets.
  • MIGRATION.md — every public break now requires an anchored entry
    with compiling before/after snippets (gate lands with P0.2).

P0 items landed so far

  • P0.1 vtbrowser — real-browser CI harness as its own module
    (core go.mod untouched). Proves what the DOM-less vt harness can't:
    click round-trips, morph focus preservation, reconnect banner
    lifecycle. ci-check.sh --browser + CI job.
  • P0.3 NumOps — inverted Min/Max removed; AtLeast/AtMost/
    Clamp with MIGRATION anchor; apidiff baselines regenerated.
  • P0.4 plugins — pinned upstream assets embedded via go:embed
    (Pico 2.1.1, ECharts 6.0.0, MapLibre 5.24.0 + licenses), served at
    content-hashed immutable paths; boot-time CDN fetch and its panic
    deleted; WithCDN(url, integrity) is the only third-party path and
    panics on missing/malformed SRI. Register does zero network I/O,
    proven by failing-transport tests.
  • P0.5 CSPmw.CSP() now emits 'unsafe-eval' (the bundled
    Datastar runtime compiles expressions via Function(); the old
    recommended policy bricked every click) plus
    frame-ancestors 'self'. Proven by a real-browser click test under
    the default policy; troubleshooting + production docs updated.
  • P0.7 SSE — drainQueue snapshots, writes, then compare-clears:
    failed writes no longer lose queued frames; reconnects re-ship a
    coalesced server-pushed-signal patch before the view fragment
    without clobbering client-local signals.
  • P0.8 backplane — all four feed tailers unified on one reconnect
    loop (jittered backoff, boot-retry, graceful stop). Changes and
    broadcast tailers previously died permanently on the first blip.
    New tailer_up/tailer_reconnect metrics; blip-injection tests
    plus an embedded-NATS server-bounce test.
  • Bonus fix found by the new harness — the reconnect banner never
    cleared passively (listened for events Datastar never dispatches)
    and its overlay swallowed clicks; now proven to clear with zero
    user interaction.

Still in flight on this branch

P0.2 (docs snippet-compile + MIGRATION coupling gates), P0.6 (strict
decode by default), P0.9/P0.10 (durable retention floor, live epoch
re-derivation), P0.12 (doc truth pass) — then P1–P4 per the roadmap.

https://claude.ai/code/session_01HUMecXGMK1WbJAf62r8AKT


Generated by Claude Code

claude and others added 9 commits June 12, 2026 00:03
Five-phase plan (P0 stop the bleeding through P4 release) converged by
a five-lens adversarial panel over four debate rounds and ratified 5-0.
MIGRATION.md starts empty; the apidiff coupling gate lands in P0.2.

https://claude.ai/code/session_01HUMecXGMK1WbJAf62r8AKT
drainQueue snapshotted the queue and cleared it before writing, so a
failed write lost every drained frame. It now snapshots under lock
without clearing, writes, and only on full success compare-and-clears
against the snapshot, so frames enqueued mid-write survive and a failed
write leaves the queue intact for the next reconnect drain.

Reconnect resync previously re-shipped only the view fragment; signal
values pushed while the tab was away were dropped. Resync now emits a
coalesced last-value-wins patch of server-pushed signals (tracked in a
per-ctx map so client-local signals are never clobbered) before the
view fragment, mirroring bootstrap order.

https://claude.ai/code/session_01HUMecXGMK1WbJAf62r8AKT
New vtbrowser submodule with its own go.mod so chromedp never taints
the dep-free core (core go.mod/go.sum byte-identical). API mirrors vt:
Open(t, app), Click, Type, WaitText, ConsoleErrors, plus SetOffline and
Eval for connectivity and focus assertions. Skips without a browser on
PATH; VIA_BROWSER_REQUIRED=1 (set by ci-check.sh --browser and the new
CI job) turns the skip into a failure so CI cannot skip silently.

Milestones prove what the DOM-less vt harness structurally cannot:
click round-trip, morph preserving focused input and typed value
across an SSE patch, reconnect banner lifecycle — each asserting zero
console errors.

https://claude.ai/code/session_01HUMecXGMK1WbJAf62r8AKT
NumOps.Min/Max had semantics inverted relative to the math.Min/Max
intuition their names invite (Min raised, Max lowered). Removed, with
a MIGRATION.md anchor; AtLeast(lo), AtMost(hi) and Clamp(lo, hi) state
the effect in the name. Clamp panics on inverted bounds.

Mount now panics on a child composition held by value, naming the
field and the fix — by-value children mis-bind and clobbered silently;
the opt-in dev-check lint for this class is replaced by the panic.
h.Fragment stops silently dropping attribute arguments: passing one
panics at construction with triage text.

apidiff baselines regenerated for the intentional break.

https://claude.ai/code/session_01HUMecXGMK1WbJAf62r8AKT
picocss fetched theme CSS from jsDelivr inside Register and panicked
on non-200 (pico.go:321), making a clean checkout's test suite RED and
offline boots impossible; echarts emitted an unpinned CDN script with
no SRI. All three plugins now vendor their pinned upstream artifacts
via go:embed (Pico CSS 2.1.1, ECharts 6.0.0, MapLibre GL 5.24.0, with
upstream licenses), served at content-hashed /via/assets paths with
immutable cache headers. Register does zero network I/O, proven by
failing-transport tests.

CDN delivery is opt-in only via WithCDN(url, integrity), panicking at
registration on empty or malformed SRI; emitted tags carry integrity
and crossorigin=anonymous. Version bumps without a matching asset
panic. refresh_assets.sh scripts re-vendor reproducibly from npm
tarballs.

https://claude.ai/code/session_01HUMecXGMK1WbJAf62r8AKT
The changes and broadcast tailers died permanently on the first
channel close or subscribe error — one blip and cross-pod broadcast or
changes processing was silently dead for the pod's lifetime, while the
projector alone knew how to reconnect. The projector's loop is now
extracted into a shared tailLoop (jittered backoff, bounded boot-time
retry, graceful-stop detection) and all four tailers run on it.

Broadcast re-Heads on every (re)connect — ephemeral semantics, missed
frames are skipped, never replayed. Changes and projector resume from
the last-applied offset, gap-free. New metrics tailer_up{feed} and
tailer_reconnect{feed} expose liveness; tests assert them through the
public Metrics hook, inject blips via a new memevents.Flaky decorator
(real channel severing, no mocks), and bounce a real embedded
JetStream server in vianats.

https://claude.ai/code/session_01HUMecXGMK1WbJAf62r8AKT
The reconnect manager listened for document-level
datastar-patch-elements/-signals events, but the bundled Datastar
never dispatches those — incoming patches surface only as
datastar-fetch CustomEvents with the patch kind in detail.type, and a
resumed SSE stream emits no started/finished. After an outage the
stream provably resumed yet the banner stayed stuck on Reconnecting
forever, and its full-width overlay swallowed clicks.

Found by the new vtbrowser harness on its first real run; the
milestone test now asserts the banner clears passively, with no user
interaction after connectivity returns.

https://claude.ai/code/session_01HUMecXGMK1WbJAf62r8AKT
mw.CSP() emitted script-src without 'unsafe-eval', but the bundled
Datastar runtime compiles every data-* expression and event handler
with Function(), which CSP gates behind that keyword — the recommended
security middleware made every click throw EvalError, and the docs
were silent. The default policy now carries 'unsafe-eval' (authorizing
eval only inside already-admitted same-origin/nonce script; inline
injection stays nonce-gated) plus frame-ancestors 'self'.

The claim is executable: TestBrowser_clickFiresUnderDefaultCSPPolicy
clicks under the default policy in a real headless Chrome and asserts
zero console errors. Troubleshooting gains the EvalError entry;
production.md states the policy and why, with a proof marker.

https://claude.ai/code/session_01HUMecXGMK1WbJAf62r8AKT
ineffassign (dead attempt=0 reset, overwritten on the disconnect path),
staticcheck S1017 (TrimPrefix), unused pinnedVersion const, and
paralleltest on the three transport-mutating registration tests
(nolint with reason — they intentionally cannot run parallel).
@joaomdsg
joaomdsg marked this pull request as ready for review June 12, 2026 09:01
@joaomdsg
joaomdsg merged commit 6bad13d into main Jun 12, 2026
7 checks passed
@joaomdsg
joaomdsg deleted the claude/inspiring-cori-iw8qkb branch June 12, 2026 09:04
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.

2 participants