Skip to content

M4 behavior contract: one diagnosis for settled money (PR4_PLAN.md) - #2063

Merged
stefan-burke merged 44 commits into
mainfrom
claude/plan-md-review-jarsho
Aug 10, 2026
Merged

M4 behavior contract: one diagnosis for settled money (PR4_PLAN.md)#2063
stefan-burke merged 44 commits into
mainfrom
claude/plan-md-review-jarsho

Conversation

@stefan-burke

@stefan-burke stefan-burke commented Aug 9, 2026

Copy link
Copy Markdown
Member

What this is

The behavior contract for milestone M4 ("One diagnosis for settled money — fail-closed cutovers only"), written per PR_WORKFLOW.md before any tests or implementation. This PR contains two documents and no code — the contract itself plus the matching PLAN.md sync (the M4 section, the M6 provider note, fault rows F6, F12, F13, and F53 gaining their M4 slices, and the new program-wide "Data laws" section). Approving it approves the contract; implementation starts only after that.

What the contract says

  • One judge. The pure outcomeOf (adapted from the great-fermi reference) becomes the only classifier of settled money on the current path. All three of today's judges are replaced and deleted in the same merges: the callback verdicts (classifySession), the refund attempt ordering (tryRefund / refundReferenceAtProvider), and the admin refresh-payment route's boolean mapping. This closes F51.
  • Refunds can no longer overlap, race, or exceed capture. Before any refund attempt, the money already returned plus the money still returning must fit inside the captured amount, or the attempt is refused before any provider call. A refund run reads and judges an attendee's complete reference set before moving any money — one park-shaped verdict refuses the whole attendee — and claims the set all-or-none by compare-and-set, minting anchor rows for row-less legacy references, which closes the legacy simultaneous-refund window with the same mechanism. A live fresh claim is exclusive: nothing else may grow the claimed set or advance its evidence mid-run, and the claim transaction re-checks the request budget against the exact rows it claims. Every claim carries an owner scope, so a payment callback can never resume a dead admin claim on a merged attendee's reference set — only an admin retry that re-claims and re-judges the complete set can.
  • Evidence-only, per provider, one remedy map. Square carries the order total separately from per-tender charges and judges each tender by its documented type. Stripe's pick widens to the charge's documented amount, currency, and amount_refunded. SumUp refund authority is the summed refund events PR3's sandbox contract proved, and a multi-child SumUp checkout routes through the same remedy map as Square. Every money decision reads each provider's complete declared observation — sibling tenders and children included, their refund evidence too, bounded everywhere by a named sibling-read cap (beyond it the observation parks for the owner rather than letting a provider-controlled list chase the request budget). Park-shaped conflicts evaluate before proceed-shaped ones, coherent parentage is a stated prerequisite of every automatic refund, and a booking whose charge carries partial-refund evidence parks for the operator's required choice.
  • No automatic money on incoherent or conflicted evidence, durably. The owner-review marker stores its conflict kind beside a committed summary of the observed evidence — judge-readable facts plus one-way identity codes, one copy serving the gates and the replay comparison alike. Recorded evidence only grows, each fact merging by its own ordering law, so a lagging provider view can never make the record forget a charge or overwrite a corrected fact; contradictory identity readings are recorded and gate money instead of silently picking a winner. Every marker carries a retirement rule — automatic where a write can prove the condition dissolved, plus an explicit recorded owner action — so no attendee's deletion is ever hostage to a later milestone. Every persist-then-refund path takes one staged lifecycle with a fresh/stale age gate, and a staged refund that outlives its redeliveries is finished by the admin refresh route. Schema impact: no new tables, exactly three new columns (evidence_index, the replay fingerprint; protected_state, the plain live-work mirror; payment_reference_index, a one-way reference index that stops two records of one payment racing two refunds), all shipped in the first PR slice.
  • The payment row is one state machine. Every consumer of a stored payment row — the callback, the admin refund routes, the scheduled cleanup including the orphan purge, and the operator actions that move or remove rows — follows the same six written laws, so no consumer can carry its own private idea of what a row means. A judgment uses only facts that were signed, stored, or proven: an old reference's provider is proven by a validated read (never guessed from today's configuration), an old charge is never checked against today's site currency, and a claim on an untagged reference holds no release rule until discovery binds the provider's declared capability. An attendee merge or delete waits while a refund is settling; a delete also waits on an unresolved owner review, because a parked payment's marker guards the retained buyer contact the manual-check promise relies on. And a PR that introduces a new row state ships every consumer of that state in the same PR.
  • Eight program-wide data laws. The rules this contract kept re-deriving are now stated once in PLAN.md's "Data laws" section — one authority per fact; facts carry provenance, never ambient; immutable identity; total state lifecycles with mirrored discriminants; decisions bound to complete, versioned evidence; no copies under weaker protection; providers as declared capability records; atomicity before compensation — with this contract as their first instantiation. Every future milestone contract starts from them, and a self-audit against them runs before each push.
  • Two standalone PR slices, hardest first: (A) the refund-overlap guard, the all-or-none claim with legacy anchor rows, provider discovery and tagging, the Square order-tender and SumUp checkout-child sweeps on the admin and refresh reads, the whole three-column state schema with the marker vocabulary, retirement rules, fence, prune gates, and merge/delete admissions, the admission pre-flight on both refund routes, and the shared owner-review recorder — admin/attempt side only (≈ 400–550 src), (B) the callback cutover including the whole rejection-arm cutover with its staged lifecycle and the committed-evidence replay identity (≈ 250–350 src). The total can run past the milestone target's top while each PR stays well under the 800-line per-PR cap; the overage buys review-found correctness, not scope creep.

Owner decisions (recorded in the document)

All five questions are answered and folded in: proceed-and-alert for multiple captures, the Stripe read widening (stated completely as amount + currency + amount_refunded), both new copy strings verbatim, the two-PR slicing, and owner review for every multi-charge observation.

Review state

Thirty-three bot review rounds (twenty-nine Codex, four CodeRabbit — about 190 threads) are absorbed; every finding was verified against the code first, then amended or declined with reasons, and every thread has a reply citing its fixing commit. A self-audit against the data laws also ran before the latest push — its seven findings (among them the staged row's key-boundary corner, the orphan-purge bypass, and cross-attendee duplicate references) were fixed in the same commit, before any bot raised them.

Evidence basis

Every claim in the current-production-evidence table was verified against 4879ae0d (file:line cited per row); the SumUp refund evidence is grounded in PR3's verified sandbox contract; the reference-module map covers the exact port list, what gets slimmed against already-merged modules, and what stays for M5.


Generated by Claude Code

Summary by CodeRabbit

  • Documentation
    • Defined unified payment outcome rules across callbacks, redirects, refunds, administrative actions, and payment refreshes.
    • Documented handling for multiple charges, partial or pending refunds, mismatched captures, free checkouts, and conflicting provider evidence.
    • Added provider-specific guidance for Square, Stripe, and SumUp, including refund references and tender detection.
    • Clarified atomic refund claims, uncertain-refund persistence, replay and concurrency behavior, security requirements, and owner-review outcomes.
    • Updated reconciliation guidance to track each charge's provider and expanded fault ownership for related payment issues.

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants