> ## Documentation Index
> Fetch the complete documentation index at: https://internal.softcrum.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Open Questions Register — Loyalty (v1.1)

> Two answers changed the design rather than merely ratifying it.

> Translation. Authoritative: [`../../design/open-questions-v1.md`](/design/open-questions-v1).

Status: **0 open** · **27 closed on 2026-08-17** · the 14 loyalty specs and their PRD sit at
`0.2.0` / `review`, awaiting only sign-off to reach `approved` and `1.0.0`.

* **OQ-LOY-02** — expiration becomes a policy of the **point currency**, not of its kind. Status
  points may expire or not, as each company configures. A consequence closed in the same move: when a
  status currency expires, the grace period and the `tier.grace_started` event stop being optional,
  because otherwise a member loses a tier without ever having stopped buying.
* **OQ-LOY-07** — multi-program is a first-class capability in F1. It reverses DEC-H2, so
  [ADR-021](/adr/adr-021-multi-program-from-day-one) was written first and the specs were
  updated from it. Program count is an **entitlement**, not a metered metric.

**OQ-LOY-14** also left a cross-cutting principle that now lives in `standards/api.md`: every policy
parameter is tenant-configurable with a published default.

## Owner's answers (2026-08-17)

Twenty-five landed exactly as recommended. The exceptions and nuances:

| ID        | Answer                                                                                                           |
| --------- | ---------------------------------------------------------------------------------------------------------------- |
| OQ-LOY-01 | Per program. Also ratified that a program belongs to exactly one company.                                        |
| OQ-LOY-02 | **Configurable per currency.** Both kinds may expire or not; the platform must allow every combination.          |
| OQ-LOY-07 | **Multi-program from the start** — see ADR-021.                                                                  |
| OQ-LOY-11 | Accepted, raised to **12 characters** so that hundreds of millions of codes do not make generation fight itself. |
| OQ-LOY-14 | Accepted **as a default**, with the general principle that every company can configure it.                       |

## The 27 questions and their recommendations

### Phase F1a blockers

| ID          | Question                                                                                             | Affects                | REC                                                                                                                                                                                           |
| ----------- | ---------------------------------------------------------------------------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ✅ OQ-LOY-01 | Does the return window (the time an `earn` stays `pending`) live on the program or per earning rule? | FS-LOY-0002            | **Per program.** Per rule is more expressive, but a member who sees two earns become available on different timelines does not understand it, and neither does support.                       |
| ✅ OQ-LOY-02 | Do status points expire, or only redeemable ones?                                                    | FS-LOY-0002, 0010, PRD | **Status points do not expire by lot; they lapse via the qualification window.** Two distinct mechanisms; mixing them produces the classic bug of losing a tier through an expiry nobody saw. |
| ✅ OQ-LOY-03 | Is `revoke` distinct from a negative `adjust`, or is the distinction only reporting?                 | FS-LOY-0002            | **Distinct, and the difference is intent.** `revoke` is "this should never have been credited"; `adjust` is "we corrected an amount".                                                         |
| ✅ OQ-LOY-04 | Does `points_lifetime_earned` live on `contact_balances` or a separate reporting projection?         | FS-LOY-0003            | **On `contact_balances`.** It grows monotonically and updates in a transaction that is already open.                                                                                          |
| ✅ OQ-LOY-05 | When several rules match one event, do all apply or does a priority stop at the first?               | FS-LOY-0004            | **All apply, with an optional `stop_on_match` per rule.** The common case is cumulative; stopping by default surprises.                                                                       |
| ✅ OQ-LOY-06 | Is the per-contact budget evaluated over the campaign lifetime or a rolling window?                  | FS-LOY-0004            | **Campaign lifetime.** A window inside another window is hard to explain and to audit.                                                                                                        |
| ✅ OQ-LOY-07 | Does the default program get a tenant-visible name, or a fixed internal one?                         | FS-LOY-0001            | **Superseded by the owner: multi-program from day one (ADR-021).**                                                                                                                            |

### Phase F1b

