fix(machine): republish cassettes-state after dispense + on reload #65

Merged
padreug merged 1 commit from cassette-state-republish into dev 2026-06-22 09:56:40 +00:00
Owner

Operator-requested fix from the 2026-06-21 cash-out leg (~/dev/coordination/smoke-bunker-pairing-sintra.md, 15:30Z spec §2 — the cassette half, which stands; the cash-in half was superseded for security and is tracked separately in spirekeeper#31).

Problem

The bitspire-cassettes-state beacon was published once at bootstrap only (operator-config.ts v1 one-shot). After a cash-out dispense the ATM decrements its local HAL counts but never republishes, so the operator's Cassettes view stays frozen at the bootstrap snapshot (still 20×4 / 50×7 after dispensing 20×1 + 50×1).

Fix

  • operator-config.ts — extract publishCassettesState() (the live, ungated publish) out of the one-shot bootstrap; expose it on OperatorConfigService; also fire it after an operator-config apply (the "on reload" case — different d-tag from the operator's config event, so no echo loop).
  • atm.ts — republish after each cash-out dispense (complete + partial), once the decremented counts are persisted via recordTransaction → reloadPersistedInventory. Cash-in complete is skipped (doesn't touch cassettes).

kind-30078 is replaceable (latest wins) and the operator already consumes every update — no operator-side change. typecheck 12/12, machine 29 tests green.

Validates live on the next cash-out

The Sintra is paired (679ac2a8) with cassette rows populated (20×4 / 50×7). Once this deploys, the next cash-out dispense will republish the decremented counts and the operator view should track it — a good leg to fold into the in-progress cash-in/out test.

Do NOT use the MCP merge endpoint — merge via the Forgejo UI after review.

🤖 Generated with Claude Code

Operator-requested fix from the 2026-06-21 cash-out leg (`~/dev/coordination/smoke-bunker-pairing-sintra.md`, 15:30Z spec §2 — the cassette half, which stands; the cash-in half was superseded for security and is tracked separately in spirekeeper#31). ### Problem The `bitspire-cassettes-state` beacon was published **once at bootstrap only** (`operator-config.ts` v1 one-shot). After a cash-out dispense the ATM decrements its local HAL counts but never republishes, so the operator's Cassettes view stays frozen at the bootstrap snapshot (still 20×4 / 50×7 after dispensing 20×1 + 50×1). ### Fix - **`operator-config.ts`** — extract `publishCassettesState()` (the live, ungated publish) out of the one-shot bootstrap; expose it on `OperatorConfigService`; also fire it after an operator-config apply (the "on reload" case — different d-tag from the operator's config event, so no echo loop). - **`atm.ts`** — republish after each cash-out dispense (complete + partial), once the decremented counts are persisted via `recordTransaction` → `reloadPersistedInventory`. Cash-in `complete` is skipped (doesn't touch cassettes). kind-30078 is replaceable (latest wins) and the operator already consumes every update — **no operator-side change**. typecheck 12/12, machine 29 tests green. ### Validates live on the next cash-out The Sintra is paired (`679ac2a8`) with cassette rows populated (20×4 / 50×7). Once this deploys, the next cash-out dispense will republish the decremented counts and the operator view should track it — a good leg to fold into the in-progress cash-in/out test. Do NOT use the MCP merge endpoint — merge via the Forgejo UI after review. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The cassette-state beacon was published only once at bootstrap, so after a
cash-out dispense the operator's view stayed frozen at the bootstrap snapshot
(still 20x4/50x7 after dispensing) — the ATM decremented its local HAL counts
but never told the operator. Coord 2026-06-21 (post cash-out leg).

- operator-config.ts: extract publishCassettesState() (the live, ungated
  publish) out of the one-shot bootstrap; expose it on OperatorConfigService;
  also fire it after an operator-config apply (the "on reload" case).
- atm.ts: republish after each cash-out dispense (complete + partial), once the
  decremented counts are persisted. kind-30078 is replaceable (latest wins) and
  the operator already consumes every update — no operator-side change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
padreug force-pushed cassette-state-republish from 8b7098a4b0 to 762b0def5c 2026-06-22 09:56:16 +00:00 Compare
padreug deleted branch cassette-state-republish 2026-06-22 09:56:40 +00:00
Sign in to join this conversation.
No reviewers
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/bitspire!65
No description provided.