Randomize questions on every Anki regen

Also make explanation section slightly more readable
This commit is contained in:
2026-06-04 11:10:08 +02:00
parent 7bf6f98ee2
commit fdc5932d7d
5 changed files with 105 additions and 17 deletions
+15 -10
View File
@@ -463,8 +463,10 @@ These do not block the Stage 1 implementation:
Given the per-edition directory produced by Stage 1, build a set of
Anki `.apkg` files that turn every catalog question into a flash card.
Same input must produce byte-identical output across runs — this is
important so generated decks can be checksummed and cached cleanly.
By default, each build uses a fresh shuffle seed so repeated imports
vary the answer order. When `--seed` and `--epoch` are supplied,
the same input must produce byte-identical output across runs — useful
for tests, checksums, and cacheable release builds.
### CLI shape
@@ -475,9 +477,9 @@ amateurfunk-anki [--data DIR] [--out DIR] [--seed STR] [--epoch INT]
- `--data DIR` — fetch output root (default `./data`). Must contain
`manifest-latest.json` pointing at a per-edition directory.
- `--out DIR` — destination for `.apkg` files (default `./anki`).
- `--seed STR` — deterministic seed for answer shuffling. The default
is fixed; changing it produces a different (but still deterministic)
shuffle.
- `--seed STR` — deterministic seed for answer shuffling. Omit it
for the normal study-deck behavior: a fresh seed is generated for
each build, so answers are reshuffled every time decks are rebuilt.
- `--epoch INT` — override the package timestamp epoch. By default we
derive it from the manifest's `fetched_at`; this flag is mainly for
tests and explicit rebuilds.
@@ -565,8 +567,10 @@ for in-Anki filtering, and harmless besides.
### Determinism
The contract is: same catalog in → same `.apkg` bytes out.
Determinism rests on three things:
The default CLI intentionally is not byte-deterministic because it
generates a fresh shuffle seed each run. The reproducible-build
contract is: same catalog + same `--seed` + same timestamp inputs →
same `.apkg` bytes out. Determinism rests on three things:
1. **Stable IDs.** `stable_id(namespace, text)` hashes a
namespaced key with SHA-1 and squashes into the standard
@@ -587,8 +591,9 @@ Determinism rests on three things:
last step, the inner SQLite would be identical but the
archive's per-entry mtimes would still vary between runs.
The combined effect: two runs with the same `data/` produce
byte-identical sha256 on each `.apkg`. Verified during review.
The combined effect: two runs with the same `data/`, `--seed`, and
timestamp inputs produce byte-identical sha256 on each `.apkg`.
Verified during review.
### Rendering decisions worth knowing
@@ -636,7 +641,7 @@ byte-identical sha256 on each `.apkg`. Verified during review.
`explanations.json` (CLI: `--explanations`) and, for any
question number found there, appends an English explanation
block to the back of the card. The block is styled distinctly
(serif italic body, sans-serif metadata, top border) and shows
(serif body, sans-serif metadata, top border) and shows
a small "low confidence" badge when the entry's `confidence`
field is below `LOW_CONFIDENCE_THRESHOLD` (= 7). `revision` and
the raw `confidence` number are editorial-only and never