Story 2538: CREATE preflight authorization and page charge

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.

Why this exists

Drafting bills by the page, but a generation's page count is only an estimate until the rendition is durably complete. Without a consent boundary, a 10-page estimate could silently become a 40-page invoice. The preflight authorization IS that boundary: the customer's maximum exposure is frozen — pages, rate-card version, currency, unit price, maximum amount in micros — before any generation starts, and the final charge can never exceed it without renewed consent.

1. Preflight (billing.page_create_authorization + POST /app/billing/create-preflight)

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.

2. Final emission (record_create_charge)

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.

RuleEnforcement
CL-06: authorize 10, render 7 → bill 7actual pages bill under the frozen card; test-proven
CL-06: render 11 against 10 → rejecttyped create_authorization_exceeded; nothing written; renewed preflight required
CL-16: save v1 → nothing; generate 22-page v2 → one 22-page CREATEthe producer is the only door; per-rendition dedup index allows the v2 charge on the same artifact
Failed/retried generations never chargeonly the success call emits; authorization stays open for the successful retry
Idempotencyledger idempotency key = uuid5(authorization_id) — a redriven completion replays to the same event
ReversalStory-2539 record_page_reversal works unchanged on a create usage event

3. The one schema correction to Story-2539

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).

Content-free throughout: the authorization and the ledger rows carry only ids, counts, and money. No draft text, filename, prompt, or model name can enter either table.

Named product-seam gaps (recorded, not hidden)