feat(cassettes): persist the machine's counts-uncertain marker

The machine has been publishing counts_uncertain_since since v1 of the
state document and spirekeeper has been parsing it into a field nobody
read. That defeats the point of the marker: it exists so a human opens
the bay and recounts.

A dispenser can throw, or time out, after notes have physically moved.
The machine cannot know how many left, so rather than decrement a number
it would be guessing at, it stamps the moment (bitspire ADR-004,
decision 3). m014 gives that stamp a home on dca_machines, and the
consumer mirrors it on every state event.

Stored on the machine rather than the bay because the uncertainty is
about the dispense as a whole; a multi-bay dispense that fails midway
gives no reliable way to attribute it to one position.

Written through even when the machine reports None. The machine clearing
the marker is as important as setting it — the operator recounted, the
bay is trustworthy again — and a banner that never goes away is a banner
nobody reads.
This commit is contained in:
Padreug 2026-09-23 12:47:30 +02:00
commit c76a1bb125
5 changed files with 112 additions and 1 deletions

19
crud.py
View file

@ -257,6 +257,25 @@ async def set_machine_unpaired(machine_id: str) -> Machine | None:
return await get_machine(machine_id)
async def set_machine_counts_uncertain(machine_id: str, since: datetime | None) -> None:
"""Record (or clear) the machine's own "I can't vouch for these counts"
marker, straight from its state document.
`updated_at` is deliberately left alone. This is the machine reporting
about itself on a five-minute heartbeat, not an operator editing the
machine, and touching the timestamp on every heartbeat would make the
registry look perpetually just-modified.
"""
await db.execute(
"""
UPDATE spirekeeper.dca_machines
SET counts_uncertain_since = :since
WHERE id = :id
""",
{"since": since, "id": machine_id},
)
async def delete_machine(machine_id: str) -> None:
await db.execute(
"DELETE FROM spirekeeper.dca_machines WHERE id = :id",