# Zeitgeist Anki · FSRS-4.5 Algorithmus-Details

Kondensierte technische Referenz für den in `/media/HDD_1TB/Zeitgeist/anki.html` eingebauten Spaced-Repetition-Algorithmus. Wird bei Fragen zum Lernverhalten, der Datenstruktur oder geplanten Tweaks benötigt.

---

## Wo der Code lebt

- **Frontend-Datei:** `/media/HDD_1TB/Zeitgeist/anki.html`
- **Algorithmus-Objekt:** globale Konstante `FSRS` (Zeilen ~678–896)
- **Legacy-Alias:** `const SM2 = FSRS;` – alter Code, der SM-2 erwartet, läuft weiter.

## Datenstruktur in `data.json`

`zeitgeist-anki-v2` ist ein **JSON-String** (doppelt decodieren!):

```json
{
  "decks": {
    "<deckId>": {
      "id": "...", "name": "...", "color": "#...", "created": 1717000000000,
      "cards": [
        {
          "id": "...", "front": "...", "back": "...",
          "state": "new" | "learning" | "review" | "relearn",
          "interval": 0,          // aktueller Abstand in Tagen
          "stability": null,      // FSRS-Stabilität in Tagen
          "difficulty": null,     // 1–10
          "lastReview": null,     // timestamp (ms)
          "dueDate": null,        // timestamp (ms)
          "lapses": 0,
          "reviews": 0,
          "learningStep": 0,
          "easeFactor": 2.5,      // Legacy, nur für Migration
          "leech": false
        }
      ]
    }
  }
}
```

## FSRS-4.5 Gewichte

```js
W: [0.4072, 1.1829, 3.1262, 15.4722, 7.2102, 0.5316,
    1.0651, 0.0234, 1.616, 0.1544, 1.0824,
    1.9813, 0.0953, 0.2975, 2.2042, 0.2407, 2.9466,
    0.5034, 0.6567]
```

Kalibriert auf ~10k Anki-Nutzer-Historien; nicht personalisiert auf den lokalen Nutzer.

## Konstanten

| Konstante | Wert | Bedeutung |
|---|---|---|
| `DESIRED_R` | 0.9 | Zielretention (90 %) |
| `MAX_INTERVAL` | 365 Tage | harter Obergrenze-Cap |
| `FUZZ` | 0.05 | ±5 % Zufallsspielraum auf dem Intervall |
| `LEECH_AT` | 8 | Lapses bis Leech-Flag |
| `STEPS_LEARN` | `[2, 1440]` | Lernsteps in Minuten: 2 min → 1 Tag |
| `STEPS_RELEARN` | `[15]` | Relearn-Step: 15 min |
| `HARD_LEARN_MIN` | 10 min | Minimum für „Schwer“ im Lernschritt |
| `HARD_MULTIPLIER` | 1.5 | Multiplikator für „Schwer“ in höheren Steps |
| `GRAD_INTERVAL` | 2 Tage | Graduating-Interval nach letztem Lernstep (Gut) |
| `EASY_INTERVAL` | 4 Tage | Graduating-Interval bei „Einfach“ |

## Kernformeln

**Retrievability** nach `t` Tagen bei Stabilität `s`:
```js
R(t,s) = (1 + t / (9*s)) ^ -1
```

**Interval** aus Stabilität:
```js
I(s) = 9 * s * (1/DESIRED_R - 1)  // ≈ s, da DESIRED_R=0.9
I = clamp(1, MAX_INTERVAL, round(I * fuzz))
```

**Initiale Stabilität** nach erstem Rating `g ∈ {1..4}`:
```js
S_init(g) = W[g-1]
```

**Initiale Schwierigkeit**:
```js
D_init(g) = W[4] - (g-3) * W[5]
```

**Schwierigkeits-Update** nach Rating `g`:
```js
dD   = -W[6] * (g - 3)
D'   = D + dD * (10 - D) / 9
D_neu = W[7] * D_init(4) + (1 - W[7]) * D'
```

**Stabilität nach erfolgreichem Review** (`g ≥ 2`):
```js
hardPen = (g === 2) ? W[15] : 1;
easyBon = (g === 4) ? W[16] : 1;
factor  = exp(W[8]) * (11 - D) * s^-W[9] * (exp(W[10]*(1-R)) - 1) * hardPen * easyBon;
S_neu   = s * (1 + factor);
```

**Stabilität nach Lapse** (`g = 1`):
```js
S_neu = W[11] * D^-W[12] * ((s+1)^W[13] - 1) * exp(W[14] * (1 - R));
```

## Zustandsmaschine

### New / Learning

| Rating | Effekt |
|---|---|
| 1 (Nochmal) | Step 0, `due = now + 2 min` |
| 2 (Schwer) | bleibt im Step, `due = now + max(10 min, step * 1.5)` |
| 3 (Gut) | nächster Step; nach letztem Step → `review`, `interval=2d`, `stability=2` |
| 4 (Einfach) | sofort `review`, `interval=4d`, `stability=4` |

### Review

| Rating | Effekt |
|---|---|
| 1 (Nochmal) | `lapses++`, Stabilität via Forget-Formel, Status → `relearn`, `due = now + 15 min`, `interval = interval(S)` |
| 2–4 | Schwierigkeit aktualisieren, Stabilität via Recall-Formel, `interval = interval(S)`, `due = now + interval` |

Bei 8 Lapses wird `leech = true` gesetzt.

### Relearn

| Rating | Effekt |
|---|---|
| 1 | Step 0, 15 min |
| 2 | 15 min × 1.5 |
| 3 / 4 | nächster Step (nur einer definiert) → zurück zu `review` mit neuem `interval(S)` |

## Migration von SM-2- zu FSRS-Karten

Transparent beim ersten Bewerten alter Karten:

```js
stability  = max(0.5, interval || 1);
difficulty = clamp(1, 10, ((5.0 - easeFactor) / 3.7) * 9 + 1);
lastReview = dueDate - interval * 86400000;
```

## Nicht-FSRS-Lernverhalten

- Die Lern- und Relearn-Phase verwenden **fixe Minuten-Steps**, keine FSRS-Formeln.
- `MAX_INTERVAL = 365` ist konservativ; wer längerfristig lernt, überschreibt diese Konstante.
- Der Algorithmus **trainiert nicht** aus der eigenen Review-Historie; er rechnet mit statischen FSRS-4.5-Gewichten.

## Wartung / Tweaks

Um Konstanten zu ändern, editiere `/media/HDD_1TB/Zeitgeist/anki.html` im `FSRS`-Objekt. Backup empfohlen, da `data.json` root-owned ist und keine Versionsgeschichte führt.
