Make the contract describe the wire it announces: the order options, the money slider, the precision signal, the second pause reason and the retired ceiling schema
This commit is contained in:
parent
358a473a29
commit
75ae6f06ca
1 changed files with 168 additions and 21 deletions
|
|
@ -17,9 +17,11 @@ info:
|
|||
**Nothing about HOW a book is translated crosses this boundary** — no model names, no phase or
|
||||
stage names, no internal vocabularies, and no cost of any model, stage or call. ⚠ **Money the
|
||||
ACCOUNT owns is not in that set** (owner, 05.09): the balance, an order's ceiling and its hold are
|
||||
the user's own figures and WILL be shown as amounts — the fields land with the order-form minor, and
|
||||
until they do, `Usage` and `CeilingBounds` below still carry the retired rule (⚠ read them together
|
||||
with this paragraph, not instead of it). The earlier blanket «no money sums» was the owner's own
|
||||
the user's own figures and WILL be shown as amounts — ⚠ **ИСПР. 06.09: условие ИЗРАСХОДОВАНО.** Минор формы
|
||||
заказа ЗАЛАНДЕН (`0.11.0`), суммы на проводе: `balance_micro_usd`, `limit.{min,max}_micro_usd`,
|
||||
`estimate.{expected,hold}_micro_usd`. `Usage` ретированное правило по-прежнему НЕСЁТ и это верно
|
||||
(её провод не изменился); `CeilingBounds` — РЕТИРОВАНА целиком и больше не отдаётся ни одной
|
||||
операцией. The earlier blanket «no money sums» was the owner's own
|
||||
rule of 02.08 and he RETIRED it on 05.09; what stays banned is the structure of OUR spend. The projection is an allowlist: a field not
|
||||
named here never reaches the client. The rule binds the PROSE too — every description here is
|
||||
compiled into the generated client's source.
|
||||
|
|
@ -1569,11 +1571,17 @@ components:
|
|||
PausedReason:
|
||||
type: string
|
||||
description: |
|
||||
Machine reason a run is paused; the client draws the phrase. One value today. A client MUST
|
||||
tolerate an unknown one under a minor bump and MUST render a paused run whose reason is
|
||||
`null` — the ordinary answer when the service has no word for what stopped it — showing the
|
||||
neutral "halted, continuable" state.
|
||||
enum: [credit_exhausted]
|
||||
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
|
||||
payment page they do not need.
|
||||
|
||||
A client MUST tolerate an unknown one under a minor bump and MUST render a paused run whose
|
||||
reason is `null` — the ordinary answer when the service has no word for what stopped it —
|
||||
showing the neutral "halted, continuable" state.
|
||||
enum: [credit_exhausted, run_limit_reached]
|
||||
|
||||
AccountHaltReason:
|
||||
type: string
|
||||
|
|
@ -1616,6 +1624,8 @@ components:
|
|||
- chapter_count
|
||||
- chapters_done
|
||||
- character_count
|
||||
- character_count_exact
|
||||
- structure
|
||||
- added_at
|
||||
- note_count
|
||||
- shape_epoch
|
||||
|
|
@ -1679,8 +1689,34 @@ components:
|
|||
**The chosen cure is a PRECISION SIGNAL BESIDE the number, not a change to what `null`
|
||||
means** — `null` already says "still arriving", a live client renders it as `0`, and
|
||||
overloading it would break a reader that is deployed. The field lands with the
|
||||
order-form pack, which is the one that makes this number a PRICE; until it does, this
|
||||
description is the only place that says the number can be wrong.
|
||||
order-form pack, which is the one that makes this number a PRICE. ⚠ **ИСПР. 06.09: ПРИЕХАЛО
|
||||
ЛЕНДИНГОМ 0.11.0** — сигнал точности стоит рядом полем `character_count_exact`, и это
|
||||
описание больше не единственное место, где сказано, что число может быть неверным.
|
||||
character_count_exact:
|
||||
type: boolean
|
||||
description: |
|
||||
Whether `character_count` is the source's own characters (`true`) or a proxy this side
|
||||
could not decode — runes of an EPUB's ZIP container, or of a stream in an encoding the
|
||||
engine re-reads (`false`). ⚠ **Added by the order-form minor (0.11.0)**, because the
|
||||
same minor turns this number into a PRICE: selling by characters against an archive's
|
||||
byte count would charge for the container.
|
||||
|
||||
Beside the number, never inside it: `null` on `character_count` keeps its one meaning,
|
||||
"still arriving", and a deployed reader that renders `null` as `0` is not broken by this.
|
||||
structure:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: 'null'
|
||||
description: |
|
||||
Where this book's chapter boundaries came from, passed through from the engine's
|
||||
manifest; `null` while the book is still arriving. ⚠ **Added by the order-form minor
|
||||
(0.11.0)** so a client can tell an order in chapters from an order it must phrase in
|
||||
characters.
|
||||
|
||||
⚠ **An OPEN vocabulary that grows additively** — today `declared`, `detected`, `none`.
|
||||
A value this build does not know is read as "not recognised" and is never promoted into
|
||||
trust. A client MUST do the same: switch on the values it knows and treat the rest as
|
||||
"no usable structure", rather than compile an exhaustive list that a minor will outgrow.
|
||||
added_at: { type: string, format: date-time }
|
||||
note_count:
|
||||
type: integer
|
||||
|
|
@ -1769,12 +1805,32 @@ components:
|
|||
cleared by a `resume` that SUCCEEDS: continuing IS the withdrawal of the request, and a
|
||||
run that was asked to continue is no longer a run someone asked to stop. A refused
|
||||
`resume` clears nothing — nothing was withdrawn.
|
||||
ceiling_chapters:
|
||||
ordered_chapters:
|
||||
type: integer
|
||||
minimum: 1
|
||||
description: |
|
||||
The limit this run was started with, in CHAPTERS — a property of the RUN. Present so a
|
||||
reloaded screen can name the limit the user chose and read `progress.total` against it.
|
||||
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.
|
||||
|
||||
⚠ **Renamed from `ceiling_chapters` by the order-form minor (0.11.0).** The old name said
|
||||
"limit" when the figure is a PURCHASE: a ceiling is what a run may not exceed, an order is
|
||||
what it owes. The retired name is rejected on the way IN with a pointer to `/chapters`,
|
||||
never silently reinterpreted.
|
||||
delivered_chapters:
|
||||
oneOf:
|
||||
- type: integer
|
||||
minimum: 0
|
||||
- type: 'null'
|
||||
description: |
|
||||
Whole chapters this run has delivered, or `null` when the question does not apply —
|
||||
an order expressed in CHARACTERS stops inside a chapter and closes none, and `0` there
|
||||
would read as "nothing happened" when work was in fact done and paid for.
|
||||
term_consistency_funded:
|
||||
type: boolean
|
||||
description: |
|
||||
Whether THIS run's reservation carries the book-wide terminology pass. It is a flat bond
|
||||
on the book, not a per-chapter cost, so a small order can be short of it while a large
|
||||
one is not — and the screen must say so BEFORE the click, not after.
|
||||
progress: { $ref: '#/components/schemas/Progress' }
|
||||
paused_reason:
|
||||
oneOf:
|
||||
|
|
@ -2504,7 +2560,7 @@ components:
|
|||
|
||||
1. the `409` of `POST /books/{bookId}/runs` (`ceiling_unavailable`) — the only authority on
|
||||
whether THIS start may happen; every read below can be stale by the time it is used;
|
||||
2. `RunOptions.ceiling.max_chapters == 0` and `RunOptions.blocked` — whether a start is worth
|
||||
2. `RunOptions.order.verdict: covers_none` and `RunOptions.blocked` — whether a start is worth
|
||||
offering AT ALL right now, and what is holding it. This is what the start screen draws;
|
||||
3. `Run.paused_reason: credit_exhausted` — why a run that already ran stopped. History, not a
|
||||
gate: a new run may still be startable (see `resumeRun`);
|
||||
|
|
@ -2514,9 +2570,16 @@ components:
|
|||
|
||||
A client that read them in the opposite order would refuse to offer a run the server would
|
||||
have accepted.
|
||||
required: [ceiling, blocked]
|
||||
required: [order, balance_micro_usd, limit, blocked]
|
||||
properties:
|
||||
ceiling: { $ref: '#/components/schemas/CeilingBounds' }
|
||||
order: { $ref: '#/components/schemas/OrderOptions' }
|
||||
balance_micro_usd:
|
||||
type: integer
|
||||
minimum: 0
|
||||
description: |
|
||||
What the account can still spend, in micro-dollars. ⚠ A quantity, not arithmetic: a hold
|
||||
is a debit when taken, so this figure ALREADY excludes the holds open against it.
|
||||
limit: { $ref: '#/components/schemas/MoneyLimit' }
|
||||
blocked:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/Blocked'
|
||||
|
|
@ -2526,6 +2589,86 @@ components:
|
|||
an account's second book shows a shrunken scale with no way to learn that its own first
|
||||
book is the reason.
|
||||
|
||||
OrderOptions:
|
||||
type: object
|
||||
description: |
|
||||
What can be ordered on this book right now, and whether the balance covers it. ⚠ **Added by
|
||||
the order-form minor (0.11.0).**
|
||||
required: [chapters_left, affordable_chapters, verdict, chapter_orders, structure, source_chars, term_consistency_funded, estimate]
|
||||
properties:
|
||||
chapters_left:
|
||||
type: integer
|
||||
minimum: 0
|
||||
description: Chapters of this book not yet delivered.
|
||||
affordable_chapters:
|
||||
type: integer
|
||||
minimum: 0
|
||||
description: |
|
||||
How many of those the balance covers, already clamped to `chapters_left`. A client MUST
|
||||
NOT clamp it again.
|
||||
verdict:
|
||||
type: string
|
||||
enum: [covers_all, covers_part, covers_none]
|
||||
description: |
|
||||
The one-word answer the start screen draws BEFORE the click. Computed by the same
|
||||
arithmetic that admits the order, so the verdict and the click cannot disagree.
|
||||
chapter_orders:
|
||||
type: boolean
|
||||
description: |
|
||||
Whether an order may be phrased in CHAPTERS at all. `false` when this build does not
|
||||
trust the book's chapter boundaries — then the only partial order is in characters, and
|
||||
the screen must say so in words rather than offering a slider against a cut nobody made.
|
||||
structure:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: 'null'
|
||||
description: |
|
||||
Where the chapter boundaries came from, passed through from the engine's manifest.
|
||||
⚠ **An open vocabulary that GROWS additively** — today `declared`, `detected`, `none`.
|
||||
A value this build does not know is read as "not recognised" and never promoted into
|
||||
trust; a client MUST do the same rather than switch on an exhaustive list.
|
||||
source_chars:
|
||||
type: integer
|
||||
minimum: 0
|
||||
description: Characters of the source this order is priced against.
|
||||
term_consistency_funded:
|
||||
type: boolean
|
||||
description: |
|
||||
Whether the balance covers the book-wide terminology bond ON TOP of this order. A flat
|
||||
bond on the book, so a small order can fall short of it while a large one does not —
|
||||
and the degradation must be visible BEFORE the click.
|
||||
estimate: { $ref: '#/components/schemas/Estimate' }
|
||||
|
||||
Estimate:
|
||||
type: object
|
||||
description: What an order is expected to cost, and what will be reserved for it.
|
||||
required: [expected_micro_usd, hold_micro_usd]
|
||||
properties:
|
||||
expected_micro_usd:
|
||||
type: integer
|
||||
minimum: 0
|
||||
description: |
|
||||
The engine's a-priori projection for this order, in micro-dollars — derived from the
|
||||
text before a single call is made, not a running total.
|
||||
hold_micro_usd:
|
||||
type: integer
|
||||
minimum: 0
|
||||
description: |
|
||||
What is actually reserved: the expectation with headroom, plus the engine's largest
|
||||
INDIVISIBLE step so the last call of the order cannot be refused for want of room.
|
||||
|
||||
MoneyLimit:
|
||||
type: object
|
||||
description: |
|
||||
Bounds of the money slider. ⚠ **These two are NOT a range.** The minimum is the engine's
|
||||
indivisible step — the smallest order any run could move under — and it can exceed the
|
||||
maximum when the balance does not carry even one reservation. That is the honest shape of
|
||||
"nothing can be bought", and `order.verdict: covers_none` says it in a word.
|
||||
required: [min_micro_usd, max_micro_usd]
|
||||
properties:
|
||||
min_micro_usd: { type: integer, minimum: 0 }
|
||||
max_micro_usd: { type: integer, minimum: 0 }
|
||||
|
||||
Blocked:
|
||||
type: object
|
||||
description: |
|
||||
|
|
@ -2551,11 +2694,15 @@ components:
|
|||
Bounds of the run-limit scale, in CHAPTERS. The conversion to money lives on the platform and
|
||||
is not exposed here in any form.
|
||||
|
||||
⚠ **THIS PARAGRAPH IS THE RETIRED RULE, KEPT UNTIL ITS FIELDS LAND (05.09).** The owner retired
|
||||
the blanket «no money on screen» ban; an order now states its ceiling AS MONEY and the account
|
||||
shows a balance. The money fields arrive with the order-form pack — the schema is NOT moved
|
||||
ahead of the code, so what is written above still describes what this version serves. What is
|
||||
NOT retired and never was: the price of a model, the cost of a stage, the price of one call.
|
||||
⛔⛔ **RETIRED BY THE ORDER-FORM MINOR (0.11.0), 06.09 — THIS SCHEMA IS SERVED BY NOTHING.**
|
||||
`GET /books/{bookId}/run-options` no longer carries a `ceiling` member at all; its answer is
|
||||
`order` + `balance_micro_usd` + `limit` + `blocked` (see `RunOptions`). Everything above is
|
||||
kept as the history of the chapter-scale era and describes NO live wire.
|
||||
⚠ The paragraph that stood here until 06.09 said the opposite — «the schema is NOT moved ahead
|
||||
of the code, so what is written above still describes what this version serves». It was written
|
||||
expecting the canon never to lag the code; the landing did the reverse, and the sentence
|
||||
outlived its condition. What is NOT retired and never was: the price of a model, the cost of a
|
||||
stage, the price of one call.
|
||||
|
||||
`max_chapters` is what the account can still spend, ALREADY clamped to what is left of the
|
||||
book; a client MUST NOT clamp it again. ⚠ A quantity, not arithmetic: a hold is a debit when
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue