Commit graph

7 commits

Author SHA1 Message Date
5a4f70c90e docs(adr-005): record the NIP-17 alert and the settle-cash-owed path as built 2026-10-10 22:27:39 +02:00
7f055cd4c6 docs(adr): ADR-005 §4 — outOfCash after payment is owed too; only the cause and the latch differ 2026-10-10 21:37:47 +02:00
f3c333c0bb docs(adr): ADR-005 accepted 2026-10-10 21:07:43 +02:00
1a24bfdda8 docs(adr): ADR-005 — a partial dispense distributes once, when the outcome is final
Decision 1's partial row said "operator confirms → distribute scaled"
and left the undispensed remainder's fate implicit. Made explicit:
partial_pending holds everything — including the share of the notes
that did dispense — until the operator records how the shortfall was
resolved (remediated → full amount; vouchered or written off → scaled),
then one distribution runs at that amount with the existing scaling
arithmetic. A vouchered remainder waits for redemption or expiry.

The alternative (scaled part now, remainder on resolution) is recorded
as deferred, not rejected: it needs a second additive distribution pass
the repo lacks, and a partial is almost always a terminal fault that
has latched cash-out off, so resolution is hours. Decided 2026-10-10.

Also carries the hold-invoice decision rule that fell out of the same
analysis: dispensed > 0 → settle, dispensed == 0 → cancel. An exit jam
that reports zero cancels cleanly — the customer is charged nothing and
the stuck note is the operator's to recover — so hold invoices remove
owed-cash for full faults and exit jams, not for true partials.
2026-10-10 21:06:08 +02:00
d569e4013e docs(adr): ADR-005 — record that packages/hal has no tests (finding 10) 2026-10-09 21:43:00 +02:00
6a974054ce docs(adr): ADR-005 — future directions and the operator-docs gap
Records where the cash-out design is heading so Decisions 1–7 are made
with the destination in view:

- Hold invoices move authorize/capture from spirekeeper into the
  Lightning layer. LNbits core already has create/settle/cancel
  (lndrest + lndgrpc only; not yet on the nostr-transport). Settlement is
  all-or-nothing per HTLC, so a full fault cancels cleanly but a partial
  fault still needs a voucher — hold invoices remove owed-cash for the
  common case, not every case.
- Vouchers: a fiat-denominated claim at the original rate, a liability
  row linked to its origin settlement, whose undispensed sats stay
  undistributed until redemption or expiry.
- CLINK as the eventual favoured customer protocol; the availability
  beacon should align with the CLINK Beacon spec rather than grow a third
  shape.
- Operator notification is a Nostr event to the operator's pubkey, not
  email/SMS. The pubkey is already on the LNbits account; nsecbunkerd
  supports nip44 so no operator ever needs their nsec.
- An operator-facing error glossary, seeded from the F56-BDU error list
  and this incident's 78 42.
- Cross-reference to the Lamassu Port Backlog, and the finding that
  bitSpire carried lamassu's narrow GTQ window byte for byte.
- Bay layout is machine-authoritative (VITE_LAMASSU_CASSETTES on first
  boot, then state.db); spirekeeper adopts and deletes absent positions;
  no operator document describes any of it, and fleet targets are keyed
  by hostname so a second Tejo cannot join without a new flake target.

Refs #122
2026-10-09 21:42:03 +02:00
483e44aaa9 docs(adr): ADR-005 — cash-out dispense outcome and settlement capture
A customer paid a 40 EUR cash-out, a note jammed at the cassette exit,
and the dashboard showed `processed`. The machine had recorded the
failure correctly. Nothing it knew ever left the box.

The root is ordering, not display: spirekeeper spawns process_settlement
the instant the payment lands, which is before the machine has begun to
dispense. The legs are paid sub-second; the dispense fails afterwards;
and the one remediation tool refuses once any leg has completed. It is
unreachable for the exact case it was built for.

ADR-005 makes payment the authorization and dispense confirmation the
capture — distribution waits for the machine's report. The report is a
report_dispense RPC (not the state doc: ADR-004's losing-writer problem),
carried through a durable outbox, sent on success and failure, adopting
lamassu's dispense_confirmed / error / error_code taxonomy and its
per-bay action log — which the machine already records in cassette_bills
and simply never ships.

Deviates from lamassu in three places it got wrong or never did: a
zero-dispensed report that arrives with an error is treated as
unverified, not as zero; a mechanical fault is its own customer screen
with evidence and is not "out of cash"; and terminal dispenser faults
latch cash-out off until a recount or an explicit operator op, because
re-initialising does not move a stuck note.

Closes the review loop with ten findings outside the ADR's decisions.

Refs #122, #27, #78
2026-10-09 16:34:54 +02:00