♻️ Introduce explicit PlaybackState machine#288
Merged
Conversation
5636ed3 to
a159cf9
Compare
3b86c20 to
ead4424
Compare
d622a99 to
91944d0
Compare
217c9df to
f964b66
Compare
Replaces flat PlaybackSession fields with sum-type states: Idle, Playing, Waiting, Paused — each frozen dataclass carrying only the fields it needs. Illegal states (e.g. paused_at without playing_tag) are now unrepresentable. RetryState replaces PlaybackCommandRetry; TransitionContext and PlaybackCommand introduced alongside.
Maps (PlaybackState, TagEvent, Disc | None, TransitionContext) to (success_state, command) without any I/O. Command is one of play | pause | resume | stop | None; the caller executes it.
HandleTagEvent is now a thin executor: resolves disc, calls the pure transition() function, executes the player command, manages retry state. DetermineAction is replaced by TransitionContext (config bundle). PlaybackSession replaced by PlaybackState (Idle | Playing | Waiting | Paused) throughout CLIController, di_container, and all call sites.
…backAction All replaced by the PlaybackState sum type and transition() function.
f964b66 to
93fd5e0
Compare
This was referenced Jun 20, 2026
Gudsfile
added a commit
that referenced
this pull request
Jun 20, 2026
## Summary Applies the same architectural pattern as the PlaybackState machine (#288) to the current-tag feature. - Add `NoTag | TagPresent | TagRemoved` frozen dataclasses and `CurrentTagContext` config bundle - Add pure `transition_current_tag(state, tag_event, ctx)` function - Rewrite `SyncCurrentTag` as a thin executor: calls `transition_current_tag`, executes repository command, stamps `last_event_timestamp` unconditionally on return - Update `CLIController` to thread `CurrentTagState` as an immutable return value instead of mutating a session - Delete `DetermineCurrentTagAction`, `ApplyCurrentTagAction`, `CurrentTagAction`, `CurrentTagSession` - Rename `transition` to `transition_playback` so both pure functions are self-describing at their call sites
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
PlaybackSession(flat mutable Pydantic model) withPlaybackState = Idle | Playing | Waiting | Pausedfrozen dataclasses. Illegal states are now unrepresentable by construction.transition(state, tag_event, disc, ctx)function: no I/O, no mocks needed in tests.HandleTagEventbecomes a thin executor: resolve disc, calltransition(), execute player command, manage retry state viaRetryState.DetermineAction,PlaybackSession,PlaybackCommandRetry,PlaybackAction(replaced entirely).Test plan
Tested end-to-end with
--player pn532 --reader dryrun: PLAY, CONTINUE, WAITING, PAUSE transitions confirmed in logsBase
Stacks on #287.