From 1375e6405d3a565eb55dc4893e6ad585ea4089e9 Mon Sep 17 00:00:00 2001 From: shum Date: Thu, 22 Oct 2026 02:40:09 +0000 Subject: [PATCH] plans: names overdue close skips funded invoices --- plans/names-codes/2026-10-21-store-api.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plans/names-codes/2026-10-21-store-api.md b/plans/names-codes/2026-10-21-store-api.md index 620b34692b..859c4a8bdb 100644 --- a/plans/names-codes/2026-10-21-store-api.md +++ b/plans/names-codes/2026-10-21-store-api.md @@ -50,7 +50,7 @@ The service serializes the requests that create or change an order: The database backs this with unique constraints: one live registration per commitment, one live registration per owner and label hash, one registration per reserved code. A registration is live while it can still lead to a registration of its name: `unpaid` with an open invoice, `queued`, `committed`, revealing or registering, `failed` (retry is allowed), and a paid `taken` order until it is moved or turned into a code. A `registered` order is not live, so the same wallet can order the name again after it lapses; a code order that ends `taken` is not live. `live` is a stored flag, and every transition that changes it does so in the same transaction. -**An overdue order is closed by the next order.** When a new order from the same wallet and name meets a live order whose open invoice has passed its expiry time (the poller may not have marked it yet), the new order closes it inside its own transaction, under the label hash's turn: the old invoice becomes `expired`, its registration loses `live`, and only then is the new order inserted. The provider's cancel of the old invoice is sent afterwards, best effort, as the poller would. Settlement queues a registration only while it is still live; a payment that arrives for a closed order is a late payment (it stays `unpaid`, the operator is alerted, and support refunds it), never a second live order. +**An overdue order is closed by the next order.** When a new order from the same wallet and name meets a live order whose open invoice has passed its expiry time with no money received (the poller may not have marked it yet; a funded invoice is never closed this way, as the sweep never expires one), the new order closes it inside its own transaction, under the label hash's turn: the old invoice becomes `expired`, its registration loses `live`, and only then is the new order inserted. The provider's cancel of the old invoice is sent afterwards, best effort, as the poller would. Settlement queues a registration only while it is still live; a payment that arrives for a closed order is a late payment (it stays `unpaid`, the operator is alerted, and support refunds it), never a second live order. ### Formats @@ -402,7 +402,7 @@ The long poll for a paid order. - Without `wait`, it answers at once. - With `wait`, it holds while the status is `wait`, the payment marks are `seenPaid` and `seenFull` (each compared only when sent), and the registration's `version` is `seenVersion` (when sent). It answers on any change, or unchanged after at most 30 seconds (the mock: 20). - An invoice that reads `paid` while its registration is `unpaid` (paid after it closed) is answered at once and never held: there is nothing more to wait for. Support refunds it. -- An open invoice past its expiry reads `expired`. +- An open invoice past its expiry with no money received reads `expired`; a funded one stays `open` until it settles. ### `GET /api/registration/:id?seenVersion=` @@ -576,7 +576,7 @@ Each line: the difference, the choice here, and what changes in the mock (`webap 29. **Link profiles.** Chosen: entities and previews carry `profile` (`ok`, `unread`, `unavailable`); a refused, `.onion` or unresolvable host, or any refused host of several, is `unavailable`, never `invalid_link`; separate search and preview fetch bounds. Mock: answer `profile: "ok"`, and `unavailable` for a fragment tag. Page: accept the link whatever `profile` says, and show the default icon unless `ok`. 30. **`/code` carries `codeLength`.** Chosen: in the body and the signed message, `409 code_length_changed` with the current value. Mock: in `takenCode`. Page: send it, and derive again on that answer. 31. **`unread` pacing.** Page: re-read without `seenVersion` after 5, 15, then every 30 seconds. -32. **Overdue orders.** Chosen: a new order from the same wallet and name closes an old order whose invoice is past its expiry time, in its own transaction; settlement queues only a live order; a payment for a closed order is a late payment. Mock: expire the old invoice in `createInvoice` and `registerWithCode` before the existing-order check, and settle only a live order. +32. **Overdue orders.** Chosen: a new order from the same wallet and name closes an old order whose invoice is past its expiry time with no money received, in its own transaction; settlement queues only a live order; a payment for a closed order is a late payment. Mock: expire the old unfunded invoice in `createInvoice` and `registerWithCode` before the existing-order check, and settle only a live order. 33. **`/code` repeats** answer the issued code whatever `codeLength` now. Mock: check the repeat first in `takenCode`. 34. **`linksRefused`** in the registration view, set when the reveal records a links refusal and cleared by a successful `/name`. Mock: in the view. Page: offer `/name` with corrected links from the view, not only from its own record. 35. **A held code on `/name`.** A code still reserved by its order is accepted on `/name` even if revoked or expired since, as on `/retry`. Mock: in `retarget`.