Skip to content

feat(api): guard machine actions from the primary scale - #845

Draft
MaxRink wants to merge 3 commits into
decentespresso:mainfrom
MaxRink:feature/guarded-plugin-scale-actions
Draft

MaxRink wants to merge 3 commits into
decentespresso:mainfrom
MaxRink:feature/guarded-plugin-scale-actions

Conversation

@MaxRink

@MaxRink MaxRink commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Add an opt-in guarded form to the machine state route so a plugin action is checked again when it reaches the hardware. GET /api/v1/machine/state now includes the current deviceId and connectionGeneration; the guarded request carries the expected machine identity, generation, state, GHC condition, and primary scale identity tokens. Stale or reassigned context is rejected before any machine write.

For example, a plugin can observe machine A idle and primary scale S selected, then queue a start; if A reconnects or S is reassigned before execution, the generation and selection tokens reject that stale start instead of writing to the replacement context.

GET /api/v1/scale/connections exposes the current primary connection as {"primary": null} or {"primary": {...}}. The guarded action accepts only the primary source role. A non-primary source is rejected with 400; stale machine or scale tokens return 409.

Only idle -> espresso starts and espresso -> idle stops are guarded. Stops use the direct stop path and invalidate older queued guarded starts. Legacy unguarded requests retain their existing path.

Linked Issue

Related #853. Related #715 for the accepted Skale button behavior. The single-device Skale consumer is #846; multi-scale host work is #843/#859.

Verification

  • Combined Linux Flutter gate for the current publication stack: 4,315 passed, 1 skipped, 0 failed; analyzer clean (48.0s). Source was unchanged during the gate.

  • This combined gate covers the primary-only guarded-action contract together with its current consumers; the primary-only API remains independently reviewable from the auxiliary-scale consumer.

  • Primary guarded-action and reload smoke passed primary start/stop, stale-context rejection, auxiliary-source rejection, and legacy bodyless stop.

  • Primary guarded-action and reload smoke passed primary start/stop, stale-context rejection, auxiliary-source rejection, and legacy bodyless stop.

Impact

The guarded form is opt-in and introduces no auxiliary machine-action role. It prevents a plugin from acting on a machine or primary scale context that changed after the button decision. Bodyless requests, valid legacy JSON without guarded, JSON null, and guarded: false retain the unguarded path; malformed nonempty JSON and a non-boolean guarded value now return 400 rather than falling through to an unguarded write.

Contributor Responsibility

AI-assisted development is allowed. The submitter remains responsible for the submitted work.

  • I have reviewed and understand all changes in this PR and take responsibility for their correctness, security, behavior, licensing, and provenance, including any AI-assisted or AI-generated work.

@MaxRink
MaxRink force-pushed the feature/guarded-plugin-scale-actions branch from 45e764a to 9320595 Compare September 13, 2026 21:39
@MaxRink MaxRink changed the title feat(plugins): add guarded scale-button machine actions feat(api): add brewing-only guarded scale actions Sep 13, 2026
@MaxRink
MaxRink force-pushed the feature/guarded-plugin-scale-actions branch from 9320595 to 5962990 Compare September 14, 2026 08:58
@MaxRink
MaxRink force-pushed the feature/guarded-plugin-scale-actions branch from 5962990 to 96ae92b Compare September 14, 2026 11:55
@MaxRink MaxRink changed the title feat(api): add brewing-only guarded scale actions feat(api): guard machine actions from the primary scale Sep 14, 2026

tadelv commented Sep 16, 2026

Copy link
Copy Markdown
Member

Maintainer direction: keep this held for human review, not as a 0.9.0 generic runtime/grinder release gate. See #853 and tracker #890.

The guarded-action idea is useful for Skale button behavior, but it is safety-sensitive machine-control API work with deliberate compatibility changes. Please do not let this block or become a prerequisite for the P0 generic runtime work while maintainer availability is limited.

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.

2 participants