← SpecPRD-COMPANION.md

Raw decision log — no interpretation. Each entry below is referenced elsewhere in this portal as "D-N" (e.g. "D14") or "PRD-COMPANION D-N".

PRD Companion: Decisions Triggered by the External Proposal

Status: Draft Owner: TBD Related: PRD.md, BRD.md, ARCHITECTURE.md, BRD-OPEN-QUESTIONS.md Triggers:

  • "API-First Headless Subscription Engine – Requirements & Architecture" — external technical proposal, 20pp PDF. Sourced D1–D11.
  • "Subscriptions: Product Pack" — internal BC discovery artifact (Q1 2023), research + partner interviews + 74-merchant survey; strategic sections (vision, pricing, packaging, metrics) empty. Sourced D12–D16.

Purpose

The external proposal overlaps heavily with our internal specs on core primitives, but differs on several design choices that materially shape the domain model, API surface, and operational footprint. This document does not summarize either doc — it records the specific decisions we need to make where the two proposals diverge, with the tradeoff and a recommendation for each.

Each decision is tagged OPEN, PROPOSED, or DECIDED. Once decided, the change gets landed in PRD.md / BRD.md / ARCHITECTURE.md as appropriate and the entry stays here as the rationale record.

How to use

  • Scan the Decision summary table.
  • For any row marked OPEN, read the full section and either accept the recommendation, counter-propose, or defer with a reason.
  • When a decision lands, move it to DECIDED and cross-link the PR that updated the downstream spec.

Decision summary

ID Decision Area Impact Recommendation Status
D1 Add Entitlement as first-class domain object Domain model High — unblocks membership, seats, usage credits Adopt DECIDED (2026-04-23)
D2 Split DeliveryInstance from Charge/Invoice Domain model High — fixes annual-prepaid, build-a-box, bundle shipping Adopt DECIDED (2026-05-07; synthesis eb678099, ADR-0024)
D3 Publish declarative tenant_config policy schema Platform Medium — consolidates 10 merchant-configurable knobs Adopt OPEN
D4 Explicit REQUIRES_ACTION charge state + guest magic-link Payments High for EU — lifts dunning recovery Adopt (Phase 2) OPEN
D5 Lift payment_customer_ref to customer level Domain model Medium — one card update cascades Adopt DECIDED (2026-05-06; synthesis 7574bb48)
D6 Invoice as first-class entity vs BC-order-as-invoice Domain model High — foundational Keep ours (BC order is the artifact) PROPOSED — reaffirm
D7 Renewal engine: one durable workflow vs. granular scheduled_tasks Runtime High — observability vs. simplicity Keep workflow; add stage events OPEN
D8 Canonical event vocabulary published in spec API surface Medium — developer platform credibility Adopt OPEN
D9 Enterprise tenant isolation upgrade path (dedicated schema/DB) Multi-tenancy Medium — enterprise tier GTM Adopt (document only, no v1 code) OPEN
D10 Platform-agnostic commerce adapter abstraction Architecture High — would erode core thesis Reject PROPOSED — confirm
D11 Java modular monolith runtime Architecture High — incompatible with BigDesign stack Reject PROPOSED — confirm
D12 Ingest 74-merchant survey + partner quotes as primary-source grounding Research Low cost, high narrative strength Adopt OPEN
D13 Tax-at-component-level for bundle renewals Billing / Bundling Medium — blocks multi-tax-code bundles Adopt — phase TBD OPEN
D14 Position entitlement/membership as the ENT-tier growth wedge Positioning Medium — sharpens GTM, not schedule Adopt as positioning OPEN
D15 Legacy Checkout (LCO) compatibility posture Scope / TAM High — affects migration TAM Decision needed OPEN
D16 Address validation as a first-class onboarding concern Reliability Low-Medium — reduces renewal failures Adopt as adapter (Phase 2) OPEN
D17 BC-native MIT path: recurring subtype + NTI persistence + adapter contract Payments / Architecture High — locks in Path A primary; closes PRD §13 row 1 Adopt DECIDED (2026-05-06; synthesis 7574bb48)
D18 AllotmentGrant primitive distinct from Entitlement (D1) Domain model High — unblocks admin-granted recurring quota / wallet patterns Adopt DECIDED (2026-05-07; synthesis eb678099)
D19 Multi-actor role enum (owner / payer / beneficiary / manager / org_admin) Domain model High — gift, B2B managed, marketplace v2 seam Adopt DECIDED (2026-05-07; synthesis eb678099, ADR-0023)
D20 CustomFieldDefinition schema-typed extensibility Domain model Medium — replaces ad-hoc metadata JSONB sprawl Adopt DECIDED (2026-05-07; synthesis eb678099)
D21 NTI freshness policy — re-prime stored credential chain when NTI ages out Payments Medium — protects long-cycle (annual+) renewal success rate Adopt (Phase 2) DECIDED (2026-05-07; synthesis eb678099)
D22 Multi-phase capture timing — defer capture to shipment/fulfillment for physical-goods EU compliance Payments / Compliance High for EU — Phase 1 advisory; Phase 2 enforced via adapter split Adopt (Phase 1 advisory shipped; Phase 2 deferred-build) DECIDED (2026-05-15; synthesis b87f5678, ADR-0038)

D1 — Add Entitlement as a first-class domain object

<!-- traceability:start:D1 -->

Prototype: Gift · Prepaid · Build-a-Box · Membership · Bundle · Usage-Based · Curation · Referral

<!-- traceability:end:D1 -->

Current state (ours). PRD.md Section 8 core entities: Subscription, Plan, Charge, Event. Membership mentioned in BRD Epic 6 and the prototype/prototypes/advanced-subs/pages/Membership.tsx prototype, but no Entitlement object exists. Provisioning of digital access is implicit.

External proposal (Section 5.6). Entitlement { status: PENDING | ACTIVE | SUSPENDED | REVOKED } with a pluggable entitlement-provider adapter. Grants are event-driven off payment.succeeded; revocations off payment.failed + grace exhaustion.

Tradeoff. Without it, every "does this customer still have access?" question is answered by inferring from subscription.status + elapsed time, which is brittle when payment retries, SCA, grace periods, bundle co-entitlement, and B2B seat reassignment interact. Adding it now is ~1 table + 1 state machine + 1 adapter interface. Adding it later means re-homing implicit logic scattered across membership, bundling, and B2B.

Options.

  • A. Adopt as proposed — entitlements table, state machine, adapter interface.
  • B. Collapse into subscription.entitlement_state column. Cheaper; fails the moment one subscription grants multiple entitlements (common in bundles).
  • C. Defer and model per-feature. Cheapest now; highest long-term cost.

Recommendation. A. Add to PRD.md Section 8 core entities and BRD Epic 6. Provider adapter should be pluggable so SSO/license-server/feature-flag systems can plug in.

Decision (2026-04-23). Adopted Option A. Entitlement becomes a first-class domain object with the PENDING | ACTIVE | SUSPENDED | REVOKED state machine and a pluggable provider adapter. BC customer-group is the v1 provider; SSO, feature-flag, and license-server adapters are post-v1 extensions against the same interface. State transitions are event-driven: grants off payment.succeeded + subscription.activated, suspensions off payment.failed + grace exhaustion, revocations on subscription.cancelled + cancel-grace expiry.

Landed in: PRD Section 8 (entity added), BRD Epic 6 US-6.5 (acceptance criteria rewritten against state machine), ARCHITECTURE Section 3 (SoR row added — engine owns entitlement, adapter applies external effect), membership prototype wired to state-machine mock (2026-04-23).


D2 — Split DeliveryInstance from Charge/Invoice

<!-- traceability:start:D2 -->

Prototype: Inventory Check · Price Strategy · Tax Address · Shipping Quote · Delivery Schedule (cadence ≠ billing)

<!-- traceability:end:D2 -->

Current state (ours). PRD.md Section 9.4 and BRD Epic 10 collapse "charge succeeds → BC order created" into a single step. Annual prepaid is modeled as pre-computed charge schedule (PRD Section 6.2 gap table).

External proposal (Section 5.5, Section 6.3.14). DeliveryInstance is a separate object with its own lifecycle: PLANNED → ORDER_CREATED → FULFILLING → COMPLETED | FAILED. Annual prepaid = 1 charge, N projected deliveries materialized each period.

Tradeoff. Billing cadence ≠ delivery cadence is not a corner case — it's most of our advanced-subs roadmap:

  • Annual prepaid, monthly ship (BRD-OPEN-QUESTIONS Section 1.3)
  • Build-a-box where box contents change per delivery independent of billing
  • Bundle shipping allocation across co-subscribed items (Section 1.2)
  • Gift with scheduled first-delivery date offset from purchase

Keeping the current model forces these flows to encode delivery state inside the charge row or in side tables per feature. A dedicated table is ~1 schema change that cleans up 4 feature areas.

Options.

  • A. Adopt — add delivery_instances FK'd to subscription_id + cycle_key. Charge success → invoice record → N scheduled delivery instances.
  • B. Keep current model; add per-feature shims. Works short-term, explodes when a fifth feature needs it.
  • C. Model deliveries as BC orders directly (no engine-side table). Fails on "gift delayed 30 days past charge" because BC order doesn't exist yet.

Recommendation. A. Non-negotiable if D1 is adopted — entitlements (digital) and delivery instances (physical) are the dual shapes of "charge grants X."

Decision (2026-05-07; synthesis eb678099, ADR-0024). Adopted Option A. delivery_instances is a first-class table, lazily populated (next-N-instances-rolling-window default N=2; on-write materialization for subscriber-action targets beyond the window). Charge ↔ DeliveryInstance is n:1 (Cintas weekly-delivery / monthly-billing fan-out permitted). Per-instance overrides (ship-to address, line-items swap) live on the row, not in side tables. Status enum: pending | fulfilled | skipped | failed | rescheduled.

Landed in: PRD §8.1 (entity added), PRD §8.2 (storage table row), PRD §8.3 (BC order linking extension), ADR-0024 (full rationale + consequences), prototype prototype/prototypes/subscriber-portal/ (DeliveryScheduleCalendar, DeliveryInstanceDetail to follow per synthesis action items 14).

Downstream edits if accepted. PRD Section 8, Section 9.4; BRD Epics 6, 10, 16; ARCHITECTURE Section 2.4 (new entity in data model diagram).


D3 — Publish declarative tenant_config policy schema

Current state (ours). Merchant-configurable policies are scattered across BRD-OPEN-QUESTIONS Section 5 (10 defaults), PRD.md Section 9.3 (dunning), BRD Epic 11 (retry), BRD Epic 17 (grace periods), etc. No canonical document of what's configurable, with what shape, and what the defaults are.

External proposal (Section 6.3.15). Single tenant_config JSON document with nested keys for dunning, grace, fulfillment, notifications, sca. Named presets (Standard / Aggressive / Lenient) layered on merchant overrides.

