Skip to content

Term status model: single source of truth + Anki/FSRS-aligned scheduling #238

@HugoFara

Description

@HugoFara

Status: Proposed — deferred until after the next release (the FSRS part is an architectural change worth landing on its own).

Proposal doc in-repo: docs-src/developer/term-status-fsrs.md.

Problem

The word-status model (1-5 learning, 98 ignored, 99 well-known) is the spine of both the reading UI (word colouring) and the review system, but it is modelled ad-hoc:

  • Duplicated: the literal [1,2,3,4,5,98,99] and checks like $status === 5 || $status === 99 recur across 11+ PHP files; label/colour/order/CSS tables are re-defined in ~6 TS files. A TermStatus value object exists (src/Modules/Vocabulary/Domain/ValueObject/TermStatus.php) but isn't the single source of truth.
  • Scheduling is a hand-tuned Leitner curve: TermStatusService::SCORE_FORMULA_TODAY/TOMORROW is a per-status linear decay stored in WoTodayScore/WoTomorrowScore, shuffled by WoRandom; a review just nudges status ±1. No memory model, no per-term difficulty, no retention target, no review history.

One integer conflates two concerns: how familiar a word is (reading view) and when it should next be reviewed (scheduling).

Phase 1 — status as a single source of truth (independent, low-risk)

Promote TermStatus to authoritative (value, label, abbr, cssClass, colour, order, isKnown()/isIgnored()/isLearning()); fold in TermStatusService/StatusHelper; replace the ~11 PHP literals; expose once to the frontend (bootstrap or GET /api/v1/settings/status-definitions) and collapse the ~6 duplicated TS tables into one store.

Phase 2 — FSRS-aligned scheduling

Split display familiarity from memory state:

Concern Today Proposed
Display familiarity (colours) WoStatus 1–5 keep 1–5, derived from stability
Scheduling per-status decay score FSRS memory state per term

FSRS models each term with Stability (S), Difficulty (D), Retrievability (R) (power forgetting curve; due when R hits target retention, default 0.9). Reviews become 4 grades (Again/Hard/Good/Easy), each updating S/D and the next due date.

Changes: schedule columns / term_schedule + review_log tables (retire WoTodayScore/WoTomorrowScore/WoRandom + formulas); a swappable Scheduler service (FSRS impl, interface-backed); SubmitAnswer calls the scheduler; 4-grade review UI; derive 1–5 colours by bucketing S; 98/99 stay manual flags (≈ suspended/known). Existing terms seed FSRS state from WoStatus + WoStatusChanged.

Decisions to make

  1. Display status derived from stability (recommended, with manual override) vs. fully manual/orthogonal.
  2. 4-grade vs. a 2-button (Again/Good) mode for existing users.
  3. Vendor a maintained PHP FSRS port vs. hand-port open-spaced-repetition (licence check before vendoring).

See the proposal doc for migration, scope, and verification detail.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions