explico 0.1.1 → 0.3.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 +102 -0
- package/README.md +46 -5
- package/dist/compiler/cli.d.ts +17 -0
- package/dist/compiler/cli.js +41 -3
- package/dist/compiler/collections.js +31 -1
- package/dist/compiler/course-config.d.ts +52 -1
- package/dist/compiler/knowledge-version.d.ts +58 -0
- package/dist/compiler/knowledge-version.js +80 -0
- package/dist/compiler/manifest.d.ts +87 -3
- package/dist/compiler/manifest.js +133 -20
- package/dist/compiler/resolution-report.d.ts +5 -0
- package/dist/reference/base-operators.d.mts +38 -0
- package/dist/reference/base-operators.mjs +103 -0
- package/dist/reference/consistency.d.ts +7 -2
- package/dist/reference/consistency.js +142 -2
- package/dist/reference/diagram-layout.d.ts +63 -0
- package/dist/reference/diagram-layout.js +122 -0
- package/dist/reference/equations-validate.d.ts +5 -0
- package/dist/reference/equations-validate.js +1 -1
- package/dist/reference/equations.d.mts +76 -18
- package/dist/reference/equations.mjs +118 -41
- package/dist/reference/figures-validate.d.ts +21 -0
- package/dist/reference/figures-validate.js +13 -0
- package/dist/reference/gate-math.d.ts +5 -4
- package/dist/reference/gate-math.js +73 -2
- package/dist/reference/gloss.d.ts +87 -0
- package/dist/reference/gloss.js +59 -0
- package/dist/reference/keyed-float-validate.d.ts +67 -0
- package/dist/reference/keyed-float-validate.js +110 -0
- package/dist/reference/keyed-jsx-floats.d.mts +56 -0
- package/dist/reference/keyed-jsx-floats.mjs +167 -0
- package/dist/reference/math-glyphs.d.mts +18 -0
- package/dist/reference/math-glyphs.mjs +92 -0
- package/dist/reference/registry.js +25 -0
- package/dist/reference/rehype-heading-anchors.d.mts +1 -0
- package/dist/reference/rehype-heading-anchors.mjs +144 -0
- package/dist/reference/remark-notation.d.mts +12 -0
- package/dist/reference/remark-notation.mjs +228 -32
- package/dist/reference/tables-validate.d.ts +21 -0
- package/dist/reference/tables-validate.js +13 -0
- package/dist/reference/types.d.ts +25 -2
- package/dist/reference/units-vocab.js +19 -1
- package/docs/VERSIONING.md +66 -0
- package/docs/authoring/README.md +96 -0
- package/docs/authoring/agents.md +63 -0
- package/docs/authoring/migrating.md +107 -0
- package/docs/authoring/notation.md +296 -0
- package/docs/authoring/versioning.md +116 -0
- package/docs/authoring/visualizations.md +195 -0
- package/package.json +20 -5
- package/src/compiler/cli.ts +49 -0
- package/src/compiler/collections.ts +52 -3
- package/src/compiler/course-config.ts +54 -0
- package/src/compiler/knowledge-version.ts +157 -0
- package/src/compiler/manifest.ts +270 -17
- package/src/components/CurriculumMap.astro +27 -0
- package/src/components/HoverPanel.astro +42 -0
- package/src/components/citation/CitationLayer.astro +1 -0
- package/src/components/diagram/Diagram.astro +317 -0
- package/src/components/examples/CompactExamples.astro +1 -1
- package/src/components/figure/Figure.astro +104 -0
- package/src/components/hover-panel.ts +71 -5
- package/src/components/notation/NotationFormula.astro +154 -0
- package/src/components/notation/NotationGlossary.astro +60 -0
- package/src/components/notation/NotationLayer.astro +248 -103
- package/src/components/notation/render-notation-math.ts +66 -0
- package/src/components/popup-stack.ts +345 -0
- package/src/components/reference/FloatRefLayer.astro +671 -0
- package/src/components/starlight/AboutPanel.astro +255 -0
- package/src/components/starlight/HeadingAnchorEnhancer.astro +131 -0
- package/src/components/starlight/KeyedFloatEnhancer.astro +137 -0
- package/src/components/starlight/LayoutSocialIcons.astro +12 -0
- package/src/components/starlight/LessonFooter.astro +8 -2
- package/src/components/table/Table.astro +104 -0
- package/src/content-config.ts +38 -0
- package/src/reference/base-operators.mjs +103 -0
- package/src/reference/consistency.ts +236 -2
- package/src/reference/diagram-layout.ts +246 -0
- package/src/reference/equations-validate.ts +6 -1
- package/src/reference/equations.mjs +118 -41
- package/src/reference/figures-validate.ts +40 -0
- package/src/reference/gate-math.ts +104 -7
- package/src/reference/gloss.ts +153 -0
- package/src/reference/keyed-float-validate.ts +207 -0
- package/src/reference/keyed-jsx-floats.mjs +167 -0
- package/src/reference/math-glyphs.mjs +92 -0
- package/src/reference/registry.ts +43 -0
- package/src/reference/rehype-heading-anchors.mjs +144 -0
- package/src/reference/remark-notation.mjs +228 -32
- package/src/reference/tables-validate.ts +40 -0
- package/src/reference/types.ts +26 -1
- package/src/reference/units-vocab.ts +18 -0
- package/src/styles/global.css +193 -3
- package/src/components/starlight/EquationEnhancer.astro +0 -72
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Authoring rules
|
|
2
|
+
|
|
3
|
+
Content rules for explico courses — strong recommendations for the people and
|
|
4
|
+
agents who write lessons, notation entries, and interactive figures.
|
|
5
|
+
|
|
6
|
+
## What these are
|
|
7
|
+
|
|
8
|
+
A course built on explico is authored by many hands — lecturers, TAs, AI
|
|
9
|
+
drafters — over a long time. These files fix the decisions that should not be
|
|
10
|
+
re-litigated per lesson: how a symbol is written, which library draws a graph,
|
|
11
|
+
how a randomised figure picks its axes.
|
|
12
|
+
|
|
13
|
+
Follow a rule unless you have a concrete, stateable reason not to — and then
|
|
14
|
+
leave that reason in the diff or the PR description. "I preferred it" is not a
|
|
15
|
+
reason; "the cited source writes it this way and the passage shows the mapping"
|
|
16
|
+
is.
|
|
17
|
+
|
|
18
|
+
Two kinds of rule live here:
|
|
19
|
+
|
|
20
|
+
- **Build-enforced** — the engine already fails the build when the rule is
|
|
21
|
+
broken. The rule text tells you _how_ to satisfy the gate, not whether to.
|
|
22
|
+
- **Review-only** — nothing checks it automatically; a reviewer does. Breaking
|
|
23
|
+
one is a review comment, not a broken build.
|
|
24
|
+
|
|
25
|
+
Every rule is written to be falsifiable: you can look at a lesson and say
|
|
26
|
+
whether it complies.
|
|
27
|
+
|
|
28
|
+
## Precedence
|
|
29
|
+
|
|
30
|
+
1. Build-enforced engine behaviour. If a rule here contradicts what the engine
|
|
31
|
+
actually does, the engine wins and the rule is stale — fix the rule.
|
|
32
|
+
2. These rules.
|
|
33
|
+
3. Author discretion, recorded in the diff.
|
|
34
|
+
|
|
35
|
+
A course may add its own rules on top — a house style for prose, a domain glyph
|
|
36
|
+
table. It must not silently relax one of these; loosening a rule is a change to
|
|
37
|
+
this folder, reviewed like any other change.
|
|
38
|
+
|
|
39
|
+
## How a rule is written
|
|
40
|
+
|
|
41
|
+
Each rule has a stable ID — a letter for its area (`N` notation,
|
|
42
|
+
`V` visualizations, `C` versioning) plus a number — and this shape:
|
|
43
|
+
|
|
44
|
+
> **N1 — One-line imperative.**
|
|
45
|
+
> _Rationale._ Why the rule exists; the failure it prevents.
|
|
46
|
+
> _How to apply._ Concrete steps, with the smallest example that shows it.
|
|
47
|
+
> _Enforcement._ Build-enforced (which gate) or Review-only.
|
|
48
|
+
> _Exceptions._ The stateable reasons that override it, if any.
|
|
49
|
+
|
|
50
|
+
IDs are permanent. A retired rule keeps its number, is struck through in the
|
|
51
|
+
index below, and gains a one-line `Retired <date>: <why>` note — so a `N3` in an
|
|
52
|
+
old commit message never goes ambiguous.
|
|
53
|
+
|
|
54
|
+
## Amending
|
|
55
|
+
|
|
56
|
+
1. Open a PR that touches exactly one area file plus the index table below.
|
|
57
|
+
2. Give a new rule the next unused number in its area. Never renumber.
|
|
58
|
+
3. Write the four parts above. If the rule could be build-enforced but is not
|
|
59
|
+
yet, say so and link the engine issue.
|
|
60
|
+
4. One maintainer review. The bar: is it falsifiable, is the rationale real, is
|
|
61
|
+
it not already covered by an existing rule or a schema.
|
|
62
|
+
|
|
63
|
+
A new area — a new letter and file — is the same PR shape plus a row in the
|
|
64
|
+
file table.
|
|
65
|
+
|
|
66
|
+
## Files
|
|
67
|
+
|
|
68
|
+
| File | Area | Covers |
|
|
69
|
+
| -------------------------------- | ---- | --------------------------------------------------------- |
|
|
70
|
+
| [notation.md](notation.md) | `N` | how math symbols are written and bound |
|
|
71
|
+
| [visualizations.md](visualizations.md) | `V` | diagrams, charts, interactive figures, randomness |
|
|
72
|
+
| [versioning.md](versioning.md) | `C` | the knowledge version and `content/CHANGELOG.md` |
|
|
73
|
+
| [agents.md](agents.md) | — | _guide_: working on a course repo (with an AI agent) |
|
|
74
|
+
| [migrating.md](migrating.md) | — | _guide_: per-version steps when bumping the `explico` dep |
|
|
75
|
+
|
|
76
|
+
## Rule index
|
|
77
|
+
|
|
78
|
+
| ID | Rule | Enforcement |
|
|
79
|
+
| ------------------------------- | ---------------------------------------------------------------- | ------------------------------------------- |
|
|
80
|
+
| [N1](notation.md#n1) | The normal distribution is `\mathcal{N}` | Build-enforced (completeness gate) + review |
|
|
81
|
+
| [N2](notation.md#n2) | `\mathbb{N,Z,R,C}` are reserved for the number systems | Partial — gate forces every other `\mathbb{}` to resolve |
|
|
82
|
+
| [N3](notation.md#n3) | Multi-letter roman labels use `\mathrm{…}` | Build-enforced (completeness gate) |
|
|
83
|
+
| [N4](notation.md#n4) | One meaning per glyph; define once; `[[key]]` before first math | Build-enforced (completeness gate) |
|
|
84
|
+
| [N5](notation.md#n5) | Referenced display equations carry `\label{eq:key}` | Review-only |
|
|
85
|
+
| [N6](notation.md#n6) | Probability is `\mathbb{P}` (double-struck `P`) | Build-enforced (completeness gate) + review |
|
|
86
|
+
| [N7](notation.md#n7) | The differential `d` is upright `\mathrm{d}` | Build-enforced (completeness gate) |
|
|
87
|
+
| [N8](notation.md#n8) | A named operator is universal (shipped/course list) or explained | Tier-3 warning (`operator-explained`) |
|
|
88
|
+
| [V1](visualizations.md#v1) | Graphs and flowcharts use the `Diagram` component | Review-only |
|
|
89
|
+
| [V2](visualizations.md#v2) | Static charts: SVG → D3 → Observable Plot, chosen per figure | Review-only |
|
|
90
|
+
| [V3](visualizations.md#v3) | Interactive figures: island + `renderLabMath` seam + text alt | Review-only |
|
|
91
|
+
| [V4](visualizations.md#v4) | Randomised figures expose an adjustable, deterministic seed | Review-only |
|
|
92
|
+
| [V5](visualizations.md#v5) | Axis ranges span the first 10 seeds at the current control values | Review-only |
|
|
93
|
+
| [C1](versioning.md#c1) | Every content change lands with a `content/CHANGELOG.md` entry | Review-only |
|
|
94
|
+
| [C2](versioning.md#c2) | The knowledge version is semver over learning-facing content | Review-only |
|
|
95
|
+
| [C3](versioning.md#c3) | `about.version` equals the newest `content/CHANGELOG.md` heading | Build-enforced (Tier-3 `knowledge-version-mismatch`) |
|
|
96
|
+
| [C4](versioning.md#c4) | On release, move `[Unreleased]` and bump `about.version` together | Review-only |
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Working on an explico course (with an agent)
|
|
2
|
+
|
|
3
|
+
Guidance for an AI agent — or a person — editing a course repo built on
|
|
4
|
+
`explico`. The engine ships this so a downstream course inherits a baseline; add
|
|
5
|
+
a repo-specific `AGENTS.md` at your course root for anything below that is
|
|
6
|
+
particular to your layout.
|
|
7
|
+
|
|
8
|
+
This is a guide, not a rule area. The enforceable rules are in
|
|
9
|
+
[`notation.md`](notation.md) (`N`), [`visualizations.md`](visualizations.md)
|
|
10
|
+
(`V`), and [`versioning.md`](versioning.md) (`C`). When the engine's behaviour
|
|
11
|
+
and a rule disagree, the engine wins — see [`README.md`](README.md).
|
|
12
|
+
|
|
13
|
+
## The loop
|
|
14
|
+
|
|
15
|
+
- **Start from the CLI, not a file hunt.** `pnpm --filter <course> content
|
|
16
|
+
context <lesson>` prints a lesson plus exactly its notation, references, and
|
|
17
|
+
assumptions. `pnpm content status` is the draft-debt overview. `pnpm content
|
|
18
|
+
check <lesson> | --changed` is schema + refs + MDX→KaTeX, exits non-zero on an
|
|
19
|
+
error. Read those before opening files.
|
|
20
|
+
- **Validate, twice.** `pnpm --filter <course> validate:content` regenerates
|
|
21
|
+
`build/resolution/*` and then fails on the same run that changed them. Run it
|
|
22
|
+
again; the second run is clean. Commit the regenerated `build/` and
|
|
23
|
+
`resolution/` files.
|
|
24
|
+
- **Before handing work back:** `validate:content` (×2) → `astro check` →
|
|
25
|
+
`astro build`. `astro build` is the only step that runs every gate the CI
|
|
26
|
+
does.
|
|
27
|
+
|
|
28
|
+
## Reading and running
|
|
29
|
+
|
|
30
|
+
- Grep for a symbol and open a line range; don't read a whole engine module out
|
|
31
|
+
of `node_modules/explico/`. The parts you actually need are
|
|
32
|
+
[`notation.md`](notation.md), this file, and the `content` CLI output.
|
|
33
|
+
- If a page 500s or a change doesn't show, the dev server's content store is
|
|
34
|
+
stale — a **new file in a `content/` collection needs a dev-server restart**,
|
|
35
|
+
not just a save. Restart it; don't diagnose it with `ps` / `curl` scrapes.
|
|
36
|
+
- Ad-hoc Node scripts run from the course package (workspace deps aren't at the
|
|
37
|
+
repo root); Playwright imports as `@playwright/test`.
|
|
38
|
+
- Pipe long command output to `| tail -n 40`. One-off probes and fetched pages
|
|
39
|
+
go to a scratch file you then grep — not into the conversation whole.
|
|
40
|
+
|
|
41
|
+
## Notation `formula:` fields (the sharp edges)
|
|
42
|
+
|
|
43
|
+
- Every glyph in a `formula:` must resolve: to the entry itself, one of its
|
|
44
|
+
`glosses:`, a card named with `\explain{key}{latex}`, or the base library.
|
|
45
|
+
An unresolved bare letter fails the build with the entry name.
|
|
46
|
+
- The notation reference graph must be **acyclic** — if `a`'s formula names `b`
|
|
47
|
+
and `b`'s names `a`, the build rejects it. Link only *down* a chain
|
|
48
|
+
(acceleration → velocity → position, not back up).
|
|
49
|
+
- Use `\mathbf` for a vector, not `\vec`: `\vec` currently trips the KaTeX
|
|
50
|
+
sanitizer in `render-notation-math`. (Engine bug, not a rule — but `\mathbf`
|
|
51
|
+
is what builds today.)
|
|
52
|
+
|
|
53
|
+
## Versioning
|
|
54
|
+
|
|
55
|
+
Every content change adds a bullet under `## [Unreleased]` in
|
|
56
|
+
`content/CHANGELOG.md`; a release moves it to a dated `## [x.y.z]` heading and
|
|
57
|
+
sets `about.version` to match, in the same commit. Rules C1–C4,
|
|
58
|
+
[`versioning.md`](versioning.md).
|
|
59
|
+
|
|
60
|
+
## Upgrading the engine
|
|
61
|
+
|
|
62
|
+
[`migrating.md`](migrating.md) — the per-version steps when you bump the
|
|
63
|
+
`explico` dependency across a **Breaking** entry in `CHANGELOG.md`.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Upgrading the explico engine
|
|
2
|
+
|
|
3
|
+
What a course repo has to change when it bumps its `explico` dependency across a
|
|
4
|
+
version that carries **Breaking** notes. Each section is the concrete work; the
|
|
5
|
+
matching `CHANGELOG.md` entry (shipped in the installed package) is the full
|
|
6
|
+
list of what moved and why.
|
|
7
|
+
|
|
8
|
+
The pattern every time:
|
|
9
|
+
|
|
10
|
+
1. `pnpm add -D explico@<version>`
|
|
11
|
+
2. Do the per-version steps below.
|
|
12
|
+
3. `pnpm validate:content` (run it **twice** — the first run regenerates
|
|
13
|
+
`build/resolution/*` and reports it stale; the second is clean), then
|
|
14
|
+
`pnpm content check --changed`, then `astro check`, then `astro build`.
|
|
15
|
+
Each stage names what it doesn't like; fix and re-run.
|
|
16
|
+
|
|
17
|
+
The engine never fails silently on a migration it can detect: a missing
|
|
18
|
+
required config block throws with the section of this file to read.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 0.2.x → 0.3.0
|
|
23
|
+
|
|
24
|
+
### 1. Add the required `about` block to `content/course.config.ts`
|
|
25
|
+
|
|
26
|
+
`CourseConfig` now requires an `about` block — the reader-facing identity behind
|
|
27
|
+
the header `[?]` panel, and the course's **knowledge version**. Building without
|
|
28
|
+
it throws `course.config.ts is missing a complete about block …`.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
export const courseConfig = {
|
|
32
|
+
title: 'My Course',
|
|
33
|
+
description: '…',
|
|
34
|
+
// …existing fields…
|
|
35
|
+
about: {
|
|
36
|
+
// materialName and summary default to title / description
|
|
37
|
+
version: '0.1.0', // the knowledge version — semver
|
|
38
|
+
authors: [{ name: 'A. Lecturer', contact: 'a.lecturer@example.edu' }],
|
|
39
|
+
disclaimer:
|
|
40
|
+
'Draft study material. No warranty. Parts are AI-assisted and under review.',
|
|
41
|
+
changelogHref: 'https://…/content/CHANGELOG.md', // optional
|
|
42
|
+
},
|
|
43
|
+
} satisfies CourseConfig;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Add `content/CHANGELOG.md`
|
|
47
|
+
|
|
48
|
+
The knowledge version (`about.version`) must equal the newest `## [x.y.z]`
|
|
49
|
+
heading in `content/CHANGELOG.md`. A missing file or a mismatch is a Tier-3
|
|
50
|
+
`knowledge-changelog-missing` / `knowledge-version-mismatch` warning (it does
|
|
51
|
+
not fail the build). Governance: [`versioning.md`](versioning.md), rules C1–C4.
|
|
52
|
+
|
|
53
|
+
```markdown
|
|
54
|
+
# Knowledge changelog — <course>
|
|
55
|
+
|
|
56
|
+
## [Unreleased]
|
|
57
|
+
|
|
58
|
+
## [0.1.0] - 2026-01-01
|
|
59
|
+
|
|
60
|
+
- Initial content.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 3. Show the About panel
|
|
64
|
+
|
|
65
|
+
The `[?]` panel renders through Starlight's `SocialIcons` slot. Add it to the
|
|
66
|
+
`components` map in `astro.config.mjs` (alongside the `Footer` override you
|
|
67
|
+
already have):
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
starlight({
|
|
71
|
+
components: {
|
|
72
|
+
Footer: 'explico/components/starlight/LessonFooter.astro',
|
|
73
|
+
SocialIcons: 'explico/components/starlight/LayoutSocialIcons.astro',
|
|
74
|
+
// …
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The build still succeeds without this; the panel just won't appear.
|
|
80
|
+
|
|
81
|
+
### 4. Only if you imported the equation-reference components directly
|
|
82
|
+
|
|
83
|
+
`EquationEnhancer` and `EquationRefLayer` are gone, replaced by
|
|
84
|
+
`KeyedFloatEnhancer` + `FloatRefLayer` (one hover/pin/jump engine now shared by
|
|
85
|
+
equation, `Figure`, and `Table` references). **If you only wire
|
|
86
|
+
`Footer: 'explico/components/starlight/LessonFooter.astro'`, there is nothing to
|
|
87
|
+
do** — the swap is internal to that component. Only a course that forked
|
|
88
|
+
`LessonFooter` or imported the old components by hand updates its imports:
|
|
89
|
+
|
|
90
|
+
| Removed | Use |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| `explico/components/starlight/EquationEnhancer.astro` | `explico/components/starlight/KeyedFloatEnhancer.astro` |
|
|
93
|
+
| `explico/components/equation/EquationRefLayer.astro` | `explico/components/reference/FloatRefLayer.astro` |
|
|
94
|
+
|
|
95
|
+
### 5. Regenerate — the manifest schema bumped
|
|
96
|
+
|
|
97
|
+
`MANIFEST_SCHEMA_VERSION` increased (additive: `manifest.about`,
|
|
98
|
+
`manifest.diagnostics.knowledge`; existing fields unchanged). `pnpm
|
|
99
|
+
validate:content` rewrites `build/manifest.json`; commit the result. An external
|
|
100
|
+
consumer that pins the schema version needs to accept the new number.
|
|
101
|
+
|
|
102
|
+
### New, no action required
|
|
103
|
+
|
|
104
|
+
`Figure` / `Table` components with numbering and `[[fig-<id>]]` / `[[tab-<id>]]`
|
|
105
|
+
references; `Diagram` gains `direction="LR"` and an optional `description`;
|
|
106
|
+
`\explain{key}{latex}` works inside notation `formula:` fields; heading anchors
|
|
107
|
+
and numbered equations are on by default.
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# Notation rules
|
|
2
|
+
|
|
3
|
+
`N` rules govern how a mathematical symbol is written in any rendered-math
|
|
4
|
+
context: lesson body, `notation.formula`, `checks.yml`, assessment prompts, and
|
|
5
|
+
the `formula` slots of `Diagram` / lab components. The completeness gate scans
|
|
6
|
+
all of these, so "the build passed" already means most of what follows holds —
|
|
7
|
+
these rules pin the _choices_ the gate leaves open.
|
|
8
|
+
|
|
9
|
+
See [README.md](README.md) for what "strong recommendation", "Build-enforced",
|
|
10
|
+
and "Review-only" mean here, and how to amend a rule.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## N1
|
|
15
|
+
|
|
16
|
+
**The normal distribution is `\mathcal{N}`.**
|
|
17
|
+
|
|
18
|
+
Write a Gaussian as `\mathcal{N}(\mu, \sigma^2)` — calligraphic `N`,
|
|
19
|
+
parameterised by **mean and variance**. Name any other named distribution the
|
|
20
|
+
same way: a calligraphic letter through `\mathcal{…}`.
|
|
21
|
+
|
|
22
|
+
Do not use `N(\mu, \sigma^2)`, `\mathrm{N}`, `Norm(...)`, or `\mathbb{N}` — the
|
|
23
|
+
last is the natural numbers ([N2](#n2)) and a build-reserved token.
|
|
24
|
+
|
|
25
|
+
_Rationale._ One corpus-wide spelling makes the symbol searchable, lets it bind
|
|
26
|
+
to a single notation card, and keeps it clear of `N` used as a count and
|
|
27
|
+
`\mathbb{N}` used as a set. Mean/variance is the form the standard-normal CDF
|
|
28
|
+
`\Phi` and PDF `\varphi` compose with cleanly.
|
|
29
|
+
|
|
30
|
+
_How to apply._
|
|
31
|
+
|
|
32
|
+
- Define it once. Add a notation entry — a shared card if the course teaches
|
|
33
|
+
probability, otherwise `notation.local` on the first lesson that needs it:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
key: prob.normal
|
|
37
|
+
latex: \mathcal{N}
|
|
38
|
+
label: Normal distribution
|
|
39
|
+
meaning: Gaussian distribution with mean μ and variance σ².
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then introduce it in prose with `[[prob.normal]]` before its first appearance
|
|
43
|
+
in math, exactly like any other shared glyph ([N4](#n4)).
|
|
44
|
+
|
|
45
|
+
- In a one-off context where a full entry is overkill, use the escape hatch:
|
|
46
|
+
`\explain{prob.normal}{\mathcal{N}}(\mu, \sigma^2)`. Prefer the entry.
|
|
47
|
+
|
|
48
|
+
- If a course standardises on standard deviation rather than variance, state
|
|
49
|
+
that once in the domain notes, then write `\mathcal{N}(\mu, \sigma)`
|
|
50
|
+
consistently. Never mix the two forms in one corpus.
|
|
51
|
+
|
|
52
|
+
- Compose consistently: `X \sim \mathcal{N}(\mu, \sigma^2)`,
|
|
53
|
+
`\Phi` for its CDF, `\varphi` for its PDF. Pick the CDF/PDF glyphs once per
|
|
54
|
+
course.
|
|
55
|
+
|
|
56
|
+
_Enforcement._ Build-enforced that the symbol resolves to a key — `\mathcal{N}`
|
|
57
|
+
is a bindable identifier atom to the glyph resolver, so an undefined one fails
|
|
58
|
+
the completeness gate at `file:line:token`. The choice of `\mathcal{N}` over
|
|
59
|
+
`N` / `\mathrm{N}` / `Norm` is convention, checked in review.
|
|
60
|
+
|
|
61
|
+
_Exceptions._ Quoting a source that uses a different glyph **and** showing the
|
|
62
|
+
mapping to `\mathcal{N}` in the same passage.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## N2
|
|
67
|
+
|
|
68
|
+
**`\mathbb{N}`, `\mathbb{Z}`, `\mathbb{R}`, `\mathbb{C}` are reserved for the
|
|
69
|
+
number systems.**
|
|
70
|
+
|
|
71
|
+
These four blackboard-bold tokens mean the naturals, integers, reals, and
|
|
72
|
+
complexes, always, and need no notation key. Every _other_ `\mathbb{…}` —
|
|
73
|
+
`\mathbb{E}`, `\mathbb{P}`, `\mathbb{Q}`, `\mathbb{1}` — is an ordinary
|
|
74
|
+
identifier that must resolve to a semantic key.
|
|
75
|
+
|
|
76
|
+
_Rationale._ The universal sets are genuinely universal; forcing a per-page
|
|
77
|
+
definition of `\mathbb{R}` would be noise. Everything else in blackboard bold
|
|
78
|
+
is domain-specific (an expectation, a probability measure, an indicator) and
|
|
79
|
+
earns a card.
|
|
80
|
+
|
|
81
|
+
_How to apply._ Need the rationals as a set on one lesson? That collides with a
|
|
82
|
+
reserved token — reach for `\explain{...}{\mathbb{Q}}` or a differently-styled
|
|
83
|
+
glyph, and note it in the domain vocabulary.
|
|
84
|
+
|
|
85
|
+
_Enforcement._ Partial. The gate forces every non-reserved `\mathbb{…}` to
|
|
86
|
+
resolve; keeping `N/Z/R/C` for the number systems (not, say, `\mathbb{N}` for a
|
|
87
|
+
sample size) is convention.
|
|
88
|
+
|
|
89
|
+
_Exceptions._ None for the four reserved tokens.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## N3
|
|
94
|
+
|
|
95
|
+
**Multi-letter roman labels use `\mathrm{…}`.**
|
|
96
|
+
|
|
97
|
+
An upright multi-letter name — `\mathrm{PV}`, `\mathrm{opt}`, `\mathrm{max}`
|
|
98
|
+
where no built-in operator exists — is wrapped in `\mathrm{}`. Never write it as
|
|
99
|
+
a run of bare italic letters (`PV`), which reads as a product `P \cdot V`.
|
|
100
|
+
|
|
101
|
+
_Rationale._ `\mathrm{}` is a typographic label, not a bindable atom — the glyph
|
|
102
|
+
resolver skips its body whole. Bare letter runs are parsed as identifier atoms,
|
|
103
|
+
so `PV` asks the gate to resolve `P` and `V` separately: a build failure at
|
|
104
|
+
best, a wrong binding at worst.
|
|
105
|
+
|
|
106
|
+
_How to apply._ Subscripts too: `v_{\mathrm{max}}`, not `v_{max}`.
|
|
107
|
+
|
|
108
|
+
_Enforcement._ Build-enforced indirectly — bare multi-letter runs hit the
|
|
109
|
+
completeness gate as unresolved identifiers.
|
|
110
|
+
|
|
111
|
+
_Exceptions._ Genuine products, and single-letter subscripts that are
|
|
112
|
+
themselves notation keys.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## N4
|
|
117
|
+
|
|
118
|
+
**One meaning per glyph per page; define once; introduce with `[[key]]` before
|
|
119
|
+
the first math use.**
|
|
120
|
+
|
|
121
|
+
A glyph has exactly one meaning on a page. A shared symbol is introduced in
|
|
122
|
+
prose with `[[key]]` before it appears in any equation. `\explain{key}{latex}`
|
|
123
|
+
is the escape hatch for a compound or glyph-colliding symbol only — not the
|
|
124
|
+
default way to bind.
|
|
125
|
+
|
|
126
|
+
_Rationale._ This is the core contract the completeness gate enforces
|
|
127
|
+
corpus-wide; the rule here is just its author-facing statement. A reader hovers
|
|
128
|
+
any symbol and gets exactly one card.
|
|
129
|
+
|
|
130
|
+
_How to apply._ See the engine README's notation section and the `notation`
|
|
131
|
+
collection schema. A letter that exists only so one entry's own `formula` can
|
|
132
|
+
be stated is a **gloss**, not a card — it creates no curriculum edge.
|
|
133
|
+
|
|
134
|
+
_Enforcement._ Build-enforced (completeness gate + one-meaning-per-glyph
|
|
135
|
+
consistency check).
|
|
136
|
+
|
|
137
|
+
_Exceptions._ None. Genuinely different meanings need different glyphs or
|
|
138
|
+
different pages.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## N5
|
|
143
|
+
|
|
144
|
+
**A display equation referenced later carries `\label{eq:key}`.**
|
|
145
|
+
|
|
146
|
+
If prose points back at a display equation — this page or another — the equation
|
|
147
|
+
has `\label{eq:key}` and the reference is `[[eq-key]]`. Do not hand-number
|
|
148
|
+
equations in the text.
|
|
149
|
+
|
|
150
|
+
_Rationale._ The engine numbers every display equation `‹chapter›.‹n›` — the
|
|
151
|
+
chapter is the lesson's position in the course, `n` counts the display
|
|
152
|
+
equations in the lesson in appearance order (`##` sub-headings do not affect
|
|
153
|
+
it) — and derives the anchor and any cross-lesson link from the label. A
|
|
154
|
+
hand-typed "(3)" goes stale the moment an equation is inserted above it, or the
|
|
155
|
+
lesson moves in the course order. `<Table>` and `<Figure>` are numbered the
|
|
156
|
+
same way, each with its own counter.
|
|
157
|
+
|
|
158
|
+
_How to apply._ Only label equations you actually reference; an unlabelled
|
|
159
|
+
display equation is still fine.
|
|
160
|
+
|
|
161
|
+
_Enforcement._ Review-only — an unlabelled-but-referenced equation builds; a
|
|
162
|
+
reviewer catches the hand-numbering.
|
|
163
|
+
|
|
164
|
+
_Exceptions._ None worth stating.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## N6
|
|
169
|
+
|
|
170
|
+
**Probability is `\mathbb{P}` — double-struck `P`.**
|
|
171
|
+
|
|
172
|
+
Write a probability as `\mathbb{P}(A)` — blackboard-bold `P`. Not `P(A)` (a bare
|
|
173
|
+
`P` is a variable — a price, a power, a point), not `\Pr`, not `\text{Prob}`.
|
|
174
|
+
Expectation is the same family: `\mathbb{E}[X]`.
|
|
175
|
+
|
|
176
|
+
_Rationale._ `\mathbb{P}` is unmistakably the probability functional, never a
|
|
177
|
+
quantity. It reads next to `\mathbb{E}` and `\mathbb{Q}` as one notation family
|
|
178
|
+
and never collides with a `P` the lesson uses for something physical.
|
|
179
|
+
|
|
180
|
+
_How to apply._
|
|
181
|
+
|
|
182
|
+
- Define it once, like [N1](#n1):
|
|
183
|
+
|
|
184
|
+
```yaml
|
|
185
|
+
key: prob.p
|
|
186
|
+
latex: \mathbb{P}
|
|
187
|
+
label: Probability
|
|
188
|
+
meaning: Probability of an event.
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Introduce it in prose with `[[prob.p]]` before its first appearance in math.
|
|
192
|
+
|
|
193
|
+
- Conditional probability is `\mathbb{P}(A \mid B)` — `\mid`, not a bare `|`.
|
|
194
|
+
|
|
195
|
+
- A course doing measure theory may define `\mathbb{P}` as the real-world
|
|
196
|
+
measure and `\mathbb{Q}` as a risk-neutral one, consistent with the reserved
|
|
197
|
+
reading of `\mathbb{Q}` ([N2](#n2)). State that split once in the domain
|
|
198
|
+
notes.
|
|
199
|
+
|
|
200
|
+
_Enforcement._ Build-enforced that the symbol resolves to a key — `\mathbb{P}`
|
|
201
|
+
is a non-reserved `\mathbb{…}` and the completeness gate demands a binding
|
|
202
|
+
([N2](#n2)). The choice of `\mathbb{P}` over `P` / `\Pr` is convention.
|
|
203
|
+
|
|
204
|
+
_Exceptions._ Quoting a source that writes `\Pr` or `P` **and** showing the
|
|
205
|
+
mapping to `\mathbb{P}` in the same passage.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## N7
|
|
210
|
+
|
|
211
|
+
**The differential `d` is upright `\mathrm{d}`.**
|
|
212
|
+
|
|
213
|
+
The `d` of an integrand and the `d` of a derivative are the same operator and
|
|
214
|
+
get the same upright form — distinct from an italic `d`, which is always a
|
|
215
|
+
variable (a distance, a day count, a dimension):
|
|
216
|
+
|
|
217
|
+
- `\int_a^b f(x)\,\mathrm{d}x` — thin space `\,`, then `\mathrm{d}x`.
|
|
218
|
+
- `\dfrac{\mathrm{d}f}{\mathrm{d}x}`, `\dfrac{\mathrm{d}^2 f}{\mathrm{d}x^2}`.
|
|
219
|
+
- `\mathrm{d}s`, `\mathrm{d}A`, `\mathrm{d}V`, `\mathrm{d}t` — same rule for
|
|
220
|
+
every differential.
|
|
221
|
+
|
|
222
|
+
A partial derivative uses `\partial` bare — `\dfrac{\partial f}{\partial x}` —
|
|
223
|
+
which is already distinct; do not wrap it in anything.
|
|
224
|
+
|
|
225
|
+
_Rationale._ This is the ISO 80000-2 convention. Upright `\mathrm{d}` cannot be
|
|
226
|
+
read as a factor `d \cdot x`, and it stays clear of a notation key `d` on a
|
|
227
|
+
lesson that happens to have one.
|
|
228
|
+
|
|
229
|
+
_How to apply._ `\mathrm{d}` is a typographic operator, not a bindable atom —
|
|
230
|
+
the glyph resolver skips its body like any `\mathrm{…}` label ([N3](#n3)), so it
|
|
231
|
+
needs no notation key. Only the variable of integration (`x`, `t`) still has to
|
|
232
|
+
resolve.
|
|
233
|
+
|
|
234
|
+
_Enforcement._ Build-enforced indirectly — a bare `\int f(x) dx` puts an
|
|
235
|
+
unresolved identifier `d` in front of the completeness gate ([N3](#n3)).
|
|
236
|
+
|
|
237
|
+
_Exceptions._ A verbatim quotation of a source in a blockquote.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## N8
|
|
242
|
+
|
|
243
|
+
**A named operator is universal, or it is explained.**
|
|
244
|
+
|
|
245
|
+
Every named operator a lesson uses — `\exp`, `\int`, `\sin`, … as built-ins,
|
|
246
|
+
`\operatorname{Var}`, `\operatorname{Cov}`, `\operatorname{E}` as declared ones
|
|
247
|
+
— is either on the shipped operator baseline (`src/reference/base-operators.mjs`
|
|
248
|
+
plus this course's `operators.allow` in `course.config.ts`) or it carries a
|
|
249
|
+
notation entry the reader can hover.
|
|
250
|
+
|
|
251
|
+
_Rationale._ The completeness gate has no opinion about operators: KaTeX parses
|
|
252
|
+
`\exp` as an operator node and `\operatorname{Var}` as an `operatorname` node,
|
|
253
|
+
and the glyph resolver skips both whole ([N3](#n3)). So `\operatorname{Var}`
|
|
254
|
+
renders fine while the reader is never told what "Var" means. `\exp` and `\int`
|
|
255
|
+
need no such help — everyone knows them — but a domain operator does, and the
|
|
256
|
+
line between the two is a course decision, made once, not per lesson.
|
|
257
|
+
|
|
258
|
+
_How to apply._
|
|
259
|
+
|
|
260
|
+
- Universal operators — trig, `\exp` / `\ln` / `\log`, `\lim`, `\max` / `\min`
|
|
261
|
+
/ `\sup` / `\inf`, `\sum` / `\prod` / `\int` — just work. The full baseline is
|
|
262
|
+
the greppable set in `base-operators.mjs`.
|
|
263
|
+
|
|
264
|
+
- A domain operator gets a notation entry, exactly like a glyph ([N4](#n4)) — a
|
|
265
|
+
shared card if the course teaches it broadly, otherwise `notation.local`:
|
|
266
|
+
|
|
267
|
+
```yaml
|
|
268
|
+
key: stats.variance
|
|
269
|
+
latex: \operatorname{Var}
|
|
270
|
+
label: Variance
|
|
271
|
+
meaning: Expected squared deviation of a random variable from its mean.
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Then introduce it in prose with `[[stats.variance]]` before its first
|
|
275
|
+
appearance in math, and write it `\operatorname{Var}(X)` — never `Var(X)`
|
|
276
|
+
(bare letters, [N3](#n3)) and never `\mathrm{Var}` (a label, not an operator).
|
|
277
|
+
|
|
278
|
+
- A course whose domain treats an operator as common — `\operatorname{Var}`,
|
|
279
|
+
`\operatorname{Cov}`, `\operatorname{Corr}`, `\operatorname{sgn}` in a
|
|
280
|
+
statistics course — lists it once in `course.config.ts` instead:
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
operators: { allow: ['Var', 'Cov', 'Corr', 'sgn'] }
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Names are the `\operatorname{…}` body, or the command without its backslash
|
|
287
|
+
for a built-in. `operators.deny` forces a baseline operator to be explained
|
|
288
|
+
anyway.
|
|
289
|
+
|
|
290
|
+
_Enforcement._ Tier-3 warning (`operator-explained`), surfaced by
|
|
291
|
+
`pnpm validate:content`, recorded in the manifest, and silenced only by a
|
|
292
|
+
reviewed line in `lint-ignore.yml` (`operator-explained:Var — <reason>`). Like
|
|
293
|
+
`formula` before it (D15), the tier can be promoted once a corpus is clean.
|
|
294
|
+
|
|
295
|
+
_Exceptions._ Quoting a source that uses an operator glyph **and** showing what
|
|
296
|
+
it means in the same passage.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Versioning rules
|
|
2
|
+
|
|
3
|
+
`C` rules govern the course's **knowledge version** — semver over the
|
|
4
|
+
learning-facing content, independent of the `explico` engine's own version. The
|
|
5
|
+
declared value is `about.version` in `content/course.config.ts`; the history and
|
|
6
|
+
the reader-facing notes are in `content/CHANGELOG.md`. Both are surfaced to
|
|
7
|
+
readers by the About `[?]` panel.
|
|
8
|
+
|
|
9
|
+
See [README.md](README.md) for what "Build-enforced" and "Review-only" mean here.
|
|
10
|
+
The engine's own versioning is a separate policy —
|
|
11
|
+
[`docs/VERSIONING.md`](../VERSIONING.md).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## C1
|
|
16
|
+
|
|
17
|
+
**Every content change lands with a `content/CHANGELOG.md` entry under
|
|
18
|
+
`## [Unreleased]`.**
|
|
19
|
+
|
|
20
|
+
A change to any lesson `.mdx`, notation entry, assessment, competency, source,
|
|
21
|
+
`content/domain/` file, or `course.config.ts` gets a bullet under
|
|
22
|
+
`## [Unreleased]` in the same commit.
|
|
23
|
+
|
|
24
|
+
_Rationale._ The knowledge version is meaningless without a record of what moved
|
|
25
|
+
between two values of it. A reader who sees "knowledge v1.4.0" in the `[?]` panel
|
|
26
|
+
can follow `changelogHref` to find out what 1.4.0 means.
|
|
27
|
+
|
|
28
|
+
_How to apply._ Keep a Changelog shape. One bullet per user-visible change,
|
|
29
|
+
written for a reader, not a commit log:
|
|
30
|
+
|
|
31
|
+
```markdown
|
|
32
|
+
## [Unreleased]
|
|
33
|
+
|
|
34
|
+
- Reworked the "Optimal Launch Angle" derivation to use the identity
|
|
35
|
+
`sin(2θ) = 2 sinθ cosθ` explicitly.
|
|
36
|
+
- New lesson: "Projectile Range with Drag" (motion.range-drag).
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
_Enforcement._ Review-only. Rule [C3](#c3) partially enforces it: a content
|
|
40
|
+
change with no matching version bump eventually trips the mismatch warning.
|
|
41
|
+
|
|
42
|
+
_Exceptions._ A pure typo fix in prose that changes no rendered symbol, no
|
|
43
|
+
number, and no outcome. When in doubt, add the bullet.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## C2
|
|
48
|
+
|
|
49
|
+
**The knowledge version is semver over learning-facing content.**
|
|
50
|
+
|
|
51
|
+
Pick the bump by the largest change in the release:
|
|
52
|
+
|
|
53
|
+
- **MAJOR** — a lesson, competency, or notation `key` is removed or renamed; a
|
|
54
|
+
stated learning outcome (`teaches`, a competency `outcome`) changes; a result
|
|
55
|
+
or convention a reader may have memorised changes.
|
|
56
|
+
- **MINOR** — something new and backward-compatible: a new lesson, section,
|
|
57
|
+
notation entry, assessment, or worked example.
|
|
58
|
+
- **PATCH** — a fix or clarification: corrected arithmetic, better prose, a added
|
|
59
|
+
or fixed `[@source]`, a non-semantic notation tweak.
|
|
60
|
+
|
|
61
|
+
_Rationale._ A downstream consumer of the content (an LMS import, a printed
|
|
62
|
+
reader, a course that forks this one) needs the same "did this break me?" signal
|
|
63
|
+
from the knowledge version that a library gets from a package version.
|
|
64
|
+
|
|
65
|
+
_How to apply._ Decide the bump when you move `## [Unreleased]` to a dated
|
|
66
|
+
heading ([C4](#c4)); set `about.version` to match.
|
|
67
|
+
|
|
68
|
+
_Enforcement._ Review-only.
|
|
69
|
+
|
|
70
|
+
_Exceptions._ None. If a change does not fit a tier, it is PATCH.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## C3
|
|
75
|
+
|
|
76
|
+
**`about.version` equals the newest `## [x.y.z]` heading in
|
|
77
|
+
`content/CHANGELOG.md`.**
|
|
78
|
+
|
|
79
|
+
_Rationale._ Two sources of the same fact must not drift. The manifest — and so
|
|
80
|
+
the `[?]` panel — reads `about.version`; a reader chasing "what changed" reads
|
|
81
|
+
the changelog. If they disagree, one is lying.
|
|
82
|
+
|
|
83
|
+
_How to apply._ On a release, edit both in the same commit ([C4](#c4)). Between
|
|
84
|
+
releases, `about.version` stays at the last released value while
|
|
85
|
+
`## [Unreleased]` accumulates bullets.
|
|
86
|
+
|
|
87
|
+
_Enforcement._ Build-enforced (Tier-3). `pnpm validate:content` emits
|
|
88
|
+
`knowledge-version-mismatch` when they differ, `knowledge-changelog-missing`
|
|
89
|
+
when there is no released heading, and `knowledge-version-invalid` when
|
|
90
|
+
`about.version` is not `x.y.z`. All are warnings — they never fail the build, but
|
|
91
|
+
CI may choose to.
|
|
92
|
+
|
|
93
|
+
_Exceptions._ None.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## C4
|
|
98
|
+
|
|
99
|
+
**On a release, move `## [Unreleased]` to `## [x.y.z] - YYYY-MM-DD` and bump
|
|
100
|
+
`about.version` in the same commit.**
|
|
101
|
+
|
|
102
|
+
_Rationale._ A release is the atomic moment the two records agree again
|
|
103
|
+
([C3](#c3)). Splitting it across commits leaves a window where the build warns
|
|
104
|
+
and the panel is wrong.
|
|
105
|
+
|
|
106
|
+
_How to apply._
|
|
107
|
+
|
|
108
|
+
1. Choose `x.y.z` from the accumulated `## [Unreleased]` bullets and [C2](#c2).
|
|
109
|
+
2. Rename the heading to `## [x.y.z] - <today>`; add a fresh empty
|
|
110
|
+
`## [Unreleased]` above it.
|
|
111
|
+
3. Set `about.version` in `content/course.config.ts` to `x.y.z`.
|
|
112
|
+
4. `pnpm validate:content` — no `knowledge-*` warning.
|
|
113
|
+
|
|
114
|
+
_Enforcement._ Review-only (the end state is checked by [C3](#c3)).
|
|
115
|
+
|
|
116
|
+
_Exceptions._ None.
|