Tradeoff. Low code cost (it's a JSONB column + JSON schema validation). High value for: (a) onboarding — merchants fill one form, not 10; (b) support — one config blob to inspect when diagnosing "why didn't this retry fire?"; (c) migration — Recharge/PayWhirl config import maps to one shape; (d) presets ship sensible defaults without per-merchant tuning.

Options.

  • A. Adopt the schema shape from external Section 6.3.15 directly.
  • B. Invent our own shape informed by our 10 BRD-OPEN-QUESTIONS Section 5 defaults.
  • C. Leave scattered; add a settings UI per area.

Recommendation. B. Adopt the pattern (one declarative JSON document with presets) but let the schema reflect our config surface, not theirs — theirs is missing entries for B2B approval policy, multi-storefront scope, migration-mode flags. Ship the 10 BRD-OPEN-QUESTIONS Section 5 items as tenant_config v1.

Downstream edits if accepted. New ARCHITECTURE Section 2.x section; BRD Epic 2 (settings) restructured around tenant_config; BRD-OPEN-QUESTIONS Section 5 closed as resolved by D3.


D4 — Explicit REQUIRES_ACTION charge state + guest magic-link

<!-- traceability:start:D4 -->

Prototype: Retry Policy · Dunning Queue · Subscription Timeline · Email Sequence · Login · Sessions · Multi-Account · Recovery · Headless Portal SDK

<!-- traceability:end:D4 -->

Current state (ours). BRD Epic 11 treats SCA/3DS as a failure category. Portal payment update requires login (BRD Epic 17). No payment_intent_ref on charge row.

External proposal (Section 6.3.7, Section 6.3.12). Charge state REQUIRES_ACTION with payment_intent_ref so a later session can resume the same intent. POST /v1/guest/sessions mints a short-lived magic-link session for payment updates without login.

Tradeoff. Two distinct capabilities bundled:

  • REQUIRES_ACTION + payment_intent_ref: required for EU SCA compliance in Phase 2. Not doing this means every 3DS challenge fails the charge and burns a retry slot.
  • Guest magic-link session: lifts dunning recovery materially. Login is the primary dunning drop-off cause, so removing the login step before a payment update should raise completion; the specific magnitude is a post-launch A/B [assumption], not sourced industry data. The direction — not a precise lift figure — is what carries the retry-economics argument.

Options.

  • A. Adopt both in Phase 2 (aligns with EU rollout).
  • B. Adopt REQUIRES_ACTION now; defer magic-link to Phase 3.
  • C. Defer both; rely on portal login for updates.

Recommendation. A. Ship together — they're both payment-update UX improvements touching overlapping code paths. Accept a Phase-2 scope rather than a Phase-1 rush.

Downstream edits if accepted. BRD Epic 11 (new AC for REQUIRES_ACTION), BRD Epic 17 (new story US-17.x for guest magic-link session), PRD Section 8 (charge state enum updated), ARCHITECTURE Section 4 (auth model addition for short-lived guest sessions).


D5 — Lift payment_customer_ref to customer level

<!-- traceability:start:D5 -->

Prototype: Payment Methods · Update Card · Address Book · Per-Sub Assignment · Update Billing Address

<!-- traceability:end:D5 -->

Status: DECIDED 2026-05-06 via synthesis 7574bb48-c8f0-4943-aed4-19ecb2e5584e (Issue #46). Combined with D17 in one Phase-1 schema migration. Source proposal 1357cbe1 (Issue #12). Schema landed in PR #62 (apps/api/migrations/0001_init.sql + apps/api/src/schema.sql). Downstream BRD Epic 19 US-19.X + subscriber-portal slice in task 2560b1b1.

Current state (ours). payment_method_ref is stored per-subscription (PRD Section 8). A customer with 3 subscriptions updates their card 3 times.

External proposal (Section 6.3.2 Type B, Section 6.3.12). customers.payment_customer_ref (gateway customer ID) at customer level, with per-subscription payment_method_ref for method selection. Card update at customer level cascades.

Tradeoff. Dual-level model matches how every major gateway (Stripe, Adyen, Braintree) actually works — they store Customer and PaymentMethod separately. Our current single-level model forces N-writes and N-webhook handling for a single card update. Code cost to migrate: ~1 table column + backfill + update-propagation logic. Doing this retroactively is painful because every existing subscription needs a customer-ref backfill.

Options.

  • A. Adopt now (Phase 1 schema).
  • B. Adopt in Phase 2 with migration script.
  • C. Keep single-level. Accept per-subscription card updates.

Recommendation. A. This is cheap in Phase 1 and expensive to retrofit. Every gateway adapter is already modeling it this way internally — we're just surfacing what's already there.

Downstream edits if accepted. PRD Section 8 (customer entity gets payment_customer_ref), ARCHITECTURE Section 3 (SoR table updated), BRD Epic 11 (payment update flow rewritten customer-first).


D6 — Invoice as first-class entity vs BC-order-as-invoice (reaffirm)

Current state (ours). PRD Section 16.1 explicitly rejects emitting a separate Invoice artifact — the BC order is the financial record of truth. Charge is the engine's internal artifact; the BC order carries line items, taxes, totals for the merchant and customer.

External proposal (Section 5.3). Immutable Invoice { status: DRAFT | OPEN | PAID | FAILED | VOID } as a first-class entity alongside the order.

Tradeoff. Theirs is cleaner for SaaS-pure use cases (entitlement-only, no fulfillment) and auditor-friendly because there's one canonical "bill" object. Ours avoids the "two artifacts per transaction" confusion for commerce merchants — the BC order is what finance/accounting/support already works with. For physical-goods merchants, introducing a parallel Invoice object doubles the accounting surface.

Decision. Keep the BC-order-as-invoice model. This is a deliberate positioning choice, not a gap.

Note. When D1 (Entitlement) lands, pure-digital subscriptions may need a lightweight "statement" representation for customers who don't have an order fulfillment record. Track as future open question — not a reason to flip D6.

Status. PROPOSED — confirm. Reaffirms PRD Section 16.1.


D7 — Renewal engine: one durable workflow vs. granular scheduled_tasks

<!-- traceability:start:D7 -->

Prototype: Charge Pipeline · Workflow Trace · Anchor Schedule · Pause Simulator

<!-- traceability:end:D7 -->

Current state (ours). PRD Section 9.3 + ARCHITECTURE Section 12: one durable workflow per charge (Vercel Workflow / Cloudflare DO / Cloud Workflows) runs inventory check → tax calc → shipping quote → charge → order creation as one orchestrated unit.

External proposal (Section 6.3.15). Task queue with granular task types: PAYMENT_RETRY, CREATE_DELIVERY, CREATE_ORDER, ENTITLEMENT_GRANT. Each task is independently scheduled, retried, and observed. scheduled_tasks.payload carries per-stage state.

Tradeoff.

  • Ours (durable workflow): atomic reasoning, simple happy-path code, all stages in one execution trace. Weakness: replaying from the middle of a failed workflow is harder; observability is per-workflow not per-stage.
  • Theirs (granular tasks): each stage is independently observable, replayable, re-orderable. Weakness: coordinating state across tasks is manual; a tax rate change mid-renewal can produce inconsistent state across tasks.

Our durable workflow primitive is genuinely good at this — we're not choosing between "bad monolith" and "good microservice." We're choosing between two valid models.

Options.

  • A. Keep durable workflow; add stage-level events emitted within the workflow so observability matches their task-level granularity without decomposing the engine.
  • B. Switch to granular tasks. Significant rewrite.
  • C. Hybrid — durable workflow for renewal; granular tasks for retry/entitlement provisioning (already partially split).

Recommendation. A. Our workflow is already atomic; adding charge.stage.inventory_checked, charge.stage.payment_attempted, charge.stage.order_created events gives us the observability win without the coordination cost. Document this stance in ARCHITECTURE Section 12 so future review cycles don't relitigate.

Downstream edits if accepted. ARCHITECTURE Section 12 (add stage-events subsection), BRD Epic 27 (publish stage events in event vocabulary).


D8 — Canonical event vocabulary published in spec

<!-- traceability:start:D8 -->

Prototype: Webhooks · API Reference · Credentials · Delivery Log

<!-- traceability:end:D8 -->

Current state (ours). Events exist as an append-only table (ARCHITECTURE Section 2.5) and BRD Epic 27 covers a developer platform, but there is no published canonical event list (names, shapes, semantics, at-least-once vs. exactly-once guarantees).

External proposal (Section 6.3.8, Section 6.3.12). Named event vocabulary: payment.succeeded, payment.failed, payment.action_required, entitlement.suspended, fulfillment.on_hold, etc. Published contract for each.

Tradeoff. Developer-platform credibility depends on this. Integrators building on a subscription engine need a contract that doesn't change shape between releases. Cost is low (a naming + schema exercise, not code). Not doing this means every integrator builds against implicit shapes and breaks on our minor releases.

Options.

  • A. Adopt — publish a canonical event list in ARCHITECTURE Section x with per-event JSON schema and delivery semantics.
  • B. Publish names only; leave schemas implicit.
  • C. Defer to post-GA.

Recommendation. A. Pairs naturally with D7 stage events. Ship the initial vocabulary alongside the developer platform milestone in BRD Epic 27.

Downstream edits if accepted. New ARCHITECTURE Section x "Event vocabulary"; BRD Epic 27 new story US-27.x "canonical event schema."


D9 — Enterprise tenant isolation upgrade path

Current state (ours). ARCHITECTURE Section 2.3 documents multi-tenant row-level security on store_hash. No documented upgrade path for enterprise merchants who demand dedicated-schema or dedicated-DB isolation.

External proposal (Section 4.2, Section 4.4). Shared DB with RLS is the default; large tenants can be migrated to dedicated schema or dedicated DB without API changes.

Tradeoff. Enterprise procurement processes frequently require "your data is not in the same database as another customer's data." Without a documented path, we either lose deals or negotiate custom carve-outs that get messy. Documenting the path now (even if we don't build it in v1) is a procurement enabler.

Options.

  • A. Document the upgrade path in ARCHITECTURE Section 2.3; defer implementation until first enterprise deal demands it.
  • B. Build it now. Premature.
  • C. Leave undocumented. Loses enterprise deals.

Recommendation. A. Document-only. One architecture section, no v1 code.

Downstream edits if accepted. ARCHITECTURE Section 2.3 addendum.


D10 — Platform-agnostic commerce adapter abstraction (reject)

External proposal (Section 3.1, Section 4.3). Pluggable commerce adapter — BC is one of many supported platforms (Shopify, WooCommerce, custom).

Why reject. Our thesis in PRD Section 3 is BC-native as the competitive moat. Deep BC integration (App Extensions, Price Lists, Customer Groups, Multi-Storefront, B2B Edition, Stencil widgets, cart custom-fields, order metafields) is what lets us beat generic subscription tools on the BigCommerce marketplace. Abstracting BC into one of N adapters would dilute every integration point down to the lowest common denominator.

Note. If we ever need to support non-BC platforms, it will be a separate product line, not a shared abstraction in this engine.

Status. PROPOSED — confirm rejection.


D11 — Java modular monolith runtime (reject)

External proposal (Section 2.2). Java, modular monolith evolving to microservices.

Why reject. BigDesign is React 18 + styled-components 5 — the frontend stack is fixed. ARCHITECTURE Section 2.2 pins backend to TypeScript to share types with the UI and reduce context-switch cost. Vercel Workflow as the durable runtime is a first-class TypeScript primitive. Switching to Java would sacrifice type-sharing, double our stack, and give up the Vercel/Cloudflare/GCP serverless surface we've priced in ARCHITECTURE Sections 5–10.

Status. PROPOSED — confirm rejection.



Decisions from the Subscriptions Product Pack (BC internal, Q1 2023)

The Product Pack is a discovery artifact, not a competing proposal — its strategic half (Section 4 vision/pricing/packaging, Section 5 metrics, Section 6 next steps) is empty. Its value is primary-source research: 74-merchant survey, SE rankings by tier, and direct app-partner quotes. Nothing in it contradicts D1–D11; it adds five previously-uncaptured concerns (D12–D16).

D12 — Ingest 74-merchant survey + partner-interview quotes as primary-source grounding

Current state (ours). PRD Section 2 and BRD Epic 1 describe the app-partner fragmentation problem (Recharge, Bold, Sticky.io, MiniBC, Rebillia, Ordergroove, Chargify) in inferred / analyst terms. No cited merchant survey, no named partner friction sources.

Product Pack evidence (Section 3.2.3, p.34). 74-merchant survey. Quality score 3.2/5 across all tiers; 10% of merchants report zero issues; Checkout and Shopper Management dominate pain stages. Partner-attributed friction (pp.25–32): Recharge's stated reasons for bypassing BC checkout (vault gaps, missing PM-change webhook — feature request PROJECT-4237); Chargify/Rebillia/Bold/MiniBC/Sticky.io each with specific quoted limitations. SE-ranked best/worst matrix by tier (pp.29–31).

Tradeoff. Zero code cost. Strengthens narrative in PRD Section 2, BRD Epic 1, and any sales/exec collateral derived from them — moves claims from inferred to evidenced. The one caution: the data is Q1 2023 and predates BC Payments (March 2026), so quotes need to be framed as historical friction rather than current state. Several specific quotes (vault gaps, PM-change webhooks) may already be resolved by BC Payments.

Options.

  • A. Adopt — cite survey + partner quotes in PRD Sections 2.1–2.2. Frame as "BC's own Q1 2023 discovery confirmed…" to time-bound it.
  • B. Adopt selectively — only cite quotes that remain current post-BC-Payments.
  • C. Don't cite; keep the inferred framing.

Recommendation. B. Audit the partner quotes against BC Payments' March 2026 capabilities before citing; drop any that the platform has since fixed. Keep the survey quality-score data point (3.2/5) — platform-level pain doesn't age out in 3 years.

Downstream edits if accepted. PRD Sections 2.1–2.2 (cite evidence); BRD Epic 1 (add research references). No schema or API changes.


D13 — Tax-at-component-level for bundle renewals

<!-- traceability:start:D13 -->

Prototype: Subscriber Opt-in · Merchant View · Shipping Split · Failure Handling

<!-- traceability:end:D13 -->

Current state (ours). BRD Epic 16 (bundling) and BRD-OPEN-QUESTIONS Sections 1.2–1.3 cover bundle price allocation and prepaid schedules, but do not address tax calculation per component. Implicit assumption is that BC's tax service handles bundles correctly at renewal.

Product Pack evidence (Section 3.2.3, p.31). ATX merchant feedback: BC pick-lists tax only at the parent SKU level; variants/components are not individually taxed. Breaks bundles where components carry different tax codes (e.g., food + apparel, or taxable + zero-rated items).

Tradeoff. This is a correctness issue, not a feature gap. A bundle with mixed tax codes renewing through our engine with incorrect tax = potential merchant tax-liability exposure. Detection path: our renewal-recalc flow already calls the BC tax service; we need to verify it calls per-component, not per-parent-SKU. If BC tax service itself only taxes at parent SKU, we need either (a) merchant-side mitigation (require tax-homogeneous bundles), or (b) engine-side per-component tax call with our own aggregation, or (c) escalate to BC tax service team.

Options.

  • A. MVP requirement — engine must call tax service per bundle component on renewal; reject bundles with mixed tax codes until BC tax service supports per-component.
  • B. Phase 2 — ship MVP with documented limitation (bundles must be tax-homogeneous), add per-component in Phase 2.
  • C. Defer indefinitely — push to BC tax service team.

Recommendation. B. Ship MVP with a BRD constraint ("bundles must contain components with identical tax codes") and a BRD-OPEN-QUESTIONS entry to validate behavior against current BC tax service in Phase 1 discovery. If BC tax service already handles this, D13 collapses to a test case, not a feature.

Downstream edits if accepted. BRD Epic 16 new AC; BRD-OPEN-QUESTIONS new row under Section 1 (verify BC tax service per-component behavior); PRD Section 9.3 renewal-recalc tax step updated.


D14 — Position entitlement/membership as the ENT-tier growth wedge

Current state (ours). D1 justifies Entitlement on domain-model grounds — membership implies it, bundles need it, B2B seats need it. PRD Section 3 positioning pillars are BC-native, unified processor rail, and merchant-first UX. Membership is a feature, not a positioning pillar.

Product Pack evidence (Section 3.2, p.39). Membership/access use cases were mentioned only by Enterprise merchants in BC's research (Career Step, St John Ambulance, Fitness First/Debit Success). SMB/mid-market merchants surveyed did not raise it. Implicit thesis: entitlement/membership is the ENT-tier wedge.

Tradeoff. D1 already commits to Entitlement as a domain object, so no additional engineering cost. D14 is purely a positioning/sequencing overlay: do we explicitly call out membership/access as the ENT differentiator in PRD Section 3 (4th pillar), or leave it as one capability among many? Calling it out sharpens the ENT sales narrative and gives the roadmap an explicit "membership depth" lane in Phase 3. Not calling it out keeps positioning simpler for mid-market, where it isn't a draw.

Options.

  • A. Add a 4th positioning pillar to PRD Section 3 — "Enterprise-grade entitlement for membership/access." Call out explicitly in Phase 3 roadmap.
  • B. Keep positioning as-is; mention membership in ENT-tier sales collateral only. D1 still delivers the capability.
  • C. Promote membership earlier in roadmap if ENT pipeline signals demand.

Recommendation. A, with Option C as a roadmap-sensitive follow-up. Four pillars is fine. Cost is a PRD edit; upside is a clearer ENT story that differentiates us from Recharge-shaped competitors.

Downstream edits if accepted. PRD Section 3 (add pillar); PRD Section 12 Phase 3 (sequence membership depth explicitly); ARCHITECTURE Section 3 unchanged (D1 already covers).


D15 — Legacy Checkout (LCO) compatibility posture

<!-- traceability:start:D15 -->

Prototype: Source Select · Field Mapping · PM Matching · Dry Run

<!-- traceability:end:D15 -->

Current state (ours). PRD Section 6.4 and our cart-custom-field capture approach assume Optimized One-Page Checkout (OPC). LCO support is not addressed. BRD and ARCHITECTURE are silent on LCO.

Product Pack evidence (p.2). BC cannot deprecate LCO because Rebillia is built on it. A non-trivial installed base of BC merchants still runs LCO, particularly those using Rebillia-mediated subscriptions.

Tradeoff. Three positions:

  • Exclude LCO entirely. Simplest scope. Accept that LCO merchants cannot adopt our engine until they migrate to OPC. Reduces addressable TAM by the LCO-store percentage (unknown exact number, but non-trivial). Creates friction for Rebillia migrants specifically — they are on LCO because Rebillia requires it.
  • Support LCO with reduced capability. Capture intent via a different mechanism (cart metafield? order metafield? legacy API?) and fall back to post-purchase setup. Doubles the capture-path surface area, adds a second test matrix, increases support burden.
  • Migration-only path. Accept LCO stores as subscription-engine prospects but require them to migrate to OPC as part of onboarding. Couples our sales motion to a checkout migration — long cycle, resistance, but aligned with BC's own direction.

Tradeoff framing: this is a TAM vs. scope decision. LCO stores are disproportionately long-tail Rebillia users (the exact migration persona we target). Excluding them cuts directly into our migration-tooling ICP.

Options.

  • A. Exclude LCO. Document clearly. Simpler v1.
  • B. Support LCO via legacy API path. More code, more test.
  • C. Require OPC migration as part of subscription-engine onboarding. Couples two sales motions.

Recommendation. Not a clear recommendation from the Product Pack alone — depends on LCO-store share and Rebillia-migration pipeline. Requires discovery before commit. Add as a P0 BRD-OPEN-QUESTION: "What % of our migration-ICP target list (Rebillia stores + others) is on LCO, and what's the cost profile of supporting each of A/B/C?"

Downstream edits if accepted. PRD Section 6.4 support-matrix row; BRD-OPEN-QUESTIONS new Section 1.x row; decision deferred pending discovery data.


D16 — Address validation as a first-class onboarding concern

<!-- traceability:start:D16 -->

Prototype: OAuth Handshake · Welcome · Setup Checklist · Registration Health · Uninstall Preview · Setup Error · Template Editor · Customer Preferences · Merchant Alerts · Integrations · Deliverability monitoring · Outbound webhooks

<!-- traceability:end:D16 -->

Current state (ours). PRD Section 13 risks table and onboarding prototypes (app-onboarding, processor-onboarding) do not flag address validation. Assumption is that address quality matches whatever the merchant already has at checkout.

Product Pack evidence (p.27). Recharge requires postal-code validation not native to BC, forcing merchants to install Addrexx (address-validation third-party). Implication: BC-native checkout does not validate postal codes strictly enough for subscription reliability, and subscription engines downstream inherit the problem. For our engine, bad addresses at capture surface as shipping-quote failures, tax-calculation errors, or failed deliveries at renewal time.

Tradeoff. Address validation is a known reliability cliff in subscription commerce — bad addresses at subscription creation compound over N renewals. Fix options:

  • Accept BC's native validation. Ship reliability issues downstream. Customer blames us; merchant blames us.
  • Bundle a validation adapter (Smarty, Loqate, Google, or BC-provided). Pluggable in the scoping / subscription-capture flow. Merchant-configurable; default off for free tier, on for paid.
  • Require merchant to install a third-party app. Matches Recharge's workaround; good for not owning vendor relationships, bad for merchant onboarding friction.

Options.

  • A. MVP adapter interface (abstract), ship with one provider (e.g., Smarty) in Phase 2, document ROI as reduced renewal-failure rate.
  • B. Document gap in PRD Section 13 risks, defer implementation; merchant owns validation via existing app.
  • C. Don't address; accept as merchant responsibility.

Recommendation. A. Address-validation failure is a real renewal-failure source that hurts our merchant-facing KPIs (failed-renewal rate, churn, support tickets). Cost is a thin adapter interface plus a Phase 2 provider integration. Keeps the engine responsible for renewal reliability where it's the natural owner.

Downstream edits if accepted. PRD Section 13 risks updated; BRD new micro-epic or story under onboarding for address-validation adapter; ARCHITECTURE Section 4 adapter interfaces section addition.


D17 — BC-native MIT path: recurring subtype + NTI persistence + adapter contract change

Status: DECIDED 2026-05-06 via synthesis 7574bb48-c8f0-4943-aed4-19ecb2e5584e (Issue #46). Source proposal 086e58dc (Issue #10). PRD §6.2 Path A rewrite + new §6.3.1 + §13 downgrade landed in PR #60. ARCHITECTURE §11 #3 marked RESOLVED in same PR. Schema columns landed in PR #62.

Bridge until PI-5062 closes (Worldpay/Paymetric only — non-blocking per ADR-0037). BC's network_transaction_id storage gap affects Worldpay/Paymetric merchants only; it does NOT block the standard stored-instruments vault rail for BC Payments/PPCP, Braintree, or Auth.Net. Our adapter persists NTI from the CIT-first auth response on payment_methods.network_transaction_id and re-attaches on every subsequent MIT for Worldpay/Paymetric stores. When PI-5062 lands BC-side, the adapter switches to reading NTI from BC's surface and the bridge code is deprecated.

Current state (pre-decision, retained for context). PRD §6.2 Path A described BC Payments primary with Braintree-direct fallback. PRD §13 row 1 flagged the BC Payments MIT API surface as a critical-new risk. BRD US-10.2 adapter charge() signature did not carry MIT context. No schema columns existed for network_transaction_id, chain_position, or mit_subtype. All resolved by PR #60 + PR #62.

Day-0 spike (eb94cf4a, decision 256591ec) findings.

  • BC's BigPay layer auto-classifies API-initiated stored-instrument charges as MIT (MREC for recurring renewals). Production-confirmed at Wren Laboratories.
  • BC has flag taxonomy: CSTO/CUSE/CREC/CINS/CGEN (cardholder) and MUSE/MREC (merchant).
  • network_transaction_id (Visa) is stored in BC's provider_vault_token but not currently populated for Worldpay/Paymetric — gap across ~4358 instruments on top 3 stores. Fix tracked by Jira PI-5062.

Proposed bundle (one synthesis cycle, one PR).

  • (a) PRD §6.2 Path A rewritten: BC Payments Processing API + Stored Instruments is the primary path; Braintree-direct is a fallback capability, not a documented production target
  • (b) New PRD §6.3 subsection covering Stored Credential Indicators (MREC for our renewals, EU SCA exemption rationale)
  • (c) Schema additions: payment_methods.network_transaction_id, charges.chain_position, subscriptions.mit_subtype. Adapter persists NTI from CIT response and re-attaches on every MIT for Worldpay/Paymetric stores until PI-5062 closes (non-blocking for standard vault rail per ADR-0037).
  • (d) ProcessorAdapter.charge() signature change to accept mitContext { type, chainPosition, networkTransactionId }; per-adapter mapping table (BC Payments → MREC, Stripe → mit_exemption.recurring=true, Braintree → transactionSource: 'recurring')

Risks if rejected. PRD §13 row 1 stays "critical, new." Production adapter ships without recurring-subtype semantics → SCA exemption forfeited → 3–8% decline-rate increase on EU renewals.

Risks if accepted but PI-5062 stalls. Adapter-side NTI persistence for Worldpay/Paymetric becomes load-bearing maintenance. Mitigated by deprecating it once PI-5062 lands. Risk scope is narrower than originally framed — per ADR-0037, standard vault-rail merchants are unaffected by PI-5062 stall.

Downstream edits if accepted. PRD §6.2 / §6.3 / §13; BRD US-10.2 / US-11.3 / Epic 28 / §9 Data Contracts; ARCHITECTURE §11 #3.


D18 — AllotmentGrant primitive distinct from Entitlement (D1)

<!-- traceability:start:D18 -->

Prototype: Allotment Grants

<!-- traceability:end:D18 -->

Current state (ours). D1 (DECIDED 2026-04-23) added Entitlement as the access primitive — its state is derived from a paid subscription's lifecycle (PENDING/ACTIVE/SUSPENDED/REVOKED). There is no primitive for admin-granted recurring quota (e.g., "Hill's gives Bella Vista clinic $200/month wellness credit refreshing each calendar month, depleted as clinic places orders").

RAG provenance. Colgate POC (docs/rag/Colgate Use Cases.pdf, use cases 4–6, 8); Whirlpool consumables-refill pattern (Subscriptions & Bundling.xlsx row 14); WM-Shred-It pickup-quota model (row 13). All three want recurring quota that can be granted by an admin, depleted by usage, and refreshed on cadence — independent of any paid subscription.

Tradeoff. Folding allotment into Entitlement (with a grant_type discriminator) muddles the lifecycle: Entitlement.suspended_at semantically means "the underlying subscription failed payment" — that's wrong for an admin-granted quota whose suspension comes from a separate revoke action with audit context. Refund and dunning behaviour also diverge — paid Entitlements can be refunded as part of charge reversal; AllotmentGrants reverse via AllotmentDebit.reversed_at with no money flow. Conflating them costs more downstream than carrying two clean primitives.

Options.

  • A. Adopt AllotmentGrant + AllotmentDebit as separate primitives. Distinct lifecycle (active | suspended | revoked), distinct refresh mechanic, separate admin UI in CS tools.
  • B. Fold into Entitlement with grant_type: paid_subscription | admin_grant discriminator. Cheaper schema, ambiguous semantics.
  • C. Defer — model per-prospect via metadata on existing entities. Cheapest now, highest cost when 3+ prospects need it (already true).

Recommendation. A. Distinct primitives. Mirrors the paid/granted asymmetry that exists in every loyalty/credit/quota surface (paid-balance vs gifted-balance is separately modeled in every loyalty system that scales).

Decision (2026-05-07; synthesis eb678099). Adopted Option A. AllotmentGrant carries unit_type: currency | count | duration_minutes, refresh_cadence_*, current_balance, and rollover_policy: none | cap_to_one_period | accumulate. AllotmentDebit records consumption events with optional links to BC orders or subscription charges. Admin-grant audit lives on granted_by + reason. Subscriber-portal exposure is per-merchant config (some merchants want quota visible to subscriber, some want it admin-only).

Landed in: PRD §8.1 (entities added), PRD §8.2 (storage table row), prototype prototype/prototypes/cs-tools/ (AllotmentGrantList / Detail / Create / BalanceView per synthesis action item 12).

Downstream edits if accepted. PRD §8 (done), BRD Epic 6 (US-6.X allotment-as-product-of-purchase), BRD Epic 22 (US-22.X CS-tools admin grant/revoke UI), ARCHITECTURE §10 (SoR row added).


D19 — Multi-actor role enum on a subscription (owner / payer / beneficiary / manager / org_admin)

<!-- traceability:start:D19 -->

Prototype: Multi-Actor Subscription Detail

<!-- traceability:end:D19 -->

Current state (ours). Subscription is a 1-customer construct — bc_customer_id is the single actor, payment_method_ref is the single PM. There is no first-class concept of "this subscription is paid by Alice but consumed by Bob and managed by Carol." Existing "gift" handling is implicit metadata (BRD Epic 6 references gift but no role primitive).

RAG provenance. Colgate POC use case 1 (multi-persona / multi-cart, single user with 3 distinct roles); use case 8 (vet-initiated D2C — clinic acts as manager, pet-parent is payer + beneficiary); B2B Edition checkout-ownership (ADR-0023) — CS-rep needs to be visible as manager on B2B subscriptions; Align/Invisalign (Subscriptions & Bundling.xlsx row 6) provider-managed enrollment.

Tradeoff. Implicit-metadata modeling (e.g., subscriptions.metadata.gift_recipient) collapses immediately under the first cross-cutting concern (notifications routing, dunning escalation, PM update permissions, audit attribution). Each of those becomes a per-feature if metadata.X lookup. A first-class actor table makes role-based behaviour declarative.

Options.

  • A. Adopt — actors table FK'd to subscription_id with a role enum; cardinality constraint "exactly one active payer per subscription"; reserved column processor_connection_ref for v2 marketplace MoR.
  • B. Keep single-customer model; bolt on per-feature shims (gift_recipient_customer_id, manager_customer_id, etc.). Works for 2 features, breaks at 3+.
  • C. Defer until a deal forces it. Already forced by the 5+ prospects above.

Recommendation. A. Adopt now — the marketplace MoR v2 path (ADR-0022) and B2B managed enrollment (ADR-0023) both require this primitive at v1. Deferring forces a v2 schema migration we already know is coming.

Decision (2026-05-07; synthesis eb678099, ADR-0023). Adopted Option A. Role enum: owner | payer | beneficiary | manager | org_admin. org_admin is reserved-but-functional in Phase 1 (used by ADR-0022's marketplace v2 hook). Notification routing, PM-update permission, dunning escalation, and portal-access policy all read role enum. Cardinality: exactly-one active payer per subscription is enforced via partial-unique-index. Multiple manager actors permitted (CS-rep + back-up rep). beneficiary defaults to owner if not explicitly distinct.

Landed in: PRD §8.1 (entity added), PRD §8.2 (storage table row), ADR-0023 (admin-only B2B enrollment depends on manager role), ADR-0022 (marketplace v2 seam = org_admin role + reserved processor_connection_ref).

Downstream edits if accepted. PRD §8 (done), BRD Epic 6 (gift stories rewritten against actor model), BRD Epic 17 (portal auth + role-based view), BRD Epic 19 (PM-update permission keyed off payer.role), BRD Epic 22 (CS-tools manager attribution), BRD Epic 24 (B2B org_admin stories), ARCHITECTURE §10 (SoR row added).


D20 — CustomFieldDefinition schema-typed extensibility on Subscription / Plan / AllotmentGrant

<!-- traceability:start:D20 -->

Prototype: Custom-field admin UI surfaces in the Plan Wizard and CS-tools detail views (per synthesis action items 12 and Catalyst-coexistence prototype, to land)

<!-- traceability:end:D20 -->

Current state (ours). Subscription.metadata and Plan.* carry merchant-supplied data via JSONB blobs with no schema. Merchants today encode {po_number, account_manager, sla_tier, ...} opportunistically, with no validation, no admin UI, and no portal-display rules.

RAG provenance. OpenText (Subscriptions & Bundling.xlsx row 5) — needs PO number per subscription with validation. Cintas (row 11) — service-window field. City of Ottawa (row 8) — fund-code accounting attribution. Lovesac (row 9) — color/material per-plan custom config. All five want typed, validated, admin-configurable fields without us adding bespoke columns.

Tradeoff. No schema = data quality erodes immediately (po_number arrives as 12345 from one merchant, PO-12345 from another, validates nowhere). Per-merchant column adds = unsustainable schema sprawl. The accepted pattern across SaaS platforms is a custom_field_definitions table that names schema, with data living on parent metadata.custom_fields.

Options.

  • A. Adopt — custom_field_definitions table per-store with type enum (text | number | boolean | date | enum | json), validation regex, default value, subscriber-visibility flags. Field data on parent entity's metadata.custom_fields.
  • B. Keep bare JSONB; document conventions in BRD-OPEN-QUESTIONS. Cheap, fails QA.
  • C. Bespoke columns per merchant request. Scaling impossible.

Recommendation. A. Industry-standard pattern; one table + one read-side validator + one admin UI unlocks N merchant-specific data needs.

Decision (2026-05-07; synthesis eb678099). Adopted Option A. Scope enum on the definition: subscription | plan | allotment_grant. Field data location: parent entity's metadata JSONB under reserved key custom_fields (e.g., subscriptions.metadata.custom_fields.po_number = "PO-12345"). Subscriber visibility flags: visible_to_subscriber (portal display), editable_by_subscriber (portal edit). Validation: optional regex per field; required-field enforcement in API and admin UI. Schema migrations on fields are forward-only — archiving a definition hides it from new admin entry but preserves existing data.

Landed in: PRD §8.1 (entity added), PRD §8.2 (storage table row), prototype custom-field surfaces in Plan Wizard and CS-tools detail views (per synthesis action items 12, 15).

Downstream edits if accepted. PRD §8 (done), BRD Epic 5 (plan-wizard custom-field config story), BRD Epic 22 (admin-edit of subscription custom-field data story), BRD Epic 17 (subscriber-portal display/edit story), ARCHITECTURE §10 (SoR row added).


D21 — NTI freshness policy: re-prime the stored credential chain when network_transaction_id ages out

<!-- traceability:start:D21 -->

Prototype: Renewal screens (term-end / mid-cycle / NTI)

<!-- traceability:end:D21 -->

Current state (ours). D17 (DECIDED 2026-05-06) ratified the BC-native MIT path: each renewal carries MREC flag + the persisted NTI from the prior charge. PI-5062 NTI threading gap (Worldpay/Paymetric only — non-blocking for standard vault rail per ADR-0037) is bridged by adapter-side persistence. There is no policy for refreshing an NTI that has aged past issuer freshness windows — for annual+ subscriptions, an old NTI may decline at renewal even if the PM is fresh.

RAG provenance. Align Technology (Subscriptions & Bundling.xlsx row 6) — annual billing cycle, decline rate uplift correlated with NTI age. Industry signal (Visa MasterCard guidance) — issuers downgrade trust on stored credentials whose chain hasn't been re-primed within 12–13 months.

Tradeoff. Without a freshness policy, annual subscribers eat preventable declines (3–8% range observed across processor reports for stale-NTI MITs). Mitigation requires (a) tracking last NTI refresh date, (b) firing a MUSE (member-initiated) verification charge before the scheduled renewal MIT to capture a fresh NTI, (c) routing failed verification to dunning. Cost: one schema column + one workflow extension + one new charge state.

Options.

  • A. Adopt — subscriptions.last_nti_refreshed_at + per-merchant nti_freshness_days config (default 365). Pre-renewal verification fires when stale.
  • B. Defer — accept the 3–8% decline penalty for annual subscribers as Phase-2 backlog.
  • C. Force annual subscribers through manual re-confirmation each cycle (UX-hostile).

Recommendation. A. Phase 2. The schema/workflow cost is small; the revenue protection is meaningful for any merchant with annual / quarterly billing cycles.

Decision (2026-05-07; synthesis eb678099). Adopted Option A, Phase 2 implementation slot. New columns on Subscription: last_nti_refreshed_at (timestamptz), with merchant-config nti_freshness_days (int, default 365). New charge sub-state verification distinguishes the $0-or-$1 MUSE pre-charge from the renewal MIT. On verification success: persist new NTI, proceed with renewal MREC carrying fresh chain. On verification fail: route to dunning as PM-decline. Default nti_freshness_days = 365 (covers annual cycle + one-month buffer); merchants on quarterly+ cycles should set 90.

Landed in: PRD §6.3.1 (stored-credential indicators table — verification charge added in Phase 2 column), prototype prototype/prototypes/dunning-retry/ NTIVerificationCharge variant (per synthesis action item 16). Schema column additions land with Epic 14 + Epic 18 stories (synthesis action item 9).

Downstream edits if accepted. PRD §6.3.1 (verification charge in indicator table), BRD Epic 14 US-14.X (NTI verification charge before stale renewal), BRD Epic 18 US-18.X (verification-failure dunning routing), ARCHITECTURE §11 (workflow extension for verification stage).


D22 — Multi-phase capture timing: defer capture to shipment/fulfillment for EU compliance

Status: DECIDED 2026-05-15 via synthesis b87f5678-b10a-4e9a-83dc-685bcd657f81 (synthesis #840). Source proposals #789 + #821. Phase 1 landed in PR #789; Phase 2 is a deferred-build clause in ADR-0038.

Current state (pre-decision, retained for context). processorAdapter.charge() is atomic: authorization and capture happen in a single request. This is correct for digital goods and immediate-fulfillment merchants, but means EU merchants selling physical-goods subscriptions are non-compliant with PSD2 and card-scheme rules that require capture no earlier than shipment. In addition, gateway auth-window limits (typically 5–7 days) risk stale authorizations when billing-period-start to shipment spans more than a few days.

Decision. Two-phase roll-out:

  • Phase 1 (shipped — PR #789). stores.capture_timing TEXT NOT NULL DEFAULT 'immediate' CHECK (capture_timing IN ('immediate', 'on_fulfillment', 'on_ship')) column added via migration 0019. Admin Payment Settings exposes a dropdown; selection is persisted but has no behavioral effect — the scheduler continues to call adapter.charge() atomically. The UI labels the feature as "Phase 1 advisory." No BC webhook registration for capture events in Phase 1.

  • Phase 2 (deferred-build — [Spec] to be filed). Split adapter.charge() into adapter.authorize(ctx) → AuthResult and adapter.capture(authRef, amount) → CaptureResult. Register BC webhooks: store/shipment/created (payload { type: "shipment", id, orderId }) to trigger capture for on_ship stores; store/order/statusUpdated for on_fulfillment stores. Add auth-expiry sweep cron: reap authorizations approaching auth_window_days per processor metadata; trigger early capture or cancellation notification. Add stores.auth_window_days per-store override. Add EU geo auto-detection warning in admin.

Rationale for the Phase 1 / Phase 2 split. The config column is cheap and unblocks merchant preference expression + data shape for Phase 2 without a second migration. The adapter split is architecturally significant (impacts scheduler, all processor adapters, BC order-lifecycle webhook handlers) and requires its own synthesis and spec; bundling it into Phase 1 would block the column behind a large-scope PR. ADR-0011 (idempotency) and ADR-0025 (order-first) must be re-examined before Phase 2 ships.

Landed in: stores.capture_timing column (migration 0019, PR #789); CaptureTiming type in @bc-subscriptions/types; admin Payment Settings dropdown at /settings/payment; state-derive capability capture-timing-stored-on-store (COMPLIANT); STATE.md R-12 + R-13 (open compliance risk until Phase 2 ships); PRD §6.2 multi-phase capture note; BRD US-10.9 (Epic 10 capture timing config story) + US-2.7 (Epic 2 onboarding advisory story).

Downstream edits if accepted. PRD §6.2 (multi-phase capture note — done); BRD US-10.9 (full AC + data contract — done); BRD US-2.7 (onboarding advisory — done); STATE.md R-12/R-13 (compliance risk entries — already present); ARCHITECTURE §11 (Phase 2: adapter split + webhook handlers — pending Phase 2 Spec); ADR-0038 Consequences (deferred-build clause — canonical, already landed).


Post-decision checklist

When each decision lands:

  • Update the status in the summary table
  • Edit the downstream spec files listed in the decision entry
  • If the decision closes a row in BRD-OPEN-QUESTIONS.md, remove that row and link it here
  • Note the PR in the decision entry's Landed in: line

Open questions for the review session

  1. D1–D5 can ship in Phase 1 with modest schema impact. Is there appetite to land all five, or should we stage?
  2. D4 (REQUIRES_ACTION + magic-link) is coupled to EU Phase 2 — confirm Phase 2 timeline before committing.
  3. D7 recommends keeping the durable workflow. Do we want a prototype comparison (workflow vs. task-queue) before finalizing, or is the recommendation acceptable on architectural grounds?
  4. D10 and D11 rejections are architectural positioning. Does leadership want these documented as explicit non-goals in PRD Section 3, or left implicit?
  5. D12 (cite partner quotes): audit against BC Payments capabilities before citing; who owns the audit?
  6. D13 (bundle tax): needs a Phase 1 discovery spike against the BC tax service to verify per-component behavior before we commit the MVP constraint.
  7. D14 (membership as ENT wedge): adds a 4th positioning pillar. Does that fit the PRD Section 3 narrative or dilute it? Marketing/PMM input needed.
  8. D15 (LCO posture): blocked on discovery data — what % of migration-ICP target list is on LCO? Who runs that discovery?
  9. D16 (address validation): Phase 2 is the recommended slot, but if Phase 1 merchant cohort is skewed toward physical goods, consider promoting to Phase 1.