docs(security-pathway): flag kind:21001 CLINK collision + rotation

S3 settlement-receipt kind was provisionally 21001, but that kind is
claimed by CLINK (Offers). Replace the speculative kind text in the
cash-out diagram and the S3 row with an explicit DO-NOT-USE alert
citing the 2026-06-02 collision, the aiolabs/satmachineadmin#44
rotation tracker, and the 22000-22099 target band.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-06-06 21:00:14 +02:00
commit 9c4d2c1324

View file

@ -256,7 +256,7 @@ What we **do not** adopt and why (from the NIP survey):
│ Lightning settles │ Lightning settles
┌─────────────────────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────────────────────┐
│ Settlement attestation (NIP-57-style receipt — kind:9735 or our own kind:21001) │ Settlement attestation (NIP-57-style receipt — see kind-rotation note in §6 / S3 row)
│ │ │ │
│ LNbits publishes (signed by the LNbits server key): │ │ LNbits publishes (signed by the LNbits server key): │
│ { kind: 9735, │ │ { kind: 9735, │
@ -303,7 +303,7 @@ None of those need to change. The new layers slot in *above* them.
| **S0 — SeedURL pairing + ATM keypair separation** | Provisioning script generates a fresh `nsec` for the ATM (already does — we just stop overwriting it with the operator's). Operator pastes a oneshot QR/seed URL containing `{atm_npub, operator_npub, relay_list, signed_delegation_token}` at ATM first boot. | G3 (most of it), G9 | 1 week | None — purely on our side. Use existing NIP26 spec. | | **S0 — SeedURL pairing + ATM keypair separation** | Provisioning script generates a fresh `nsec` for the ATM (already does — we just stop overwriting it with the operator's). Operator pastes a oneshot QR/seed URL containing `{atm_npub, operator_npub, relay_list, signed_delegation_token}` at ATM first boot. | G3 (most of it), G9 | 1 week | None — purely on our side. Use existing NIP26 spec. |
| **S1 — NIP40 expiration on all kind21000** | Every RPC carries `["expiration", now+5min]`. Handler refuses pastexpiration. ATM clock check on boot (warn if drift > 60s). | G4 | 12 days | Relay must support NIP40 (most do). | | **S1 — NIP40 expiration on all kind21000** | Every RPC carries `["expiration", now+5min]`. Handler refuses pastexpiration. ATM clock check on boot (warn if drift > 60s). | G4 | 12 days | Relay must support NIP40 (most do). |
| **S2 — NIP26 delegation enforcement in nostrtransport** | Handler parses `delegation` tag, validates sig over conditions, checks conditions match the event, looks up operator pubkey in roster. Reject events without a valid delegation. | G3 (rest), G7 (partially) | 12 weeks | LNbits PR upstream (or vendored fork on `aiolabs/lnbits` branch `nostr-transport-nip26`). | | **S2 — NIP26 delegation enforcement in nostrtransport** | Handler parses `delegation` tag, validates sig over conditions, checks conditions match the event, looks up operator pubkey in roster. Reject events without a valid delegation. | G3 (rest), G7 (partially) | 12 weeks | LNbits PR upstream (or vendored fork on `aiolabs/lnbits` branch `nostr-transport-nip26`). |
| **S3 — NIP57style settlement receipts** | After LNbits internal payment legs complete, publish a signed receipt event per settlement (and per leg if we want leglevel audit). ATM subscribes; operator dashboard renders receipts sidebyside with `dca_settlements`. | G2, G7 | 12 weeks | Decide kind: `9735` (semantic abuse for nonzap) vs. our own kind in `21001`/`21002` range. | | **S3 — NIP57style settlement receipts** | After LNbits internal payment legs complete, publish a signed receipt event per settlement (and per leg if we want leglevel audit). ATM subscribes; operator dashboard renders receipts sidebyside with `dca_settlements`. | G2, G7 | 12 weeks | **Kind allocation — DO NOT USE `kind:21001`.** That kind is claimed by CLINK (Offers) — collision caught during the 20260602 CLINK primer review. Rotation off 21001 is tracked at `aiolabs/satmachineadmin#44`; target is the aiolabs reserved band **`2200022099`** per the workspace rule in `~/dev/CLAUDE.md` (§ "Nostr kind allocations — avoid the CLINK band"). The earlier 21001 lock across `aiolabs/lnbits#22`, `aiolabs/satmachineadmin#17`, and the satmachine ATM is **SUPERSEDED** — pick the new kind before any of those land. Reusing `kind:9735` (zap receipt) is also off the table: NIP57 semantics don't apply to bitSpire cashout settlements. |
| **S4 — NIP78 permachine config + fleet roster** | Operator publishes `kind:30078` config + `kind:30000` fleet list. Handler crosschecks ATM npub ∈ fleet; reads maxwithdraw/fee policy from config. | G1, G9 | 1 week | Define config schema; backwardscompat path for preNIP78 machines. | | **S4 — NIP78 permachine config + fleet roster** | Operator publishes `kind:30078` config + `kind:30000` fleet list. Handler crosschecks ATM npub ∈ fleet; reads maxwithdraw/fee policy from config. | G1, G9 | 1 week | Define config schema; backwardscompat path for preNIP78 machines. |
| **S5 — `sender_pubkey` persistence + signed metadata in Payment.extra** | When the dispatcher writes a Payment row, it stamps `Payment.extra.sender_pubkey`, `delegation_root`, and an HMAC over the key fields keyed by the LNbits server's own secret. Mutation postwrite breaks the HMAC. | G2 (DBside), G5, G6 | 35 days | LNbits PR — fairly localised. | | **S5 — `sender_pubkey` persistence + signed metadata in Payment.extra** | When the dispatcher writes a Payment row, it stamps `Payment.extra.sender_pubkey`, `delegation_root`, and an HMAC over the key fields keyed by the LNbits server's own secret. Mutation postwrite breaks the HMAC. | G2 (DBside), G5, G6 | 35 days | LNbits PR — fairly localised. |
| **S6 — Rate limiting + rostergated autoaccount** | Autoaccountfromnpub only fires if the npub appears in some operator's NIP78 fleet OR if an explicit "open enrollment" flag is set. Relay/handlerlevel rate limit per pubkey. | G8, G9 | 1 week | LNbits PR. | | **S6 — Rate limiting + rostergated autoaccount** | Autoaccountfromnpub only fires if the npub appears in some operator's NIP78 fleet OR if an explicit "open enrollment" flag is set. Relay/handlerlevel rate limit per pubkey. | G8, G9 | 1 week | LNbits PR. |