Token fading
Status: ⭐ Differentiator · ⏸️ Engine deferred · ✅ Schema shape Accepted (2026-07-15) · ⚗️ Values pending Phase-2 clinical sign-off
Scope
The long-term product thesis is that the token economy should be a scaffold, not a permanent fixture. Token fading reduces reward frequency (and optionally value) over time as a child builds intrinsic motivation. The engine (FadingService, UI, parameter wiring) remains deferred until kudos and celebration rails land. The schema SHAPE is now frozen — one additive migration when the engine work starts. This ADR resolves rebuild-spec open item 3 (TokenBatch schema freeze).
Source of truth: docs/decisions/2026-07-15-token-fading-schema-shape.md.
Two independent mechanisms
Fading is two distinct systems that must not be conflated:
| Mechanism | What it does | Default | Scope |
|---|---|---|---|
| Reinforcement schedule thinning (the moat) | Changes future earn frequency per chore as habit stabilizes (FR1 → FR2 → VR3 → social-only → graduated). The moat: no consumer product automates this. | OFF (enabled by policy) | Per (member, chore) state |
| Batch value decay | Unspent earned tokens dim over time to encourage spending velocity. | OFF — enabling is a product+clinical call, not engineering | Household/chore policy |
These are independent; enabling one does not imply the other.
Balance effects — ledger only
All balance changes from fading go through a new LedgerEntryKind.fade (Dart enum widening + SQL kind CHECK widening — exact precedent: move was added post-Tier-0). Decay debits are appended via the existing LedgerService.debit path:
- Append-only ledger preserved.
- Zero-floor enforced via
enforce_zero_floortrigger — unchanged. token_batchesrows only bookkeep lots (remaining,fade_state,fade_started_atare mutable batch fields); they never carry balance truth.- No direct balance mutation, ever. No UPDATE-balance shortcut (invariant 2 machinery).
LedgerEntryKind.fade is ADR-frozen but pending — it is not emitted until the engine migration lands.
Policy shape (frozen)
Three layers compose fading configuration:
-
Household defaults —
households.fade_policy jsonb not null default '{}'(empty object = all fading disabled). Jsonb because values are clinical-tunable and versioned; a minimal SQL CHECK asserts it is an object. SDKFadingServiceis the validation twin (house rule: invariants in service AND schema). -
Per-chore override — nullable
chores.fade_override jsonb. Absent = household policy. A chore can be pinned out of thinning entirely ({"thinning":{"enabled":false}}). -
Per-
(member, chore)reinforcement state — new table when the engine lands:member_chore_reinforcement_state(id, household_id, member_id, chore_id, phase check in ('p0','p1','p2','p3','graduated'), entered_phase_at, held_by_parent bool default false, last_holiday_at, occurrence_cursor, updated_at)+ unique(member_id, chore_id). RLS: read-household / write-parental. Phase moves one step only (service + trigger twin).
Research defaults from the ABA literature are documented in the ADR's jsonc block — all values are tunable, none are load-bearing until Phase-2 clinical sign-off.
token_batches is FROZEN
With the two mechanisms above, token_batches needs no new columns: decay bookkeeping uses existing fields (remaining, fade_state, fade_started_at); thinning never touches batches (it modulates earn-time credits). The schema as deployed in 20260612000002 is declared frozen. Rebuild-spec open item 3 is resolved.
Invariants
- Fading is never behavior-contingent removal. Thinning changes only future earn frequency; decay (if ever enabled) is time/policy-based and never fires in response to a missed chore, a decline, or any behavior. Violating this breaks invariant 2.
- Promotion is occurrence-based, not calendar-based. A phase advance is keyed to the number of completions, never to a wall-clock date.
- Every graduation is celebrated, not silent. Child-visible framing is positive at every transition ("you're building a real habit"). A creature that shrinks or a fade that is invisible both contradict the thesis.
- Dewdrops are separate. The companion's dewdrop economy is physically separate from
ledger_entries; fading never reaches it. See Companion.
Deferred / open
- Parameter VALUES — Phase-2 clinical sign-off required; the ADR's jsonc is research defaults from ABA literature only.
- FadingService engine + UI — build-order item 10; requires kudos and celebration rails first.
- Enabling decay at all — a product+clinical call, not an engineering decision.
- OT-assessment readiness signals — pluggable policy inputs, defined in Phase 2.
Relationship
- Clinical OT framework — fading signals come from OT assessment in Phase 2.
- Token economy — the append-only ledger and
LedgerEntryKindthatfadewill widen. - Companion — dewdrop economy is physically separate; fading does not touch it (by design).