explico 0.12.0 → 0.13.1
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 +1137 -1
- package/README.md +91 -13
- package/dist/compiler/astro.d.ts +4 -3
- package/dist/compiler/astro.js +45 -15
- package/dist/compiler/cli.d.ts +26 -12
- package/dist/compiler/cli.js +96 -25
- package/dist/compiler/collections.d.ts +9 -1
- package/dist/compiler/collections.js +55 -16
- 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 +14 -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 +87 -6
- package/dist/compiler/manifest.js +174 -31
- package/dist/compiler/render-diagnostics.d.ts +65 -0
- package/dist/compiler/render-diagnostics.js +56 -0
- package/dist/compiler/resolution-report.d.ts +2 -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 +2 -2
- package/dist/reference/base-operators.mjs +2 -2
- 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/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-part-pages.d.ts +1 -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-math-scope.d.ts +1 -0
- package/dist/reference/lab-math-scope.js +13 -2
- 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 +34 -4
- package/dist/reference/page-notation.js +54 -2
- package/dist/reference/references.d.ts +11 -1
- package/dist/reference/references.js +6 -0
- package/dist/reference/registry.js +104 -10
- 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 +84 -20
- package/dist/reference/render-lab-math.d.ts +2 -0
- package/dist/reference/render-lab-math.js +17 -5
- 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 +191 -30
- package/dist/rules/in-effect.d.ts +1 -1
- package/dist/rules/rules.schema.json +79 -24
- 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 +32 -21
- package/docs/authoring/agents.md +38 -7
- package/docs/authoring/components.md +111 -6
- package/docs/authoring/migrating.md +707 -0
- package/docs/authoring/notation.md +281 -29
- package/docs/authoring/retired.md +1 -0
- package/docs/authoring/structure-rules.md +10 -41
- package/docs/authoring/structure.md +53 -2
- package/docs/authoring/visualizations.md +144 -18
- package/package.json +12 -7
- package/src/compiler/astro.ts +57 -17
- package/src/compiler/cli.ts +143 -35
- package/src/compiler/collections.ts +92 -19
- 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 +299 -28
- package/src/compiler/render-diagnostics.ts +111 -0
- package/src/components/HoverPanel.astro +204 -6
- package/src/components/PartOverview.astro +12 -9
- 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/figure/Figure.astro +11 -0
- package/src/components/figure/FloatCaption.astro +4 -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 +321 -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 +47 -9
- 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 +13 -21
- 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 +2 -2
- 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/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-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-math-scope.ts +15 -1
- package/src/reference/math-glyphs.mjs +851 -46
- package/src/reference/mixed-content.ts +11 -2
- package/src/reference/page-notation.ts +100 -3
- package/src/reference/references.ts +14 -0
- package/src/reference/registry.ts +154 -8
- 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 +84 -20
- package/src/reference/render-lab-math.ts +29 -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 +205 -29
- package/src/rules/settings.ts +10 -0
- package/src/session/PreferenceStore.ts +53 -0
- package/src/styles/global.css +291 -75
|
@@ -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,6 +228,42 @@ 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;
|
|
@@ -263,8 +307,17 @@ stripped before KaTeX like the label, heads the `[[eq-…]]` preview card and
|
|
|
263
307
|
names the copy action ("Copy LaTeX — Range formula"). An equation takes no
|
|
264
308
|
long caption ([components.md § The caption pair](components.md#the-caption-pair)).
|
|
265
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
|
+
|
|
266
318
|
_Enforcement._ Partial. The converse is checked: `equations-validate.ts`
|
|
267
|
-
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.
|
|
268
321
|
An unlabelled-but-referenced equation builds; a reviewer catches the
|
|
269
322
|
hand-numbering.
|
|
270
323
|
|
|
@@ -392,14 +445,14 @@ next to it was invisible to every check until this rule.
|
|
|
392
445
|
_How to apply._
|
|
393
446
|
|
|
394
447
|
- A table header cell that names a quantity uses the same bound symbol the
|
|
395
|
-
lesson already introduced,
|
|
396
|
-
|
|
397
|
-
`
|
|
398
|
-
|
|
399
|
-
|
|
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:
|
|
400
453
|
|
|
401
454
|
```text
|
|
402
|
-
| $t\ \text{(s)}$ |
|
|
455
|
+
| $t\ \text{(s)}$ | $v_x\ \text{(m/s)}$ |
|
|
403
456
|
```
|
|
404
457
|
|
|
405
458
|
- An absolute value or norm is `\lvert…\rvert`, never a literal `|` — a raw
|
|
@@ -477,6 +530,12 @@ as a hard error with no Tier-3 warming-up period and no `lint-ignore.yml`
|
|
|
477
530
|
entry, because each part landed in the same change that brought the whole
|
|
478
531
|
corpus to zero — see the two files for the exact patterns.
|
|
479
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
|
+
|
|
480
539
|
_Settings._ `rules.N9.allow` in the course settings lists unit words the
|
|
481
540
|
course lets prose spell out (`["hour", "minute"]`), singular or plural; a
|
|
482
541
|
phrase is skipped only when every unit word in it is allowed.
|
|
@@ -522,11 +581,13 @@ _How to apply._
|
|
|
522
581
|
itself a notation key stays a key.
|
|
523
582
|
|
|
524
583
|
- A generic qualifier that functions like an operator's extremum subscript —
|
|
525
|
-
`x_{\mathrm{opt}}`, an "optimal" reading with no quantity of its own —
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
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.
|
|
530
591
|
|
|
531
592
|
- A named quantity gets a notation entry, exactly like a glyph ([N4](#n4)) —
|
|
532
593
|
a shared card if the course teaches it broadly, otherwise `notation.local`,
|
|
@@ -694,7 +755,7 @@ resolves, table cells and component slots included — and
|
|
|
694
755
|
`gateMathPunctuationInAssessments` every assessment `prompt` /
|
|
695
756
|
`explanation`. It flags a `.`, `,`, `;` or `:` that is the last visible
|
|
696
757
|
thing in the span, or in a row before a `\\`. It looks through what renders
|
|
697
|
-
nothing there: spacing (`\,`, `\quad`), `\label{…}` / `\
|
|
758
|
+
nothing there: spacing (`\,`, `\quad`), `\label{…}` / `\caption{…}`, a row
|
|
698
759
|
break, `\end{…}`, the null delimiter `\right.`. It looks into a closing
|
|
699
760
|
`\text{…}` / `\mathrm{…}`, so `5\ \text{m,}` is caught. A finding is located
|
|
700
761
|
at the mark, so a per-place waiver can cover it.
|
|
@@ -1024,7 +1085,9 @@ or `a = b \le c` — write it as an `aligned` block. The first line carries the
|
|
|
1024
1085
|
left-hand side. Every later line starts with `&` directly before its relation
|
|
1025
1086
|
(`&=`, `&\le`, `&\approx`, `&\propto`), so the relation signs stand in one
|
|
1026
1087
|
column. A step that needs a reason gets it at the end of its own line, after
|
|
1027
|
-
`\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:
|
|
1028
1091
|
|
|
1029
1092
|
```text
|
|
1030
1093
|
$$
|
|
@@ -1134,7 +1197,9 @@ _Enforcement._ Build-enforced (`consistency.ts` `checkNotationUnits`,
|
|
|
1134
1197
|
and `units-vocab` (a token outside the vocabulary).
|
|
1135
1198
|
|
|
1136
1199
|
_Exceptions._ A `lint-ignore.yml` entry (`- notation-units:<key> — <reason>`)
|
|
1137
|
-
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.
|
|
1138
1203
|
|
|
1139
1204
|
## N20
|
|
1140
1205
|
|
|
@@ -1168,33 +1233,33 @@ definition table) may cite the whole; say so in the locator (`"whole"`).
|
|
|
1168
1233
|
|
|
1169
1234
|
**A gloss is named by a short noun phrase, not described by a sentence.**
|
|
1170
1235
|
|
|
1171
|
-
A gloss binds a symbol on one page with a `
|
|
1172
|
-
|
|
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.
|
|
1173
1238
|
|
|
1174
1239
|
```yaml
|
|
1175
1240
|
# A name.
|
|
1176
|
-
-
|
|
1177
|
-
|
|
1241
|
+
- latex: \theta
|
|
1242
|
+
name: launch angle
|
|
1178
1243
|
|
|
1179
|
-
# A description — belongs in a full notation entry's body, not a gloss
|
|
1180
|
-
-
|
|
1181
|
-
|
|
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
|
|
1182
1247
|
```
|
|
1183
1248
|
|
|
1184
1249
|
_Rationale._ A gloss is the lightweight form: a name and a glyph. Once the
|
|
1185
|
-
|
|
1250
|
+
name grows a clause or a sentence it is doing a notation entry's job without
|
|
1186
1251
|
that entry's units, sources, or shared identity — and the card shows a wall of
|
|
1187
1252
|
text where every other card shows a name.
|
|
1188
1253
|
|
|
1189
|
-
_How to apply._ Keep the
|
|
1254
|
+
_How to apply._ Keep the name to a few words with no sentence punctuation or
|
|
1190
1255
|
relative clause. If the symbol needs a description, promote the gloss to a
|
|
1191
1256
|
notation entry (the `gloss-wants-promoting` hint under N4 says when).
|
|
1192
1257
|
|
|
1193
1258
|
_Enforcement._ Build-enforced (`consistency.ts` `checkGlossNameShape`, `pnpm
|
|
1194
|
-
validate:content`) — warning `gloss-name-shape` for a
|
|
1259
|
+
validate:content`) — warning `gloss-name-shape` for a name over the word
|
|
1195
1260
|
limit or containing sentence punctuation / a relative clause.
|
|
1196
1261
|
|
|
1197
|
-
_Exceptions._ None — a
|
|
1262
|
+
_Exceptions._ None — a name that cannot be short is a notation entry.
|
|
1198
1263
|
|
|
1199
1264
|
---
|
|
1200
1265
|
|
|
@@ -1295,6 +1360,7 @@ operator on the page, and why.
|
|
|
1295
1360
|
|
|
1296
1361
|
| Code | Severity | When |
|
|
1297
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 |
|
|
1298
1364
|
| `suspended-operator-unresolved` | error | a decorated form of a suspended decoration has no whole form |
|
|
1299
1365
|
| `operator-suspended` | info | a suspension with a `reason` — recorded, nothing to fix |
|
|
1300
1366
|
| `operator-suspension-reason` | warning | a suspension without a `reason` |
|
|
@@ -1308,7 +1374,12 @@ _Enforcement._ Tier-3 warning `accent-explained` (`consistency.ts`
|
|
|
1308
1374
|
`checkAccentExplained`) for a decoration that composes with no operator entry
|
|
1309
1375
|
and is not on the allow list, one per decoration per lesson, surfaced by `pnpm
|
|
1310
1376
|
validate:content` and silenced only by a reviewed line in `lint-ignore.yml`
|
|
1311
|
-
(`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
|
|
1312
1383
|
completeness gate (`gate-math.ts`) and the render path (`remark-notation.mjs`)
|
|
1313
1384
|
both fail `suspended-operator-unresolved`; `checkOperatorSuspension` emits the
|
|
1314
1385
|
other three codes.
|
|
@@ -1316,3 +1387,184 @@ other three codes.
|
|
|
1316
1387
|
_Exceptions._ Suspension (above) is the sanctioned way to give a decoration a
|
|
1317
1388
|
different meaning on one page. Quoting a source that uses a decoration
|
|
1318
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 -->
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
`S` rules govern the shape of a lesson's headings, the short captions on its
|
|
4
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
|
|
6
|
-
diagram
|
|
5
|
+
a chapter may carry, and how a table or a
|
|
6
|
+
diagram is declared so the rest of the course can reach it —
|
|
7
7
|
the parts of a page a reader scans, links to, or cites. This
|
|
8
8
|
is not [structure.md](structure.md), which is the taxonomy these rules (and
|
|
9
9
|
the rest of the engine) speak in, not a rule set itself.
|
|
@@ -28,7 +28,9 @@ tooltip — the `[short]` half of LaTeX's `\caption[short]{long}`. The long
|
|
|
28
28
|
`caption` is never measured: it is the full sentence shown with the float's
|
|
29
29
|
number (see [components.md § The caption pair](components.md#the-caption-pair)).
|
|
30
30
|
A heading is measured as the reader sees it: its markers (`[collapsed]`,
|
|
31
|
-
`[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.
|
|
32
34
|
|
|
33
35
|
A heading or short caption that runs long is usually doing a caption's job.
|
|
34
36
|
Move the rest of the sentence into the paragraph right after a heading, or
|
|
@@ -230,43 +232,6 @@ fail the build.
|
|
|
230
232
|
_Exceptions._ A purely decorative diagram that nothing will ever cite may stay
|
|
231
233
|
unkeyed; say so in a comment next to it.
|
|
232
234
|
|
|
233
|
-
## S5
|
|
234
|
-
|
|
235
|
-
**A sign or perspective convention is declared once and cited everywhere
|
|
236
|
-
else.**
|
|
237
|
-
|
|
238
|
-
A course names one notation entry as its sign convention
|
|
239
|
-
(`conventions.signConventionKey`) and one competency as its cash-flow /
|
|
240
|
-
perspective convention (`conventions.cashFlowPerspectiveCompetency`). A lesson
|
|
241
|
-
whose prose states such a convention — "outflows are negative", "angles are
|
|
242
|
-
measured counter-clockwise from the horizontal" — resolves it to that single
|
|
243
|
-
declaration rather than restating it.
|
|
244
|
-
|
|
245
|
-
```mdx
|
|
246
|
-
<!-- Restated: a second, drifting definition. -->
|
|
247
|
-
In this chapter, an outflow is a negative cash flow.
|
|
248
|
-
|
|
249
|
-
<!-- Resolved to the declaration. -->
|
|
250
|
-
Cash flows follow the [[cash-flow.sign]] convention: an outflow is negative.
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
_Rationale._ A convention restated in several lessons drifts — one says
|
|
254
|
-
"negative", another "shown in parentheses" — and a reader who learned it in
|
|
255
|
-
one place cannot tell whether the other place means the same thing. One
|
|
256
|
-
declaration, cited, keeps the meaning in one file.
|
|
257
|
-
|
|
258
|
-
_How to apply._ Cite the convention's notation entry with `[[key]]` in the
|
|
259
|
-
sentence that invokes it, or list the convention's competency in the lesson's
|
|
260
|
-
`teaches` / `requires`. Either anchors the prose to the declaration.
|
|
261
|
-
|
|
262
|
-
_Enforcement._ Build-enforced (`consistency.ts`
|
|
263
|
-
`checkConventionSingleDefinition`, `pnpm validate:content`) — a warning
|
|
264
|
-
(`convention-single-definition`) for a lesson whose prose matches the
|
|
265
|
-
convention pattern and is anchored by neither the term nor the competency.
|
|
266
|
-
|
|
267
|
-
_Exceptions._ The lesson that *is* the declaration — the one that teaches the
|
|
268
|
-
convention's competency — is anchored by definition.
|
|
269
|
-
|
|
270
235
|
## S6
|
|
271
236
|
|
|
272
237
|
**Headings descend one level at a time: a lesson body starts at `##` and
|
|
@@ -307,7 +272,11 @@ _Enforcement._ Build-enforced (`gate-heading-structure.ts`, `pnpm
|
|
|
307
272
|
validate:content`, `heading-skip`) over a lesson's outline — the top-level
|
|
308
273
|
headings the section numbers count. A heading inside a component's children
|
|
309
274
|
(a `<Memo>`, a `<CompactExample>`) belongs to that component and is not part
|
|
310
|
-
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.
|
|
311
280
|
|
|
312
281
|
_Exceptions._ None in the rule; waive one place with
|
|
313
282
|
`{/* explico-allow S6: reason */}` above the heading.
|
|
@@ -106,6 +106,13 @@ Part 2 Projectile motion
|
|
|
106
106
|
|
|
107
107
|
## Part pages
|
|
108
108
|
|
|
109
|
+
A part is listed in `course.settings.json` → `parts` as `{ "dir", "label" }`
|
|
110
|
+
and lives in `content/docs/<dir>/`. A part listed before anything is written
|
|
111
|
+
in it — no chapter and no overview page yet — is left out of the sidebar and
|
|
112
|
+
the numbering, with a `part-empty` warning, so the parts after it keep their
|
|
113
|
+
numbers until it has content. A lesson in a directory no part lists fails
|
|
114
|
+
`validate:content` (`lesson-outside-parts`).
|
|
115
|
+
|
|
109
116
|
A part is a directory, so `/<part>/` is a URL a reader will eventually type,
|
|
110
117
|
follow, or be handed by a search engine. Without a page it is a 404, and the
|
|
111
118
|
part exists only as a sidebar heading that cannot be linked to.
|
|
@@ -309,7 +316,11 @@ punctuation dropped, so `## Two ways to name the same point` is
|
|
|
309
316
|
`-1`, `-2`. A reference to a heading without a number (deeper than `depth`, or
|
|
310
317
|
with `show: false`) prints the heading's title in quotes instead: a reader
|
|
311
318
|
could not find the number. A reference that names no top-level heading fails
|
|
312
|
-
`pnpm validate:content` (`sec-ref-resolves`) and the build.
|
|
319
|
+
`pnpm validate:content` (`sec-ref-resolves`) and the build. So does a heading
|
|
320
|
+
whose anchor the page already gives something else
|
|
321
|
+
(`heading-anchor-collision`): `## References` on a page that cites a source
|
|
322
|
+
(the References section is generated, at `#references`), or `## Tab totals`
|
|
323
|
+
beside `<Table id="totals">` (`#tab-totals`).
|
|
313
324
|
|
|
314
325
|
### Structure from the bottom up
|
|
315
326
|
|
|
@@ -347,6 +358,13 @@ worked-example set (`<CompactExamples>`) is numbered **`‹part›.‹chapter›
|
|
|
347
358
|
- **Keyed or not, everything counts.** An equation with no `\label{eq:…}` still
|
|
348
359
|
takes a number and a positional anchor (`#eq-2-1-4`); it just cannot be
|
|
349
360
|
referenced by name.
|
|
361
|
+
- **The lesson's flow counts, a callout does not.** An equation or a float
|
|
362
|
+
in a list item or a `>` quote counts like one at the top level, and so
|
|
363
|
+
does one in a `<Memo>`, `<ShortNote>` or `<Fold>`. One in a `:::note`
|
|
364
|
+
aside (or `<Aside>`, or a worked example) is illustrative and takes no
|
|
365
|
+
number; a `<Table>` or `<Figure>` there fails the build. A display
|
|
366
|
+
equation is a `$$` block whose fences sit on lines of their own:
|
|
367
|
+
`$$x$$` inside a sentence, or on one line, is inline math.
|
|
350
368
|
- **The number sits with the caption.** A figure or diagram prints it in the
|
|
351
369
|
caption line below its picture, a table in the caption line above, and a
|
|
352
370
|
display equation beside it. What names each
|
|
@@ -571,7 +589,9 @@ A block folds in one of two ways, and every default lives in one place, the
|
|
|
571
589
|
`sections`, `subsections` and `knowledgeChecks` take `{ collapsible,
|
|
572
590
|
defaultOpen }`; the others take `{ defaultOpen }`; `tables` takes
|
|
573
591
|
`{ truncateAfter }` — a table with more rows shows that many, half from each
|
|
574
|
-
end, and a "… N more rows …" line
|
|
592
|
+
end, and a "… N more rows …" line, unless that would hide a single row (the
|
|
593
|
+
line is as tall as the row, so the table shows whole). There is no
|
|
594
|
+
`disclosure.diagrams`: a
|
|
575
595
|
diagram does not fold. Every collapsible remembers the reader's own choice,
|
|
576
596
|
per page, over the default (`rememberState={false}` on a memo, a fold, a
|
|
577
597
|
figure's tools or an example set opts that one out). A short note's in-place
|
|
@@ -646,3 +666,34 @@ While collapsed, the surrounding sentence remains one paragraph and only the
|
|
|
646
666
|
point in the reading flow, and exposes a “Show less” control that restores the
|
|
647
667
|
original sentence. Short notes are for a locally optional explanation, not for
|
|
648
668
|
material that needs a number or citations elsewhere; use a memo for that.
|
|
669
|
+
|
|
670
|
+
## Retired keys
|
|
671
|
+
|
|
672
|
+
A key the engine has stopped reading fails the build wherever a content file
|
|
673
|
+
still sets it, so a course cannot keep maintaining a field that does nothing.
|
|
674
|
+
Each `retired-key` error names the file and the key's line; deleting the line
|
|
675
|
+
clears it.
|
|
676
|
+
|
|
677
|
+
| Key | Where it was set | Why it went |
|
|
678
|
+
| --- | --- | --- |
|
|
679
|
+
| `editorialStatus` | pages, notation entries, abbreviations, competencies, assessments, sources, tracks | Lessons are reviewed continuously, so no page ever earns a one-time "reviewed" stamp. The draft / in-review / reviewed labels it put on part pages, notation cards, glossary entries and citations are gone. |
|
|
680
|
+
|
|
681
|
+
Two of Starlight's own keys do not work in a course, because the manifest,
|
|
682
|
+
not Starlight, decides which chapters a course lists and in what order. A
|
|
683
|
+
lesson's `draft: true` fails the build as `unsupported-key`: Starlight would
|
|
684
|
+
leave the page out of a production build while the sidebar still names it.
|
|
685
|
+
Keep an unfinished lesson outside `content/docs/` until it is ready. A
|
|
686
|
+
chapter's `sidebar.order` warns as `ignored-key`: chapters follow the order of
|
|
687
|
+
the tracks (`content/tracks/*.json`).
|
|
688
|
+
|
|
689
|
+
## Content schemas
|
|
690
|
+
|
|
691
|
+
Every content file is checked against its collection's schema — the same
|
|
692
|
+
one `astro build` loads it with (`src/compiler/content-schemas.ts`) — by
|
|
693
|
+
`pnpm validate:content` and `pnpm content check`, so a value the build would
|
|
694
|
+
reject fails there first, at the key's line, as a `content-schema` error:
|
|
695
|
+
a notation `meaning` with `$` or `\`, a source `type` outside `primary`,
|
|
696
|
+
`official-guidance`, `paper`, `book` and `secondary`, or a `studyMinutes`
|
|
697
|
+
range whose low end exceeds its high end. A lesson is checked for the fields
|
|
698
|
+
explico adds (`teaches`, `assumptions`, `studyMinutes`, `notation`);
|
|
699
|
+
Starlight checks its own (`title`, `description`, …) when the site builds.
|