Note: the governing Story explicitly exempts walkthrough delivery (backend contract; the customer
walkthrough is owned by the app Billing & Usage Story). This file exists because the
pr-closes-check gate cannot read the pramaan-spec issue body to verify the exemption.
One immutable receipt per planned CREATE: estimated pages, frozen
rate_card_version, currency, unit_price_micros,
max_amount_micros (pages x unit price), the initiating user, and — for an explicit
Generate new version — the parent_rendition_version. A DB trigger blocks
DELETE forever and blocks every UPDATE except the one-time consumption stamp; a consumed receipt
is fully immutable. The route emits a typed page_create_authorization.created audit row.
Called by the deliverable-generation workflow exactly when a durable canonical rendition
succeeded — that call IS the billing signal. It emits ONE ledger charge
(verb=create) for the ACTUAL complete rendered page count through the Story-2539
allocate_and_record_usage money path (per-firm advisory lock, onboarding →
monthly → offline_purchase → overage, frozen pricing), then stamps the authorization consumed
with the usage event id, rendition version, completion receipt, and actual pages.
| Rule | Enforcement |
|---|---|
| CL-06: authorize 10, render 7 → bill 7 | actual pages bill under the frozen card; test-proven |
| CL-06: render 11 against 10 → reject | typed create_authorization_exceeded; nothing written; renewed preflight required |
| CL-16: save v1 → nothing; generate 22-page v2 → one 22-page CREATE | the producer is the only door; per-rendition dedup index allows the v2 charge on the same artifact |
| Failed/retried generations never charge | only the success call emits; authorization stays open for the successful retry |
| Idempotency | ledger idempotency key = uuid5(authorization_id) — a redriven completion replays to the same event |
| Reversal | Story-2539 record_page_reversal works unchanged on a create usage event |
The usage dedup index keyed every charge on (verb, original_receipt_id) — for CREATE
that is the artifact's document id, which repeats across versions, so a Generate-new-version could
never bill. Migration 0179 splits it: intake stays keyed on the physical receipt;
create keys on rendition_version (each explicitly generated version is
its own billable receipt).
record_create_charge is deliberately unwired (same doctrine as Story-2539's
intake producer awaiting Story-2508). Tests exercise the full money path against real
Postgres with fixture artifacts.resolve_firm_rate_card_id pins the latest
(IN, firm) launch card and is the single seam to replace when the firm billing profile lands.documents.documents + an opaque
rendition_version UUID until the versioned-artifact model ships.