Skip to main content

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:

MechanismWhat it doesDefaultScope
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 decayUnspent earned tokens dim over time to encourage spending velocity.OFF — enabling is a product+clinical call, not engineeringHousehold/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_floor trigger — unchanged.
  • token_batches rows only bookkeep lots (remaining, fade_state, fade_started_at are 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:

  1. Household defaultshouseholds.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. SDK FadingService is the validation twin (house rule: invariants in service AND schema).

  2. Per-chore override — nullable chores.fade_override jsonb. Absent = household policy. A chore can be pinned out of thinning entirely ({"thinning":{"enabled":false}}).

  3. 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 LedgerEntryKind that fade will widen.
  • Companion — dewdrop economy is physically separate; fading does not touch it (by design).