The state diffing and gating logic moves verbatim from the
broadcastResult decorator into collectRuntimeStateChanges in
runtime.utils.ts. The decorator becomes a thin shell: snapshot, diff,
batch the changed keys, save the restore point, send.
The entire gating matrix is now unit tested against plain state
objects (see runtime.utils.test.ts), including the characterised
entry-diffing short-circuit, without sockets or module mocking. The
broadcast-contract tests remain the end-to-end lock and are unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PVTnCfesGNGwPQJwJ9FwoD
updateIfIdle and updateIfWaitingToRoll were declared inside update(),
allocating two closures on every 32ms tick. They are now module-level
functions receiving the state explicitly. Behaviour is unchanged, as
proven by the characterisation suite.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PVTnCfesGNGwPQJwJ9FwoD
Every mutator in runtimeState.ts now has a *Core function that receives
the state it operates on and touches nothing else. The module keeps the
singleton and exports thin wrappers with the existing names and
signatures, so all call sites (EventTimer, runtime service, rundown
service) are unchanged and the hot path gains no allocations.
This also removes the partial-injection hazards of the previous seams:
start(state) wrote timer.phase, offset and expected times to the module
singleton rather than the received state, and stop(state) cleared the
singleton. Production behaviour is identical since production always
operated on the singleton; the characterisation harness and snapshots
are untouched and prove it.
The cores can now be unit tested against a plain state object without
the singleton, module resets or the rundown cache.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PVTnCfesGNGwPQJwJ9FwoD
Locks down the current behaviour of the runtime state hot path before
any refactoring work:
- scenario driver and fixtures that script playback sequences against
the real runtimeState singleton with fake timers, mirroring the
EventTimer tick loop
- characterisation catalogue covering absolute/relative offsets,
expected group/flag/rundown times, gap compensation, delays,
countToEnd, addTime edge cases, pause accounting, roll modes and
playback across midnight
- broadcast-contract tests locking which top-level store keys are
emitted per action and tick, including the per-second gating and
integration throttling
- unit tests for the previously untested change-detection predicates
in runtime.utils.ts
The tests characterise current behaviour, including quirks (documented
inline): the entry diffing short-circuit that drips changed entries one
per broadcast, the sticky forceFinish flag after negative addTime, and
roll-continuation overwriting actualStart.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PVTnCfesGNGwPQJwJ9FwoD
* refactor: allow secondary rundowns
* ui: move dropdown
* feat: follow loaded
* ui: background edit warning
ui: fix disable radio button
* feat(ui): add loaded sufix in the rundown list
* feat(ui): add direct link to background edit from rundown manager
* fix: better fallback
* fix: default to is isCurrentRundown for nav bar colour
* chore: rename navigate to cuesheet
---------
Co-authored-by: alex-arc <ac@omnivox.dk>
Adds timer-legacy.html — a zero-dependency static page that connects
to the Ontime WebSocket and displays the live countdown for browsers
that cannot parse the Vite-built React bundle (Safari < 14, Chrome < 85).
Also adds a synchronous pre-React guard in index.html that redirects
/timer visitors to the legacy page when Promise.any is unavailable,
matching the Vite build target floor of Safari 14 / Chrome 85.
https://claude.ai/code/session_013MfdwdjdDUnr3akpGSGXa4
* feat: update auto cue numbering
* feat: renumber from ui
* refactor: patchEntries is not used
* chore: format
* fix: correct cue at top of group
* fix: handle precision
* refactor dialog
* bump limit for performance time test
* extract type
* add class name to lable
* fix rebase
* refator: extract renumering logic
* chore: comments for getIntegerAndFraction function
* chore: add the for renumber mutation
* fix: fraction match precision
* refactor: small cleanup
* refactor: use more narrow validator
---------
Co-authored-by: alex-Arc <omnivox@LAPTOP-RC5SNBVV.localdomain>
* refactor: remove unneeded async
* chore: add express Router type to all routes
* refactor: don't use index in react key
* refactor: correctly get error message in excel route
* refactor: avoid exporting muteable values
* refactor: replace traslation hook refetch time with stale time
* refactor: make it the service responsebillety to send refetch keys for asset changes
* fix: prevent add filter from submitting form
* refactor: event clarifies whether automations exist but are disabled
* refactor: improve readability of automation form
* refactor: add affordance for field warnings
* refactor: improve visibility of automation off state
* refactor: apply warning styles to other feature toggles
* Adding playback actions to automations (#2024)
* adding intial automation actions
* cleaning up
* fixing formatting
* ran oxfmt
* switching action names to playback- to match the dropdown strings
* fixing flicker that was caused by scroll arrows gettting unmounted
---------
Co-authored-by: Cameron Slipp <cdslipp@gmail.com>
* chore: migrate eslint to oxlint
* chore: migrate prettier to oxfmt
* chore: migrate typescript
* chore: toThrow should have a expected value
* chore: cast test value as Day
* chore: small title fix
* chore: mocks should be hoisted
* chore: incorrect async useage
* chore: test should be inside description
* chore: test sohuld include an expeced
* chore: oxfmt
---------
Co-authored-by: alex-Arc <omnivox@LAPTOP-RC5SNBVV.localdomain>
* feat: get server port from app satate or env
optional startup port from env will always override
function for parsing port from env
populate default port in app state
add test for migration
* bump version