explico 0.11.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1292 -1
- package/README.md +91 -13
- package/dist/compiler/astro.d.ts +11 -4
- package/dist/compiler/astro.js +48 -15
- package/dist/compiler/cli.d.ts +27 -12
- package/dist/compiler/cli.js +96 -25
- package/dist/compiler/collections.d.ts +33 -2
- package/dist/compiler/collections.js +91 -19
- package/dist/compiler/content-schema.d.ts +31 -0
- package/dist/compiler/content-schema.js +82 -0
- package/dist/compiler/content-schemas.d.ts +422 -0
- package/dist/compiler/content-schemas.js +229 -0
- package/dist/compiler/course-config.d.ts +1 -1
- package/dist/compiler/course-config.js +30 -2
- package/dist/compiler/exports/combined-html.d.ts +97 -0
- package/dist/compiler/exports/combined-html.js +492 -0
- package/dist/compiler/exports/download-index.d.ts +9 -0
- package/dist/compiler/exports/download-index.js +33 -0
- package/dist/compiler/exports/export-chapters.d.ts +98 -0
- package/dist/compiler/exports/export-chapters.js +164 -0
- package/dist/compiler/exports/export-pages.d.ts +48 -0
- package/dist/compiler/exports/export-pages.js +22 -0
- package/dist/compiler/exports/html-tree.d.ts +22 -0
- package/dist/compiler/exports/html-tree.js +47 -0
- package/dist/compiler/exports/latex/capture.d.ts +106 -0
- package/dist/compiler/exports/latex/capture.js +435 -0
- package/dist/compiler/exports/latex/compile.d.ts +73 -0
- package/dist/compiler/exports/latex/compile.js +115 -0
- package/dist/compiler/exports/latex/document.d.ts +102 -0
- package/dist/compiler/exports/latex/document.js +349 -0
- package/dist/compiler/exports/latex/explico.cls +415 -0
- package/dist/compiler/exports/latex/numbering.d.ts +18 -0
- package/dist/compiler/exports/latex/numbering.js +57 -0
- package/dist/compiler/exports/latex/serialize.d.ts +112 -0
- package/dist/compiler/exports/latex/serialize.js +606 -0
- package/dist/compiler/exports/latex-export.d.ts +44 -0
- package/dist/compiler/exports/latex-export.js +169 -0
- package/dist/compiler/exports/markdown/serialize.d.ts +51 -0
- package/dist/compiler/exports/markdown/serialize.js +527 -0
- package/dist/compiler/exports/markdown-export.d.ts +39 -0
- package/dist/compiler/exports/markdown-export.js +240 -0
- package/dist/compiler/exports/standalone-html.d.ts +15 -5
- package/dist/compiler/exports/standalone-html.js +23 -51
- package/dist/compiler/exports/static-tree.d.ts +253 -0
- package/dist/compiler/exports/static-tree.js +625 -0
- package/dist/compiler/exports/zip.d.ts +16 -0
- package/dist/compiler/exports/zip.js +72 -0
- package/dist/compiler/lesson-derivation.d.ts +8 -2
- package/dist/compiler/lesson-derivation.js +6 -7
- package/dist/compiler/manifest.d.ts +115 -8
- package/dist/compiler/manifest.js +221 -39
- package/dist/compiler/render-diagnostics.d.ts +65 -0
- package/dist/compiler/render-diagnostics.js +56 -0
- package/dist/compiler/resolution-report.d.ts +3 -1
- package/dist/{course-config-Dsnri9Tk.d.ts → course-config-rRtME5UV.d.ts} +56 -13
- package/dist/curriculum/validation.d.ts +9 -3
- package/dist/curriculum/validation.js +35 -17
- package/dist/reference/base-abbreviations.d.mts +2 -2
- package/dist/reference/base-abbreviations.mjs +2 -2
- package/dist/reference/base-operators.d.mts +8 -2
- package/dist/reference/base-operators.mjs +8 -10
- package/dist/reference/base-roman-labels.d.mts +4 -3
- package/dist/reference/base-roman-labels.mjs +4 -3
- package/dist/reference/citation-format.d.mts +35 -0
- package/dist/reference/citation-format.mjs +74 -0
- package/dist/reference/consistency.d.ts +5 -9
- package/dist/reference/consistency.js +34 -38
- package/dist/reference/curriculum-alignment.js +3 -24
- package/dist/reference/derived-entries.d.ts +45 -0
- package/dist/reference/derived-entries.js +50 -0
- package/dist/reference/derived-notation.d.mts +125 -0
- package/dist/reference/derived-notation.mjs +121 -0
- package/dist/reference/diagram-fit.d.ts +45 -0
- package/dist/reference/diagram-fit.js +54 -0
- package/dist/reference/diagram-layout.d.ts +59 -10
- package/dist/reference/diagram-layout.js +85 -24
- package/dist/reference/diagrams-validate.d.ts +1 -1
- package/dist/reference/equations-validate.d.ts +1 -1
- package/dist/reference/equations-validate.js +26 -1
- package/dist/reference/equations.d.mts +27 -0
- package/dist/reference/equations.mjs +120 -22
- package/dist/reference/examples-validate.d.ts +1 -1
- package/dist/reference/figure-fit.d.ts +70 -0
- package/dist/reference/figure-fit.js +60 -0
- package/dist/reference/figure-pictures.d.ts +27 -0
- package/dist/reference/figure-pictures.js +49 -0
- package/dist/reference/figure-symbols.d.ts +32 -0
- package/dist/reference/figure-symbols.js +55 -0
- package/dist/reference/figures-validate.d.ts +1 -1
- package/dist/reference/gate-abbreviations.d.ts +1 -1
- package/dist/reference/gate-abbreviations.js +1 -1
- package/dist/reference/gate-course-rules.d.ts +4 -3
- package/dist/reference/gate-course-rules.js +9 -4
- package/dist/reference/gate-heading-length.d.ts +2 -0
- package/dist/reference/gate-heading-length.js +7 -5
- package/dist/reference/gate-heading-structure.js +26 -0
- package/dist/reference/gate-indices.d.ts +35 -0
- package/dist/reference/gate-indices.js +299 -0
- package/dist/reference/gate-math.d.ts +32 -2
- package/dist/reference/gate-math.js +68 -12
- package/dist/reference/gate-mdx-expression.d.ts +17 -0
- package/dist/reference/gate-mdx-expression.js +29 -0
- package/dist/reference/gate-non-chapter-pages.d.ts +39 -0
- package/dist/reference/gate-non-chapter-pages.js +156 -0
- package/dist/reference/gate-part-pages.d.ts +4 -2
- package/dist/reference/gate-part-pages.js +2 -1
- package/dist/reference/gate-prop-text.d.ts +28 -0
- package/dist/reference/gate-prop-text.js +106 -0
- package/dist/reference/gate-prose-notation.d.ts +3 -1
- package/dist/reference/gate-prose-notation.js +4 -2
- package/dist/reference/gate-retired-keys.d.ts +35 -0
- package/dist/reference/gate-retired-keys.js +58 -0
- package/dist/reference/gloss.d.ts +2 -0
- package/dist/reference/katex-measure.d.ts +17 -0
- package/dist/reference/katex-measure.js +223 -0
- package/dist/reference/keyed-float-validate.js +12 -0
- package/dist/reference/keyed-jsx-floats.d.mts +2 -2
- package/dist/reference/keyed-jsx-floats.mjs +11 -14
- package/dist/reference/lab-katex-validate.d.ts +43 -0
- package/dist/reference/lab-katex-validate.js +96 -0
- package/dist/reference/lab-math-scope.d.ts +1 -0
- package/dist/reference/lab-math-scope.js +13 -2
- package/dist/reference/lint-ignore.js +1 -1
- package/dist/reference/math-glyphs.d.mts +94 -2
- package/dist/reference/math-glyphs.mjs +851 -46
- package/dist/reference/mixed-content.d.ts +8 -3
- package/dist/reference/mixed-content.js +4 -2
- package/dist/reference/page-notation.d.ts +39 -7
- package/dist/reference/page-notation.js +62 -10
- package/dist/reference/raw-floats.mjs +37 -13
- package/dist/reference/references.d.ts +11 -1
- package/dist/reference/references.js +6 -0
- package/dist/reference/registry.js +115 -11
- package/dist/reference/rehype-fail-katex-errors.d.mts +9 -0
- package/dist/reference/rehype-fail-katex-errors.mjs +19 -0
- package/dist/reference/rehype-heading-anchors.mjs +11 -1
- package/dist/reference/remark-citation.mjs +0 -0
- package/dist/reference/remark-notation.mjs +275 -23
- package/dist/reference/render-lab-math.d.ts +13 -2
- package/dist/reference/render-lab-math.js +18 -6
- package/dist/reference/sections-validate.d.ts +28 -3
- package/dist/reference/sections-validate.js +31 -4
- package/dist/reference/sections.d.mts +24 -6
- package/dist/reference/sections.mjs +92 -17
- package/dist/reference/tables-validate.d.ts +1 -1
- package/dist/reference/tables-validate.js +24 -1
- package/dist/reference/text-measure.d.ts +10 -0
- package/dist/reference/text-measure.js +41 -0
- package/dist/reference/text-widths.d.ts +10 -0
- package/dist/reference/text-widths.js +1238 -0
- package/dist/reference/types.d.ts +64 -8
- package/dist/rules/catalog.js +223 -32
- package/dist/rules/in-effect.d.ts +1 -1
- package/dist/rules/rules.schema.json +100 -27
- package/dist/rules/settings.d.ts +1 -1
- package/dist/rules/settings.js +7 -0
- package/dist/session/PreferenceStore.d.ts +18 -1
- package/dist/session/PreferenceStore.js +29 -1
- package/docs/authoring/README.md +33 -21
- package/docs/authoring/agents.md +38 -7
- package/docs/authoring/components.md +115 -10
- package/docs/authoring/migrating.md +878 -0
- package/docs/authoring/notation.md +285 -30
- package/docs/authoring/retired.md +1 -0
- package/docs/authoring/structure-rules.md +84 -45
- package/docs/authoring/structure.md +67 -2
- package/docs/authoring/visualizations.md +167 -25
- package/package.json +12 -7
- package/src/compiler/astro.ts +72 -21
- package/src/compiler/cli.ts +143 -35
- package/src/compiler/collections.ts +158 -27
- package/src/compiler/content-schema.ts +108 -0
- package/src/compiler/content-schemas.ts +391 -0
- package/src/compiler/course-config.ts +86 -15
- package/src/compiler/exports/combined-html.ts +669 -0
- package/src/compiler/exports/download-index.ts +36 -0
- package/src/compiler/exports/export-chapters.ts +233 -0
- package/src/compiler/exports/export-pages.ts +44 -0
- package/src/compiler/exports/html-tree.ts +62 -0
- package/src/compiler/exports/latex/capture.ts +651 -0
- package/src/compiler/exports/latex/compile.ts +168 -0
- package/src/compiler/exports/latex/document.ts +479 -0
- package/src/compiler/exports/latex/explico.cls +415 -0
- package/src/compiler/exports/latex/numbering.ts +74 -0
- package/src/compiler/exports/latex/serialize.ts +787 -0
- package/src/compiler/exports/latex/texlive-packages.txt +76 -0
- package/src/compiler/exports/latex-export.ts +255 -0
- package/src/compiler/exports/markdown/serialize.ts +632 -0
- package/src/compiler/exports/markdown-export.ts +329 -0
- package/src/compiler/exports/standalone-html.ts +39 -70
- package/src/compiler/exports/static-tree.ts +944 -0
- package/src/compiler/exports/zip.ts +88 -0
- package/src/compiler/lesson-derivation.ts +13 -8
- package/src/compiler/manifest.ts +387 -40
- package/src/compiler/render-diagnostics.ts +111 -0
- package/src/components/CourseContents.astro +6 -0
- package/src/components/HoverPanel.astro +204 -6
- package/src/components/PartOverview.astro +18 -9
- package/src/components/abbreviation/AbbreviationGlossary.astro +6 -2
- package/src/components/abbreviation/AbbreviationLayer.astro +21 -12
- package/src/components/assessments/AssessmentRunner.tsx +7 -1
- package/src/components/assessments/AssessmentSet.astro +14 -1
- package/src/components/block-heading.ts +38 -0
- package/src/components/card-arrow.ts +18 -4
- package/src/components/card-carry.ts +406 -0
- package/src/components/card-drag.ts +1 -30
- package/src/components/card-fetch.ts +87 -0
- package/src/components/card-manager.ts +1222 -38
- package/src/components/card-memory.ts +5 -1
- package/src/components/card-placement.ts +211 -13
- package/src/components/card-side.ts +281 -31
- package/src/components/citation/CitationLayer.astro +45 -40
- package/src/components/diagram/Diagram.astro +123 -44
- package/src/components/disclosure/print-as-shown.ts +42 -6
- package/src/components/figure/Figure.astro +17 -1
- package/src/components/figure/FloatCaption.astro +4 -17
- package/src/components/figure/figure-state.ts +26 -17
- package/src/components/float-toolbar.ts +274 -0
- package/src/components/memo/Memo.astro +21 -10
- package/src/components/memo/ShortNote.astro +4 -0
- package/src/components/notation/NotationGlossary.astro +22 -17
- package/src/components/notation/NotationLayer.astro +300 -79
- package/src/components/notation/NotationMath.astro +8 -1
- package/src/components/notation/render-notation-math.ts +51 -5
- package/src/components/readable-text.ts +25 -0
- package/src/components/reference/FloatRefLayer.astro +162 -89
- package/src/components/starlight/HeadingAnchorEnhancer.astro +13 -8
- package/src/components/starlight/KeyedFloatEnhancer.astro +28 -9
- package/src/components/starlight/LayoutPageSidebar.astro +17 -3
- package/src/components/starlight/LayoutSocialIcons.astro +79 -29
- package/src/components/starlight/LessonExportActions.astro +384 -310
- package/src/components/starlight/LessonFooter.astro +66 -8
- package/src/components/starlight/PrintController.astro +28 -0
- package/src/components/starlight/TextSizeControl.astro +137 -0
- package/src/components/starlight/print-controller.ts +380 -0
- package/src/components/starlight/section-summary.ts +13 -5
- package/src/components/table/Table.astro +14 -22
- package/src/components/table/table-truncation.ts +15 -0
- package/src/content-config.ts +20 -312
- package/src/curriculum/validation.ts +72 -24
- package/src/reference/base-abbreviations.mjs +2 -2
- package/src/reference/base-operators.mjs +8 -10
- package/src/reference/base-roman-labels.mjs +4 -3
- package/src/reference/citation-format.mjs +74 -0
- package/src/reference/consistency.ts +47 -61
- package/src/reference/curriculum-alignment.ts +4 -41
- package/src/reference/derived-entries.ts +68 -0
- package/src/reference/derived-notation.mjs +121 -0
- package/src/reference/diagram-fit.ts +104 -0
- package/src/reference/diagram-layout.ts +182 -51
- package/src/reference/diagrams-validate.ts +2 -1
- package/src/reference/equations-validate.ts +41 -2
- package/src/reference/equations.mjs +120 -22
- package/src/reference/examples-validate.ts +1 -0
- package/src/reference/figure-fit.ts +139 -0
- package/src/reference/figure-pictures.ts +96 -0
- package/src/reference/figure-symbols.ts +117 -0
- package/src/reference/figures-validate.ts +2 -1
- package/src/reference/gate-abbreviations.ts +1 -1
- package/src/reference/gate-course-rules.ts +22 -7
- package/src/reference/gate-heading-length.ts +25 -7
- package/src/reference/gate-heading-structure.ts +40 -1
- package/src/reference/gate-indices.ts +470 -0
- package/src/reference/gate-math.ts +102 -13
- package/src/reference/gate-mdx-expression.ts +45 -0
- package/src/reference/gate-non-chapter-pages.ts +241 -0
- package/src/reference/gate-part-pages.ts +1 -1
- package/src/reference/gate-prop-text.ts +145 -0
- package/src/reference/gate-prose-notation.ts +19 -5
- package/src/reference/gate-retired-keys.ts +101 -0
- package/src/reference/gloss.ts +2 -0
- package/src/reference/katex-measure.ts +384 -0
- package/src/reference/keyed-float-validate.ts +22 -0
- package/src/reference/keyed-jsx-floats.mjs +11 -14
- package/src/reference/lab-katex-validate.ts +156 -0
- package/src/reference/lab-math-scope.ts +15 -1
- package/src/reference/lint-ignore.ts +4 -1
- package/src/reference/math-glyphs.mjs +851 -46
- package/src/reference/mixed-content.ts +11 -2
- package/src/reference/page-notation.ts +114 -14
- package/src/reference/raw-floats.mjs +37 -13
- package/src/reference/references.ts +14 -0
- package/src/reference/registry.ts +170 -9
- package/src/reference/rehype-fail-katex-errors.mjs +19 -0
- package/src/reference/rehype-heading-anchors.mjs +11 -1
- package/src/reference/remark-citation.mjs +0 -0
- package/src/reference/remark-notation.mjs +275 -23
- package/src/reference/render-lab-math.ts +40 -5
- package/src/reference/sections-validate.ts +67 -3
- package/src/reference/sections.mjs +92 -17
- package/src/reference/tables-validate.ts +40 -2
- package/src/reference/text-measure.ts +63 -0
- package/src/reference/text-widths.ts +133 -0
- package/src/reference/types.ts +75 -8
- package/src/rules/catalog.ts +241 -31
- package/src/rules/settings.ts +10 -0
- package/src/session/PreferenceStore.ts +53 -0
- package/src/styles/global.css +322 -83
|
@@ -77,6 +77,8 @@ _How to apply._
|
|
|
77
77
|
(thin space, then `\mathrm{d}x`), `\dfrac{\mathrm{d}f}{\mathrm{d}x}`,
|
|
78
78
|
`\dfrac{\mathrm{d}^2 f}{\mathrm{d}x^2}`, `\mathrm{d}s`, `\mathrm{d}A`,
|
|
79
79
|
`\mathrm{d}t`. An italic `d` is always a variable (a distance, a day count).
|
|
80
|
+
The resolver still reads a bare `d` as the differential (the base library,
|
|
81
|
+
[N4](#n4)), so an italic one does not fail the build: a reviewer catches it.
|
|
80
82
|
This is the ISO 80000-2 convention, and it keeps the differential clear of a
|
|
81
83
|
lesson that binds `d`. A partial derivative uses `\partial` bare —
|
|
82
84
|
`\dfrac{\partial f}{\partial x}` — which is already distinct; do not wrap
|
|
@@ -122,8 +124,8 @@ _Rationale._ This is the core contract the completeness gate enforces
|
|
|
122
124
|
corpus-wide; the rule here is just its author-facing statement. A reader hovers
|
|
123
125
|
any symbol and gets exactly one card.
|
|
124
126
|
|
|
125
|
-
_How to apply._ See the
|
|
126
|
-
|
|
127
|
+
_How to apply._ See the `notation` collection schema
|
|
128
|
+
(`src/compiler/content-schemas.ts`). A letter that exists only so one entry's own `formula` can
|
|
127
129
|
be stated is a **gloss**, not a card — it creates no curriculum edge.
|
|
128
130
|
|
|
129
131
|
Do not satisfy this rule by dumping every `[[key]]` a page uses into one
|
|
@@ -152,6 +154,12 @@ the body — otherwise the build fails with "Stale Explico manifest for
|
|
|
152
154
|
[…]." So every local entry still needs one `\explain{key}{…}` (or `[[key]]`)
|
|
153
155
|
mention, even though the math gate alone wouldn't ask for it.
|
|
154
156
|
|
|
157
|
+
A local entry's key is its own: one that equals a shared entry's key wins on
|
|
158
|
+
its page, so `[[key]]` would mean one thing there and another in the
|
|
159
|
+
glossary and on every other page. `pnpm validate:content` warns
|
|
160
|
+
(`local-shadows-shared`); give the local entry a key of its own, or use the
|
|
161
|
+
shared one.
|
|
162
|
+
|
|
155
163
|
The auto-annotator (`resolveMathGlyphs` in `math-glyphs.mjs`) re-derives every
|
|
156
164
|
`\explain{…}` marker's insertion point from KaTeX's own parsed offsets, then
|
|
157
165
|
re-applies those offsets to the raw source. Three shapes used to corrupt that
|
|
@@ -220,12 +228,51 @@ lesson and supplied component/formula context; a final Astro build check also
|
|
|
220
228
|
rejects any `data-notation-key` in generated HTML that has no matching
|
|
221
229
|
`data-notation-entry` source.
|
|
222
230
|
|
|
231
|
+
**Indexed symbols.** How the resolver binds a symbol with a subscript is part
|
|
232
|
+
of this rule and always on; [N23](#n23) builds on it. A whole form wins under
|
|
233
|
+
a power or a mark (`v_0^{2}` is `v_0` squared). An instance takes its
|
|
234
|
+
family's card ahead of a plain entry for its base (`x_1` opens the `x_k`
|
|
235
|
+
card), and only from a family whose index has the same shape. An indexed
|
|
236
|
+
entry lends its card to no bare symbol: a family (`\alpha_i`) explains its
|
|
237
|
+
own instances only, and an entry with a fixed index (`v_0`, `H_0`) only
|
|
238
|
+
itself. A bare `\alpha` that had a card only by borrowing one fails
|
|
239
|
+
`unresolved-glyph`, and the message names the indexed entry with that base:
|
|
240
|
+
give it its own entry, or `\explain{key}{\alpha}` where it really is the
|
|
241
|
+
family's shorthand. A function form still lends by its head (`V_0(1_t)`
|
|
242
|
+
explains `V_0(1_2)`), and an entry with only a superscript (`j^{(m)}`) still
|
|
243
|
+
lends to its base.
|
|
244
|
+
|
|
245
|
+
**A definition that is a convention.** Some definitions are one of several in
|
|
246
|
+
use: the sign on a moving-average coefficient, kurtosis with or without the
|
|
247
|
+
Gaussian 3 subtracted, information per observation or per sample, whom a cash
|
|
248
|
+
flow is positive for. The mathematics is the same and only the choice differs,
|
|
249
|
+
so a formula brought in from a source that chose the other way gives a wrong
|
|
250
|
+
answer and no error. Such an entry is defined once and cited with `[[key]]`
|
|
251
|
+
like any other, and it also says that it is a choice: its `meaning` names the
|
|
252
|
+
other choice in a clause, so the card warns where the symbol is used, and its
|
|
253
|
+
body says how to convert. A definition nobody writes differently (a residual
|
|
254
|
+
as observed minus fitted) is not a convention and needs neither. This part is
|
|
255
|
+
a guide; no check reads it.
|
|
256
|
+
|
|
257
|
+
```md
|
|
258
|
+
---
|
|
259
|
+
key: ma.coefficient
|
|
260
|
+
latex: \theta
|
|
261
|
+
meaning: Weight on the lagged innovation, added to the current one; Box–Jenkins and statsmodels subtract it instead.
|
|
262
|
+
---
|
|
263
|
+
A formula from a source that subtracts the term holds for this course's
|
|
264
|
+
$\theta$ after replacing $\theta$ with $-\theta$.
|
|
265
|
+
```
|
|
266
|
+
|
|
223
267
|
_Enforcement._ Build-enforced. The completeness gate (`gate-math.ts`, `pnpm
|
|
224
268
|
validate:content`; `astro build` re-runs the same resolver) fails on an
|
|
225
269
|
unresolved glyph (`unresolved-glyph`) in every rendered-math context;
|
|
226
270
|
`consistency.ts` adds the corpus-level lints `glyph-unique-in-corpus`
|
|
227
271
|
(warning), `weak-local`, `gloss-wants-promoting`, `card-wants-demoting`
|
|
228
|
-
(info); a final rendered-trigger/payload parity check backs it at render time
|
|
272
|
+
(info); a final rendered-trigger/payload parity check backs it at render time,
|
|
273
|
+
and a last pass over every built page fails a symbol a figure shows that KaTeX
|
|
274
|
+
drew outside a notation binding (`figure-symbols.ts`: a lab that called KaTeX
|
|
275
|
+
itself — see [V3](visualizations.md#v3)).
|
|
229
276
|
This rule is **locked** — the notation layer is this rule, so a course cannot
|
|
230
277
|
turn it off.
|
|
231
278
|
|
|
@@ -260,8 +307,17 @@ stripped before KaTeX like the label, heads the `[[eq-…]]` preview card and
|
|
|
260
307
|
names the copy action ("Copy LaTeX — Range formula"). An equation takes no
|
|
261
308
|
long caption ([components.md § The caption pair](components.md#the-caption-pair)).
|
|
262
309
|
|
|
310
|
+
A `$$…$$` block is one numbered equation, so it takes one label: to refer to
|
|
311
|
+
two rows, give each its own block. LaTeX's own numbering tools have no place
|
|
312
|
+
in it — the block already is the display, and the engine numbers it — so
|
|
313
|
+
`\begin{align}`, `\begin{equation}`, `\begin{gather}` and `\tag{…}` fail
|
|
314
|
+
with what to write instead (the rows of an `align` go in `\begin{aligned}`),
|
|
315
|
+
and so do `\eqref{…}`, `\ref{…}` and a `\label` without `eq:`: a reference
|
|
316
|
+
is `[[eq-key]]` in the prose.
|
|
317
|
+
|
|
263
318
|
_Enforcement._ Partial. The converse is checked: `equations-validate.ts`
|
|
264
|
-
reports `eq-key-unused` (info) for a labelled equation nothing references
|
|
319
|
+
reports `eq-key-unused` (info) for a labelled equation nothing references,
|
|
320
|
+
and `eq-label-repeated` (an error) for a second `\label` in one block.
|
|
265
321
|
An unlabelled-but-referenced equation builds; a reviewer catches the
|
|
266
322
|
hand-numbering.
|
|
267
323
|
|
|
@@ -389,14 +445,14 @@ next to it was invisible to every check until this rule.
|
|
|
389
445
|
_How to apply._
|
|
390
446
|
|
|
391
447
|
- A table header cell that names a quantity uses the same bound symbol the
|
|
392
|
-
lesson already introduced,
|
|
393
|
-
|
|
394
|
-
`
|
|
395
|
-
|
|
396
|
-
|
|
448
|
+
lesson already introduced, with its unit folded into the same span as a
|
|
449
|
+
`\text{}` suffix. A component takes its subscript the way [N23](#n23)
|
|
450
|
+
asks: an index entry `{}_x` makes `v_x` one derived card, "Horizontal
|
|
451
|
+
component of velocity". An `\explain{motion.velocity}{v_x}` wrap fails
|
|
452
|
+
`index-swallowed`, since that card describes the vector:
|
|
397
453
|
|
|
398
454
|
```text
|
|
399
|
-
| $t\ \text{(s)}$ |
|
|
455
|
+
| $t\ \text{(s)}$ | $v_x\ \text{(m/s)}$ |
|
|
400
456
|
```
|
|
401
457
|
|
|
402
458
|
- An absolute value or norm is `\lvert…\rvert`, never a literal `|` — a raw
|
|
@@ -474,6 +530,12 @@ as a hard error with no Tier-3 warming-up period and no `lint-ignore.yml`
|
|
|
474
530
|
entry, because each part landed in the same change that brought the whole
|
|
475
531
|
corpus to zero — see the two files for the exact patterns.
|
|
476
532
|
|
|
533
|
+
A currency amount is prose too, its dollar escaped: `\$5 to \$6`. remark-math
|
|
534
|
+
pairs any two unescaped `$` on a line, so `$5 to $6` is one math span that
|
|
535
|
+
shows "5 to", dollars gone; `pnpm validate:content` fails such a pair
|
|
536
|
+
(`currency-dollar`, invariant `math-syntax`) — one whose content starts with
|
|
537
|
+
a digit and ends in a space or runs into a digit.
|
|
538
|
+
|
|
477
539
|
_Settings._ `rules.N9.allow` in the course settings lists unit words the
|
|
478
540
|
course lets prose spell out (`["hour", "minute"]`), singular or plural; a
|
|
479
541
|
phrase is skipped only when every unit word in it is allowed.
|
|
@@ -519,11 +581,13 @@ _How to apply._
|
|
|
519
581
|
itself a notation key stays a key.
|
|
520
582
|
|
|
521
583
|
- A generic qualifier that functions like an operator's extremum subscript —
|
|
522
|
-
`x_{\mathrm{opt}}`, an "optimal" reading with no quantity of its own —
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
584
|
+
`x_{\mathrm{opt}}`, an "optimal" reading with no quantity of its own —
|
|
585
|
+
needs no card of its own under this rule. The symbol it indexes still does
|
|
586
|
+
([N23](#n23)): a whole form `x_{\mathrm{opt}}`, or an index entry
|
|
587
|
+
`{}_{\mathrm{opt}}`. The full baseline is the greppable set in
|
|
588
|
+
`base-roman-labels.mjs`, kept deliberately small: unlike a trig function,
|
|
589
|
+
an upright label is almost always a named quantity specific to one course,
|
|
590
|
+
so it defaults to needing a card rather than defaulting to universal.
|
|
527
591
|
|
|
528
592
|
- A named quantity gets a notation entry, exactly like a glyph ([N4](#n4)) —
|
|
529
593
|
a shared card if the course teaches it broadly, otherwise `notation.local`,
|
|
@@ -691,7 +755,7 @@ resolves, table cells and component slots included — and
|
|
|
691
755
|
`gateMathPunctuationInAssessments` every assessment `prompt` /
|
|
692
756
|
`explanation`. It flags a `.`, `,`, `;` or `:` that is the last visible
|
|
693
757
|
thing in the span, or in a row before a `\\`. It looks through what renders
|
|
694
|
-
nothing there: spacing (`\,`, `\quad`), `\label{…}` / `\
|
|
758
|
+
nothing there: spacing (`\,`, `\quad`), `\label{…}` / `\caption{…}`, a row
|
|
695
759
|
break, `\end{…}`, the null delimiter `\right.`. It looks into a closing
|
|
696
760
|
`\text{…}` / `\mathrm{…}`, so `5\ \text{m,}` is caught. A finding is located
|
|
697
761
|
at the mark, so a per-place waiver can cover it.
|
|
@@ -1021,7 +1085,9 @@ or `a = b \le c` — write it as an `aligned` block. The first line carries the
|
|
|
1021
1085
|
left-hand side. Every later line starts with `&` directly before its relation
|
|
1022
1086
|
(`&=`, `&\le`, `&\approx`, `&\propto`), so the relation signs stand in one
|
|
1023
1087
|
column. A step that needs a reason gets it at the end of its own line, after
|
|
1024
|
-
`\qquad` (or `\quad` when the line is tight), inside `\text{…}
|
|
1088
|
+
`\qquad` (or `\quad` when the line is tight), inside `\text{…}`. A `\quad`
|
|
1089
|
+
clause that names an index and its set, `\quad i = 1, \dots, n`, is
|
|
1090
|
+
[N23](#n23)'s set statement, not a reason:
|
|
1025
1091
|
|
|
1026
1092
|
```text
|
|
1027
1093
|
$$
|
|
@@ -1131,7 +1197,9 @@ _Enforcement._ Build-enforced (`consistency.ts` `checkNotationUnits`,
|
|
|
1131
1197
|
and `units-vocab` (a token outside the vocabulary).
|
|
1132
1198
|
|
|
1133
1199
|
_Exceptions._ A `lint-ignore.yml` entry (`- notation-units:<key> — <reason>`)
|
|
1134
|
-
for a symbol whose unit is genuinely context-dependent.
|
|
1200
|
+
for a symbol whose unit is genuinely context-dependent. An index entry
|
|
1201
|
+
(`latex: "{}_0"`, [N23](#n23)) takes no units at all: a subscript has none,
|
|
1202
|
+
and the derived card it makes takes the indexed symbol's.
|
|
1135
1203
|
|
|
1136
1204
|
## N20
|
|
1137
1205
|
|
|
@@ -1165,33 +1233,33 @@ definition table) may cite the whole; say so in the locator (`"whole"`).
|
|
|
1165
1233
|
|
|
1166
1234
|
**A gloss is named by a short noun phrase, not described by a sentence.**
|
|
1167
1235
|
|
|
1168
|
-
A gloss binds a symbol on one page with a `
|
|
1169
|
-
|
|
1236
|
+
A gloss binds a symbol on one page with a `name` shown in the hover card. The
|
|
1237
|
+
name *names* the symbol; it does not explain it.
|
|
1170
1238
|
|
|
1171
1239
|
```yaml
|
|
1172
1240
|
# A name.
|
|
1173
|
-
-
|
|
1174
|
-
|
|
1241
|
+
- latex: \theta
|
|
1242
|
+
name: launch angle
|
|
1175
1243
|
|
|
1176
|
-
# A description — belongs in a full notation entry's body, not a gloss
|
|
1177
|
-
-
|
|
1178
|
-
|
|
1244
|
+
# A description — belongs in a full notation entry's body, not a gloss name.
|
|
1245
|
+
- latex: \theta
|
|
1246
|
+
name: the angle between the launch velocity and the horizontal, which we vary
|
|
1179
1247
|
```
|
|
1180
1248
|
|
|
1181
1249
|
_Rationale._ A gloss is the lightweight form: a name and a glyph. Once the
|
|
1182
|
-
|
|
1250
|
+
name grows a clause or a sentence it is doing a notation entry's job without
|
|
1183
1251
|
that entry's units, sources, or shared identity — and the card shows a wall of
|
|
1184
1252
|
text where every other card shows a name.
|
|
1185
1253
|
|
|
1186
|
-
_How to apply._ Keep the
|
|
1254
|
+
_How to apply._ Keep the name to a few words with no sentence punctuation or
|
|
1187
1255
|
relative clause. If the symbol needs a description, promote the gloss to a
|
|
1188
1256
|
notation entry (the `gloss-wants-promoting` hint under N4 says when).
|
|
1189
1257
|
|
|
1190
1258
|
_Enforcement._ Build-enforced (`consistency.ts` `checkGlossNameShape`, `pnpm
|
|
1191
|
-
validate:content`) — warning `gloss-name-shape` for a
|
|
1259
|
+
validate:content`) — warning `gloss-name-shape` for a name over the word
|
|
1192
1260
|
limit or containing sentence punctuation / a relative clause.
|
|
1193
1261
|
|
|
1194
|
-
_Exceptions._ None — a
|
|
1262
|
+
_Exceptions._ None — a name that cannot be short is a notation entry.
|
|
1195
1263
|
|
|
1196
1264
|
---
|
|
1197
1265
|
|
|
@@ -1292,6 +1360,7 @@ operator on the page, and why.
|
|
|
1292
1360
|
|
|
1293
1361
|
| Code | Severity | When |
|
|
1294
1362
|
| --- | --- | --- |
|
|
1363
|
+
| `accent-swallowed` | warning | `\explain{key}{\hat{\beta}}` names a key whose own `latex` has no `\hat`, so its card cannot explain the hat |
|
|
1295
1364
|
| `suspended-operator-unresolved` | error | a decorated form of a suspended decoration has no whole form |
|
|
1296
1365
|
| `operator-suspended` | info | a suspension with a `reason` — recorded, nothing to fix |
|
|
1297
1366
|
| `operator-suspension-reason` | warning | a suspension without a `reason` |
|
|
@@ -1305,7 +1374,12 @@ _Enforcement._ Tier-3 warning `accent-explained` (`consistency.ts`
|
|
|
1305
1374
|
`checkAccentExplained`) for a decoration that composes with no operator entry
|
|
1306
1375
|
and is not on the allow list, one per decoration per lesson, surfaced by `pnpm
|
|
1307
1376
|
validate:content` and silenced only by a reviewed line in `lint-ignore.yml`
|
|
1308
|
-
(`accent-explained:\hat — <reason>`).
|
|
1377
|
+
(`accent-explained:\hat — <reason>`). The same function warns
|
|
1378
|
+
`accent-swallowed` for an `\explain{key}{…}` around a decorated form whose
|
|
1379
|
+
key's `latex` lacks that decoration (`\explain{beta}{\hat{\beta}}`): the wrap
|
|
1380
|
+
counts as the whole form, but its card says nothing about the hat. Wrap only
|
|
1381
|
+
the letter (`\hat{\explain{beta}{\beta}}`) and explain the hat, or name an entry
|
|
1382
|
+
for `\hat{\beta}`. Suspension is build-enforced: the
|
|
1309
1383
|
completeness gate (`gate-math.ts`) and the render path (`remark-notation.mjs`)
|
|
1310
1384
|
both fail `suspended-operator-unresolved`; `checkOperatorSuspension` emits the
|
|
1311
1385
|
other three codes.
|
|
@@ -1313,3 +1387,184 @@ other three codes.
|
|
|
1313
1387
|
_Exceptions._ Suspension (above) is the sanctioned way to give a decoration a
|
|
1314
1388
|
different meaning on one page. Quoting a source that uses a decoration
|
|
1315
1389
|
differently **and** showing what it means in the same passage.
|
|
1390
|
+
|
|
1391
|
+
## N23
|
|
1392
|
+
|
|
1393
|
+
**An index is part of the symbol: a subscript is explained by the indexed
|
|
1394
|
+
symbol's entry, a family entry, or an index entry.**
|
|
1395
|
+
|
|
1396
|
+
`\mathbf{v}_0` is the initial velocity, not the velocity: hovering it must
|
|
1397
|
+
say so. A subscript on a symbol is explained in one of three ways, and a card
|
|
1398
|
+
on the base alone does not count. If more than one applies, the first wins,
|
|
1399
|
+
the same precedence [N22](#n22) uses for decorations:
|
|
1400
|
+
|
|
1401
|
+
1. **Whole form** — the indexed symbol is a quantity of its own. Give it its
|
|
1402
|
+
own entry; that form gets that card, under a power too (`v_0^{2}` is `v_0`
|
|
1403
|
+
squared):
|
|
1404
|
+
|
|
1405
|
+
```yaml
|
|
1406
|
+
key: initial-velocity
|
|
1407
|
+
latex: \mathbf{v}_0
|
|
1408
|
+
label: Initial velocity
|
|
1409
|
+
```
|
|
1410
|
+
|
|
1411
|
+
2. **Family** — the entry's index is a running letter: `latex: x_k`, "k-th
|
|
1412
|
+
iterate". It gives its card to every instance with the same shape — the
|
|
1413
|
+
same base and number of comma-separated slots: `x_1`, `x_{k+1}`, `x_N` —
|
|
1414
|
+
ahead of a plain `x` entry, and never to a bare `x`, which is a different
|
|
1415
|
+
object (it needs its own entry, or an `\explain{key}{x}` where it really
|
|
1416
|
+
is shorthand). A digit fills a running slot, but a `\mathrm{…}` or
|
|
1417
|
+
`\text{…}` label never does: `x_{\mathrm{e}}` is not an instance of
|
|
1418
|
+
`x_k`. Two families on one base that both fit an instance fail
|
|
1419
|
+
`ambiguous-base-fallback`: keep one per page, or `\explain` the instance.
|
|
1420
|
+
An entry whose index is fixed (`v_0`, `H_1`, `T_{\mathrm{opt}}`, or one
|
|
1421
|
+
marked `fixedIndex: true`) is a single symbol and lends its card to
|
|
1422
|
+
nothing. A function form still lends by its head: `V_0(1_t)` explains
|
|
1423
|
+
`V_0(1_2)`.
|
|
1424
|
+
|
|
1425
|
+
3. **Index entry** — the subscript means the same thing on every symbol of
|
|
1426
|
+
the page. Give the subscript alone an entry: `latex` is the subscript on
|
|
1427
|
+
an empty group, quoted, because a bare `{}` starts a YAML mapping.
|
|
1428
|
+
|
|
1429
|
+
```yaml
|
|
1430
|
+
key: motion.initial
|
|
1431
|
+
latex: "{}_0"
|
|
1432
|
+
label: Initial value
|
|
1433
|
+
meaning: The value of a quantity at the start of the scenario, the instant when time is zero.
|
|
1434
|
+
reads: "{base} evaluated at t = 0"
|
|
1435
|
+
formula: "{base}_0 = {base}\\,(\\explain{motion.time}{t} = 0)"
|
|
1436
|
+
```
|
|
1437
|
+
|
|
1438
|
+
With the entry of the symbol it indexes, it makes a **derived card**: the
|
|
1439
|
+
whole `\mathbf{v}_0` is one target, titled "Velocity vector evaluated at
|
|
1440
|
+
t = 0". Its summary is the index entry's `meaning`, never the base's; its
|
|
1441
|
+
formula is the index entry's `formula` with `{base}` bound to the base
|
|
1442
|
+
symbol, so the reader opens the base's card from it; its units are the
|
|
1443
|
+
base's. `reads` defaults to "`<label>` of `{base}`" ("Horizontal component
|
|
1444
|
+
of velocity"); it names the symbol with `{base}` and is plain prose, with
|
|
1445
|
+
no `$`, `\` or backtick. An index entry is listed with a square for the
|
|
1446
|
+
symbol, `□₀`; a derived card is never listed. The loader rejects `units`,
|
|
1447
|
+
`dimensionless`, `range` or `fixedIndex` on an index entry ([N19](#n19)
|
|
1448
|
+
does not apply), and `reads` on any other entry. Two index entries for the
|
|
1449
|
+
same subscript on one page fail `ambiguous-canonical-notation`: an index
|
|
1450
|
+
has one meaning per page.
|
|
1451
|
+
|
|
1452
|
+
Arithmetic on an index letter with its own card is explained already:
|
|
1453
|
+
`X_{t-1}` is `X`'s card, `t`'s card (`time.index`) and an offset, and every
|
|
1454
|
+
comma-separated slot needs such a letter (`F_{0,T}` needs the `0`
|
|
1455
|
+
explained). A letter in a subscript is an index, so a base-library `i`, `e`
|
|
1456
|
+
or `d` there needs a card too.
|
|
1457
|
+
|
|
1458
|
+
A subscript on an operator or a bracket is not an index: `\sum_{i=1}`,
|
|
1459
|
+
`\lim_{t \to 0}`, `\log_{10}`, `\lVert x\rVert_2`, `\left.f\right\rvert_{x=0}`.
|
|
1460
|
+
A superscript is a power (`y^{(m)}` is out of scope). An entry whose `latex`
|
|
1461
|
+
has a superscript and no subscript (`j^{(m)}`) is a whole form for that
|
|
1462
|
+
symbol and, having no index, still lends its card to its bare base.
|
|
1463
|
+
|
|
1464
|
+
### Running and fixed indices
|
|
1465
|
+
|
|
1466
|
+
A **running** index is a lowercase letter (`i`, `k`, `t`) that ranges over a
|
|
1467
|
+
set; the rule asks for that set, in one of two places:
|
|
1468
|
+
|
|
1469
|
+
- on the letter's card, or on the family entry that covers it, as `range`
|
|
1470
|
+
(LaTeX, shown on the card as "Runs over …"):
|
|
1471
|
+
|
|
1472
|
+
```yaml
|
|
1473
|
+
key: time.index
|
|
1474
|
+
latex: t
|
|
1475
|
+
range: "1, \\dots, T"
|
|
1476
|
+
```
|
|
1477
|
+
|
|
1478
|
+
- after a `\quad` on the first display line where the letter is an index,
|
|
1479
|
+
for a set that belongs to the page:
|
|
1480
|
+
|
|
1481
|
+
```latex
|
|
1482
|
+
x_i \sim \mathcal{N}(\mu,\ \sigma^2), \quad i = 1, \dots, n
|
|
1483
|
+
```
|
|
1484
|
+
|
|
1485
|
+
The clause names the letter and a relation (`=`, `\in`, `\le`, `\dots`, …).
|
|
1486
|
+
It is a different slot from [N18](#n18)'s `\qquad` reason.
|
|
1487
|
+
|
|
1488
|
+
A **fixed** index names one member: digits, a `\mathrm{…}` or `\text{…}`
|
|
1489
|
+
label, a subscript an index entry declares (`{}_x`), or a letter whose card
|
|
1490
|
+
says `fixedIndex: true` (a component `x`, a label). An uppercase or Greek
|
|
1491
|
+
letter in a subscript (`X_N`, `p_\theta`) is a size or a symbol, not a
|
|
1492
|
+
running index, and needs no set.
|
|
1493
|
+
|
|
1494
|
+
### `\explain` around an indexed symbol
|
|
1495
|
+
|
|
1496
|
+
`\explain{key}{v_x}` makes the whole `v_x` one target with `key`'s card. If
|
|
1497
|
+
`key`'s own `latex` has no index (`motion.velocity` is `v(t)`), that card
|
|
1498
|
+
cannot explain the `x`, and the wrap hides the gap from the resolver: the
|
|
1499
|
+
rule reports it. Give the subscript an index entry (`{}_x`) and drop the wrap,
|
|
1500
|
+
or name an entry for the indexed symbol. An index inside a larger wrap
|
|
1501
|
+
(`\explain{survival-probability}{S(0,t_i)}`) is the wrap's, as every glyph
|
|
1502
|
+
inside one is.
|
|
1503
|
+
|
|
1504
|
+
| Code | Severity | When |
|
|
1505
|
+
| --- | --- | --- |
|
|
1506
|
+
| `index-explained` | error | a subscript on a symbol has no whole form, family or index entry, and a slot has no letter with its own card — a digit, a label, a base-library letter — or the base itself has no card |
|
|
1507
|
+
| `index-swallowed` | error | `\explain{key}{X_i}` names a key whose `latex` has no index |
|
|
1508
|
+
| `index-range` | error | a running index letter's card (and the family entry over it) has no `range`, and the first display line where it is an index has no `\quad` clause stating its set |
|
|
1509
|
+
| `derived-key-taken` | error | an authored entry's key equals a derived card's, `<base>.sub.<index>` |
|
|
1510
|
+
|
|
1511
|
+
In a lesson body each is reported once per indexed form (per letter, for
|
|
1512
|
+
`index-range`) per page, at its line; a `notation.local` formula counts with
|
|
1513
|
+
its page. An assessment counts on its own, and a shared entry's formula once
|
|
1514
|
+
per formula, with no line.
|
|
1515
|
+
|
|
1516
|
+
**Where the rule applies.** Everywhere math is rendered:
|
|
1517
|
+
|
|
1518
|
+
| Where | Derived cards | Checked by |
|
|
1519
|
+
| --- | --- | --- |
|
|
1520
|
+
| Lesson body (and a page that is not a chapter) | yes | `validate:content` (all four codes) |
|
|
1521
|
+
| Assessment prompt, explanation, option | yes | `validate:content` (`index-explained`, `index-swallowed`) |
|
|
1522
|
+
| Lab math (`renderLabMath` with a `labMathScope` table) | yes | `astro build`, as the lab renders |
|
|
1523
|
+
| `<Diagram>` node formula | yes | `astro build`, as the diagram renders |
|
|
1524
|
+
| Notation entry `formula:` | no | `validate:content` (`index-explained`, `index-swallowed`) |
|
|
1525
|
+
|
|
1526
|
+
A notation formula resolves against its own card's table, so an index entry
|
|
1527
|
+
does not compose there. Explain an indexed symbol in a formula with a whole
|
|
1528
|
+
form instead: `\explain{motion.launch-speed}{v_0}`, or a gloss on the entry
|
|
1529
|
+
(`glosses:` with `latex: v_0` and its `name`, as in [N21](#n21)). Or wrap the subscript in the index entry's key,
|
|
1530
|
+
`\mathbf{v}_{\explain{motion.initial}{0}}`, which gives the `0` that card.
|
|
1531
|
+
`index-range` reads lesson bodies only: a letter's set is stated once, on its
|
|
1532
|
+
card or on the page.
|
|
1533
|
+
|
|
1534
|
+
_Rationale._ The resolver binds a letter by its shape, so before this rule a
|
|
1535
|
+
subscript inherited whatever its base meant: `\mathbf{v}_0` opened "Velocity
|
|
1536
|
+
vector", with only the `v` highlighted and the `0` explained by nothing. An
|
|
1537
|
+
indexed entry also lent its card to symbols it is not: the family `\alpha_i`
|
|
1538
|
+
("ARCH coefficient") opened on a bare `\alpha` meaning a learning rate, and
|
|
1539
|
+
`H_0` ("Null hypothesis") on `H_1`. A printed book's list of symbols makes
|
|
1540
|
+
the same split this rule does: `v_0` when it is a named quantity, and a
|
|
1541
|
+
"Subscripts" group that gives `0` once when it means the same thing on many
|
|
1542
|
+
symbols. And a running index without its set is a familiar omission: the
|
|
1543
|
+
reader cannot tell whether `i` runs to `n` or to `N`.
|
|
1544
|
+
|
|
1545
|
+
_How to apply._ For each reported form, pick the first that fits: a whole
|
|
1546
|
+
form for a named quantity, a family for a running index, an index entry for a
|
|
1547
|
+
subscript that recurs with one meaning. The same index on the same letter can
|
|
1548
|
+
mean different things on two pages (`x_0` as a starting point, a center, a
|
|
1549
|
+
first observation), so an index entry is often page-local
|
|
1550
|
+
(`notation.local`). Give each index letter's card a `range`, or state the set
|
|
1551
|
+
after a `\quad`.
|
|
1552
|
+
|
|
1553
|
+
_Enforcement._ Partial (`gate-indices.ts` `gateIndices`, `pnpm
|
|
1554
|
+
validate:content`) — the four errors above, over lesson bodies, notation
|
|
1555
|
+
formulas and assessments. A lesson-body finding is located, so `{/*
|
|
1556
|
+
explico-allow N23: <reason> */}` waives one place. Lab math
|
|
1557
|
+
(`render-lab-math.ts`) and `<Diagram>` formulas fail `astro build` with the
|
|
1558
|
+
same findings as they render (`indexFindings`). A reviewer checks the rest:
|
|
1559
|
+
that a `\quad` clause states the right set, and that a lowercase index the
|
|
1560
|
+
build treats as running really runs. A course switches the rule
|
|
1561
|
+
off with `rules.N23.enabled: false`, which stops all of it; the derived cards
|
|
1562
|
+
are built either way. The resolver behaviors the rule rests on — whole forms
|
|
1563
|
+
under a power, families by shape, no lending from a fixed label or to a bare
|
|
1564
|
+
symbol — are part of [N4](#n4) and always on: a bare symbol that has no card
|
|
1565
|
+
of its own fails `unresolved-glyph`, and its message names the indexed
|
|
1566
|
+
entry with that base.
|
|
1567
|
+
|
|
1568
|
+
_Exceptions._ A `\quad` clause the check misreads takes a waiver with its
|
|
1569
|
+
reason. A lab whose glyph table is not the one `labMathScope` returned (a
|
|
1570
|
+
copy) composes no derived card and is not checked.
|
|
@@ -31,5 +31,6 @@ fails when it is stale.
|
|
|
31
31
|
| N7 | The differential `d` is upright `\mathrm{d}`. | 2026-09-26 | [N2](README.md#rule-index) | `\mathrm{d}` is a line in N2’s `reserved` table. |
|
|
32
32
|
| N16 | In AI-generated mathematical content, alternate delimiter types for nested grouping when their shape is stylistic; preserve every conventional or semantic delimiter shape. | 2026-09-26 | [N17](README.md#rule-index) | Folded into N17 with the preference dropped: a delimiter’s shape carries its meaning, so depth is shown by size — which this engine handles automatically — not by alternating shapes. The rule also scoped itself to “AI-generated” content, which is not a property of the page. |
|
|
33
33
|
| C4 | On a release, move `## [Unreleased]` to `## [x.y.z] - YYYY-MM-DD` and bump `about.version` in the same commit. | 2026-09-26 | [C3](README.md#rule-index) | The release procedure and the invariant it keeps are one rule, and `knowledge-changelog-missing` (owned by C3) was already the check that fired on a half-finished release. |
|
|
34
|
+
| S5 | A sign or perspective convention is declared once and cited everywhere else. | 2026-10-07 | [N4](README.md#rule-index) | Its check knew one finance course’s phrasing and one key per course, and never fired in any course; the `conventions` setting it read is gone. A convention is a definition, so it is now N4’s: defined once on its notation entry, whose `meaning` names the other choice and whose body says how to convert. |
|
|
34
35
|
|
|
35
36
|
<!-- RETIRED-RULES:END -->
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Structure rules
|
|
2
2
|
|
|
3
3
|
`S` rules govern the shape of a lesson's headings, the short captions on its
|
|
4
|
-
keyed floats, the paragraphs that open a part page,
|
|
5
|
-
|
|
4
|
+
keyed floats, the paragraphs that open a part page, what a page that is not
|
|
5
|
+
a chapter may carry, and how a table or a
|
|
6
|
+
diagram is declared so the rest of the course can reach it —
|
|
6
7
|
the parts of a page a reader scans, links to, or cites. This
|
|
7
8
|
is not [structure.md](structure.md), which is the taxonomy these rules (and
|
|
8
9
|
the rest of the engine) speak in, not a rule set itself.
|
|
@@ -27,7 +28,9 @@ tooltip — the `[short]` half of LaTeX's `\caption[short]{long}`. The long
|
|
|
27
28
|
`caption` is never measured: it is the full sentence shown with the float's
|
|
28
29
|
number (see [components.md § The caption pair](components.md#the-caption-pair)).
|
|
29
30
|
A heading is measured as the reader sees it: its markers (`[collapsed]`,
|
|
30
|
-
`[card]`, …) never render, so they never count
|
|
31
|
+
`[card]`, …) never render, so they never count; a formula counts as its
|
|
32
|
+
glyphs (`$\explain{motion.range}{R}$` is one character) and a `[[key]]` term
|
|
33
|
+
as its label.
|
|
31
34
|
|
|
32
35
|
A heading or short caption that runs long is usually doing a caption's job.
|
|
33
36
|
Move the rest of the sentence into the paragraph right after a heading, or
|
|
@@ -109,7 +112,8 @@ launch angle that gives the largest range.
|
|
|
109
112
|
```
|
|
110
113
|
|
|
111
114
|
Keep a blank line inside each tag, so MDX parses the paragraph as Markdown and
|
|
112
|
-
its math and `[[key]]` references render
|
|
115
|
+
its math and `[[key]]` references render with their cards
|
|
116
|
+
([S10](#s10)). A part page recalls symbols; it defines none.
|
|
113
117
|
|
|
114
118
|
The word range is a course setting, `rules.S2` in `course.settings.json`
|
|
115
119
|
(`CourseConfig.rules`). Each end defaults to 30–150 words; list only what
|
|
@@ -184,9 +188,13 @@ validate:content`) — a warning per lesson (`raw-table-markdown`,
|
|
|
184
188
|
`raw-table-html`); `remarkNotation` repeats it at render time for content
|
|
185
189
|
added since the manifest was compiled. It does not fail the build.
|
|
186
190
|
|
|
187
|
-
_Exceptions._
|
|
188
|
-
|
|
189
|
-
|
|
191
|
+
_Exceptions._ The scan counts a table only where a `<Table>` would number
|
|
192
|
+
it: at the top level of the lesson body, or in a `<Memo>`, `<ShortNote>` or
|
|
193
|
+
`<Fold>`, which keep their place in the reading order. A table already inside
|
|
194
|
+
a `<Table>` or `<Figure>` has its identity. A table in a worked example
|
|
195
|
+
(`<CompactExample>`) or in another component is illustrative, like an
|
|
196
|
+
equation there: leave it a plain Markdown table. A `<Table>` there gets no
|
|
197
|
+
number, and the build fails on it with that reason.
|
|
190
198
|
|
|
191
199
|
## S4
|
|
192
200
|
|
|
@@ -224,43 +232,6 @@ fail the build.
|
|
|
224
232
|
_Exceptions._ A purely decorative diagram that nothing will ever cite may stay
|
|
225
233
|
unkeyed; say so in a comment next to it.
|
|
226
234
|
|
|
227
|
-
## S5
|
|
228
|
-
|
|
229
|
-
**A sign or perspective convention is declared once and cited everywhere
|
|
230
|
-
else.**
|
|
231
|
-
|
|
232
|
-
A course names one notation entry as its sign convention
|
|
233
|
-
(`conventions.signConventionKey`) and one competency as its cash-flow /
|
|
234
|
-
perspective convention (`conventions.cashFlowPerspectiveCompetency`). A lesson
|
|
235
|
-
whose prose states such a convention — "outflows are negative", "angles are
|
|
236
|
-
measured counter-clockwise from the horizontal" — resolves it to that single
|
|
237
|
-
declaration rather than restating it.
|
|
238
|
-
|
|
239
|
-
```mdx
|
|
240
|
-
<!-- Restated: a second, drifting definition. -->
|
|
241
|
-
In this chapter, an outflow is a negative cash flow.
|
|
242
|
-
|
|
243
|
-
<!-- Resolved to the declaration. -->
|
|
244
|
-
Cash flows follow the [[cash-flow.sign]] convention: an outflow is negative.
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
_Rationale._ A convention restated in several lessons drifts — one says
|
|
248
|
-
"negative", another "shown in parentheses" — and a reader who learned it in
|
|
249
|
-
one place cannot tell whether the other place means the same thing. One
|
|
250
|
-
declaration, cited, keeps the meaning in one file.
|
|
251
|
-
|
|
252
|
-
_How to apply._ Cite the convention's notation entry with `[[key]]` in the
|
|
253
|
-
sentence that invokes it, or list the convention's competency in the lesson's
|
|
254
|
-
`teaches` / `requires`. Either anchors the prose to the declaration.
|
|
255
|
-
|
|
256
|
-
_Enforcement._ Build-enforced (`consistency.ts`
|
|
257
|
-
`checkConventionSingleDefinition`, `pnpm validate:content`) — a warning
|
|
258
|
-
(`convention-single-definition`) for a lesson whose prose matches the
|
|
259
|
-
convention pattern and is anchored by neither the term nor the competency.
|
|
260
|
-
|
|
261
|
-
_Exceptions._ The lesson that *is* the declaration — the one that teaches the
|
|
262
|
-
convention's competency — is anchored by definition.
|
|
263
|
-
|
|
264
235
|
## S6
|
|
265
236
|
|
|
266
237
|
**Headings descend one level at a time: a lesson body starts at `##` and
|
|
@@ -301,7 +272,11 @@ _Enforcement._ Build-enforced (`gate-heading-structure.ts`, `pnpm
|
|
|
301
272
|
validate:content`, `heading-skip`) over a lesson's outline — the top-level
|
|
302
273
|
headings the section numbers count. A heading inside a component's children
|
|
303
274
|
(a `<Memo>`, a `<CompactExample>`) belongs to that component and is not part
|
|
304
|
-
of the outline, and a memo's own bar is not a heading of the lesson.
|
|
275
|
+
of the outline, and a memo's own bar is not a heading of the lesson. A
|
|
276
|
+
`<CompactExamples>` or an `<AssessmentSet>` draws an `<h2>` of its own, so
|
|
277
|
+
one inside a `<Memo>` or a `<ShortNote>` fails (`heading-nested`): its
|
|
278
|
+
heading would land under the memo's `<h6>`, and "On this page" would never
|
|
279
|
+
list it. Put it at the top level, after the memo.
|
|
305
280
|
|
|
306
281
|
_Exceptions._ None in the rule; waive one place with
|
|
307
282
|
`{/* explico-allow S6: reason */}` above the heading.
|
|
@@ -449,3 +424,67 @@ title from one that builds on it.
|
|
|
449
424
|
_Exceptions._ A float that needs no name of its own may go without a
|
|
450
425
|
`short`; the "Figures and tables" page then lists it by its long caption,
|
|
451
426
|
muted.
|
|
427
|
+
|
|
428
|
+
## S10
|
|
429
|
+
|
|
430
|
+
**A page that is not a chapter — the landing page, a part’s overview page —
|
|
431
|
+
explains its symbols like a chapter, but carries no numbered float: it links
|
|
432
|
+
the chapter’s float instead.**
|
|
433
|
+
|
|
434
|
+
This applies to `content/docs/index.mdx`, to every
|
|
435
|
+
`content/docs/<part>/index.mdx`, and to any other page outside a part
|
|
436
|
+
directory. What makes a card works there as in a chapter:
|
|
437
|
+
|
|
438
|
+
- a `[[key]]` term and `\explain{key}{…}` in math, each opening its card;
|
|
439
|
+
- plain math, bound symbol by symbol, so every symbol it shows is explained;
|
|
440
|
+
- a citation `[@id]`, an abbreviation, and a link to a chapter’s float,
|
|
441
|
+
`[[motion/constant-acceleration#tab-kinematics-summary]]`, whose card
|
|
442
|
+
previews the table.
|
|
443
|
+
|
|
444
|
+
The math and prose rules hold there too ([N4](notation.md#n4),
|
|
445
|
+
[N9](notation.md#n9), [N10](notation.md#n10), [N14](notation.md#n14), and a
|
|
446
|
+
course’s `X` rules). What such a page may not carry:
|
|
447
|
+
|
|
448
|
+
| Not here | Instead |
|
|
449
|
+
| --- | --- |
|
|
450
|
+
| `<Table>`, `<Figure>`, `<Diagram>`, `<CompactExamples>`, `<AssessmentSet>` | Link the chapter’s float: `[[<chapter>#tab-<key>]]` (`fig-`, `dia-`, …). |
|
|
451
|
+
| A lab, or any `client:*` island | Link the chapter’s `<Figure>` that holds it. |
|
|
452
|
+
| `\label{eq:…}` on a display equation | Drop the label (the equation shows unnumbered), or link the chapter’s equation. |
|
|
453
|
+
| `notation.local`, `notation.suspend` | Define the symbol in the chapter that introduces it, or in shared notation, and name it with `[[key]]`. |
|
|
454
|
+
| `$…$` or `[[…]]` in `hero.title`, `hero.tagline`, a `<PartOverview chain>` step | Write words; these strings are plain text and print markup literally. |
|
|
455
|
+
|
|
456
|
+
```mdx
|
|
457
|
+
<PartScope>
|
|
458
|
+
|
|
459
|
+
Part 1 ended on a point that moves under a constant acceleration
|
|
460
|
+
[[motion.acceleration]]. The worked examples in
|
|
461
|
+
[[motion/constant-acceleration#tab-kinematics-summary]] give its velocity.
|
|
462
|
+
|
|
463
|
+
</PartScope>
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
A plain Markdown table is ordinary text on such a page: it has no caption and
|
|
467
|
+
no number, so it is not a float.
|
|
468
|
+
|
|
469
|
+
_Rationale._ A float number starts with its chapter’s number, and a page that
|
|
470
|
+
is not a chapter has none: a table on a part page would need a number that
|
|
471
|
+
collides with a chapter’s, or no number, which makes it the one float in the
|
|
472
|
+
course a reference cannot reach. A part page in a printed book points to the
|
|
473
|
+
chapters’ floats and does not copy them. The reference card gives the reader
|
|
474
|
+
the same view without the copy. Symbols are different: an overview that
|
|
475
|
+
recalls a result needs its symbols, and a symbol without its card breaks the
|
|
476
|
+
promise every other page keeps.
|
|
477
|
+
|
|
478
|
+
_How to apply._ Write the overview’s recap with the chapter’s own symbols,
|
|
479
|
+
each introduced with `[[key]]`. Where the recap leans on a table, figure or
|
|
480
|
+
equation, link it instead of repeating it. If a symbol has no shared entry,
|
|
481
|
+
recall it in words or give it one in `content/notation/`.
|
|
482
|
+
|
|
483
|
+
_Enforcement._ Build-enforced (`gate-non-chapter-pages.ts`,
|
|
484
|
+
`pnpm validate:content`): `non-chapter-float` for a numbered block, a lab or
|
|
485
|
+
an equation label; `non-chapter-local-notation` for a notation block;
|
|
486
|
+
`non-chapter-plain-text` for markup in a plain-text string. `astro build`
|
|
487
|
+
fails the same numbered block and equation label at render time. This rule is
|
|
488
|
+
**locked**: turning it off would not give the page a number to print.
|
|
489
|
+
|
|
490
|
+
_Exceptions._ None.
|