diff --git a/docs/architecture/14-api-contract/openapi.yaml b/docs/architecture/14-api-contract/openapi.yaml index 25b370b9..5d6007f3 100644 --- a/docs/architecture/14-api-contract/openapi.yaml +++ b/docs/architecture/14-api-contract/openapi.yaml @@ -1574,8 +1574,11 @@ components: Machine reason a run is paused; the client draws the phrase. **TWO values since the order-form minor (0.11.0), and the distinction is load-bearing because the remedies are OPPOSITE:** `credit_exhausted` — the ACCOUNT has no money, the remedy is to top up; - `run_limit_reached` — the account is fine and the RUN delivered everything that was ordered, - the remedy is to order more. Reading the second as the first sends a paying user to a + `run_limit_reached` — the account is fine and the RUN spent the order it was + sold, the remedy is to order more. ⚠ **The mechanism is the run's own ceiling, set flush + against its hold — NOT a proof that everything ordered was delivered:** an order whose + projection ran low reaches this state before the last chapter, and the honest reading is + "this run has spent what it was given", not "your order is complete". Reading the second as the first sends a paying user to a payment page they do not need. A client MUST tolerate an unknown one under a minor bump and MUST render a paused run whose @@ -1807,8 +1810,13 @@ components: `resume` clears nothing — nothing was withdrawn. ordered_chapters: type: integer - minimum: 1 + minimum: 0 description: | + ⚠ **`0` is legal and is not "nothing was ordered":** a re-pass buys no chapters, and an + order phrased in CHARACTERS spans no whole chapter — both report `0` here while being + perfectly ordinary runs. A client that treats this as at-least-one will reject valid + answers. + What this run was ORDERED to deliver, in chapters — a property of the RUN. Present so a reloaded screen can name what the user bought and read `progress` against it. @@ -2535,20 +2543,45 @@ components: run does not stop for it and uses the bank as it stands. Nothing on this surface marks a book as having been translated against an unsigned bank: what is observable is the bank itself — `BankPage.signed` against `BankPage.total`. - ceiling_chapters: + chapters: type: integer minimum: 1 description: | - Limit of THIS run, in chapters, within the bounds from - `GET /books/{bookId}/run-options`. + Order this many chapters, counted from the first not yet delivered. Bounds come from + `GET /books/{bookId}/run-options` (`order.chapters_left`, `order.affordable_chapters`). - Required for an ordinary run, and a run started without a declared limit would spend - past the boundary the user is entitled to set BEFORE it begins rather than learn about - after. `0` is not legal. + ⚠ **OPTIONAL, and its absence is not "no limit" — it is the order of the WHOLE BOOK**, + which is the ratified default. `0` is not legal: an order that buys nothing is not an + order. - ⚠ **Absent — and refused — when `re_pass` is true:** a re-pass does not buy chapters, so - a chapter limit would describe nothing. The two members are mutually exclusive, and a - request carrying both is `400`. + Mutually exclusive with `characters`; a request carrying both is `400`. + characters: + type: integer + minimum: 1 + description: | + Order by size instead of by chapters, for a book whose chapter boundaries this build + does not trust — `order.chapter_orders: false` says when that is the case. + + ⚠ **Such an order stops INSIDE a chapter**, so the run it starts reports + `delivered_chapters: null` rather than `0`: it closed no whole chapter, and `0` would + read as "nothing happened" when work was done and paid for. + + Mutually exclusive with `chapters`; a request carrying both is `400`. + ceiling_chapters: + deprecated: true + type: integer + description: | + ⛔ **RETIRED BY THE ORDER-FORM MINOR (0.11.0) AND REFUSED ON THE WAY IN — `400` with a + pointer to `/chapters`.** It is NOT silently reinterpreted: the old name said "limit" + when the figure is a PURCHASE, and a client that kept sending it would be buying + something it did not mean. + + ⚠ Named here only so a reader of a 0.10.0 client can find out what became of it. It is + not accepted, and it is not the same field as `chapters` — one bounded a run, the other + orders work. + + ⚠ **A re-pass (`re_pass: true`) carries NEITHER volume member:** it does not buy + chapters, so a volume would describe nothing. RunOptions: type: object