42 topics across 10 subjects — FSA at module level from your own notes (Reading 7 consolidated into one combined topic once fully mastered), the rest at reading level. Click one, record what you actually understand.
CONTENT[key].compare), branch/mind-map nodes (CONTENT[key].notes) — never left as a plain paragraph dump.ledger-comments.gs); Claude works through the open ones, updates the data, and resolves each with a reply. Explanations happen in chat, not in a textarea; Claude decides status (not started/progress/mastered), writes the structured notes, logs gaps and tuition misses, and sets links between topics — all directly in the file's data. The user never fills in a form here.TUITION_MISSES entry per concept, tagged with the module it belongs to. Each entry records: the questions missed (picked vs. correct; and the full question word for word, with every option, in TUITION_Q keyed by its ref), why the wrong answer felt right, the logic that gets it right, how to tackle that question type step by step, and how it shows up in the exam. It renders as a rose weak-spot card inside that module's group, with an index of weak spots at the top of the topic.Written Notes/<subject>/Test Result), Claude logs it in TESTS: every question, right or wrong, with the session it tests (mod), whether it was right, and for a miss the kind of mistake (gap, flip, calc, or guess for a lucky right answer). The wrong answers then go through the tuition-miss workflow above. The 🧪 Test log turns this into a Dig in / Quick fix / Move on verdict per session.CHECKS[key][module] from the session’s own notes: why it works, what changes if an input moves, a fresh calculation, and an “explain it” prompt, never a plain definition. Keep each question id stable once published. Shaky and missed questions come back on a 1 / 3 / 7 / 14 / 30-day schedule. When processing comments, also check node tools/comments.mjs progress: a question that keeps coming back Shaky or Didn’t know is a gap to explain, and Teach-back comments (blurts and explain-it answers) get graded in the reply.formula blocks, but the concise notes are written by hand in EXAM: a reading overview (EXAM[key].about, paragraphs on what the reading covers and how its topics connect), and for each session a prose summary (s) plus linked key points (n). Concise means a real overview, not one-liners. In the same change that adds or edits a session (or a whole reading), Claude writes or updates the overview, that session’s summary and key points, adds any formula that only sits inside an example or point list as an f entry, and runs node tools/exam-check.mjs. The pre-commit hook (tools/hooks) stops a commit that leaves a session without exam notes or breaks a ↗ link, and the GitHub check re-runs it on every push.new: 'YYYY-MM-DD', and every new button or feature gets data-new="f-some-name". The page shows a NEW tag on it (and on the reading in the sidebar) until its first use: a block once it has been on screen, a feature once it is tapped. Small fixes to existing blocks are not tagged.index.html, the pre-commit hook writes out the staged copy (what will really be pushed, which differs from the working file when only part of the changes is committed) and runs node tools/page-check.mjs (script compiles, data evaluates, every block can render) and exam-check on it. Claude never bypasses the hook (--no-verify). When committing only part of the changes, Claude builds the staged copy by matching text, never with line-number patches, and runs page-check on it. After every push, Claude runs node tools/page-check.mjs --live, which waits for GitHub Pages to serve the new commit and checks it, and only then tells the user it’s live. The GitHub check also runs both checks and the live check on every push. The check also opens the page in headless Chrome and fails on any error at startup or when opening any reading or view. Top-level const/let must sit above the first render(); (the page draws at that line, so anything declared below it doesn’t exist yet), and optional widgets draw through safeHtml() so one broken widget can’t blank the page.