| ID          | Question                                                                                                | Affects     | REC                                                                                                            |
| ----------- | ------------------------------------------------------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------- |
| ✅ OQ-LOY-08 | Is a reward's `per_contact_limit` counted over the member's lifetime or a rolling period?               | FS-LOY-0005 | **Configurable, default lifetime.** A nullable `limit_window_days` covers both without branching the logic.    |
| ✅ OQ-LOY-09 | On rollback, do restored points keep their original expiry or reset it?                                 | FS-LOY-0006 | **Keep the original.** Resetting turns rollback into a way to extend expiries, and someone will find it.       |
| ✅ OQ-LOY-10 | Is there a time limit after which a redemption can no longer be rolled back?                            | FS-LOY-0006 | **Yes, configurable per program, default 90 days.**                                                            |
| ✅ OQ-LOY-11 | Coupon code length and alphabet: how much entropy versus being readable aloud?                          | FS-LOY-0007 | **12 characters over Crockford Base32** (raised from 10 on the owner's volume argument).                       |
| ✅ OQ-LOY-12 | Can a generic code be restricted to a segment rather than a contact?                                    | FS-LOY-0007 | **Yes.** It is the natural shape of a campaign and the segment already exists in `core`.                       |
| ✅ OQ-LOY-13 | When a non-combinable set is violated, keep the highest-precedence benefit or reject the whole request? | FS-LOY-0008 | **Keep the best and report the exclusion.** Rejecting everything at a counter leaves the cashier with no move. |
| ✅ OQ-LOY-14 | Default referral attribution window: 30, 60 or 90 days?                                                 | FS-LOY-0009 | **60 days**, as a configurable default.                                                                        |
| ✅ OQ-LOY-15 | Do fraud-flagged conversions expire if nobody reviews them?                                             | FS-LOY-0009 | **They do not expire; they escalate at 14 days.**                                                              |
| ✅ OQ-LOY-16 | Default tier qualification window: rolling 12 months or calendar year?                                  | FS-LOY-0010 | **Rolling 12 months.** Continuous and fair, and it avoids the January cliff.                                   |
| ✅ OQ-LOY-17 | Does entering grace emit an event?                                                                      | FS-LOY-0010 | **Yes, `loyalty.tier.grace_started`.** One of the highest-performing retention campaigns in the format.        |
| ✅ OQ-LOY-18 | Can a member skip a tier when one event crosses two thresholds?                                         | FS-LOY-0010 | **Yes, jump to the highest reached, emitting once.**                                                           |
| ✅ OQ-LOY-19 | Default expiry-warning horizons: 30 and 7 days, or a single 14-day warning?                             | FS-LOY-0011 | **30 and 7.** The 30 gives time to react; the 7 converts.                                                      |
| ✅ OQ-LOY-20 | Is `cohort_key` the expiry date or the month?                                                           | FS-LOY-0011 | **The date.** The month groups lots with different expiries into one misleading warning.                       |

### Phase F2

| ID          | Question                                                               | Affects     | REC                                                                                    |
| ----------- | ---------------------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------- |
| ✅ OQ-LOY-21 | Can a challenge be repeatable with a reset, or are instances distinct? | FS-LOY-0012 | **Distinct instances from a template.** A reset destroys participation history.        |
| ✅ OQ-LOY-22 | Do badges carry status points, making them a tier input?               | FS-LOY-0012 | **Not by themselves; yes as an optional rule effect.**                                 |
| ✅ OQ-LOY-23 | `apply_discount` reservation TTL: 15, 30 or 60 minutes?                | FS-LOY-0013 | **30 minutes.** Covers a checkout with real friction without freezing campaign budget. |
| ✅ OQ-LOY-24 | Line-item discounts in the first version, or cart-level only?          | FS-LOY-0013 | **Cart only.** Line items need a product model we do not have.                         |
| ✅ OQ-LOY-25 | Cart snapshot retention: the standard tier, or shorter?                | FS-LOY-0013 | **90 days fixed.** It is not an order.                                                 |
| ✅ OQ-LOY-26 | Wallet pass push coalescing window: 5, 15 or 60 minutes?               | FS-LOY-0014 | **15 minutes.**                                                                        |
| ✅ OQ-LOY-27 | Is the wallet pass offered automatically or on request?                | FS-LOY-0014 | **On request, with a prominent link.**                                                 |

## Blocked by something other than a decision

| ID        | Topic                                    | Status                                                                                                                                                                                                                                                                                                                                                                                                                       |
| --------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| P-3       | Unit prices per metered metric           | **Method agreed**: cost floor from the real stack, ceiling from market anchoring, first-plan allowances that cover the design partner's first year. The missing deliverable is the *cost model*, and it must exist **before G1** — if serving costs more than the market pays per contact, we want to know while the architecture can still change.                                                                          |
| OQ-LOY-28 | Wallet pass signing libraries            | Needs an ADR covering four things: a maintained library per platform behind a port, the **certificate lifecycle** (expiry, rotation without reissuing, early alerting) which is what actually breaks programs in production, which accounts issue them, and the coalescing window already fixed at 15 min. **Blocking spike first**: can one Apple Pass Type ID serve every tenant with per-pass branding?                   |
| OQ-LOY-29 | Default expiration per vertical template | **Yes, but recommended and never silently applied.** The template ships the policy with its rationale, onboarding shows it, and the tenant actively accepts or changes it — which also produces evidence that they chose, useful in the DPA. Starting points: subscriptions 24 rolling months, retail 12, high-frequency 6–12. **For the lawyer**: confirm whether point expiry has legal limits in the supported countries. |

## Changelog

| Version | Date       | Change                                                                                       | Why                                                                       | Author                 |
| ------- | ---------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ---------------------- |
| 1.1.0   | 2026-08-17 | All 27 answered and closed; applied to the specs, which move to 0.2.0 / review               | The owner answered the complete batch                                     | daniel + claude-opus-5 |
| 1.0.0   | 2026-08-17 | Initial register: 27 open questions for the loyalty module, plus 3 blocked by something else | Consolidate in one place what was preventing 14 specs from being approved | daniel + claude-opus-5 |
