diff --git a/CLAUDE.md b/CLAUDE.md index 0021ad0..5897e5d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -163,8 +163,11 @@ decks never collide on import. - `EXPLANATIONS.md` — the editorial contract for agents asked to add or improve per-question explanations. The schema, the workflows ("explain everything unexplained", "improve everything below - confidence 7"), and the source/confidence guidance live there. - `explanations.json` is an empty `{}` until agents populate it. + confidence 7"), the source/confidence guidance, and the **MathJax + typesetting rules (§4a) with a verification sweep** live there. The + `$...$` typesetting is the most error-prone part of the file — read + §4a before touching any formula, and fix every occurrence in both the + explanation body and the `Hilfsmittel:` note. - Start from `DESIGN.md` — it has the JSON schema, the question/answer conventions (answer A is always correct upstream → consumers shuffle before display), the LaTeX-in-questions caveat, the exam-structure diff --git a/EXPLANATIONS.md b/EXPLANATIONS.md index 929708a..e9e63dd 100644 --- a/EXPLANATIONS.md +++ b/EXPLANATIONS.md @@ -156,13 +156,137 @@ source citation. rule of thumb. - **Math.** Use inline `$...$`; it's rewritten to MathJax on the card, same as for question text. Don't use display math `$$...$$` - (the deck has no MathJax support for those). + (the deck has no MathJax support for those). Getting the *inside* of + `$...$` right is its own discipline — see **§4a Math typesetting** + below. This is the single most error-prone part of this file. - **Inline emphasis.** `...` is the only HTML you should type by hand. Everything else gets HTML-escaped. - **No spoilers about other answers.** If a distractor is a common trap, naming the trap is fine; quoting the distractor's text is noise. +### 4a. Math typesetting (MathJax) — get this right + +Everything between `$...$` is TeX. MathJax renders **bare multi-letter +runs as a product of italic variables**, so `ohm` shows as *o·h·m*, +`log10` as *l·o·g·10*, `P_{PEP}` as *P·(P·E·P)*. A whole multi-round +review on this repo was spent fixing exactly these. The rules below are +the checklist; wrong → right. + +**Units** — never leave a unit as bare letters; wrap in `\text{}` (or use +the symbol) and put a thin space `\,` after the number: + +| Wrong (in `$...$`) | Right | +|---|---| +| `0.01 ohm`, `10 kOhm`, `5 MOhm` | `0.01\,\Omega`, `10\,\text{k}\Omega`, `5\,\text{M}\Omega` | +| `3 microhenry`, `3 uH` | `3\,\mu\text{H}` | +| `1 uF`, `100 nF`, `47 pF` | `1\,\mu\text{F}`, `100\,\text{nF}`, `47\,\text{pF}` | +| `5 mA`, `2 mV`, `1 kHz`, `28 MHz` | `5\,\text{mA}`, `2\,\text{mV}`, `1\,\text{kHz}`, `28\,\text{MHz}` | +| `12 dB`, `8 dBi`, `46.8 bit/s` | `12\,\text{dB}`, `8\,\text{dBi}`, `46.8\,\text{bit/s}` | +| `5 mm2`, `2.5 A/mm2` | `5\,\text{mm}^2`, `2.5\,\text{A/mm}^2` | +| `360 degrees`, `45°` | `360^\circ`, `45^\circ` | +| `20 A`, `12 V`, `100 W`, `5 m`, `50 s` | `20\,\text{A}`, `12\,\text{V}`, `100\,\text{W}`, `5\,\text{m}`, `50\,\text{s}` | + +**Operators, functions, Greek, powers:** + +| Wrong | Right | Why | +|---|---|---| +| `log10(x)` | `\log_{10}(x)` | bare `log` is *l·o·g* | +| `10^(20/10)` | `10^{20/10}` | `^(` superscripts only the `(`; braces group | +| `lambda`, `pi`, `tau`, `omega`, `rho`, `mu` | `\lambda`, `\pi`, `\tau`, … | bare = italic letters | +| `sin`, `cos`, `ln` | `\sin`, `\cos`, `\ln` | | +| `2 x 3`, `R1 || R2` | `2 \cdot 3`, `R_1 \parallel R_2` | `x`/`||` are not operators | +| `62.5%` | `62.5\%` | **bare `%` is a TeX comment — it silently eats the rest of the math** | +| `4,200,000` | `4{,}200{,}000` | bare `,` gets TeX punctuation spacing | + +**Subscripts.** Descriptive multi-letter labels/acronyms are roman; a +single-letter subscript stays italic: + +| Wrong | Right | +|---|---| +| `P_{EIRP}`, `U_{peak}`, `f_{mod}`, `V_{BE}`, `f_{sum}` | `P_\mathrm{EIRP}`, `U_\mathrm{peak}`, `f_\mathrm{mod}`, `V_\mathrm{BE}`, `f_\mathrm{sum}` | +| `R1/R2 = R3/R4` | `R_1/R_2 = R_3/R_4` | +| keep italic: `U_F`, `f_c`, `X_C`, `R_g` | (single letter = variable, leave as-is) | + +A standalone acronym used as a variable (e.g. `MUF` on a formula's LHS) +also goes roman: `\mathrm{MUF}`. + +**Dimensional constants keep their unit.** The field-strength constant is +`30\,\Omega`, so write `\sqrt{30\,\Omega \cdot P_\mathrm{EIRP}}` and +`(E\cdot d)^2/(30\,\Omega)`, not a bare `30`. Same idea for the dB-level +exponent: `10^{g/(10\,\text{dB})}` (the `(...)` groups the denominator — +`10^{g/10\,\text{dB}}` parses as `(g/10)·dB`). + +**Unit vs. variable — don't blindly unit-ize a single letter.** `A` is +amperes in `20 A` but *area* in `N^2 A/l`; `s`/`m` are seconds/metres in +`50 s` / `5 m` but could be variables elsewhere. The tell: a *free-standing +number* immediately before the letter (`20 A`) means a unit; an exponent +base (`N^2 A`) or a symbolic factor (`S \cdot A`) means a variable. When +unsure, read the sentence. + +**What stays prose — do NOT force into `$...$`:** + +- Band/wavelength designations: `5/8-wave`, `20/15/10 m trap dipole`, + `the 80 m band`. +- Conceptual word-equations: `1st overtone = 2nd harmonic`, + `Region 1 = Europe/Africa`. +- Units mentioned adjectivally in a sentence: "a 50 ohm antenna", + "the 28 V/m limit", "about 11.7 V/m". + +But a **worked computation with an `=`** (e.g. `230 V / 20 = 11.5 V`) +belongs in `$...$`, fully typeset. + +### Verifying it — the process lessons + +These review rounds kept finding *peers* of an already-fixed defect. +Avoid the repeat: + +1. **Fix the whole record, not a substring.** The same formula usually + appears in *both* the explanation body *and* the `Hilfsmittel:` note. + Search the entire entry and fix every occurrence. +2. **Fix the whole class, file-wide — not just the IDs someone listed.** + If `P_{EIRP}` is wrong in one card it is wrong in twenty; sweep the + whole file for the pattern. +3. **Verify with a positive sweep, not a blacklist.** A list of + known-bad tokens always misses a new category (it missed `degrees`, + `bit`, `||`, bare seconds…). Instead: strip `\text{}`/`\mathrm{}` and + the known macros, then flag *every remaining* ≥2-letter run inside + `$...$` — each survivor must be a deliberate variable product + (`LC`, `jX`, `RC`, `di/dt`) or it's a bug. +4. **Don't claim "0 / exhaustive" unless the check actually covers that + category.** Report what you checked, not a blanket adjective. + +A ready-made sweep: + +```sh +python3 -c ' +import json, re +d = json.load(open("explanations.json")) +span = re.compile(r"\$[^$]*\$") +def strip(s): + s = re.sub(r"\\(?:text|mathrm|operatorname)\{[^{}]*\}", " ", s) + return re.sub(r"\\[A-Za-z]+", " ", s) # drop macros (\sqrt, \pi, \cdot, ...) +for k, e in d.items(): + ex = e["explanation"] if isinstance(e, dict) else "" + if ex.count("$") % 2 or ex.count("{") != ex.count("}"): + print("BALANCE", k) + for m in span.finditer(ex): + s = m.group(0) + if re.search(r"(?