cassette_configs never reconciles bay removals, and Publish can overwrite a newer ATM report #43

Closed
opened 2026-09-20 15:15:33 +00:00 by padreug · 0 comments
Owner

Two halves of the same problem, found alongside aiolabs/bitspire#94.

  1. apply_bootstrap_state upserts the positions in the payload but never deletes positions that are absent. If a machine's bay count shrinks, the stale row stays, the dashboard shows a mix of old and new, and publish_cassettes rejects every payload with a position mismatch. The error text tells the operator to fix it with atm-tui, but atm-tui changes don't propagate (see the bitspire issue), so the advice is a dead end. There is no delete endpoint; the only way out today is DELETE FROM cassette_configs by hand.

  2. The cassettes form is a load-once snapshot and Publish sends it as-is. Nothing checks whether the machine has reported a newer state since the form was loaded, so a stale Publish gets a fresh created_at and the ATM applies it over its own fresh report. The state_* columns already hold the reported values and event id but the UI doesn't render them.

Proposed:

  • consumer: reconcile the row set on receipt — delete positions not in the payload, insert new ones, update the rest.
  • dedup gate: compare all rows' state_event_id, not one.
  • UI: show reported denomination/count + state_at next to the operator values; refresh on tab open.
  • publish_cassettes: accept the state_event_id the form was loaded against and reject with 409 when the stored one differs, so the operator reloads before publishing.
Two halves of the same problem, found alongside aiolabs/bitspire#94. 1. apply_bootstrap_state upserts the positions in the payload but never deletes positions that are absent. If a machine's bay count shrinks, the stale row stays, the dashboard shows a mix of old and new, and publish_cassettes rejects every payload with a position mismatch. The error text tells the operator to fix it with atm-tui, but atm-tui changes don't propagate (see the bitspire issue), so the advice is a dead end. There is no delete endpoint; the only way out today is DELETE FROM cassette_configs by hand. 2. The cassettes form is a load-once snapshot and Publish sends it as-is. Nothing checks whether the machine has reported a newer state since the form was loaded, so a stale Publish gets a fresh created_at and the ATM applies it over its own fresh report. The state_* columns already hold the reported values and event id but the UI doesn't render them. Proposed: - consumer: reconcile the row set on receipt — delete positions not in the payload, insert new ones, update the rest. - dedup gate: compare all rows' state_event_id, not one. - UI: show reported denomination/count + state_at next to the operator values; refresh on tab open. - publish_cassettes: accept the state_event_id the form was loaded against and reject with 409 when the stored one differs, so the operator reloads before publishing.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/spirekeeper#43
No description provided.