Learning Platformindex / ADRs / ADR-006E8

ADR-006 — Premium vetted community — payments, tiers & entitlements

Status: Proposed (design-panel synthesis) · Date: 2026-07-22 · Track: E8 (premium vetted community — Pillar 1 tier + admission) Method: adversarial design panel — estate-scout + four expert lenses (payments-security · compliance & legal · data · simplicity). Dissent preserved below.

Follows the ADR-001 template. Brand-free: processors/tools named by capability only. This ADR is the direct extension of ADR-001's I9/I10 into the billing dimension.


1. Context

The foundation spec (§2, §7) locks four tiers as a single attribute on the member record, read at every surface and at AI retrieval, re-implemented nowhere. E8 must make that attribute earn-able and pay-able: a payments processor to take fiat, an entitlements model that turns "who paid / who was admitted" into "what this member can reach on every surface," and a vetting/admission workflow (Guest→Member self-serve; Member→Inner-Circle vetted; Founding granted; grandfather the 60).

The estate-scout confirmed the load-bearing gap: there is no payment processor, no subscription lifecycle, no checkout, no webhook→entitlement sync, and no member/tier billing model anywhere in the estate. The fiat side is ~80% greenfield. What is reusable is a pattern, not code: the capability-gate's fail-closed, default-deny evaluate → (allowed, reason, audit-event) contract maps almost 1:1 onto a tier/feature entitlement check, and the agent-wallet's windowed-limit + kill-switch + immutable JSONL audit shape is a serviceable template for usage quotas and the entitlement-transition audit trail. Both are agent-facing or crypto-rail — the contract transfers, the code does not. So E8 is a genuine build, anchored on a payment integration the estate does not have, sitting on top of the tier-at-read substrate ADR-001 already decided.

2. Decision drivers

3. Options considered

4. The panel (rankings diverged; read the core argument, not the rank)

Lens Rank #1 Core argument
Payments-security (webhook integrity · PCI · chargeback abuse) C The decisive question is "is the payment system allowed to own entitlement, or only to emit signed events we turn into entitlement." Processor = signed event source only: verify signature → dedup on event-id → append immutable entitlement event → recompute tier. Hosted checkout keeps SAQ-A; dispute→revocation must be automatic; secrets in SOPS, signing-secret separate from API key.
Compliance & legal (GDPR/CCPA · ToS/liability · portability) A Clean liability split: processor owns payment PII/chargebacks under its DPA; we own tier + admission, so the liability story is ours by construction. Vetting data is "legitimate-interest" PII with a hard retention limit + Art.15/17 rights. Refund policy (T0→T1 window; T1→T2 rejection keeps T1) must be unambiguous pre-purchase. You cannot borrow your way out — pick the architecture, pay the compliance tax.
Data (Kleppmann) A The processor is the truth for money, never for access. Webhooks are at-least-once, out-of-order, lossy — a hint, not a command. Entitlement is a read-time function over the append-only admission/billing-event log + a rebuildable subscription-status projection, reconciled by a periodic pull (the load-bearing half). Out-of-order delivery ordered by per-member effective_at.
Simplicity (Torvalds) A The entitlements model already exists: object.tier_visibility ≤ member.tier, evaluated at read (I9). E8 adds zero entitlement code — just a webhook that writes the attribute. Ship one paid tier (Guest→Member); the 60 are a column write; vetting/admission machinery is built when the first Member asks to upgrade, shaped around a real applicant. Keep the 4-value enum (a cheap ordering), defer the machine.
Estate-scout The fiat side is confirmed greenfield (~80% new). Real reuse (~20%): the capability-gate's fail-closed evaluate → (allowed, reason, audit-event) contract as the entitlement check, and the wallet's windowed-limit/kill-switch + JSONL audit shape for quotas and the transition trail. Nothing ships as-is; no code copies cleanly.

(Note: the data lens numbered its ballot 1–4 as Option-1…4; mapped here A/C/B/D. It, compliance, and simplicity all rank A #1; payments-security ranks C #1. Both agree A≈C. Every lens ranks the vendor-owns-access options (B, D) last.)

5. The convergence (what all five agree on, under the different ranks)

Despite the C-vs-A split at the top, and B/D fighting for last, the lenses converge on one architecture:

  1. The processor is the source of truth for money, never for access. Payments-security ("signed event source only"), Kleppmann ("truth for money, not access"), Torvalds ("rent the checkout, never rent the answer to is this member allowed"), Compliance ("processor owns payment PII, we own tier") enter from four doors into the same room. A vendor holding the entitlement authority (B, D) is the ADR-001 fork+reskin failure with money attached — two permission systems that drift, a chargeback that leaves their record stale vs our tier attribute, a direct violation of I10.
  2. A≈C; the top-of-ballot split is cosmetic. A and C are the same architecture — the only difference is whether entitlement enforcement reuses the estate's fail-closed capability-gate contract (C) or restates it (A). The reuse is a contract, not Ruby code (the gate is in-process, config-static, agent-facing). So the decision adopts A's shape and C's contract.
  3. Webhooks are events, not commands. Signature-verified, replay-resistant (event-id dedup + timestamp window), idempotent, appended to an immutable entitlement log — then we recompute tier. A forged/replayed payment.succeeded must not mint free access; a missed chargeback must not leave a fraudster inside with retrieval access.
  4. Entitlement is derived and read-time; nothing caches "paid." A dispute/refund/lapse is a single attribute downgrade; tier-at-read (I9) de-provisions every surface and the AI filter at the next read. No tier claim outlives a chargeback in a token/session/feed/index chunk.
  5. Ship one paid tier first; the 4-tier machinery is data, not machinery. Because tier is one ordered attribute and entitlement is a read-time function, T2/T3 are new tier values + new event types (vetting-approval, grant, grandfather) dropped into the same log later — a repoint, not a rebuild. Grandfather the 60 as 60 grant events; never route the charter cohort through checkout.
  6. Rent the billing mechanics. Proration, dunning, tax, invoicing are the processor's native subscription primitives — own only the entitlement event + tier attribute.

6. Decision — "Own the entitlement · rent the rails · defer the machinery"

A hybrid that takes the winning move from each lens. Adopt A's shape with C's estate contract; ship one paid tier (Guest→Member self-serve) as the entire E8 v1.

6.1 Own (the moat — cheap now, catastrophic to retrofit)

6.2 Rent (the commodity — don't hand-roll, don't let it become the record)

6.3 Defer (Torvalds' cut — scoped, not killed)

7. Tradeoff matrix

Dimension A processor+own B bundled platform C processor+estate patterns D subscription/marketplace Decision (hybrid)
Tier stays sole permission authority (I10/I11) ❌ second system of record ❌ authority rented by construction
Processor = billing truth only, never access
No tier-leak on dispute/refund/lapse ✅ (at-read) ❌ drift on chargeback ❌ webhook-lag window
PCI stays SAQ-A ✅ (hosted) ⚠️ vendor-dependent ✅ (hosted) ✅ (marketplace) ✅ hosted checkout
GDPR / liability split clean ✅ (we own tier) ❌ vendor owns it ⚠️ marketplace is customer-of-record
Time-to-first-dollar ◑ integrate webhook ✅ fast ✅ fast ◑ (one webhook, one tier)
Ops-service count / small team ✅ (but forbidden) ❌ stateful billing service ✅ (defer machinery)
Rent proration/dunning/tax ⚠️ processor primitives ⚠️ processor primitives ✅ (processor-native)
Reversibility (swap = repoint) ✅ one function
Estate pattern reuse ◑ restated ✅ contract reused ✅ (contract, not code)

8. Consequences

New locked invariants (promote into the foundation spec §7, continuing I9/I10):

New required evals (the moat is only as trustworthy as these):

E8's first task is the processor→entitlement seam, not the admission machinery (Torvalds + Kleppmann): specify and build the idempotent webhook handler keyed on source_ref + the periodic reconciliation pull + the rebuildable subscription-status projection + the single subscription→tier function, for one paid tier (Guest→Member) — with the P0 entitlement tier-leak eval built before the first charge. Vetting/admission is a deferred bead ("design Inner-Circle admission when the first Member asks to upgrade"); the 60 are grant events.

Estate seams (what we actually reuse):

9. Preserved dissent (do not resolve away)

10. Follow-up (beads to file in Phase B under the E8 epic)

  1. Lock invariants I11 + I12 + I13 into the foundation spec §7.
  2. P0 entitlement tier-leak eval (fail-closed) — before the first real charge.
  3. P0 webhook signature + idempotency + ordering test as a required CI check; P1 reconciliation-drift eval with a stated leak-window durability parameter.
  4. Specify the processor→entitlement seam: idempotent webhook handler keyed on source_ref + periodic reconciliation pull + rebuildable subscription-status projection + single subscription→tier function.
  5. Ship Guest→Member self-serve (one paid tier) end-to-end; grandfather the 60 as grant events; never route Founding through checkout.
  6. Defer the Member→Inner-Circle admission machinery to a bead ("design when the first Member asks to upgrade"); reuse the fail-closed capability-gate entitlement contract at the surface boundary.
  7. Processor secrets in SOPS/age (API key + signing secret separate, per-env, least-privilege); processor DPA/SCC + refund/ToS/privacy policy covering vetting-data retention, tier-downgrade consequences, and GDPR/CCPA/PIPEDA rights.
  8. Annotate per-seam reversibility: entitlement authority / tier attribute = irreversible; processor, checkout, subscription-mechanics = repoint.

Panel transcript basis: estate-scout + payments-security / compliance-&-legal / Kleppmann (data) / Torvalds (simplicity) lenses, 2026-07-22. Follows the ADR-001 template; E8's entitlement model is the direct extension of I9/I10.