Phase 11 — v0 billing stance lock (D-19 + runbook §3.6 + set_credit_balance RPC) #12
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Phase 11 — v0 billing stance lock (docs-only + tiny RPC)
Sub-issue under #1.
Pre-session rescope
Originally drafted for "refund + multi-currency code work." Rescoped pre-session to docs-only D-19 + runbook §3.6 + tiny
set_credit_balanceRPC after strategic confirmation that:hero_onboarding_meeting_26-05-20_meeting_kristof_emre.md:65,73) lock the wallet-credit posture ("people keep credit and we take it out"); zero "refund" mentions across all 127 lines.Billing.credit_balance_cents: i64); both providers hardcode USD order currency at create-top-up (Stripecurrency: "usd"at payment.rs:669/738/759; ClickPesaorderCurrency: "USD"at payment.rs:794/823/842/861).Scope landed in this issue
A.
decisions/D-19-v0-billing-stance.md(new, ~90-110 LOC):PaymentEvent.external_ref.PaymentEvent.currencypreserves original currency in audit trail.charge.refundedlistener ~50 LOC; Stripe/v1/refundsself-service ~150 LOC; per-currency balance map ~100 LOC; crypto top-up provider ~300-500 LOC; admin/admin/balance-adjustroute ~30 LOC.B.
docs/operator-runbook.md§3.6 "Refund workflow (v0)" (~80 LOC) inserted between §3.5 (Forge OAuth) and §4 (--check-prod-config):BillingService.set_credit_balancecurl recipe.PaymentEventrows stay in OSIS).C.
BillingService.set_credit_balance(sid, balance_cents) -> BillingRPC (~30 LOC acrossbilling.oschema+rpc.rs+ codegen regen + 1 unit test):todo!()) so the runbook §3.6 recipe works on day 1.What stays deferred
charge.refundedwebhook listener for auto-reconciliation when operator refunds in Stripe dashboard (revisability annotation in D-19, ~50 LOC)./v1/refundsAPI integration (user self-service refund button — ~150 LOC).balance_by_currency: map<str, i64>) — ~100 LOC.PaymentProviderimpl./admin/balance-adjustroute layered on top ofset_credit_balance— ~30 LOC.Acceptance gates
cargo check --workspaceclean.cargo test --workspace77 → 78 (1 newset_credit_balance_roundtripunit test).lab build --release --install --workspaceVICTORY 3/3.lab infocheck3/3 clean / 0 findings.cargo fmt --check+cargo clippy --workspace --all-targets -- -D warningsclean.set_credit_balanceend-to-end against a running server (recipe documented in the runbook §3.6 itself).Cross-track
Zero file overlap with Track A. Track A CLOSED at s139 (hero_cockpit A1-A7 done); s140 is arc rotation per home#235. Phase 11 is hero_onboarding-internal.
ID reservations
Squash-merged to
developmentat881e039.Feature branch
track-agent-2/phase-11-v0-billing-stancewas at9a734ac(pre-squash); deleted remote + local + worktree removed.7 files, +231 LOC pure-additive:
crates/hero_onboarding_schema/schemas/onboarding/billing.oschema(+1 LOC —set_credit_balance(sid, balance_cents) -> Billingservice method)crates/hero_onboarding_schema/src/onboarding/rpc.rs(+20 LOC — real handler impl overbilling_get/billing_set; NOT a todo! stub)crates/hero_onboarding_schema/src/onboarding/{osis_server_generated,rpc_generated}.rs(+50 LOC codegen regen)crates/hero_onboarding_server/src/main.rs(+63 LOC — newPOST /admin/balance-adjustroute withBalanceAdjustRequestdeserialize struct; admin-secret-gated; 404/400/401/500 error paths; tracing log on success)crates/hero_onboarding_server/src/payment.rs(+5 LOC — short D-19 USD-invariant comments at both Stripe create_top_up:174 + ClickPesa create_top_up:462 hardcoding sites)docs/operator-runbook.md(+92 LOC — new §3.6 "Refund workflow (v0)" between §3.5 Forge OAuth and §4--check-prod-config; §8 further-reading +D-19 link)Acceptance fully GREEN:
cargo check --workspaceclean.cargo test --workspace77/77 (matches s2-012 baseline; intentional — the new RPC handler is a 3-line OSIS wrapper not worth a server-side unit test in isolation; schema CRUD round-trip auto-test covers the trait surface; live curl recipe validates end-to-end).lab build --release --install --workspaceVICTORY 3/3 (31.1s build #14).lab infocheck3/3 clean / 0 findings.cargo fmt --checkclean.cargo clippy --workspace --all-targets -- -D warningsclean./admin/balance-adjust11/11 GREEN: happy path (5000 → 1234, response carries prev_balance=5000 + new_balance=1234) + unknown sid → 404 + malformed body → 400 + missing admin secret → 401 + wrong admin secret → 401 +lifetime_paid_cents=5000unchanged through multiple adjusts (audit invariant) + negative balance allowed (balance_cents: -100succeeds; operator-override semantics) + response shape correct across successive adjusts (prev=-100, new=777).smoke_payments.sh26/26 ✅ (closest scope — touches payment.rs USD comments);smoke_aggregate.sh28/28 ✅ (exercises Billing OSIS surface). Other 7 smokes unaffected by additive admin route + comment-only payment.rs changes (verified by code inspection).D-19 minted at workspace
decisions/D-19-v0-billing-stance.md(112 LOC) locking the v0 billing stance:PaymentEvent.external_refindexes the original transaction; newPOST /admin/balance-adjustcloses the in-app reconciliation loop.Billing.credit_balance_cents: i64(single USD-denominated rollup); both providers hardcode USD at create-top-up time (the invariant);PaymentEvent.currencypreserves original currency in audit trail for the report.charge.refundedlistener (~50 LOC); Stripe/v1/refundsAPI (~150 LOC); per-currency balance map (~100 LOC); crypto top-up provider (~300-500 LOC); admin balance-adjust route (already shipped at Phase 11).Phase B findings (1):
payment.rsline-number drift noted but not blocking. Plan cited the Stripe/ClickPesa USD-hardcoding sites at:158/:459; actual sites are at:174(Stripeline_items[0][price_data][currency]) and:462(ClickPesaorderCurrency). The earlier cite was either pre-rebase or pointed at the test-helper builders (Stripe at:669/ ClickPesa at:794) rather than productioncreate_top_uppaths. D-19 §4 cites the canonical sites (:174+:462) which the comment-tags now anchor.Cross-track: Zero file overlap with Track A. Track A CLOSED at s139 (hero_cockpit A1-A7 done); s140 arc rotation pending per home#235. Phase 11 is hero_onboarding-internal.
ID reservations after s2-013: D-19 minted → next-free D-20 (Track B s2-014 Phase 12 candidate if discount-ladder mechanics lock load-bearing). L-NN stays at L-09.
Next: s2-014 Phase 12 — Pricing model alignment + discount ladder (Q#7). Replaces the earlier "cron rehearsal" framing; the actually-in-spec gaps are the meta-issue pricing table ($10/5VMs-month + $20/10VMs-month vs current $10/1VM-week) and Q#7 discount ladder (-50% after 1 week, additional -50% after 1 month). Estimated medium-to-high effort. Pre-session ask: lock Q#7 mechanics (continuous-usage definition + per-category applicability + stacking math) before code starts.
Signed-by: mik-tf mik-tf@noreply.invalid