Skip to content

fix(osc): float32 readback tolerance for list values; loud placement failures; disarm skips reset layers and always logs (869f8hfra) - #20

Merged
ibiltari merged 11 commits into
rc_1from
fix/869f8hfra-scale-readback
Sep 29, 2026
Merged

ibiltari merged 11 commits into
rc_1from
fix/869f8hfra-scale-readback

Conversation

@ibiltari

Copy link
Copy Markdown
Member

Fixes ClickUp 869f8hfra. Plan: cuems-RELATIONS/Plans/2026-09-28-videocue-scale-readback-869f8hfra.md

Problem

On every video layer arm and GO, the engine logged Could not set …/scale even though the value was sent correctly.

The ticket blamed an OSC race, but the real cause is a readback check. pyossia stores list elements as float32, and OssiaNodes.set_value compared lists with a strict !=. So 0.1 sent never equalled 0.10000000149… read back.

Changes

A. set_value tolerance. _values_match compares recursively. Numbers use math.isclose (rel/abs 1e-6), and lists must match in length.

B. Placement failures are loud. If position or scale cannot be applied:

  • it is logged at ERROR, naming the cue, the layer and the output;
  • it is recorded in cue._placement_failed, which is reset on every arm;
  • the arm still succeeds. That is a deliberate decision: wrong geometry beats no video in a live show.

D. Disarm skips layers /videocomposer/reset already removed. STOP resets before it disarms, on purpose, for an instant blackout. Disarm used to write to endpoints that were gone and logged Node not found. Within disarm, hiding and unloading now fail independently: a failed visible 0 still unloads the layer.

D4. Every disarm logs at DEBUG, with a reason: cue_end, stop, stop_action, load, ready_script, disabled, project_changed or shutdown. A silent disarm is not acceptable.

Docs. CLAUDE.md gains two gotchas: the float32 readback, and the fact that engine-driven layers never auto-unload. They freeze on their last frame until the disarm.

Tests come first in each pair of commits. The last pair holds the /code-review follow-ups.

Verification

Engine suite on test2: 818 passed on rc_1; 853 passed on this branch.

Live A/B on test2:

Measure rc_1 this branch
Could not set 10 0
Node not found at STOP 4 0

Disarm lines carry their reasons, and a bad output name produces the B ERROR while the cue still plays.

Compatibility

Engine only; there is no protocol or config change. Placement messages move from WARNING to ERROR, and disarms now log at DEBUG.

…included (869f8hfra)

pyossia stores Float and the elements of List/Vec2f as float32. set_value
only tolerated that for scalar floats and compared lists with !=, so any
scale that is not exactly representable (1200/2160) raised "Could not set
.../scale" on every video layer arm, after the value had already been sent.
Numbers now compare with math.isclose (rel/abs 1e-6), lists element by
element, and every failure reports what was read back. The scalar branch's
fixed 1e-5 absolute bound also failed large floats (1920.3); covered too.
… cue (869f8hfra)

When a layer's placement/scale cannot be applied (no output match, or a
genuine readback mismatch), arm_videoCue and run_videoCue's GO re-apply
logged a WARNING and moved on, so the cue reported "armed" with the layer at
default geometry and nothing told the operator. They now log at ERROR with
the cue, layer and output, and record the layer in cue._placement_failed,
which every arm resets. The cue still arms and plays: a wrong-sized video is
better than no video in a live show (Ion, 2026-09-28).
…disarm with a reason (869f8hfra)

STOP, load and ready_script reset the videocomposer before disarm_all on
purpose (instant blackout); disarm then wrote visible 0 to endpoints the
reset had removed, 70 "Node not found" per week on medina cupula2, logged at
DEBUG. disarm now skips a layer PlayerHandler no longer tracks, keeping the
order untouched.

Every disarm now logs what it did and why (Ion: a silent disarm, the
automatic one at cue end included, is not acceptable): one DEBUG line per cue
with a reason (cue_end, stop_action, disabled, project_changed, load,
ready_script, shutdown); video cues list the layers unloaded and skipped.
A per-layer failure is now a WARNING instead of DEBUG.
… reason stop; a GO re-apply clears the arm failure (red, 869f8hfra)
- disarm: hiding (visible 0) and unloading are separate; a failed hide no
  longer skips the unload and leaves the layer loaded. A failed unload keeps
  the layer registered so the next /reset still cleans it up.
- disarm's skipped-layer note says what it knows ("no longer tracked:
  removed by reset or quit") and flags a cue with no video client.
- ready_script takes its caller's reason, so a STOP logs "(stop)" and a
  load "(load)" instead of "(ready_script)".
- a successful placement re-apply at GO clears the failure recorded at arm.
- the placement ERROR no longer claims default geometry when only one of
  position/scale failed.
@ibiltari
ibiltari requested a review from backenv as a code owner September 28, 2026 21:45
CI Lint failed on PR #20: black --check flagged OssiaNodes.py,
test_video_placement_failure.py and test_ossia.py. Purely cosmetic
(blank lines, line width); no behavior change. Re-ran the 3 affected
test files after formatting: 54 passed.
@ibiltari
ibiltari merged commit 93ffb41 into rc_1 Sep 29, 2026
2 checks passed
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