Conversation
wagenet
force-pushed
the
wagenet/ws-macro-pip-take
branch
from
August 28, 2026 00:26
cc5eac8 to
d31aec5
Compare
The WS controller has no test coverage — `activation.test.ts` and `macros.test.ts` both mock `../ws/controller.js` out entirely — so there is nowhere to assert what a macro action sends to Strom or broadcasts to subscribers. Adds that harness: `handleMessage` driven directly with CouchDB and StromClient mocked, asserting the Strom call sequence and the broadcast payloads. State is established through real inbound messages rather than by reaching into the module-level maps, so each case exercises the same state machine the server runs in production. One case here, a macro CUT with no PiP anywhere, which pins the behaviour the PiP work must leave untouched. Cases that require a behaviour change to pass belong with the commits that make them pass. `handleMessage` is exported for this and is the only production change; the plugin exposes just a websocket route, so there was no other seam. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uhnqt88WrXHGV7VF4D65x3
The CUT and TRANSITION handlers each do four things when a real source replaces a PiP that is on program: resolve `from_input` from `pgmBgByProduction`, move the PiP from PGM to PVW, broadcast `PIP_STATE`, and call `selectPreview` so the PiP lands back in Strom's preview. The same three actions executed from a macro do none of it. `MACRO_EXEC` updates `tally` and calls `stromTransition` directly, so with a PiP on program the PiP is never returned to preview, `pgmPipByProduction` and `pgmBgByProduction` keep their old values, and no `PIP_STATE` is emitted — leaving both the server and every subscriber believing a PiP is on program long after it left. The `selectPreview` omission is the one that reaches the mixer. Strom's `trigger_transition` reads the authoritative PGM/PVW source from the block's overlay state, which `selectPreview` is what sets. Without the restore, preview holds the cut target that `stromTransition` selected rather than the displaced PiP, so the operator's next take airs the wrong source. The frame airing at the moment the macro runs is unaffected: the cut target comes from `stromTransition`'s own `selectPreview`, which is untouched here. Passing `fromPad` instead of `tally.pgm` is included for consistency with the interactive handlers, not as a fix. Strom ignores the request's `from_input`/`to_input` whenever overlay state exists, falling back to them only when it is missing entirely. Mirrors the interactive logic into the three macro actions. The displacement block is inlined rather than extracted so each macro path can be diffed against the handler it copies; the interactive handlers are left untouched. Adds the two harness cases this makes pass — a macro CUT and a macro TRANSITION over a PiP on program. Both fail without the change. A PiP sitting in *preview* is still not promoted to program by a macro TAKE — that needs the full TAKE path, which tracks `pvwBeforePipByProduction` and runs its own Strom sequence. This commit only covers displacing a PiP that is already on program. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uhnqt88WrXHGV7VF4D65x3
A macro TAKE never promoted a PiP sitting in preview, and the failure was
silent. `SELECT_PVW_PIP` leaves `tally.pvw` null, so the swap produced
`{ pgm: null, pvw: <old pgm> }`, which was broadcast as-is and then passed to
`stromTransition` as `toMixerInput` — where it early-returns on the null.
The result: every subscriber is told the program bus is empty, Strom is never
called at all and keeps airing the previous source, and `pgmPipByProduction`
is never set, so the server does not know the PiP took either.
Restructures the macro TAKE to mirror the interactive handler's three
branches — PiP moving PVW to PGM, PiP moving PGM to PVW, and no PiP — instead
of the single displacement path that only covered the second. The pip maps
are swapped as a pair (`newPgmPip = curPvwPip`, `newPvwPip = curPgmPip`)
rather than cleared, and `PIP_STATE` is emitted unconditionally, matching the
interactive TAKE.
The forward branch reuses `pvwBeforePipByProduction` as `to_input` and records
it as the new `pgmBg`, so a later CUT or TRANSITION while the PiP is on
program has a background to report and Strom keeps `pgm_input ≠ pvw_input`.
Adds the harness case this makes pass. It asserts that Strom is called at all
on this path, which is what the previous behaviour got wrong.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uhnqt88WrXHGV7VF4D65x3
wagenet
force-pushed
the
wagenet/ws-macro-pip-take
branch
from
August 28, 2026 00:35
d31aec5 to
69dbdd7
Compare
Contributor
|
This PR is part of a multi-PR dependency stack (the WS macro / PiP fixes), in dependency order:
Holding off on automated review/merge here — both open PRs are drafts and each still carries the other's commits until the one below it merges, so they need a human (or the relevant dev agent) to assess the stack as a whole, not a per-PR pass. Nothing further is needed from the author; this comment records the dependency on the PR itself rather than only in a run log. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Top of a three-PR stack: #182 (harness) → #179 (displace a PGM PiP) → this. The diff contains all three commits until those merge — only the third,
fix(ws): take a preview PiP to program from a macro, belongs to this PR.Problem
A macro TAKE never promotes a PiP sitting in preview, and the failure is silent rather than merely stale.
SELECT_PVW_PIPsetsnewTally = { pgm: tally.pgm, pvw: null }, sotally.pvwis null whenever a PiP is in preview. The macro TAKE then does:So every subscriber is told the program bus went empty, Strom is never called and keeps airing the previous source, and
pgmPipByProductionis never set — the server does not know the PiP took either. The operator sees a macro that appears to do nothing while the tally says the show went black.Fix
Restructures the macro TAKE to mirror the interactive handler's three branches — PiP moving PVW→PGM, PiP moving PGM→PVW, and no PiP — instead of the single displacement path that only covered the second.
The pip maps are now swapped as a pair (
newPgmPip = curPvwPip,newPvwPip = curPgmPip) rather than cleared, andPIP_STATEis emitted unconditionally, both matching the interactive TAKE.The forward branch reuses
pvwBeforePipByProductionasto_inputand records it as the newpgmBg, so a later CUT or TRANSITION while the PiP is on program has a background to report and Strom keepspgm_input ≠ pvw_input.Impact
The
selectPreview({ source: { pip: N } })andtransitionpair in the forward branch is what reaches the mixer — previously no Strom call was made at all on this path.trigger_transitionreads the authoritative PGM/PVW source from overlay state (gst/pipeline/effects/take.rs), whichselectPreviewis what sets.As in #179, the
from_input/to_inputvalues are carried for consistency with the interactive handler rather than as a fix; Strom reads them only when overlay state is missing.With no PiP on either bus, the new
elsebranch is the previous behaviour unchanged.Conflicts with #156
Same five hunks as #179 — three in
src/ws/controller.ts, two insrc/__tests__/ws-macro-pip.test.ts— since this PR carries #179's commit until that merges. Mechanical, and I will rebase whichever lands second.Testing
Ships with the harness case it makes pass. That case asserts Strom is called at all on this path, which is precisely what the previous behaviour got wrong — it fails against #179 and passes here.
npx vitest run src/__tests__/ws-macro-pip.test.ts— 4 passed.npx tsc --noEmitclean.npx vitest run— the suite's 27 pre-existing failures inactivation.test.tsandmacros.test.tsare unchanged and present onmaintoo.selectPreview({pip:N})rests on readingflows.rsandmixer_ops.rsrather than on execution.