Back to the resultsSource: night-2026-10-11/proof-w1-server.md

W1 lane B proof: inhibit masters, tempo clock, highlight

Branch w1-server-core, worktree ~/trc-lighting/wt-server-core, cut from two-screen 4dbe8af. Mac dry run: dotnet bin/w1/LightDesk.dll --dry-run --ui-standalone --port 7081 --camera-from audit-2026-10-10/.camera-scratch. Baseline for the ms check: git archive 4dbe8af built and run the same way on port 7089. Never called: /api/dmx/nodes, POST /api/dmx/output. Both servers stopped after the run. Build: dotnet build -c Release succeeded; the only warnings left are CA1416 in CamFrame.cs (not touched). The one pre-existing warning in Program.cs (CS8632, string? Mode) was removed.

1. Inhibit: ANTHEM with KEY capped at 5

Leko 1 = universe 1 address 33, dimmer channel 40. Leko 2 = address 41, dimmer channel 48. ANTHEM (703) asks Group 21 At 10 in data/scenes.json (not 15 as PLAN.md says).

Camera-safe KEY inhibit Engine target Frame leko 1 / leko 2 (of 255)
off 100 (none) 10 % 25 / 25
off 5 10 % 12 / 12
on 100 (none) 25 % (the camera-safe floor) 64 / 64
on 5 25 % 12 / 12
off 5, then KEY fader to Full 100 % 12 / 12

Pass: at or below 13/255 in every case; the cap wins over the camera-safe floor and over a fader at Full. /api/status.inhibits and /api/rig/state.inhibits both read KEY 21 max 5 fixtures 1-6, FOH 22 max 10 fixtures 201, 202. SSE: inhibit arrived at once on a POST, and the next rig event carried inhibits with the new FOH value.

2. Tempo: a beats:1 hit at 120 BPM

Test hit (temporary, not committed): two steps on the truss pars, Group 3 At Full then Group 3 At 0, each beats: 1. Sampled /api/dmx/frame on channel 112 (truss par 3101 dimmer); the 40 fps loop reached 31 ms per sample (each request renders a frame), 256 samples over 8 s.

Measure n Mean Median Min Max
Step period, 120 BPM (target 500) 14 501.1 ms 499.1 478.4 527.0
Two-step cycle, 120 BPM (target 1000) 7 1002.2 ms 999.0 987.4 1023.8
Step period, 90 BPM (target 666.7) 8 666.3 ms 667.0 652.1 681.6

Pass: 500 ms ±10 on the mean. Single intervals spread about ±25 ms because the samples are 31 ms apart. A first run before the final rebuild read 499.1 ms mean (n=15). Tap: six taps 500 ms apart gave 120 BPM with taps: 4; one tap after a 2.2 s gap kept 120 and restarted the count at 1.

3. ms-only hits unchanged

HEARTBEAT (ms 220 / 220, no beats), the dimmer of 1101 sampled through /api/dmx/state, the same way on both builds:

Build Run 1 mean Run 2 mean
this branch (7081) 221.9 ms 221.2 ms
baseline 4dbe8af (7089) 222.0 ms 221.4 ms

Pass: same period within 1 ms. The final binary read 220.8 ms through /api/dmx/frame.

4. Highlight

Picked 1201 and 1202 (/api/ui/selection), ANTHEM live, POST /api/highlight {fixtures:[1201,1202], on:true}, 3 s of frames:

Fixture Channel Min Max Distinct values
1201 picked 238 51 255 77
1202 picked 282 51 255 77
1203 not picked 304 230 230 1
leko 1 not picked 40 12 12 1

Breath period on 1201: 986 ms and 998 ms. 51/255 = 20 %. Undo ring before and after highlight on, 1.5 s, off: identical (depth 10, same top entry and times). Released by on:false (1201 back to 230), by a new pick ([1203]), and by /api/blackout; a re-post of the same pick keeps it. Highlight on leko 1 with KEY capped at 5 reached 255 in this first run; superseded by the re-run below. Errors answer 400: inhibit on group 99, tempo without bpm, highlight without fixtures.

5. Re-run: highlight now respects the inhibit cap (team lead ruling, Greg: "Don't use the key light almost at all")

Engine.cs Render: the cap now applies after the highlight; the highlight still overrides the grand master. ANTHEM live, KEY 5, FOH 10, POST /api/highlight {fixtures:[1201,1202,1], on:true}, 3 s of frames, 98 samples:

Fixture Channel Min Max Distinct values
1201 highlighted 238 51 255 70
1202 highlighted 282 51 255 70
1203 not highlighted 304 230 230 1
leko 1 highlighted, KEY capped at 5 40 12 12 1

Breath period on 1201: 1007 ms and 1014 ms. Pass: leko 1 never exceeded 13/255 while highlighted.