BENCH-RITUAL-COLOR-001 — Color Preset cues in one Virtual Playback exclusion zone keep exactly one colour on the rig and fall back to its resting colour
tests/113-semantic-exclusive-color-playbacks.spec.ts:58 · migrated-semantic-world · last run: not merged
show: EmptyBrowser UICue timingDMX outputDesktop layoutEncoder controlsGroupsPlaybacksPresetsProgrammerProgrammer timingRecordingSelectionShow PatchShow filesTest clockTyped APIVirtual Playbacks
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.Empty show.t.show.use(Show.Empty)
| 62 |
Open the ToskLight browser application.t.app.open()
| 63 |
The ToskLight browser application is ready.t.app.expect.ready()
| 64 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 65 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 66 |
| Step | Patch → api → add with {
number: 1,
name: "Sunstrip",
address: "1.1",
<unresolved: ...SUNSTRIP>
}t.patch.via.api.add({ number: 1, name: "Sunstrip", address: "1.1", ...SUNSTRIP })
| 68 |
| Step | Patch → api → add with {
number: 2,
name: "PAR L",
address: "1.41",
<unresolved: ...PAR>
}t.patch.via.api.add({ number: 2, name: "PAR L", address: "1.41", ...PAR })
| 69 |
| Step | Patch → api → add with {
number: 3,
name: "PAR R",
address: "1.46",
<unresolved: ...PAR>
}t.patch.via.api.add({ number: 3, name: "PAR R", address: "1.46", ...PAR })
| 70 |
| Step | Patch → api → add with {
number: 4,
name: "Wash",
address: "1.61",
<unresolved: ...WASH_MOVER>
}t.patch.via.api.add({ number: 4, name: "Wash", address: "1.61", ...WASH_MOVER })
| 71 |
| Step | Selection → fixtures → api → items with 1, 2, 3, 4. t.selection.fixtures.via.api.items(1, 2, 3, 4)
| 72 |
| Step | Group → api → store with 1, {
mode: StoreMode.Overwrite
}t.group.via.api.store(1, { mode: StoreMode.Overwrite })
| 73 |
| Step | Clear the current selection. t.selection.clear()
| 74 |
| Step | Group → api → select with 1. t.group.via.api.select(1)
| 78 |
| Step | Encoder → color → red → api → set with <unresolved: color.red>. t.encoder.color.red.via.api.set(color.red)
| 79 |
| Step | Encoder → color → green → api → set with <unresolved: color.green>. t.encoder.color.green.via.api.set(color.green)
| 80 |
| Step | Encoder → color → blue → api → set with <unresolved: color.blue>. t.encoder.color.blue.via.api.set(color.blue)
| 81 |
| Step | Encoder → color → white → api → set with <unresolved: color.white>. t.encoder.color.white.via.api.set(color.white)
| 82 |
| Step | Preset → api → store with PresetFamily.Color, <unresolved: index + 1>, {
mode: "overwrite"
}t.preset.via.api.store(PresetFamily.Color, index + 1, {
mode: "overwrite",
})
| 83 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 86 |
| Step | Clear the current selection. t.selection.clear()
| 87 |
| Step | Group → api → select with 1. t.group.via.api.select(1)
| 92 |
| Step | Encoder → intensity → dimmer → api → set with 100. t.encoder.intensity.dimmer.via.api.set(100)
| 93 |
| Step | Preset → api → recall with PresetFamily.Color, <unresolved: index + 1>. t.preset.via.api.recall(PresetFamily.Color, index + 1)
| 94 |
| Step | Record → playback with <unresolved: 1 + index>. t.record.playback(1 + index)
| 95 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 96 |
| Step | Clear the current selection. t.selection.clear()
| 97 |
| Step | Playback → configure with $playback (result of record.playback), {
name: <unresolved: color.name>,
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name: color.name,
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty,
],
})
| 98 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 108 |
| Step | Desktop → configure with .desktop: Colour ritual t.desktop.configure("Colour ritual")
| 111 |
| Step | Add the PaneType.VirtualPlaybacks pane desktop.addPane(
PaneType.VirtualPlaybacks,
{ slug: "colour-ritual", column: 1, row: 1, width: 12, height: 10 },
{ rows: 1, columns: COLORS.length },
)
| 112 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 117 |
| Step | Virtual playback → assign source with $pane (result of desktopBuilder.addPane), <unresolved: color.name>, <unresolved: index + 1>. t.virtualPlayback.assignSource(pane, color.name, index + 1)
| 121 |
| Step | Virtual playback → create solo region with attached shift with $pane (result of desktopBuilder.addPane), zone = "Solo Region 1", cells = <unresolved: COLORS.map((_, index) => index + 1)>. t.virtualPlayback.createSoloRegionWithAttachedShift(pane, zone, cells)
| 126 |
| Expected | Virtual playback → zones: [
{
name: zone = "Solo Region 1",
members: <unresolved: cells.map((cell) => ({ page: 1, position: 400 + cell }))>
}
]t.virtualPlayback.expect.zones([
{ name: zone, members: cells.map((cell) => ({ page: 1, position: 400 + cell })) },
])
| 127 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), <unresolved: index + 1>. t.virtualPlayback.activate(pane, index + 1)
| 157 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 159 |
| Expected | fixture(1, 2) DMX equals <unresolved: rgb(color.rgb)>. t.expectFixtureDMX(fixture(1, 2), rgb(color.rgb))
| 144 |
| Expected | fixture(1, 11) DMX equals <unresolved: rgb(color.rgb)>. t.expectFixtureDMX(fixture(1, 11), rgb(color.rgb))
| 145 |
| Expected | fixture(2) DMX equals <unresolved: rgb(color.rgb)>. t.expectFixtureDMX(fixture(2), rgb(color.rgb))
| 146 |
| Expected | fixture(3) DMX equals <unresolved: rgb(color.rgb)>. t.expectFixtureDMX(fixture(3), rgb(color.rgb))
| 147 |
| Expected | fixture(4) DMX equals {
<unresolved: ...rgb("moverRgb" in color ? color.moverRgb : color.rgb)>,
"Color white": <unresolved: byte(color.moverWhite)>,
Intensity: 255
}t.expectFixtureDMX(fixture(4), {
...rgb("moverRgb" in color ? color.moverRgb : color.rgb),
"Color white": byte(color.moverWhite),
Intensity: 255,
})
| 148 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 2. t.virtualPlayback.activate(pane, 2)
| 163 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 165 |
| Expected | fixture(1, 2) DMX equals <unresolved: rgb(color.rgb)>. t.expectFixtureDMX(fixture(1, 2), rgb(color.rgb))
| 144 |
| Expected | fixture(1, 11) DMX equals <unresolved: rgb(color.rgb)>. t.expectFixtureDMX(fixture(1, 11), rgb(color.rgb))
| 145 |
| Expected | fixture(2) DMX equals <unresolved: rgb(color.rgb)>. t.expectFixtureDMX(fixture(2), rgb(color.rgb))
| 146 |
| Expected | fixture(3) DMX equals <unresolved: rgb(color.rgb)>. t.expectFixtureDMX(fixture(3), rgb(color.rgb))
| 147 |
| Expected | fixture(4) DMX equals {
<unresolved: ...rgb("moverRgb" in color ? color.moverRgb : color.rgb)>,
"Color white": <unresolved: byte(color.moverWhite)>,
Intensity: 255
}t.expectFixtureDMX(fixture(4), {
...rgb("moverRgb" in color ? color.moverRgb : color.rgb),
"Color white": byte(color.moverWhite),
Intensity: 255,
})
| 148 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 2. t.virtualPlayback.activate(pane, 2)
| 169 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 171 |
| Expected | fixture(1, 2) DMX equals resting = {
"Color red": 255,
"Color green": 255,
"Color blue": 255
}t.expectFixtureDMX(fixture(1, 2), resting)
| 173 |
| Expected | fixture(1, 11) DMX equals resting = {
"Color red": 255,
"Color green": 255,
"Color blue": 255
}t.expectFixtureDMX(fixture(1, 11), resting)
| 174 |
| Expected | fixture(2) DMX equals resting = {
"Color red": 255,
"Color green": 255,
"Color blue": 255
}t.expectFixtureDMX(fixture(2), resting)
| 175 |
| Expected | fixture(3) DMX equals resting = {
"Color red": 255,
"Color green": 255,
"Color blue": 255
}t.expectFixtureDMX(fixture(3), resting)
| 176 |
| Expected | fixture(4) DMX equals {
<unresolved: ...resting>,
"Color white": 255,
Intensity: 0
}t.expectFixtureDMX(fixture(4), {
...resting,
"Color white": 255,
Intensity: 0,
})
| 177 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Step | <unresolved: ...SUNSTRIP> Object member ...SUNSTRIP is not statically resolved. | 68 |
| unresolved-expression | Step | <unresolved: ...PAR> Object member ...PAR is not statically resolved. | 69 |
| unresolved-expression | Step | <unresolved: ...PAR> Object member ...PAR is not statically resolved. | 70 |
| unresolved-expression | Step | <unresolved: ...WASH_MOVER> Object member ...WASH_MOVER is not statically resolved. | 71 |
| static-control-flow | Source | Control flow for (const [index, color] of COLORS.entries()) { await t.group.via.api.select(1); await t.encoder.color.red.via.api.set(color.red); await t.encoder.color.green.via.api.set(color… is narrated once; iteration values are not guessed. | 77 |
| unresolved-expression | Step | <unresolved: color.red> Property access color.red depends on a runtime value. | 79 |
| unresolved-expression | Step | <unresolved: color.green> Property access color.green depends on a runtime value. | 80 |
| unresolved-expression | Step | <unresolved: color.blue> Property access color.blue depends on a runtime value. | 81 |
| unresolved-expression | Step | <unresolved: color.white> Property access color.white depends on a runtime value. | 82 |
| unresolved-expression | Step | <unresolved: index + 1> Expression index + 1 is not statically resolved. | 83 |
| static-control-flow | Source | Control flow for (const [index, color] of COLORS.entries()) { await t.group.via.api.select(1); await t.encoder.intensity.dimmer.via.api.set(100); await t.preset.via.api.recall(PresetFamily.C… is narrated once; iteration values are not guessed. | 91 |
| unresolved-expression | Step | <unresolved: index + 1> Expression index + 1 is not statically resolved. | 94 |
| unresolved-expression | Step | <unresolved: 1 + index> Expression 1 + index is not statically resolved. | 95 |
| unresolved-expression | Step | <unresolved: color.name> Property access color.name depends on a runtime value. | 99 |
| static-control-flow | Source | Control flow for (const [index, color] of COLORS.entries()) playbacks.push( await t.virtualPlayback.assignSource(pane, color.name, index + 1), ); is narrated once; iteration values are not guessed. | 119 |
| unresolved-expression | Step | <unresolved: color.name> Property access color.name depends on a runtime value. | 121 |
| unresolved-expression | Step | <unresolved: index + 1> Expression index + 1 is not statically resolved. | 121 |
| unresolved-expression | Step | <unresolved: COLORS.map((_, index) => index + 1)> Call expression COLORS.map((_, index) => index + 1) is dynamic and was not executed. | 123 |
| unresolved-expression | Expected outcome | <unresolved: cells.map((cell) => ({ page: 1, position: 400 + cell }))> Call expression cells.map((cell) => ({ page: 1, position: 400 + cell })) is dynamic and was not executed. | 128 |
| static-control-flow | Source | Control flow for (const [index, color] of COLORS.entries()) { await t.virtualPlayback.activate(pane, index + 1); await expectOnly(index); await t.clock.advanceStep(); await expectRig(color); } is narrated once; iteration values are not guessed. | 156 |
| unresolved-expression | Step | <unresolved: index + 1> Expression index + 1 is not statically resolved. | 157 |
| unresolved-expression | Expected outcome | <unresolved: rgb(color.rgb)> Call expression rgb(color.rgb) is dynamic and was not executed. | 144 |
| unresolved-expression | Expected outcome | <unresolved: rgb(color.rgb)> Call expression rgb(color.rgb) is dynamic and was not executed. | 145 |
| unresolved-expression | Expected outcome | <unresolved: rgb(color.rgb)> Call expression rgb(color.rgb) is dynamic and was not executed. | 146 |
| unresolved-expression | Expected outcome | <unresolved: rgb(color.rgb)> Call expression rgb(color.rgb) is dynamic and was not executed. | 147 |
| unresolved-expression | Expected outcome | <unresolved: ...rgb("moverRgb" in color ? color.moverRgb : color.rgb)> Object member ...rgb("moverRgb" in color ? color.moverRgb : color.rgb) is not statically resolved. | 149 |
| unresolved-expression | Expected outcome | <unresolved: byte(color.moverWhite)> Call expression byte(color.moverWhite) is dynamic and was not executed. | 150 |
| unresolved-expression | Expected outcome | <unresolved: rgb(color.rgb)> Call expression rgb(color.rgb) is dynamic and was not executed. | 144 |
| unresolved-expression | Expected outcome | <unresolved: rgb(color.rgb)> Call expression rgb(color.rgb) is dynamic and was not executed. | 145 |
| unresolved-expression | Expected outcome | <unresolved: rgb(color.rgb)> Call expression rgb(color.rgb) is dynamic and was not executed. | 146 |
| unresolved-expression | Expected outcome | <unresolved: rgb(color.rgb)> Call expression rgb(color.rgb) is dynamic and was not executed. | 147 |
| unresolved-expression | Expected outcome | <unresolved: ...rgb("moverRgb" in color ? color.moverRgb : color.rgb)> Object member ...rgb("moverRgb" in color ? color.moverRgb : color.rgb) is not statically resolved. | 149 |
| unresolved-expression | Expected outcome | <unresolved: byte(color.moverWhite)> Call expression byte(color.moverWhite) is dynamic and was not executed. | 150 |
| unresolved-expression | Expected outcome | <unresolved: ...resting> Object member ...resting is not statically resolved. | 178 |
BENCH-DYNAMIC-REUSE-001 — one targetless Dynamic applied to two mover Groups runs on each Group's own Virtual Playback and nowhere else
tests/114-semantic-dynamic-reuse-across-groups.spec.ts:39 · migrated-semantic-world · last run: not merged
show: EmptyBrowser UICue timingDMX outputDesktop layoutDynamicsEncoder controlsGroupsPlaybacksPresetsProgrammerProgrammer timingRecordingSelectionShow PatchShow filesTest clockTyped APIVirtual Playbacks
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.Empty show.t.show.use(Show.Empty)
| 43 |
Open the ToskLight browser application.t.app.open()
| 44 |
The ToskLight browser application is ready.t.app.expect.ready()
| 45 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 46 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 47 |
| Step | Patch → api → add with {
number: number = ...<unresolved: GROUP_ONE>,
name: "Mover number = ...<unresolved: GROUP_ONE>", address: "1.<unresolved: 1 + (number - 1) * 15>", location: { x: <unresolved: ((number - 1) % 4) * 1000>, y: <unresolved: number <= 4 ? 0 : 1000>, z: 0 }, <unresolved: ...MOVER> }t.patch.via.api.add({
number,
name: `Mover ${number}`,
address: `1.${1 + (number - 1) * 15}`,
location: {
x: ((number - 1) % 4) * 1000,
y: number <= 4 ? 0 : 1000,
z: 0,
},
...MOVER,
})
| 50 |
| Step | Patch → api → add with {
number: number = ...<unresolved: GROUP_TWO>,
name: "Mover number = ...<unresolved: GROUP_TWO>", address: "1.<unresolved: 1 + (number - 1) * 15>", location: { x: <unresolved: ((number - 1) % 4) * 1000>, y: <unresolved: number <= 4 ? 0 : 1000>, z: 0 }, <unresolved: ...MOVER> }t.patch.via.api.add({
number,
name: `Mover ${number}`,
address: `1.${1 + (number - 1) * 15}`,
location: {
x: ((number - 1) % 4) * 1000,
y: number <= 4 ? 0 : 1000,
z: 0,
},
...MOVER,
})
| 50 |
| Step | Selection → fixtures → api → items with ...<unresolved: GROUP_ONE>. t.selection.fixtures.via.api.items(...GROUP_ONE)
| 61 |
| Step | Group → api → store with 1, {
mode: StoreMode.Overwrite
}t.group.via.api.store(1, { mode: StoreMode.Overwrite })
| 62 |
| Step | Selection → fixtures → api → items with ...<unresolved: GROUP_TWO>. t.selection.fixtures.via.api.items(...GROUP_TWO)
| 63 |
| Step | Group → api → store with 2, {
mode: StoreMode.Overwrite
}t.group.via.api.store(2, { mode: StoreMode.Overwrite })
| 64 |
| Expected | Group → fixtures: 1, ...<unresolved: GROUP_ONE>. t.group.expect(1).fixtures(...GROUP_ONE)
| 65 |
| Expected | Group → fixtures: 2, ...<unresolved: GROUP_TWO>. t.group.expect(2).fixtures(...GROUP_TWO)
| 66 |
| Step | Selection → fixtures → api → items with ...<unresolved: GROUP_ONE>, ...<unresolved: GROUP_TWO>. t.selection.fixtures.via.api.items(...GROUP_ONE, ...GROUP_TWO)
| 73 |
| Step | Encoder → position → pan → api → set with <unresolved: position.pan>. t.encoder.position.pan.via.api.set(position.pan)
| 74 |
| Step | Encoder → position → tilt → api → set with <unresolved: position.tilt>. t.encoder.position.tilt.via.api.set(position.tilt)
| 75 |
| Step | Preset → api → store with PresetFamily.Position, number = 1, {
mode: "overwrite"
}t.preset.via.api.store(PresetFamily.Position, number, {
mode: "overwrite",
})
| 76 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 79 |
| Step | Selection → fixtures → api → items with ...<unresolved: GROUP_ONE>, ...<unresolved: GROUP_TWO>. t.selection.fixtures.via.api.items(...GROUP_ONE, ...GROUP_TWO)
| 73 |
| Step | Encoder → position → pan → api → set with <unresolved: position.pan>. t.encoder.position.pan.via.api.set(position.pan)
| 74 |
| Step | Encoder → position → tilt → api → set with <unresolved: position.tilt>. t.encoder.position.tilt.via.api.set(position.tilt)
| 75 |
| Step | Preset → api → store with PresetFamily.Position, number = 2, {
mode: "overwrite"
}t.preset.via.api.store(PresetFamily.Position, number, {
mode: "overwrite",
})
| 76 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 79 |
| Step | Clear the current selection. t.selection.clear()
| 81 |
| Step | Dynamic → create with { pool: 1, name: "Rise", cycleMillis: <unresolved: CYCLE_MILLIS>, gridAngleDegrees: 0, lanes: [{ attribute: "intensity", keyframes: [[0, 0], [1, 1]] }, ...<unresolved: (["position:pan", "position:tilt"] as const).map((attribute) => ({ attribute, keyframes: [ [0, { preset: { family: PresetFamily.Position, number: 1 } }], [1, { preset: { family:…>] }. t.dynamic.create({
pool: 1,
name: "Rise",
cycleMillis: CYCLE_MILLIS,
gridAngleDegrees: 0,
lanes: [
{ attribute: "intensity", keyframes: [[0, 0], [1, 1]] },
...(["position:pan", "position:tilt"] as const).map((attribute) => ({
attribute,
keyframes: [
[0, { preset: { family: PresetFamily.Position, number: 1 } }],
[1, { preset: { family: PresetFamily.Position, number: 2 } }],
] as Array<
[number, { preset: { family: PresetFamily; number: number } }]
>,
})),
],
})
| 84 |
| Expected | Dynamic → targetless: $dynamic (result of dynamic.create). t.dynamic.expect(dynamic).targetless()
| 102 |
| Step | Group → api → select with group = 1. t.group.via.api.select(group)
| 106 |
| Step | Dynamic → apply with $dynamic (result of dynamic.create). t.dynamic.apply(dynamic)
| 107 |
| Step | Record → playback with <unresolved: 1 + index>. t.record.playback(1 + index)
| 108 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 109 |
| Step | Clear the current selection. t.selection.clear()
| 110 |
| Step | Playback → configure with $playback (result of record.playback), {
name: "Rise group = 1",
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name: `Rise ${group}`,
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty,
],
})
| 111 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 121 |
| Step | Group → api → select with group = 2. t.group.via.api.select(group)
| 106 |
| Step | Dynamic → apply with $dynamic (result of dynamic.create). t.dynamic.apply(dynamic)
| 107 |
| Step | Record → playback with <unresolved: 1 + index>. t.record.playback(1 + index)
| 108 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 109 |
| Step | Clear the current selection. t.selection.clear()
| 110 |
| Step | Playback → configure with $playback (result of record.playback), {
name: "Rise group = 2",
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name: `Rise ${group}`,
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty,
],
})
| 111 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 121 |
| Expected | Dynamic → targetless: $dynamic (result of dynamic.create). t.dynamic.expect(dynamic).targetless()
| 124 |
| Step | Desktop → configure with .desktop: Dynamic reuse t.desktop.configure("Dynamic reuse")
| 126 |
| Step | Add the PaneType.VirtualPlaybacks pane desktop.addPane(
PaneType.VirtualPlaybacks,
{ slug: "dynamic-reuse", column: 1, row: 1, width: 12, height: 10 },
{ rows: 1, columns: 2 },
)
| 127 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 132 |
| Step | Virtual playback → assign source with $pane (result of desktopBuilder.addPane), "Rise 1", 1. t.virtualPlayback.assignSource(pane, "Rise 1", 1)
| 133 |
| Step | Virtual playback → assign source with $pane (result of desktopBuilder.addPane), "Rise 2", 2. t.virtualPlayback.assignSource(pane, "Rise 2", 2)
| 134 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 1. t.virtualPlayback.activate(pane, 1)
| 163 |
| Expected | Virtual playback → runtime: $first (result of virtualPlayback.assignSource), {
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(first, { runtime: { enabled: true } })
| 164 |
| Expected | Virtual playback → runtime: $second (result of virtualPlayback.assignSource), {
runtime: {
enabled: false
}
}t.virtualPlayback.expect.runtime(second, { runtime: { enabled: false } })
| 165 |
| Step | Advance the test clock by quarter = "<unresolved: CYCLE_MILLIS / 4>ms". t.clock.advanceBy(quarter)
| 166 |
| Expected | fixture(number) DMX equals {
Intensity: <unresolved: near(phase)>,
"Tilt coarse": <unresolved: between("tilt")>,
"Pan coarse": <unresolved: between("pan")>
}t.expectFixtureDMX(fixture(number), {
Intensity: near(phase),
"Tilt coarse": between("tilt"),
"Pan coarse": between("pan"),
})
| 149 |
| Expected | fixture(number) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixture(number), { Intensity: 0 })
| 158 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 2. t.virtualPlayback.activate(pane, 2)
| 171 |
| Expected | Virtual playback → runtime: $first (result of virtualPlayback.assignSource), {
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(first, { runtime: { enabled: true } })
| 172 |
| Expected | Virtual playback → runtime: $second (result of virtualPlayback.assignSource), {
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(second, { runtime: { enabled: true } })
| 173 |
| Step | Advance the test clock by quarter = "<unresolved: CYCLE_MILLIS / 4>ms". t.clock.advanceBy(quarter)
| 174 |
| Expected | fixture(number) DMX equals {
Intensity: <unresolved: near(phase)>,
"Tilt coarse": <unresolved: between("tilt")>,
"Pan coarse": <unresolved: between("pan")>
}t.expectFixtureDMX(fixture(number), {
Intensity: near(phase),
"Tilt coarse": between("tilt"),
"Pan coarse": between("pan"),
})
| 149 |
| Expected | fixture(number) DMX equals {
Intensity: <unresolved: near(phase)>,
"Tilt coarse": <unresolved: between("tilt")>,
"Pan coarse": <unresolved: between("pan")>
}t.expectFixtureDMX(fixture(number), {
Intensity: near(phase),
"Tilt coarse": between("tilt"),
"Pan coarse": between("pan"),
})
| 149 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 1. t.virtualPlayback.activate(pane, 1)
| 179 |
| Expected | Virtual playback → runtime: $first (result of virtualPlayback.assignSource), {
runtime: {
enabled: false
}
}t.virtualPlayback.expect.runtime(first, { runtime: { enabled: false } })
| 180 |
| Expected | Virtual playback → runtime: $second (result of virtualPlayback.assignSource), {
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(second, { runtime: { enabled: true } })
| 181 |
| Step | Advance the test clock by quarter = "<unresolved: CYCLE_MILLIS / 4>ms". t.clock.advanceBy(quarter)
| 182 |
| Expected | fixture(number) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixture(number), { Intensity: 0 })
| 158 |
| Expected | fixture(number) DMX equals {
Intensity: <unresolved: near(phase)>,
"Tilt coarse": <unresolved: between("tilt")>,
"Pan coarse": <unresolved: between("pan")>
}t.expectFixtureDMX(fixture(number), {
Intensity: near(phase),
"Tilt coarse": between("tilt"),
"Pan coarse": between("pan"),
})
| 149 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 2. t.virtualPlayback.activate(pane, 2)
| 186 |
| Expected | Virtual playback → runtime: $second (result of virtualPlayback.assignSource), {
runtime: {
enabled: false
}
}t.virtualPlayback.expect.runtime(second, { runtime: { enabled: false } })
| 187 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 188 |
| Expected | fixture(number) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixture(number), { Intensity: 0 })
| 158 |
| Expected | fixture(number) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixture(number), { Intensity: 0 })
| 158 |
| Expected | Dynamic → targetless: $dynamic (result of dynamic.create). t.dynamic.expect(dynamic).targetless()
| 191 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Step | <unresolved: GROUP_ONE> Expression GROUP_ONE is not statically resolved. | 49 |
| unresolved-expression | Step | <unresolved: GROUP_ONE> Expression GROUP_ONE is not statically resolved. | 49 |
| unresolved-expression | Step | <unresolved: 1 + (number - 1) * 15> Expression 1 + (number - 1) * 15 is not statically resolved. | 53 |
| unresolved-expression | Step | <unresolved: ((number - 1) % 4) * 1000> Expression ((number - 1) % 4) * 1000 is not statically resolved. | 55 |
| unresolved-expression | Step | <unresolved: number <= 4 ? 0 : 1000> Expression number <= 4 ? 0 : 1000 is not statically resolved. | 56 |
| unresolved-expression | Step | <unresolved: ...MOVER> Object member ...MOVER is not statically resolved. | 59 |
| unresolved-expression | Step | <unresolved: GROUP_TWO> Expression GROUP_TWO is not statically resolved. | 49 |
| unresolved-expression | Step | <unresolved: GROUP_TWO> Expression GROUP_TWO is not statically resolved. | 49 |
| unresolved-expression | Step | <unresolved: 1 + (number - 1) * 15> Expression 1 + (number - 1) * 15 is not statically resolved. | 53 |
| unresolved-expression | Step | <unresolved: ((number - 1) % 4) * 1000> Expression ((number - 1) % 4) * 1000 is not statically resolved. | 55 |
| unresolved-expression | Step | <unresolved: number <= 4 ? 0 : 1000> Expression number <= 4 ? 0 : 1000 is not statically resolved. | 56 |
| unresolved-expression | Step | <unresolved: ...MOVER> Object member ...MOVER is not statically resolved. | 59 |
| unresolved-expression | Step | <unresolved: GROUP_ONE> Expression GROUP_ONE is not statically resolved. | 61 |
| unresolved-expression | Step | <unresolved: GROUP_TWO> Expression GROUP_TWO is not statically resolved. | 63 |
| unresolved-expression | Expected outcome | <unresolved: GROUP_ONE> Expression GROUP_ONE is not statically resolved. | 65 |
| unresolved-expression | Expected outcome | <unresolved: GROUP_TWO> Expression GROUP_TWO is not statically resolved. | 66 |
| unresolved-expression | Step | <unresolved: GROUP_ONE> Expression GROUP_ONE is not statically resolved. | 73 |
| unresolved-expression | Step | <unresolved: GROUP_TWO> Expression GROUP_TWO is not statically resolved. | 73 |
| unresolved-expression | Step | <unresolved: position.pan> Property access position.pan depends on a runtime value. | 74 |
| unresolved-expression | Step | <unresolved: position.tilt> Property access position.tilt depends on a runtime value. | 75 |
| unresolved-expression | Step | <unresolved: GROUP_ONE> Expression GROUP_ONE is not statically resolved. | 73 |
| unresolved-expression | Step | <unresolved: GROUP_TWO> Expression GROUP_TWO is not statically resolved. | 73 |
| unresolved-expression | Step | <unresolved: position.pan> Property access position.pan depends on a runtime value. | 74 |
| unresolved-expression | Step | <unresolved: position.tilt> Property access position.tilt depends on a runtime value. | 75 |
| unresolved-expression | Step | <unresolved: CYCLE_MILLIS> Expression CYCLE_MILLIS is not statically resolved. | 87 |
| unresolved-expression | Step | <unresolved: (["position:pan", "position:tilt"] as const).map((attribute) => ({ attribute, keyframes: [ [0, { preset: { family: PresetFamily.Position, number: 1 } }], [1, { preset: { family:…> Call expression (["position:pan", "position:tilt"] as const).map((attribute) => ({ attribute, keyframes: [ [0, { preset: { family: PresetFamily.Position, number: 1 } }], [1, { preset: { family:… is dynamic and was not executed. | 91 |
| unresolved-expression | Step | <unresolved: 1 + index> Expression 1 + index is not statically resolved. | 108 |
| unresolved-expression | Step | <unresolved: 1 + index> Expression 1 + index is not statically resolved. | 108 |
| unresolved-expression | Step | <unresolved: CYCLE_MILLIS / 4> Expression CYCLE_MILLIS / 4 is not statically resolved. | 160 |
| static-control-flow | Source | Control flow for (const [index, number] of members.entries()) { const phase = (progress + index * 0.25) % 1; const between = (axis: "pan" | "tilt") => { const from = percentOfTravel(axis, DO… is narrated once; iteration values are not guessed. | 142 |
| unresolved-expression | Expected outcome | <unresolved: near(phase)> Call expression near(phase) is dynamic and was not executed. | 150 |
| unresolved-expression | Expected outcome | <unresolved: between("tilt")> Call expression between("tilt") is dynamic and was not executed. | 151 |
| unresolved-expression | Expected outcome | <unresolved: between("pan")> Call expression between("pan") is dynamic and was not executed. | 152 |
| static-control-flow | Source | Control flow for (const number of members) await t.expectFixtureDMX(fixture(number), { Intensity: 0 }); is narrated once; iteration values are not guessed. | 157 |
| unresolved-expression | Step | <unresolved: CYCLE_MILLIS / 4> Expression CYCLE_MILLIS / 4 is not statically resolved. | 160 |
| static-control-flow | Source | Control flow for (const [index, number] of members.entries()) { const phase = (progress + index * 0.25) % 1; const between = (axis: "pan" | "tilt") => { const from = percentOfTravel(axis, DO… is narrated once; iteration values are not guessed. | 142 |
| unresolved-expression | Expected outcome | <unresolved: near(phase)> Call expression near(phase) is dynamic and was not executed. | 150 |
| unresolved-expression | Expected outcome | <unresolved: between("tilt")> Call expression between("tilt") is dynamic and was not executed. | 151 |
| unresolved-expression | Expected outcome | <unresolved: between("pan")> Call expression between("pan") is dynamic and was not executed. | 152 |
| static-control-flow | Source | Control flow for (const [index, number] of members.entries()) { const phase = (progress + index * 0.25) % 1; const between = (axis: "pan" | "tilt") => { const from = percentOfTravel(axis, DO… is narrated once; iteration values are not guessed. | 142 |
| unresolved-expression | Expected outcome | <unresolved: near(phase)> Call expression near(phase) is dynamic and was not executed. | 150 |
| unresolved-expression | Expected outcome | <unresolved: between("tilt")> Call expression between("tilt") is dynamic and was not executed. | 151 |
| unresolved-expression | Expected outcome | <unresolved: between("pan")> Call expression between("pan") is dynamic and was not executed. | 152 |
| unresolved-expression | Step | <unresolved: CYCLE_MILLIS / 4> Expression CYCLE_MILLIS / 4 is not statically resolved. | 160 |
| static-control-flow | Source | Control flow for (const number of members) await t.expectFixtureDMX(fixture(number), { Intensity: 0 }); is narrated once; iteration values are not guessed. | 157 |
| static-control-flow | Source | Control flow for (const [index, number] of members.entries()) { const phase = (progress + index * 0.25) % 1; const between = (axis: "pan" | "tilt") => { const from = percentOfTravel(axis, DO… is narrated once; iteration values are not guessed. | 142 |
| unresolved-expression | Expected outcome | <unresolved: near(phase)> Call expression near(phase) is dynamic and was not executed. | 150 |
| unresolved-expression | Expected outcome | <unresolved: between("tilt")> Call expression between("tilt") is dynamic and was not executed. | 151 |
| unresolved-expression | Expected outcome | <unresolved: between("pan")> Call expression between("pan") is dynamic and was not executed. | 152 |
BENCH-TEMP-RELEASE-001 — a Temp runs a Sunstrip Cuelist with its timing, follows into the release, and turns itself off once nothing is held
tests/115-semantic-temp-release-shutdown.spec.ts:22 · migrated-semantic-world · last run: not merged
show: EmptyBrowser UICommand keypadCommand lineCue runtimeCue timingCuesDMX outputDesktop layoutEncoder controlsPlaybacksProgrammerProgrammer timingRecordingSelectionShow PatchShow filesTest clockTyped APIVirtual Playbacks
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.Empty show.t.show.use(Show.Empty)
| 26 |
Open the ToskLight browser application.t.app.open()
| 27 |
The ToskLight browser application is ready.t.app.expect.ready()
| 28 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 29 |
| Step | Patch → api → add with {
number: 1,
name: "Sunstrip",
address: "1.1",
<unresolved: ...SUNSTRIP_DIMMERS>
}t.patch.via.api.add({ number: 1, name: "Sunstrip", address: "1.1", ...SUNSTRIP_DIMMERS })
| 31 |
| Step | Patch → api → add with {
number: 2,
name: "Sunstrip RGB",
address: "1.11",
<unresolved: ...SUNSTRIP>
}t.patch.via.api.add({ number: 2, name: "Sunstrip RGB", address: "1.11", ...SUNSTRIP })
| 32 |
| Step | Selection → fixtures → api → items with 1, 2. t.selection.fixtures.via.api.items(1, 2)
| 35 |
| Step | Encoder → intensity → dimmer → api → set with 100. t.encoder.intensity.dimmer.via.api.set(100)
| 36 |
| Step | Selection → fixtures → api → item with 2. t.selection.fixtures.via.api.item(2)
| 37 |
| Step | Encoder → color → red → api → set with 100. t.encoder.color.red.via.api.set(100)
| 38 |
| Step | Encoder → color → green → api → set with 100. t.encoder.color.green.via.api.set(100)
| 39 |
| Step | Encoder → color → blue → api → set with 100. t.encoder.color.blue.via.api.set(100)
| 40 |
| Step | Record → playback with 1. t.record.playback(1)
| 41 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 42 |
| Step | Command → type with "FIXTURE 1 THRU 2". t.command.type("FIXTURE 1 THRU 2")
| 45 |
| Step | Press keypad keys [
"SHIFT",
"OFF",
"0",
"SHIFT",
"ENT"
] t.keypad.press(["SHIFT", "OFF", "0", "SHIFT", "ENT"])
| 46 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 47 |
| Expected | Cue → present: $playback (result of record.playback), 2. t.cue.expect(playback, 2).present()
| 48 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 49 |
| Step | Clear the current selection. t.selection.clear()
| 50 |
| Step | Cue → open editor with $playback (result of record.playback). t.cue.openEditor(playback)
| 53 |
| Step | Cue editor → edit with 1, {
fade: "0.2",
outFade: "1"
}editor.edit(1, { fade: "0.2", outFade: "1" })
| 54 |
| Step | Cue editor → edit with 2, {
fade: "1",
trigger: "FOLLOW",
triggerTime: "0.3"
}editor.edit(2, { fade: "1", trigger: "FOLLOW", triggerTime: "0.3" })
| 55 |
| Step | Playback → configure with $playback (result of record.playback), {
name: "Strip release",
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Temp,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name: "Strip release",
buttonCount: 1,
hasFader: false,
buttons: [PlaybackButton.Temp, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 57 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 63 |
| Step | Desktop → configure with .desktop: Temp release t.desktop.configure("Temp release")
| 64 |
| Step | Add the PaneType.VirtualPlaybacks pane desktop.addPane(
PaneType.VirtualPlaybacks,
{ slug: "temp-release", column: 1, row: 1, width: 12, height: 10 },
{ rows: 1, columns: 1 },
)
| 65 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 70 |
| Step | Virtual playback → assign source with $pane (result of desktopBuilder.addPane), "Strip release", 1. t.virtualPlayback.assignSource(pane, "Strip release", 1)
| 71 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 80 |
| Expected | fixture(1, head) DMX equals {
Intensity: level = 0
}t.expectFixtureDMX(fixture(1, head), { Intensity: level })
| 77 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 1. t.virtualPlayback.activate(pane, 1)
| 82 |
| Expected | Virtual playback → runtime: $temp (result of virtualPlayback.assignSource), {
runtime: {
temporary_active: true
}
}t.virtualPlayback.expect.runtime(temp, {
runtime: { temporary_active: true },
})
| 83 |
| Step | Advance the test clock by "100ms". t.clock.advanceBy("100ms")
| 86 |
| Expected | fixture(1, head) DMX equals {
Intensity: level = {
between: [
100,
155
]
}
}t.expectFixtureDMX(fixture(1, head), { Intensity: level })
| 77 |
| Step | Advance the test clock by "110ms". t.clock.advanceBy("110ms")
| 88 |
| Expected | fixture(1, head) DMX equals {
Intensity: level = 255
}t.expectFixtureDMX(fixture(1, head), { Intensity: level })
| 77 |
| Step | Advance the test clock by "300ms". t.clock.advanceBy("300ms")
| 92 |
| Expected | Virtual playback → runtime: $temp (result of virtualPlayback.assignSource), {
runtime: {
temporary_active: true
}
}t.virtualPlayback.expect.runtime(temp, {
runtime: { temporary_active: true },
})
| 93 |
| Step | Advance the test clock by "500ms". t.clock.advanceBy("500ms")
| 96 |
| Expected | fixture(1, head) DMX equals {
Intensity: level = {
between: [
100,
155
]
}
}t.expectFixtureDMX(fixture(1, head), { Intensity: level })
| 77 |
| Step | Advance the test clock by "510ms". t.clock.advanceBy("510ms")
| 101 |
| Expected | fixture(1, head) DMX equals {
Intensity: level = 0
}t.expectFixtureDMX(fixture(1, head), { Intensity: level })
| 77 |
| Expected | Virtual playback → runtime: $temp (result of virtualPlayback.assignSource), {
runtime: {
enabled: false
}
}t.virtualPlayback.expect.runtime(temp, { runtime: { enabled: false } })
| 103 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 1. t.virtualPlayback.activate(pane, 1)
| 105 |
| Expected | Virtual playback → runtime: $temp (result of virtualPlayback.assignSource), {
runtime: {
temporary_active: true
}
}t.virtualPlayback.expect.runtime(temp, {
runtime: { temporary_active: true },
})
| 106 |
| Step | Advance the test clock by "210ms". t.clock.advanceBy("210ms")
| 109 |
| Expected | fixture(1, head) DMX equals {
Intensity: level = 255
}t.expectFixtureDMX(fixture(1, head), { Intensity: level })
| 77 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Step | <unresolved: ...SUNSTRIP_DIMMERS> Object member ...SUNSTRIP_DIMMERS is not statically resolved. | 31 |
| unresolved-expression | Step | <unresolved: ...SUNSTRIP> Object member ...SUNSTRIP is not statically resolved. | 32 |
BENCH-DYNAMIC-EDITOR-001 — a two-axis Circle built by touch in the Dynamics editor stores typed Angle lanes in degrees and moves the movers
tests/127-dynamic-editor-position-circle.spec.ts:27 · migrated-semantic-world · last run: not merged
show: EmptyBrowser UICue timingDMX outputDynamicsGroupsProgrammer timingSelectionShow PatchShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.Empty show.t.show.use(Show.Empty)
| 31 |
Open the ToskLight browser application.t.app.open()
| 32 |
The ToskLight browser application is ready.t.app.expect.ready()
| 33 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 34 |
| Step | Patch → api → add with {
number: <unresolved: number>,
name: "Mover <unresolved: number>", address: "1.<unresolved: 1 + (number - 1) * 15>", <unresolved: ...MOVER> }t.patch.via.api.add({
number,
name: `Mover ${number}`,
address: `1.${1 + (number - 1) * 15}`,
...MOVER,
})
| 37 |
| Step | Selection → fixtures → api → items with ...<unresolved: MOVERS>. t.selection.fixtures.via.api.items(...MOVERS)
| 43 |
| Step | Group → api → store with 1, {
mode: StoreMode.Overwrite
}t.group.via.api.store(1, { mode: StoreMode.Overwrite })
| 44 |
| Step | Group → api → select with 1. t.group.via.api.select(1)
| 45 |
| Step | Built in → open with PaneType.Dynamics. t.builtIn.open(PaneType.Dynamics)
| 47 |
| Step | Tap empty Dynamics tile 1 and choose the lane {
group: "position",
attribute: "Pan"
} in the lane chooser. t.dynamic.editor.create(1, {
group: "position",
attribute: "Pan",
})
| 50 |
| Expected | $circle (result of dynamic.editor.create) stores the lanes [
{
family: "position",
component: "pan"
},
{
family: "position",
component: "tilt"
}
]t.dynamic.editor.expect.lanes(circle, [
{ family: "position", component: "pan" },
{ family: "position", component: "tilt" },
])
| 54 |
| Expected | The "Middle" lane encoder reads "Current". t.dynamic.editor.expect.encoder("Middle", "Current")
| 58 |
| Expected | The "Amplitude" lane encoder reads "45°". t.dynamic.editor.expect.encoder("Amplitude", "45°")
| 59 |
| Step | Enter <unresolved: String(PAN_AMPLITUDE)> on the "Amplitude" lane encoder's value modal. t.dynamic.editor.setEncoder("Amplitude", String(PAN_AMPLITUDE))
| 60 |
| Expected | The "Amplitude" lane encoder reads "<unresolved: PAN_AMPLITUDE>°". t.dynamic.editor.expect.encoder("Amplitude", `${PAN_AMPLITUDE}°`)
| 61 |
| Step | Tap + Add Lane and choose the lane {
group: "position",
attribute: "Tilt"
}t.dynamic.editor.addLane(circle, { group: "position", attribute: "Tilt" })
| 64 |
| Expected | $circle (result of dynamic.editor.create) stores the lanes [
{
family: "position",
component: "pan"
},
{
family: "position",
component: "tilt"
}
]t.dynamic.editor.expect.lanes(circle, [
{ family: "position", component: "pan" },
{ family: "position", component: "tilt" },
])
| 65 |
| Step | Select lane 2, "Tilt", in the Dynamics editor. t.dynamic.editor.selectLane(2, "Tilt")
| 69 |
| Step | Choose the "Cosinus" curve function for the selected lane. t.dynamic.editor.chooseCurve("Cosinus")
| 70 |
| Expected | The "Amplitude" lane encoder reads "<unresolved: TILT_AMPLITUDE>°". t.dynamic.editor.expect.encoder("Amplitude", `${TILT_AMPLITUDE}°`)
| 71 |
| Expected | Dynamic → editor → lane configuration: $circle (result of dynamic.editor.create), 1, {
mode: "middle_amplitude",
configuration: {
function: "sinus",
middle: {
kind: "current"
},
amplitude: {
kind: "scalar",
value: <unresolved: PAN_AMPLITUDE>
}
}
}t.dynamic.editor.expect.laneConfiguration(circle, 1, {
mode: "middle_amplitude",
configuration: {
function: "sinus",
middle: { kind: "current" },
amplitude: { kind: "scalar", value: PAN_AMPLITUDE },
},
})
| 72 |
| Expected | Dynamic → editor → lane configuration: $circle (result of dynamic.editor.create), 2, {
mode: "middle_amplitude",
configuration: {
function: "cosinus",
middle: {
kind: "current"
},
amplitude: {
kind: "scalar",
value: <unresolved: TILT_AMPLITUDE>
}
}
}t.dynamic.editor.expect.laneConfiguration(circle, 2, {
mode: "middle_amplitude",
configuration: {
function: "cosinus",
middle: { kind: "current" },
amplitude: { kind: "scalar", value: TILT_AMPLITUDE },
},
})
| 80 |
| Expected | The Dynamics editor shows no error. t.dynamic.editor.expect.noError()
| 88 |
| Step | In Dynamic Settings › Targets tap Take Selection, then go back to the pool. t.dynamic.editor.takeSelectionAndClose()
| 90 |
| Step | Tap the pool tile of $circle (result of dynamic.editor.create) to toggle it. t.dynamic.editor.toggle(circle)
| 91 |
| Step | Advance the test clock by "<unresolved: CYCLE_MILLIS / 4>ms". t.clock.advanceBy(`${CYCLE_MILLIS / 4}ms`)
| 107 |
| Expected | fixture(number) DMX equals {
"Pan coarse": <unresolved: angle("pan", PAN_AMPLITUDE * Math.sin(turn))>,
"Tilt coarse": <unresolved: angle("tilt", TILT_AMPLITUDE * Math.cos(turn))>
}t.expectFixtureDMX(fixture(number), {
"Pan coarse": angle("pan", PAN_AMPLITUDE * Math.sin(turn)),
"Tilt coarse": angle("tilt", TILT_AMPLITUDE * Math.cos(turn)),
})
| 100 |
| Step | Advance the test clock by "<unresolved: CYCLE_MILLIS / 4>ms". t.clock.advanceBy(`${CYCLE_MILLIS / 4}ms`)
| 107 |
| Expected | fixture(number) DMX equals {
"Pan coarse": <unresolved: angle("pan", PAN_AMPLITUDE * Math.sin(turn))>,
"Tilt coarse": <unresolved: angle("tilt", TILT_AMPLITUDE * Math.cos(turn))>
}t.expectFixtureDMX(fixture(number), {
"Pan coarse": angle("pan", PAN_AMPLITUDE * Math.sin(turn)),
"Tilt coarse": angle("tilt", TILT_AMPLITUDE * Math.cos(turn)),
})
| 100 |
| Step | Advance the test clock by "<unresolved: CYCLE_MILLIS / 4>ms". t.clock.advanceBy(`${CYCLE_MILLIS / 4}ms`)
| 107 |
| Expected | fixture(number) DMX equals {
"Pan coarse": <unresolved: angle("pan", PAN_AMPLITUDE * Math.sin(turn))>,
"Tilt coarse": <unresolved: angle("tilt", TILT_AMPLITUDE * Math.cos(turn))>
}t.expectFixtureDMX(fixture(number), {
"Pan coarse": angle("pan", PAN_AMPLITUDE * Math.sin(turn)),
"Tilt coarse": angle("tilt", TILT_AMPLITUDE * Math.cos(turn)),
})
| 100 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| static-control-flow | Source | Control flow for (const number of MOVERS) await t.patch.via.api.add({ number, name: `Mover ${number}`, address: `1.${1 + (number - 1) * 15}`, ...MOVER, }); is narrated once; iteration values are not guessed. | 36 |
| unresolved-expression | Step | <unresolved: number> Expression number is not statically resolved. | 38 |
| unresolved-expression | Step | <unresolved: number> Expression number is not statically resolved. | 39 |
| unresolved-expression | Step | <unresolved: 1 + (number - 1) * 15> Expression 1 + (number - 1) * 15 is not statically resolved. | 40 |
| unresolved-expression | Step | <unresolved: ...MOVER> Object member ...MOVER is not statically resolved. | 41 |
| unresolved-expression | Step | <unresolved: MOVERS> Expression MOVERS is not statically resolved. | 43 |
| unresolved-expression | Step | <unresolved: String(PAN_AMPLITUDE)> Call expression String(PAN_AMPLITUDE) is dynamic and was not executed. | 60 |
| unresolved-expression | Expected outcome | <unresolved: PAN_AMPLITUDE> Expression PAN_AMPLITUDE is not statically resolved. | 61 |
| unresolved-expression | Expected outcome | <unresolved: TILT_AMPLITUDE> Expression TILT_AMPLITUDE is not statically resolved. | 71 |
| unresolved-expression | Expected outcome | <unresolved: PAN_AMPLITUDE> Expression PAN_AMPLITUDE is not statically resolved. | 77 |
| unresolved-expression | Expected outcome | <unresolved: TILT_AMPLITUDE> Expression TILT_AMPLITUDE is not statically resolved. | 85 |
| unresolved-expression | Step | <unresolved: CYCLE_MILLIS / 4> Expression CYCLE_MILLIS / 4 is not statically resolved. | 107 |
| static-control-flow | Source | Control flow for (const [index, number] of MOVERS.entries()) { const turn = 2 * Math.PI * ((phase + index * 0.5) % 1); await t.expectFixtureDMX(fixture(number), { "Pan coarse": angle("pan", … is narrated once; iteration values are not guessed. | 98 |
| unresolved-expression | Expected outcome | <unresolved: angle("pan", PAN_AMPLITUDE * Math.sin(turn))> Call expression angle("pan", PAN_AMPLITUDE * Math.sin(turn)) is dynamic and was not executed. | 101 |
| unresolved-expression | Expected outcome | <unresolved: angle("tilt", TILT_AMPLITUDE * Math.cos(turn))> Call expression angle("tilt", TILT_AMPLITUDE * Math.cos(turn)) is dynamic and was not executed. | 102 |
| unresolved-expression | Step | <unresolved: CYCLE_MILLIS / 4> Expression CYCLE_MILLIS / 4 is not statically resolved. | 107 |
| static-control-flow | Source | Control flow for (const [index, number] of MOVERS.entries()) { const turn = 2 * Math.PI * ((phase + index * 0.5) % 1); await t.expectFixtureDMX(fixture(number), { "Pan coarse": angle("pan", … is narrated once; iteration values are not guessed. | 98 |
| unresolved-expression | Expected outcome | <unresolved: angle("pan", PAN_AMPLITUDE * Math.sin(turn))> Call expression angle("pan", PAN_AMPLITUDE * Math.sin(turn)) is dynamic and was not executed. | 101 |
| unresolved-expression | Expected outcome | <unresolved: angle("tilt", TILT_AMPLITUDE * Math.cos(turn))> Call expression angle("tilt", TILT_AMPLITUDE * Math.cos(turn)) is dynamic and was not executed. | 102 |
| unresolved-expression | Step | <unresolved: CYCLE_MILLIS / 4> Expression CYCLE_MILLIS / 4 is not statically resolved. | 107 |
| static-control-flow | Source | Control flow for (const [index, number] of MOVERS.entries()) { const turn = 2 * Math.PI * ((phase + index * 0.5) % 1); await t.expectFixtureDMX(fixture(number), { "Pan coarse": angle("pan", … is narrated once; iteration values are not guessed. | 98 |
| unresolved-expression | Expected outcome | <unresolved: angle("pan", PAN_AMPLITUDE * Math.sin(turn))> Call expression angle("pan", PAN_AMPLITUDE * Math.sin(turn)) is dynamic and was not executed. | 101 |
| unresolved-expression | Expected outcome | <unresolved: angle("tilt", TILT_AMPLITUDE * Math.cos(turn))> Call expression angle("tilt", TILT_AMPLITUDE * Math.cos(turn)) is dynamic and was not executed. | 102 |
BENCH-DYNAMIC-EDITOR-002 — Color and Zoom lanes chosen in the Dynamics editor are stored as semantic family lanes in their own units
tests/127-dynamic-editor-position-circle.spec.ts:113 · migrated-semantic-world · last run: not merged
show: EmptyBrowser UIDynamicsShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.Empty show.t.show.use(Show.Empty)
| 117 |
Open the ToskLight browser application.t.app.open()
| 118 |
The ToskLight browser application is ready.t.app.expect.ready()
| 119 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Built in → open with PaneType.Dynamics. t.builtIn.open(PaneType.Dynamics)
| 120 |
| Step | Tap empty Dynamics tile 2 and choose the lane {
group: "color",
attribute: "Red"
} in the lane chooser. t.dynamic.editor.create(2, { group: "color", attribute: "Red" })
| 122 |
| Expected | The "Top" lane encoder reads "100%". t.dynamic.editor.expect.encoder("Top", "100%")
| 123 |
| Expected | The "Bottom" lane encoder reads "0%". t.dynamic.editor.expect.encoder("Bottom", "0%")
| 124 |
| Step | Tap + Add Lane and choose the lane {
group: "color",
attribute: "White Blend"
}t.dynamic.editor.addLane(look, { group: "color", attribute: "White Blend" })
| 125 |
| Step | Tap + Add Lane and choose the lane {
group: "focus",
attribute: "Zoom"
}t.dynamic.editor.addLane(look, { group: "focus", attribute: "Zoom" })
| 126 |
| Step | Select lane 3, "Zoom", in the Dynamics editor. t.dynamic.editor.selectLane(3, "Zoom")
| 127 |
| Expected | The "Top" lane encoder reads "40°". t.dynamic.editor.expect.encoder("Top", "40°")
| 128 |
| Expected | The "Bottom" lane encoder reads "10°". t.dynamic.editor.expect.encoder("Bottom", "10°")
| 129 |
| Expected | $look (result of dynamic.editor.create) stores the lanes [
{
family: "color",
component: "red"
},
{
family: "color",
component: "white_blend"
},
{
family: "zoom"
}
]t.dynamic.editor.expect.lanes(look, [
{ family: "color", component: "red" },
{ family: "color", component: "white_blend" },
{ family: "zoom" },
])
| 130 |
| Expected | The Dynamics editor shows no error. t.dynamic.editor.expect.noError()
| 135 |
Diagnostics
None.
HIGHLIGHT-006 — the production hardware simulator preserves geometry and sends independent full-height faders
tests/21-completion-coverage.spec.ts:5 · migrated-semantic-world · last run: not merged
Hardware simulatorOSC
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | Hardware simulator → expect geometry and independent faders. t.hardwareSimulator.expectGeometryAndIndependentFaders()
| 9 |
Diagnostics
None.
ENCODER-DISPLAY-001 — simulator touch controls emit encoder and NAV turn, held-turn, and click tokens
tests/21-completion-coverage.spec.ts:13 · migrated-semantic-world · last run: not merged
Hardware simulatorOSC
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | Hardware simulator → expect encoder and navigation tokens. t.hardwareSimulator.expectEncoderAndNavigationTokens()
| 17 |
Diagnostics
None.
UPDATE-002 — actual simulator pointer gestures emit complete, mutually exclusive Shift and Record sequences
tests/21-completion-coverage.spec.ts:21 · migrated-semantic-world · last run: not merged
Hardware simulatorOSC
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | Hardware simulator → expect shift record pointer sequences. t.hardwareSimulator.expectShiftRecordPointerSequences()
| 25 |
Diagnostics
None.
BENCH-UI-003 — captures semantic surfaces and emits typed secondary-screen intent
tests/37-semantic-desktop-show-clock.spec.ts:9 · migrated-semantic-world · last run: not merged
Browser UIDesktop layoutGenerated artifactsSecondary screen
Preconditions (1)
| Context | Line |
|---|
Open the ToskLight browser application.t.app.open()
| 13 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Built in → open with PaneType.Stage.2 tools t.builtIn.open(PaneType.Stage)
| 14 |
| Tool | Capture application screenshot "bench-application". t.screenshot.application("bench-application")
| 15 |
| Tool | Capture PaneType.Stage pane screenshot "bench-stage-built-in". t.screenshot.builtIn(PaneType.Stage, "bench-stage-built-in")
| 16 |
| Step | Desktop → create with "Screenshot Desktop". t.desktop.create("Screenshot Desktop")
| 18 |
| Step | Desktop → open settings for with "Screenshot Desktop".2 tools t.desktop.openSettingsFor("Screenshot Desktop")
| 19 |
| Tool | Capture "Desktop settings" dialog screenshot "bench-desktop-dialog". t.screenshot.dialog("Desktop settings", "bench-desktop-dialog")
| 20 |
| Tool | Capture application screenshot "bench-application-with-portal". t.screenshot.application("bench-application-with-portal")
| 21 |
| Step | Desktop → close settings. t.desktop.closeSettings()
| 22 |
| Step | Screen → create with screen: Bench output {
fixedPane: "fixture_sheet",
showDock: false,
showPlaybacks: true,
showPageControls: true,
fullscreen: false,
desiredOpen: true,
playbacks: {
perRow: 8,
rows: [
{
first: 41,
fader: true,
buttons: 3
}
],
pageMode: "dedicated"
}
}t.screen.create({
name: "Bench output",
fixedPane: "fixture_sheet",
showDock: false,
showPlaybacks: true,
showPageControls: true,
display: { id: "display-2", name: "Operator display" },
bounds: { x: 100, y: 80, width: 1024, height: 768 },
fullscreen: false,
desiredOpen: true,
playbacks: {
perRow: 8,
rows: [{ first: 41, fader: true, buttons: 3 }],
pageMode: "dedicated",
},
})
| 24 |
| Expected | Secondary-screen bridge action is "open_console_screen". screen.expectBridgeAction("open_console_screen")
| 40 |
| Expected | Secondary screen → fixed pane is "fixture_sheet". screen.expectFixedPane("fixture_sheet")
| 41 |
| Step | Close the configured secondary screen. screen.close()
| 42 |
| Expected | Secondary-screen bridge action is "close_console_screen". screen.expectBridgeAction("close_console_screen")
| 43 |
| Step | Remove the configured secondary screen. screen.remove()
| 44 |
Diagnostics
None.
BENCH-SHOW-004 — runs named create, autosave, Save As, revision, and reopen through visible operator controls
tests/37-semantic-desktop-show-clock.spec.ts:48 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UIShow files
Preconditions (10)
| Context | Line |
|---|
Open the ToskLight browser application.t.app.open()
| 52 |
Create the show "Operator Empty <generated: UUID>".t.show.create(`Operator Empty ${crypto.randomUUID()}`)
| 53 |
Save the active show.t.show.save()
| 56 |
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 58 |
Save the active show as "Portable Source <generated: UUID>".t.show.saveAs(
`Portable Source ${crypto.randomUUID()}`,
)
| 59 |
Save a named show revision "Approved operator state".t.show.saveRevision("Approved operator state")
| 63 |
Save the active show as "Portable Later Copy <generated: UUID>".t.show.saveAs(
`Portable Later Copy ${crypto.randomUUID()}`,
)
| 68 |
Load the show $source (result of show.saveAs).t.show.load(source)
| 72 |
Load revision $revision (result of show.saveRevision) of $source (result of show.saveAs).t.show.loadRevision(source, revision)
| 74 |
Save the active show.t.show.save()
| 76 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | Show → active is the created show. t.show.expect.active(empty)
| 54 |
| Expected | Show → dirty is false. t.show.expect.dirty(false)
| 55 |
| Expected | Show → active is the saved show copy. t.show.expect.active(source)
| 62 |
| Expected | Show → revision matches {
number: $revision (result of show.saveRevision),
name: "Approved operator state"
}t.show.expect.revision({
number: revision,
name: "Approved operator state",
})
| 64 |
| Expected | Show → active is the saved show copy. t.show.expect.active(laterCopy)
| 71 |
| Expected | Show → active is the saved show copy. t.show.expect.active(source)
| 73 |
| Expected | Show → active is the loaded revision copy. t.show.expect.active(revisionCopy)
| 75 |
Diagnostics
None.
BENCH-CLOCK-DMX-001 — uses exact clock boundaries and fixture-aware logical DMX without hidden ticks
tests/37-semantic-desktop-show-clock.spec.ts:80 · migrated-semantic-world · last run: not merged
DMX outputSemantic oracleTest clock
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 84 |
| Expected | $first.now (from clock.advanceStep) is "2020-01-01T00:00:00Z". expect(first.now).toBe("2020-01-01T00:00:00Z")
| 85 |
| Expected | $first.packets_sent (from clock.advanceStep) is 2. expect(first.packets_sent).toBe(2)
| 86 |
| Step | Clock → at with [
{
name: "before",
at: "999ms"
},
{
name: "exact",
at: "1s"
},
{
name: "after",
at: "1.001s"
}
], <generated: callback>. t.clock.at(
[
{ name: "before", at: "999ms" },
{ name: "exact", at: "1s" },
{ name: "after", at: "1.001s" },
],
({ name, frame }) => boundaries.push(`${name}:${frame.now}`),
)
| 89 |
| Expected | boundaries = [
] equals [
"before:2020-01-01T00:00:00.999Z",
"exact:2020-01-01T00:00:01Z",
"after:2020-01-01T00:00:01.001Z"
] expect(boundaries).toEqual([
"before:2020-01-01T00:00:00.999Z",
"exact:2020-01-01T00:00:01Z",
"after:2020-01-01T00:00:01.001Z",
])
| 97 |
| Expected | fixture(1) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixture(1), { Intensity: 0 })
| 103 |
| Expected | fixtureRange(1, 3) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(1, 3), { Intensity: 0 })
| 104 |
| Expected | Calling t.expectFixtureDMX(fixture(1), {
"Missing component": 0
}) rejects with /Valid channels: Intensity/u. expect(
t.expectFixtureDMX(fixture(1), { "Missing component": 0 }),
).rejects.toThrow(/Valid channels: Intensity/u)
| 105 |
| Expected | Calling t.expectFixtureDMX(fixture(1), {
Intensity: 256
}) rejects with /integer from 0 through 255/u. expect(
t.expectFixtureDMX(fixture(1), { Intensity: 256 }),
).rejects.toThrow(/integer from 0 through 255/u)
| 108 |
Diagnostics
None.
BENCH-COMMAND-SELECTION-002 — preserves ordered typed sources while Highlight power stays independent
tests/38-semantic-command-programmer-group-preset.spec.ts:18 · migrated-semantic-world · last run: not merged
Attached hardwareBrowser UIHighlightOSCSelectionSemantic oracleTyped API
Preconditions (2)
| Context | Line |
|---|
Open the ToskLight browser application.t.app.open()
| 22 |
The ToskLight browser application is ready.t.app.expect.ready()
| 23 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → targets with fixture(3), fixture(1). t.selection.targets(fixture(3), fixture(1))
| 25 |
| Expected | Selection: fixture(3), fixture(1). t.expect.selection(fixture(3), fixture(1))
| 26 |
| Step | Selection → groups → range with 1, 4. t.selection.groups.range(1, 4)
| 28 |
| Expected | Selection: groupRange(1, 4). t.expect.selection(groupRange(1, 4))
| 29 |
| Step | Selection → observe. t.selection.observe()
| 30 |
| Step | Highlight → api → on. t.highlight.via.api.on()
| 32 |
| Step | Highlight → api → off. t.highlight.via.api.off()
| 33 |
| Step | Selection → observe. t.selection.observe()
| 34 |
| Expected | $after.selected (from selection.observe) equals $before.selected (from selection.observe). expect(after.selected).toEqual(before.selected)
| 35 |
| Expected | $after.expression (from selection.observe) equals $before.expression (from selection.observe). expect(after.expression).toEqual(before.expression)
| 36 |
| Step | Connect the simulated attached hardware surface. t.hardware.connect()
| 38 |
| Step | Highlight → osc → toggle. t.highlight.via.osc.toggle()
| 40 |
| Step | Highlight → osc → toggle. t.highlight.via.osc.toggle()
| 41 |
| Step | Disconnect the simulated attached hardware surface. t.hardware.disconnect()
| 43 |
Diagnostics
None.
BENCH-ENCODER-001 — normalized Dimmer absolute and relative API intents retain distinct semantics
tests/38-semantic-command-programmer-group-preset.spec.ts:48 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UIDMX outputEncoder controlsProgrammerSelectionSemantic oracleShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 52 |
Open the ToskLight browser application.t.app.open()
| 53 |
The ToskLight browser application is ready.t.app.expect.ready()
| 54 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | Show → active is Default Stage. t.show.expect.active(Show.DefaultStage)
| 55 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 56 |
| Expected | Selection: fixture(1). t.expect.selection(fixture(1))
| 57 |
| Step | Encoder → intensity → dimmer → api → set with 50. t.encoder.intensity.dimmer.via.api.set(50)
| 59 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 60 |
| Step | Encoder → intensity → dimmer → api → add with 3. t.encoder.intensity.dimmer.via.api.add(3)
| 61 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 62 |
| Step | Encoder → intensity → dimmer → api → subtract with 2. t.encoder.intensity.dimmer.via.api.subtract(2)
| 63 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 64 |
| Expected | dmxFixture(1) DMX equals {
Intensity: 130
}t.expectFixtureDMX(dmxFixture(1), { Intensity: 130 })
| 65 |
Diagnostics
None.
BENCH-GROUP-002 — live Group references refresh while dereferenced captures retain concrete fixtures
tests/38-semantic-command-programmer-group-preset.spec.ts:69 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UIGroupsSelectionSemantic oracleShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 73 |
Open the ToskLight browser application.t.app.open()
| 74 |
The ToskLight browser application is ready.t.app.expect.ready()
| 75 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → items with 1, 2. t.selection.fixtures.via.api.items(1, 2)
| 77 |
| Step | Group → api → store with 80, {
mode: StoreMode.Overwrite
}t.group.via.api.store(80, { mode: StoreMode.Overwrite })
| 78 |
| Step | Selection → targets with dereferencedGroup(80). t.selection.targets(dereferencedGroup(80))
| 80 |
| Step | Group → api → store with 80, {
mode: StoreMode.Subtract
}t.group.via.api.store(80, { mode: StoreMode.Subtract })
| 81 |
| Expected | Group → empty: 80. t.group.expect(80).empty()
| 82 |
| Expected | Selection: fixture(1), fixture(2). t.expect.selection(fixture(1), fixture(2))
| 83 |
| Step | Group → api → store with 80, {
mode: StoreMode.Overwrite
}t.group.via.api.store(80, { mode: StoreMode.Overwrite })
| 85 |
| Step | Group → api → select with 80. t.group.via.api.select(80)
| 86 |
| Expected | Selection: group(80). t.expect.selection(group(80))
| 87 |
| Step | Group → api → store with 80, {
mode: StoreMode.Subtract
}t.group.via.api.store(80, { mode: StoreMode.Subtract })
| 88 |
| Expected | Group → empty: 80. t.group.expect(80).empty()
| 89 |
| Expected | Selection: group(80). t.expect.selection(group(80))
| 90 |
Diagnostics
None.
BENCH-PRESET-001 — Preset families record and recall through pool, keypad, API, and OSC
tests/38-semantic-command-programmer-group-preset.spec.ts:94 · migrated-semantic-world · last run: not merged
show: Default StageAttached hardwareBrowser UICommand keypadCue timingDMX outputDesktop layoutEncoder controlsHighlightOSCPool UIPresetsProgrammerProgrammer timingSelectionSemantic oracleShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 98 |
Open the ToskLight browser application.t.app.open()
| 99 |
The ToskLight browser application is ready.t.app.expect.ready()
| 100 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 102 |
| Step | Desktop → configure with .desktop: Groups and Presets t.desktop.configure("Groups and Presets")
| 203 |
| Step | Add the PaneType.Presets pane desktop.addPane(PaneType.Presets, {
slug: "presets",
column: 1,
row: 1,
width: 12,
height: 18,
})
| 204 |
| Step | Add the PaneType.Fixtures pane desktop.addPane(PaneType.Fixtures, {
slug: "fixtures",
column: 13,
row: 1,
width: 6,
height: 18,
})
| 211 |
| Step | Add the PaneType.Stage pane desktop.addPane(PaneType.Stage, {
slug: "stage",
column: 19,
row: 1,
width: 6,
height: 18,
})
| 218 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 225 |
| Step | Selection → fixtures → api → items with 101, 102. t.selection.fixtures.via.api.items(101, 102)
| 104 |
| Step | Encoder → intensity → dimmer → api → set with 70. t.encoder.intensity.dimmer.via.api.set(70)
| 106 |
| Step | Encoder → color → red → api → set with [
40,
ProgrammerToken.Thru,
60
] t.encoder.color.red.via.api.set([40, ProgrammerToken.Thru, 60])
| 110 |
| Step | Encoder → position → pan → api → set with <unresolved: -135>. t.encoder.position.pan.via.api.set(-135)
| 112 |
| Step | Encoder → beam → gobo1 → api → set with 30. t.encoder.beam.gobo1.via.api.set(30)
| 113 |
| Step | Preset → api → store with PresetFamily.Mixed, 1, {
mode: "overwrite"
}t.preset.via.api.store(PresetFamily.Mixed, 1, {
mode: "overwrite",
})
| 115 |
| Step | Preset → pool → store with PresetFamily.Intensity, 1, {
mode: "overwrite"
}t.preset.via.pool.store(PresetFamily.Intensity, 1, {
mode: "overwrite",
})
| 118 |
| Step | Preset → keypad → store with PresetFamily.Color, 1, {
mode: "overwrite"
}t.preset.via.keypad.store(PresetFamily.Color, 1, {
mode: "overwrite",
})
| 121 |
| Step | Connect the simulated attached hardware surface. t.hardware.connect()
| 125 |
| Step | Preset → api → store with PresetFamily.Mixed, 2, {
mode: "overwrite"
}t.preset.via.api.store(PresetFamily.Mixed, 2, {
mode: "overwrite",
})
| 127 |
| Expected | Preset → present: PresetFamily.Mixed, 2. t.preset.expect(PresetFamily.Mixed, 2).present()
| 130 |
| Step | Disconnect the simulated attached hardware surface. t.hardware.disconnect()
| 132 |
| Step | Preset → api → store with PresetFamily.Position, 1, {
mode: "overwrite"
}t.preset.via.api.store(PresetFamily.Position, 1, {
mode: "overwrite",
})
| 135 |
| Step | Preset → api → store with PresetFamily.Beam, 1, {
mode: "overwrite"
}t.preset.via.api.store(PresetFamily.Beam, 1, {
mode: "overwrite",
})
| 138 |
| Expected | Preset → present: PresetFamily.Mixed, 1. t.preset.expect(family, 1).present()
| 142 |
| Expected | Preset → metadata: PresetFamily.Mixed, 1, {
family: PresetFamily.Mixed,
number: 1
}t.preset.expect(family, 1).metadata({ family, number: 1 })
| 143 |
| Expected | Preset → present: PresetFamily.Intensity, 1. t.preset.expect(family, 1).present()
| 142 |
| Expected | Preset → metadata: PresetFamily.Intensity, 1, {
family: PresetFamily.Intensity,
number: 1
}t.preset.expect(family, 1).metadata({ family, number: 1 })
| 143 |
| Expected | Preset → present: PresetFamily.Color, 1. t.preset.expect(family, 1).present()
| 142 |
| Expected | Preset → metadata: PresetFamily.Color, 1, {
family: PresetFamily.Color,
number: 1
}t.preset.expect(family, 1).metadata({ family, number: 1 })
| 143 |
| Expected | Preset → present: PresetFamily.Position, 1. t.preset.expect(family, 1).present()
| 142 |
| Expected | Preset → metadata: PresetFamily.Position, 1, {
family: PresetFamily.Position,
number: 1
}t.preset.expect(family, 1).metadata({ family, number: 1 })
| 143 |
| Expected | Preset → present: PresetFamily.Beam, 1. t.preset.expect(family, 1).present()
| 142 |
| Expected | Preset → metadata: PresetFamily.Beam, 1, {
family: PresetFamily.Beam,
number: 1
}t.preset.expect(family, 1).metadata({ family, number: 1 })
| 143 |
| Step | Preset → pool → edit with PresetFamily.Mixed, 1, {
title: "Stage look"
}t.preset.via.pool.edit(PresetFamily.Mixed, 1, {
title: "Stage look",
})
| 146 |
| Expected | Preset → button: PresetFamily.Mixed, 1, {
title: "Stage look"
}t.preset.expect(PresetFamily.Mixed, 1).button({
title: "Stage look",
})
| 149 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 153 |
| Step | Clear the current selection. t.selection.clear()
| 154 |
| Expected | Preset → expect visible selection count: 0. t.preset.expectVisibleSelectionCount(0)
| 155 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 156 |
| Expected | dmxFixture(101) DMX equals {
Intensity: 0
}t.expectFixtureDMX(dmxFixture(101), { Intensity: 0 })
| 157 |
| Expected | dmxFixture(102) DMX equals {
Intensity: 0
}t.expectFixtureDMX(dmxFixture(102), { Intensity: 0 })
| 158 |
| Step | Preset → tap empty pool slot with PresetFamily.Mixed, 9. t.preset.tapEmptyPoolSlot(PresetFamily.Mixed, 9)
| 159 |
| Expected | Selection. t.expect.selection()
| 160 |
| Step | Preset → pool → recall with PresetFamily.Mixed, 1. t.preset.via.pool.recall(PresetFamily.Mixed, 1)
| 162 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 163 |
| Expected | Poll → to be: <generated: callback>, count = 2. expect
.poll(async () => (await t.selection.observe()).selected.length)
.toBe(count)
| 232 |
| Step | Selection → observe. t.selection.observe()
| 240 |
| Expected | <unresolved: selection.targets.map((target) => target.number)> equals [102, 101]. expect(selection.targets.map((target) => target.number)).toEqual([102, 101])
| 241 |
| Expected | $selection.expression (from selection.observe) equals {
type: "static"
}expect(selection.expression).toEqual({ type: "static" })
| 242 |
| Expected | Preset → expect visible selection: 101, 102. t.preset.expectVisibleSelection(101, 102)
| 166 |
| Expected | dmxFixture(101) DMX equals {
Intensity: 0
}t.expectFixtureDMX(dmxFixture(101), { Intensity: 0 })
| 167 |
| Expected | dmxFixture(102) DMX equals {
Intensity: 0
}t.expectFixtureDMX(dmxFixture(102), { Intensity: 0 })
| 168 |
| Step | Preset → pool → recall with PresetFamily.Mixed, 1. t.preset.via.pool.recall(PresetFamily.Mixed, 1)
| 170 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 171 |
| Expected | dmxFixture(101) DMX equals {
Intensity: 179
}t.expectFixtureDMX(dmxFixture(101), { Intensity: 179 })
| 172 |
| Expected | dmxFixture(102) DMX equals {
Intensity: 179
}t.expectFixtureDMX(dmxFixture(102), { Intensity: 179 })
| 173 |
| Step | Preset → keypad → recall with PresetFamily.Position, 1. t.preset.via.keypad.recall(PresetFamily.Position, 1)
| 175 |
| Step | Selection → observe. t.selection.observe()
| 240 |
| Expected | <unresolved: selection.targets.map((target) => target.number)> equals [102, 101]. expect(selection.targets.map((target) => target.number)).toEqual([102, 101])
| 241 |
| Expected | $selection.expression (from selection.observe) equals {
type: "static"
}expect(selection.expression).toEqual({ type: "static" })
| 242 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 178 |
| Step | Clear the current selection. t.selection.clear()
| 179 |
| Expected | Preset → expect visible selection count: 0. t.preset.expectVisibleSelectionCount(0)
| 180 |
| Step | Preset → api → recall with PresetFamily.Color, 1. t.preset.via.api.recall(PresetFamily.Color, 1)
| 181 |
| Expected | Poll → to be: <generated: callback>, count = 2. expect
.poll(async () => (await t.selection.observe()).selected.length)
.toBe(count)
| 232 |
| Step | Selection → observe. t.selection.observe()
| 240 |
| Expected | <unresolved: selection.targets.map((target) => target.number)> equals [102, 101]. expect(selection.targets.map((target) => target.number)).toEqual([102, 101])
| 241 |
| Expected | $selection.expression (from selection.observe) equals {
type: "static"
}expect(selection.expression).toEqual({ type: "static" })
| 242 |
| Step | Preset → api → recall with PresetFamily.Color, 1. t.preset.via.api.recall(PresetFamily.Color, 1)
| 184 |
| Step | Connect the simulated attached hardware surface. t.hardware.connect()
| 186 |
| Step | Preset → osc → recall with PresetFamily.Mixed, 2. t.preset.via.osc.recall(PresetFamily.Mixed, 2)
| 188 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 189 |
| Step | Selection → observe. t.selection.observe()
| 240 |
| Expected | <unresolved: selection.targets.map((target) => target.number)> equals [102, 101]. expect(selection.targets.map((target) => target.number)).toEqual([102, 101])
| 241 |
| Expected | $selection.expression (from selection.observe) equals {
type: "static"
}expect(selection.expression).toEqual({ type: "static" })
| 242 |
| Expected | dmxFixture(101) DMX equals {
Intensity: 179
}t.expectFixtureDMX(dmxFixture(101), { Intensity: 179 })
| 191 |
| Expected | dmxFixture(102) DMX equals {
Intensity: 179
}t.expectFixtureDMX(dmxFixture(102), { Intensity: 179 })
| 192 |
| Step | Highlight → osc → toggle. t.highlight.via.osc.toggle()
| 193 |
| Step | Selection → observe. t.selection.observe()
| 240 |
| Expected | <unresolved: selection.targets.map((target) => target.number)> equals [102, 101]. expect(selection.targets.map((target) => target.number)).toEqual([102, 101])
| 241 |
| Expected | $selection.expression (from selection.observe) equals {
type: "static"
}expect(selection.expression).toEqual({ type: "static" })
| 242 |
| Step | Highlight → osc → toggle. t.highlight.via.osc.toggle()
| 195 |
| Step | Disconnect the simulated attached hardware surface. t.hardware.disconnect()
| 197 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Step | <unresolved: -135> Expression -135 is not statically resolved. | 112 |
| unresolved-expression | Expected outcome | <unresolved: selection.targets.map((target) => target.number)> Call expression selection.targets.map((target) => target.number) is dynamic and was not executed. | 241 |
| unresolved-expression | Expected outcome | <unresolved: selection.targets.map((target) => target.number)> Call expression selection.targets.map((target) => target.number) is dynamic and was not executed. | 241 |
| unresolved-expression | Expected outcome | <unresolved: selection.targets.map((target) => target.number)> Call expression selection.targets.map((target) => target.number) is dynamic and was not executed. | 241 |
| unresolved-expression | Expected outcome | <unresolved: selection.targets.map((target) => target.number)> Call expression selection.targets.map((target) => target.number) is dynamic and was not executed. | 241 |
| unresolved-expression | Expected outcome | <unresolved: selection.targets.map((target) => target.number)> Call expression selection.targets.map((target) => target.number) is dynamic and was not executed. | 241 |
BENCH-CUE-PLAYBACK-001 — visible recording and typed runtime actions preserve Cue timing and concrete Playback identity
tests/39-semantic-playback-and-osc.spec.ts:19 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UICue runtimeCue timingDMX outputEncoder controlsPlaybacksProgrammerProgrammer timingRecordingSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 23 |
Open the ToskLight browser application.t.app.open()
| 24 |
The ToskLight browser application is ready.t.app.expect.ready()
| 25 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 26 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 27 |
| Step | Selection → fixtures → api → item with 101. t.selection.fixtures.via.api.item(101)
| 28 |
| Step | Encoder → intensity → dimmer → api → set with 20. t.encoder.intensity.dimmer.via.api.set(20)
| 30 |
| Step | Record → ui → playback with 1. t.record.via.ui.playback(1)
| 31 |
| Expected | Playback → present: $playback (result of record.via.ui.playback). t.playback.expect(playback).present()
| 32 |
| Expected | Cue → present: $playback (result of record.via.ui.playback), 1. t.cue.expect(playback, 1).present()
| 33 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 35 |
| Step | Encoder → intensity → dimmer → api → set with 80. t.encoder.intensity.dimmer.via.api.set(80)
| 36 |
| Step | Record → api → cue with {
playback: $playback (result of record.via.ui.playback),
cue: 2,
mode: CueRecordMode.Overwrite,
timing: {
fade: "1"
}
}t.record.via.api.cue({
playback,
cue: 2,
mode: CueRecordMode.Overwrite,
timing: { fade: "1" },
})
| 37 |
| Expected | Cue → metadata: $playback (result of record.via.ui.playback), 2, {
fade_millis: 1000
}t.cue.expect(playback, 2).metadata({ fade_millis: 1_000 })
| 43 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 44 |
| Step | Playback → api → off with $playback (result of record.via.ui.playback). t.playback.via.api.off(playback)
| 46 |
| Step | Playback → ui → go with $playback (result of record.via.ui.playback). t.playback.via.ui.go(playback)
| 47 |
| Expected | Playback → runtime: $playback (result of record.via.ui.playback), {
current_cue_number: "1",
enabled: true
}t.playback.expect(playback).runtime({
current_cue_number: "1",
enabled: true,
})
| 48 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 52 |
| Expected | dmxFixture(101) DMX equals {
Intensity: 51
}t.expectFixtureDMX(dmxFixture(101), { Intensity: 51 })
| 53 |
| Step | Playback → api → go with $playback (result of record.via.ui.playback). t.playback.via.api.go(playback)
| 55 |
| Step | Advance the test clock by "500ms". t.clock.advanceBy("500ms")
| 56 |
| Expected | dmxFixture(101) DMX equals {
Intensity: 128
}t.expectFixtureDMX(dmxFixture(101), { Intensity: 128 })
| 57 |
| Step | Advance the test clock by "500ms". t.clock.advanceBy("500ms")
| 58 |
| Expected | dmxFixture(101) DMX equals {
Intensity: 204
}t.expectFixtureDMX(dmxFixture(101), { Intensity: 204 })
| 59 |
| Step | Playback → api → select with $playback (result of record.via.ui.playback). t.playback.via.api.select(playback)
| 61 |
| Expected | Playback → selected: $playback (result of record.via.ui.playback). t.playback.expect(playback).selected()
| 62 |
Diagnostics
None.
BENCH-PAGE-PLAYBACK-001 — current and explicit Page targets retain distinct Playback authority
tests/39-semantic-playback-and-osc.spec.ts:66 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UICue timingEncoder controlsPlayback pagesPlaybacksProgrammerProgrammer timingRecordingSecondary screenSelectionSemantic oracleShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 70 |
Open the ToskLight browser application.t.app.open()
| 71 |
The ToskLight browser application is ready.t.app.expect.ready()
| 72 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 73 |
| Step | Selection → fixtures → api → item with 101. t.selection.fixtures.via.api.item(101)
| 75 |
| Step | Encoder → intensity → dimmer → api → set with 25. t.encoder.intensity.dimmer.via.api.set(25)
| 76 |
| Step | Record → playback with 1. t.record.playback(1)
| 77 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 78 |
| Step | Selection → fixtures → api → item with 102. t.selection.fixtures.via.api.item(102)
| 79 |
| Step | Encoder → intensity → dimmer → api → set with 75. t.encoder.intensity.dimmer.via.api.set(75)
| 80 |
| Step | Record → playback with 2. t.record.playback(2)
| 81 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 82 |
| Step | Page → create with 2. t.page.create(2)
| 84 |
| Step | Page → rename with 2, "Second". t.page.rename(2, "Second")
| 85 |
| Step | Page → map with {
sourceAddress: $second (result of record.playback),
targetAddress: {
page: 2,
position: 1
}
}t.page.map({
sourceAddress: second,
targetAddress: { page: 2, position: 1 },
})
| 86 |
| Expected | Page → named: 2, "Second". t.page.expect(2).named("Second")
| 90 |
| Step | Playback → api → off with $first (result of record.playback). t.playback.via.api.off(first)
| 92 |
| Step | Playback → api → off with $second (result of record.playback). t.playback.via.api.off(second)
| 93 |
| Step | Page → api → select with 1. t.page.via.api.select(1)
| 94 |
| Step | Playback → api → go with currentPagePlayback(1). t.playback.via.api.go(currentPagePlayback(1))
| 95 |
| Expected | Playback → runtime: $first (result of record.playback), {
enabled: true
}t.playback.expect(first).runtime({ enabled: true })
| 96 |
| Expected | Playback → runtime: $second (result of record.playback), {
enabled: false
}t.playback.expect(second).runtime({ enabled: false })
| 97 |
| Step | Page → ui → select with 2. t.page.via.ui.select(2)
| 99 |
| Step | Playback → api → go with currentPagePlayback(1). t.playback.via.api.go(currentPagePlayback(1))
| 100 |
| Expected | Playback → runtime: {
page: 2,
position: 1
}{
enabled: true
}t.playback.expect({ page: 2, position: 1 }).runtime({ enabled: true })
| 101 |
| Expected | Playback → runtime: $second (result of record.playback), {
enabled: true
}t.playback.expect(second).runtime({ enabled: true })
| 103 |
| Step | Playback → api → off with $first (result of record.playback). t.playback.via.api.off(first)
| 105 |
| Step | Playback → api → go with explicitPagePlayback(1, 1). t.playback.via.api.go(explicitPagePlayback(1, 1))
| 106 |
| Expected | Playback → runtime: $first (result of record.playback), {
enabled: true
}t.playback.expect(first).runtime({ enabled: true })
| 107 |
| Expected | Page → selected: 2. t.page.expect(2).selected()
| 108 |
| Step | Screen → create with screen: Independent Playbacks {
showPlaybacks: true,
showPageControls: true,
playbacks: {
perRow: 1,
rows: [
{
first: 1,
fader: true,
buttons: 3
}
],
pageMode: "dedicated"
}
}t.screen.create({
name: "Independent Playbacks",
showPlaybacks: true,
showPageControls: true,
playbacks: {
perRow: 1,
rows: [{ first: 1, fader: true, buttons: 3 }],
pageMode: "dedicated",
},
})
| 110 |
| Step | Screen handle → page → select with 1. screen.page.select(1)
| 120 |
| Expected | Secondary screen → selected page is 1. screen.page.expectSelected(1)
| 121 |
| Expected | <unresolved: await t.page.resolvedPage("main")> is 2. expect(await t.page.resolvedPage("main")).toBe(2)
| 123 |
| Expected | Page → selected: 1. t.page.expect(1).selected()
| 124 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: await t.page.resolvedPage("main")> Expression await t.page.resolvedPage("main") is not statically resolved. | 123 |
BENCH-SELECTION-ROUTES-001 — visible panes, keypad, API, and OSC converge on the ordered selection oracle
tests/39-semantic-playback-and-osc.spec.ts:128 · migrated-semantic-world · last run: not merged
Attached hardwareBrowser UICommand keypadDesktop layoutFixture SheetOSCSelectionSemantic oracleTyped API
Preconditions (2)
| Context | Line |
|---|
Open the ToskLight browser application.t.app.open()
| 132 |
The ToskLight browser application is ready.t.app.expect.ready()
| 133 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Selection route proof t.desktop.configure("Selection route proof")
| 134 |
| Step | Add the PaneType.Fixtures pane desktop.addPane(PaneType.Fixtures, {
slug: "fixtures",
column: 1,
row: 1,
width: 8,
height: 18,
})
| 135 |
| Step | Add the PaneType.Stage pane desktop.addPane(PaneType.Stage, {
slug: "stage",
column: 9,
row: 1,
width: 8,
height: 18,
})
| 142 |
| Step | Add the PaneType.Groups pane desktop.addPane(PaneType.Groups, {
slug: "groups",
column: 17,
row: 1,
width: 8,
height: 18,
})
| 149 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 156 |
| Step | Clear the current selection. t.selection.clear()
| 158 |
| Step | Selection → fixtures → fixture sheet → items with 1, 3, 2. t.selection.fixtures.via.fixtureSheet.items(1, 3, 2)
| 159 |
| Expected | Selection: fixture(1), fixture(3), fixture(2). t.expect.selection(fixture(1), fixture(3), fixture(2))
| 160 |
| Step | Clear the current selection. t.selection.clear()
| 162 |
| Step | Selection → fixtures → fixture sheet → range with 1, 4. t.selection.fixtures.via.fixtureSheet.range(1, 4)
| 163 |
| Expected | Selection: fixtureRange(1, 4). t.expect.selection(fixtureRange(1, 4))
| 164 |
| Step | Clear the current selection. t.selection.clear()
| 166 |
| Step | Selection → groups → api → range with 1, 4. t.selection.groups.via.api.range(1, 4)
| 167 |
| Expected | Selection: groupRange(1, 4). t.expect.selection(groupRange(1, 4))
| 168 |
| Step | Selection → fixtures → keypad → range with 2, 5. t.selection.fixtures.via.keypad.range(2, 5)
| 170 |
| Expected | Selection: fixtureRange(2, 5). t.expect.selection(fixtureRange(2, 5))
| 171 |
| Step | Selection → fixtures → api → items with 5, 2, 4. t.selection.fixtures.via.api.items(5, 2, 4)
| 173 |
| Expected | Selection: fixture(5), fixture(2), fixture(4). t.expect.selection(fixture(5), fixture(2), fixture(4))
| 174 |
| Step | Connect the simulated attached hardware surface. t.hardware.connect()
| 176 |
| Step | Selection → fixtures → osc → item with 6. t.selection.fixtures.via.osc.item(6)
| 178 |
| Expected | Selection: fixture(6). t.expect.selection(fixture(6))
| 179 |
| Step | Disconnect the simulated attached hardware surface. t.hardware.disconnect()
| 181 |
Diagnostics
None.
SHOW-000 — Save As produces independent reusable show files
tests/40-semantic-generate-show-files.spec.ts:11 · migrated-semantic-world · last run: not merged
show: Compact Rigshow: Default StageBrowser UICommand keypadDesktop layoutFixture SheetGroupsPool UISelectionSemantic oracleShow files
Preconditions (13)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 15 |
Open the ToskLight browser application.t.app.open()
| 16 |
The ToskLight browser application is ready.t.app.expect.ready()
| 17 |
Show → ui → save as with "show-000-compact-copy-<generated: UUID>".t.show.via.ui.saveAs(
`show-000-compact-copy-${crypto.randomUUID()}`,
)
| 35 |
Show → ui → save revision with "SHOW-000 compact UI mutation".t.show.via.ui.saveRevision(
"SHOW-000 compact UI mutation",
)
| 38 |
Show → ui → load revision with $compactCopy (result of show.via.ui.saveAs), $compactRevision (result of show.via.ui.saveRevision).t.show.via.ui.loadRevision(
compactCopy,
compactRevision,
)
| 41 |
Reset the isolated working copy.t.show.resetWorkingCopy()
| 53 |
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 62 |
Open the ToskLight browser application.t.app.open()
| 63 |
The ToskLight browser application is ready.t.app.expect.ready()
| 64 |
Show → ui → save as with "show-000-default-copy-<generated: UUID>".t.show.via.ui.saveAs(
`show-000-default-copy-${crypto.randomUUID()}`,
)
| 69 |
Show → ui → save revision with "SHOW-000 default UI mutation".t.show.via.ui.saveRevision("SHOW-000 default UI mutation")
| 72 |
Reset the isolated working copy.t.show.resetWorkingCopy()
| 74 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Generated show workflow t.desktop.configure("Generated show workflow")
| 83 |
| Step | Add the PaneType.Fixtures pane desktop.addPane(PaneType.Fixtures, {
slug: "fixtures",
column: 1,
row: 1,
width: 12,
height: 18,
})
| 84 |
| Step | Add the PaneType.Groups pane desktop.addPane(PaneType.Groups, {
slug: "groups",
column: 13,
row: 1,
width: 12,
height: 18,
})
| 91 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 98 |
| Step | Selection → fixtures → fixture sheet → item with 1. t.selection.fixtures.via.fixtureSheet.item(1)
| 20 |
| Expected | Selection: fixture(1). t.expect.selection(fixture(1))
| 21 |
| Step | Group → pool → store with 4, {
mode: StoreMode.Overwrite
}t.group.via.pool.store(4, { mode: StoreMode.Overwrite })
| 22 |
| Step | Group → pool → edit with 4, {
name: "Copy Center Spot",
color: "#1bd6ec",
icon: "★"
}t.group.via.pool.edit(4, {
name: "Copy Center Spot",
color: "#1bd6ec",
icon: "★",
})
| 23 |
| Expected | Group → fixtures: 4, 1. t.group.expect(4).fixtures(1)
| 28 |
| Expected | Group → metadata: 4, {
name: "Copy Center Spot",
color: "#1bd6ec",
icon: "★"
}t.group.expect(4).metadata({
name: "Copy Center Spot",
color: "#1bd6ec",
icon: "★",
})
| 29 |
| Expected | Show → active is the loaded revision copy. t.show.expect.active(compactRevisionCopy)
| 45 |
| Expected | Group → fixtures: 4, 1. t.group.expect(4).fixtures(1)
| 46 |
| Expected | Group → metadata: 4, {
name: "Copy Center Spot",
color: "#1bd6ec",
icon: "★"
}t.group.expect(4).metadata({
name: "Copy Center Spot",
color: "#1bd6ec",
icon: "★",
})
| 47 |
| Expected | Show → active is Compact Rig. t.show.expect.active(Show.CompactRig)
| 54 |
| Expected | Group → empty: 4. t.group.expect(4).empty()
| 55 |
| Expected | Group → metadata: 4, {
name: "Center Spot",
color: null,
icon: null
}t.group.expect(4).metadata({
name: "Center Spot",
color: null,
icon: null,
})
| 56 |
| Step | Selection → fixtures → fixture sheet → item with 1. t.selection.fixtures.via.fixtureSheet.item(1)
| 65 |
| Expected | Selection: fixture(1). t.expect.selection(fixture(1))
| 66 |
| Step | Group → keypad → store with 900, {
mode: StoreMode.Overwrite
}t.group.via.keypad.store(900, { mode: StoreMode.Overwrite })
| 67 |
| Expected | Group → fixtures: 900, 1. t.group.expect(900).fixtures(1)
| 68 |
| Expected | Show → active is Default Stage. t.show.expect.active(Show.DefaultStage)
| 75 |
| Expected | Group → absent: 900. t.group.expect(900).absent()
| 76 |
Diagnostics
None.
DIM-001 — ordered Group edits retain their live value and append re-added fixtures
tests/41-semantic-foundational-dimmer-command.spec.ts:11 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineDMX outputGroupsShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 15 |
Open the ToskLight browser application.t.app.open()
| 16 |
The ToskLight browser application is ready.t.app.expect.ready()
| 17 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command command = "GROUP 3 AT 50". t.command.execute(command)
| 24 |
| Step | Execute the desk command command = "GROUP 3 + 5 + 6". t.command.execute(command)
| 24 |
| Step | Execute the desk command command = "RECORD GROUP 3". t.command.execute(command)
| 24 |
| Expected | Group → fixtures: 3, 1, 2, 3, 4, 5, 6. t.group.expect(3).fixtures(1, 2, 3, 4, 5, 6)
| 28 |
| Step | Execute the desk command "FIXTURE 2". t.command.execute("FIXTURE 2")
| 29 |
| Step | Execute the desk command "RECORD - GROUP 3". t.command.execute("RECORD - GROUP 3")
| 30 |
| Expected | Group → fixtures: 3, 1, 3, 4, 5, 6. t.group.expect(3).fixtures(1, 3, 4, 5, 6)
| 31 |
| Step | Execute the desk command "GROUP 3 + 2". t.command.execute("GROUP 3 + 2")
| 32 |
| Step | Execute the desk command "RECORD GROUP 3". t.command.execute("RECORD GROUP 3")
| 33 |
| Expected | Group → fixtures: 3, 1, 3, 4, 5, 6, 2. t.group.expect(3).fixtures(1, 3, 4, 5, 6, 2)
| 34 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 35 |
| Expected | fixtureRange(1, 6) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixtureRange(1, 6), { Intensity: 128 })
| 36 |
Diagnostics
None.
DIM-002 — Lightning Desk command reaches the exact rendered output boundary
tests/41-semantic-foundational-dimmer-command.spec.ts:40 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineCue timingDMX outputProgrammer timingShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 44 |
Open the ToskLight browser application.t.app.open()
| 45 |
The ToskLight browser application is ready.t.app.expect.ready()
| 46 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Programmer Fade → command-line AT fade is true. t.timing.programmerFade.setCommandLineAtEnabled(true)
| 48 |
| Step | Execute the desk command "GROUP 1 AT 50". t.command.execute("GROUP 1 AT 50")
| 49 |
| Step | Advance the test clock by "1.5s". t.clock.advanceBy("1.5s")
| 50 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 64
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 64 })
| 51 |
| Step | Advance the test clock by "1.5s". t.clock.advanceBy("1.5s")
| 52 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 128 })
| 53 |
| Step | Advance the test clock by "1ms". t.clock.advanceBy("1ms")
| 54 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 128 })
| 55 |
Diagnostics
None.
CMD-001 — Fixture and Group default modes toggle while explicit prefixes stay scoped
tests/41-semantic-foundational-dimmer-command.spec.ts:59 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand keypadCommand lineSemantic oracleShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 63 |
Open the ToskLight browser application.t.app.open()
| 64 |
The ToskLight browser application is ready.t.app.expect.ready()
| 65 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Press keypad keys [
"GRP"
] t.keypad.press(["GRP"])
| 67 |
| Expected | Command line shows "GROUP". t.command.expect("GROUP")
| 68 |
| Step | Press keypad keys [
"ENT"
] t.keypad.press(["ENT"])
| 69 |
| Expected | Command line shows "GROUP". t.command.expect("GROUP")
| 70 |
| Step | Press keypad keys [
"SHIFT",
"GRP",
"SHIFT"
] t.keypad.press(["SHIFT", "GRP", "SHIFT"])
| 71 |
| Expected | Command line shows "FIXTURE". t.command.expect("FIXTURE")
| 72 |
| Step | Press keypad keys [
"ENT"
] t.keypad.press(["ENT"])
| 73 |
| Expected | Command line shows "FIXTURE". t.command.expect("FIXTURE")
| 74 |
| Step | Execute the desk command "GROUP 1 + 2". t.command.execute("GROUP 1 + 2")
| 76 |
| Expected | Selection: group(1), fixture(2). t.expect.selection(group(1), fixture(2))
| 77 |
Diagnostics
None.
GROUP-003 — derived Group follows source ordering
tests/42-semantic-foundational-groups.spec.ts:16 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineDesktop layoutGroupsPool UISelectionShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 20 |
Open the ToskLight browser application.t.app.open()
| 21 |
The ToskLight browser application is ready.t.app.expect.ready()
| 22 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Foundational Groups t.desktop.configure("Foundational Groups")
| 117 |
| Step | Add the PaneType.Fixtures pane desktop.addPane(PaneType.Fixtures, {
slug: "fixtures",
column: 1,
row: 1,
width: 12,
height: 18,
})
| 118 |
| Step | Add the PaneType.Groups pane desktop.addPane(PaneType.Groups, {
slug: "groups",
column: 13,
row: 1,
width: 12,
height: 18,
})
| 125 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 132 |
| Step | Execute the desk command "GROUP 1 DIV 2". t.command.execute("GROUP 1 DIV 2")
| 25 |
| Step | Group → pool → store with 5, {
mode: StoreMode.Overwrite
}t.group.via.pool.store(5, { mode: StoreMode.Overwrite })
| 26 |
| Step | Selection → fixtures → api → items with ...sourceOrder = [
12,
1,
2,
8,
4,
5,
6,
7,
9,
10,
11
] t.selection.fixtures.via.api.items(...sourceOrder)
| 29 |
| Step | Group → pool → store with 1, {
mode: StoreMode.Overwrite
}t.group.via.pool.store(1, { mode: StoreMode.Overwrite })
| 30 |
| Expected | Group → fixtures: 1, ...sourceOrder = [
12,
1,
2,
8,
4,
5,
6,
7,
9,
10,
11
] t.group.expect(1).fixtures(...sourceOrder)
| 32 |
| Expected | Group → fixtures: 5, 12, 2, 4, 6, 9, 11. t.group.expect(5).fixtures(12, 2, 4, 6, 9, 11)
| 33 |
| Expected | Group → empty: 4. t.group.expect(4).empty()
| 34 |
Diagnostics
None.
GROUP-004 — frozen Group survives source edits and keeps unpatched fixtures programmable
tests/42-semantic-foundational-groups.spec.ts:38 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineDMX outputDesktop layoutEncoder controlsGroupsPool UIProgrammerSelectionShow PatchShow filesTest clockTyped API
Preconditions (5)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 42 |
Open the ToskLight browser application.t.app.open()
| 43 |
The ToskLight browser application is ready.t.app.expect.ready()
| 44 |
Open the ToskLight browser application.t.app.open()
| 56 |
The ToskLight browser application is ready.t.app.expect.ready()
| 57 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Foundational Groups t.desktop.configure("Foundational Groups")
| 117 |
| Step | Add the PaneType.Fixtures pane desktop.addPane(PaneType.Fixtures, {
slug: "fixtures",
column: 1,
row: 1,
width: 12,
height: 18,
})
| 118 |
| Step | Add the PaneType.Groups pane desktop.addPane(PaneType.Groups, {
slug: "groups",
column: 13,
row: 1,
width: 12,
height: 18,
})
| 125 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 132 |
| Step | Execute the desk command "DEGRP 1". t.command.execute("DEGRP 1")
| 47 |
| Step | Group → pool → store with 5, {
mode: StoreMode.Overwrite
}t.group.via.pool.store(5, { mode: StoreMode.Overwrite })
| 48 |
| Step | Selection → fixtures → api → items with ...sourceOrder = [
12,
1,
2,
4,
5,
6,
7,
8,
9,
10,
11
] t.selection.fixtures.via.api.items(...sourceOrder)
| 51 |
| Step | Group → pool → store with 1, {
mode: StoreMode.Overwrite
}t.group.via.pool.store(1, { mode: StoreMode.Overwrite })
| 52 |
| Step | Patch → ui → unpatch with 3. t.patch.via.ui.unpatch(3)
| 53 |
| Expected | Patch → unpatched: 3. t.patch.expect(3).unpatched()
| 54 |
| Step | Execute the desk command "GROUP 5". t.command.execute("GROUP 5")
| 58 |
| Step | Encoder → intensity → dimmer → ui → set with 50. t.encoder.intensity.dimmer.via.ui.set(50)
| 59 |
| Expected | Group → fixtures: 5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12. t.group.expect(5).fixtures(
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
)
| 60 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 74 |
| Expected | fixtureRange(1, 2) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixtureRange(1, 2), { Intensity: 128 })
| 75 |
| Expected | fixture(3) has no DMX output. t.expectFixtureDMXAbsent(fixture(3))
| 76 |
| Expected | fixtureRange(4, 12) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixtureRange(4, 12), { Intensity: 128 })
| 77 |
Diagnostics
None.
GROUP-005 — stored empty Groups remain distinct from missing references
tests/42-semantic-foundational-groups.spec.ts:81 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineDMX outputDesktop layoutEncoder controlsFixture SheetGroupsPool UIProgrammerSelectionSemantic oracleShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 85 |
Open the ToskLight browser application.t.app.open()
| 86 |
The ToskLight browser application is ready.t.app.expect.ready()
| 87 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Foundational Groups t.desktop.configure("Foundational Groups")
| 117 |
| Step | Add the PaneType.Fixtures pane desktop.addPane(PaneType.Fixtures, {
slug: "fixtures",
column: 1,
row: 1,
width: 12,
height: 18,
})
| 118 |
| Step | Add the PaneType.Groups pane desktop.addPane(PaneType.Groups, {
slug: "groups",
column: 13,
row: 1,
width: 12,
height: 18,
})
| 125 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 132 |
| Step | Group → api → delete with 4. t.group.via.api.delete(4)
| 90 |
| Expected | Group → absent: 4. t.group.expect(4).absent()
| 91 |
| Step | Execute the desk command "GROUP 1 THRU 5". t.command.execute("GROUP 1 THRU 5")
| 92 |
| Expected | Selection: groupRange(1, 5). t.expect.selection(groupRange(1, 5))
| 93 |
| Step | Clear the current selection. t.selection.clear()
| 95 |
| Step | Group → pool → store with 4, {
mode: StoreMode.Overwrite
}t.group.via.pool.store(4, { mode: StoreMode.Overwrite })
| 96 |
| Expected | Group → present: 4. t.group.expect(4).present()
| 97 |
| Expected | Group → empty: 4. t.group.expect(4).empty()
| 98 |
| Step | Group → pool → select with 4. t.group.via.pool.select(4)
| 99 |
| Expected | Selection: group(4). t.expect.selection(group(4))
| 100 |
| Step | Encoder → intensity → dimmer → ui → set with 50. t.encoder.intensity.dimmer.via.ui.set(50)
| 101 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 102 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 0 })
| 103 |
| Step | Selection → fixtures → fixture sheet → item with 1. t.selection.fixtures.via.fixtureSheet.item(1)
| 105 |
| Expected | Selection: fixture(1). t.expect.selection(fixture(1))
| 106 |
| Step | Group → pool → store with 4, {
mode: StoreMode.Merge
}t.group.via.pool.store(4, { mode: StoreMode.Merge })
| 107 |
| Expected | Group → fixtures: 4, 1. t.group.expect(4).fixtures(1)
| 108 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 109 |
| Expected | fixture(1) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixture(1), { Intensity: 128 })
| 110 |
Diagnostics
None.
PROG-001 — values retain selection until replacement while leading Plus continues it
tests/43-semantic-foundational-programmer.spec.ts:12 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineDMX outputSemantic oracleShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 16 |
Open the ToskLight browser application.t.app.open()
| 17 |
The ToskLight browser application is ready.t.app.expect.ready()
| 18 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command command = "1 + 2 AT 50". t.command.execute(command)
| 21 |
| Step | Execute the desk command command = "AT 25". t.command.execute(command)
| 21 |
| Step | Execute the desk command command = "3 AT 75". t.command.execute(command)
| 21 |
| Step | Execute the desk command command = "+ 4 AT 100". t.command.execute(command)
| 21 |
| Expected | Selection: fixture(3), fixture(4). t.expect.selection(fixture(3), fixture(4))
| 23 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 24 |
| Expected | fixtureRange(1, 2) DMX equals {
Intensity: 64
}t.expectFixtureDMX(fixtureRange(1, 2), { Intensity: 64 })
| 25 |
| Expected | fixtureRange(3, 4) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixtureRange(3, 4), { Intensity: 255 })
| 26 |
| Expected | fixtureRange(5, 12) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(5, 12), { Intensity: 0 })
| 27 |
Diagnostics
None.
PROG-002 — relative values spread across the live ordered Group
tests/43-semantic-foundational-programmer.spec.ts:31 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineDMX outputDesktop layoutFixture SheetGroupsPool UISelectionShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 35 |
Open the ToskLight browser application.t.app.open()
| 36 |
The ToskLight browser application is ready.t.app.expect.ready()
| 37 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Foundational Programmer t.desktop.configure("Foundational Programmer")
| 137 |
| Step | Add the PaneType.Fixtures pane desktop.addPane(PaneType.Fixtures, {
slug: "fixtures",
column: 1,
row: 1,
width: 12,
height: 18,
})
| 138 |
| Step | Add the PaneType.Groups pane desktop.addPane(PaneType.Groups, {
slug: "groups",
column: 13,
row: 1,
width: 12,
height: 18,
})
| 145 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 152 |
| Step | Selection → fixtures → fixture sheet → range with 1, 10. t.selection.fixtures.via.fixtureSheet.range(1, 10)
| 40 |
| Step | Group → pool → store with 1, {
mode: StoreMode.Overwrite
}t.group.via.pool.store(1, { mode: StoreMode.Overwrite })
| 41 |
| Step | Execute the desk command "GROUP 1 AT 0 THRU 100". t.command.execute("GROUP 1 AT 0 THRU 100")
| 42 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 43 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 0
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 28
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 57
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 85
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 113
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 142
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 170
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 198
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 227
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 255
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 0
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 0
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Step | Selection → fixtures → fixture sheet → items with ...sourceOrder = [
12,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
] t.selection.fixtures.via.fixtureSheet.items(...sourceOrder)
| 50 |
| Step | Group → pool → store with 1, {
mode: StoreMode.Overwrite
}t.group.via.pool.store(1, { mode: StoreMode.Overwrite })
| 51 |
| Expected | Group → fixtures: 1, ...sourceOrder = [
12,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
] t.group.expect(1).fixtures(...sourceOrder)
| 52 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 53 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 26
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 51
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 77
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 102
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 128
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 153
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 179
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 204
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 230
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 255
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 0
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 0
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
Diagnostics
None.
PROG-002 — fixture ranges and retained selections spread through the desk command line
tests/43-semantic-foundational-programmer.spec.ts:61 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineDMX outputShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 65 |
Open the ToskLight browser application.t.app.open()
| 66 |
The ToskLight browser application is ready.t.app.expect.ready()
| 67 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "1 THRU 5 AT 20 THRU 50". t.command.execute("1 THRU 5 AT 20 THRU 50")
| 69 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 70 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 51
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 70
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 89
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 108
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 128
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Step | Execute the desk command "1 THRU 5". t.command.execute("1 THRU 5")
| 73 |
| Step | Execute the desk command "AT 0 THRU 50". t.command.execute("AT 0 THRU 50")
| 74 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 75 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 0
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 32
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 64
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 96
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 128
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Step | Execute the desk command "1 THRU 5". t.command.execute("1 THRU 5")
| 78 |
| Step | Execute the desk command "AT 100 THRU 0 THRU 100". t.command.execute("AT 100 THRU 0 THRU 100")
| 79 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 80 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 255
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 128
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 0
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 128
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
| Expected | fixture(index + 1) DMX equals {
Intensity: intensity = 255
}t.expectFixtureDMX(fixture(index + 1), { Intensity: intensity })
| 131 |
Diagnostics
None.
PROG-003 — newer fixture intensity wins LTP and releases back to its Group value
tests/43-semantic-foundational-programmer.spec.ts:85 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineDMX outputEncoder controlsProgrammerShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 89 |
Open the ToskLight browser application.t.app.open()
| 90 |
The ToskLight browser application is ready.t.app.expect.ready()
| 91 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "GROUP 1 AT 50". t.command.execute("GROUP 1 AT 50")
| 93 |
| Step | Execute the desk command "1 AT 25". t.command.execute("1 AT 25")
| 94 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 95 |
| Expected | fixture(1) DMX equals {
Intensity: 64
}t.expectFixtureDMX(fixture(1), { Intensity: 64 })
| 96 |
| Expected | fixtureRange(2, 12) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixtureRange(2, 12), { Intensity: 128 })
| 97 |
| Step | Encoder → intensity → dimmer → release. t.encoder.intensity.dimmer.release()
| 99 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 100 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 128 })
| 101 |
Diagnostics
None.
PROG-004 — Clear removes selection first and programmer values second
tests/43-semantic-foundational-programmer.spec.ts:105 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand keypadCommand lineDMX outputSemantic oracleShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 109 |
Open the ToskLight browser application.t.app.open()
| 110 |
The ToskLight browser application is ready.t.app.expect.ready()
| 111 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "1 + 2 AT 50". t.command.execute("1 + 2 AT 50")
| 113 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 114 |
| Step | Press keypad keys [
"CLR"
] t.keypad.press(["CLR"])
| 115 |
| Expected | Selection. t.expect.selection()
| 116 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 117 |
| Expected | fixtureRange(1, 2) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixtureRange(1, 2), { Intensity: 128 })
| 118 |
| Step | Press keypad keys [
"CLR"
] t.keypad.press(["CLR"])
| 120 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 121 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 0 })
| 122 |
Diagnostics
None.
CUE-008 — blind Preload records the same Cue without activating playback or output
tests/44-semantic-cue-recording-and-reconstruction.spec.ts:9 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICommand lineDMX outputGroupsPlaybacksPreloadRecordingSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 13 |
Open the ToskLight browser application.t.app.open()
| 14 |
The ToskLight browser application is ready.t.app.expect.ready()
| 15 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → items with ...fixtures = [
1,
2,
3,
4
] t.selection.fixtures.via.api.items(...fixtures)
| 147 |
| Step | Group → api → store with group = 1, {
mode: GroupStoreMode.Overwrite
}t.group.via.api.store(group, { mode: GroupStoreMode.Overwrite })
| 148 |
| Step | Selection → fixtures → api → items with ...fixtures = [
5,
6,
7,
8
] t.selection.fixtures.via.api.items(...fixtures)
| 147 |
| Step | Group → api → store with group = 2, {
mode: GroupStoreMode.Overwrite
}t.group.via.api.store(group, { mode: GroupStoreMode.Overwrite })
| 148 |
| Step | Selection → fixtures → api → items with ...fixtures = [
9,
10,
11,
12
] t.selection.fixtures.via.api.items(...fixtures)
| 147 |
| Step | Group → api → store with group = 3, {
mode: GroupStoreMode.Overwrite
}t.group.via.api.store(group, { mode: GroupStoreMode.Overwrite })
| 148 |
| Step | Clear the current selection. t.selection.clear()
| 150 |
| Step | Start blind Preload programming. t.preload.start()
| 18 |
| Step | Execute the desk command "GROUP 1 AT 100". t.command.execute("GROUP 1 AT 100")
| 19 |
| Step | Record → playback with 1. t.record.playback(1)
| 20 |
| Expected | Playback → present: $playback (result of record.playback). t.playback.expect(playback).present()
| 21 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 22 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 0 })
| 23 |
| Step | Release blind Preload programming. t.preload.release()
| 25 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 26 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 27 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixtureRange(1, 4), { Intensity: 255 })
| 28 |
| Expected | fixtureRange(5, 12) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(5, 12), { Intensity: 0 })
| 29 |
Diagnostics
None.
CUE-001 — Record targets playbacks while decimal insertion and Record operations preserve tracking
tests/44-semantic-cue-recording-and-reconstruction.spec.ts:33 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICommand lineCue runtimeDMX outputEncoder controlsGroupsPlaybacksProgrammerRecordingSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 37 |
Open the ToskLight browser application.t.app.open()
| 38 |
The ToskLight browser application is ready.t.app.expect.ready()
| 39 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → items with ...fixtures = [
1,
2,
3,
4
] t.selection.fixtures.via.api.items(...fixtures)
| 147 |
| Step | Group → api → store with group = 1, {
mode: GroupStoreMode.Overwrite
}t.group.via.api.store(group, { mode: GroupStoreMode.Overwrite })
| 148 |
| Step | Selection → fixtures → api → items with ...fixtures = [
5,
6,
7,
8
] t.selection.fixtures.via.api.items(...fixtures)
| 147 |
| Step | Group → api → store with group = 2, {
mode: GroupStoreMode.Overwrite
}t.group.via.api.store(group, { mode: GroupStoreMode.Overwrite })
| 148 |
| Step | Selection → fixtures → api → items with ...fixtures = [
9,
10,
11,
12
] t.selection.fixtures.via.api.items(...fixtures)
| 147 |
| Step | Group → api → store with group = 3, {
mode: GroupStoreMode.Overwrite
}t.group.via.api.store(group, { mode: GroupStoreMode.Overwrite })
| 148 |
| Step | Clear the current selection. t.selection.clear()
| 150 |
| Step | Execute the desk command "GROUP 1 AT 100". t.command.execute("GROUP 1 AT 100")
| 42 |
| Step | Record → playback with 1. t.record.playback(1)
| 43 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 44 |
| Step | Execute the desk command "GROUP 3 AT 100". t.command.execute("GROUP 3 AT 100")
| 45 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 1.5
}t.record.cue({ playback, cue: 1.5 })
| 46 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 47 |
| Step | Execute the desk command "GROUP 2 AT 80". t.command.execute("GROUP 2 AT 80")
| 48 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 49 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 50 |
| Step | Execute the desk command "GROUP 2 AT 50". t.command.execute("GROUP 2 AT 50")
| 51 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2,
mode: CueRecordMode.Merge
}t.record.cue({
playback,
cue: 2,
mode: CueRecordMode.Merge,
})
| 52 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2,
mode: CueRecordMode.Subtract
}t.record.cue({
playback,
cue: 2,
mode: CueRecordMode.Subtract,
})
| 57 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 62 |
| Expected | Cue → present: $playback (result of record.playback), 1. t.cue.expect(playback, 1).present()
| 64 |
| Expected | Cue → present: $playback (result of record.playback), 1.5. t.cue.expect(playback, 1.5).present()
| 65 |
| Expected | Cue → present: $playback (result of record.playback), 2. t.cue.expect(playback, 2).present()
| 66 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 67 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 69 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 70 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixtureRange(1, 4), { Intensity: 255 })
| 71 |
| Expected | fixtureRange(5, 12) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(5, 12), { Intensity: 0 })
| 72 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 74 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 75 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixtureRange(1, 4), { Intensity: 255 })
| 76 |
| Expected | fixtureRange(5, 8) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(5, 8), { Intensity: 0 })
| 77 |
| Expected | fixtureRange(9, 12) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixtureRange(9, 12), { Intensity: 255 })
| 78 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 80 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 81 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixtureRange(1, 4), { Intensity: 255 })
| 82 |
| Expected | fixtureRange(5, 8) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(5, 8), { Intensity: 0 })
| 83 |
| Expected | fixtureRange(9, 12) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixtureRange(9, 12), { Intensity: 255 })
| 84 |
Diagnostics
None.
CUE-002 — Cue-only restoration reconstructs identically for sequential GO and direct jumps
tests/44-semantic-cue-recording-and-reconstruction.spec.ts:88 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICommand lineCue runtimeDMX outputEncoder controlsGroupsPlaybacksProgrammerRecordingSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 92 |
Open the ToskLight browser application.t.app.open()
| 93 |
The ToskLight browser application is ready.t.app.expect.ready()
| 94 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → items with ...fixtures = [
1,
2,
3,
4
] t.selection.fixtures.via.api.items(...fixtures)
| 147 |
| Step | Group → api → store with group = 1, {
mode: GroupStoreMode.Overwrite
}t.group.via.api.store(group, { mode: GroupStoreMode.Overwrite })
| 148 |
| Step | Selection → fixtures → api → items with ...fixtures = [
5,
6,
7,
8
] t.selection.fixtures.via.api.items(...fixtures)
| 147 |
| Step | Group → api → store with group = 2, {
mode: GroupStoreMode.Overwrite
}t.group.via.api.store(group, { mode: GroupStoreMode.Overwrite })
| 148 |
| Step | Selection → fixtures → api → items with ...fixtures = [
9,
10,
11,
12
] t.selection.fixtures.via.api.items(...fixtures)
| 147 |
| Step | Group → api → store with group = 3, {
mode: GroupStoreMode.Overwrite
}t.group.via.api.store(group, { mode: GroupStoreMode.Overwrite })
| 148 |
| Step | Clear the current selection. t.selection.clear()
| 150 |
| Step | Execute the desk command "GROUP 1 AT 30". t.command.execute("GROUP 1 AT 30")
| 97 |
| Step | Record → playback with 1. t.record.playback(1)
| 98 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 99 |
| Step | Execute the desk command "GROUP 1 AT 80". t.command.execute("GROUP 1 AT 80")
| 100 |
| Step | Record → cue only with true. t.record.cueOnly(true)
| 101 |
| Step | Record → append with $playback (result of record.playback). t.record.append(playback)
| 102 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 103 |
| Step | Execute the desk command "GROUP 2 AT 60". t.command.execute("GROUP 2 AT 60")
| 104 |
| Step | Record → cue only with false. t.record.cueOnly(false)
| 105 |
| Step | Record → append with $playback (result of record.playback). t.record.append(playback)
| 106 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 107 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 108 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 110 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 111 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 77
}t.expectFixtureDMX(fixtureRange(1, 4), { Intensity: 77 })
| 112 |
| Expected | fixtureRange(5, 8) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(5, 8), { Intensity: 0 })
| 113 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 115 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 116 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 204
}t.expectFixtureDMX(fixtureRange(1, 4), { Intensity: 204 })
| 117 |
| Expected | fixtureRange(5, 8) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(5, 8), { Intensity: 0 })
| 118 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 120 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 121 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 77
}t.expectFixtureDMX(fixtureRange(1, 4), { Intensity: 77 })
| 122 |
| Expected | fixtureRange(5, 8) DMX equals {
Intensity: 153
}t.expectFixtureDMX(fixtureRange(5, 8), { Intensity: 153 })
| 123 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 126 |
| Step | Cue → goto with $playback (result of record.playback), cue = 1. t.cue.goto(playback, cue)
| 127 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 128 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 77
}t.expectFixtureDMX(fixtureRange(1, 4), {
Intensity: cue === 2 ? 204 : 77,
})
| 129 |
| Expected | fixtureRange(5, 8) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(5, 8), {
Intensity: cue === 3 ? 153 : 0,
})
| 132 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 126 |
| Step | Cue → goto with $playback (result of record.playback), cue = 2. t.cue.goto(playback, cue)
| 127 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 128 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 204
}t.expectFixtureDMX(fixtureRange(1, 4), {
Intensity: cue === 2 ? 204 : 77,
})
| 129 |
| Expected | fixtureRange(5, 8) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(5, 8), {
Intensity: cue === 3 ? 153 : 0,
})
| 132 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 126 |
| Step | Cue → goto with $playback (result of record.playback), cue = 3. t.cue.goto(playback, cue)
| 127 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 128 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 77
}t.expectFixtureDMX(fixtureRange(1, 4), {
Intensity: cue === 2 ? 204 : 77,
})
| 129 |
| Expected | fixtureRange(5, 8) DMX equals {
Intensity: 153
}t.expectFixtureDMX(fixtureRange(5, 8), {
Intensity: cue === 3 ? 153 : 0,
})
| 132 |
Diagnostics
None.
CUE-003 — GO, pause, resume, back, and release use exact application-time boundaries
tests/45-semantic-cue-runtime-timing.spec.ts:8 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICue timingDMX outputEncoder controlsPlaybacksProgrammerProgrammer timingRecordingSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 12 |
Open the ToskLight browser application.t.app.open()
| 13 |
The ToskLight browser application is ready.t.app.expect.ready()
| 14 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 15 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 16 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 18 |
| Step | Encoder → intensity → dimmer → api → set with 0. t.encoder.intensity.dimmer.via.api.set(0)
| 19 |
| Step | Record → playback with 1. t.record.playback(1)
| 20 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 21 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 22 |
| Step | Encoder → intensity → dimmer → api → set with 100. t.encoder.intensity.dimmer.via.api.set(100)
| 23 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2,
timing: {
fade: "4"
}
}t.record.cue({ playback, cue: 2, timing: { fade: "4" } })
| 24 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 25 |
| Step | Playback → configure with $playback (result of record.playback), {
buttons: [
PlaybackButton.GoBack,
PlaybackButton.Go,
PlaybackButton.Pause
]
}t.playback.configure(playback, {
buttons: [PlaybackButton.GoBack, PlaybackButton.Go, PlaybackButton.Pause],
})
| 26 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 29 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 31 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 32 |
| Step | Advance the test clock by "1s". t.clock.advanceBy("1s")
| 33 |
| Expected | fixture(1) DMX equals {
Intensity: 64
}t.expectFixtureDMX(fixture(1), { Intensity: 64 })
| 34 |
| Step | Playback → pause with $playback (result of record.playback). t.playback.pause(playback)
| 35 |
| Step | Advance the test clock by "10s". t.clock.advanceBy("10s")
| 36 |
| Expected | fixture(1) DMX equals {
Intensity: 64
}t.expectFixtureDMX(fixture(1), { Intensity: 64 })
| 37 |
| Step | Playback → pause with $playback (result of record.playback). t.playback.pause(playback)
| 38 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 39 |
| Expected | fixture(1) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixture(1), { Intensity: 255 })
| 40 |
| Step | Playback → go back with $playback (result of record.playback). t.playback.goBack(playback)
| 42 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 43 |
| Expected | fixture(1) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixture(1), { Intensity: 255 })
| 44 |
| Step | Advance the test clock by "4s". t.clock.advanceBy("4s")
| 45 |
| Expected | fixture(1) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixture(1), { Intensity: 0 })
| 46 |
| Step | Playback → release with $playback (result of record.playback). t.playback.release(playback)
| 47 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 48 |
| Expected | fixture(1) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixture(1), { Intensity: 0 })
| 49 |
Diagnostics
None.
CUE-004 — per-value timing overrides Cue fallback and Force Cue Timing is reversible
tests/46-semantic-cue-value-timing.spec.ts:7 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineCue runtimeCue timingDMX outputEncoder controlsPlaybacksProgrammerProgrammer timingRecordingShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 11 |
Open the ToskLight browser application.t.app.open()
| 12 |
The ToskLight browser application is ready.t.app.expect.ready()
| 13 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 14 |
| Step | Execute the desk command "GROUP 1 AT 0". t.command.execute("GROUP 1 AT 0")
| 16 |
| Step | Record → playback with 1. t.record.playback(1)
| 17 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 18 |
| Step | Timing → programmer fade → api → set with "9s". t.timing.programmerFade.via.api.set("9s")
| 20 |
| Step | Execute the desk command "GROUP 1 AT 50 TIME 2". t.command.execute("GROUP 1 AT 50 TIME 2")
| 21 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2,
timing: {
fade: "3"
}
}t.record.cue({ playback, cue: 2, timing: { fade: "3" } })
| 22 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 23 |
| Expected | Cue → metadata: $playback (result of record.playback), 2, {
fade_millis: 3000,
delay_millis: 0
}t.cue.expect(playback, 2).metadata({
fade_millis: 3_000,
delay_millis: 0,
})
| 24 |
| Expected | Cue → group value timing: $playback (result of record.playback), 2, 1, "intensity", {
fade: "2s"
}t.cue
.expect(playback, 2)
.groupValueTiming(1, "intensity", { fade: "2s" })
| 28 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 32 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 33 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 34 |
| Step | Advance the test clock by "1999ms". t.clock.advanceBy("1999ms")
| 35 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 127
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 127 })
| 36 |
| Step | Advance the test clock by "1ms". t.clock.advanceBy("1ms")
| 37 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 128 })
| 38 |
Diagnostics
None.
CUE-005 — GO, FOLLOW, and TIME retain their distinct Cue trigger meanings
tests/47-semantic-cue-trigger-and-selection.spec.ts:8 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand keypadCommand lineCue runtimeCue timingProgrammer timingRecordingShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 12 |
Open the ToskLight browser application.t.app.open()
| 13 |
The ToskLight browser application is ready.t.app.expect.ready()
| 14 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 15 |
| Step | Execute the desk command "GROUP 1 AT 50". t.command.execute("GROUP 1 AT 50")
| 17 |
| Step | Record → playback with 1. t.record.playback(1)
| 18 |
| Step | Command → type with "RECORD PBK 1 CUE 2 TIME TIME 0". t.command.type("RECORD PBK 1 CUE 2 TIME TIME 0")
| 19 |
| Expected | Command line shows "RECORD PBK 1 CUE 2 DELAY 0". t.command.expect("RECORD PBK 1 CUE 2 DELAY 0")
| 20 |
| Step | Press keypad keys [
"ENT"
] t.keypad.press(["ENT"])
| 21 |
| Step | Command → type with "RECORD PBK 1 CUE 3 TIME TIME 4". t.command.type("RECORD PBK 1 CUE 3 TIME TIME 4")
| 22 |
| Expected | Command line shows "RECORD PBK 1 CUE 3 DELAY 4". t.command.expect("RECORD PBK 1 CUE 3 DELAY 4")
| 23 |
| Step | Press keypad keys [
"ENT"
] t.keypad.press(["ENT"])
| 24 |
| Expected | Cue → trigger: $playback (result of record.playback), 1, {
type: "manual"
}t.cue.expect(playback, 1).trigger({ type: "manual" })
| 26 |
| Expected | Cue → trigger: $playback (result of record.playback), 2, {
type: "follow",
delay_millis: 0
}t.cue
.expect(playback, 2)
.trigger({ type: "follow", delay_millis: 0 })
| 27 |
| Expected | Cue → trigger: $playback (result of record.playback), 3, {
type: "wait",
delay_millis: 4000
}t.cue
.expect(playback, 3)
.trigger({ type: "wait", delay_millis: 4_000 })
| 30 |
Diagnostics
None.
CUE-006 — explicit playback selection supplies the implicit Cuelist without following execution order
tests/47-semantic-cue-trigger-and-selection.spec.ts:36 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineCue runtimeCue timingEncoder controlsPlaybacksProgrammerProgrammer timingRecordingSelectionShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 40 |
Open the ToskLight browser application.t.app.open()
| 41 |
The ToskLight browser application is ready.t.app.expect.ready()
| 42 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 43 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 45 |
| Step | Encoder → intensity → dimmer → api → set with 20. t.encoder.intensity.dimmer.via.api.set(20)
| 46 |
| Step | Record → playback with 1. t.record.playback(1)
| 47 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 48 |
| Step | Selection → fixtures → api → item with 2. t.selection.fixtures.via.api.item(2)
| 49 |
| Step | Encoder → intensity → dimmer → api → set with 30. t.encoder.intensity.dimmer.via.api.set(30)
| 50 |
| Step | Record → playback with 2. t.record.playback(2)
| 51 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 52 |
| Step | Playback → select with $second (result of record.playback). t.playback.select(second)
| 54 |
| Expected | Playback → selected: $second (result of record.playback). t.playback.expect(second).selected()
| 55 |
| Step | Playback → go with $first (result of record.playback). t.playback.go(first)
| 56 |
| Expected | Playback → selected: $second (result of record.playback). t.playback.expect(second).selected()
| 57 |
| Step | Selection → fixtures → api → item with 3. t.selection.fixtures.via.api.item(3)
| 59 |
| Step | Encoder → intensity → dimmer → api → set with 70. t.encoder.intensity.dimmer.via.api.set(70)
| 60 |
| Step | Execute the desk command "RECORD CUE 7". t.command.execute("RECORD CUE 7")
| 61 |
| Expected | Cue → present: $second (result of record.playback), 7. t.cue.expect(second, 7).present()
| 62 |
| Expected | Cue → absent: $first (result of record.playback), 7. t.cue.expect(first, 7).absent()
| 63 |
| Expected | Playback → selected: $second (result of record.playback). t.playback.expect(second).selected()
| 64 |
Diagnostics
None.
CUE-007 — explicit zeroes block a later inserted on Cue from tracking past Cue 4
tests/47-semantic-cue-trigger-and-selection.spec.ts:68 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineCue runtimeCue timingDMX outputEncoder controlsGroupsPlaybacksProgrammerProgrammer timingRecordingSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 72 |
Open the ToskLight browser application.t.app.open()
| 73 |
The ToskLight browser application is ready.t.app.expect.ready()
| 74 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 75 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 76 |
| Step | Selection → fixtures → api → items with 1, 2, 3, 4. t.selection.fixtures.via.api.items(1, 2, 3, 4)
| 78 |
| Step | Group → api → store with 1, {
mode: StoreMode.Overwrite
}t.group.via.api.store(1, { mode: StoreMode.Overwrite })
| 79 |
| Step | Selection → fixtures → api → items with 5, 6, 7, 8. t.selection.fixtures.via.api.items(5, 6, 7, 8)
| 80 |
| Step | Group → api → store with 2, {
mode: StoreMode.Overwrite
}t.group.via.api.store(2, { mode: StoreMode.Overwrite })
| 81 |
| Step | Selection → fixtures → api → items with 9, 10, 11, 12. t.selection.fixtures.via.api.items(9, 10, 11, 12)
| 82 |
| Step | Group → api → store with 3, {
mode: StoreMode.Overwrite
}t.group.via.api.store(3, { mode: StoreMode.Overwrite })
| 83 |
| Step | Clear the current selection. t.selection.clear()
| 84 |
| Step | Execute the desk command "GROUP 1 AT 100". t.command.execute("GROUP 1 AT 100")
| 85 |
| Step | Record → playback with 1. t.record.playback(1)
| 86 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 87 |
| Step | Execute the desk command "GROUP 1 AT 0". t.command.execute("GROUP 1 AT 0")
| 88 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 89 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 90 |
| Step | Execute the desk command "GROUP 2 AT 100". t.command.execute("GROUP 2 AT 100")
| 91 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 3
}t.record.cue({ playback, cue: 3 })
| 92 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 93 |
| Step | Execute the desk command "GROUP 1 AT 0". t.command.execute("GROUP 1 AT 0")
| 94 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 4
}t.record.cue({ playback, cue: 4 })
| 95 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 96 |
| Step | Execute the desk command "GROUP 3 AT 100". t.command.execute("GROUP 3 AT 100")
| 97 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 5
}t.record.cue({ playback, cue: 5 })
| 98 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 99 |
| Step | Execute the desk command "GROUP 1 AT 100". t.command.execute("GROUP 1 AT 100")
| 100 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 3.5
}t.record.cue({ playback, cue: 3.5 })
| 101 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 102 |
| Expected | Cue → group value: $playback (result of record.playback), 1, 1, "intensity", 1. t.cue.expect(playback, 1).groupValue(1, "intensity", 1)
| 104 |
| Expected | Cue → group value: $playback (result of record.playback), 4, 1, "intensity", 0. t.cue.expect(playback, 4).groupValue(1, "intensity", 0)
| 105 |
| Step | Playback → release with $playback (result of record.playback). t.playback.release(playback)
| 106 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 107 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 108 |
| Expected | Playback → runtime: $playback (result of record.playback), {
current_cue_number: "1"
}t.playback.expect(playback).runtime({ current_cue_number: "1" })
| 109 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixtureRange(1, 4), { Intensity: 255 })
| 110 |
| Expected | fixtureRange(5, 12) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(5, 12), { Intensity: 0 })
| 111 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 112 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 113 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 0 })
| 114 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 115 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 116 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(1, 4), { Intensity: 0 })
| 117 |
| Expected | fixtureRange(5, 8) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixtureRange(5, 8), { Intensity: 255 })
| 118 |
| Expected | fixtureRange(9, 12) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(9, 12), { Intensity: 0 })
| 119 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 120 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 121 |
| Expected | fixtureRange(1, 8) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixtureRange(1, 8), { Intensity: 255 })
| 122 |
| Expected | fixtureRange(9, 12) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(9, 12), { Intensity: 0 })
| 123 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 124 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 125 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(1, 4), { Intensity: 0 })
| 126 |
| Expected | fixtureRange(5, 8) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixtureRange(5, 8), { Intensity: 255 })
| 127 |
| Expected | fixtureRange(9, 12) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(9, 12), { Intensity: 0 })
| 128 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 129 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 130 |
| Expected | fixtureRange(1, 4) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixtureRange(1, 4), { Intensity: 0 })
| 131 |
| Expected | fixtureRange(5, 12) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixtureRange(5, 12), { Intensity: 255 })
| 132 |
Diagnostics
None.
CUE-010 — tracking and LTP ownership stay per attribute and reveal the underlying programmer
tests/48-semantic-cue-tracking-and-merge.spec.ts:8 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICue runtimeCue timingEncoder controlsPlaybacksProgrammerProgrammer timingRecordingResolved outputSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 12 |
Open the ToskLight browser application.t.app.open()
| 13 |
The ToskLight browser application is ready.t.app.expect.ready()
| 14 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 15 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 16 |
| Step | Selection → fixtures → api → item with 21. t.selection.fixtures.via.api.item(21)
| 18 |
| Step | Encoder → intensity → dimmer → api → set with 100. t.encoder.intensity.dimmer.via.api.set(100)
| 19 |
| Step | Record → playback with 1. t.record.playback(1)
| 20 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 21 |
| Step | Selection → fixtures → api → item with 21. t.selection.fixtures.via.api.item(21)
| 22 |
| Step | Encoder → intensity → dimmer → api → set with 50. t.encoder.intensity.dimmer.via.api.set(50)
| 23 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 24 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 25 |
| Step | Selection → fixtures → api → item with 21. t.selection.fixtures.via.api.item(21)
| 26 |
| Step | Encoder → color → red → api → set with 0. t.encoder.color.red.via.api.set(0)
| 27 |
| Step | Encoder → color → green → api → set with 0. t.encoder.color.green.via.api.set(0)
| 28 |
| Step | Encoder → color → blue → api → set with 100. t.encoder.color.blue.via.api.set(100)
| 29 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 3
}t.record.cue({ playback, cue: 3 })
| 30 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 31 |
| Step | Clear the current selection. t.selection.clear()
| 32 |
| Step | Selection → fixtures → api → item with 2. t.selection.fixtures.via.api.item(2)
| 33 |
| Step | Encoder → intensity → dimmer → api → set with 40. t.encoder.intensity.dimmer.via.api.set(40)
| 34 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 4
}t.record.cue({ playback, cue: 4 })
| 35 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 36 |
| Step | Playback → configure with $playback (result of record.playback), {
buttons: [
PlaybackButton.GoBack,
PlaybackButton.Go,
PlaybackButton.Off
]
}t.playback.configure(playback, {
buttons: [PlaybackButton.GoBack, PlaybackButton.Go, PlaybackButton.Off],
})
| 37 |
| Step | Cue → configure with $playback (result of record.playback), {
priority: 100
}t.cue.configure(playback, { priority: 100 })
| 40 |
| Step | Programmer → priority → api → set with 100. t.programmer.priority.via.api.set(100)
| 41 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 42 |
| Step | Selection → fixtures → api → item with 21. t.selection.fixtures.via.api.item(21)
| 44 |
| Step | Encoder → color → red → api → set with 0. t.encoder.color.red.via.api.set(0)
| 45 |
| Step | Encoder → color → green → api → set with 100. t.encoder.color.green.via.api.set(100)
| 46 |
| Step | Encoder → color → blue → api → set with 0. t.encoder.color.blue.via.api.set(0)
| 47 |
| Step | Advance the test clock by "1ms". t.clock.advanceBy("1ms")
| 48 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 50 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 51 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 52 |
| Expected | fixture(21) resolved values equal {
intensity: 0.5,
"color:red": 0,
"color:green": 1,
"color:blue": 0
}t.expectFixtureValue(fixture(21), {
intensity: 0.5,
"color:red": 0,
"color:green": 1,
"color:blue": 0,
})
| 53 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 59 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 60 |
| Expected | fixture(21) resolved values equal {
intensity: 0.5,
"color:red": 0,
"color:green": 0,
"color:blue": 1
}t.expectFixtureValue(fixture(21), {
intensity: 0.5,
"color:red": 0,
"color:green": 0,
"color:blue": 1,
})
| 61 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 67 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 68 |
| Expected | fixture(21) resolved values equal {
intensity: 0.5,
"color:red": 0,
"color:green": 0,
"color:blue": 1
}t.expectFixtureValue(fixture(21), {
intensity: 0.5,
"color:red": 0,
"color:green": 0,
"color:blue": 1,
})
| 69 |
| Step | Playback → off with $playback (result of record.playback). t.playback.off(playback)
| 75 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 76 |
| Expected | fixture(21) resolved values equal {
intensity: 0,
"color:red": 0,
"color:green": 1,
"color:blue": 0
}t.expectFixtureValue(fixture(21), {
intensity: 0,
"color:red": 0,
"color:green": 1,
"color:blue": 0,
})
| 77 |
Diagnostics
None.
MERGE-002 — independent Sequences coexist and retrigger only their stored addresses
tests/48-semantic-cue-tracking-and-merge.spec.ts:86 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineCue runtimeCue timingEncoder controlsPlaybacksProgrammerProgrammer timingRecordingResolved outputSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 90 |
Open the ToskLight browser application.t.app.open()
| 91 |
The ToskLight browser application is ready.t.app.expect.ready()
| 92 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 93 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 94 |
| Step | Programmer → priority → api → set with 100. t.programmer.priority.via.api.set(100)
| 95 |
| Step | Selection → fixtures → api → item with 21. t.selection.fixtures.via.api.item(21)
| 97 |
| Step | Encoder → intensity → dimmer → api → set with 60. t.encoder.intensity.dimmer.via.api.set(60)
| 98 |
| Step | Encoder → color → red → api → set with 0. t.encoder.color.red.via.api.set(0)
| 99 |
| Step | Encoder → color → green → api → set with 0. t.encoder.color.green.via.api.set(0)
| 100 |
| Step | Encoder → color → blue → api → set with 100. t.encoder.color.blue.via.api.set(100)
| 101 |
| Step | Record → playback with 1. t.record.playback(1)
| 102 |
| Step | Playback → configure with $sequenceA (result of record.playback), {
name: "Sequence A",
buttons: [
PlaybackButton.On,
PlaybackButton.Go,
PlaybackButton.Off
]
}t.playback.configure(sequenceA, {
name: "Sequence A",
buttons: [PlaybackButton.On, PlaybackButton.Go, PlaybackButton.Off],
})
| 103 |
| Step | Cue → configure with $sequenceA (result of record.playback), {
priority: 100
}t.cue.configure(sequenceA, { priority: 100 })
| 107 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 108 |
| Step | Clear the current selection. t.selection.clear()
| 109 |
| Step | Selection → fixtures → api → item with 22. t.selection.fixtures.via.api.item(22)
| 111 |
| Step | Encoder → intensity → dimmer → api → set with 40. t.encoder.intensity.dimmer.via.api.set(40)
| 112 |
| Step | Encoder → color → red → api → set with 100. t.encoder.color.red.via.api.set(100)
| 113 |
| Step | Encoder → color → green → api → set with 70. t.encoder.color.green.via.api.set(70)
| 114 |
| Step | Encoder → color → blue → api → set with 40. t.encoder.color.blue.via.api.set(40)
| 115 |
| Step | Record → playback with 2. t.record.playback(2)
| 116 |
| Step | Playback → configure with $sequenceB (result of record.playback), {
name: "Sequence B",
buttons: [
PlaybackButton.On,
PlaybackButton.Go,
PlaybackButton.Off
]
}t.playback.configure(sequenceB, {
name: "Sequence B",
buttons: [PlaybackButton.On, PlaybackButton.Go, PlaybackButton.Off],
})
| 117 |
| Step | Cue → configure with $sequenceB (result of record.playback), {
priority: 100
}t.cue.configure(sequenceB, { priority: 100 })
| 121 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 122 |
| Step | Clear the current selection. t.selection.clear()
| 123 |
| Step | Playback → api → off with $sequenceA (result of record.playback). t.playback.via.api.off(sequenceA)
| 124 |
| Step | Playback → api → off with $sequenceB (result of record.playback). t.playback.via.api.off(sequenceB)
| 125 |
| Step | Playback → api → on with $sequenceA (result of record.playback). t.playback.via.api.on(sequenceA)
| 126 |
| Step | Playback → api → on with $sequenceB (result of record.playback). t.playback.via.api.on(sequenceB)
| 127 |
| Step | Advance the test clock by "1ms". t.clock.advanceBy("1ms")
| 128 |
| Step | Selection → fixtures → api → item with 21. t.selection.fixtures.via.api.item(21)
| 130 |
| Step | Encoder → color → red → api → set with 100. t.encoder.color.red.via.api.set(100)
| 131 |
| Step | Clear the current selection. t.selection.clear()
| 132 |
| Step | Selection → fixtures → api → item with 22. t.selection.fixtures.via.api.item(22)
| 133 |
| Step | Encoder → color → blue → api → set with 80. t.encoder.color.blue.via.api.set(80)
| 134 |
| Step | Advance the test clock by "1ms". t.clock.advanceBy("1ms")
| 135 |
| Expected | fixture(22) resolved values equal {
"color:blue": 0.8
}t.expectFixtureValue(fixture(22), { "color:blue": 0.8 })
| 136 |
| Step | Command → clear. t.command.clear()
| 138 |
| Step | Playback → select with $sequenceA (result of record.playback). t.playback.select(sequenceA)
| 139 |
| Step | Cue → goto with $sequenceA (result of record.playback), 1. t.cue.goto(sequenceA, 1)
| 141 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 142 |
| Expected | fixture(21) resolved values equal {
intensity: 0.6,
"color:red": 0,
"color:green": 0,
"color:blue": 1
}t.expectFixtureValue(fixture(21), {
intensity: 0.6,
"color:red": 0,
"color:green": 0,
"color:blue": 1,
})
| 143 |
| Expected | fixture(22) resolved values equal {
intensity: 0.4,
"color:red": 1,
"color:green": 0.7,
"color:blue": 0.8
}t.expectFixtureValue(fixture(22), {
intensity: 0.4,
"color:red": 1,
"color:green": 0.7,
"color:blue": 0.8,
})
| 149 |
Diagnostics
None.
MERGE-003 — full normal overwrite auto-Offs while partial, disabled, Flash, and Temp restore
tests/48-semantic-cue-tracking-and-merge.spec.ts:158 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICue timingEncoder controlsPlaybacksProgrammerProgrammer timingRecordingResolved outputSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 162 |
Open the ToskLight browser application.t.app.open()
| 163 |
The ToskLight browser application is ready.t.app.expect.ready()
| 164 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 165 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 166 |
| Step | Selection → fixtures → api → item with 21. t.selection.fixtures.via.api.item(21)
| 176 |
| Step | Encoder → color → red → api → set with 0. t.encoder.color.red.via.api.set(color[0])
| 179 |
| Step | Encoder → color → green → api → set with 0. t.encoder.color.green.via.api.set(color[1])
| 180 |
| Step | Encoder → color → blue → api → set with 100. t.encoder.color.blue.via.api.set(color[2])
| 181 |
| Step | Record → playback with number = 1. t.record.playback(number)
| 182 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Underlying blue",
autoOff: autoOff = true,
buttons: buttons = [
PlaybackButton.On,
PlaybackButton.Off,
PlaybackButton.Empty
]
}t.playback.configure(playback, { name, autoOff, buttons })
| 183 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 184 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 185 |
| Step | Selection → fixtures → api → item with 21. t.selection.fixtures.via.api.item(21)
| 176 |
| Step | Encoder → color → red → api → set with 100. t.encoder.color.red.via.api.set(color[0])
| 179 |
| Step | Encoder → color → green → api → set with 0. t.encoder.color.green.via.api.set(color[1])
| 180 |
| Step | Encoder → color → blue → api → set with 0. t.encoder.color.blue.via.api.set(color[2])
| 181 |
| Step | Record → playback with number = 2. t.record.playback(number)
| 182 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Replacing red",
autoOff: autoOff = false,
buttons: buttons = [
PlaybackButton.On,
PlaybackButton.Flash,
PlaybackButton.Temp
]
}t.playback.configure(playback, { name, autoOff, buttons })
| 183 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 184 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 185 |
| Step | Selection → fixtures → api → item with 21. t.selection.fixtures.via.api.item(21)
| 176 |
| Step | Encoder → intensity → dimmer → api → set with intensity = 100. t.encoder.intensity.dimmer.via.api.set(intensity)
| 178 |
| Step | Encoder → color → red → api → set with 0. t.encoder.color.red.via.api.set(color[0])
| 179 |
| Step | Encoder → color → green → api → set with 0. t.encoder.color.green.via.api.set(color[1])
| 180 |
| Step | Encoder → color → blue → api → set with 100. t.encoder.color.blue.via.api.set(color[2])
| 181 |
| Step | Record → playback with number = 3. t.record.playback(number)
| 182 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Partial underlying blue",
autoOff: autoOff = true,
buttons: buttons = [
PlaybackButton.On,
PlaybackButton.Off,
PlaybackButton.Empty
]
}t.playback.configure(playback, { name, autoOff, buttons })
| 183 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 184 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 185 |
| Step | Selection → fixtures → api → item with 21. t.selection.fixtures.via.api.item(21)
| 176 |
| Step | Encoder → color → red → api → set with 100. t.encoder.color.red.via.api.set(color[0])
| 179 |
| Step | Encoder → color → green → api → set with 0. t.encoder.color.green.via.api.set(color[1])
| 180 |
| Step | Encoder → color → blue → api → set with 0. t.encoder.color.blue.via.api.set(color[2])
| 181 |
| Step | Record → playback with number = 4. t.record.playback(number)
| 182 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Partial replacing red",
autoOff: autoOff = false,
buttons: buttons = [
PlaybackButton.On,
PlaybackButton.Flash,
PlaybackButton.Temp
]
}t.playback.configure(playback, { name, autoOff, buttons })
| 183 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 184 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 185 |
| Expected | Playback → configuration: $underlying (result of recordLook), {
auto_off: true
}t.playback.expect(underlying).configuration({ auto_off: true })
| 221 |
| Expected | Playback → configuration: $replacing (result of recordLook), {
auto_off: false
}t.playback.expect(replacing).configuration({ auto_off: false })
| 222 |
| Step | Playback → on with $underlying (result of recordLook). t.playback.on(underlying)
| 224 |
| Step | Advance the test clock by "1ms". t.clock.advanceBy("1ms")
| 225 |
| Step | Playback → on with $replacing (result of recordLook). t.playback.on(replacing)
| 226 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 227 |
| Expected | Playback → runtime: $underlying (result of recordLook), {
enabled: false
}t.playback.expect(underlying).runtime({ enabled: false })
| 228 |
| Expected | fixture(21) resolved values equal {
"color:red": 1,
"color:green": 0,
"color:blue": 0
}t.expectFixtureValue(fixture(21), {
"color:red": 1,
"color:green": 0,
"color:blue": 0,
})
| 229 |
| Step | Playback → configure with $underlying (result of recordLook), {
autoOff: false
}t.playback.configure(underlying, { autoOff: false })
| 235 |
| Step | Playback → api → off with $replacing (result of recordLook). t.playback.via.api.off(replacing)
| 236 |
| Step | Playback → on with $underlying (result of recordLook). t.playback.on(underlying)
| 237 |
| Step | Advance the test clock by "1ms". t.clock.advanceBy("1ms")
| 238 |
| Step | Playback → on with $replacing (result of recordLook). t.playback.on(replacing)
| 239 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 240 |
| Expected | Playback → runtime: $underlying (result of recordLook), {
enabled: true
}t.playback.expect(underlying).runtime({ enabled: true })
| 241 |
| Step | Playback → api → off with $replacing (result of recordLook). t.playback.via.api.off(replacing)
| 242 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 243 |
| Expected | fixture(21) resolved values equal {
"color:red": 0,
"color:green": 0,
"color:blue": 1
}t.expectFixtureValue(fixture(21), {
"color:red": 0,
"color:green": 0,
"color:blue": 1,
})
| 244 |
| Step | Playback → configure with $underlying (result of recordLook), {
autoOff: true
}t.playback.configure(underlying, { autoOff: true })
| 250 |
| Step | Advance the test clock by "1ms". t.clock.advanceBy("1ms")
| 251 |
| Step | Playback → ui → flash → hold with $replacing (result of recordLook), <generated: callback>. t.playback.via.ui.flash(replacing).hold(async () => {
await t.playback.expect(replacing).runtime({ enabled: false, flash: true });
await t.clock.advanceStep();
await t.playback.expect(underlying).runtime({ enabled: true });
await t.expectFixtureValue(fixture(21), {
"color:red": 1,
"color:green": 0,
"color:blue": 0,
});
})
| 252 |
| Expected | Playback → runtime: $replacing (result of recordLook), {
enabled: false,
flash: true
}t.playback.expect(replacing).runtime({ enabled: false, flash: true })
| 253 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 254 |
| Expected | Playback → runtime: $underlying (result of recordLook), {
enabled: true
}t.playback.expect(underlying).runtime({ enabled: true })
| 255 |
| Expected | fixture(21) resolved values equal {
"color:red": 1,
"color:green": 0,
"color:blue": 0
}t.expectFixtureValue(fixture(21), {
"color:red": 1,
"color:green": 0,
"color:blue": 0,
})
| 256 |
| Expected | Playback → runtime: $replacing (result of recordLook), {
enabled: false,
flash: false
}t.playback.expect(replacing).runtime({ enabled: false, flash: false })
| 263 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 264 |
| Expected | fixture(21) resolved values equal {
"color:red": 0,
"color:green": 0,
"color:blue": 1
}t.expectFixtureValue(fixture(21), {
"color:red": 0,
"color:green": 0,
"color:blue": 1,
})
| 265 |
| Step | Playback → ui → temp with $replacing (result of recordLook). t.playback.via.ui.temp(replacing)
| 271 |
| Expected | Playback → runtime: $replacing (result of recordLook), {
temporary_active: true
}t.playback.expect(replacing).runtime({ temporary_active: true })
| 272 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 273 |
| Expected | Playback → runtime: $underlying (result of recordLook), {
enabled: true
}t.playback.expect(underlying).runtime({ enabled: true })
| 274 |
| Expected | fixture(21) resolved values equal {
"color:red": 1,
"color:green": 0,
"color:blue": 0
}t.expectFixtureValue(fixture(21), {
"color:red": 1,
"color:green": 0,
"color:blue": 0,
})
| 275 |
| Step | Playback → ui → temp with $replacing (result of recordLook). t.playback.via.ui.temp(replacing)
| 280 |
| Expected | Playback → runtime: $replacing (result of recordLook), {
enabled: false,
temporary_active: false
}t.playback.expect(replacing).runtime({ enabled: false, temporary_active: false })
| 281 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 282 |
| Expected | fixture(21) resolved values equal {
"color:red": 0,
"color:green": 0,
"color:blue": 1
}t.expectFixtureValue(fixture(21), {
"color:red": 0,
"color:green": 0,
"color:blue": 1,
})
| 283 |
| Step | Playback → api → off with $underlying (result of recordLook). t.playback.via.api.off(underlying)
| 289 |
| Step | Playback → api → off with $replacing (result of recordLook). t.playback.via.api.off(replacing)
| 290 |
| Step | Playback → on with $partialUnderlying (result of recordLook). t.playback.on(partialUnderlying)
| 291 |
| Step | Advance the test clock by "1ms". t.clock.advanceBy("1ms")
| 292 |
| Step | Playback → on with $partialReplacing (result of recordLook). t.playback.on(partialReplacing)
| 293 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 294 |
| Expected | Playback → runtime: $partialUnderlying (result of recordLook), {
enabled: true
}t.playback.expect(partialUnderlying).runtime({ enabled: true })
| 295 |
| Expected | fixture(21) resolved values equal {
intensity: 1,
"color:red": 1,
"color:green": 0,
"color:blue": 0
}t.expectFixtureValue(fixture(21), {
intensity: 1,
"color:red": 1,
"color:green": 0,
"color:blue": 0,
})
| 296 |
Diagnostics
None.
CUE-009 — explicit Plain/Status Move/Copy choices preserve both independent axes
tests/49-semantic-cue-transfer-speed-and-navigation.spec.ts:8 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineCue runtimeEncoder controlsProgrammerRecordingSelectionShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 12 |
Open the ToskLight browser application.t.app.open()
| 13 |
The ToskLight browser application is ready.t.app.expect.ready()
| 14 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 16 |
| Step | Encoder → intensity → dimmer → api → set with 25. t.encoder.intensity.dimmer.via.api.set(25)
| 17 |
| Step | Record → playback with 1. t.record.playback(1)
| 18 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 19 |
| Step | Encoder → intensity → dimmer → api → set with 50. t.encoder.intensity.dimmer.via.api.set(50)
| 20 |
| Step | Record → cue with {
playback: $source (result of record.playback),
cue: 2
}t.record.cue({ playback: source, cue: 2 })
| 21 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 22 |
| Step | Encoder → intensity → dimmer → api → set with 75. t.encoder.intensity.dimmer.via.api.set(75)
| 23 |
| Step | Record → playback with 2. t.record.playback(2)
| 24 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 25 |
| Expected | Cue → present: $source (result of record.playback), 2. t.cue.expect(source, 2).present()
| 27 |
| Expected | Cue → absent: $destination (result of record.playback), 2. t.cue.expect(destination, 2).absent()
| 28 |
| Step | Execute the desk command "COPY CUELIST 1 CUE 2 AT CUELIST 2 CUE 2". t.command.execute("COPY CUELIST 1 CUE 2 AT CUELIST 2 CUE 2")
| 29 |
| Step | Cue → transfer choice → cancel with "COPY". t.cue.transferChoice("COPY").cancel()
| 30 |
| Expected | Cue → present: $source (result of record.playback), 2. t.cue.expect(source, 2).present()
| 31 |
| Expected | Cue → absent: $destination (result of record.playback), 2. t.cue.expect(destination, 2).absent()
| 32 |
Diagnostics
None.
CMD-002 — Speed Group commands address, synchronize, display, and manually unlink all five groups
tests/49-semantic-cue-transfer-speed-and-navigation.spec.ts:36 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UICommand lineShow filesSpeed Groups
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 40 |
Open the ToskLight browser application.t.app.open()
| 41 |
The ToskLight browser application is ready.t.app.expect.ready()
| 42 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "SPD GRP 1 AT 120". t.command.execute("SPD GRP 1 AT 120")
| 44 |
| Expected | Speed group → A → bpm: 120. t.speedGroup.A.expect.bpm(120)
| 45 |
| Step | Execute the desk command "SPD GRP 2 AT 127.5". t.command.execute("SPD GRP 2 AT 127.5")
| 46 |
| Expected | Speed group → B → bpm: 127.5. t.speedGroup.B.expect.bpm(127.5)
| 47 |
| Step | Execute the desk command "SPD GRP 3 AT 131". t.command.execute("SPD GRP 3 AT 131")
| 48 |
| Expected | Speed group → C → bpm: 131. t.speedGroup.C.expect.bpm(131)
| 49 |
| Step | Execute the desk command "SPD GRP 4 AT 142". t.command.execute("SPD GRP 4 AT 142")
| 50 |
| Expected | Speed group → D → bpm: 142. t.speedGroup.D.expect.bpm(142)
| 51 |
| Step | Execute the desk command "SPD GRP 5 AT 153". t.command.execute("SPD GRP 5 AT 153")
| 52 |
| Expected | Speed group → E → bpm: 153. t.speedGroup.E.expect.bpm(153)
| 53 |
| Step | Execute the desk command "SPD GRP 1 AT + 5". t.command.execute("SPD GRP 1 AT + 5")
| 55 |
| Expected | Speed group → A → bpm: 125. t.speedGroup.A.expect.bpm(125)
| 56 |
| Step | Execute the desk command "SPD GRP 1 AT - 5". t.command.execute("SPD GRP 1 AT - 5")
| 57 |
| Expected | Speed group → A → bpm: 120. t.speedGroup.A.expect.bpm(120)
| 58 |
| Step | Execute the desk command "SPD GRP 3 AT 90". t.command.execute("SPD GRP 3 AT 90")
| 59 |
| Step | Execute the desk command "SPD GRP 1 AT SPD GRP 3". t.command.execute("SPD GRP 1 AT SPD GRP 3")
| 60 |
| Expected | Speed group → C → synchronized from: "A". t.speedGroup.C.expect.synchronizedFrom(t.speedGroup.A.group)
| 61 |
| Expected | Speed group → C → bpm: 120. t.speedGroup.C.expect.bpm(120)
| 62 |
| Step | Speed group → A → click → tap tempo with 80, 5. t.speedGroup.A.via.click.tapTempo(80, 5)
| 64 |
| Expected | Speed group → A → bpm within: 80, 2. t.speedGroup.A.expect.bpmWithin(80, 2)
| 65 |
| Expected | Speed group → A → synchronized from: null. t.speedGroup.A.expect.synchronizedFrom(null)
| 66 |
| Expected | Speed group → C → bpm: 120. t.speedGroup.C.expect.bpm(120)
| 67 |
| Expected | Speed group → C → synchronized from: null. t.speedGroup.C.expect.synchronizedFrom(null)
| 68 |
| Step | Execute the desk command "SPD GRP 1 AT 85". t.command.execute("SPD GRP 1 AT 85")
| 70 |
| Expected | Speed group → A → bpm: 85. t.speedGroup.A.expect.bpm(85)
| 71 |
| Expected | Speed group → C → bpm: 120. t.speedGroup.C.expect.bpm(120)
| 72 |
Diagnostics
None.
CUE-014 — Cue Go To and Load preserve desk-local selection and authoritative output controls
tests/49-semantic-cue-transfer-speed-and-navigation.spec.ts:76 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineCue timingDMX outputEncoder controlsPlaybacksProgrammerProgrammer timingRecordingSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 80 |
Open the ToskLight browser application.t.app.open()
| 81 |
The ToskLight browser application is ready.t.app.expect.ready()
| 82 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 83 |
| Step | Timing → cue fade → set with "3s". t.timing.cueFade.set("3s")
| 84 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 87 |
| Step | Encoder → intensity → dimmer → api → set with 20. t.encoder.intensity.dimmer.via.api.set(20)
| 88 |
| Step | Record → playback with slot = 1. t.record.playback(slot)
| 89 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 90 |
| Step | Encoder → intensity → dimmer → api → set with 50. t.encoder.intensity.dimmer.via.api.set(50)
| 91 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 92 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 93 |
| Step | Encoder → intensity → dimmer → api → set with 80. t.encoder.intensity.dimmer.via.api.set(80)
| 94 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 3
}t.record.cue({ playback, cue: 3 })
| 95 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 96 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Twin A",
buttons: [
PlaybackButton.GoBack,
PlaybackButton.Go,
PlaybackButton.Off
]
}t.playback.configure(playback, {
name,
buttons: [PlaybackButton.GoBack, PlaybackButton.Go, PlaybackButton.Off],
})
| 97 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 101 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 87 |
| Step | Encoder → intensity → dimmer → api → set with 20. t.encoder.intensity.dimmer.via.api.set(20)
| 88 |
| Step | Record → playback with slot = 2. t.record.playback(slot)
| 89 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 90 |
| Step | Encoder → intensity → dimmer → api → set with 50. t.encoder.intensity.dimmer.via.api.set(50)
| 91 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 92 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 93 |
| Step | Encoder → intensity → dimmer → api → set with 80. t.encoder.intensity.dimmer.via.api.set(80)
| 94 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 3
}t.record.cue({ playback, cue: 3 })
| 95 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 96 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Twin B",
buttons: [
PlaybackButton.GoBack,
PlaybackButton.Go,
PlaybackButton.Off
]
}t.playback.configure(playback, {
name,
buttons: [PlaybackButton.GoBack, PlaybackButton.Go, PlaybackButton.Off],
})
| 97 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 101 |
| Step | Command → clear. t.command.clear()
| 107 |
| Step | Playback → select with $second (result of recordSequence). t.playback.select(second)
| 108 |
| Step | Playback → go with $first (result of recordSequence). t.playback.go(first)
| 109 |
| Expected | Playback → runtime: $first (result of recordSequence), {
current_cue_number: "1"
}t.playback.expect(first).runtime({ current_cue_number: "1" })
| 110 |
| Expected | Playback → selected: $second (result of recordSequence). t.playback.expect(second).selected()
| 111 |
| Step | Execute the desk command "GO TO PBK 2 CUE 3". t.command.execute("GO TO PBK 2 CUE 3")
| 113 |
| Expected | Playback → runtime: $second (result of recordSequence), {
current_cue_number: "3",
master: 1,
enabled: true
}t.playback.expect(second).runtime({
current_cue_number: "3",
master: 1,
enabled: true,
})
| 114 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 119 |
| Expected | fixture(1) DMX equals {
Intensity: 204
}t.expectFixtureDMX(fixture(1), { Intensity: 204 })
| 120 |
| Step | Execute the desk command "LOAD PBK 2 CUE 2". t.command.execute("LOAD PBK 2 CUE 2")
| 122 |
| Expected | Playback → runtime: $second (result of recordSequence), {
current_cue_number: "3",
effective_next_cue_number: "2",
effective_next_is_loaded: true
}t.playback.expect(second).runtime({
current_cue_number: "3",
effective_next_cue_number: "2",
effective_next_is_loaded: true,
})
| 123 |
| Step | Playback → go with $second (result of recordSequence). t.playback.go(second)
| 128 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 129 |
| Expected | Playback → runtime: $second (result of recordSequence), {
current_cue_number: "2",
effective_next_cue_number: "3",
effective_next_is_loaded: false
}t.playback.expect(second).runtime({
current_cue_number: "2",
effective_next_cue_number: "3",
effective_next_is_loaded: false,
})
| 130 |
| Expected | fixture(1) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixture(1), { Intensity: 128 })
| 135 |
| Step | Execute the desk command "LOAD PBK 2 CUE 3". t.command.execute("LOAD PBK 2 CUE 3")
| 137 |
| Step | Playback → go back with $second (result of recordSequence). t.playback.goBack(second)
| 138 |
| Expected | Playback → runtime: $second (result of recordSequence), {
current_cue_number: "1",
loaded_cue_number: "3",
effective_next_is_loaded: true
}t.playback.expect(second).runtime({
current_cue_number: "1",
loaded_cue_number: "3",
effective_next_is_loaded: true,
})
| 139 |
| Step | Playback → api → off with $second (result of recordSequence). t.playback.via.api.off(second)
| 144 |
| Expected | Playback → runtime: $second (result of recordSequence), {
enabled: false,
effective_next_is_loaded: false
}t.playback.expect(second).runtime({
enabled: false,
effective_next_is_loaded: false,
})
| 145 |
Diagnostics
None.
DMX-001 — exact byte conversion agrees in logical, Art-Net, and sACN output
tests/49-semantic-network-output-protocols.spec.ts:8 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineCue timingDMX outputProgrammer timingSemantic oracleShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 12 |
Open the ToskLight browser application.t.app.open()
| 13 |
The ToskLight browser application is ready.t.app.expect.ready()
| 14 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 15 |
| Step | Execute the desk command "FIXTURE 1 AT 0 TIME 0". t.command.execute("FIXTURE 1 AT 0 TIME 0")
| 17 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 18 |
| Expected | fixture(1) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixture(1), { Intensity: 0 })
| 19 |
| Step | Execute the desk command "FIXTURE 1 AT 25 TIME 0". t.command.execute("FIXTURE 1 AT 25 TIME 0")
| 20 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 21 |
| Expected | fixture(1) DMX equals {
Intensity: 64
}t.expectFixtureDMX(fixture(1), { Intensity: 64 })
| 22 |
| Step | Execute the desk command "FIXTURE 1 AT 50 TIME 0". t.command.execute("FIXTURE 1 AT 50 TIME 0")
| 23 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 24 |
| Expected | fixture(1) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixture(1), { Intensity: 128 })
| 25 |
| Step | Execute the desk command "FIXTURE 1 AT 75 TIME 0". t.command.execute("FIXTURE 1 AT 75 TIME 0")
| 26 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 27 |
| Expected | fixture(1) DMX equals {
Intensity: 191
}t.expectFixtureDMX(fixture(1), { Intensity: 191 })
| 28 |
| Step | Execute the desk command "FIXTURE 1 AT 100 TIME 0". t.command.execute("FIXTURE 1 AT 100 TIME 0")
| 29 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 30 |
| Expected | fixture(1) DMX equals {
Intensity: 255
}t.expectFixtureDMX(fixture(1), { Intensity: 255 })
| 31 |
| Expected | Output packet: "artnet", 1, <generated: callback>. t.expect.outputPacket("artnet", 1, (packet) =>
expect(packet.slots[0]).toBe(255),
)
| 32 |
| Expected | <unresolved: packet.slots[0]> is 255. expect(packet.slots[0]).toBe(255)
| 33 |
| Expected | Output packet: "sacn", 101, <generated: callback>. t.expect.outputPacket("sacn", 101, (packet) =>
expect(packet.slots[0]).toBe(255),
)
| 35 |
| Expected | <unresolved: packet.slots[0]> is 255. expect(packet.slots[0]).toBe(255)
| 36 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: packet.slots[0]> Expression packet.slots[0] is not statically resolved. | 33 |
| unresolved-expression | Expected outcome | <unresolved: packet.slots[0]> Expression packet.slots[0] is not statically resolved. | 36 |
DMX-002 — visible programming reaches a wire-correct ArtDMX packet
tests/49-semantic-network-output-protocols.spec.ts:41 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineSemantic oracleShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 45 |
Open the ToskLight browser application.t.app.open()
| 46 |
The ToskLight browser application is ready.t.app.expect.ready()
| 47 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "FIXTURE 1 AT 25 TIME 0". t.command.execute("FIXTURE 1 AT 25 TIME 0")
| 48 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 49 |
| Expected | Output packet: "artnet", 1, <generated: callback>. t.expect.outputPacket("artnet", 1, (packet) => {
expect(packet.sequence).not.toBe(0);
expect(packet.slots).toHaveLength(512);
expect(packet.slots[0]).toBe(64);
expect(packet.artnet).toMatchObject({
id: "Art-Net\0",
opcode: 0x5000,
protocolVersion: 14,
payloadLength: 512,
});
})
| 50 |
| Expected | Not → to be: <unresolved: packet.sequence>, 0. expect(packet.sequence).not.toBe(0)
| 51 |
| Expected | To have length: <unresolved: packet.slots>, 512. expect(packet.slots).toHaveLength(512)
| 52 |
| Expected | <unresolved: packet.slots[0]> is 64. expect(packet.slots[0]).toBe(64)
| 53 |
| Expected | <unresolved: packet.artnet> matches { id: "Art-Net\u0000", opcode: 20480, protocolVersion: 14, payloadLength: 512 }. expect(packet.artnet).toMatchObject({
id: "Art-Net\0",
opcode: 0x5000,
protocolVersion: 14,
payloadLength: 512,
})
| 54 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: packet.sequence> Property access packet.sequence depends on a runtime value. | 51 |
| unresolved-expression | Expected outcome | <unresolved: packet.slots> Property access packet.slots depends on a runtime value. | 52 |
| unresolved-expression | Expected outcome | <unresolved: packet.slots[0]> Expression packet.slots[0] is not statically resolved. | 53 |
| unresolved-expression | Expected outcome | <unresolved: packet.artnet> Property access packet.artnet depends on a runtime value. | 54 |
DMX-003 — visible programming reaches a wire-correct E1.31 packet
tests/49-semantic-network-output-protocols.spec.ts:64 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineSemantic oracleShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 68 |
Open the ToskLight browser application.t.app.open()
| 69 |
The ToskLight browser application is ready.t.app.expect.ready()
| 70 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "FIXTURE 1 AT 50 TIME 0". t.command.execute("FIXTURE 1 AT 50 TIME 0")
| 71 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 72 |
| Expected | Output packet: "sacn", 101, <generated: callback>. t.expect.outputPacket("sacn", 101, (packet) => {
expect(packet.sequence).not.toBe(0);
expect(packet.priority).toBe(100);
expect(packet.slots).toHaveLength(512);
expect(packet.slots[0]).toBe(128);
expect(packet.sacn).toMatchObject({
preambleSize: 0x10,
rootVector: 0x00000004,
framingVector: 0x00000002,
propertyValueCount: 513,
startCode: 0,
});
})
| 73 |
| Expected | Not → to be: <unresolved: packet.sequence>, 0. expect(packet.sequence).not.toBe(0)
| 74 |
| Expected | <unresolved: packet.priority> is 100. expect(packet.priority).toBe(100)
| 75 |
| Expected | To have length: <unresolved: packet.slots>, 512. expect(packet.slots).toHaveLength(512)
| 76 |
| Expected | <unresolved: packet.slots[0]> is 128. expect(packet.slots[0]).toBe(128)
| 77 |
| Expected | <unresolved: packet.sacn> matches { preambleSize: 16, rootVector: 4, framingVector: 2, propertyValueCount: 513, startCode: 0 }. expect(packet.sacn).toMatchObject({
preambleSize: 0x10,
rootVector: 0x00000004,
framingVector: 0x00000002,
propertyValueCount: 513,
startCode: 0,
})
| 78 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: packet.sequence> Property access packet.sequence depends on a runtime value. | 74 |
| unresolved-expression | Expected outcome | <unresolved: packet.priority> Property access packet.priority depends on a runtime value. | 75 |
| unresolved-expression | Expected outcome | <unresolved: packet.slots> Property access packet.slots depends on a runtime value. | 76 |
| unresolved-expression | Expected outcome | <unresolved: packet.slots[0]> Expression packet.slots[0] is not statically resolved. | 77 |
| unresolved-expression | Expected outcome | <unresolved: packet.sacn> Property access packet.sacn depends on a runtime value. | 78 |
DMX-004 — remapped fan-out reaches every enabled destination and no disabled route
tests/49-semantic-network-output-protocols.spec.ts:89 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineDMX outputOutput runtimeShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 93 |
Open the ToskLight browser application.t.app.open()
| 94 |
The ToskLight browser application is ready.t.app.expect.ready()
| 95 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Output → network → add with "extra Art-Net", {
protocol: "art_net",
logicalUniverse: 1,
destinationUniverse: 11,
deliveryMode: "unicast",
capture: true
}t.output.network.add("extra Art-Net", {
protocol: "art_net",
logicalUniverse: 1,
destinationUniverse: 11,
deliveryMode: "unicast",
capture: true,
})
| 96 |
| Step | Output → network → add with "disabled sACN", {
protocol: "sacn",
logicalUniverse: 1,
destinationUniverse: 102,
deliveryMode: "unicast",
enabled: false,
capture: true
}t.output.network.add("disabled sACN", {
protocol: "sacn",
logicalUniverse: 1,
destinationUniverse: 102,
deliveryMode: "unicast",
enabled: false,
capture: true,
})
| 103 |
| Step | Output → network → mark with "extra Art-Net". t.output.network.mark("extra Art-Net")
| 111 |
| Step | Output → network → mark with "disabled sACN". t.output.network.mark("disabled sACN")
| 112 |
| Step | Execute the desk command "FIXTURE 1 AT 25 TIME 0". t.command.execute("FIXTURE 1 AT 25 TIME 0")
| 113 |
| Step | Execute the desk command "FIXTURE 2 AT 50 TIME 0". t.command.execute("FIXTURE 2 AT 50 TIME 0")
| 114 |
| Step | Execute the desk command "FIXTURE 3 AT 75 TIME 0". t.command.execute("FIXTURE 3 AT 75 TIME 0")
| 115 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 116 |
| Expected | Output → network → expect packet: "extra Art-Net", {
slots: {
1: 64,
2: 128,
3: 191
}
}t.output.network.expectPacket("extra Art-Net", {
slots: { 1: 64, 2: 128, 3: 191 },
})
| 117 |
| Expected | Output → network → expect no packet: "disabled sACN". t.output.network.expectNoPacket("disabled sACN")
| 120 |
| Expected | fixture(1) DMX equals {
Intensity: 64
}t.expectFixtureDMX(fixture(1), { Intensity: 64 })
| 121 |
| Expected | fixture(2) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixture(2), { Intensity: 128 })
| 122 |
| Expected | fixture(3) DMX equals {
Intensity: 191
}t.expectFixtureDMX(fixture(3), { Intensity: 191 })
| 123 |
Diagnostics
None.
DMX-005 — a conflicting visible patch edit preserves both previous addresses atomically
tests/49-semantic-network-output-protocols.spec.ts:127 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UIShow PatchShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 131 |
Open the ToskLight browser application.t.app.open()
| 132 |
The ToskLight browser application is ready.t.app.expect.ready()
| 133 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Patch → prepare address conflict. t.patch.prepareAddressConflict()
| 134 |
| Step | Patch → ui → address with $conflict.candidate (from patch.prepareAddressConflict), "2.1". t.patch.via.ui.address(conflict.candidate, "2.1")
| 135 |
| Step | Patch → keep old address after conflict. t.patch.keepOldAddressAfterConflict()
| 136 |
| Expected | Patch → address: $conflict.anchor (from patch.prepareAddressConflict), "2.1". t.patch.expect(conflict.anchor).address("2.1")
| 137 |
| Expected | Patch → address: $conflict.candidate (from patch.prepareAddressConflict), "2.2". t.patch.expect(conflict.candidate).address("2.2")
| 138 |
Diagnostics
None.
DMX-006 — visible programming encodes deterministic 16-bit coarse and fine bytes
tests/49-semantic-network-output-protocols.spec.ts:142 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UICommand lineCue timingDMX outputOutput runtimeProgrammer timingShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 146 |
Open the ToskLight browser application.t.app.open()
| 147 |
The ToskLight browser application is ready.t.app.expect.ready()
| 148 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 149 |
| Step | Output → network → install sixteen bit fixture. t.output.network.installSixteenBitFixture()
| 150 |
| Step | Execute the desk command "FIXTURE $fixtureNumber (result of output.network.installSixteenBitFixture) AT 50 TIME 0". t.command.execute(`FIXTURE ${fixtureNumber} AT 50 TIME 0`)
| 151 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 152 |
| Expected | fixture(fixtureNumber) DMX equals {
"Intensity coarse": 128,
"Intensity fine": 0
}t.expectFixtureDMX(fixture(fixtureNumber), {
"Intensity coarse": 128,
"Intensity fine": 0,
})
| 153 |
Diagnostics
None.
DMX-007 — one route failure is isolated and recovery sends current state
tests/49-semantic-network-output-protocols.spec.ts:160 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineOutput runtimeSemantic oracleShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 164 |
Open the ToskLight browser application.t.app.open()
| 165 |
The ToskLight browser application is ready.t.app.expect.ready()
| 166 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Output → network → add with "recovering Art-Net", {
protocol: "art_net",
logicalUniverse: 1,
destinationUniverse: 11,
deliveryMode: "unicast",
capture: true
}t.output.network.add("recovering Art-Net", {
protocol: "art_net",
logicalUniverse: 1,
destinationUniverse: 11,
deliveryMode: "unicast",
capture: true,
})
| 167 |
| Step | Output → network → failure with "recovering Art-Net", true. t.output.network.failure("recovering Art-Net", true)
| 174 |
| Step | Output → network → mark with "recovering Art-Net". t.output.network.mark("recovering Art-Net")
| 175 |
| Step | Execute the desk command "FIXTURE 1 AT 25 TIME 0". t.command.execute("FIXTURE 1 AT 25 TIME 0")
| 176 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 177 |
| Expected | Output → network → expect no packet: "recovering Art-Net". t.output.network.expectNoPacket("recovering Art-Net")
| 178 |
| Expected | Output packet: "artnet", 1, <generated: callback>. t.expect.outputPacket("artnet", 1, (packet) =>
expect(packet.slots[0]).toBe(64),
)
| 179 |
| Expected | <unresolved: packet.slots[0]> is 64. expect(packet.slots[0]).toBe(64)
| 180 |
| Step | Output → network → failure with "recovering Art-Net", false. t.output.network.failure("recovering Art-Net", false)
| 182 |
| Step | Output → network → mark with "recovering Art-Net". t.output.network.mark("recovering Art-Net")
| 183 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 184 |
| Expected | Output → network → expect packet: "recovering Art-Net", {
slots: {
1: 64
},
sequenceNonZero: true
}t.output.network.expectPacket("recovering Art-Net", {
slots: { 1: 64 },
sequenceNonZero: true,
})
| 185 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: packet.slots[0]> Expression packet.slots[0] is not statically resolved. | 180 |
DMX-009 — protocol-correct delivery modes persist and resolve to actual destinations
tests/49-semantic-network-output-protocols.spec.ts:192 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineOutput runtimeShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 196 |
Open the ToskLight browser application.t.app.open()
| 197 |
The ToskLight browser application is ready.t.app.expect.ready()
| 198 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Output → network → add with "Art-Net broadcast", {
protocol: "art_net",
logicalUniverse: 1,
destinationUniverse: 201,
deliveryMode: "broadcast"
}t.output.network.add("Art-Net broadcast", {
protocol: "art_net",
logicalUniverse: 1,
destinationUniverse: 201,
deliveryMode: "broadcast",
})
| 199 |
| Step | Output → network → add with "Art-Net unicast", {
protocol: "art_net",
logicalUniverse: 1,
destinationUniverse: 202,
deliveryMode: "unicast",
capture: true
}t.output.network.add("Art-Net unicast", {
protocol: "art_net",
logicalUniverse: 1,
destinationUniverse: 202,
deliveryMode: "unicast",
capture: true,
})
| 205 |
| Step | Output → network → add with "sACN multicast", {
protocol: "sacn",
logicalUniverse: 1,
destinationUniverse: 301,
deliveryMode: "multicast"
}t.output.network.add("sACN multicast", {
protocol: "sacn",
logicalUniverse: 1,
destinationUniverse: 301,
deliveryMode: "multicast",
})
| 212 |
| Step | Output → network → add with "sACN unicast", {
protocol: "sacn",
logicalUniverse: 1,
destinationUniverse: 302,
deliveryMode: "unicast",
capture: true
}t.output.network.add("sACN unicast", {
protocol: "sacn",
logicalUniverse: 1,
destinationUniverse: 302,
deliveryMode: "unicast",
capture: true,
})
| 218 |
| Step | Output → network → mark with "Art-Net unicast". t.output.network.mark("Art-Net unicast")
| 225 |
| Step | Output → network → mark with "sACN unicast". t.output.network.mark("sACN unicast")
| 226 |
| Step | Execute the desk command "FIXTURE 1 AT 50 TIME 0". t.command.execute("FIXTURE 1 AT 50 TIME 0")
| 227 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 228 |
| Expected | Output → network → expect stored: "Art-Net broadcast", {
delivery_mode: "broadcast",
destination: null
}t.output.network.expectStored("Art-Net broadcast", {
delivery_mode: "broadcast",
destination: null,
})
| 229 |
| Expected | Output → network → expect stored: "sACN multicast", {
delivery_mode: "multicast",
destination: null
}t.output.network.expectStored("sACN multicast", {
delivery_mode: "multicast",
destination: null,
})
| 233 |
| Expected | Output → network → expect diagnostic: "Art-Net broadcast", {
delivery_mode: "broadcast",
destination: "255.255.255.255:6454",
enabled: true
}t.output.network.expectDiagnostic("Art-Net broadcast", {
delivery_mode: "broadcast",
destination: "255.255.255.255:6454",
enabled: true,
})
| 237 |
| Expected | Output → network → expect diagnostic: "sACN multicast", {
delivery_mode: "multicast",
destination: "239.255.1.45:5568",
enabled: true
}t.output.network.expectDiagnostic("sACN multicast", {
delivery_mode: "multicast",
destination: "239.255.1.45:5568",
enabled: true,
})
| 242 |
| Expected | Output → network → expect same payload: "Art-Net unicast", "sACN unicast". t.output.network.expectSamePayload("Art-Net unicast", "sACN unicast")
| 247 |
Diagnostics
None.
CUE-011 — Cuelist View edits preserve Cue identity, runtime selection, and persisted values
tests/50-semantic-cue-editing.spec.ts:7 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICue runtimeCue timingCuesEncoder controlsPlaybacksProgrammerProgrammer timingRecordingSelectionShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 11 |
Open the ToskLight browser application.t.app.open()
| 12 |
The ToskLight browser application is ready.t.app.expect.ready()
| 13 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 14 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 15 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 17 |
| Step | Encoder → intensity → dimmer → api → set with 25. t.encoder.intensity.dimmer.via.api.set(25)
| 18 |
| Step | Record → playback with 1. t.record.playback(1)
| 19 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 20 |
| Step | Encoder → intensity → dimmer → api → set with 50. t.encoder.intensity.dimmer.via.api.set(50)
| 21 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 22 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 23 |
| Step | Encoder → intensity → dimmer → api → set with 75. t.encoder.intensity.dimmer.via.api.set(75)
| 24 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 3
}t.record.cue({ playback, cue: 3 })
| 25 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 26 |
| Step | Playback → configure with $playback (result of record.playback), {
name: "CUE-011 Sequence",
buttons: [
PlaybackButton.GoBack,
PlaybackButton.Go,
PlaybackButton.Off
]
}t.playback.configure(playback, {
name: "CUE-011 Sequence",
buttons: [PlaybackButton.GoBack, PlaybackButton.Go, PlaybackButton.Off],
})
| 27 |
| Step | Playback → api → go with $playback (result of record.playback). t.playback.via.api.go(playback)
| 31 |
| Expected | Playback → runtime: $playback (result of record.playback), {
current_cue_number: "1"
}t.playback.expect(playback).runtime({ current_cue_number: "1" })
| 32 |
| Step | Cue → open editor with $playback (result of record.playback). t.cue.openEditor(playback)
| 34 |
| Expected | Cue editor → structure. editor.expect.structure()
| 35 |
| Step | Cue editor → select with 2. editor.select(2)
| 36 |
| Step | Cue editor → edit with 2, {
fade: "2.5",
delay: "1.25",
trigger: "TIME",
triggerTime: "4"
}editor.edit(2, {
fade: "2.5",
delay: "1.25",
trigger: "TIME",
triggerTime: "4",
})
| 37 |
| Expected | Cue → metadata: $playback (result of record.playback), 2, {
fade_millis: 2500,
delay_millis: 1250
}t.cue.expect(playback, 2).metadata({
fade_millis: 2_500,
delay_millis: 1_250,
})
| 43 |
| Expected | Cue → trigger: $playback (result of record.playback), 2, {
type: "wait",
delay_millis: 4000
}t.cue
.expect(playback, 2)
.trigger({ type: "wait", delay_millis: 4_000 })
| 47 |
| Step | Cue editor → select with 3. editor.select(3)
| 51 |
| Step | Cue editor → select with 2. editor.select(2)
| 52 |
| Expected | Cue editor → selected: 2, {
fade: "2.5",
delay: "1.25",
triggerTime: "4"
}editor.expect.selected(2, {
fade: "2.5",
delay: "1.25",
triggerTime: "4",
})
| 53 |
| Step | Cue editor → inspect settings. editor.inspectSettings()
| 58 |
| Expected | Cue editor → selected: 2. editor.expect.selected(2)
| 59 |
| Expected | Playback → runtime: $playback (result of record.playback), {
current_cue_number: "1"
}t.playback.expect(playback).runtime({ current_cue_number: "1" })
| 60 |
| Step | Cue editor → reject with 2, {
fade: "-1"
}editor.reject(2, { fade: "-1" })
| 62 |
| Expected | Cue → metadata: $playback (result of record.playback), 2, {
fade_millis: 2500,
delay_millis: 1250
}t.cue.expect(playback, 2).metadata({
fade_millis: 2_500,
delay_millis: 1_250,
})
| 63 |
| Expected | Playback → runtime: $playback (result of record.playback), {
current_cue_number: "1"
}t.playback.expect(playback).runtime({ current_cue_number: "1" })
| 67 |
| Step | Cue → reopen editor with $playback (result of record.playback). t.cue.reopenEditor(playback)
| 69 |
| Step | Cue editor → select with 2. editor.select(2)
| 70 |
| Expected | Cue editor → selected: 2, {
fade: "2.5",
delay: "1.25",
triggerTime: "4"
}editor.expect.selected(2, {
fade: "2.5",
delay: "1.25",
triggerTime: "4",
})
| 71 |
Diagnostics
None.
FILE-002 — File Manager provides the three-column browsing workflow and text editor
tests/50-semantic-files-and-text-editor.spec.ts:7 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UIDesktop layoutFile ManagerShow filesText Editor
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 11 |
Open the ToskLight browser application.t.app.open()
| 12 |
The ToskLight browser application is ready.t.app.expect.ready()
| 13 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: File Manager editing t.desktop.configure("File Manager editing")
| 14 |
| Step | Add the PaneType.FileManager pane desktop.addPane(PaneType.FileManager, {
slug: "files",
column: 1,
row: 1,
width: 24,
height: 18,
})
| 15 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 22 |
| Expected | Files → expect manager edits text. t.files.expectManagerEditsText()
| 23 |
Diagnostics
None.
TEXT-001 — dedicated Text Editor persists its file association and reports dirty state
tests/50-semantic-files-and-text-editor.spec.ts:32 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UIDesktop layoutFile ManagerShow filesText Editor
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 36 |
Open the ToskLight browser application.t.app.open()
| 37 |
The ToskLight browser application is ready.t.app.expect.ready()
| 38 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Text Editor saving t.desktop.configure("Text Editor saving")
| 39 |
| Step | Add the PaneType.TextEditor pane desktop.addPane(PaneType.TextEditor, {
slug: "editor",
column: 1,
row: 1,
width: 24,
height: 18,
})
| 40 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 47 |
| Expected | Files → expect editor dirty save. t.files.expectEditorDirtySave()
| 48 |
Diagnostics
None.
TEXT-015 — Text Editors synchronize, surface conflicts, recover files, and retain configured views
tests/50-semantic-files-and-text-editor.spec.ts:52 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UIDesktop layoutFile ManagerShow filesText Editor
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 56 |
Open the ToskLight browser application.t.app.open()
| 57 |
The ToskLight browser application is ready.t.app.expect.ready()
| 58 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Text Editor collaboration t.desktop.configure("Text Editor collaboration")
| 59 |
| Step | Add the PaneType.TextEditor pane desktop.addPane(PaneType.TextEditor, {
slug: "first-editor",
column: 1,
row: 1,
width: 12,
height: 18,
})
| 60 |
| Step | Add the PaneType.TextEditor pane desktop.addPane(PaneType.TextEditor, {
slug: "second-editor",
column: 13,
row: 1,
width: 12,
height: 18,
})
| 67 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 74 |
| Expected | Files → expect two editor lifecycle. t.files.expectTwoEditorLifecycle()
| 75 |
| Expected | Files → expect editor modes. t.files.expectEditorModes()
| 76 |
Diagnostics
None.
FILE-016 — File Manager operations, launchers, hosted picking, and system fallback stay confined
tests/50-semantic-files-and-text-editor.spec.ts:80 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UIDesktop layoutFile ManagerShow filesText Editor
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 84 |
Open the ToskLight browser application.t.app.open()
| 85 |
The ToskLight browser application is ready.t.app.expect.ready()
| 86 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: File Manager workflows t.desktop.configure("File Manager workflows")
| 87 |
| Step | Add the PaneType.FileManager pane desktop.addPane(PaneType.FileManager, {
slug: "files",
column: 1,
row: 1,
width: 24,
height: 18,
})
| 88 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 95 |
| Expected | Files → expect manager operations. t.files.expectManagerOperations()
| 96 |
| Expected | Files → expect setup launchers. t.files.expectSetupLaunchers()
| 97 |
| Expected | Files → expect hosted picker. t.files.expectHostedPicker()
| 98 |
| Expected | Files → expect system picker fallback. t.files.expectSystemPickerFallback()
| 99 |
Diagnostics
None.
CUE-012 — Cuelist Settings persist Sequence and Chaser runtime policy
tests/51-semantic-cuelist-settings.spec.ts:7 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICue runtimeCuelist SettingsCuesEncoder controlsPlaybacksProgrammerRecordingSelectionShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 11 |
Open the ToskLight browser application.t.app.open()
| 12 |
The ToskLight browser application is ready.t.app.expect.ready()
| 13 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 15 |
| Step | Encoder → intensity → dimmer → api → set with 25. t.encoder.intensity.dimmer.via.api.set(25)
| 16 |
| Step | Record → playback with 1. t.record.playback(1)
| 17 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 18 |
| Step | Encoder → intensity → dimmer → api → set with 50. t.encoder.intensity.dimmer.via.api.set(50)
| 19 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 20 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 21 |
| Step | Playback → configure with $playback (result of record.playback), {
name: "CUE-012 Settings",
buttons: [
PlaybackButton.GoBack,
PlaybackButton.Go,
PlaybackButton.Off
]
}t.playback.configure(playback, {
name: "CUE-012 Settings",
buttons: [PlaybackButton.GoBack, PlaybackButton.Go, PlaybackButton.Off],
})
| 22 |
| Step | Cue → open editor with $playback (result of record.playback). t.cue.openEditor(playback)
| 27 |
| Step | Cue editor → open settings. editor.openSettings()
| 28 |
| Expected | Cue list settings → expect defaults. settings.expectDefaults()
| 29 |
| Step | Cue list settings → configure with {
mode: "Chaser",
priority: 42,
intensityPriority: "LTP",
wrap: "Reset",
restart: "Continue Current Cue",
forceCueTiming: true,
disableCueTiming: true,
speedMultiplier: 2,
chaserXfade: 50
}settings.configure({
mode: "Chaser",
priority: 42,
intensityPriority: "LTP",
wrap: "Reset",
restart: "Continue Current Cue",
forceCueTiming: true,
disableCueTiming: true,
speedMultiplier: 2,
chaserXfade: 50,
})
| 30 |
| Step | Cue list settings → save. settings.save()
| 41 |
| Expected | Cue → expect list → configuration: $playback (result of record.playback), {
mode: "chaser",
priority: 42,
intensity_priority_mode: "ltp",
wrap_mode: "reset",
restart_mode: "continue_current_cue",
force_cue_timing: true,
disable_cue_timing: true,
speed_group: "A",
speed_multiplier: 2,
chaser_xfade_percent: 50
}t.cue.expectList(playback).configuration({
mode: "chaser",
priority: 42,
intensity_priority_mode: "ltp",
wrap_mode: "reset",
restart_mode: "continue_current_cue",
force_cue_timing: true,
disable_cue_timing: true,
speed_group: "A",
speed_multiplier: 2,
chaser_xfade_percent: 50,
})
| 43 |
Diagnostics
None.
CUE-013 — deleting the active Cue holds output and anchors GO around the surviving Cues
tests/52-semantic-cue-deletion.spec.ts:8 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICue runtimeCue timingDMX outputEncoder controlsPlaybacksProgrammerProgrammer timingRecordingSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 12 |
Open the ToskLight browser application.t.app.open()
| 13 |
The ToskLight browser application is ready.t.app.expect.ready()
| 14 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 15 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 16 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 18 |
| Step | Encoder → intensity → dimmer → api → set with 25. t.encoder.intensity.dimmer.via.api.set(25)
| 19 |
| Step | Record → playback with 1. t.record.playback(1)
| 20 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 21 |
| Step | Encoder → intensity → dimmer → api → set with 50. t.encoder.intensity.dimmer.via.api.set(50)
| 22 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 23 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 24 |
| Step | Encoder → intensity → dimmer → api → set with 75. t.encoder.intensity.dimmer.via.api.set(75)
| 25 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 3
}t.record.cue({ playback, cue: 3 })
| 26 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 27 |
| Step | Playback → configure with $playback (result of record.playback), {
name: "Delete Active Sequence",
buttons: [
PlaybackButton.GoBack,
PlaybackButton.Go,
PlaybackButton.Off
]
}t.playback.configure(playback, {
name: "Delete Active Sequence",
buttons: [PlaybackButton.GoBack, PlaybackButton.Go, PlaybackButton.Off],
})
| 28 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 33 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 34 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 35 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 36 |
| Expected | fixture(1) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixture(1), { Intensity: 128 })
| 37 |
| Step | Cue → delete with $playback (result of record.playback), 2. t.cue.delete(playback, 2)
| 39 |
| Expected | Cue → absent: $playback (result of record.playback), 2. t.cue.expect(playback, 2).absent()
| 40 |
| Expected | Playback → runtime: $playback (result of record.playback), {
current_cue_number: "2",
deleted_cue_hold: {
deleted_number: "2",
previous_number: "1",
next_number: "3"
}
}t.playback.expect(playback).runtime({
current_cue_number: "2",
deleted_cue_hold: {
deleted_number: "2",
previous_number: "1",
next_number: "3",
},
})
| 41 |
| Expected | fixture(1) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixture(1), { Intensity: 128 })
| 49 |
| Step | Playback → go with $playback (result of record.playback). t.playback.go(playback)
| 51 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 52 |
| Expected | Playback → runtime: $playback (result of record.playback), {
current_cue_number: "3"
}t.playback.expect(playback).runtime({ current_cue_number: "3" })
| 53 |
| Expected | fixture(1) DMX equals {
Intensity: 191
}t.expectFixtureDMX(fixture(1), { Intensity: 191 })
| 54 |
| Step | Playback → go back with $playback (result of record.playback). t.playback.goBack(playback)
| 56 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 57 |
| Expected | Playback → runtime: $playback (result of record.playback), {
current_cue_number: "1"
}t.playback.expect(playback).runtime({ current_cue_number: "1" })
| 58 |
| Expected | fixture(1) DMX equals {
Intensity: 64
}t.expectFixtureDMX(fixture(1), { Intensity: 64 })
| 59 |
Diagnostics
None.
PRELOAD-001 — programmer-only Preload stays blind, commits, and releases
tests/53-semantic-programmer-preload.spec.ts:7 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICue timingDMX outputPreloadProgrammer timingShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 11 |
Open the ToskLight browser application.t.app.open()
| 12 |
The ToskLight browser application is ready.t.app.expect.ready()
| 13 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 14 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 16 |
| Expected | fixture(1) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixture(1), { Intensity: 0 })
| 17 |
| Step | Start blind Preload programming. t.preload.start()
| 19 |
| Expected | Preload → active. t.preload.expect.active()
| 20 |
| Step | Preload → set fixture value with {
fixture: 1,
attribute: "intensity",
value: {
kind: "normalized",
value: 0.5
}
}t.preload.setFixtureValue({
fixture: 1,
attribute: "intensity",
value: { kind: "normalized", value: 0.5 },
})
| 21 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 26 |
| Expected | fixture(1) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixture(1), { Intensity: 0 })
| 27 |
| Step | Preload → api → commit. t.preload.via.api.commit()
| 29 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 30 |
| Expected | fixture(1) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixture(1), { Intensity: 128 })
| 31 |
| Step | Release blind Preload programming. t.preload.release()
| 33 |
| Expected | Preload → inactive. t.preload.expect.inactive()
| 34 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 35 |
| Expected | fixture(1) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixture(1), { Intensity: 0 })
| 36 |
Diagnostics
None.
PRELOAD-002 — physical Playback Preload preserves all seven ordered action verbs
tests/54-semantic-physical-playback-preload.spec.ts:7 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICue timingEncoder controlsPlaybacksPreloadProgrammerProgrammer timingRecordingSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 11 |
Open the ToskLight browser application.t.app.open()
| 12 |
The ToskLight browser application is ready.t.app.expect.ready()
| 13 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 14 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 15 |
| Step | Clear the current selection. t.selection.clear()
| 22 |
| Step | Selection → fixtures → api → item with fixture = 1. t.selection.fixtures.via.api.item(fixture)
| 23 |
| Step | Encoder → intensity → dimmer → api → set with 30. t.encoder.intensity.dimmer.via.api.set(30)
| 24 |
| Step | Record → playback with slot = 1. t.record.playback(slot)
| 25 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 26 |
| Step | Encoder → intensity → dimmer → api → set with 70. t.encoder.intensity.dimmer.via.api.set(70)
| 27 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 28 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 29 |
| Step | Playback → configure with $playback (result of record.playback), {
name: "Physical button = PlaybackButton.Toggle",
buttons: [
button = PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name: `Physical ${button}`,
buttons: [button, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 30 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 34 |
| Step | Clear the current selection. t.selection.clear()
| 22 |
| Step | Selection → fixtures → api → item with fixture = 2. t.selection.fixtures.via.api.item(fixture)
| 23 |
| Step | Encoder → intensity → dimmer → api → set with 30. t.encoder.intensity.dimmer.via.api.set(30)
| 24 |
| Step | Record → playback with slot = 2. t.record.playback(slot)
| 25 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 26 |
| Step | Encoder → intensity → dimmer → api → set with 70. t.encoder.intensity.dimmer.via.api.set(70)
| 27 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 28 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 29 |
| Step | Playback → configure with $playback (result of record.playback), {
name: "Physical button = PlaybackButton.Go",
buttons: [
button = PlaybackButton.Go,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name: `Physical ${button}`,
buttons: [button, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 30 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 34 |
| Step | Clear the current selection. t.selection.clear()
| 22 |
| Step | Selection → fixtures → api → item with fixture = 3. t.selection.fixtures.via.api.item(fixture)
| 23 |
| Step | Encoder → intensity → dimmer → api → set with 30. t.encoder.intensity.dimmer.via.api.set(30)
| 24 |
| Step | Record → playback with slot = 3. t.record.playback(slot)
| 25 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 26 |
| Step | Encoder → intensity → dimmer → api → set with 70. t.encoder.intensity.dimmer.via.api.set(70)
| 27 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 28 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 29 |
| Step | Playback → configure with $playback (result of record.playback), {
name: "Physical button = PlaybackButton.GoBack",
buttons: [
button = PlaybackButton.GoBack,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name: `Physical ${button}`,
buttons: [button, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 30 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 34 |
| Step | Clear the current selection. t.selection.clear()
| 22 |
| Step | Selection → fixtures → api → item with fixture = 4. t.selection.fixtures.via.api.item(fixture)
| 23 |
| Step | Encoder → intensity → dimmer → api → set with 30. t.encoder.intensity.dimmer.via.api.set(30)
| 24 |
| Step | Record → playback with slot = 4. t.record.playback(slot)
| 25 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 26 |
| Step | Encoder → intensity → dimmer → api → set with 70. t.encoder.intensity.dimmer.via.api.set(70)
| 27 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 28 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 29 |
| Step | Playback → configure with $playback (result of record.playback), {
name: "Physical button = PlaybackButton.Off",
buttons: [
button = PlaybackButton.Off,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name: `Physical ${button}`,
buttons: [button, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 30 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 34 |
| Step | Clear the current selection. t.selection.clear()
| 22 |
| Step | Selection → fixtures → api → item with fixture = 5. t.selection.fixtures.via.api.item(fixture)
| 23 |
| Step | Encoder → intensity → dimmer → api → set with 30. t.encoder.intensity.dimmer.via.api.set(30)
| 24 |
| Step | Record → playback with slot = 5. t.record.playback(slot)
| 25 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 26 |
| Step | Encoder → intensity → dimmer → api → set with 70. t.encoder.intensity.dimmer.via.api.set(70)
| 27 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 28 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 29 |
| Step | Playback → configure with $playback (result of record.playback), {
name: "Physical button = PlaybackButton.On",
buttons: [
button = PlaybackButton.On,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name: `Physical ${button}`,
buttons: [button, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 30 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 34 |
| Step | Clear the current selection. t.selection.clear()
| 22 |
| Step | Selection → fixtures → api → item with fixture = 6. t.selection.fixtures.via.api.item(fixture)
| 23 |
| Step | Encoder → intensity → dimmer → api → set with 30. t.encoder.intensity.dimmer.via.api.set(30)
| 24 |
| Step | Record → playback with slot = 6. t.record.playback(slot)
| 25 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 26 |
| Step | Encoder → intensity → dimmer → api → set with 70. t.encoder.intensity.dimmer.via.api.set(70)
| 27 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 28 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 29 |
| Step | Playback → configure with $playback (result of record.playback), {
name: "Physical button = PlaybackButton.Temp",
buttons: [
button = PlaybackButton.Temp,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name: `Physical ${button}`,
buttons: [button, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 30 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 34 |
| Step | Playback → api → go with $backPlayback (result of recordPlayback). t.playback.via.api.go(backPlayback)
| 45 |
| Step | Playback → api → go with $backPlayback (result of recordPlayback). t.playback.via.api.go(backPlayback)
| 46 |
| Step | Playback → api → go with $offPlayback (result of recordPlayback). t.playback.via.api.go(offPlayback)
| 47 |
| Step | Preload → configure with {
programmer: false,
playbackScope: {
position_ranges: [
{
start: 1,
end: 6
}
],
pages: null
},
programmerFade: 2000,
cueFade: 0
}t.preload.configure({
programmer: false,
playbackScope: {
position_ranges: [{ start: 1, end: 6 }],
pages: null,
},
programmerFade: 2_000,
cueFade: 0,
})
| 48 |
| Step | Playback → open. t.playback.open()
| 57 |
| Step | Start blind Preload programming. t.preload.start()
| 58 |
| Step | Playback → toggle with $togglePlayback (result of recordPlayback). t.playback.toggle(togglePlayback)
| 60 |
| Step | Playback → go with $goPlayback (result of recordPlayback). t.playback.go(goPlayback)
| 61 |
| Step | Playback → go back with $backPlayback (result of recordPlayback). t.playback.goBack(backPlayback)
| 62 |
| Step | Playback → off with $offPlayback (result of recordPlayback). t.playback.off(offPlayback)
| 63 |
| Step | Playback → on with $onPlayback (result of recordPlayback). t.playback.on(onPlayback)
| 64 |
| Step | Playback → ui → temp with $tempPlayback (result of recordPlayback). t.playback.via.ui.temp(tempPlayback)
| 65 |
| Step | Playback → ui → temp with $tempPlayback (result of recordPlayback). t.playback.via.ui.temp(tempPlayback)
| 66 |
| Expected | Preload → pending playback actions: [
"toggle",
"go",
"go-minus",
"off",
"on",
"temp-on",
"temp-off"
] t.preload.expect.pendingPlaybackActions([
"toggle",
"go",
"go-minus",
"off",
"on",
"temp-on",
"temp-off",
])
| 67 |
| Step | Preload → commit. t.preload.commit()
| 77 |
| Step | Advance the test clock by "2s". t.clock.advanceBy("2s")
| 78 |
| Expected | Playback → runtime: $togglePlayback (result of recordPlayback), {
enabled: true,
current_cue_number: "1"
}t.playback.expect(togglePlayback).runtime({
enabled: true,
current_cue_number: "1",
})
| 79 |
| Expected | Playback → runtime: $goPlayback (result of recordPlayback), {
enabled: true,
current_cue_number: "1"
}t.playback.expect(goPlayback).runtime({
enabled: true,
current_cue_number: "1",
})
| 83 |
| Expected | Playback → runtime: $backPlayback (result of recordPlayback), {
enabled: true,
current_cue_number: "1"
}t.playback.expect(backPlayback).runtime({
enabled: true,
current_cue_number: "1",
})
| 87 |
| Expected | Playback → runtime: $onPlayback (result of recordPlayback), {
enabled: true
}t.playback.expect(onPlayback).runtime({ enabled: true })
| 91 |
| Step | Release blind Preload programming. t.preload.release()
| 93 |
| Expected | Playback → runtime: $togglePlayback (result of recordPlayback), {
enabled: true,
current_cue_number: "1"
}t.playback.expect(togglePlayback).runtime({
enabled: true,
current_cue_number: "1",
})
| 94 |
| Expected | Playback → runtime: $onPlayback (result of recordPlayback), {
enabled: true
}t.playback.expect(onPlayback).runtime({ enabled: true })
| 98 |
Diagnostics
None.
OSC-001 — page changes produce one complete feedback cycle without periodic mutation
tests/55-semantic-osc-api-and-cross-surface.spec.ts:12 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICross-surface stateOSCPlayback pagesShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 16 |
Open the ToskLight browser application.t.app.open()
| 17 |
The ToskLight browser application is ready.t.app.expect.ready()
| 18 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Page → create with 2. t.page.create(2)
| 19 |
| Step | Page → rename with 2, "Page 2". t.page.rename(2, "Page 2")
| 20 |
| Expected | Cross surface → expect complete feedback for page: "Page 2". t.crossSurface.expectCompleteFeedbackForPage("Page 2")
| 22 |
| Expected | Page → selected: 2. t.page.expect(2).selected()
| 23 |
Diagnostics
None.
OSC-002 — hardware-equivalent command reaches shared programmer and output
tests/55-semantic-osc-api-and-cross-surface.spec.ts:27 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICross-surface stateDMX outputOSCShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 31 |
Open the ToskLight browser application.t.app.open()
| 32 |
The ToskLight browser application is ready.t.app.expect.ready()
| 33 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Cross surface → execute osc group command and verify output. t.crossSurface.executeOscGroupCommandAndVerifyOutput()
| 35 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 64
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 64 })
| 36 |
Diagnostics
None.
OSC-003 — two OSC surfaces share the desk's command line and unsubscribe is reference-counted
tests/55-semantic-osc-api-and-cross-surface.spec.ts:40 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICross-surface stateOSCShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 44 |
Open the ToskLight browser application.t.app.open()
| 45 |
The ToskLight browser application is ready.t.app.expect.ready()
| 46 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | Cross surface → expect subscribers share the desk command line. t.crossSurface.expectSubscribersShareTheDeskCommandLine()
| 48 |
Diagnostics
None.
OSC-004 — invalid input is rejected without programmer or output mutation
tests/55-semantic-osc-api-and-cross-surface.spec.ts:52 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICross-surface stateOSCShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 56 |
Open the ToskLight browser application.t.app.open()
| 57 |
The ToskLight browser application is ready.t.app.expect.ready()
| 58 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Cross surface → reject invalid group command. t.crossSurface.rejectInvalidGroupCommand()
| 60 |
| Expected | Invalid visible input leaves Programmer and rendered output state unchanged. t.crossSurface.rejectInvalidGroupCommand()
| 60 |
Diagnostics
None.
OSC-005 — one command line is built from several surfaces and completed once
tests/55-semantic-osc-api-and-cross-surface.spec.ts:64 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICross-surface stateOSCShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 68 |
Open the ToskLight browser application.t.app.open()
| 69 |
The ToskLight browser application is ready.t.app.expect.ready()
| 70 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Cross surface → complete one shared value from several surfaces. t.crossSurface.completeOneSharedValueFromSeveralSurfaces()
| 72 |
| Expected | One command line is built from several surfaces of the desk and completed once, writing one value into the desk's one Programmer. t.crossSurface.completeOneSharedValueFromSeveralSurfaces()
| 72 |
Diagnostics
None.
OSC-006 — exact OSC addresses retain targets with shared page feedback and independent pickup
tests/55-semantic-osc-api-and-cross-surface.spec.ts:76 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICross-surface stateCue timingEncoder controlsOSCPlayback pagesPlaybacksProgrammerProgrammer timingRecordingSelectionShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 80 |
Open the ToskLight browser application.t.app.open()
| 81 |
The ToskLight browser application is ready.t.app.expect.ready()
| 82 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 83 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 85 |
| Step | Encoder → intensity → dimmer → api → set with 25. t.encoder.intensity.dimmer.via.api.set(25)
| 86 |
| Step | Record → playback with 1. t.record.playback(1)
| 87 |
| Step | Playback → api → off with $first (result of record.playback). t.playback.via.api.off(first)
| 88 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 89 |
| Step | Selection → fixtures → api → item with 2. t.selection.fixtures.via.api.item(2)
| 90 |
| Step | Encoder → intensity → dimmer → api → set with 75. t.encoder.intensity.dimmer.via.api.set(75)
| 91 |
| Step | Record → playback with 2. t.record.playback(2)
| 92 |
| Step | Playback → api → off with $second (result of record.playback). t.playback.via.api.off(second)
| 93 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 94 |
| Step | Playback → configure with $first (result of record.playback), {
buttons: [
PlaybackButton.Go,
PlaybackButton.GoBack,
PlaybackButton.Flash
]
}t.playback.configure(first, {
buttons: [PlaybackButton.Go, PlaybackButton.GoBack, PlaybackButton.Flash],
})
| 95 |
| Step | Playback → configure with $second (result of record.playback), {
buttons: [
PlaybackButton.Go,
PlaybackButton.GoBack,
PlaybackButton.Flash
]
}t.playback.configure(second, {
buttons: [PlaybackButton.Go, PlaybackButton.GoBack, PlaybackButton.Flash],
})
| 98 |
| Step | Page → create with 2. t.page.create(2)
| 101 |
| Step | Page → rename with 2, "Page 2". t.page.rename(2, "Page 2")
| 102 |
| Step | Page → map with {
sourceAddress: $second (result of record.playback),
targetAddress: {
page: 2,
position: 1
}
}t.page.map({
sourceAddress: second,
targetAddress: { page: 2, position: 1 },
})
| 103 |
| Step | Cross surface → verify explicit page osc addressing and pickup. t.crossSurface.verifyExplicitPageOscAddressingAndPickup()
| 108 |
| Expected | Playback → runtime: {
page: 2,
position: 1
}{
enabled: true
}t.playback.expect({ page: 2, position: 1 }).runtime({ enabled: true })
| 109 |
| Expected | Playback → runtime: $second (result of record.playback), {
enabled: true
}t.playback.expect(second).runtime({ enabled: true })
| 111 |
Diagnostics
None.
CROSS-003 — relative software, API, and OSC encoder changes bypass Programmer Fade
tests/55-semantic-osc-api-and-cross-surface.spec.ts:115 · migrated-semantic-world · last run: not merged
show: Twelve DimmersAttached hardwareBrowser UICue timingDMX outputEncoder controlsOSCProgrammerProgrammer timingSelectionSemantic oracleShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 119 |
Open the ToskLight browser application.t.app.open()
| 120 |
The ToskLight browser application is ready.t.app.expect.ready()
| 121 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "5s". t.timing.programmerFade.via.api.set("5s")
| 122 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 124 |
| Step | Encoder → intensity → dimmer → ui → set with 0. t.encoder.intensity.dimmer.via.ui.set(0)
| 125 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 126 |
| Expected | <unresolved: beforeDrag.universes.find((item) => item.universe === 1)?.slots[0]> is 0. expect(
beforeDrag.universes.find((item) => item.universe === 1)?.slots[0],
).toBe(0)
| 127 |
| Step | Encoder → intensity → dimmer → ui → drag with "add", "slow". t.encoder.intensity.dimmer.via.ui.drag("add", "slow")
| 130 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 132 |
| Expected | $firstFrame.now (from clock.advanceStep) is $beforeDrag.now (from clock.advanceStep). expect(firstFrame.now).toBe(beforeDrag.now)
| 136 |
| Expected | <unresolved: firstFrame.universes.find((item) => item.universe === 1)?.slots[0]> is <unresolved: Math.round(target * 255)>. expect(
firstFrame.universes.find((item) => item.universe === 1)?.slots[0],
).toBe(Math.round(target * 255))
| 137 |
| Step | Encoder → intensity → dimmer → ui → set with 0. t.encoder.intensity.dimmer.via.ui.set(0)
| 140 |
| Step | Encoder → intensity → dimmer → ui → add with 10. t.encoder.intensity.dimmer.via.ui.add(10)
| 141 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 142 |
| Expected | fixture(1) DMX equals {
Intensity: 26
}t.expectFixtureDMX(fixture(1), { Intensity: 26 })
| 143 |
| Step | Connect the simulated attached hardware surface. t.hardware.connect()
| 145 |
| Step | Encoder → intensity → dimmer → osc → add with 1. t.encoder.intensity.dimmer.via.osc.add(1)
| 147 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 148 |
| Expected | fixture(1) DMX equals {
Intensity: 28
}t.expectFixtureDMX(fixture(1), { Intensity: 28 })
| 149 |
| Step | Disconnect the simulated attached hardware surface. t.hardware.disconnect()
| 151 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 154 |
| Step | Encoder → intensity → dimmer → api → set with 20. t.encoder.intensity.dimmer.via.api.set(20)
| 155 |
| Step | Selection → fixtures → api → item with 2. t.selection.fixtures.via.api.item(2)
| 156 |
| Step | Encoder → intensity → dimmer → api → set with 80. t.encoder.intensity.dimmer.via.api.set(80)
| 157 |
| Step | Selection → fixtures → api → items with 1, 2. t.selection.fixtures.via.api.items(1, 2)
| 158 |
| Step | Encoder → intensity → dimmer → api → add with 10. t.encoder.intensity.dimmer.via.api.add(10)
| 159 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 160 |
| Expected | fixture(1) DMX equals {
Intensity: 77
}t.expectFixtureDMX(fixture(1), { Intensity: 77 })
| 161 |
| Expected | fixture(2) DMX equals {
Intensity: 230
}t.expectFixtureDMX(fixture(2), { Intensity: 230 })
| 162 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: beforeDrag.universes.find((item) => item.universe === 1)?.slots[0]> Expression beforeDrag.universes.find((item) => item.universe === 1)?.slots[0] is not statically resolved. | 128 |
| unresolved-expression | Expected outcome | <unresolved: firstFrame.universes.find((item) => item.universe === 1)?.slots[0]> Expression firstFrame.universes.find((item) => item.universe === 1)?.slots[0] is not statically resolved. | 138 |
| unresolved-expression | Expected outcome | <unresolved: Math.round(target * 255)> Call expression Math.round(target * 255) is dynamic and was not executed. | 139 |
API-001 — authenticated revisioned membership updates preserve one atomic visible Group result
tests/55-semantic-osc-api-and-cross-surface.spec.ts:166 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UIGroupsSelectionSemantic oracleShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 170 |
Open the ToskLight browser application.t.app.open()
| 171 |
The ToskLight browser application is ready.t.app.expect.ready()
| 172 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Group → snapshot with 3. t.group.snapshot(3)
| 174 |
| Expected | Not → to be null: $before (result of group.snapshot). expect(before).not.toBeNull()
| 175 |
| Expected | Group → expect api authentication rejected: 3, $before.revision (from group.snapshot). t.group.expectApiAuthenticationRejected(3, before.revision)
| 177 |
| Step | Selection → fixtures → api → item with 5. t.selection.fixtures.via.api.item(5)
| 178 |
| Step | Group → record via api with 3, StoreMode.Merge, $before.revision (from group.snapshot), "api-001-merge". t.group.recordViaApi(
3,
StoreMode.Merge,
before.revision,
"api-001-merge",
)
| 179 |
| Expected | $changed (result of group.recordViaApi) matches {
status: "changed",
replayed: false,
group: {
state: "stored",
id: "3",
revision: <unresolved: before.revision + 1>
}
}expect(changed).toMatchObject({
status: "changed",
replayed: false,
group: { state: "stored", id: "3", revision: before.revision + 1 },
})
| 185 |
| Step | Group → snapshot with 3. t.group.snapshot(3)
| 190 |
| Expected | Group → expect stale api record rejected: 3, StoreMode.Merge, $before.revision (from group.snapshot), <unresolved: before.revision + 1>. t.group.expectStaleApiRecordRejected(
3,
StoreMode.Merge,
before.revision,
before.revision + 1,
)
| 191 |
| Expected | <unresolved: await t.group.snapshot(3)> equals $afterChanged (result of group.snapshot). expect(await t.group.snapshot(3)).toEqual(afterChanged)
| 197 |
| Expected | Group → fixtures: 3, 1, 2, 3, 4, 5. t.group.expect(3).fixtures(1, 2, 3, 4, 5)
| 198 |
| Step | Group → snapshot with 3. t.group.snapshot(3)
| 199 |
| Expected | $after?.revision (from group.snapshot) is <unresolved: before.revision + 1>. expect(after?.revision).toBe(before.revision + 1)
| 200 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| static-control-flow | Source | The if/else !before has conditional execution; branches are documented separately and no branch is assumed. | 176 |
| unresolved-expression | Expected outcome | <unresolved: before.revision + 1> Expression before.revision + 1 is not statically resolved. | 188 |
| unresolved-expression | Expected outcome | <unresolved: before.revision + 1> Expression before.revision + 1 is not statically resolved. | 195 |
| unresolved-expression | Expected outcome | <unresolved: await t.group.snapshot(3)> Expression await t.group.snapshot(3) is not statically resolved. | 197 |
| unresolved-expression | Expected outcome | <unresolved: before.revision + 1> Expression before.revision + 1 is not statically resolved. | 200 |
API-002 — Group and Cuelist/Cue typed mutations remain ordered visible operations
tests/55-semantic-osc-api-and-cross-surface.spec.ts:204 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICue runtimeEncoder controlsGroupsProgrammerRecordingSelectionSemantic oracleShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 208 |
Open the ToskLight browser application.t.app.open()
| 209 |
The ToskLight browser application is ready.t.app.expect.ready()
| 210 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → items with 1, 2. t.selection.fixtures.via.api.items(1, 2)
| 212 |
| Step | Group → record via api with 90, StoreMode.Overwrite, 0, "api-002-create". t.group.recordViaApi(
90,
StoreMode.Overwrite,
0,
"api-002-create",
)
| 213 |
| Step | Selection → fixtures → api → item with 3. t.selection.fixtures.via.api.item(3)
| 219 |
| Step | Group → record via api with 90, StoreMode.Merge, $created.group.revision (from group.recordViaApi), "api-002-merge". t.group.recordViaApi(
90,
StoreMode.Merge,
created.group.revision,
"api-002-merge",
)
| 220 |
| Expected | Group → fixtures: 90, 1, 2, 3. t.group.expect(90).fixtures(1, 2, 3)
| 226 |
| Step | Group → record via api with 90, "delete", $merged.group.revision (from group.recordViaApi), "api-002-delete". t.group.recordViaApi(
90,
"delete",
merged.group.revision,
"api-002-delete",
)
| 227 |
| Expected | [
$created.group.revision (from group.recordViaApi),
$merged.group.revision (from group.recordViaApi),
$deleted.group.revision (from group.recordViaApi)
] equals [
1,
2,
3
] expect([
created.group.revision,
merged.group.revision,
deleted.group.revision,
]).toEqual([1, 2, 3])
| 233 |
| Expected | eventSequences = [
<unresolved: created.status === "changed" ? created.eventSequence : null>,
<unresolved: merged.status === "changed" ? merged.eventSequence : null>,
<unresolved: deleted.status === "changed" ? deleted.eventSequence : null>
] equals [
<unresolved: expect.any(Number)>,
<unresolved: expect.any(Number)>,
<unresolved: expect.any(Number)>
] expect(eventSequences).toEqual([
expect.any(Number),
expect.any(Number),
expect.any(Number),
])
| 243 |
| Expected | To be less than: <unresolved: created.status === "changed" ? created.eventSequence : null>, <unresolved: eventSequences[1] as number>. expect(eventSequences[0]).toBeLessThan(eventSequences[1] as number)
| 248 |
| Expected | To be less than: <unresolved: merged.status === "changed" ? merged.eventSequence : null>, <unresolved: eventSequences[2] as number>. expect(eventSequences[1]).toBeLessThan(eventSequences[2] as number)
| 249 |
| Expected | $deleted.group (from group.recordViaApi) matches {
state: "deleted",
id: "90"
}expect(deleted.group).toMatchObject({ state: "deleted", id: "90" })
| 250 |
| Expected | Group → absent: 90. t.group.expect(90).absent()
| 251 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 253 |
| Step | Encoder → intensity → dimmer → api → set with 25. t.encoder.intensity.dimmer.via.api.set(25)
| 254 |
| Step | Record → record via api with {
playback: {
page: 1,
position: 1
},
cue: 90
}t.record.recordViaApi({ playback: { page: 1, position: 1 }, cue: 90 })
| 255 |
| Expected | $cueCreated (result of record.recordViaApi) matches {
status: "changed",
recordedCue: {
number: "90",
deleted: false
}
}expect(cueCreated).toMatchObject({
status: "changed",
recordedCue: { number: "90", deleted: false },
})
| 256 |
| Step | Selection → fixtures → api → item with 2. t.selection.fixtures.via.api.item(2)
| 260 |
| Step | Encoder → intensity → dimmer → api → set with 75. t.encoder.intensity.dimmer.via.api.set(75)
| 261 |
| Step | Record → record via api with {
playback: {
page: 1,
position: 1
},
cue: 90
}t.record.recordViaApi({
playback: { page: 1, position: 1 },
cue: 90,
})
| 262 |
| Expected | $cueOverwritten (result of record.recordViaApi) matches {
status: "changed",
recordedCue: {
number: "90",
deleted: false
}
}expect(cueOverwritten).toMatchObject({
status: "changed",
recordedCue: { number: "90", deleted: false },
})
| 266 |
| Expected | To be less than: $cueCreated.showEventSequence (from record.recordViaApi), $cueOverwritten.showEventSequence (from record.recordViaApi). expect(cueCreated.showEventSequence).toBeLessThan(
cueOverwritten.showEventSequence,
)
| 272 |
| Expected | Cue → present: {
page: 1,
position: 1
}, 90. t.cue.expect({ page: 1, position: 1 }, 90).present()
| 275 |
| Step | Record → record via api with {
playback: {
page: 1,
position: 1
},
cue: 91
}t.record.recordViaApi({ playback: { page: 1, position: 1 }, cue: 91 })
| 276 |
| Expected | To be less than: $cueOverwritten.showEventSequence (from record.recordViaApi), $siblingCue.showEventSequence (from record.recordViaApi). expect(cueOverwritten.showEventSequence).toBeLessThan(
siblingCue.showEventSequence,
)
| 279 |
| Expected | Cue → present: {
page: 1,
position: 1
}, 91. t.cue.expect({ page: 1, position: 1 }, 91).present()
| 282 |
| Step | Cue → delete via api with {
page: 1,
position: 1
}, 90. t.cue.deleteViaApi({ page: 1, position: 1 }, 90)
| 283 |
| Expected | $cueDeleted (result of cue.deleteViaApi) matches {
status: "changed",
deletedCue: {
number: "90"
}
}expect(cueDeleted).toMatchObject({
status: "changed",
deletedCue: { number: "90" },
})
| 284 |
| Expected | To be less than: $siblingCue.showEventSequence (from record.recordViaApi), $cueDeleted.showEventSequence (from cue.deleteViaApi). expect(siblingCue.showEventSequence).toBeLessThan(
cueDeleted.showEventSequence,
)
| 290 |
| Expected | Cue → absent: {
page: 1,
position: 1
}, 90. t.cue.expect({ page: 1, position: 1 }, 90).absent()
| 293 |
| Expected | Cue → present: {
page: 1,
position: 1
}, 91. t.cue.expect({ page: 1, position: 1 }, 91).present()
| 294 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| static-control-flow | Source | The conditional expression created.status === "changed" has conditional execution; branches are documented separately and no branch is assumed. | 239 |
| static-control-flow | Source | The conditional expression merged.status === "changed" has conditional execution; branches are documented separately and no branch is assumed. | 240 |
| static-control-flow | Source | The conditional expression deleted.status === "changed" has conditional execution; branches are documented separately and no branch is assumed. | 241 |
| unresolved-expression | Expected outcome | <unresolved: created.status === "changed" ? created.eventSequence : null> Expression created.status === "changed" ? created.eventSequence : null is not statically resolved. | 239 |
| unresolved-expression | Expected outcome | <unresolved: merged.status === "changed" ? merged.eventSequence : null> Expression merged.status === "changed" ? merged.eventSequence : null is not statically resolved. | 240 |
| unresolved-expression | Expected outcome | <unresolved: deleted.status === "changed" ? deleted.eventSequence : null> Expression deleted.status === "changed" ? deleted.eventSequence : null is not statically resolved. | 241 |
| unresolved-expression | Expected outcome | <unresolved: expect.any(Number)> Call expression expect.any(Number) is dynamic and was not executed. | 244 |
| unresolved-expression | Expected outcome | <unresolved: expect.any(Number)> Call expression expect.any(Number) is dynamic and was not executed. | 245 |
| unresolved-expression | Expected outcome | <unresolved: expect.any(Number)> Call expression expect.any(Number) is dynamic and was not executed. | 246 |
| unresolved-expression | Expected outcome | <unresolved: created.status === "changed" ? created.eventSequence : null> Expression created.status === "changed" ? created.eventSequence : null is not statically resolved. | 239 |
| unresolved-expression | Expected outcome | <unresolved: eventSequences[1] as number> Expression eventSequences[1] as number is not statically resolved. | 248 |
| unresolved-expression | Expected outcome | <unresolved: merged.status === "changed" ? merged.eventSequence : null> Expression merged.status === "changed" ? merged.eventSequence : null is not statically resolved. | 240 |
| unresolved-expression | Expected outcome | <unresolved: eventSequences[2] as number> Expression eventSequences[2] as number is not statically resolved. | 249 |
| static-control-flow | Source | The if/else cueCreated.status !== "changed" || cueOverwritten.status !== "changed" has conditional execution; branches are documented separately and no branch is assumed. | 270 |
| static-control-flow | Source | The if/else siblingCue.status !== "changed" has conditional execution; branches are documented separately and no branch is assumed. | 277 |
| static-control-flow | Source | The if/else cueDeleted.status !== "changed" has conditional execution; branches are documented separately and no branch is assumed. | 288 |
CROSS-001 — equivalent group value agrees across command surfaces
tests/55-semantic-osc-api-and-cross-surface.spec.ts:298 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICommand lineDMX outputShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 302 |
Open the ToskLight browser application.t.app.open()
| 303 |
The ToskLight browser application is ready.t.app.expect.ready()
| 304 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "GROUP 1 AT 50". t.command.execute("GROUP 1 AT 50")
| 306 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 307 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 128 })
| 308 |
Diagnostics
None.
CROSS-001 — typed API Group value produces the shared Programmer and wire output
tests/55-semantic-osc-api-and-cross-surface.spec.ts:312 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICross-surface stateDMX outputOSCShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 316 |
Open the ToskLight browser application.t.app.open()
| 317 |
The ToskLight browser application is ready.t.app.expect.ready()
| 318 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Cross surface → apply group one at fifty via api. t.crossSurface.applyGroupOneAtFiftyViaApi()
| 320 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 128 })
| 321 |
Diagnostics
None.
CROSS-001 — real OSC Group command produces the shared Programmer and wire output
tests/55-semantic-osc-api-and-cross-surface.spec.ts:325 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICross-surface stateDMX outputOSCShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 329 |
Open the ToskLight browser application.t.app.open()
| 330 |
The ToskLight browser application is ready.t.app.expect.ready()
| 331 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Cross surface → apply group one at fifty via osc. t.crossSurface.applyGroupOneAtFiftyViaOsc()
| 333 |
| Expected | fixtureRange(1, 12) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixtureRange(1, 12), { Intensity: 128 })
| 334 |
Diagnostics
None.
CROSS-002 — browser live-reconciles external REST and typed live-action mutations
tests/55-semantic-osc-api-and-cross-surface.spec.ts:338 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICross-surface stateGroupsOSCShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 342 |
Open the ToskLight browser application.t.app.open()
| 343 |
The ToskLight browser application is ready.t.app.expect.ready()
| 344 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Cross surface → reconcile external group mutation. t.crossSurface.reconcileExternalGroupMutation()
| 346 |
| Expected | The browser reconciles external Group membership and Programmer value mutations before and after reload. t.crossSurface.reconcileExternalGroupMutation()
| 346 |
| Expected | Group → fixtures: 3, 1, 2, 3, 4, 5. t.group.expect(3).fixtures(1, 2, 3, 4, 5)
| 347 |
Diagnostics
None.
PRELOAD-003 — Playback panes persist sparse addresses with Follow Main and Pinned page sources
tests/55-semantic-virtual-playback-layout.spec.ts:11 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICue timingDesktop layoutEncoder controlsPlaybacksProgrammerProgrammer timingRecordingSelectionSemantic oracleShow filesTyped APIVirtual Playbacks
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 15 |
Open the ToskLight browser application.t.app.open()
| 16 |
The ToskLight browser application is ready.t.app.expect.ready()
| 17 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 18 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 19 |
| Expected | <unresolved: panePlaybackAddress(1, 1)> equals { page: 1, position: 401 }. expect(panePlaybackAddress(1, 1)).toEqual({ page: 1, position: 401 })
| 20 |
| Expected | <unresolved: panePlaybackAddress(300, 1)> equals { page: 1, position: 700 }. expect(panePlaybackAddress(300, 1)).toEqual({ page: 1, position: 700 })
| 21 |
| Expected | <unresolved: panePlaybackAddress(1, 2)> equals { page: 2, position: 401 }. expect(panePlaybackAddress(1, 2)).toEqual({ page: 2, position: 401 })
| 22 |
| Expected | <unresolved: panePlaybackAddress(600, 99)> equals { page: 99, position: 1000 }. expect(panePlaybackAddress(600, 99)).toEqual({ page: 99, position: 1000 })
| 23 |
| Expected | To throw: <generated: callback>, "Playback position must be within 1-1000". expect(() => panePlaybackAddress(601, 1)).toThrow("Playback position must be within 1-1000")
| 24 |
| Step | Clear the current selection. t.selection.clear()
| 31 |
| Step | Selection → fixtures → api → item with fixture = 3. t.selection.fixtures.via.api.item(fixture)
| 32 |
| Step | Encoder → intensity → dimmer → api → set with 20. t.encoder.intensity.dimmer.via.api.set(20)
| 33 |
| Step | Record → playback with slot = 5. t.record.playback(slot)
| 34 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 35 |
| Step | Encoder → intensity → dimmer → api → set with 80. t.encoder.intensity.dimmer.via.api.set(80)
| 36 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 37 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 38 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Virtual Source A",
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Go,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name,
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Go,
PlaybackButton.Empty,
PlaybackButton.Empty,
],
})
| 39 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 49 |
| Step | Clear the current selection. t.selection.clear()
| 31 |
| Step | Selection → fixtures → api → item with fixture = 4. t.selection.fixtures.via.api.item(fixture)
| 32 |
| Step | Encoder → intensity → dimmer → api → set with 20. t.encoder.intensity.dimmer.via.api.set(20)
| 33 |
| Step | Record → playback with slot = 6. t.record.playback(slot)
| 34 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 35 |
| Step | Encoder → intensity → dimmer → api → set with 80. t.encoder.intensity.dimmer.via.api.set(80)
| 36 |
| Step | Record → cue with {
playback: $playback (result of record.playback),
cue: 2
}t.record.cue({ playback, cue: 2 })
| 37 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 38 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Virtual Source B",
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Go,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name,
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Go,
PlaybackButton.Empty,
PlaybackButton.Empty,
],
})
| 39 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 49 |
| Step | Desktop → configure with .desktop: Virtual Playback Desktop t.desktop.configure("Virtual Playback Desktop")
| 56 |
| Step | Add the PaneType.VirtualPlaybacks pane desktop.addPane(
PaneType.VirtualPlaybacks,
{
slug: "virtual-playbacks-follow",
column: 1,
row: 1,
width: 12,
height: 5,
},
{ rows: 2, columns: 6, pageMode: "follow_main" },
)
| 57 |
| Step | Add the PaneType.VirtualPlaybacks pane desktop.addPane(
PaneType.VirtualPlaybacks,
{
slug: "virtual-playbacks-pinned",
column: 1,
row: 6,
width: 12,
height: 5,
},
{ rows: 2, columns: 6, pageMode: "pinned", pinnedPage: 2 },
)
| 68 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 79 |
| Expected | Virtual playback → effective page: $followPane (result of desktopBuilder.addPane), 1. t.virtualPlayback.expect.effectivePage(followPane, 1)
| 83 |
| Expected | Virtual playback → effective page: $pinnedPane (result of desktopBuilder.addPane), 2. t.virtualPlayback.expect.effectivePage(pinnedPane, 2)
| 84 |
| Step | Virtual playback → assign source with $followPane (result of desktopBuilder.addPane), "Virtual Source A", 1, 1. t.virtualPlayback.assignSource(
followPane,
"Virtual Source A",
1,
1,
)
| 86 |
| Step | Virtual playback → assign source with $pinnedPane (result of desktopBuilder.addPane), "Virtual Source B", 1, 2. t.virtualPlayback.assignSource(
pinnedPane,
"Virtual Source B",
1,
2,
)
| 92 |
| Step | Virtual playback → configure top button with $pinnedPane (result of desktopBuilder.addPane), 1, PlaybackButton.Toggle, 2. t.virtualPlayback.configureTopButton(
pinnedPane,
1,
PlaybackButton.Toggle,
2,
)
| 98 |
| Step | Virtual playback → activate with $followPane (result of desktopBuilder.addPane), 1, 1. t.virtualPlayback.activate(followPane, 1, 1)
| 105 |
| Step | Virtual playback → activate with $pinnedPane (result of desktopBuilder.addPane), 1, 2. t.virtualPlayback.activate(pinnedPane, 1, 2)
| 106 |
| Expected | Virtual playback → runtime: $firstPlayback (result of virtualPlayback.assignSource), {
identity: {
kind: "playback",
page: 1,
position: 401
},
target: "cue_list",
runtime: {
enabled: true,
current: {
number: "1"
}
}
}t.virtualPlayback.expect.runtime(firstPlayback, {
identity: {
kind: "playback",
page: 1,
position: 401,
},
target: "cue_list",
runtime: { enabled: true, current: { number: "1" } },
})
| 107 |
| Expected | Virtual playback → runtime: $secondPlayback (result of virtualPlayback.assignSource), {
identity: {
kind: "playback",
page: 2,
position: 401
},
target: "cue_list",
runtime: {
enabled: true,
current: {
number: "1"
}
}
}t.virtualPlayback.expect.runtime(secondPlayback, {
identity: {
kind: "playback",
page: 2,
position: 401,
},
target: "cue_list",
runtime: { enabled: true, current: { number: "1" } },
})
| 116 |
| Expected | Playback → runtime: $firstSource (result of recordSource), {
enabled: true,
current_cue_number: "1"
}t.playback.expect(firstSource).runtime({ enabled: true, current_cue_number: "1" })
| 125 |
| Expected | Playback → runtime: $secondSource (result of recordSource), {
enabled: true,
current_cue_number: "1"
}t.playback.expect(secondSource).runtime({ enabled: true, current_cue_number: "1" })
| 126 |
| Expected | Playback → present: $firstSource (result of recordSource). t.playback.expect(firstSource).present()
| 127 |
| Expected | Playback → present: $secondSource (result of recordSource). t.playback.expect(secondSource).present()
| 128 |
| Step | Virtual playback → set main page with 2. t.virtualPlayback.setMainPage(2)
| 130 |
| Expected | Virtual playback → effective page: $followPane (result of desktopBuilder.addPane), 2. t.virtualPlayback.expect.effectivePage(followPane, 2)
| 131 |
| Expected | Virtual playback → effective page: $pinnedPane (result of desktopBuilder.addPane), 2. t.virtualPlayback.expect.effectivePage(pinnedPane, 2)
| 132 |
| Step | Virtual playback → set main page with 1. t.virtualPlayback.setMainPage(1)
| 133 |
| Expected | Virtual playback → effective page: $followPane (result of desktopBuilder.addPane), 1. t.virtualPlayback.expect.effectivePage(followPane, 1)
| 134 |
| Expected | Virtual playback → effective page: $pinnedPane (result of desktopBuilder.addPane), 2. t.virtualPlayback.expect.effectivePage(pinnedPane, 2)
| 135 |
| Step | Virtual playback → reload with $followPane (result of desktopBuilder.addPane). t.virtualPlayback.reload(followPane)
| 137 |
| Expected | Virtual playback → logical cells: $followPane (result of desktopBuilder.addPane), 12. t.virtualPlayback.expect.logicalCells(followPane, 12)
| 138 |
| Expected | Virtual playback → logical cells: $pinnedPane (result of desktopBuilder.addPane), 12. t.virtualPlayback.expect.logicalCells(pinnedPane, 12)
| 139 |
| Expected | Virtual playback → button: $followPane (result of desktopBuilder.addPane), 1, "GO", 1. t.virtualPlayback.expect.button(followPane, 1, "GO", 1)
| 140 |
| Expected | Virtual playback → button: $pinnedPane (result of desktopBuilder.addPane), 1, "TOGGLE", 2. t.virtualPlayback.expect.button(pinnedPane, 1, "TOGGLE", 2)
| 141 |
| Expected | Virtual playback → assignment: $firstPlayback (result of virtualPlayback.assignSource), {
button_count: 1,
has_fader: false,
buttons: [
"go",
"none",
"none"
]
}t.virtualPlayback.expect.assignment(firstPlayback, {
button_count: 1,
has_fader: false,
buttons: ["go", "none", "none"],
})
| 142 |
| Expected | Virtual playback → assignment: $secondPlayback (result of virtualPlayback.assignSource), {
button_count: 1,
has_fader: false,
buttons: [
"toggle",
"none",
"none"
]
}t.virtualPlayback.expect.assignment(secondPlayback, {
button_count: 1,
has_fader: false,
buttons: ["toggle", "none", "none"],
})
| 147 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: panePlaybackAddress(1, 1)> Call expression panePlaybackAddress(1, 1) is dynamic and was not executed. | 20 |
| unresolved-expression | Expected outcome | <unresolved: panePlaybackAddress(300, 1)> Call expression panePlaybackAddress(300, 1) is dynamic and was not executed. | 21 |
| unresolved-expression | Expected outcome | <unresolved: panePlaybackAddress(1, 2)> Call expression panePlaybackAddress(1, 2) is dynamic and was not executed. | 22 |
| unresolved-expression | Expected outcome | <unresolved: panePlaybackAddress(600, 99)> Call expression panePlaybackAddress(600, 99) is dynamic and was not executed. | 23 |
LOCK-001 — Desk Lock protects every screen and keeps its configuration in Screens
tests/56-semantic-desk-lock.spec.ts:6 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UIDesk LockScreensShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 10 |
Open the ToskLight browser application.t.app.open()
| 11 |
The ToskLight browser application is ready.t.app.expect.ready()
| 12 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | Desk lock → expect pin protection across screens. t.deskLock.expectPinProtectionAcrossScreens()
| 14 |
| Expected | Desk lock → expect button fallback. t.deskLock.expectButtonFallback()
| 15 |
| Expected | Desk lock → expect screen settings ownership. t.deskLock.expectScreenSettingsOwnership()
| 16 |
Diagnostics
None.
VPB-007 — show-owned Solo Region selection is inert, saved winners are authoritative, and regions are explicitly removable
tests/56-semantic-virtual-playback-exclusion-zone.spec.ts:10 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICue timingDesktop layoutEncoder controlsPlaybacksProgrammerProgrammer timingRecordingResolved outputSelectionShow filesTest clockTyped APIVirtual Playbacks
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 14 |
Open the ToskLight browser application.t.app.open()
| 15 |
The ToskLight browser application is ready.t.app.expect.ready()
| 16 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 17 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 18 |
| Step | Clear the current selection. t.selection.clear()
| 26 |
| Step | Selection → fixtures → api → item with fixtureNumber = 3. t.selection.fixtures.via.api.item(fixtureNumber)
| 27 |
| Step | Encoder → intensity → dimmer → api → set with intensity = 25. t.encoder.intensity.dimmer.via.api.set(intensity)
| 28 |
| Step | Record → playback with slot = 5. t.record.playback(slot)
| 29 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 30 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Touring A",
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name,
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty,
],
})
| 31 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 41 |
| Step | Clear the current selection. t.selection.clear()
| 26 |
| Step | Selection → fixtures → api → item with fixtureNumber = 4. t.selection.fixtures.via.api.item(fixtureNumber)
| 27 |
| Step | Encoder → intensity → dimmer → api → set with intensity = 50. t.encoder.intensity.dimmer.via.api.set(intensity)
| 28 |
| Step | Record → playback with slot = 6. t.record.playback(slot)
| 29 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 30 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Touring B",
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name,
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty,
],
})
| 31 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 41 |
| Step | Clear the current selection. t.selection.clear()
| 26 |
| Step | Selection → fixtures → api → item with fixtureNumber = 5. t.selection.fixtures.via.api.item(fixtureNumber)
| 27 |
| Step | Encoder → intensity → dimmer → api → set with intensity = 75. t.encoder.intensity.dimmer.via.api.set(intensity)
| 28 |
| Step | Record → playback with slot = 7. t.record.playback(slot)
| 29 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 30 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Touring C",
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name,
buttonCount: 1,
hasFader: false,
buttons: [
PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty,
],
})
| 31 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 41 |
| Step | Desktop → configure with .desktop: Touring Virtual Playbacks t.desktop.configure("Touring Virtual Playbacks")
| 49 |
| Step | Add the PaneType.VirtualPlaybacks pane desktop.addPane(
PaneType.VirtualPlaybacks,
{
slug: "touring-virtual-playbacks",
column: 1,
row: 1,
width: 12,
height: 10,
},
{ rows: 3, columns: 6 },
)
| 50 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 61 |
| Step | Virtual playback → assign source with $pane (result of desktopBuilder.addPane), "Touring A", 1. t.virtualPlayback.assignSource(
pane,
"Touring A",
1,
)
| 64 |
| Step | Virtual playback → assign source with $pane (result of desktopBuilder.addPane), "Touring B", 2. t.virtualPlayback.assignSource(
pane,
"Touring B",
2,
)
| 69 |
| Step | Virtual playback → assign source with $pane (result of desktopBuilder.addPane), "Touring C", 3. t.virtualPlayback.assignSource(
pane,
"Touring C",
3,
)
| 74 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 1. t.virtualPlayback.activate(pane, 1)
| 79 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 2. t.virtualPlayback.activate(pane, 2)
| 80 |
| Expected | Virtual playback → runtime: $firstPlayback (result of virtualPlayback.assignSource), {
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(firstPlayback, { runtime: { enabled: true } })
| 81 |
| Expected | Virtual playback → runtime: $secondPlayback (result of virtualPlayback.assignSource), {
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(secondPlayback, { runtime: { enabled: true } })
| 82 |
| Step | Virtual playback → create solo region with attached shift with $pane (result of desktopBuilder.addPane), "Touring pair", [
1,
2
] t.virtualPlayback.createSoloRegionWithAttachedShift(
pane,
"Touring pair",
[1, 2],
)
| 84 |
| Expected | Virtual playback → zones: [
{
name: "Touring pair",
members: [
{
page: 1,
position: 401
},
{
page: 1,
position: 402
}
]
}
]t.virtualPlayback.expect.zones([
{ name: "Touring pair", members: [{ page: 1, position: 401 }, { page: 1, position: 402 }] },
])
| 89 |
| Expected | Virtual playback → fence: $pane (result of desktopBuilder.addPane), 1, "top bottom left". t.virtualPlayback.expect.fence(pane, 1, "top bottom left")
| 92 |
| Expected | Virtual playback → fence: $pane (result of desktopBuilder.addPane), 2, "top right bottom". t.virtualPlayback.expect.fence(pane, 2, "top right bottom")
| 93 |
| Expected | Virtual playback → fence: $pane (result of desktopBuilder.addPane), 1, "top bottom left". t.virtualPlayback.expect.fence(pane, 1, "top bottom left")
| 99 |
| Expected | Virtual playback → fence: $pane (result of desktopBuilder.addPane), 2, "top right bottom". t.virtualPlayback.expect.fence(pane, 2, "top right bottom")
| 100 |
| Expected | Virtual playback → fence: $pane (result of desktopBuilder.addPane), 1, "top bottom left". t.virtualPlayback.expect.fence(pane, 1, "top bottom left")
| 99 |
| Expected | Virtual playback → fence: $pane (result of desktopBuilder.addPane), 2, "top right bottom". t.virtualPlayback.expect.fence(pane, 2, "top right bottom")
| 100 |
| Expected | Virtual playback → fence: $pane (result of desktopBuilder.addPane), 1, "top bottom left". t.virtualPlayback.expect.fence(pane, 1, "top bottom left")
| 105 |
| Expected | Virtual playback → fence: $pane (result of desktopBuilder.addPane), 2, "top right bottom". t.virtualPlayback.expect.fence(pane, 2, "top right bottom")
| 106 |
| Expected | Virtual playback → runtime: $firstPlayback (result of virtualPlayback.assignSource), {
identity: {
kind: "playback",
page: 1,
position: 401
},
target: "cue_list",
runtime: {
enabled: false
}
}t.virtualPlayback.expect.runtime(firstPlayback, {
identity: {
kind: "playback",
page: 1,
position: 401,
},
target: "cue_list",
runtime: { enabled: false },
})
| 109 |
| Expected | Virtual playback → runtime: $secondPlayback (result of virtualPlayback.assignSource), {
identity: {
kind: "playback",
page: 1,
position: 402
},
target: "cue_list",
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(secondPlayback, {
identity: {
kind: "playback",
page: 1,
position: 402,
},
target: "cue_list",
runtime: { enabled: true },
})
| 118 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 1. t.virtualPlayback.activate(pane, 1)
| 128 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 2. t.virtualPlayback.activate(pane, 2)
| 129 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 1. t.virtualPlayback.activate(pane, 1)
| 130 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 2. t.virtualPlayback.activate(pane, 2)
| 131 |
| Expected | Virtual playback → runtime: $firstPlayback (result of virtualPlayback.assignSource), {
target: "cue_list",
runtime: {
enabled: false
}
}t.virtualPlayback.expect.runtime(firstPlayback, {
target: "cue_list",
runtime: { enabled: false },
})
| 132 |
| Expected | Virtual playback → runtime: $secondPlayback (result of virtualPlayback.assignSource), {
target: "cue_list",
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(secondPlayback, {
target: "cue_list",
runtime: { enabled: true },
})
| 136 |
| Expected | Virtual playback → runtime: $thirdPlayback (result of virtualPlayback.assignSource), {
target: "cue_list",
runtime: {
enabled: false
}
}t.virtualPlayback.expect.runtime(thirdPlayback, {
target: "cue_list",
runtime: { enabled: false },
})
| 140 |
| Expected | Playback → runtime: $firstSource (result of recordSource), {
enabled: false
}t.playback.expect(firstSource).runtime({ enabled: false })
| 144 |
| Expected | Playback → runtime: $secondSource (result of recordSource), {
enabled: true
}t.playback.expect(secondSource).runtime({ enabled: true })
| 145 |
| Expected | Playback → runtime: $thirdSource (result of recordSource), {
enabled: false
}t.playback.expect(thirdSource).runtime({ enabled: false })
| 146 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 147 |
| Expected | fixture(3) resolved values equal {
intensity: 0
}t.expectFixtureValue(fixture(3), { intensity: 0 })
| 148 |
| Expected | fixture(4) resolved values equal {
intensity: 0.5
}t.expectFixtureValue(fixture(4), { intensity: 0.5 })
| 149 |
| Expected | fixture(5) resolved values equal {
intensity: 0
}t.expectFixtureValue(fixture(5), { intensity: 0 })
| 150 |
| Step | Virtual playback → delete solo region with $pane (result of desktopBuilder.addPane), "Touring pair". t.virtualPlayback.deleteSoloRegion(pane, "Touring pair")
| 152 |
| Expected | Virtual playback → zones: [
] t.virtualPlayback.expect.zones([])
| 153 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 2. t.virtualPlayback.activate(pane, 2)
| 154 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 1. t.virtualPlayback.activate(pane, 1)
| 155 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 2. t.virtualPlayback.activate(pane, 2)
| 156 |
| Expected | Virtual playback → runtime: $firstPlayback (result of virtualPlayback.assignSource), {
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(firstPlayback, {
runtime: { enabled: true },
})
| 157 |
| Expected | Virtual playback → runtime: $secondPlayback (result of virtualPlayback.assignSource), {
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(secondPlayback, {
runtime: { enabled: true },
})
| 160 |
Diagnostics
None.
UPDATE-001 — Update Add New appends ordered Group membership
tests/57-semantic-system-integrations.spec.ts:6 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineGroupsSelectionShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 10 |
Open the ToskLight browser application.t.app.open()
| 11 |
The ToskLight browser application is ready.t.app.expect.ready()
| 12 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → item with 5. t.selection.fixtures.via.api.item(5)
| 13 |
| Step | Execute the desk command "UPDATE ALL GROUP 3" through the API. t.command.via.api.execute("UPDATE ALL GROUP 3")
| 14 |
| Expected | Group → fixtures: 3, 1, 2, 3, 4, 5. t.group.expect(3).fixtures(1, 2, 3, 4, 5)
| 15 |
Diagnostics
None.
HIGHLIGHT-001 — HIGH follows the actual stepped selection
tests/57-semantic-system-integrations.spec.ts:19 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UICommand keypadHighlightSelectionShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 23 |
Open the ToskLight browser application.t.app.open()
| 24 |
The ToskLight browser application is ready.t.app.expect.ready()
| 25 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → items with 101, 102, 103. t.selection.fixtures.via.api.items(101, 102, 103)
| 26 |
| Step | Highlight → on. t.highlight.on()
| 27 |
| Step | Press keypad keys [
"NEXT"
] t.keypad.press(["NEXT"])
| 28 |
| Expected | Highlight → expect selection: 101. t.highlight.expectSelection(101)
| 29 |
| Step | Highlight → wait for control debounce. t.highlight.waitForControlDebounce()
| 30 |
| Step | Press keypad keys [
"NEXT"
] t.keypad.press(["NEXT"])
| 31 |
| Expected | Highlight → expect selection: 102. t.highlight.expectSelection(102)
| 32 |
| Step | Highlight → off. t.highlight.off()
| 33 |
Diagnostics
None.
HIGHLIGHT-002 — HIGH follows external selection and survives an empty selection
tests/57-semantic-system-integrations.spec.ts:37 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UIHighlightSelectionShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 41 |
Open the ToskLight browser application.t.app.open()
| 42 |
The ToskLight browser application is ready.t.app.expect.ready()
| 43 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → items with 101, 102, 103, 104. t.selection.fixtures.via.api.items(101, 102, 103, 104)
| 44 |
| Step | Highlight → on. t.highlight.on()
| 45 |
| Step | Clear the current selection. t.selection.clear()
| 46 |
| Step | Selection → fixtures → api → items with 103, 104. t.selection.fixtures.via.api.items(103, 104)
| 47 |
| Expected | Highlight → expect selection: 103, 104. t.highlight.expectSelection(103, 104)
| 48 |
| Step | Highlight → off. t.highlight.off()
| 49 |
Diagnostics
None.
HIGHLIGHT-003 — PREV NEXT ALL mutate the real selection
tests/57-semantic-system-integrations.spec.ts:53 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UICommand keypadHighlightSelectionShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 57 |
Open the ToskLight browser application.t.app.open()
| 58 |
The ToskLight browser application is ready.t.app.expect.ready()
| 59 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → items with 101, 102, 103, 104. t.selection.fixtures.via.api.items(101, 102, 103, 104)
| 60 |
| Step | Highlight → on. t.highlight.on()
| 61 |
| Step | Press keypad keys [
"NEXT"
] t.keypad.press(["NEXT"])
| 62 |
| Expected | Highlight → expect selection: 101. t.highlight.expectSelection(101)
| 63 |
| Step | Highlight → wait for control debounce. t.highlight.waitForControlDebounce()
| 64 |
| Step | Press keypad keys [
"NEXT"
] t.keypad.press(["NEXT"])
| 65 |
| Expected | Highlight → expect selection: 102. t.highlight.expectSelection(102)
| 66 |
| Step | Highlight → wait for control debounce. t.highlight.waitForControlDebounce()
| 67 |
| Step | Press keypad keys [
"ALL"
] t.keypad.press(["ALL"])
| 68 |
| Expected | Highlight → expect selection: 101, 102, 103, 104. t.highlight.expectSelection(101, 102, 103, 104)
| 69 |
| Step | Highlight → wait for control debounce. t.highlight.waitForControlDebounce()
| 70 |
| Step | Press keypad keys [
"PREV"
] t.keypad.press(["PREV"])
| 71 |
| Expected | Highlight → expect selection: 104. t.highlight.expectSelection(104)
| 72 |
| Step | Highlight → off. t.highlight.off()
| 73 |
Diagnostics
None.
HIGHLIGHT-005 — Highlight errors remain reachable and dismissible
tests/57-semantic-system-integrations.spec.ts:77 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UIDesk integrationsShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 81 |
Open the ToskLight browser application.t.app.open()
| 82 |
The ToskLight browser application is ready.t.app.expect.ready()
| 83 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | System integration → expect highlight error overlay. t.systemIntegration.expectHighlightErrorOverlay()
| 84 |
Diagnostics
None.
FIXTURE-001 — a complete fixture profile is created through the desk library
tests/57-semantic-system-integrations.spec.ts:88 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UIDesk integrationsShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 92 |
Open the ToskLight browser application.t.app.open()
| 93 |
The ToskLight browser application is ready.t.app.expect.ready()
| 94 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | System integration → expect fixture profile creation: "Semantic Acceptance", "Revisioned profile <unresolved: crypto.randomUUID().slice(0, 8)>". t.systemIntegration.expectFixtureProfileCreation(
"Semantic Acceptance",
`Revisioned profile ${crypto.randomUUID().slice(0, 8)}`,
)
| 95 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: crypto.randomUUID().slice(0, 8)> Call expression crypto.randomUUID().slice(0, 8) is dynamic and was not executed. | 97 |
MATTER-001 — the desk-persistent Matter bridge toggles from Network and Inputs
tests/57-semantic-system-integrations.spec.ts:102 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UIDesk integrationsShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 106 |
Open the ToskLight browser application.t.app.open()
| 107 |
The ToskLight browser application is ready.t.app.expect.ready()
| 108 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | System integration → expect matter bridge toggle. t.systemIntegration.expectMatterBridgeToggle()
| 109 |
Diagnostics
None.
SOUND-001 — a desk-local audio observation drives Speed Group A
tests/57-semantic-system-integrations.spec.ts:113 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UIDesk integrationsShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 117 |
Open the ToskLight browser application.t.app.open()
| 118 |
The ToskLight browser application is ready.t.app.expect.ready()
| 119 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | System integration → expect sound to light configuration. t.systemIntegration.expectSoundToLightConfiguration()
| 120 |
Diagnostics
None.
PRELOAD-004 — virtual GO and TOGGLE alone remain pending and share Programmer Fade
tests/57-semantic-virtual-playback-preload.spec.ts:10 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICommand lineCue timingDesktop layoutEncoder controlsPlaybacksPreloadProgrammerProgrammer timingRecordingResolved outputSelectionShow filesTest clockTyped APIVirtual Playbacks
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 14 |
Open the ToskLight browser application.t.app.open()
| 15 |
The ToskLight browser application is ready.t.app.expect.ready()
| 16 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 17 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 18 |
| Step | Clear the current selection. t.selection.clear()
| 27 |
| Step | Selection → fixtures → api → item with fixtureNumber = 3. t.selection.fixtures.via.api.item(fixtureNumber)
| 28 |
| Step | Encoder → intensity → dimmer → api → set with intensity = 100. t.encoder.intensity.dimmer.via.api.set(intensity)
| 29 |
| Step | Record → playback with slot = 5. t.record.playback(slot)
| 30 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 31 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Virtual GO",
buttonCount: 1,
hasFader: false,
buttons: [
button = PlaybackButton.Go,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name,
buttonCount: 1,
hasFader: false,
buttons: [button, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 32 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 38 |
| Step | Clear the current selection. t.selection.clear()
| 27 |
| Step | Selection → fixtures → api → item with fixtureNumber = 4. t.selection.fixtures.via.api.item(fixtureNumber)
| 28 |
| Step | Encoder → intensity → dimmer → api → set with intensity = 80. t.encoder.intensity.dimmer.via.api.set(intensity)
| 29 |
| Step | Record → playback with slot = 6. t.record.playback(slot)
| 30 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 31 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Virtual TOGGLE",
buttonCount: 1,
hasFader: false,
buttons: [
button = PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name,
buttonCount: 1,
hasFader: false,
buttons: [button, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 32 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 38 |
| Step | Clear the current selection. t.selection.clear()
| 27 |
| Step | Selection → fixtures → api → item with fixtureNumber = 5. t.selection.fixtures.via.api.item(fixtureNumber)
| 28 |
| Step | Encoder → intensity → dimmer → api → set with intensity = 60. t.encoder.intensity.dimmer.via.api.set(intensity)
| 29 |
| Step | Record → playback with slot = 3. t.record.playback(slot)
| 30 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 31 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Physical live",
buttonCount: 1,
hasFader: false,
buttons: [
button = PlaybackButton.Go,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name,
buttonCount: 1,
hasFader: false,
buttons: [button, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 32 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 38 |
| Step | Desktop → configure with .desktop: Preload Virtual Playbacks t.desktop.configure("Preload Virtual Playbacks")
| 64 |
| Step | Add the PaneType.VirtualPlaybacks pane desktop.addPane(
PaneType.VirtualPlaybacks,
{
slug: "preload-virtual-playbacks",
column: 1,
row: 1,
width: 12,
height: 10,
},
{ rows: 1, columns: 3 },
)
| 65 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 76 |
| Step | Virtual playback → assign source with $pane (result of desktopBuilder.addPane), "Virtual GO", 1. t.virtualPlayback.assignSource(
pane,
"Virtual GO",
1,
)
| 77 |
| Step | Virtual playback → assign source with $pane (result of desktopBuilder.addPane), "Virtual TOGGLE", 2. t.virtualPlayback.assignSource(
pane,
"Virtual TOGGLE",
2,
)
| 82 |
| Expected | Playback → present: $goSource (result of recordSource). t.playback.expect(goSource).present()
| 87 |
| Expected | Playback → present: $toggleSource (result of recordSource). t.playback.expect(toggleSource).present()
| 88 |
| Step | Preload → configure with {
programmer: false,
playbackScope: {
position_ranges: [
{
start: 401,
end: 402
}
],
pages: null
},
programmerFade: 2500,
cueFade: 8000
}t.preload.configure({
programmer: false,
playbackScope: { position_ranges: [{ start: 401, end: 402 }], pages: null },
programmerFade: 2_500,
cueFade: 8_000,
})
| 90 |
| Step | Start blind Preload programming. t.preload.start()
| 96 |
| Step | Execute the desk command "1 AT 35". t.command.execute("1 AT 35")
| 97 |
| Step | Playback → open. t.playback.open()
| 98 |
| Step | Playback → go with $physicalPlayback (result of recordSource). t.playback.go(physicalPlayback)
| 99 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 1. t.virtualPlayback.activate(pane, 1)
| 100 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 2. t.virtualPlayback.activate(pane, 2)
| 101 |
| Expected | Preload → pending matching: {
groupIds: [
],
playbackActions: [
[
$virtualGo (result of virtualPlayback.assignSource),
"go",
{
surface_id: <unresolved: expect.any(String)>,
control_id: <unresolved: expect.any(Number)>
}
],
[
$virtualToggle (result of virtualPlayback.assignSource),
"toggle",
{
surface_id: <unresolved: expect.any(String)>,
control_id: <unresolved: expect.any(Number)>
}
]
]
}t.preload.expect.pendingMatching({ groupIds: [], playbackActions: [
[virtualGo, "go", { surface_id: expect.any(String), control_id: expect.any(Number) }],
[virtualToggle, "toggle", { surface_id: expect.any(String), control_id: expect.any(Number) }],
] })
| 102 |
| Expected | Playback → runtime: $goSource (result of recordSource), {
enabled: false
}t.playback.expect(goSource).runtime({ enabled: false })
| 106 |
| Expected | Playback → runtime: $toggleSource (result of recordSource), {
enabled: false
}t.playback.expect(toggleSource).runtime({ enabled: false })
| 107 |
| Expected | Playback → runtime: $physicalPlayback (result of recordSource), {
enabled: true,
current_cue_number: "1"
}t.playback.expect(physicalPlayback).runtime({
enabled: true,
current_cue_number: "1",
})
| 108 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 112 |
| Expected | fixture(3) resolved values equal {
intensity: 0
}t.expectFixtureValue(fixture(3), { intensity: 0 })
| 113 |
| Expected | fixture(4) resolved values equal {
intensity: 0
}t.expectFixtureValue(fixture(4), { intensity: 0 })
| 114 |
| Step | Preload → commit. t.preload.commit()
| 116 |
| Expected | Virtual playback → runtime: $virtualGo (result of virtualPlayback.assignSource), {
identity: {
kind: "playback",
page: 1,
position: 401
},
target: "cue_list",
runtime: {
enabled: true,
current: {
number: "1"
}
}
}t.virtualPlayback.expect.runtime(virtualGo, {
identity: {
kind: "playback",
page: 1,
position: 401,
},
target: "cue_list",
runtime: { enabled: true, current: { number: "1" } },
})
| 117 |
| Expected | Virtual playback → runtime: $virtualToggle (result of virtualPlayback.assignSource), {
identity: {
kind: "playback",
page: 1,
position: 402
},
target: "cue_list",
runtime: {
enabled: true,
current: {
number: "1"
}
}
}t.virtualPlayback.expect.runtime(virtualToggle, {
identity: {
kind: "playback",
page: 1,
position: 402,
},
target: "cue_list",
runtime: { enabled: true, current: { number: "1" } },
})
| 126 |
| Step | Advance the test clock by "2500ms". t.clock.advanceBy("2500ms")
| 135 |
| Expected | fixture(3) resolved values equal {
intensity: 1
}t.expectFixtureValue(fixture(3), { intensity: 1 })
| 136 |
| Expected | fixture(4) resolved values equal {
intensity: 0.8
}t.expectFixtureValue(fixture(4), { intensity: 0.8 })
| 137 |
| Step | Release blind Preload programming. t.preload.release()
| 139 |
| Expected | Virtual playback → runtime: $virtualGo (result of virtualPlayback.assignSource), {
target: "cue_list",
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(virtualGo, {
target: "cue_list",
runtime: { enabled: true },
})
| 140 |
| Expected | Virtual playback → runtime: $virtualToggle (result of virtualPlayback.assignSource), {
target: "cue_list",
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(virtualToggle, {
target: "cue_list",
runtime: { enabled: true },
})
| 144 |
| Expected | fixture(1) resolved values equal {
intensity: 0.35
}t.expectFixtureValue(fixture(1), { intensity: 0.35 })
| 148 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: expect.any(String)> Call expression expect.any(String) is dynamic and was not executed. | 103 |
| unresolved-expression | Expected outcome | <unresolved: expect.any(Number)> Call expression expect.any(Number) is dynamic and was not executed. | 103 |
| unresolved-expression | Expected outcome | <unresolved: expect.any(String)> Call expression expect.any(String) is dynamic and was not executed. | 104 |
| unresolved-expression | Expected outcome | <unresolved: expect.any(Number)> Call expression expect.any(Number) is dynamic and was not executed. | 104 |
PRELOAD-005 — programmer capture and four range/page eligibility scopes persist independently
tests/58-semantic-preload-capture-mask.spec.ts:7 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UIPreloadPreload SettingsShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 11 |
Open the ToskLight browser application.t.app.open()
| 12 |
The ToskLight browser application is ready.t.app.expect.ready()
| 13 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Preload → open settings. t.preload.openSettings()
| 27 |
| Step | Preload settings → configure with mask = {
programmer: programmer = false,
playbackScope: playbackScope = {
position_ranges: [
{
start: 1,
end: 1000
}
],
pages: null
}
}settings.configure(mask)
| 31 |
| Expected | Preload settings → mask: mask = {
programmer: programmer = false,
playbackScope: playbackScope = {
position_ranges: [
{
start: 1,
end: 1000
}
],
pages: null
}
}settings.expect.mask(mask)
| 32 |
| Step | Preload settings → configure with mask = {
programmer: programmer = true,
playbackScope: playbackScope = {
position_ranges: [
{
start: 1,
end: 1000
}
],
pages: null
}
}settings.configure(mask)
| 31 |
| Expected | Preload settings → mask: mask = {
programmer: programmer = true,
playbackScope: playbackScope = {
position_ranges: [
{
start: 1,
end: 1000
}
],
pages: null
}
}settings.expect.mask(mask)
| 32 |
| Step | Preload settings → configure with mask = {
programmer: programmer = false,
playbackScope: playbackScope = {
position_ranges: [
{
start: 1,
end: 15
}
],
pages: null
}
}settings.configure(mask)
| 31 |
| Expected | Preload settings → mask: mask = {
programmer: programmer = false,
playbackScope: playbackScope = {
position_ranges: [
{
start: 1,
end: 15
}
],
pages: null
}
}settings.expect.mask(mask)
| 32 |
| Step | Preload settings → configure with mask = {
programmer: programmer = true,
playbackScope: playbackScope = {
position_ranges: [
{
start: 1,
end: 15
}
],
pages: null
}
}settings.configure(mask)
| 31 |
| Expected | Preload settings → mask: mask = {
programmer: programmer = true,
playbackScope: playbackScope = {
position_ranges: [
{
start: 1,
end: 15
}
],
pages: null
}
}settings.expect.mask(mask)
| 32 |
| Step | Preload settings → configure with mask = {
programmer: programmer = false,
playbackScope: playbackScope = {
position_ranges: [
{
start: 301,
end: 305
},
{
start: 401,
end: 680
}
],
pages: [
1,
2
]
}
}settings.configure(mask)
| 31 |
| Expected | Preload settings → mask: mask = {
programmer: programmer = false,
playbackScope: playbackScope = {
position_ranges: [
{
start: 301,
end: 305
},
{
start: 401,
end: 680
}
],
pages: [
1,
2
]
}
}settings.expect.mask(mask)
| 32 |
| Step | Preload settings → configure with mask = {
programmer: programmer = true,
playbackScope: playbackScope = {
position_ranges: [
{
start: 301,
end: 305
},
{
start: 401,
end: 680
}
],
pages: [
1,
2
]
}
}settings.configure(mask)
| 31 |
| Expected | Preload settings → mask: mask = {
programmer: programmer = true,
playbackScope: playbackScope = {
position_ranges: [
{
start: 301,
end: 305
},
{
start: 401,
end: 680
}
],
pages: [
1,
2
]
}
}settings.expect.mask(mask)
| 32 |
| Step | Preload settings → configure with mask = {
programmer: programmer = false,
playbackScope: playbackScope = {
position_ranges: [
{
start: 101,
end: 115
}
],
pages: [
99
]
}
}settings.configure(mask)
| 31 |
| Expected | Preload settings → mask: mask = {
programmer: programmer = false,
playbackScope: playbackScope = {
position_ranges: [
{
start: 101,
end: 115
}
],
pages: [
99
]
}
}settings.expect.mask(mask)
| 32 |
| Step | Preload settings → configure with mask = {
programmer: programmer = true,
playbackScope: playbackScope = {
position_ranges: [
{
start: 101,
end: 115
}
],
pages: [
99
]
}
}settings.configure(mask)
| 31 |
| Expected | Preload settings → mask: mask = {
programmer: programmer = true,
playbackScope: playbackScope = {
position_ranges: [
{
start: 101,
end: 115
}
],
pages: [
99
]
}
}settings.expect.mask(mask)
| 32 |
Diagnostics
None.
PRELOAD-006 — combined Preload commits atomically and releases only programmer data
tests/59-semantic-combined-preload.spec.ts:10 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICommand lineCue timingDesktop layoutEncoder controlsPlaybacksPreloadProgrammerProgrammer timingRecordingResolved outputSelectionShow filesTest clockTyped APIVirtual Playbacks
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 14 |
Open the ToskLight browser application.t.app.open()
| 15 |
The ToskLight browser application is ready.t.app.expect.ready()
| 16 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 17 |
| Step | Timing → cue fade → set with "0s". t.timing.cueFade.set("0s")
| 18 |
| Step | Clear the current selection. t.selection.clear()
| 27 |
| Step | Selection → fixtures → api → item with fixtureNumber = 1. t.selection.fixtures.via.api.item(fixtureNumber)
| 28 |
| Step | Encoder → intensity → dimmer → api → set with intensity = 25. t.encoder.intensity.dimmer.via.api.set(intensity)
| 29 |
| Step | Record → playback with slot = 5. t.record.playback(slot)
| 30 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 31 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Underlying source",
buttonCount: 1,
hasFader: false,
buttons: [
button = PlaybackButton.Go,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name,
buttonCount: 1,
hasFader: false,
buttons: [button, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 32 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 38 |
| Step | Clear the current selection. t.selection.clear()
| 27 |
| Step | Selection → fixtures → api → item with fixtureNumber = 3. t.selection.fixtures.via.api.item(fixtureNumber)
| 28 |
| Step | Encoder → intensity → dimmer → api → set with intensity = 60. t.encoder.intensity.dimmer.via.api.set(intensity)
| 29 |
| Step | Record → playback with slot = 1. t.record.playback(slot)
| 30 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 31 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Physical combined",
buttonCount: 1,
hasFader: false,
buttons: [
button = PlaybackButton.Go,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name,
buttonCount: 1,
hasFader: false,
buttons: [button, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 32 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 38 |
| Step | Clear the current selection. t.selection.clear()
| 27 |
| Step | Selection → fixtures → api → item with fixtureNumber = 4. t.selection.fixtures.via.api.item(fixtureNumber)
| 28 |
| Step | Encoder → intensity → dimmer → api → set with intensity = 80. t.encoder.intensity.dimmer.via.api.set(intensity)
| 29 |
| Step | Record → playback with slot = 6. t.record.playback(slot)
| 30 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 31 |
| Step | Playback → configure with $playback (result of record.playback), {
name: name = "Virtual combined",
buttonCount: 1,
hasFader: false,
buttons: [
button = PlaybackButton.Toggle,
PlaybackButton.Empty,
PlaybackButton.Empty
]
}t.playback.configure(playback, {
name,
buttonCount: 1,
hasFader: false,
buttons: [button, PlaybackButton.Empty, PlaybackButton.Empty],
})
| 32 |
| Step | Playback → api → off with $playback (result of record.playback). t.playback.via.api.off(playback)
| 38 |
| Step | Preload → configure with {
programmer: true,
playbackScope: {
position_ranges: [
{
start: 1,
end: 1000
}
],
pages: null
},
programmerFade: 1500,
cueFade: 8000
}t.preload.configure({
programmer: true,
playbackScope: { position_ranges: [{ start: 1, end: 1000 }], pages: null },
programmerFade: 1_500,
cueFade: 8_000,
})
| 57 |
| Step | Playback → api → go with $underlying (result of recordSource). t.playback.via.api.go(underlying)
| 63 |
| Step | Advance the test clock by "8s". t.clock.advanceBy("8s")
| 64 |
| Expected | fixture(1) resolved values equal {
intensity: 0.25
}t.expectFixtureValue(fixture(1), { intensity: 0.25 })
| 65 |
| Step | Desktop → configure with .desktop: Combined Preload t.desktop.configure("Combined Preload")
| 67 |
| Step | Add the PaneType.VirtualPlaybacks pane desktop.addPane(
PaneType.VirtualPlaybacks,
{
slug: "combined-preload",
column: 1,
row: 1,
width: 12,
height: 10,
},
{ rows: 1, columns: 2 },
)
| 68 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 79 |
| Step | Virtual playback → assign source with $pane (result of desktopBuilder.addPane), "Virtual combined", 2. t.virtualPlayback.assignSource(
pane,
"Virtual combined",
2,
)
| 80 |
| Step | Start blind Preload programming. t.preload.start()
| 86 |
| Step | Execute the desk command "GROUP 1 AT 80". t.command.execute("GROUP 1 AT 80")
| 87 |
| Step | Playback → open. t.playback.open()
| 88 |
| Step | Playback → go with $physicalPlayback (result of recordSource). t.playback.go(physicalPlayback)
| 89 |
| Step | Virtual playback → activate with $pane (result of desktopBuilder.addPane), 2. t.virtualPlayback.activate(pane, 2)
| 90 |
| Expected | Preload → pending matching: {
groupIds: [
"1"
],
playbackActions: [
[
$physicalPlayback (result of recordSource),
"go",
{
surface_id: <unresolved: expect.any(String)>,
control_id: <unresolved: expect.any(Number)>
}
],
[
$virtualPlayback (result of virtualPlayback.assignSource),
"toggle",
{
surface_id: <unresolved: expect.any(String)>,
control_id: <unresolved: expect.any(Number)>
}
]
]
}t.preload.expect.pendingMatching({ groupIds: ["1"], playbackActions: [
[physicalPlayback, "go", { surface_id: expect.any(String), control_id: expect.any(Number) }],
[virtualPlayback, "toggle", { surface_id: expect.any(String), control_id: expect.any(Number) }],
] })
| 91 |
| Step | Preload → commit. t.preload.commit()
| 96 |
| Expected | Preload → atomic commit: "1", [
$physicalPlayback (result of recordSource),
$virtualPlayback (result of virtualPlayback.assignSource)
] t.preload.expect.atomicCommit("1", [
physicalPlayback,
virtualPlayback,
])
| 97 |
| Step | Advance the test clock by "1500ms". t.clock.advanceBy("1500ms")
| 101 |
| Expected | fixture(1) resolved values equal {
intensity: 0.8
}t.expectFixtureValue(fixture(1), { intensity: 0.8 })
| 102 |
| Expected | Playback → runtime: $physicalPlayback (result of recordSource), {
enabled: true,
current_cue_number: "1"
}t.playback.expect(physicalPlayback).runtime({
enabled: true,
current_cue_number: "1",
})
| 103 |
| Expected | Virtual playback → runtime: $virtualPlayback (result of virtualPlayback.assignSource), {
runtime: {
enabled: true,
current: {
number: "1"
}
}
}t.virtualPlayback.expect.runtime(virtualPlayback, {
runtime: {
enabled: true,
current: { number: "1" },
},
})
| 107 |
| Step | Release blind Preload programming. t.preload.release()
| 114 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 116 |
| Expected | fixture(1) resolved values equal {
intensity: 0.25
}t.expectFixtureValue(fixture(1), { intensity: 0.25 })
| 117 |
| Expected | Playback → runtime: $physicalPlayback (result of recordSource), {
enabled: true
}t.playback.expect(physicalPlayback).runtime({ enabled: true })
| 118 |
| Expected | Virtual playback → runtime: $virtualPlayback (result of virtualPlayback.assignSource), {
runtime: {
enabled: true
}
}t.virtualPlayback.expect.runtime(virtualPlayback, {
runtime: { enabled: true },
})
| 119 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: expect.any(String)> Call expression expect.any(String) is dynamic and was not executed. | 92 |
| unresolved-expression | Expected outcome | <unresolved: expect.any(Number)> Call expression expect.any(Number) is dynamic and was not executed. | 92 |
| unresolved-expression | Expected outcome | <unresolved: expect.any(String)> Call expression expect.any(String) is dynamic and was not executed. | 93 |
| unresolved-expression | Expected outcome | <unresolved: expect.any(Number)> Call expression expect.any(Number) is dynamic and was not executed. | 93 |
MIB-001 — a dark fixture prepositions for its next lit Cue
tests/60-semantic-move-in-black.spec.ts:7 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UICue runtimeMove in BlackPlaybacksResolved outputShow PatchShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 11 |
Open the ToskLight browser application.t.app.open()
| 18 |
The ToskLight browser application is ready.t.app.expect.ready()
| 19 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Move in black → install with {
enabledFixture: 101,
disabledFixture: 102,
playback: 1,
delay: "1s"
}t.moveInBlack.install({
enabledFixture: 101,
disabledFixture: 102,
playback: 1,
delay: "1s",
})
| 12 |
| Expected | Move in black → expect configuration: 101, {
enabled: true,
delay: "1s"
}t.moveInBlack.expectConfiguration(101, {
enabled: true,
delay: "1s",
})
| 21 |
| Expected | Move in black → expect configuration: 102, {
enabled: false,
delay: "1s"
}t.moveInBlack.expectConfiguration(102, {
enabled: false,
delay: "1s",
})
| 25 |
| Step | Move in black → ui → select fixture with 101. t.moveInBlack.via.ui.selectFixture(101)
| 29 |
| Step | Move in black → ui → set enabled with 101, false. t.moveInBlack.via.ui.setEnabled(101, false)
| 30 |
| Step | Move in black → ui → set enabled with 101, true. t.moveInBlack.via.ui.setEnabled(101, true)
| 31 |
| Step | Move in black → ui → set delay with 101, "1200ms". t.moveInBlack.via.ui.setDelay(101, "1200ms")
| 32 |
| Step | Move in black → ui → set delay with 101, "1s". t.moveInBlack.via.ui.setDelay(101, "1s")
| 33 |
| Step | Move in black → reopen patch. t.moveInBlack.reopenPatch()
| 34 |
| Expected | Move in black → expect configuration: 101, {
enabled: true,
delay: "1s"
}t.moveInBlack.expectConfiguration(101, {
enabled: true,
delay: "1s",
})
| 35 |
| Step | Move in black → reset. t.moveInBlack.reset()
| 40 |
| Step | Playback → open. t.playback.open()
| 41 |
| Step | Playback → go with {
page: 1,
position: 1
}t.playback.go({ page: 1, position: 1 })
| 42 |
| Step | Playback → go with {
page: 1,
position: 1
}t.playback.go({ page: 1, position: 1 })
| 43 |
| Step | Advance the test clock by "1999ms". t.clock.advanceBy("1999ms")
| 47 |
| Expected | fixture(101) resolved values equal {
"position:pan": <unresolved: -161.918>
}t.expectFixtureValue(fixture(101), { "position:pan": -161.918 })
| 48 |
| Expected | Move in black → expect state: 101, {
state: "delaying",
currentCue: "2",
targetCue: "3"
}t.moveInBlack.expectState(101, {
state: "delaying",
currentCue: "2",
targetCue: "3",
})
| 49 |
| Step | Advance the test clock by "1ms". t.clock.advanceBy("1ms")
| 55 |
| Expected | fixture(101) resolved values equal {
intensity: 0,
"position:pan": <unresolved: -162>
}t.expectFixtureValue(fixture(101), { intensity: 0, "position:pan": -162 })
| 56 |
| Expected | Move in black → expect state: 101, {
state: "delaying",
currentCue: "2",
targetCue: "3"
}t.moveInBlack.expectState(101, {
state: "delaying",
currentCue: "2",
targetCue: "3",
})
| 57 |
| Expected | Move in black → expect safety delay: 101, "1s". t.moveInBlack.expectSafetyDelay(101, "1s")
| 62 |
| Expected | Move in black → expect state: 102, {
state: "disabled",
currentCue: "2",
targetCue: "3"
}t.moveInBlack.expectState(102, {
state: "disabled",
currentCue: "2",
targetCue: "3",
})
| 63 |
| Step | Advance the test clock by "999ms". t.clock.advanceBy("999ms")
| 70 |
| Expected | fixture(101) resolved values equal {
"position:pan": <unresolved: -161.918>
}t.expectFixtureValue(fixture(101), { "position:pan": -161.918 })
| 71 |
| Step | Advance the test clock by "1ms". t.clock.advanceBy("1ms")
| 72 |
| Expected | Move in black → expect state: 101, {
state: "moving",
currentCue: "2",
targetCue: "3"
}t.moveInBlack.expectState(101, {
state: "moving",
currentCue: "2",
targetCue: "3",
})
| 73 |
| Expected | fixture(101) resolved values equal {
"position:pan": <unresolved: -161.811>
}t.expectFixtureValue(fixture(101), { "position:pan": -161.811 })
| 78 |
| Step | Advance the test clock by "1500ms". t.clock.advanceBy("1500ms")
| 80 |
| Expected | fixture(101) resolved values equal {
intensity: 0,
"position:pan": 0.149
}t.expectFixtureValue(fixture(101), { intensity: 0, "position:pan": 0.149 })
| 81 |
| Expected | fixture(102) resolved values equal {
"position:pan": <unresolved: -162>
}t.expectFixtureValue(fixture(102), { "position:pan": -162 })
| 82 |
| Step | Advance the test clock by "1500ms". t.clock.advanceBy("1500ms")
| 83 |
| Expected | fixture(101) resolved values equal {
intensity: 0,
"position:pan": 162
}t.expectFixtureValue(fixture(101), { intensity: 0, "position:pan": 162 })
| 84 |
| Expected | fixture(102) resolved values equal {
"position:pan": <unresolved: -162>
}t.expectFixtureValue(fixture(102), { "position:pan": -162 })
| 85 |
| Expected | Move in black → expect state: 101, {
state: "completed",
currentCue: "2",
targetCue: "3"
}t.moveInBlack.expectState(101, {
state: "completed",
currentCue: "2",
targetCue: "3",
})
| 86 |
| Step | Playback → go with {
page: 1,
position: 1
}t.playback.go({ page: 1, position: 1 })
| 92 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 93 |
| Expected | fixture(101) resolved values equal {
"position:pan": 162
}t.expectFixtureValue(fixture(101), { "position:pan": 162 })
| 94 |
| Expected | fixture(102) resolved values equal {
"position:pan": <unresolved: -162>
}t.expectFixtureValue(fixture(102), { "position:pan": -162 })
| 95 |
| Step | Advance the test clock by "1500ms". t.clock.advanceBy("1500ms")
| 96 |
| Expected | fixture(101) resolved values equal {
"position:pan": 162
}t.expectFixtureValue(fixture(101), { "position:pan": 162 })
| 97 |
| Expected | fixture(102) resolved values equal {
"position:pan": 0
}t.expectFixtureValue(fixture(102), { "position:pan": 0 })
| 98 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: -161.918> Expression -161.918 is not statically resolved. | 48 |
| unresolved-expression | Expected outcome | <unresolved: -162> Expression -162 is not statically resolved. | 56 |
| unresolved-expression | Expected outcome | <unresolved: -161.918> Expression -161.918 is not statically resolved. | 71 |
| unresolved-expression | Expected outcome | <unresolved: -161.811> Expression -161.811 is not statically resolved. | 78 |
| unresolved-expression | Expected outcome | <unresolved: -162> Expression -162 is not statically resolved. | 82 |
| unresolved-expression | Expected outcome | <unresolved: -162> Expression -162 is not statically resolved. | 85 |
| unresolved-expression | Expected outcome | <unresolved: -162> Expression -162 is not statically resolved. | 95 |
PBK-001 — Set inspection resolves one playback identity and Close is mutation-free
tests/61-semantic-playback-configuration.spec.ts:8 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UIPlayback ConfigurationPlaybacksShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 12 |
Open the ToskLight browser application.t.app.open()
| 14 |
The ToskLight browser application is ready.t.app.expect.ready()
| 15 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Playback configuration → prepare inspection. t.playbackConfiguration.prepareInspection()
| 13 |
| Expected | Playback configuration → expect inspection without mutation: 1, {
address: {
page: 1,
position: 1
},
targetType: "cue_list",
buttons: [
"go_minus",
"go",
"flash"
],
buttonCount: 3,
fader: "master",
hasFader: true,
color: "#20c997"
}t.playbackConfiguration.expectInspectionWithoutMutation(1, {
address: {page:1,position:1},
targetType: "cue_list",
buttons: ["go_minus", "go", "flash"],
buttonCount: 3,
fader: "master",
hasFader: true,
color: "#20c997",
})
| 16 |
Diagnostics
None.
PBK-002 — Cue List assignment, color, and None plus Apply clear are atomic
tests/61-semantic-playback-configuration.spec.ts:28 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UIPlayback ConfigurationPlaybacksShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 32 |
Open the ToskLight browser application.t.app.open()
| 34 |
The ToskLight browser application is ready.t.app.expect.ready()
| 35 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Playback configuration → prepare assignment. t.playbackConfiguration.prepareAssignment()
| 33 |
| Step | Playback configuration → assign cue list with 1, "Configured Sequence", "#8b5cf6". t.playbackConfiguration.assignCueList(
1,
"Configured Sequence",
"#8b5cf6",
)
| 36 |
| Expected | Playback configuration → expect assignment: 1, {
targetType: "cue_list",
cueList: "Configured Sequence",
buttons: [
"go_minus",
"go",
"flash"
],
buttonCount: 3,
fader: "master",
hasFader: true,
color: "#8b5cf6"
}t.playbackConfiguration.expectAssignment(1, {
targetType: "cue_list",
cueList: "Configured Sequence",
buttons: ["go_minus", "go", "flash"],
buttonCount: 3,
fader: "master",
hasFader: true,
color: "#8b5cf6",
})
| 41 |
| Step | Playback configuration → clear with 1. t.playbackConfiguration.clear(1)
| 50 |
| Expected | Playback configuration → expect unassigned: 1. t.playbackConfiguration.expectUnassigned(1)
| 51 |
| Expected | Playback configuration → expect cue list present: "Configured Sequence". t.playbackConfiguration.expectCueListPresent("Configured Sequence")
| 52 |
Diagnostics
None.
PBK-003 — default navigation and remapped Select Contents dispatch one exact action
tests/61-semantic-playback-configuration.spec.ts:56 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UIPlayback ConfigurationPlaybacksShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 60 |
Open the ToskLight browser application.t.app.open()
| 62 |
The ToskLight browser application is ready.t.app.expect.ready()
| 63 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Playback configuration → prepare action matrix. t.playbackConfiguration.prepareActionMatrix()
| 61 |
| Step | Playback → go with {
page: 1,
position: 1
}t.playback.go({ page: 1, position: 1 })
| 64 |
| Step | Playback → go with {
page: 1,
position: 1
}t.playback.go({ page: 1, position: 1 })
| 65 |
| Step | Playback → go back with {
page: 1,
position: 1
}t.playback.goBack({ page: 1, position: 1 })
| 66 |
| Expected | Playback → runtime: {
page: 1,
position: 1
}{
current_cue_number: "1"
}t.playback.expect({ page: 1, position: 1 }).runtime({ current_cue_number: "1" })
| 67 |
| Step | Playback configuration → set button with 1, "Top button", "Select contents". t.playbackConfiguration.setButton(1, "Top button", "Select contents")
| 68 |
| Expected | Playback configuration → expect assignment: 1, {
address: {
page: 1,
position: 1
},
buttons: [
"select_contents",
"go",
"flash"
]
}t.playbackConfiguration.expectAssignment(1, {
address: {page:1,position:1},
buttons: ["select_contents", "go", "flash"],
})
| 69 |
| Step | Playback configuration → select contents without playback mutation with 1, 1, {
fixtures: [
1,
2
],
group: 3
}t.playbackConfiguration.selectContentsWithoutPlaybackMutation(1, 1, {
fixtures: [1, 2],
group: 3,
})
| 73 |
Diagnostics
None.
PBK-004 — X-fade travel advances one Cue and preserves manual direction and timing
tests/61-semantic-playback-configuration.spec.ts:80 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICue runtimePlayback ConfigurationPlaybacksResolved outputShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 84 |
Open the ToskLight browser application.t.app.open()
| 86 |
The ToskLight browser application is ready.t.app.expect.ready()
| 87 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Playback configuration → prepare crossfade. t.playbackConfiguration.prepareCrossfade()
| 85 |
| Step | Playback → fader with {
page: 1,
position: 1
}, 25. t.playback.fader({ page: 1, position: 1 }, 25)
| 88 |
| Expected | Playback → runtime: {
page: 1,
position: 1
}{
current_cue_number: "1",
manual_xfade_position: 0.25,
manual_xfade_progress: 0.25,
manual_xfade_direction: "towards_high"
}t.playback.expect({ page: 1, position: 1 }).runtime({
current_cue_number: "1",
manual_xfade_position: 0.25,
manual_xfade_progress: 0.25,
manual_xfade_direction: "towards_high",
})
| 89 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 96 |
| Expected | fixture(1) resolved values equal {
intensity: 0.25
}t.expectFixtureValue(fixture(1), { intensity: 0.25 })
| 97 |
| Step | Playback → fader with {
page: 1,
position: 1
}, 100. t.playback.fader({ page: 1, position: 1 }, 100)
| 98 |
| Expected | Playback → runtime: {
page: 1,
position: 1
}{
current_cue_number: "2",
manual_xfade_position: 1,
manual_xfade_direction: "towards_low"
}t.playback.expect({ page: 1, position: 1 }).runtime({
current_cue_number: "2",
manual_xfade_position: 1,
manual_xfade_direction: "towards_low",
})
| 99 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 104 |
| Expected | fixture(1) resolved values equal {
intensity: 1
}t.expectFixtureValue(fixture(1), { intensity: 1 })
| 105 |
| Expected | Cue → metadata: {
page: 1,
position: 1
}, 1, {
fade_millis: 30000,
delay_millis: 10000
}t.cue
.expect({ page: 1, position: 1 }, 1)
.metadata({ fade_millis: 30_000, delay_millis: 10_000 })
| 106 |
| Expected | Cue → metadata: {
page: 1,
position: 1
}, 2, {
fade_millis: 30000,
delay_millis: 10000
}t.cue
.expect({ page: 1, position: 1 }, 2)
.metadata({ fade_millis: 30_000, delay_millis: 10_000 })
| 109 |
Diagnostics
None.
PBK-005 — Temp and held Swap have explicit lifetimes and restore the underlying playback
tests/61-semantic-playback-configuration.spec.ts:115 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UIPlayback ConfigurationPlaybacksResolved outputShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 119 |
Open the ToskLight browser application.t.app.open()
| 121 |
The ToskLight browser application is ready.t.app.expect.ready()
| 122 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Playback configuration → prepare temp and swap. t.playbackConfiguration.prepareTempAndSwap()
| 120 |
| Step | Playback → open. t.playback.open()
| 123 |
| Step | Playback → ui → temp with {
page: 1,
position: 2
}t.playback.via.ui.temp({ page: 1, position: 2 })
| 124 |
| Expected | Playback configuration → expect temporary: 2, true. t.playbackConfiguration.expectTemporary(2, true)
| 125 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 126 |
| Expected | fixture(1) resolved values equal {
intensity: 0.8
}t.expectFixtureValue(fixture(1), { intensity: 0.8 })
| 127 |
| Expected | fixture(2) resolved values equal {
intensity: 0.6
}t.expectFixtureValue(fixture(2), { intensity: 0.6 })
| 128 |
| Expected | fixture(3) resolved values equal {
intensity: 0.4
}t.expectFixtureValue(fixture(3), { intensity: 0.4 })
| 129 |
| Step | Playback → ui → temp with {
page: 1,
position: 2
}t.playback.via.ui.temp({ page: 1, position: 2 })
| 130 |
| Expected | Playback configuration → expect temporary: 2, false. t.playbackConfiguration.expectTemporary(2, false)
| 131 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 132 |
| Expected | fixture(1) resolved values equal {
intensity: 0.3
}t.expectFixtureValue(fixture(1), { intensity: 0.3 })
| 133 |
| Step | Playback → ui → swap → hold with {
page: 1,
position: 2
}, <generated: callback>. t.playback.via.ui.swap({ page: 1, position: 2 }).hold(async () => {
await t.playbackConfiguration.expectSwap(2, true);
await t.clock.advanceBy("0ms");
await t.expectFixtureValue(fixture(1), { intensity: 0.8 });
await t.expectFixtureValue(fixture(2), { intensity: 0 });
await t.expectFixtureValue(fixture(3), { intensity: 0.4 });
})
| 135 |
| Expected | Playback configuration → expect swap: 2, true. t.playbackConfiguration.expectSwap(2, true)
| 136 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 137 |
| Expected | fixture(1) resolved values equal {
intensity: 0.8
}t.expectFixtureValue(fixture(1), { intensity: 0.8 })
| 138 |
| Expected | fixture(2) resolved values equal {
intensity: 0
}t.expectFixtureValue(fixture(2), { intensity: 0 })
| 139 |
| Expected | fixture(3) resolved values equal {
intensity: 0.4
}t.expectFixtureValue(fixture(3), { intensity: 0.4 })
| 140 |
| Expected | Playback configuration → expect swap: 2, false. t.playbackConfiguration.expectSwap(2, false)
| 142 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 143 |
| Expected | fixture(1) resolved values equal {
intensity: 0.3
}t.expectFixtureValue(fixture(1), { intensity: 0.3 })
| 144 |
| Expected | fixture(2) resolved values equal {
intensity: 0.6
}t.expectFixtureValue(fixture(2), { intensity: 0.6 })
| 145 |
| Expected | fixture(3) resolved values equal {
intensity: 0.4
}t.expectFixtureValue(fixture(3), { intensity: 0.4 })
| 146 |
| Expected | Playback → runtime: {
page: 1,
position: 1
}{
enabled: true
}t.playback.expect({ page: 1, position: 1 }).runtime({ enabled: true })
| 147 |
| Expected | Playback → runtime: {
page: 1,
position: 3
}{
enabled: true
}t.playback.expect({ page: 1, position: 3 }).runtime({ enabled: true })
| 148 |
| Expected | Playback → runtime: {
page: 1,
position: 4
}{
enabled: true
}t.playback.expect({ page: 1, position: 4 }).runtime({ enabled: true })
| 149 |
Diagnostics
None.
PBK-006 — specialized layouts control their authoritative Speed, Group, Grand, and Fade masters
tests/61-semantic-playback-configuration.spec.ts:153 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UIPlayback ConfigurationPlaybacksShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 157 |
Open the ToskLight browser application.t.app.open()
| 159 |
The ToskLight browser application is ready.t.app.expect.ready()
| 160 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Playback configuration → prepare masters. t.playbackConfiguration.prepareMasters()
| 158 |
| Step | Playback configuration → press with 1, "DOUBLE". t.playbackConfiguration.press(1, "DOUBLE")
| 161 |
| Step | Playback configuration → set slot fader with 1, 0.5. t.playbackConfiguration.setSlotFader(1, 0.5)
| 162 |
| Step | Playback configuration → set slot fader with 2, 0.4. t.playbackConfiguration.setSlotFader(2, 0.4)
| 163 |
| Step | Playback configuration → press with 2, "SELECT". t.playbackConfiguration.press(2, "SELECT")
| 164 |
| Step | Playback configuration → set slot fader with 3, 0.3. t.playbackConfiguration.setSlotFader(3, 0.3)
| 165 |
| Step | Playback configuration → press with 3, "BLACKOUT". t.playbackConfiguration.press(3, "BLACKOUT")
| 166 |
| Step | Playback configuration → set slot fader with 4, 0.25. t.playbackConfiguration.setSlotFader(4, 0.25)
| 167 |
| Step | Playback configuration → set slot fader with 5, 0.25. t.playbackConfiguration.setSlotFader(5, 0.25)
| 168 |
| Expected | Playback configuration → expect masters: {
speed: {
manualBpm: 240,
effectiveBpm: 120,
paused: false
},
neighborBpms: [
96,
72,
60,
48
],
group: {
master: 0.4,
flashLevel: 0
},
grand: {
level: 0.3,
effectiveLevel: 0.3,
blackout: true,
dynamicsPaused: false
},
programmerFadeMillis: 5000,
cueFadeMillis: 15000
}t.playbackConfiguration.expectMasters({
speed: { manualBpm: 240, effectiveBpm: 120, paused: false },
neighborBpms: [96, 72, 60, 48],
group: { master: 0.4, flashLevel: 0 },
grand: {
level: 0.3,
effectiveLevel: 0.3,
blackout: true,
dynamicsPaused: false,
},
programmerFadeMillis: 5_000,
cueFadeMillis: 15_000,
})
| 169 |
| Expected | Playback configuration → expect assignment: 1, {
address: {
page: 1,
position: 1
},
targetType: "speed_group",
buttons: [
"double",
"half",
"learn"
],
fader: "learned_percentage",
color: "#8b5cf6"
}t.playbackConfiguration.expectAssignment(1, {
address: {page:1,position:1},
targetType: "speed_group",
buttons: ["double", "half", "learn"],
fader: "learned_percentage",
color: "#8b5cf6",
})
| 182 |
| Expected | Playback configuration → expect assignment: 2, {
address: {
page: 1,
position: 2
},
targetType: "group"
}t.playbackConfiguration.expectAssignment(2, {
address: {page:1,position:2},
targetType: "group",
})
| 189 |
| Expected | Playback configuration → expect assignment: 3, {
address: {
page: 1,
position: 3
},
targetType: "grand_master"
}t.playbackConfiguration.expectAssignment(3, {
address: {page:1,position:3},
targetType: "grand_master",
})
| 193 |
Diagnostics
None.
PBK-006 — independent overlapping Group Masters use the highest assigned level
tests/61-semantic-playback-configuration.spec.ts:200 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineDMX outputGroupsPlayback ConfigurationPlaybacksSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 204 |
Open the ToskLight browser application.t.app.open()
| 206 |
The ToskLight browser application is ready.t.app.expect.ready()
| 207 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Playback configuration → clear page. t.playbackConfiguration.clearPage()
| 205 |
| Step | Selection → fixtures → api → items with 1, 2, 3, 4, 5, 6. t.selection.fixtures.via.api.items(1, 2, 3, 4, 5, 6)
| 209 |
| Step | Group → api → store with 5, {
mode: GroupStoreMode.Overwrite
}t.group.via.api.store(5, { mode: GroupStoreMode.Overwrite })
| 210 |
| Step | Selection → fixtures → api → items with 1, 3, 5. t.selection.fixtures.via.api.items(1, 3, 5)
| 211 |
| Step | Group → api → store with 6, {
mode: GroupStoreMode.Overwrite
}t.group.via.api.store(6, { mode: GroupStoreMode.Overwrite })
| 212 |
| Step | Selection → fixtures → api → items with 2, 4, 6. t.selection.fixtures.via.api.items(2, 4, 6)
| 213 |
| Step | Group → api → store with 7, {
mode: GroupStoreMode.Overwrite
}t.group.via.api.store(7, { mode: GroupStoreMode.Overwrite })
| 214 |
| Step | Clear the current selection. t.selection.clear()
| 215 |
| Step | Playback configuration → assign group master with 1, 6. t.playbackConfiguration.assignGroupMaster(1, 6)
| 217 |
| Step | Playback configuration → assign group master with 2, 7. t.playbackConfiguration.assignGroupMaster(2, 7)
| 218 |
| Step | Execute the desk command "GROUP 7 AT 100". t.command.execute("GROUP 7 AT 100")
| 219 |
| Step | Playback configuration → set slot fader with 2, 0.8. t.playbackConfiguration.setSlotFader(2, 0.8)
| 220 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 221 |
| Expected | fixture(1) DMX equals {
Intensity: 0
}t.expectFixtureDMX(fixture(1), { Intensity: 0 })
| 222 |
| Expected | fixture(2) DMX equals {
Intensity: 204
}t.expectFixtureDMX(fixture(2), { Intensity: 204 })
| 223 |
| Expected | fixture(4) DMX equals {
Intensity: 204
}t.expectFixtureDMX(fixture(4), { Intensity: 204 })
| 224 |
| Expected | fixture(6) DMX equals {
Intensity: 204
}t.expectFixtureDMX(fixture(6), { Intensity: 204 })
| 225 |
| Step | Playback configuration → assign group master with 3, 5. t.playbackConfiguration.assignGroupMaster(3, 5)
| 227 |
| Step | Playback configuration → set slot fader with 3, 0.6. t.playbackConfiguration.setSlotFader(3, 0.6)
| 228 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 229 |
| Expected | fixture(2) DMX equals {
Intensity: 204
}t.expectFixtureDMX(fixture(2), { Intensity: 204 })
| 230 |
| Expected | fixture(4) DMX equals {
Intensity: 204
}t.expectFixtureDMX(fixture(4), { Intensity: 204 })
| 231 |
| Expected | fixture(6) DMX equals {
Intensity: 204
}t.expectFixtureDMX(fixture(6), { Intensity: 204 })
| 232 |
| Step | Playback configuration → assign grand master with 4. t.playbackConfiguration.assignGrandMaster(4)
| 234 |
| Step | Playback configuration → set slot fader with 4, 0.5. t.playbackConfiguration.setSlotFader(4, 0.5)
| 235 |
| Step | Advance the test clock by "0ms". t.clock.advanceBy("0ms")
| 236 |
| Expected | fixture(2) DMX equals {
Intensity: 102
}t.expectFixtureDMX(fixture(2), { Intensity: 102 })
| 237 |
| Expected | fixture(4) DMX equals {
Intensity: 102
}t.expectFixtureDMX(fixture(4), { Intensity: 102 })
| 238 |
| Expected | fixture(6) DMX equals {
Intensity: 102
}t.expectFixtureDMX(fixture(6), { Intensity: 102 })
| 239 |
Diagnostics
None.
TIME-001 — zero ticks emit current state without advancing behavior time
tests/62-semantic-time-persistence-and-recovery.spec.ts:13 · migrated-semantic-world · last run: not merged
show: Twelve DimmersAttached hardwareBrowser UICue timingDMX outputDesktop layoutEncoder controlsOSCProgrammerProgrammer timingSelectionSemantic oracleShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 17 |
Open the ToskLight browser application.t.app.open()
| 18 |
The ToskLight browser application is ready.t.app.expect.ready()
| 19 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Time and recovery programming t.desktop.configure("Time and recovery programming")
| 121 |
| Step | Add the PaneType.Fixtures pane desktop.addPane(PaneType.Fixtures, {
slug: "fixtures",
column: 1,
row: 1,
width: 12,
height: 18,
})
| 122 |
| Step | Add the PaneType.Groups pane desktop.addPane(PaneType.Groups, {
slug: "groups",
column: 13,
row: 1,
width: 12,
height: 18,
})
| 129 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 136 |
| Step | Timing → programmer fade → api → set with "0ms". t.timing.programmerFade.via.api.set("0ms")
| 21 |
| Step | Selection → fixtures → ui → item with 1. t.selection.fixtures.via.ui.item(1)
| 22 |
| Step | Encoder → intensity → dimmer → ui → set with 50. t.encoder.intensity.dimmer.via.ui.set(50)
| 23 |
| Step | Connect the simulated attached hardware surface. t.hardware.connect()
| 24 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 26 |
| Step | Advance the test clock by one deterministic step. t.clock.advanceStep()
| 27 |
| Expected | $second.now (from clock.advanceStep) is $first.now (from clock.advanceStep). expect(second.now).toBe(first.now)
| 28 |
| Expected | fixture(1) DMX equals {
Intensity: 128
}t.expectFixtureDMX(fixture(1), { Intensity: 128 })
| 29 |
| Step | Disconnect the simulated attached hardware surface. t.hardware.disconnect()
| 31 |
Diagnostics
None.
TIME-002 — absolute fixture Set Value follows Programmer Fade at every timing boundary
tests/62-semantic-time-persistence-and-recovery.spec.ts:36 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICue timingDMX outputDesktop layoutEncoder controlsProgrammerProgrammer timingSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 40 |
Open the ToskLight browser application.t.app.open()
| 41 |
The ToskLight browser application is ready.t.app.expect.ready()
| 42 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Time and recovery programming t.desktop.configure("Time and recovery programming")
| 121 |
| Step | Add the PaneType.Fixtures pane desktop.addPane(PaneType.Fixtures, {
slug: "fixtures",
column: 1,
row: 1,
width: 12,
height: 18,
})
| 122 |
| Step | Add the PaneType.Groups pane desktop.addPane(PaneType.Groups, {
slug: "groups",
column: 13,
row: 1,
width: 12,
height: 18,
})
| 129 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 136 |
| Step | Programmer Fade → command-line AT fade is true. t.timing.programmerFade.setCommandLineAtEnabled(true)
| 44 |
| Step | Timing → programmer fade → api → set with "3s". t.timing.programmerFade.via.api.set("3s")
| 45 |
| Step | Selection → fixtures → ui → item with 1. t.selection.fixtures.via.ui.item(1)
| 46 |
| Step | Encoder → intensity → dimmer → ui → set with 0. t.encoder.intensity.dimmer.via.ui.set(0)
| 47 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 48 |
| Step | Encoder → intensity → dimmer → ui → set with 100. t.encoder.intensity.dimmer.via.ui.set(100)
| 49 |
| Step | Clock → at with [
{
name: "start",
at: "0ms"
},
{
name: "midpoint",
at: "1.5s"
},
{
name: "complete",
at: "3s"
}
], <generated: callback>. t.clock.at(
[
{ name: "start", at: "0ms" },
{ name: "midpoint", at: "1.5s" },
{ name: "complete", at: "3s" },
],
async ({ name }) => {
await t.expectFixtureDMX(fixture(1), {
Intensity: name === "start" ? 0 : name === "midpoint" ? 128 : 255,
});
},
)
| 50 |
| Expected | fixture(1) DMX equals {
Intensity: <unresolved: name === "start" ? 0 : name === "midpoint" ? 128 : 255>
}t.expectFixtureDMX(fixture(1), {
Intensity: name === "start" ? 0 : name === "midpoint" ? 128 : 255,
})
| 57 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: name === "start" ? 0 : name === "midpoint" ? 128 : 255> Expression name === "start" ? 0 : name === "midpoint" ? 128 : 255 is not statically resolved. | 58 |
TIME-002 — absolute Group Set Value follows Programmer Fade for every ordered member
tests/62-semantic-time-persistence-and-recovery.spec.ts:65 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UICue timingDMX outputDesktop layoutEncoder controlsPool UIProgrammerProgrammer timingSelectionShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 69 |
Open the ToskLight browser application.t.app.open()
| 70 |
The ToskLight browser application is ready.t.app.expect.ready()
| 71 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Time and recovery programming t.desktop.configure("Time and recovery programming")
| 121 |
| Step | Add the PaneType.Fixtures pane desktop.addPane(PaneType.Fixtures, {
slug: "fixtures",
column: 1,
row: 1,
width: 12,
height: 18,
})
| 122 |
| Step | Add the PaneType.Groups pane desktop.addPane(PaneType.Groups, {
slug: "groups",
column: 13,
row: 1,
width: 12,
height: 18,
})
| 129 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 136 |
| Step | Programmer Fade → command-line AT fade is true. t.timing.programmerFade.setCommandLineAtEnabled(true)
| 73 |
| Step | Timing → programmer fade → api → set with "3s". t.timing.programmerFade.via.api.set("3s")
| 74 |
| Step | Selection → groups → pool → item with 3. t.selection.groups.via.pool.item(3)
| 75 |
| Step | Encoder → intensity → dimmer → ui → set with 0. t.encoder.intensity.dimmer.via.ui.set(0)
| 76 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 77 |
| Step | Encoder → intensity → dimmer → ui → set with 100. t.encoder.intensity.dimmer.via.ui.set(100)
| 78 |
| Step | Clock → at with [
{
name: "start",
at: "0ms"
},
{
name: "midpoint",
at: "1.5s"
},
{
name: "complete",
at: "3s"
}
], <generated: callback>. t.clock.at(
[
{ name: "start", at: "0ms" },
{ name: "midpoint", at: "1.5s" },
{ name: "complete", at: "3s" },
],
async ({ name }) => {
for (const number of [1, 2, 3, 4])
await t.expectFixtureDMX(fixture(number), {
Intensity: name === "start" ? 0 : name === "midpoint" ? 128 : 255,
});
},
)
| 79 |
| Expected | fixture(number) DMX equals {
Intensity: <unresolved: name === "start" ? 0 : name === "midpoint" ? 128 : 255>
}t.expectFixtureDMX(fixture(number), {
Intensity: name === "start" ? 0 : name === "midpoint" ? 128 : 255,
})
| 87 |
| Expected | fixture(number) DMX equals {
Intensity: <unresolved: name === "start" ? 0 : name === "midpoint" ? 128 : 255>
}t.expectFixtureDMX(fixture(number), {
Intensity: name === "start" ? 0 : name === "midpoint" ? 128 : 255,
})
| 87 |
| Expected | fixture(number) DMX equals {
Intensity: <unresolved: name === "start" ? 0 : name === "midpoint" ? 128 : 255>
}t.expectFixtureDMX(fixture(number), {
Intensity: name === "start" ? 0 : name === "midpoint" ? 128 : 255,
})
| 87 |
| Expected | fixture(number) DMX equals {
Intensity: <unresolved: name === "start" ? 0 : name === "midpoint" ? 128 : 255>
}t.expectFixtureDMX(fixture(number), {
Intensity: name === "start" ? 0 : name === "midpoint" ? 128 : 255,
})
| 87 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Expected outcome | <unresolved: name === "start" ? 0 : name === "midpoint" ? 128 : 255> Expression name === "start" ? 0 : name === "midpoint" ? 128 : 255 is not statically resolved. | 88 |
| unresolved-expression | Expected outcome | <unresolved: name === "start" ? 0 : name === "midpoint" ? 128 : 255> Expression name === "start" ? 0 : name === "midpoint" ? 128 : 255 is not statically resolved. | 88 |
| unresolved-expression | Expected outcome | <unresolved: name === "start" ? 0 : name === "midpoint" ? 128 : 255> Expression name === "start" ? 0 : name === "midpoint" ? 128 : 255 is not statically resolved. | 88 |
| unresolved-expression | Expected outcome | <unresolved: name === "start" ? 0 : name === "midpoint" ? 128 : 255> Expression name === "start" ? 0 : name === "midpoint" ? 128 : 255 is not statically resolved. | 88 |
SHOW-001 — operator programming and a named revision survive an abrupt restart
tests/62-semantic-time-persistence-and-recovery.spec.ts:95 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UIDesktop layoutEncoder controlsGroupsPool UIProgrammerSelectionShow files
Preconditions (5)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 99 |
Open the ToskLight browser application.t.app.open()
| 100 |
The ToskLight browser application is ready.t.app.expect.ready()
| 101 |
Save a named show revision "SHOW-001 before restart".t.show.saveRevision("SHOW-001 before restart")
| 107 |
The ToskLight browser application is ready.t.app.expect.ready()
| 109 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Time and recovery programming t.desktop.configure("Time and recovery programming")
| 121 |
| Step | Add the PaneType.Fixtures pane desktop.addPane(PaneType.Fixtures, {
slug: "fixtures",
column: 1,
row: 1,
width: 12,
height: 18,
})
| 122 |
| Step | Add the PaneType.Groups pane desktop.addPane(PaneType.Groups, {
slug: "groups",
column: 13,
row: 1,
width: 12,
height: 18,
})
| 129 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 136 |
| Step | Selection → fixtures → ui → items with 5, 6. t.selection.fixtures.via.ui.items(5, 6)
| 103 |
| Step | Group → pool → store with 3, {
mode: StoreMode.Merge
}t.group.via.pool.store(3, { mode: StoreMode.Merge })
| 104 |
| Step | Selection → targets with group(3). t.selection.targets(group(3))
| 105 |
| Step | Encoder → intensity → dimmer → ui → set with 40. t.encoder.intensity.dimmer.via.ui.set(40)
| 106 |
| Step | Show → restart with RestartMode.Abrupt. t.show.restart(RestartMode.Abrupt)
| 108 |
| Expected | Group → fixtures: 3, 1, 2, 3, 4, 5, 6. t.group.expect(3).fixtures(1, 2, 3, 4, 5, 6)
| 110 |
| Expected | Show → revision matches {
number: $revision (result of show.saveRevision),
name: "SHOW-001 before restart"
}t.show.expect.revision({
number: revision,
name: "SHOW-001 before restart",
})
| 111 |
Diagnostics
None.
SHOW-003 — a malformed active show remains intact while the operator recovers safely
tests/62-semantic-time-persistence-and-recovery.spec.ts:139 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UIShow files
Preconditions (2)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 143 |
Open the ToskLight browser application.t.app.open()
| 144 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Show → recovery → prepare malformed active. t.show.recovery.prepareMalformedActive()
| 145 |
| Expected | Show → recovery required. t.show.expect.recoveryRequired()
| 146 |
| Step | Show → load clean default. t.show.loadCleanDefault()
| 147 |
| Expected | Show → recovered. t.show.expect.recovered()
| 148 |
Diagnostics
None.
SHOW-005 — named revisions load as durable, visibly independent copies
tests/62-semantic-time-persistence-and-recovery.spec.ts:152 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UIGroupsSelectionShow filesTyped API
Preconditions (8)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 156 |
Open the ToskLight browser application.t.app.open()
| 157 |
The ToskLight browser application is ready.t.app.expect.ready()
| 158 |
Save the active show as "SHOW-005 source <generated: UUID>".t.show.saveAs(`SHOW-005 source ${crypto.randomUUID()}`)
| 159 |
Save a named show revision "SHOW-005 named revision".t.show.saveRevision("SHOW-005 named revision")
| 160 |
Save the active show as "SHOW-005 changed <generated: UUID>".t.show.saveAs(`SHOW-005 changed ${crypto.randomUUID()}`)
| 163 |
Load revision $revision (result of show.saveRevision) of $source (result of show.saveAs).t.show.loadRevision(source, revision)
| 165 |
Save the active show.t.show.save()
| 168 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → items with 5, 6. t.selection.fixtures.via.api.items(5, 6)
| 161 |
| Step | Group → api → store with 3, {
mode: StoreMode.Merge
}t.group.via.api.store(3, { mode: StoreMode.Merge })
| 162 |
| Expected | Show → active is the saved show copy. t.show.expect.active(changed)
| 164 |
| Expected | Show → active is the loaded revision copy. t.show.expect.active(revisionCopy)
| 166 |
| Expected | Group → fixtures: 3, 1, 2, 3, 4. t.group.expect(3).fixtures(1, 2, 3, 4)
| 167 |
| Expected | Show → active is the loaded revision copy. t.show.expect.active(revisionCopy)
| 169 |
Diagnostics
None.
MANUAL-019 — saved workspaces are Desktops while physical control surfaces remain desks
tests/63-semantic-operator-shell.spec.ts:6 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UIOperator shellShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 10 |
Open the ToskLight browser application.t.app.open()
| 11 |
The ToskLight browser application is ready.t.app.expect.ready()
| 12 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | Operator shell → expect desktop and desk terminology. t.operatorShell.expectDesktopAndDeskTerminology()
| 13 |
Diagnostics
None.
MANUAL-019 — fixture browsers share title-bar search and readable name/detail alignment
tests/63-semantic-operator-shell.spec.ts:17 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UIOperator shellShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 21 |
Open the ToskLight browser application.t.app.open()
| 22 |
The ToskLight browser application is ready.t.app.expect.ready()
| 23 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | Operator shell → expect fixture browser alignment. t.operatorShell.expectFixtureBrowserAlignment()
| 24 |
Diagnostics
None.
MANUAL-019 — every operator file field uses its confined extension contract
tests/63-semantic-operator-shell.spec.ts:28 · migrated-semantic-world · last run: not merged
show: Twelve DimmersBrowser UIOperator shellShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 32 |
Open the ToskLight browser application.t.app.open()
| 33 |
The ToskLight browser application is ready.t.app.expect.ready()
| 34 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | Operator shell → expect operator file picker contracts. t.operatorShell.expectOperatorFilePickerContracts()
| 35 |
Diagnostics
None.
COMMAND-HISTORY-001 — Command Line history shows accepted and rejected desk commands once
tests/64-semantic-operator-controls.spec.ts:8 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UICommand lineShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 12 |
Open the ToskLight browser application.t.app.open()
| 13 |
The ToskLight browser application is ready.t.app.expect.ready()
| 14 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Expected | Command → history → expect accepted and rejected. t.command.history.expectAcceptedAndRejected()
| 15 |
Diagnostics
None.
PROG-002 — software encoder value dialog spreads a two-point range over the ordered selection
tests/64-semantic-operator-controls.spec.ts:19 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineDMX outputEncoder controlsProgrammerShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 23 |
Open the ToskLight browser application.t.app.open()
| 24 |
The ToskLight browser application is ready.t.app.expect.ready()
| 25 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "FIXTURE 1 THRU 5". t.command.execute("FIXTURE 1 THRU 5")
| 26 |
| Step | Encoder → intensity → dimmer → ui → set with [
0,
ProgrammerToken.Thru,
50
] t.encoder.intensity.dimmer.via.ui.set([
0,
ProgrammerToken.Thru,
50,
])
| 27 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 32 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 0
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 34 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 32
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 34 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 64
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 34 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 96
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 34 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 128
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 34 |
Diagnostics
None.
PROG-002 — software encoder value dialog lands a multi-point intensity spread once over the ordered selection
tests/64-semantic-operator-controls.spec.ts:38 · migrated-semantic-world · last run: not merged
show: Compact RigBrowser UICommand lineDMX outputEncoder controlsProgrammerShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 42 |
Open the ToskLight browser application.t.app.open()
| 43 |
The ToskLight browser application is ready.t.app.expect.ready()
| 44 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "FIXTURE 1 THRU 5". t.command.execute("FIXTURE 1 THRU 5")
| 45 |
| Step | Encoder → intensity → dimmer → ui → set with [
100,
ProgrammerToken.Thru,
0,
ProgrammerToken.Thru,
100
] t.encoder.intensity.dimmer.via.ui.set([
100,
ProgrammerToken.Thru,
0,
ProgrammerToken.Thru,
100,
])
| 46 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 53 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 255
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 55 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 128
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 55 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 0
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 55 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 128
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 55 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 255
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 55 |
Diagnostics
None.
PROG-002 — software encoder value dialog spreads a multi-point Pan over the ordered moving-head selection
tests/64-semantic-operator-controls.spec.ts:59 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UICommand lineDMX outputEncoder controlsProgrammerShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 63 |
Open the ToskLight browser application.t.app.open()
| 64 |
The ToskLight browser application is ready.t.app.expect.ready()
| 65 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "FIXTURE 101 THRU 105". t.command.execute("FIXTURE 101 THRU 105")
| 66 |
| Step | Encoder → position → pan → ui → set with [
270,
ProgrammerToken.Thru,
<unresolved: -270>,
ProgrammerToken.Thru,
270
] t.encoder.position.pan.via.ui.set([
270,
ProgrammerToken.Thru,
-270,
ProgrammerToken.Thru,
270,
])
| 68 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 75 |
| Expected | fixture(number + 101) DMX equals {
Pan: value = 255
}t.expectFixtureDMX(fixture(number + 101), {
Pan: value,
})
| 77 |
| Expected | fixture(number + 101) DMX equals {
Pan: value = 128
}t.expectFixtureDMX(fixture(number + 101), {
Pan: value,
})
| 77 |
| Expected | fixture(number + 101) DMX equals {
Pan: value = 0
}t.expectFixtureDMX(fixture(number + 101), {
Pan: value,
})
| 77 |
| Expected | fixture(number + 101) DMX equals {
Pan: value = 128
}t.expectFixtureDMX(fixture(number + 101), {
Pan: value,
})
| 77 |
| Expected | fixture(number + 101) DMX equals {
Pan: value = 255
}t.expectFixtureDMX(fixture(number + 101), {
Pan: value,
})
| 77 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Step | <unresolved: -270> Expression -270 is not statically resolved. | 71 |
ENCODER-DISPLAY-001 — OSC NAV wraps families while non-first encoder turn, held-turn, and click follow the displayed cell
tests/64-semantic-operator-controls.spec.ts:83 · migrated-semantic-world · last run: not merged
show: Default StageAttached hardwareBrowser UICommand lineOSCShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 87 |
Open the ToskLight browser application.t.app.open()
| 88 |
The ToskLight browser application is ready.t.app.expect.ready()
| 89 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "FIXTURE 101". t.command.execute("FIXTURE 101")
| 90 |
| Expected | Attached encoder → expect navigation and secondary encoder. t.attachedEncoder.expectNavigationAndSecondaryEncoder()
| 91 |
Diagnostics
None.
PROG-002 — hardware encoder modal spreads a typed value over the ordered selection
tests/64-semantic-operator-controls.spec.ts:95 · migrated-semantic-world · last run: not merged
show: Compact RigAttached hardwareBrowser UICommand lineDMX outputOSCShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 99 |
Open the ToskLight browser application.t.app.open()
| 100 |
The ToskLight browser application is ready.t.app.expect.ready()
| 101 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "FIXTURE 1 THRU 5". t.command.execute("FIXTURE 1 THRU 5")
| 102 |
| Expected | Attached encoder → expect typed intensity spread. t.attachedEncoder.expectTypedIntensitySpread()
| 103 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 104 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 0
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 106 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 32
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 106 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 64
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 106 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 96
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 106 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 128
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 106 |
Diagnostics
None.
PROG-002 — hardware encoder modal lands a multi-point intensity spread once over the ordered selection
tests/64-semantic-operator-controls.spec.ts:110 · migrated-semantic-world · last run: not merged
show: Compact RigAttached hardwareBrowser UICommand lineDMX outputOSCShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.CompactRig show.t.show.use(Show.CompactRig)
| 114 |
Open the ToskLight browser application.t.app.open()
| 115 |
The ToskLight browser application is ready.t.app.expect.ready()
| 116 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "FIXTURE 1 THRU 5". t.command.execute("FIXTURE 1 THRU 5")
| 117 |
| Expected | Attached encoder → expect multi point intensity spread. t.attachedEncoder.expectMultiPointIntensitySpread()
| 118 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 119 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 255
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 121 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 128
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 121 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 0
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 121 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 128
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 121 |
| Expected | fixture(number + 1) DMX equals {
Intensity: value = 255
}t.expectFixtureDMX(fixture(number + 1), { Intensity: value })
| 121 |
Diagnostics
None.
PROG-002 — hardware encoder modal spreads a multi-point Pan over the ordered moving-head selection
tests/64-semantic-operator-controls.spec.ts:125 · migrated-semantic-world · last run: not merged
show: Default StageAttached hardwareBrowser UICommand lineDMX outputOSCShow filesTest clock
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 129 |
Open the ToskLight browser application.t.app.open()
| 130 |
The ToskLight browser application is ready.t.app.expect.ready()
| 131 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Execute the desk command "FIXTURE 101 THRU 105". t.command.execute("FIXTURE 101 THRU 105")
| 132 |
| Expected | Attached encoder → expect multi point pan spread. t.attachedEncoder.expectMultiPointPanSpread()
| 133 |
| Step | Advance the test clock by "3s". t.clock.advanceBy("3s")
| 134 |
| Expected | fixture(number + 101) DMX equals {
Pan: value = 255
}t.expectFixtureDMX(fixture(number + 101), {
Pan: value,
})
| 136 |
| Expected | fixture(number + 101) DMX equals {
Pan: value = 128
}t.expectFixtureDMX(fixture(number + 101), {
Pan: value,
})
| 136 |
| Expected | fixture(number + 101) DMX equals {
Pan: value = 0
}t.expectFixtureDMX(fixture(number + 101), {
Pan: value,
})
| 136 |
| Expected | fixture(number + 101) DMX equals {
Pan: value = 128
}t.expectFixtureDMX(fixture(number + 101), {
Pan: value,
})
| 136 |
| Expected | fixture(number + 101) DMX equals {
Pan: value = 255
}t.expectFixtureDMX(fixture(number + 101), {
Pan: value,
})
| 136 |
Diagnostics
None.
POSITION-HOME-001 — Return Home applies per-head Position defaults as one programmer gesture
tests/65-semantic-special-dialogs-and-hardware-selection.spec.ts:6 · migrated-semantic-world · last run: not merged
show: Default StageAttached hardwareBrowser UICommand keypadOSCProgrammerSemantic oracleShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 10 |
Open the ToskLight browser application.t.app.open()
| 11 |
The ToskLight browser application is ready.t.app.expect.ready()
| 12 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Special → position → prepare return home contract. t.special.position.prepareReturnHomeContract()
| 13 |
| Step | Special → position → return home. t.special.position.returnHome()
| 15 |
| Expected | Special → position → expect at home. t.special.position.expectAtHome()
| 16 |
| Step | Press keypad keys [
"SHIFT",
"ESC",
"SHIFT"
] t.keypad.press(["SHIFT", "ESC", "SHIFT"])
| 17 |
| Expected | Special → position → expect before return home. t.special.position.expectBeforeReturnHome()
| 18 |
| Step | Connect the simulated attached hardware surface. t.hardware.connect()
| 20 |
| Step | Special → position → return home. t.special.position.returnHome()
| 22 |
| Step | Disconnect the simulated attached hardware surface. t.hardware.disconnect()
| 24 |
| Expected | Special → position → expect at home. t.special.position.expectAtHome()
| 26 |
| Step | Press keypad keys [
"CLR"
] t.keypad.press(["CLR"])
| 28 |
| Expected | Selection. t.expect.selection()
| 29 |
| Expected | Special → position → expect unavailable. t.special.position.expectUnavailable()
| 30 |
Diagnostics
None.
COLOR-RANGE-001 — Shift-drag applies an ordered Color range from software and attached hardware
tests/65-semantic-special-dialogs-and-hardware-selection.spec.ts:34 · migrated-semantic-world · last run: not merged
show: Default StageAttached hardwareBrowser UICommand keypadOSCProgrammerShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 38 |
Open the ToskLight browser application.t.app.open()
| 39 |
The ToskLight browser application is ready.t.app.expect.ready()
| 40 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Special → color → prepare range contract. t.special.color.prepareRangeContract()
| 41 |
| Step | Special → color → set uniform. t.special.color.setUniform()
| 43 |
| Step | Press keypad keys [
"SHIFT",
"ESC",
"SHIFT"
] t.keypad.press(["SHIFT", "ESC", "SHIFT"])
| 44 |
| Expected | Special → color → expect prior. t.special.color.expectPrior()
| 45 |
| Step | Special → color → apply range with shift. t.special.color.applyRangeWithShift()
| 47 |
| Step | Press keypad keys [
"SHIFT",
"ESC",
"SHIFT"
] t.keypad.press(["SHIFT", "ESC", "SHIFT"])
| 48 |
| Expected | Special → color → expect prior. t.special.color.expectPrior()
| 49 |
| Step | Special → color → cancel range with shift. t.special.color.cancelRangeWithShift()
| 50 |
| Step | Connect the simulated attached hardware surface. t.hardware.connect()
| 52 |
| Step | Special → color → apply range with hardware shift. t.special.color.applyRangeWithHardwareShift()
| 54 |
| Step | Disconnect the simulated attached hardware surface. t.hardware.disconnect()
| 56 |
| Expected | Special → color → expect range. t.special.color.expectRange()
| 58 |
| Expected | Special → color → expect selection preserved. t.special.color.expectSelectionPreserved()
| 59 |
Diagnostics
None.
PLAYBACK-SELECT-001 — an attached-hardware playback card selects its concrete Cuelist playback
tests/65-semantic-special-dialogs-and-hardware-selection.spec.ts:63 · migrated-semantic-world · last run: not merged
show: Default StageAttached hardwareBrowser UIEncoder controlsOSCPlaybacksProgrammerRecordingSelectionShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 67 |
Open the ToskLight browser application.t.app.open()
| 68 |
The ToskLight browser application is ready.t.app.expect.ready()
| 69 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Selection → fixtures → api → item with 101. t.selection.fixtures.via.api.item(101)
| 70 |
| Step | Encoder → intensity → dimmer → api → set with 73. t.encoder.intensity.dimmer.via.api.set(73)
| 71 |
| Step | Record → playback with 1. t.record.playback(1)
| 72 |
| Step | Playback → name target cuelist with $playback (result of record.playback), "Front Cuelist". t.playback.nameTargetCuelist(playback, "Front Cuelist")
| 73 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 74 |
| Step | Connect the simulated attached hardware surface. t.hardware.connect()
| 76 |
| Step | Playback → select from hardware card with $playback (result of record.playback). t.playback.selectFromHardwareCard(playback)
| 78 |
| Step | Disconnect the simulated attached hardware surface. t.hardware.disconnect()
| 80 |
| Expected | Playback → selected: $playback (result of record.playback). t.playback.expect(playback).selected()
| 82 |
Diagnostics
None.
STAGE-001 — Live and Follow Preload Stage panes retain independent operator configuration
tests/66-semantic-stage-visualizer.spec.ts:7 · migrated-semantic-world · last run: not merged
show: Default StageBrowser UIDesktop layoutShow files
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.DefaultStage show.t.show.use(Show.DefaultStage)
| 11 |
Open the ToskLight browser application.t.app.open()
| 12 |
The ToskLight browser application is ready.t.app.expect.ready()
| 13 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Desktop → configure with .desktop: Stage lane proof t.desktop.configure("Stage lane proof")
| 15 |
| Step | Add the PaneType.Stage pane desktop.addPane(
PaneType.Stage,
{
slug: "live-stage",
column: 1,
row: 1,
width: 12,
height: 18,
},
{ view: StageView.TwoDimensional, followPreload: false },
)
| 16 |
| Step | Add the PaneType.Stage pane desktop.addPane(
PaneType.Stage,
{
slug: "preload-stage",
column: 13,
row: 1,
width: 12,
height: 18,
},
{ view: StageView.TwoDimensional, followPreload: true },
)
| 27 |
| Step | Apply the configured Desktop layout. desktop.apply()
| 38 |
| Expected | Desktop builder → expect stage pane: $live (result of desktopBuilder.addPane), {
lane: "live",
view: StageView.TwoDimensional,
followPreload: false,
nativeRendererAvailable: false
}desktop.expectStagePane(live, {
lane: "live",
view: StageView.TwoDimensional,
followPreload: false,
nativeRendererAvailable: false,
})
| 40 |
| Expected | Desktop builder → expect stage pane: $preload (result of desktopBuilder.addPane), {
lane: "preload",
view: StageView.TwoDimensional,
followPreload: true,
nativeRendererAvailable: false
}desktop.expectStagePane(preload, {
lane: "preload",
view: StageView.TwoDimensional,
followPreload: true,
nativeRendererAvailable: false,
})
| 46 |
Diagnostics
None.
PERF-PROGRAMMER-001 — programmer actions acknowledge and reach their first output frame within the output-tick budget
tests/77-programmer-action-latency.spec.ts:8 · unresolved · last run: not merged
show: Twelve DimmersAttached hardwareBrowser UICommand keypadCommand lineDMX outputEncoder controlsOSCPresetsProgrammerSelectionShow filesTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.TwelveDimmers show.t.show.use(Show.TwelveDimmers)
| 12 |
Open the ToskLight browser application.t.app.open()
| 13 |
The ToskLight browser application is ready.t.app.expect.ready()
| 14 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Command → api → type with "FIXTURE 1". t.command.via.api.type("FIXTURE 1")
| 24 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 33 |
| Step | Encoder → intensity → dimmer → api → set with 20. t.encoder.intensity.dimmer.via.api.set(20)
| 42 |
| Step | Press keypad keys [
"PRE"
] t.keypad.press(["PRE"])
| 63 |
| Step | Press keypad keys [
"ESC"
] t.keypad.press(["ESC"])
| 65 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 71 |
| Step | Encoder → intensity → dimmer → api → set with 45. t.encoder.intensity.dimmer.via.api.set(45)
| 72 |
| Step | Preset → api → store with PresetFamily.Intensity, 99, {
mode: "overwrite"
}t.preset.via.api.store(PresetFamily.Intensity, 99, {
mode: "overwrite",
})
| 73 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 76 |
| Step | Preset → api → recall with PresetFamily.Intensity, 99. t.preset.via.api.recall(PresetFamily.Intensity, 99)
| 84 |
| Step | Show → contract identity. t.show.contractIdentity()
| 87 |
| Step | Connect the simulated attached hardware surface. t.hardware.connect()
| 90 |
| Step | Disconnect the simulated attached hardware surface. t.hardware.disconnect()
| 94 |
| Expected | fixture(1) DMX equals {
Intensity: 140
}t.expectFixtureDMX(fixture(1), { Intensity: 140 })
| 107 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| missing-migration-status | Source | No exact source, ID, and title match exists in the generated migration inventory. | 8 |
BENCH-PRESET-COLOR-001 — a Cue on a Group Color Preset follows a replaced fixture from a color wheel to RGBWA mixing
tests/94-semantic-preset-color-across-fixture-types.spec.ts:24 · migrated-semantic-world · last run: not merged
show: EmptyBrowser UICommand lineCue runtimeCue timingDMX outputEncoder controlsGroupsPlaybacksPresetsProgrammerProgrammer timingRecordingSelectionSemantic oracleShow PatchShow filesTest clockTyped API
Preconditions (3)
| Context | Line |
|---|
Use the isolated Show.Empty show.t.show.use(Show.Empty)
| 28 |
Open the ToskLight browser application.t.app.open()
| 30 |
The ToskLight browser application is ready.t.app.expect.ready()
| 31 |
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Set the active show's color programming model to "intent". t.show.colorModel("intent")
| 29 |
| Step | Timing → programmer fade → api → set with "0s". t.timing.programmerFade.via.api.set("0s")
| 32 |
| Step | Patch → api → add with {
number: 1,
name: "Wheel Spot",
address: "1.1",
<unresolved: ...WHEEL_SPOT>
}t.patch.via.api.add({
number: 1,
name: "Wheel Spot",
address: "1.1",
...WHEEL_SPOT,
})
| 35 |
| Step | Selection → fixtures → api → item with 1. t.selection.fixtures.via.api.item(1)
| 41 |
| Step | Group → api → store with 1, {
mode: StoreMode.Overwrite
}t.group.via.api.store(1, { mode: StoreMode.Overwrite })
| 42 |
| Expected | Group → fixtures: 1, 1. t.group.expect(1).fixtures(1)
| 43 |
| Step | Execute the desk command "GROUP 1 AT COLOR 100 DIV 0 DIV 0 DIV 0" through the API. t.command.via.api.execute("GROUP 1 AT COLOR 100 DIV 0 DIV 0 DIV 0")
| 46 |
| Step | Preset → api → store with PresetFamily.Color, 1, {
mode: "overwrite"
}t.preset.via.api.store(PresetFamily.Color, 1, { mode: "overwrite" })
| 47 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 48 |
| Step | Clear the current selection. t.selection.clear()
| 49 |
| Step | Execute the desk command "GROUP 1 AT 100" through the visible command line. t.command.via.ui.execute("GROUP 1 AT 100")
| 52 |
| Step | Execute the desk command "GROUP 1 AT 2.1" through the visible command line. t.command.via.ui.execute("GROUP 1 AT 2.1")
| 53 |
| Step | Record → ui → playback with 1. t.record.via.ui.playback(1)
| 54 |
| Expected | Cue → present: $playback (result of record.via.ui.playback), 1. t.cue.expect(playback, 1).present()
| 55 |
| Expected | Cue → group value: $playback (result of record.via.ui.playback), 1, 1, "intensity", 1. t.cue.expect(playback, 1).groupValue(1, "intensity", 1)
| 56 |
| Step | Read stored Cue 1 from the Cuelist assigned to Playback $playback (result of record.via.ui.playback). t.cue.cue(playback, 1)
| 57 |
| Step | Read the stored PresetFamily.Color Preset 1, requiring that it exists. t.preset.requiredObject(PresetFamily.Color, 1)
| 58 |
| Expected | $recordedCue?.group_changes (from cue.cue) equals <unresolved: expect.arrayContaining([ expect.objectContaining({ group_id: "1", preset_reference: expect.objectContaining({ preset_instance_id: colorPreset.body.instance_id, source_attribute:…>. expect(recordedCue?.group_changes).toEqual(
expect.arrayContaining([
expect.objectContaining({
group_id: "1",
preset_reference: expect.objectContaining({
preset_instance_id: colorPreset.body.instance_id,
source_attribute: "color",
}),
}),
]),
)
| 59 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 70 |
| Step | Clear the current selection. t.selection.clear()
| 71 |
| Step | Playback → api → go with $playback (result of record.via.ui.playback). t.playback.via.api.go(playback)
| 73 |
| Expected | Playback → runtime: $playback (result of record.via.ui.playback), {
current_cue_number: "1",
enabled: true
}t.playback.expect(playback).runtime({
current_cue_number: "1",
enabled: true,
})
| 74 |
| Step | Advance the test clock by "5s". t.clock.advanceBy("5s")
| 78 |
| Expected | fixture(1) DMX equals {
"Intensity coarse": 255,
"Intensity fine": 255,
"Color wheel 1": <unresolved: AURO_DEEP_RED_SLOT>
}t.expectFixtureDMX(
fixture(1),
{
"Intensity coarse": 255,
"Intensity fine": 255,
"Color wheel 1": AURO_DEEP_RED_SLOT,
},
)
| 79 |
| Step | Playback → api → off with $playback (result of record.via.ui.playback). t.playback.via.api.off(playback)
| 88 |
| Expected | Playback → runtime: $playback (result of record.via.ui.playback), {
enabled: false
}t.playback.expect(playback).runtime({ enabled: false })
| 89 |
| Step | Advance the test clock by "5s". t.clock.advanceBy("5s")
| 90 |
| Step | Patch → api → remove with 1. t.patch.via.api.remove(1)
| 93 |
| Expected | Group → empty: 1. t.group.expect(1).empty()
| 94 |
| Step | Patch → api → add with {
number: 2,
name: "RGBWA Wash",
address: "1.1",
<unresolved: ...RGBWA_WASH>
}t.patch.via.api.add({
number: 2,
name: "RGBWA Wash",
address: "1.1",
...RGBWA_WASH,
})
| 95 |
| Step | Selection → fixtures → api → item with 2. t.selection.fixtures.via.api.item(2)
| 101 |
| Step | Group → api → store with 1, {
mode: StoreMode.Merge
}t.group.via.api.store(1, { mode: StoreMode.Merge })
| 102 |
| Expected | Group → fixtures: 1, 2. t.group.expect(1).fixtures(2)
| 103 |
| Step | Clear the current selection. t.selection.clear()
| 104 |
| Step | Execute the desk command "GROUP 1 AT COLOR 0 DIV 100 DIV 0 DIV 0" through the API. t.command.via.api.execute("GROUP 1 AT COLOR 0 DIV 100 DIV 0 DIV 0")
| 107 |
| Step | Preset → api → update with PresetFamily.Color, 1, {
mode: "all"
}t.preset.via.api.update(PresetFamily.Color, 1, { mode: "all" })
| 108 |
| Step | Execute the desk command "GROUP 1 AT COLOR 100 DIV 0 DIV 0 DIV 0" through the API. t.command.via.api.execute("GROUP 1 AT COLOR 100 DIV 0 DIV 0 DIV 0")
| 109 |
| Step | Preset → api → update with PresetFamily.Color, 1, {
mode: "all"
}t.preset.via.api.update(PresetFamily.Color, 1, { mode: "all" })
| 111 |
| Step | Clear Programmer values through the encoder intent. t.encoder.clear()
| 112 |
| Step | Clear the current selection. t.selection.clear()
| 113 |
| Step | Playback → api → go with $playback (result of record.via.ui.playback). t.playback.via.api.go(playback)
| 116 |
| Expected | Playback → runtime: $playback (result of record.via.ui.playback), {
current_cue_number: "1",
enabled: true
}t.playback.expect(playback).runtime({
current_cue_number: "1",
enabled: true,
})
| 117 |
| Step | Advance the test clock by "5s". t.clock.advanceBy("5s")
| 121 |
| Expected | fixture(2) DMX equals {
Intensity: 255,
"Color red": 255,
"Color green": 0,
"Color blue": 0,
"Color white": 0,
"Color amber": 0
}t.expectFixtureDMX(
fixture(2),
{
Intensity: 255,
"Color red": 255,
"Color green": 0,
"Color blue": 0,
"Color white": 0,
"Color amber": 0,
},
)
| 122 |
| Step | Playback → api → off with $playback (result of record.via.ui.playback). t.playback.via.api.off(playback)
| 135 |
| Step | Advance the test clock by "5s". t.clock.advanceBy("5s")
| 136 |
| Expected | fixture(2) DMX equals {
Intensity: 0,
"Color green": 255,
"Color blue": 255,
"Color white": 255
}t.expectFixtureDMX(
fixture(2),
{ Intensity: 0, "Color green": 255, "Color blue": 255, "Color white": 255 },
)
| 137 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| unresolved-expression | Step | <unresolved: ...WHEEL_SPOT> Object member ...WHEEL_SPOT is not statically resolved. | 39 |
| unresolved-expression | Expected outcome | <unresolved: expect.arrayContaining([ expect.objectContaining({ group_id: "1", preset_reference: expect.objectContaining({ preset_instance_id: colorPreset.body.instance_id, source_attribute:…> Call expression expect.arrayContaining([ expect.objectContaining({ group_id: "1", preset_reference: expect.objectContaining({ preset_instance_id: colorPreset.body.instance_id, source_attribute:… is dynamic and was not executed. | 60 |
| unresolved-expression | Expected outcome | <unresolved: AURO_DEEP_RED_SLOT> Expression AURO_DEEP_RED_SLOT is not statically resolved. | 84 |
| unresolved-expression | Step | <unresolved: ...RGBWA_WASH> Object member ...RGBWA_WASH is not statically resolved. | 99 |
BENCH-PRODUCT-DEMO-001 — narrates the complete Full HD product demo surface in one regression run
tests/product-demo.spec.ts:5 · unresolved · last run: not merged
Browser UIGenerated artifacts
Scenario contract
| Kind | Scenario contract | Line |
|---|
| Step | Run the complete narrated Full HD product-demo workflow and its internal semantic assertions. t.demo.run()
| 9 |
| Expected | Complete product-demo workflow and its internal semantic assertions pass. t.demo.run()
| 9 |
Diagnostics
| Diagnostic | Where | Detail | Line |
|---|
| missing-migration-status | Source | No exact source, ID, and title match exists in the generated migration inventory. | 5 |