A word like makan (eat) has a "family": forms it turns into (makanan = food), compound words built from it (rumah makan = restaurant), and words that mean something similar or opposite. Right now that family gets stored two or three different, inconsistent ways — and none of them can yet hold a French translation next to the Indonesian. This decides the one way going forward, and it's the piece the cluster-card screens you already designed are waiting on.
Audit finding D16, plus the related fields that share the same gap
Way #1 — its own entry. A form of a word (like makan → makanan) gets its own full database row, with its own meaning, pronunciation, and example. There are 1,221 of these today.
Way #2 — a copied list on the parent. A "related compound" (a different word built from this one, like rumah makan) instead gets stuffed into a list of text sitting inside the parent word's own entry, duplicating some of the same information. There are 368 words carrying one of these lists, holding 2,159 entries in total.
The trouble: these two ways overlap, and the overlap is a mess. 234 words have both kinds at once. In 123 of those cases, the exact same word shows up twice — once as its own entry, once again copied into the list. And 121 of the "own entry" rows are marked hidden, with a note literally saying they were being moved into the list-on-the-parent approach and the move was never finished. That's a live, half-done migration sitting in the data today.
| Field | What it holds | Same gap? |
|---|---|---|
| Word forms (own entry) | 1,221 rows — full entry per form | Duplicates 123 of the list-on-parent entries below |
| Related compounds (list on parent) | 368 words, 2,159 entries — text + meaning + pronunciation copied inline | Also duplicates the audio file for 211 of those entries |
| Similar words / opposite words | 560 / 299 words — a list of {word, meaning} pairs | Same shape problem: no agreed structure, English-only meaning |
| Informal variants | 403 words — casual ways to say the same thing | Same shape problem, plus it's designed to duplicate the others on purpose (see note below) |
One thing that's not broken: the "informal variants" sparsity looked like a bug at first, but it isn't — 226 of the 227 "missing" ones are recorded on purpose as "this word has no casual variant," and the design intentionally repeats some of what's in the similar-words/forms lists for a simpler on-screen view. That part is fine as-is; it's flagged here only because it's another user of whatever shared structure gets picked below.
Why this blocks French (or any new language): every one of these fields hard-writes the translated meaning into a single "eng" slot. There's no second slot for French, and no code that knows how to fill one. Fixing the storage shape and fixing the language problem are the same piece of work.
Quoted from your response to Decision 4 — lightly cleaned up from voice dictation, your words
"Perhaps we need to have a heart-to-heart talk about related compounds and the other fields that are similar — similar words, opposites, and things like that. If I want to support them in multiple languages, they need to have a structure when they're being stored. Right now... I don't know if it would be better to have a standard JSON, or another table in the database that relates to those, with a key on these related terms so we connect into it.
Maybe we should have every word flat underneath CT2 as its own entity, and attach a flag to it that had all the different information — reversing the informational structure, using tags rather than database structures. It seems like that's the more modern WordWeb kind of approach. But it would have to be a really strong argument to get me to do that, because it would basically be a refactor of everything.
The enrichment needs to be so extensive for the family forms — that's why we created the CT3 level. But for related compounds, the only place I'm really going to use it is the CT3 level, or the data would just be very simple — just a gloss, or maybe a one-word sentence with it. Maybe there'll be three elements rather than 30, like etymology or why-learn-this. So I don't think it needs its own separate entry at CT3, but I do think it needs some kind of standardized structure and the ability to have translations associated with it.
We have the direction from a user-experience point of view — the cluster cards. However, the data doesn't support it at this point, and it needs to be included in the v4 enrichment pipeline."
CLUSTER-CARD-PLAN.md, ratified 2026-07-14 — plus the Bodhisattva Vows mockup you already clicked through
You ratified the cluster-card interaction back on 2026-07-14: a word's family members become a flip-through drill on one card, instead of one flashcard per family member. There are two kinds already scoped — a related-cluster (the related-compounds list) and a form-cluster (the CT3 word-form rows) — and the plan says outright that both pull their rows directly from the two storage shapes this checkpoint is about.
You've since seen this pattern working, live and clickable, on a real deck — the Bodhisattva Vows cluster mockup. It uses a 4-face flip: an identifier, a short gloss, the fuller text, then loops back. Here's what one row's cycle looks like:
That's the concrete shape the storage decision below has to support, per family member: an identifier (the word/compound text), a short gloss (what shows on the quick flip), and a fuller text (the full definition or sentence) — each one needing an Indonesian version and, per the language-swap goal, a version in whatever language the learner reads in. The plan's form-cluster variant adds one more flip for the grammar rule that applies to that form, pulled from form_rule_keys. This is exactly the "some kind of standardized structure, with the ability to have translations" your note above is asking for — it's not a hypothetical, it's what's already sitting live on wordsense-reviews.pages.dev.
ind, eng, and later fra) instead of one hard-wired English slot. This is the "three elements, not thirty" shape your note describes.form_rule_keys) for the 5th flip face.