Complete Phase 3B authoritative playback
Audit, fix, and verify the Phase 3B playback engine under Node 22 with a full backend suite, project lint/build checks, Docker builds, Compose validation, and isolated runtime playback verification. Two concrete correctness bugs were found and fixed, each with a regression test that fails without the fix: reconcileRotating() evaluated boundaries against a stale entry. After fastForwardStable() skipped whole cycles it could move the stable cursor, but the loop kept using the pre-skip entry, so that entry's schedule end or expiration cut the successor's slide short and shifted every later absolute deadline. Re-evaluate the loop when the cursor moves. resumeHeldEntry() could reconstruct a timeline whose slide_started_at was in the future. A remainder captured under a longer duration was replayed verbatim after the effective duration shrank, publishing a snapshot whose current slide had not started yet and whose remaining time exceeded its own effective duration. Clamp the remainder to the effective duration. Two Phase 3A tests built playback_state rows by raw SQL that the service can never hold: an activation queued behind a playlist with no playable entry, and a static hold that still carried a live absolute timeline. Both now drive the authoritative service, keeping their original assertions about deletion protection and revision bookkeeping. Record the static-target deletion refusal as a known interim integration point rather than final behavior; playback already tolerates a deleted static asset, so Phase 3B does not depend on it. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -174,6 +174,13 @@ the playback revision.
|
||||
Phase 3B exposes this state and behavior through REST and Socket.IO only. MQTT
|
||||
command wiring and the browser display renderer remain later phases.
|
||||
|
||||
Deleting a library asset that is the current static target is still refused by
|
||||
the Phase 2 deletion model. That refusal is a known interim integration point,
|
||||
not the intended final behavior: deleting the statically held slide is meant to
|
||||
exit static safely, return to normal rotation, and only then delete the asset.
|
||||
Phase 3B does not depend on the refusal, so the change belongs to the later
|
||||
phase that revisits asset lifecycle.
|
||||
|
||||
## Storage and health
|
||||
|
||||
The API uses a small path-style S3 adapter configured by `S3_ENDPOINT`,
|
||||
|
||||
Reference in New Issue
Block a user