| index 1512984b7..d5ed3adbc 100644 |
| --- a/implementation/carloku-paid-launch/AGENT_HANDOFF.md |
| +++ b/implementation/carloku-paid-launch/AGENT_HANDOFF.md |
| @@ -1,93 +1,74 @@ |
| -# Agent pickup instructions — Carloku paid launch |
| +# Agent pickup instructions: Carloku paid launch |
| |
| -CURRENT GATE: local build, vet and `make test` GREEN after fixing the intermittent durability snapshot failure and sustained-drain fallback. Amadan CI passed on final durability commit `c0d60af8`. This remains a checkpoint of unfinished work. |
| +CURRENT GATE (2026-10-01): work in progress, pushed, not merged, not deployed. Billing is OFF. Live Stripe is read-only and was not touched in this run. No AWS or production change was made. Nothing here is launch-ready until a real purchase, webhook and metering are verified live. |
| |
| -This file is context and instructions for the next coding agent. The branch is a work-in-progress checkpoint, not a release candidate. Do not merge, deploy, enable billing, or infer that the overnight launch goal was achieved. |
| +Read `AGENTS.md`, the spec `docs/superpowers/specs/2026-09-07-carloku-pricing-plans-design.md`, `requirements-audit.json` (the 18 spec steps, none complete) and this file. `session.md` is the September investigation log; prefer this file where they disagree. `.claude/HANDOFF.md` and the Amadan branch handoff carry the short status. |
| |
| -## Objective and current boundary |
| +## What Paul asked for |
| |
| -Paul asked to get carloku.com paid pricing live by morning and asked whether Stripe Tax can handle tax. Yes for calculation and collection. The VAT/OSS registrations are active, and Paul approved Stripe's PaaS classification and the plan-specific codes below. He requires the complete metered model at launch; annual subscriptions with temporarily waived overages are not an acceptable launch scope. Object-storage overages count only transfer that AWS charges Team Tito for, so delivered-byte access logs alone are not billing authority. He then explicitly requested this branch handoff so another agent can pick up the work. |
| +Paid plans live with Stripe Tax and the complete metered model. No annual-only launch and no blanket waiver of overages. Object-storage overages count only transfer AWS charges Team Tito for; delivered-byte access logs are not billing authority; missing evidence holds billing. On 2026-09-30 he asked for an unattended overnight run with the pricing page and signup flow ready to review in the morning. |
| |
| -Billing remains OFF. Read-only live Stripe requests verified the account on 2026-09-21; no charges, catalog mutations, production infrastructure changes, or deployments were made. The platform changes are being checkpointed on `feat/carloku-paid-launch-20260916` at `https://amadan.net/carlos/platform`. Nothing is being merged to main. |
| +## Where everything is |
| |
| -Read `AGENTS.md` and `docs/superpowers/specs/2026-09-07-carloku-pricing-plans-design.md` before proceeding. `requirements-audit.json` inventories all 18 spec steps and deliberately marks the overall implementation incomplete. `session.md` is the chronological investigation/test log; prefer this handoff for current state where older log entries disagree. |
| +- Platform worktree: `/home/paulca/amadan.net/carlos/platform-paid-launch`, branch `feat/carloku-paid-launch-20260916`, origin `https://amadan.net/carlos/platform`. Pass `carlos/platform` and `-hub https://amadan.net` to the amadan CLI and `AMADAN_HOME=~/.amadan-agent`. |
| +- Site worktree: `/home/paulca/github.com/carlosframework/carloku-paid-pricing`, branch `feat/paid-pricing-20260916` (GitHub `carlosframework/carloku`). Pages live under `src/` (Eleventy layout). The pricing page is rendered from `copy-review/pricing/strings.json` by `copy-review/pricing/build.mjs`. |
| +- Infrastructure worktree: `/home/paulca/github.com/carlosframework/platform-infrastructure-store-logs` (`feat/carloku-store-logs-20260917`). It holds nothing new: the access-log design it was for is superseded. The old uncommitted `store-logs.tf` was lost with `/tmp`. |
| +- Run directory (brief, logs, screenshots, server pids): `/home/paulca/.local/share/carloku-paid-launch-20260930/`. |
| +- The old `/tmp/carloku-pricing-overnight-20260916` tree is gone. The copy approved on 2026-09-22 lived only there. No transcript or repository holds it. Do not claim it. |
| |
| -## Resume locations |
| +## Review surfaces (running on docs-t1; restart recipes below) |
| |
| -- Platform worktree: `/tmp/carloku-pricing-overnight-20260916/platform`. |
| -- Site worktree: `/tmp/carloku-pricing-overnight-20260916/site`, branch `feat/paid-pricing-20260916`, base `a71ce06`, no edits applied. |
| -- Infrastructure worktree: `/tmp/carloku-pricing-overnight-20260916/infrastructure`, branch `feat/carloku-store-logs-20260917`, base `1cb7bc9`; local-only `flagship/region-ie.tf` modification and new `flagship/store-logs.tf`. These are NOT included in this platform branch. |
| -- Scratch reports, task briefs, logs and review artifacts: `/tmp/carloku-pricing-overnight-20260916/`. |
| -- Original user checkout `/home/paulca/amadan.net/carlos/platform` has unrelated dirty `go.mod`, `.claude/`, `.gocache-tmp/`, and `pitch-ten-slides.txt`; do not overwrite or clean it. Its handoff concerns another task. |
| -- This repository's `origin` is Amadan itself. There is no `amadan` remote. Use `-hub https://amadan.net` with the Amadan CLI because the operator is logged into several hubs. Older GitHub/mirror passages in AGENTS are stale relative to the actual remote; preserve branch review and CI, never direct-push main. |
| +- Pricing page copy review: `http://docs-t1.tail5fd3ba.ts.net:38009`, fallback `http://100.119.180.57:38009`. 87 strings, hand-built preview. |
| +- Console billing page copy review: `http://docs-t1.tail5fd3ba.ts.net:36481`, fallback `http://100.119.180.57:36481`. 39 strings; the preview is ten page states rendered through the real handlers. |
| +- Interactive signup and billing demo: `http://100.119.180.57:41881`. Real console handlers and store in test mode. Keymail sign-in and Stripe checkout and portal are labelled simulations on the same host. It is not Stripe proof. |
| +- The tailnet name did not resolve from the box itself or from the supervising session; only the IP form was verified by request. Both review results land in `result.json` beside each `strings.json`. |
| +- Restart a review: `~/.claude/skills/copy-review/serve.sh <strings.json> 1440` with the sandbox off. Restart the demo: `CARLOS_BILLING_DEMO_ADDR=0.0.0.0:41881 CARLOS_BILLING_DEMO_ORIGIN=http://100.119.180.57:41881 CARLOS_BILLING_DEMO_STOP=<file> go test ./internal/console -run TestBillingFlowDemo -count=1 -timeout 15h`; create the stop file to end it. Re-render billing page states: `CARLOS_BILLING_PREVIEW_DIR=<dir> go test ./internal/console -run TestBillingPageRenderPreview`, then `copy-review/billing-page/bind.py <dir>`. |
| |
| -## Existing local implementation |
| +When a review is approved, apply each string byte for byte: the site by replacing `strings.json` text and re-running `build.mjs`; the console by editing `templates/billing.html` at the matching `<!-- id -->` comment and the constants in `billingpage_test.go`. Count occurrences of a string before replacing it (shared strings need their own review). |
| |
| -1. Plans and calculations: immutable integer-unit EUR plans, effective assignment history, customer-favour rounding and allowance allocation. Rates in the authoritative spec: Personal EUR24/year; Community EUR5/member/year; Business EUR50/member/year; team minimum10; monthly pooled inclusions. Country factor boundary assumptions still need review. Full-month paid history is required: partial first month, free-to-paid transitions, cancellation gaps and some house changes currently HOLD rather than guess. |
| -2. Stripe boundary: restricted-key client, pinned API version, mode/identity validation, sanitized failures, checkout intents with complete commercial snapshots, tax/location checks, safe portal configuration, signed webhook reconciliation and missed-webhook polling. The console now accepts one tax code per paid plan, verifies each Stripe Product against its plan's code and freezes the applicable code into overage calculations before any provider write. |
| -3. Entitlements and membership: live-only publication outbox and authority/revision checks; Personal member limit; team quantity event history. Runtime Free-tier enforcement and the quantity/proration worker are not implemented. |
| -4. Quantity history: append-only events with exact time/generation/owner/terms, including transient add/remove. SQL guards reject REPLACE, preprocessed inserts, invalid processing timestamps and missing outcome/reference. Processing audit cannot be rewritten. Clock rollback retains events and holds history. Reconciliation refreshes summaries; pending additions/history gaps block retirement and first monthly freeze. Bound authoritative checkout expiry and proven never-created checkout abandonment atomically audit their own events. Positive proration collection timing is still an explicit product/implementation decision; no worker silently collects or waives it. |
| -5. Invoice engine: frozen month, tax code, durable ownership lease and per-operation request journal; idempotent recovery before/after provider requests; bounded replay window; exact draft/lines/finalize/pay verification; auto-advance disabled; terminal payment failure and review holds. A month spanning plans with different tax codes holds before any provider write until line allocation is defined. Unfinished calculations frozen by an older binary without a tax code also hold, while terminal rows stay terminal. Every POST rechecks ownership, age, frozen identity and open reviews. It reloads after acquiring ownership to avoid acting on a stale pre-lease draft. SQLite writes reserve the writer before transaction reads where needed. These mocks do not prove a real verified all-meter purchase path. |
| -6. Metering: durable edge spool and evidence closure; ownership and lifecycle proofs; separate CPU interval attribution; cost model no longer prices ordinary edge HTTP requests as S3 writes and pools edge/store transfer once. Object access-log parser exists, including unknown classification, but the collector is absent. |
| -7. Replication ledger: real SDK per-attempt hooks, bounded recording, durable SQLite ledger, immutable owner/purpose binding, publication lineage, incomplete/late/crash evidence, Abandon cleanup and read-connection snapshots. Vendored Litestream passes client options through its real S3 clients; close-order fixes preserve final flush. The new vendor test fixture drains multipart request bodies to avoid TCP reset. |
| -8. NEWEST / least reviewed: host integration in `internal/host/durability.go`, `agent.go`, `movespass.go`, `internal/activator/backend_exec.go`, and `internal/lease/requestmeter_api.go`. Opens ledger before tenant clients; binds account/app/host/purpose with bounded waits; records acquire, replicate, restore, staged copy/delete, move mirror and checkpoint requests; independently publishes lifecycle evidence and closes after child shutdown. Host attestation stays FALSE. No automatic handoff-token replay. Unknown owners never default to ops. External Litestream processes and continuity across arbitrary old-binary restarts are still unproved. Do not enable the meter as complete merely because embedded hooks exist. |
| +## What exists on the branch |
| |
| -## Verification and review |
| +1. Plans and calculations, Stripe boundary, entitlements and membership, quantity history, invoice engine: as described in the September handoff (kept in git history at `aed42815`). Unchanged in this run. |
| +2. Console GET `/a/{sqid}/billing` (`billingpage.go`, `templates/billing.html`): current plan, owner-only chooser posting to the existing checkout door, `?country=` price preview computed from the plans terms, error and pending banners, portal button once a customer exists, read-only for members, byte-identical 404 for non-members, closed state when billing is off. `plans.Countries()` exposes the embedded country list. |
| +3. Durability ledger: the epoch read race is fixed (epoch and created-at are immutable after recover) with a `-race` regression. Every unmetered replication fallback now files an escape (`DurabilityLedger.Escaped`): the box-day is incomplete and the owner is excluded for the run. Attestation is still false everywhere in production. |
| +4. `internal/awsbilling`: Cost and Usage Report reader, newest-delivery selection, digests, charged S3 transfer classifier. |
| +5. `internal/objstore/ownership.go`: append-only bucket ownership ledger, opened at grant, closed at teardown. |
| +6. Statement folds: `console/durabilityfold.go` (`durability_writes_1k`, policy in `usage.BillableReplicationWrites`) and `console/storeegressfold.go` (`store_egress_gb`). `usage.MeterSource` now names a source for both meters. Month evidence pins ownership ledgers by their month projection and knows the durability box directory. |
| +7. Stripe provisioning plan `stripe-provisioning.md` and print-only `stripe-provision.sh` (verified never to invoke the CLI). |
| +8. Plans: `docs/superpowers/plans/2026-10-01-store-transfer-cur-collector.md` and `2026-10-01-durability-attestation-path.md`. |
| |
| -- The immutable `verification-0324` snapshot contains the completed quantity/invoice fixes, BEFORE the newest host integration. Source manifest SHA256: `1b25b52b64efa1621511fa8b8c079de13d0ec57f208bf67d6b708a02f890c569`. |
| -- That snapshot passed `go build ./...`, `make test` (nested launchctx, vet, formatting, all packages plus vendored Litestream S3), required JS pricing parity, and ALL invoice tests under `-race`. Log: `full-gate-snapshot0324-realtemp.txt`; invoice race36.415s. |
| -- Invoice two-store concurrency and deterministic stale-pre-lease regression passed `-race -count=20` (40.639s). Log: `invoice-lock-contention-root2.txt`. |
| -- Quantity/checkout/membership audit tests passed `-race` (49.015s), before the final invoice lock changes. Log: `quantity-complete-root-race.txt`. |
| -- New host ownership, locked-ledger timeout, shutdown/publication and actual fake-HTTP SDK List/Copy/Delete-to-ledger tests passed `-race` (1.551s). Log: `host-durability-sdk-root-race.txt`. |
| -- New activator meter selection plus existing staging-restore tests passed `-race` (1.032s). Log: `activator-metering-root-race.txt`. |
| -- The prior intermittent failure was real: a snapshot could read SQLite before a background failure drain, then read the latch after that drain cleared it. The fix retries when a committed drain crosses the read and checks the final latch state under the writer mutex, which spans commit and subtraction. A forced-interleaving regression, an arrival-during-read regression, a sustained-drain regression, and the original late-failure test passed repeated `-race` runs. The complete local gate (`go build ./...`, `go vet ./...`, `make test` with JS parity) passed on the final code on 2026-09-18. Amadan CI passed on the previous handoff commit `099586ea`, first fix commit `eea00ee`, first reviewed amendment `665bcb7`, and final durability commit `c0d60af8`. |
| -- Opus reviews found and verified three follow-up corrections: arriving failures do not cause retries; after eight crossed drains a ninth snapshot holds a dedicated drain lock so publication gets a stable view; the drainer waits without holding the ordinary recording lock. The ninth-read test proves `Start`/`Finish` still progress and a new failure is counted. Final Opus review found no deadlock or data loss in this diff. Low residual risk: `Close(ctx)` and `Seal` can wait on a fallback read without a context bound, and a long fallback delays drain persistence; this does not block ordinary recording. A reviewer also noted a pre-existing unsynchronized read of `l.state.epoch` in the snapshot; it has not been addressed here. |
| -- CURRENT tree passed all five cross-builds (Darwin arm64/amd64, Linux arm64, Windows amd64/arm64). Log: `handoff-cross.txt`. |
| -- Final whole-branch Fable review and production/authority Opus review remain outstanding. All three Claude agents stopped at the shared usage limit, which reports reset at05:50 Europe/Dublin on2026-09-17 (04:50UTC). No agents remain running. That reset time has now passed; availability has not been rechecked for this handoff. Relevant task briefs/reports are in scratch, especially `durability-host-integration-brief.txt`, `opus-durability-integration-design.txt`, `quantity-history-hardening-brief.txt` and the invoice reports. The older design's arbitrary five-minute late-callback slack is NOT accepted proof. |
| +## Why no overage can be invoiced yet, precisely |
| |
| -Use BOTH short real temp directories; the symlink `/tmp/j` and a long GOTMPDIR each broke test isolation/socket tests: |
| +The monthly freeze requires all five billed meters complete. Two cannot be, in production, today: |
| |
| -```sh |
| -export TMPDIR=/tmp/k GOTMPDIR=/tmp/k |
| -export GOCACHE=/home/paulca/.cache/carloku-pricing-overnight-20260916/gocache |
| -export GOFLAGS=-mod=mod GOPROXY=off CARLOS_REQUIRE_JS_PARITY=1 |
| -go build ./... |
| -make test |
| -``` |
| +- `store_egress_gb`: no Cost and Usage Report export exists, so the source is unconfigured. It needs the scoped infrastructure approval in the collector plan, a first real delivery, and ownership ledgers for the stores that already exist. |
| +- `durability_writes_1k`: no box attests, because the external `carlos-litestream` binary replicates unit-backed routes outside the ledger. The attestation plan gives the two ways out. Do not set the flag to pass a test. |
| |
| -`/tmp/k` is a task-owned real directory, mode0700. Do not replace it with a symlink. /tmp had approximately2.9GB free at the last check; cache is on the main disk. Never edit source while a test of that source is running; immutable checkpoint tests may run independently. |
| +## Still missing from the full requirements audit |
| |
| -## Stripe live account state (read-only, 2026-09-21) |
| +- Quantity and proration worker: nothing processes subscription-bound member additions, `billingstripe.UpdateQuantity` has no console caller, removals at renewal are not applied, and an account that adds a member holds its own monthly freeze forever. The collection policy is Paul's decision; the pricing review proposes "charged straight away, prorated". |
| +- Partial first month and free-to-paid months hold permanently (`plans.ErrAssignmentHistory` is quiet and files no review). Months spanning two tax codes hold with a review; per-line tax codes are not implemented. |
| +- House marker door and billing review resolution door: store functions only, no HTTP or CLI caller. |
| +- Free tier: no Free entitlement, no app cap, no storage refusal, no per-plan hibernation idle, no flush-only replication class, nothing at runtime reads entitlements. |
| +- Dormancy archive and warnings, recognised-revenue pool accounting at 15 percent, the books site: not started. |
| +- Statement rebuild door for a closed month: missing. |
| +- Move and checkpoint metering tests in `internal/host/movespass_test.go`: missing. |
| +- An operator verb to backfill bucket ownership for existing stores: missing. |
| |
| -- 1Password item `Carloku/Stripe Production Keys/Live Key` authenticated successfully against expected merchant `acct_1UD7LXI4Nrr6AEsO`: Ireland, EUR, charges and payouts enabled. |
| -- The key is a full `sk_live` provisioning key. Production console configuration deliberately requires an `rk_live` restricted key, which does not exist in the inspected item. Never put the full key into console runtime configuration. |
| -- The live account has zero active products, recurring prices, portal configurations and webhook endpoints. |
| -- Stripe legal entity is `Team Tito Limited`, business profile `Carloku`. Paul confirmed Team Tito is VAT and OSS registered. On 2026-09-21 the live account gained and read back two active registrations: Irish `standard` with `place_of_supply_scheme=standard` (`taxreg_1UI9NEI4Nrr6AEsOPpkwK80n`) and Irish `oss_union` (`taxreg_1UI9NQI4Nrr6AEsOrBwcY1rE`). Stable idempotency keys are recorded in `stripe-live-readiness.json`. |
| -- The account default remains generic tax code `txcd_10000000`; do not use it for Carloku. Paul approved Platform as a Service on 2026-09-21. Configure Personal and Community as `txcd_10102001` (PaaS, personal use) and Business as `txcd_10102000` (PaaS, business use). Stripe says the personal-use category fits products available to serious hobbyists; the business category is for products restricted to commercial enterprise use. |
| -- `stripe-live-readiness.json` records the exact required 12-price EUR catalog and the remaining mutation gates. The two Tax Registration objects are the only live Stripe mutations so far; no product, price, webhook, portal, customer, subscription or charge was created or changed. |
| -- Raw API responses were kept only in task-owned scratch with mode 0600. The temporary 1Password session token and raw response files were removed after the registration work. |
| +## Verification in this run |
| |
| -## Pending user/external inputs — do not repeatedly ask |
| +Recorded in the run directory's `logs/`. Targeted: BillingPage tests; usage Durability under `-race`; host and activator under `-race` outside the sandbox; awsbilling; objstore; the new fold and evidence tests, with a mutation check that the hold conditions are pinned. The full gate result and the Amadan CI result for the tip are in `.claude/HANDOFF.md`, which is rewritten at each checkpoint; do not trust a gate claim that is not there with a commit. |
| |
| -- Pricing copy review: http://docs-t1.tail5fd3ba.ts.net:37461 |
| -- Billing copy review: http://docs-t1.tail5fd3ba.ts.net:34185 |
| -- Postal/location copy review: http://docs-t1.tail5fd3ba.ts.net:46235 |
| -- Review data lives in `writing/{pricing-launch,billing-launch,billing-location}` in scratch. All three servers last responded HTTP200; no result.json was present. No pricing page or billing UI copy has been applied. Apply submitted source strings verbatim; use the writing/copy-review skills for new user-facing copy. |
| -- Object-store transfer contract is settled: count only transfer that AWS charges Team Tito for. AWS access logs show delivered bytes but cannot reliably identify every free-transfer case, so they are not sufficient billing authority by themselves. The collector needs billing-grade AWS evidence, durable customer attribution and a hold when that evidence is incomplete. |
| -- Launch scope is settled: the complete metered model is required. Do not launch annual subscriptions with overages waived or defer any meter as a post-launch follow-up. |
| +Environment that works on docs-t1: inside the sandbox `GOCACHE=$TMPDIR/gocache GOFLAGS='-mod=mod -buildvcs=false' GOPROXY=off`; socket-binding packages (host, activator, edge) and the full gate outside the sandbox with `TMPDIR=/tmp/k GOTMPDIR=/tmp/k` (a real, short, 0700 directory) and the default build cache. Without `-buildvcs=false` eight `TestControlPlane*` tests fail in a linked worktree with "error obtaining VCS status"; that is the worktree, not the code, and it reproduces on `aed42815`. |
| |
| -## Infrastructure and artifact cautions |
| +## Stripe and secrets |
| |
| -The separate infrastructure worktree prepares seven resources for private/versioned/SSE-S3 bucket `carloku-store-logs-271376211898-eu-west-1` and narrowly scoped delivery/host permissions. No source bucket logging was enabled, and no Terraform apply occurred. A refreshed targeted plan has exactly7 creates and0 updates/deletes. The full root plan also contains unrelated dangerous drift (DNS deletion, port25 removal, host user_data replacements/restarts, other-region IAM); NEVER apply it wholesale. Scoped production approval, retention/cost/activation design and ownership history are still required. Current bucket ownership/name/listing does not prove historical ownership. |
| +Merchant `acct_1UD7LXI4Nrr6AEsO`, Team Tito Limited, Ireland, EUR; Irish standard VAT and Union OSS registrations active; zero products, prices, portal configurations and webhook endpoints as of 2026-09-30. The Stripe CLI is logged in under project `carloku` for read-only live inspection; that credential and the 1Password `sk_live` are provisioning credentials, never the console runtime key, which must be `rk_live_`. Never print or read a secret into output. Raw Terraform plans from September contained an SES SMTP credential: never post or attach plan bodies. |
| |
| -A local generated full Terraform plan contained an existing unrelated SES SMTP credential and had broad file permissions. Scratch is now0700 and21 plan/JSON artifacts are0600. Do not print, commit, attach, or post those plan bodies. Access by other local users was not established and no credential rotation occurred. Paul was informed. Only unchanged upstream test-key fixtures matched the credential-pattern scan in the platform source. |
| +## Next actions, in order |
| |
| -A scratch SQLite experiment was also found replacing local root main.go. It was preserved outside the repo and restored byte-for-byte from the verified checkpoint/HEAD; no CLI change was intended or deployed. The succeeding full gate used the restored entry point. Other changed Go files were compared to the checkpoint and corresponded to known work. |
| - |
| -## Next agent actions |
| - |
| -1. Read Amadan CI for the final durability-fix commit and inspect the complete branch diff as WIP. The local gate is green, but that does not make the launch ready. |
| -2. Review host wiring: `bindingFailed` is set on unmetered fallbacks but currently only the permanently false attestation prevents billing. Finish per-route move/checkpoint tests and client inventory, source completeness folding, scoped external-client exclusion, crash/late-callback/restart proof, bounded ledger retention and real-disk latency measurement. Keep unattested usage unbillable until proved. |
| -3. Implement P5 collector with durable deduplication, immutable historical bucket ownership and AWS billing-grade classification so only transfer AWS charges Team Tito for reaches overage billing. Prepare exact scoped logging activation before seeking production approval. |
| -4. Complete partial-month billing, quantity/proration collection, operator review/house doors, Free enrollment/caps/idle/flush-only, dormancy warnings/archive and revenue-pool accounting required by the spec. Use the requirements audit rather than treating these as optional follow-ups. |
| -5. After copy approvals, provision and verify the Stripe catalog with the approved per-plan PaaS codes, run the real sandbox purchase/webhook/portal flow, obtain independent reviews, pass Amadan CI and release gates, then land/deploy through the required reviewed path and verify live behaviour. No main merge or deployment is part of this handoff. |
| +1. Apply approved copy from both reviews when `result.json` arrives. |
| +2. Get the independent whole-branch review (Astra via codex, brief committed beside the spec) and resolve findings. |
| +3. Scoped approvals: Cost and Usage Report export; Stripe catalog, portal, webhook and the `rk_live` key; then a test-mode rehearsal and a real purchase. |
| +4. Build the quantity and proration worker behind an explicit policy switch, the two operator doors, then Free-tier enforcement. |
| +5. Choose and build the attestation path. Until then replication writes hold every month. |