Repository navigation
Scope the equilibrium check to SceneUpdate — fixes arbitrary drops of single-parameter updates - #4
Merged
Conversation
…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]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes LIMITATIONS.md item 7, which was previously deliberately left as "not fixed — this needs a real design answer, not a guess."
validate_invariantsrejected every message type outright if its self-reportedpir_invariants.residualexceeded1e-12— includingControlParameter,Heartbeat,MusicalContextandArtistTracking, 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
SceneUpdatecan 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(...)inkraken-tentacle.only-pchi). The message-level gate was duplicating that check, badly, over data that was never a valid invariant claim.Test plan
SceneUpdatestill rejects a real equilibrium violation (regression guard — this is exactly the case the check exists for);ControlParameter/Heartbeat/MusicalContext/ArtistTrackingare no longer gated on residualcargo test --workspace: 29/29 passcargo clippy --workspace --all-targets -- -D warnings: clean🤖 Generated with Claude Code