Verify staged lazy loading and record Phase 3 measurements

This commit is contained in:
Jonathan Sykes
2026-10-08 04:19:02 +08:00
parent fab444b7b8
commit b84050578b
12 changed files with 5462 additions and 46 deletions

View File

@@ -1,43 +1,29 @@
# Phase 3 — decision required before live module replacement
# Phase 3 staged apply — accepted owner decision
COMMON.md says: "If you hit a decision that changes user-visible behaviour or
risks data loss that the documents do not answer, write QUESTION ... and end your
turn instead." This concerns §2c.5's instruction to switch stale modules when
new bytes arrive, after a new build has booted using a same-contract fallback.
The owner accepted this decision on 2026-10-08. It refines master §2c.5:
background downloading never implies that an executing classic script can be
safely replaced.
Concrete finding: direct-media.js creates private rooms, pending, transfers and
waiting maps at module evaluation (lines 4–6). Its public API has no busy,
dispose or state handoff method. Re-evaluation replaces window.DirectMedia,
while WebRTC callbacks/workers still close over the old maps. Later messages
routed by app.js through the new DirectMedia.handle can no longer find those
in-flight transfers. p2p-client.js similarly replaces its public singleton but
retains old sockets, timers and its visibility listener; P2PTransfer exposes
start/download without disposal. Matching contract numbers do not establish
safe runtime state migration. Piano/MIDI/floating-window UI also retains closures.
1. Already executing groups stay pinned until the session ends or the next
user-initiated, playback-guarded reload. P2P/direct and every stateful instance
are never re-evaluated live. Phase 4 must provide disposal and state handoff
before live replacement is allowed.
2. A group that has not executed can immediately use newer verified cached URLs
only when its contract and dependency contracts equal those expected by the
running core's embedded manifest. For a different contract, keep the running
build's N-1 URLs, set `Lazy.reloadRequired`, and request the existing Refresh UI
banner through the unchanged meta-build versus `/api/version` comparison.
3. New core boot may receive a verified N-1 response for an uncached new URL only
when group contracts match. The response retains its actual hash; it is never
stored under the new hash. Contract changes join the blocking download set.
Recommended owner decision: background-download and verify the new URLs
immediately, but pin an already-executing stale module until its feature session
closes and can be safely recreated. Keep P2P/direct instances until the next
explicit user-initiated, playback-guarded page reload. Groups never executed use
the newest cached version immediately. In Phase 4, introduce explicit teardown
and state handoff seams before enabling live replacement of these instances.
This narrows "switch when the new one arrives" for stateful modules; it requires
owner approval rather than silently claiming that caching new bytes replaces
running code.
Reason: direct-media.js owns private room, pending transfer and waiting maps;
WebRTC callbacks retain these closures. Re-evaluating the singleton redirects
messages away from those transfers. P2P sockets/timers and piano/MIDI/floating
windows have similar state. Contract equality alone does not migrate it.
Completed safe prerequisites: plan commit 895f20a; pure contract fallback and
background-group synchronization commit f804a23; ordered build-local loader with
unit tests (not yet wired into index.html). No layout or feature was removed
from the current eager path. Full browser/layout/performance acceptance remains
outstanding. This is a QUESTION checkpoint, not a completed phase report.
## Accepted owner decision
The owner accepted pinning on 2026-10-08. Already executing stale groups remain
pinned until their session ends or the next explicit playback-guarded reload.
P2P/direct and other stateful instances are never re-evaluated live; Phase 4 must
add disposal/state handoff before permitting replacement. An unexecuted group
may use newly cached URLs only when its contract equals the running core's
embedded contract. A different contract keeps the running build's N-1 URLs,
marks reload required and prompts the existing build-tag-based Refresh UI banner.
Unit tests cover all three cases. Continue Phase 3 under these rules.
Implemented in 4853c2c and 5d6a154. Node loader tests cover pinned execution,
compatible unexecuted selection, incompatible N-1 plus reload-required, and
incompatible dependencies. Worker tests cover same-contract fallback without
cache poisoning and changed-contract readiness before commit. `perf/lazy.mjs`
checks these decisions with real workers on Chromium and WebKit.