Skip to content

Scope the equilibrium check to SceneUpdate — fixes arbitrary drops of single-parameter updates - #4

Merged
vdmo merged 1 commit into
mainfrom
fix/equilibrium-check-scoped-to-scene-update
Sep 30, 2026
Merged

vdmo merged 1 commit into
mainfrom
fix/equilibrium-check-scoped-to-scene-update

Conversation

@vdmo

@vdmo vdmo commented Sep 30, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes LIMITATIONS.md item 7, which was previously deliberately left as "not fixed — this needs a real design answer, not a guess."

validate_invariants rejected every message type outright if its self-reported pir_invariants.residual exceeded 1e-12 — including ControlParameter, Heartbeat, MusicalContext and ArtistTracking, none of which carry a genuine multi-value invariant. The Resolume bridge computed that residual as a Prouhet-Thue-Morse-signed sum over its last 1–4 recently-set, often unrelated parameter values. A single layer's opacity change (one value) always failed — a lone value can never cancel by construction. Matched multi-value updates passed or failed depending purely on which arbitrary window a given message happened to land on at send time.

The design answer

Equilibrium is a property of a scene — a set of related values a sender deliberately constructed to balance together (the Kraken example: 8 tentacles' wobbliness, paired so the PTM-signed sum cancels) — not of one independent fact like "opacity is now 0.85." Only SceneUpdate can genuinely carry that. Every other message type is no longer gated on residual/coherence-gap.

This isn't a loosened check, it's a correctly-scoped one. The conductor already has the real mechanism for tracking equilibrium across a sequence of independent updates: it recomputes actual aggregate equilibrium from the real accumulated scene state after every message (SceneState::update_equilibrium_status), and the shipped default rule file already acts on that real value (if equilibrium > 1e-12 then escalate(...) in kraken-tentacle.only-pchi). The message-level gate was duplicating that check, badly, over data that was never a valid invariant claim.

Test plan

  • 4 new tests: SceneUpdate still rejects a real equilibrium violation (regression guard — this is exactly the case the check exists for); ControlParameter/Heartbeat/MusicalContext/ArtistTracking are no longer gated on residual
  • cargo test --workspace: 29/29 pass
  • cargo clippy --workspace --all-targets -- -D warnings: clean
  • Live re-run of the exact documented scenario: a real conductor + the real (fixed, Fix Resolume bridge: wire-format bugs meant zero messages ever reached the conductor #3) Resolume bridge. A single opacity change, previously always rejected → now applied. An 11-message burst across mixed parameters, previously 5/11 applied and 6/11 dropped at random → now 25/25 applied, 0 dropped, across both scenarios combined

🤖 Generated with Claude Code

…ry message type

Fixes LIMITATIONS.md item 7. validate_invariants rejected every message
type outright if its self-reported pir_invariants.residual exceeded
1e-12, including ControlParameter, Heartbeat, MusicalContext and
ArtistTracking — messages that report one independent fact and never
carried a genuine multi-value invariant. The Resolume bridge computed
that residual as a PTM-signed sum over its last 1-4 recently-set
parameter values, a number with no real meaning for unrelated values:
a single layer's opacity change always failed (one value can never
cancel by construction), and matched multi-value updates passed or
failed depending on which arbitrary window a message happened to land
on at send time.

Equilibrium is a property of a scene — a set of related values a sender
constructed to balance together (the Kraken example: 8 tentacles'
wobbliness, deliberately paired so the signed sum cancels) — not of one
independent fact. Only SceneUpdate can carry that. Every other message
type is no longer gated on residual/coherence-gap.

This isn't a loosened check, it's a correctly-scoped one: the conductor
already has the real mechanism for tracking equilibrium across a
sequence of independent updates — it recomputes actual aggregate
equilibrium from the real accumulated scene state after every message
(SceneState::update_equilibrium_status), and the shipped default rule
file already acts on that real value (`if equilibrium > 1e-12 then
escalate(...)` in kraken-tentacle.only-pchi). The message-level gate was
duplicating that check, badly, over data that was never a valid
invariant claim.

Added 4 tests: SceneUpdate still rejects a real equilibrium violation
(regression guard — this is exactly the case the check exists for);
ControlParameter, Heartbeat, MusicalContext and ArtistTracking are no
longer gated on residual. 29/29 tests pass; clippy clean.

Verified live: re-ran the exact scenario documented in LIMITATIONS.md —
a single opacity change (previously: always rejected) and an 11-message
burst across mixed parameters (previously: 5/11 applied, 6/11 dropped
at random) — against the same real conductor and bridge. Now: 25/25
applied, 0 dropped, across both.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
@vdmo
vdmo merged commit 0f01ae8 into main Sep 30, 2026
1 check passed
@vdmo
vdmo deleted the fix/equilibrium-check-scoped-to-scene-update branch September 30, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant