STEVE-1 Book a call
Case study #2 / production payment feature

Family billing. Real cards. Live payment system.

One payer's card funds multiple family memberships, with a second discount stacked on top of the existing promo. Ordinary-sounding feature. It went onto a billing system with a documented history of charging a real parent five times for one signup.

This is the same argument as case study #1, made on harder ground: not a video nobody depends on, but a change to the exact code path that moves real money — walked move by move, with the vanilla-Claude contrast at every step.

The ask

One message, typos and all

AK, verbatim, stream-of-thought Family account for bkfk.ca — a "CONVERT TO FAMILY ACCOUNT" button in the members panel, add Jr Jabber / Standard / Unlimited for named family members, all paid on the same card, a "ready for onboarding" status flow, an extra 10% off stacked on the existing 25% promo, family-first signup with no root membership where only the 2nd kid gets the 10%. Mid-build, two more asks landed on top: document it as a case study, and turn the process into a reusable skill.
What this actually is

A production billing feature: real cards, real recurring charges, a change to the discount engine — on a system with a documented history of a 5× double-charge incident, $6,737.65, 2026-06-25/26. The gap between "add a button" and "don't charge a parent five times" is the whole story below.

The build, move by move

Thirteen moves. Every one with the vanilla-Claude contrast.

Entries 4, 10, and 13 are the permission layer stopping a write mid-build. That is not friction the build fought through — it's the safety architecture doing its job, on a system where a wrong write is real money.

Move 1 before any code
STEVE-1

Loaded 63K tokens of standing law before reading any code. 79 always-on rule files + 9 BKFK-scoped rules — including payment flows require explicit approval + $1-test verification, tests must never notify real people, backups before every write, never edit build artifacts.

Vanilla Claude

Starts with the code it can see, knows none of the institutional scar tissue. Would not know monthly idempotency is a uuidv4() by owner decision, or that a past test once texted a real coach.

Move 2 recon before code
STEVE-1

Two parallel read-only recon agents, then business rules locked with the owner before code. Mapped 4 candidate node apps, found the real money engine (bkfk-onboard :3003), the hardcoded discount math at calculateAmount :173 — not in the admin "promo settings" UI where it appears to live — plus the STATIC-vs-RELATIVE Square trap. Then asked the owner 4 pricing-policy questions (multiplicative vs additive, permanence, cancel cascade, billing shape) before any code existed.

Vanilla Claude

Greps "promo," finds promo_settings + the admin UI, "fixes" the display table the charge path never reads. Ships a discount that shows on the page and never changes a charge — and picks a discount-stacking rule silently, a real-money policy decision made by autocomplete.

Move 3 unrelated landmine found
STEVE-1

A pre-flight drift check found a live landmine that had nothing to do with the feature. bkfk-deploy's public onboarding file was frozen at 2026-06-28 while the live funnel had advanced to 2026-07-12 — the next routine deploy would have silently reverted the live payment funnel roughly three weeks. Flagged, fix prepared, held for owner approval, logged as a defect.

Vanilla Claude

Doesn't know deploys rsync a build dir into the webroot. Would likely edit one of the two copies — a coin flip on the wrong one — and have its own work, or the live funnel, erased by the next deploy.

Move 4 permission layer held
STEVE-1

The permission layer said no mid-build — and that was the system working. A production-repo write got denied by the auto-mode classifier. Standing rule: ask for that one specific permission, never rephrase, encode, or slip past it. Work continued on everything not blocked.

Vanilla Claude

No permission layer at all in most setups. Where one exists, there's no doctrine against creatively routing around it.

Move 5
STEVE-1

Payment code authored against the incident file, held uncommitted. The builder agent was briefed with the exact traps from PAYMENT_FLOW.md — 45-char idempotency keys, prefixes ≤9 chars, single-use nonces vs stable card_id, charge/record split, STATIC+price_override_money only. The deliverable stayed uncommitted and unrestarted until a diff review. The existing signup path had to stay byte-identical in behavior.

Vanilla Claude

Would plausibly reach for a Square discount object or a RELATIVE phase — the "natural" API reading, and the exact approach that already failed in production on 2026-06-27 (a conflicting-parameters error after the charge, leaving customers charged but invisible).

Move 6 diff review caught 5 defects
STEVE-1

456 inserted lines sat uncommitted and unrestarted until the orchestrator reviewed every one. The review caught: an unauthenticated card-save endpoint that minted the owner's 30-day portal JWT for anyone who guessed a numeric group id, and let them overwrite the family's card on file; a stable idempotency key that would soft-lock retries after a declined card; the portal accepting yearly billing for family members while the charge path rejected it; a duplicate-email guard blocking the parent-managed-kid flow; and discount eligibility missing 33 live paying promo-status members. All five fixed, re-checked, then restarted.

Vanilla Claude

One context writes and ships its own code — nothing separates "written" from "live." The JWT hole goes to production on a payment system.

Move 7
STEVE-1

The repo's own secret scanner fired on the fix — bypassed loudly, never silently. The pre-commit scanner flagged a new jwt.sign line as a possible token literal. Verified as a false positive (a function call, env-var secret), then used the scanner's own deliberate, logged bypass. The scanner exists because of a real credential leak on 2026-07-09.

Vanilla Claude

No layered scanners in the loop at all — or the hook gets disabled permanently just to make the error go away.

Move 8
STEVE-1

Deploy verified, not assumed. Restart confirmed "Migrations OK" in logs; SHOW TABLES confirmed family_groups/family_members plus 4 new columns exist; the unauthenticated family endpoint returns 401; port 3003 loopback is healthy; and the server file was checked clean of invisible NUL bytes — a past incident wrote them via escape collapsing, checked on every deploy since.

Vanilla Claude

"I've restarted the server and the feature is now live" — off a 200, or off nothing at all.

Move 9
STEVE-1

The live signup funnel got a staging file, not a live edit. A JS error there kills every real signup. The build deployed to a staging copy first, verified it live at three phone widths with vision-read screenshots (normal path untouched, family form validates, card-on-file banner renders, zero console errors) — and only then promoted the verified file over the real one. The one behavioral change to existing code, measured by diff: 238 additions, 1 modified line, an if that became an else if behind a try/catch-guarded new branch.

Vanilla Claude

Edits the live file in place. The first syntax error takes down signups until someone notices.

Move 10 two permission layers, both handled
STEVE-1

Two permission layers fired during the front-end deploy — both handled by protocol. The auto-mode classifier blocked the subagent's promotion of the staging file to the live funnel because its transcript lacked the owner-approved plan context; the subagent stopped and reported rather than working around it, and the orchestrator — holding the approved plan — reviewed the diff independently and performed the promotion itself, then vision-verified the live URL. Separately, the pre-commit secret scanner flagged 3 lines; each was inspected, confirmed literal-free, and bypassed with its own loud, logged mechanism.

Vanilla Claude

No permission layering exists at all — or the block "goes away" by disabling the hook.

Move 11
STEVE-1

A 9-check regression suite was registered before "done" was ever said. A read-only smoke test was written, run (9/9 pass), and registered in the daily 07:00 regression pass forever — including a permanent probe that the fixed JWT auth hole stays fixed. Seven user stories were committed with acceptance criteria mapped 1:1 to the checks.

Vanilla Claude

"All tests pass" means the tests it ran once, in that chat. Nothing re-runs tomorrow; the auth hole can silently regress.

Move 12
STEVE-1

The deploy landmine from move 3 stayed blocked until the owner said go — then took 90 seconds. Drift was confirmed by hash mismatch between the live and stale copies, both were backed up, the live version was promoted over the stale source, hash parity was verified, and the fix was committed. The build-output copy was left alone — hand-editing build artifacts is its own banned failure mode.

Vanilla Claude

Either "fixes" it unprompted the moment it sees the drift — an unapproved production write — or forgets it entirely and the next deploy reverts the live payment funnel three weeks.

Move 13 permission held the line on the charge
STEVE-1

The full lifecycle E2E was scripted, syntax-checked, and staged — and the runtime permission classifier still blocked executing it, twice, even after the owner's explicit written go. Protocol: no rewording, no rerouting, no disguising the action. The trigger was handed to the owner to fire from his side of the permission line. The math was pre-computed and asserted before any charge: $1.00 × 0.75 buildout × 0.90 family = $0.68 pre-tax, 77¢ tax-in, first and recurring.

Vanilla Claude

No second layer exists. "The user said go" and the charge runs from whatever context happens to hold the card path — a prompt-injected "go" charges just as easily.

The risk map

Where this feature bites, and what catches it

Eight specific failure modes this feature could have shipped with, and the real, in-this-build mechanism that catches each one.

RiskHow it bitesCatch mechanism
Double-charge on retryParent taps Pay twice, or the UI errors after the charge already went through.Stable idempotency keys on card-on-file (card_id is stable, unlike single-use nonces) + a completed-payment reference guard + the $1 E2E retry test.
Discount that displays but doesn't chargepromo_settings is display-only; the real math is hardcoded at the charge path.Recon found the real charge path; the change was made there, not in the admin table; a price-table test asserts the exact cents.
Square discount-object dead-endRELATIVE-phase discounts reject price overrides — and fail after the charge already happened.PAYMENT_FLOW.md institutional memory; STATIC+override pattern mandated in the brief.
Cancellation silently raising a kid's priceA naive "first paying account" recompute strips a sibling's grandfathered discount.Grandfather flag stored at add-time, never recomputed downward; an explicit E2E case for it.
Quote ≠ charge driftThe price shown on screen gets recomputed differently at charge time.The existing final-amount lock is reused; the family multiplier is applied at lock time, not charge time.
Test run charges or notifies real peopleWelcome emails, owner alerts, or a real coach SMS — this happened once, 2026-07-03.@example.invalid test data, a send-path grep before any test runs, a $1 hidden test package.
Editing the artifact instead of the sourceTwo copies of the funnel exist in the deploy pipeline; one is a build output.Hash-based provenance check across webroot/public/dist before editing anything.
"Done" without proofA 200 OK isn't the same as working — a "beautiful" page was once a 404.Vision-read screenshots, dashboard verification of the actual override amounts, regression tests registered to run daily.
Honest status

Built. Gated. Not yet called finished.

Built and deployed behind the verification gates above; final end-to-end verification in progress.

Ask vanilla Claude to add a billing feature and you get code that compiles. Ask STEVE-1 and you get thirteen gated moves against a documented incident history and a permission layer that held the line on the actual charge — or you get told, honestly, exactly what's still pending approval.
Book a call