Uh oh!
There was an error while loading. Please reload this page.
[codepress#5858 3a-0] EditorHost.subscribe - #15
Conversation
The published EditorHost was pull-only, so the only way to push an agent's or another user's revision into a mounted editor was to swap the host prop — a full remount. Add an optional subscribe port: the surface wires it to the runtime controller's replaceAuthoritativeSnapshot, the same path a submitted edit's result takes, and returns the unsubscribe from the mount effect's cleanup.
lightninglu10
commented
Aug 22, 2026
Canonical QA ReportVerifier revision bindingbase: 47e2db3 (origin/staging) Gate results
Inherited baseline failures
Environment blockers
Visual / browser artifacts
Overall✅ PASS — PENDING JUDGE (gates 4, 10 and 11 fail identically at base No merge until trusted judge PASS. |
lightninglu10
commented
Aug 22, 2026
@codepress /judge-verification can you judge this verification? |
👋 Hey @lightninglu10! Spawning a verification judge session to help with your request. View session |
Dispatched by judge-verification. Work the Path to merge below. Reuse healthy exact-head verification environments; do not redeploy or restart unless stale or unhealthy. Continue only when there is meaningful work to clear the blocker. If the path is already satisfied, the same blocker remains, or another judge pass would add no useful evidence, stop and report that instead of submitting another verification report. Verification Judgment — PR #15 (staging)Verdict: ❌ NOT READY TO MERGE PR Head SHA: Summary: The supplied report is missing. The linked PR comment contains only a request to start judging and no canonical report head, verification marker, or evidence rows. Safety of the live head therefore cannot be established; the verification report must be reposted and rerun for this exact head. Revision binding
Diff trigger inventory
Per-item
Overall status check
Path to merge
Becomes Dispatch: yes What stood up
|
lightninglu10
commented
Aug 22, 2026
@codepress /judge-verification can you judge this verification? Local Verification — PR #15 (FreeCut, base |
| Surface | Location | Row |
|---|---|---|
Public optional EditorHost.subscribe contract | src/features/editor/host/contract.ts:302; packages/freecut-editor/src/index.d.ts:343 | 1 |
| Out-of-band snapshot delivery into the mounted editor and stores | src/features/editor/host/editor-surface.tsx:39-49; controller.ts:456-462; runtime.ts:116-119 | 2 |
Backward-compatible host without subscribe | src/features/editor/host/editor-surface.tsx:46 | 3 |
| Subscription cleanup on teardown and host replacement | src/features/editor/host/editor-surface.tsx:34-59 | 4 |
| Published version, copied declaration, installed-consumer surface | packages/freecut-editor/package.json:3; vite.editor-package.config.ts:84-87 | 5 |
How rows 1–4 were exercised
All four rows were exercised against the real published artifact, not the repo source: npm run package:editor-surface produced artifacts/freecut-editor-surface-0.3.3.tgz (sha256 9f0e3da0b32f4fae67b6d3d6004b06f8c89a42bbe082b0e161535fa02194cdd7, reproduced byte-identical on two independent runs), which was installed with npm install --ignore-scripts --no-package-lock --no-save <tgz> into a fresh fixture. The probe renders the real FreeCutEditorSurface → real LoadedEditor tree → real EmbeddedEditorHostRuntime → real zustand stores. Nothing inside the package is mocked or stubbed; the only test doubles are the EditorHost implementations, which are the caller-supplied port the contract exists for.
Negative control (anti-vacuity). The identical probe file and the identical TypeScript consumer file were run a second time against a tarball built from the base commit 47e2db3c (freecut-editor-surface-0.3.2.tgz, sha256 f8c185d25065a0827302661af4011aef43e83de9d8de301b4c94886bfc87764d). Rows 2/4a/4b fail there and row 3 still passes — so the probes detect exactly this PR's behavior and are not passing vacuously.
Behavioral contract results
| # | Effect that must be observed | Required evidence | Result | How it was observed |
|---|---|---|---|---|
| 1 | Source contract and published declaration expose the same optionalsubscribe, and the declaration is load-bearing for consumers | installed-artifact typecheck | ✅ PASS | Byte-identical signature at three layers: src/features/editor/host/contract.ts:302, packages/freecut-editor/src/index.d.ts:343, and the installednode_modules/@quantfive/freecut-editor-surface/dist/index.d.ts:343 — all subscribe?(listener: (snapshot: EmbeddedEditorSnapshot) => void): () => void. Real tsc@7.0.2 --strict --noEmit against the installed declaration: a host withoutsubscribe and a host with it both compile (exit=0), and the call site must be defensive (subscribe?.(...)). Load-bearing, not any: a subscribe returning void → TS2322: Type 'void' is not assignable to type '() => void' (exit=1); a listener typed (snapshot: string) → TS2345: Type 'EmbeddedEditorSnapshot' is not assignable to type 'string' (exit=1). Base control: the same positive file against installed 0.3.2 → TS2353: 'subscribe' does not exist in type 'EditorHost' (exit=1) |
| 2 | A snapshot pushed through subscribe reaches the mounted editor and stores with no remount and no extra load() | live execution against installed package | ✅ PASS | Probe ROW 2: mounted the real editor tree from installed 0.3.3, captured the [data-freecut-editor-surface="host"] node, pushed revision 7 carrying a text item PUSHED_BY_AGENT_MARKER. Observed: same surface node = true (identical DOM node instance → never torn down), load calls = 1, subscribe calls = 1, rendered marker nodes = 1 — the pushed item is rendered by the real timeline tree, having gone through replaceAuthoritativeSnapshot → controller listener → applySnapshotToStores. The marker was asserted absent before the push. Base control: fails (subscribe never called) |
| 3 | An existing host that omits subscribe still mounts the full editor unchanged | live execution against installed package | ✅ PASS | Probe ROW 3: asserted 'subscribe' in host === false and host.subscribe === undefined, then mounted from installed 0.3.3 → full tree renders (≥2 toolbars, Preview area region, Timeline, properties-clip-panel-host), load calls = 1, and unmount runs the cleanup path without throwing. Base control: also passes (correct — this is the pre-existing behavior this PR must not regress) |
| 4 | The returned unsubscribe runs on unmount and on host replacement, leaving no stale listener able to deliver | live execution against installed package | ✅ PASS | Probe ROW 4a (unmount): unsubscribe calls after unmount = 1, listeners = 0. Probe ROW 4b (host replacement): after rerender with a second host — old-host unsubscribes = 1, old listeners = 0, new listeners = 1, new host subscribe called exactly once; a stale push through the replaced host reached nobody (marker asserted absent) while a push through the live host rendered. Base control: both fail |
| 5 | The 0.3.3 package builds, the declaration is copied, and the tarball is consumable as an installed dependency | packaged + installed consumer run | ✅ PASS | npm run package:editor-surface → version 0.3.3, sha256 9f0e3da0…94cdd7, identical across two runs (deterministic). npm run test:editor-surface:consumer -- --artifact artifacts/freecut-editor-surface-0.3.3.tgz → fresh temp fixture, verifyInstalledPackage name+version assertions pass, Test Files 1 passed (1) / Tests 1 passed (1), "installed and tested @quantfive/freecut-editor-surface@0.3.3". The independent probe fixture separately confirmed installed version 0.3.3 and the copied dist/index.d.ts |
Probe run (installed 0.3.3): Test Files 1 passed (1) / Tests 4 passed (4).
Negative control (installed 0.3.2 from base): Test Files 1 failed (1) / Tests 3 failed | 1 passed (4) — failing exactly rows 2, 4a, 4b.
Committed in-repo focused tests at this head: vp test run src/features/editor/host/editor-surface.test.tsx → Tests 3 passed (3) (no-subscribe mount; pushed snapshot without remount; unsubscribe on unmount).
Repo gate set (FreeCut docs/qa gates 1–20, unchanged head)
17 of 20 gates plus the publish guards pass; full evidence table in comment 5381952676. Three gates fail identically at base 47e2db3c and are disclosed there, reproduced at the base SHA in a separate clean worktree, with no allowlist, skip list, or config edited:
- Gate 4 unit tests: base 45 failed files / 584 failed tests; head 45 failed files / 584 failed tests. Head passes 4280 vs base 4278 — the delta is exactly the two tests this PR adds. Cause: jsdom opaque origin leaves
localStorageundefined, which the zustand persist middleware captures at import time. - Gate 10 unused exports: "129 findings, 119 allowlisted, 10 new, 3 stale" — identical at base and head; none of the 10 is in a file this PR touches.
- Gate 11 unused class members: "83 findings, 83 allowlisted, 0 new, 2 stale" — identical at base and head.
Scope note
applySnapshotToStores still resets playhead/undo when an authoritative snapshot is adopted. That is pre-existing behavior on the receiving path, explicitly out of scope for this item, and unchanged here — it is a known limitation, not a regression introduced by this PR.
Overall: ✅ PASS — PENDING JUDGE
Rows 1–5 are each covered by live execution against the installed published artifact, each with a base-commit negative control. Head unchanged at aca961335d9856fe6e5059950646f6ca0bbf9d2a. PR remains DRAFT.
👋 Hey @lightninglu10! Spawning a verification judge session to help with your request. View session |
lightninglu10
commented
Aug 22, 2026
@codepress /judge-verification can you judge this verification? Local Verification — FreeCut PR #15 (base |
| Surface | Location | Row |
|---|---|---|
Public optional EditorHost.subscribe contract | src/features/editor/host/contract.ts:302; packages/freecut-editor/src/index.d.ts:343 | 1 |
| Out-of-band snapshot delivery into the mounted editor and stores | src/features/editor/host/editor-surface.tsx:39-49; controller.ts:456-462; runtime.ts:116-119 | 2 |
Backward-compatible host without subscribe | src/features/editor/host/editor-surface.tsx:46 | 3 |
| Subscription cleanup on teardown and host replacement | src/features/editor/host/editor-surface.tsx:34-59 | 4 |
| Published version, copied declaration, installed-consumer surface | packages/freecut-editor/package.json:3; vite.editor-package.config.ts:84-87 | 5 |
How rows 1-4 were exercised
All four rows were exercised against the real published artifact, not the repo source. npm run package:editor-surface produced artifacts/freecut-editor-surface-0.3.3.tgz (sha256 9f0e3da0b32f4fae67b6d3d6004b06f8c89a42bbe082b0e161535fa02194cdd7, reproduced byte-identical on two independent runs), which was installed with npm install --ignore-scripts --no-package-lock --no-save <tgz> into a fresh fixture. The probe renders the real FreeCutEditorSurface -> real LoadedEditor tree -> real EmbeddedEditorHostRuntime -> real zustand stores. Nothing inside the package is mocked or stubbed; the only test doubles are the EditorHost implementations, which are the caller-supplied port the contract exists for.
Negative control (anti-vacuity). The identical probe file and the identical TypeScript consumer file were run a second time against a tarball built from the base commit 47e2db3c (freecut-editor-surface-0.3.2.tgz, sha256 f8c185d25065a0827302661af4011aef43e83de9d8de301b4c94886bfc87764d). Rows 2/4a/4b fail there and row 3 still passes, so the probes detect exactly this PR's behavior and are not passing vacuously.
Verification Contract Results
| # | Effect that must be observed | Required evidence | Result | How it was observed |
|---|---|---|---|---|
| 1 | Source contract and published declaration expose the same optionalsubscribe, and the declaration is load-bearing for consumers | installed-artifact typecheck | ✅ PASS | Byte-identical signature at three layers: src/features/editor/host/contract.ts:302, packages/freecut-editor/src/index.d.ts:343, and the installednode_modules/@quantfive/freecut-editor-surface/dist/index.d.ts:343 — all subscribe?(listener: (snapshot: EmbeddedEditorSnapshot) => void): () => void. Real tsc@7.0.2 --strict --noEmit against the installed declaration: a host withoutsubscribe and a host with it both compile (exit=0), and the call site must be defensive (subscribe?.(...)). Load-bearing, not any: a subscribe returning void -> TS2322: Type 'void' is not assignable to type '() => void' (exit=1); a listener typed (snapshot: string) -> TS2345: Type 'EmbeddedEditorSnapshot' is not assignable to type 'string' (exit=1). Base control: the same positive file against installed 0.3.2 -> TS2353: 'subscribe' does not exist in type 'EditorHost' (exit=1) |
| 2 | A snapshot pushed through subscribe reaches the mounted editor and stores with no remount and no extra load() | live execution against installed package | ✅ PASS | Probe ROW 2: mounted the real editor tree from installed 0.3.3, captured the [data-freecut-editor-surface="host"] node, pushed revision 7 carrying a text item PUSHED_BY_AGENT_MARKER. Observed same surface node = true (identical DOM node instance, so never torn down), load calls = 1, subscribe calls = 1, rendered marker nodes = 1 — the pushed item is rendered by the real timeline tree, having gone through replaceAuthoritativeSnapshot -> controller listener -> applySnapshotToStores. The marker was asserted absent before the push. Base control: fails, subscribe never called |
| 3 | An existing host that omits subscribe still mounts the full editor unchanged | live execution against installed package | ✅ PASS | Probe ROW 3: asserted 'subscribe' in host === false and host.subscribe === undefined, then mounted from installed 0.3.3 -> full tree renders (at least 2 toolbars, Preview area region, Timeline, properties-clip-panel-host), load calls = 1, and unmount runs the cleanup path without throwing. Base control: also passes, which is correct — this is the pre-existing behavior this PR must not regress |
| 4 | The returned unsubscribe runs on unmount and on host replacement, leaving no stale listener able to deliver | live execution against installed package | ✅ PASS | Probe ROW 4a (unmount): unsubscribe calls after unmount = 1, listeners = 0. Probe ROW 4b (host replacement): after rerender with a second host — old-host unsubscribes = 1, old listeners = 0, new listeners = 1, new host subscribe called exactly once; a stale push through the replaced host reached nobody (marker asserted absent) while a push through the live host rendered. Base control: both fail |
| 5 | The 0.3.3 package builds, the declaration is copied, and the tarball is consumable as an installed dependency | packaged plus installed consumer run | ✅ PASS | npm run package:editor-surface -> version 0.3.3, sha256 9f0e3da0...94cdd7, identical across two runs (deterministic). npm run test:editor-surface:consumer -- --artifact artifacts/freecut-editor-surface-0.3.3.tgz -> fresh temp fixture, verifyInstalledPackage name and version assertions pass, Test Files 1 passed (1) / Tests 1 passed (1), "installed and tested @quantfive/freecut-editor-surface@0.3.3". The independent probe fixture separately confirmed installed version 0.3.3 and the copied dist/index.d.ts |
Probe run (installed 0.3.3): Test Files 1 passed (1) / Tests 4 passed (4).
Negative control (installed 0.3.2 from base): Test Files 1 failed (1) / Tests 3 failed | 1 passed (4) — failing exactly rows 2, 4a, 4b.
Committed in-repo focused tests at this head: vp test run src/features/editor/host/editor-surface.test.tsx -> Tests 3 passed (3) (no-subscribe mount; pushed snapshot without remount; unsubscribe on unmount).
Repo gate set (FreeCut docs/qa gates 1-20, unchanged head)
17 of 20 gates plus the publish guards pass; the full evidence table is in comment 5381952676. Three gates fail identically at base 47e2db3c, reproduced at the base SHA in a separate clean worktree, with no allowlist, skip list, or config edited:
- Gate 4 unit tests: base 45 failed files / 584 failed tests; head 45 failed files / 584 failed tests. Head passes 4280 vs base 4278 — the delta is exactly the two tests this PR adds. Cause: jsdom opaque origin leaves
localStorageundefined, which the zustand persist middleware captures at import time. - Gate 10 unused exports: "129 findings, 119 allowlisted, 10 new, 3 stale" — identical at base and head; none of the 10 is in a file this PR touches.
- Gate 11 unused class members: "83 findings, 83 allowlisted, 0 new, 2 stale" — identical at base and head.
Scope and disclosure
applySnapshotToStores still resets playhead/undo when an authoritative snapshot is adopted. That is pre-existing behavior on the receiving path, explicitly out of scope for this item, and unchanged here — a known limitation, not a regression introduced by this PR.
Rows 3 and 4b are evidenced by an ad-hoc probe held outside the repo, because the dispatch required the head to stay unchanged. If those branches should be covered by tests that live in the PR, that requires a new commit and can be added on request.
Overall: ✅ PASS — PENDING JUDGE
👋 Hey @lightninglu10! Spawning a verification judge session to help with your request. View session |
Dispatched by judge-verification. This judgment is READY TO MERGE at the current head. If the PR is still a draft, transition it to ready for review now with the guarded readiness transaction: Verification Judgment — PR #15 (local)Verdict: ✅ READY TO MERGE PR Head SHA: Summary: The current PR head is safe to merge based on the diff and the exact-head verification evidence. The optional host subscription contract is wired into the mounted editor's existing authoritative-snapshot path, backward compatibility is preserved, teardown and host replacement remove listeners, and the published package surface is covered. Revision binding
Diff trigger inventory
Per-item
Overall status check
What stood up
|
Review of |
#15 publishes 0.3.3 when it merges, and the OIDC publish workflow's already-published guard refuses a second publish at the same version. This PR therefore has to carry its own version for its surface changes (the ripple_delete capability, the transcript cut action, and the optional requestTranscription port) to reach the registry.
Dispatched by judge-verification. This judgment is READY TO MERGE at the current head. If the PR is still a draft, transition it to ready for review now with the guarded readiness transaction: Verification Judgment — PR #15 (local)Verdict: ✅ READY TO MERGE PR Head SHA: Summary: The current PR head is safe to merge based on the audited diff and exact-head verification evidence. The optional host subscription is wired into the existing authoritative-snapshot path, hosts without the optional method remain supported, cleanup covers unmount and host replacement, and the published package surface is covered. Revision binding
Diff trigger inventory
Per-item
Overall status check
What stood up
|
Starting initial review of |
There was a problem hiding this comment.
Approved.
The change is the right shape: it extends the existing host boundary with an optional push channel and routes updates through the established authoritative-snapshot controller. The source and published declarations match, and the effect cleanup correctly owns the host listener lifecycle.
One nonblocking follow-up is worth addressing: a host that emits during subscribe (or immediately after it is registered) can update the controller before the runtime's mountStores() listener exists. The runtime then mounts from its original snapshot and drops that early revision. Have the runtime read the controller's current snapshot when mounting, or establish the runtime listener before registering the host callback, and cover an immediately-emitting host in a regression test.
Review head |
Uh oh!
There was an error while loading. Please reload this page.
Item 3a-0 of https://github.com/quantfive/codepress/issues/5858 ("Video editor v1: ship the editor and connect it to the CodePress agent").
Why
The published
EditorHostis pull-only (capabilities, load, resolveMedia, submitEdit, transcript?, navigation?, notify?).HostEditorController.replaceAuthoritativeSnapshot()is the right entry point for an out-of-band revision andEmbeddedEditorHostRuntimealready subscribes to it, but nothing on the public contract reaches it. So the only way a host could push an agent's (or another user's) revision into a mounted editor was to swap thehostprop — a full remount that resets the playhead, clears undo, and rebuilds the media library.This is the prerequisite for the in-editor agent loop in CodePress (#5858 item 2c).
What
EditorHostgains an optionalsubscribe?(listener: (snapshot: EmbeddedEditorSnapshot) => void): () => void.FreeCutEditorSurfacewires it to the runtime's controller right after constructing the runtime, and returns the unsubscribe from the mount effect's cleanup. A pushed snapshot travels the existing receiving path — the same one asubmitEditresult takes.packages/freecut-editor/src/index.d.ts(hand-written, copied verbatim intodist) declares the same optional method;@quantfive/freecut-editor-surfacebumps to 0.3.3.subscribelands in the timeline stores with the same DOM node and a singleload()(no remount), and the listener is dropped on unmount.applySnapshotToStoresis unchanged — it still resets playhead/undo on an authoritative snapshot. Known and accepted for now; out of scope here.Publishing 0.3.3 to npm is not part of this PR — a maintainer publishes after merge.