explico 0.5.0 → 0.7.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 +295 -7
- package/README.md +16 -2
- package/dist/compiler/astro.d.ts +13 -2
- package/dist/compiler/astro.js +39 -0
- package/dist/compiler/cli.d.ts +22 -3
- package/dist/compiler/cli.js +71 -10
- package/dist/compiler/course-config.d.ts +31 -1
- package/dist/compiler/course-config.js +7 -0
- package/dist/compiler/exports/standalone-html.js +13 -0
- package/dist/compiler/logging.d.ts +109 -0
- package/dist/compiler/logging.js +107 -0
- package/dist/compiler/manifest.d.ts +16 -4
- package/dist/compiler/manifest.js +7 -3
- package/dist/reference/base-abbreviations.mjs +8 -2
- package/dist/reference/consistency.d.ts +8 -10
- package/dist/reference/consistency.js +3 -47
- package/dist/reference/delimiter-size.d.ts +39 -0
- package/dist/reference/delimiter-size.js +177 -0
- package/dist/reference/diagrams-validate.d.ts +1 -1
- package/dist/reference/equations-validate.d.ts +2 -2
- package/dist/reference/equations-validate.js +1 -1
- package/dist/reference/figures-validate.d.ts +1 -1
- package/dist/reference/gate-heading-length.d.ts +12 -0
- package/dist/reference/gate-heading-length.js +79 -0
- package/dist/reference/gate-math.d.ts +8 -2
- package/dist/reference/gate-math.js +30 -7
- package/dist/reference/keyed-float-validate.d.ts +2 -2
- package/dist/reference/keyed-float-validate.js +1 -1
- package/dist/reference/math-glyphs.d.mts +12 -0
- package/dist/reference/math-glyphs.mjs +183 -42
- package/dist/reference/references.js +2 -1
- package/dist/reference/registry.js +1 -1
- package/dist/reference/rehype-base-links.d.mts +23 -0
- package/dist/reference/rehype-base-links.mjs +40 -0
- package/dist/reference/remark-abbreviations.mjs +10 -12
- package/dist/reference/remark-citation.d.mts +5 -1
- package/dist/reference/remark-citation.mjs +0 -0
- package/dist/reference/render-lab-math.d.ts +18 -1
- package/dist/reference/render-lab-math.js +10 -3
- package/dist/reference/tables-validate.d.ts +1 -1
- package/dist/reference/types.d.ts +1 -1
- package/docs/VERSIONING.md +24 -4
- package/docs/authoring/README.md +14 -2
- package/docs/authoring/agents.md +7 -3
- package/docs/authoring/components.md +4 -1
- package/docs/authoring/migrating.md +477 -8
- package/docs/authoring/notation.md +194 -7
- package/docs/authoring/prose.md +64 -0
- package/docs/authoring/structure-rules.md +69 -0
- package/docs/authoring/visualizations.md +2 -2
- package/package.json +1 -1
- package/src/compiler/astro.ts +89 -0
- package/src/compiler/cli.ts +144 -12
- package/src/compiler/course-config.ts +40 -0
- package/src/compiler/exports/standalone-html.ts +15 -0
- package/src/compiler/logging.ts +248 -0
- package/src/compiler/manifest.ts +20 -3
- package/src/components/diagram/Diagram.astro +0 -55
- package/src/components/memo/Memo.astro +2 -5
- package/src/components/memo/ShortNote.astro +2 -5
- package/src/components/notation/NotationFormula.astro +199 -10
- package/src/components/notation/NotationGlossary.astro +89 -58
- package/src/components/notation/NotationLayer.astro +238 -156
- package/src/components/scroll-animation.ts +160 -0
- package/src/components/starlight/AnchorScrollEnhancer.astro +102 -0
- package/src/components/starlight/HeadingAnchorEnhancer.astro +2 -4
- package/src/components/starlight/KeyedFloatEnhancer.astro +17 -16
- package/src/components/starlight/LessonFooter.astro +5 -1
- package/src/content-config.ts +16 -1
- package/src/reference/base-abbreviations.mjs +8 -2
- package/src/reference/consistency.ts +10 -66
- package/src/reference/delimiter-size.ts +301 -0
- package/src/reference/diagrams-validate.ts +1 -1
- package/src/reference/equations-validate.ts +3 -3
- package/src/reference/figures-validate.ts +1 -1
- package/src/reference/gate-heading-length.ts +131 -0
- package/src/reference/gate-math.ts +48 -8
- package/src/reference/keyed-float-validate.ts +3 -3
- package/src/reference/math-glyphs.mjs +183 -42
- package/src/reference/references.ts +2 -1
- package/src/reference/registry.ts +1 -1
- package/src/reference/rehype-base-links.mjs +40 -0
- package/src/reference/remark-abbreviations.mjs +10 -12
- package/src/reference/remark-citation.mjs +0 -0
- package/src/reference/render-lab-math.ts +24 -1
- package/src/reference/tables-validate.ts +1 -1
- package/src/reference/types.ts +1 -1
- package/src/styles/global.css +120 -15
package/docs/VERSIONING.md
CHANGED
|
@@ -38,8 +38,8 @@ passed now fails.
|
|
|
38
38
|
`CHANGELOG.md`).
|
|
39
39
|
|
|
40
40
|
**PATCH** — a bug fix, a docs change, an internal refactor with no surface
|
|
41
|
-
change, or a new **Tier-3 warning** (
|
|
42
|
-
one does not break a consumer).
|
|
41
|
+
change, or a new **Tier-3 warning/info diagnostic** (neither fails a build, so
|
|
42
|
+
surfacing one does not break a consumer).
|
|
43
43
|
|
|
44
44
|
### Pre-1.0
|
|
45
45
|
|
|
@@ -66,6 +66,21 @@ whether the bump is MAJOR, MINOR, or PATCH. The section must do one of two thing
|
|
|
66
66
|
- state explicitly that no course changes are required, followed by the normal
|
|
67
67
|
verification commands.
|
|
68
68
|
|
|
69
|
+
**Every build-enforced/authoring rule and every manifest-schema bump the
|
|
70
|
+
release's `CHANGELOG.md` entry names gets its own migration coverage.** 0.5.0
|
|
71
|
+
shipped with only rule N14 and the schema-version bump covered — N9, N10, N13,
|
|
72
|
+
and N15 were all in the changelog and all missing from `migrating.md`, and the
|
|
73
|
+
schema-chain statement itself skipped the v8 and v9 bumps. A migration section
|
|
74
|
+
that has *some* ordered steps is not the same as a *complete* one: derive it by
|
|
75
|
+
walking the release's complete changelog entry line by line, not just its
|
|
76
|
+
headline items. `pnpm check:release-migration` now cross-checks this
|
|
77
|
+
mechanically (see below) — it greps the changelog entry for `rule N9`-style
|
|
78
|
+
mentions and `is now v9`-style schema bumps and fails if the matching version's
|
|
79
|
+
`migrating.md` section doesn't name each one the same way (`rule N9`, `v9`).
|
|
80
|
+
Keep both files' phrasing in that shape; a rule discussed without the word
|
|
81
|
+
"rule" immediately before its ID, or a schema bump not written `is now vN`,
|
|
82
|
+
won't be picked up by either side of the check.
|
|
83
|
+
|
|
69
84
|
The changelog explains what changed and why; it is not a substitute for the
|
|
70
85
|
migration section. The migration section, changelog entry, version bump, and
|
|
71
86
|
package are one atomic release. An agent upgrading across several versions
|
|
@@ -77,12 +92,17 @@ applies every intervening section in order.
|
|
|
77
92
|
section of `CHANGELOG.md`.
|
|
78
93
|
2. Add the section for `x.y.z` to `docs/authoring/migrating.md`, derived from the
|
|
79
94
|
complete release diff. Write explicit no-action instructions when nothing in
|
|
80
|
-
a downstream course needs to change.
|
|
95
|
+
a downstream course needs to change. Walk the `CHANGELOG.md` entry you're
|
|
96
|
+
about to finalize bullet by bullet and give every `rule N#` it names, and
|
|
97
|
+
every `is now vN` schema bump, its own coverage — not only the entry's
|
|
98
|
+
headline item.
|
|
81
99
|
3. `CHANGELOG.md`: rename `## [Unreleased]` to `## [x.y.z] - YYYY-MM-DD`, add a
|
|
82
100
|
fresh empty `## [Unreleased]`, and fix up the compare links at the bottom.
|
|
83
101
|
4. Bump `package.json` `version` (`npm version x.y.z --no-git-tag-version`).
|
|
84
102
|
5. Run `pnpm check:release-migration`. It fails when the new version has no
|
|
85
|
-
migration section
|
|
103
|
+
migration section, the shipped-file configuration excludes the guide, or a
|
|
104
|
+
`rule N#` / `is now vN` mention in the `CHANGELOG.md` entry has no match in
|
|
105
|
+
the `migrating.md` section.
|
|
86
106
|
6. Run `pnpm build && pnpm test`, then inspect `pnpm pack --dry-run` and confirm
|
|
87
107
|
that `docs/authoring/migrating.md` and `docs/authoring/agents.md` are listed.
|
|
88
108
|
7. Commit, then `git tag vx.y.z`.
|
package/docs/authoring/README.md
CHANGED
|
@@ -22,6 +22,12 @@ Two kinds of rule live here:
|
|
|
22
22
|
- **Review-only** — nothing checks it automatically; a reviewer does. Breaking
|
|
23
23
|
one is a review comment, not a broken build.
|
|
24
24
|
|
|
25
|
+
Automated diagnostics use three severities. An **error** means the content is
|
|
26
|
+
incorrect, ambiguous, unexplainable, or cannot render reliably and therefore
|
|
27
|
+
blocks validation. A **warning** is non-blocking but marks a rule, readability,
|
|
28
|
+
or maintenance problem that should be repaired. **Info** is optional advice;
|
|
29
|
+
leaving it in place can be intentional and creates no repair debt.
|
|
30
|
+
|
|
25
31
|
Every rule is written to be falsifiable: you can look at a lesson and say
|
|
26
32
|
whether it complies.
|
|
27
33
|
|
|
@@ -43,7 +49,7 @@ speak in: what a part, a chapter, a section, and a subsection are, and which of
|
|
|
43
49
|
them an equation number counts.
|
|
44
50
|
|
|
45
51
|
Each rule has a stable ID — a letter for its area (`N` notation,
|
|
46
|
-
`V` visualizations, `C` versioning) plus a number — and this shape:
|
|
52
|
+
`V` visualizations, `C` versioning, `S` structure, `P` prose) plus a number — and this shape:
|
|
47
53
|
|
|
48
54
|
> **N1 — One-line imperative.**
|
|
49
55
|
> _Rationale._ Why the rule exists; the failure it prevents.
|
|
@@ -74,6 +80,8 @@ file table.
|
|
|
74
80
|
| [notation.md](notation.md) | `N` | how math symbols are written and bound |
|
|
75
81
|
| [visualizations.md](visualizations.md) | `V` | diagrams, charts, interactive figures, randomness |
|
|
76
82
|
| [versioning.md](versioning.md) | `C` | the knowledge version and `content/CHANGELOG.md` |
|
|
83
|
+
| [structure-rules.md](structure-rules.md) | `S` | heading and figure/diagram/memo/short-note title length |
|
|
84
|
+
| [prose.md](prose.md) | `P` | how a lesson's sentences are worded |
|
|
77
85
|
| [components.md](components.md) | — | _catalog_: inline/block features available in a lesson body — tooltips, tables, figures, diagrams, memos, abbreviations, citations |
|
|
78
86
|
| [agents.md](agents.md) | — | _guide_: working on a course repo (with an AI agent) |
|
|
79
87
|
| [migrating.md](migrating.md) | — | _guide_: per-version steps when bumping the `explico` dep |
|
|
@@ -96,7 +104,9 @@ file table.
|
|
|
96
104
|
| [N12](notation.md#n12) | Math syntax never carries the sentence's own trailing punctuation | Review-only |
|
|
97
105
|
| [N13](notation.md#n13) | A nonlinear function always takes a parenthesized argument | Build-enforced (`resolveMathGlyphs`) |
|
|
98
106
|
| [N14](notation.md#n14) | An abbreviation-shaped word in prose is universal, or explained | Build-enforced (`gate-abbreviations.ts`) |
|
|
99
|
-
| [N15](notation.md#n15) | A nested `(`, `[`, `{`, or `\|` must use
|
|
107
|
+
| [N15](notation.md#n15) | A nested `(`, `[`, `{`, or `\|` must use scalable sizing | Build-enforced (`resolveMathGlyphs`) |
|
|
108
|
+
| [N16](notation.md#n16) | AI-generated stylistic grouping alternates delimiter types | Review-only |
|
|
109
|
+
| [N17](notation.md#n17) | Nested scalable delimiters grow strictly from inside to outside | Tier-3 warning (`delimiter-size-hierarchy`) |
|
|
100
110
|
| [V1](visualizations.md#v1) | Graphs and flowcharts use the `Diagram` component | Review-only |
|
|
101
111
|
| [V2](visualizations.md#v2) | Static charts: SVG → D3 → Observable Plot, chosen per figure | Review-only |
|
|
102
112
|
| [V3](visualizations.md#v3) | Interactive figures: island + `renderLabMath` seam + text alt | Review-only |
|
|
@@ -106,3 +116,5 @@ file table.
|
|
|
106
116
|
| [C2](versioning.md#c2) | The knowledge version is semver over learning-facing content | Review-only |
|
|
107
117
|
| [C3](versioning.md#c3) | `about.version` equals the newest `content/CHANGELOG.md` heading | Build-enforced (Tier-3 `knowledge-version-mismatch`) |
|
|
108
118
|
| [C4](versioning.md#c4) | On release, move `[Unreleased]` and bump `about.version` together | Review-only |
|
|
119
|
+
| [S1](structure-rules.md#s1) | No heading, or figure/diagram/memo/short-note title, over 65 characters | Build-enforced (`gate-heading-length.ts`) for body/floats + review for `frontmatter.title` |
|
|
120
|
+
| [P1](prose.md#p1) | "or" never introduces a second name for the same thing | Review-only |
|
package/docs/authoring/agents.md
CHANGED
|
@@ -7,7 +7,9 @@ particular to your layout.
|
|
|
7
7
|
|
|
8
8
|
This is a guide, not a rule area. The enforceable rules are in
|
|
9
9
|
[`notation.md`](notation.md) (`N`), [`visualizations.md`](visualizations.md)
|
|
10
|
-
(`V`),
|
|
10
|
+
(`V`), [`versioning.md`](versioning.md) (`C`),
|
|
11
|
+
[`structure-rules.md`](structure-rules.md) (`S`), and [`prose.md`](prose.md)
|
|
12
|
+
(`P`). When the engine's behaviour
|
|
11
13
|
and a rule disagree, the engine wins — see [`README.md`](README.md).
|
|
12
14
|
|
|
13
15
|
## The loop
|
|
@@ -15,8 +17,10 @@ and a rule disagree, the engine wins — see [`README.md`](README.md).
|
|
|
15
17
|
- **Start from the CLI, not a file hunt.** `pnpm --filter <course> content
|
|
16
18
|
context <lesson>` prints a lesson plus exactly its notation, references, and
|
|
17
19
|
assumptions. `pnpm content status` is the draft-debt overview. `pnpm content
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
diagnostics info` lists everything; `warning` and `error` raise the minimum
|
|
21
|
+
severity. `pnpm content warnings` lists warnings only.
|
|
22
|
+
`pnpm content check <lesson> | --changed` is schema + refs + MDX→KaTeX, exits
|
|
23
|
+
non-zero on an error. Read those before opening files.
|
|
20
24
|
- **Validate, twice.** `pnpm --filter <course> validate:content` regenerates
|
|
21
25
|
`build/resolution/*` and then fails on the same run that changed them. Run it
|
|
22
26
|
again; the second run is clean. Commit the regenerated `build/` and
|
|
@@ -92,7 +92,10 @@ Two naming traps worth flagging for an AI author:
|
|
|
92
92
|
- **`<Figure title="…">` is a visible short label in the collapsible title
|
|
93
93
|
bar, not the HTML `title` attribute's hover tooltip.** It always renders on
|
|
94
94
|
the page; it is a different feature from the [native tooltip](#inline-zero-registration)
|
|
95
|
-
above even though it reuses the same prop name.
|
|
95
|
+
above even though it reuses the same prop name. Keep it short — the whole
|
|
96
|
+
caption sentence does not belong here; see [S1](structure-rules.md#s1). An
|
|
97
|
+
omitted `title` silently falls back to `caption` in full, which is exactly
|
|
98
|
+
the failure S1 exists to catch.
|
|
96
99
|
- **A raw Markdown pipe table or a raw `<table>`, or a `<Diagram>` with no
|
|
97
100
|
`id`,** renders fine but never enters keyed-float validation — no number,
|
|
98
101
|
no `[[…]]` target. Wrap it (`<Table>`/`<Figure>`) or give the diagram an
|
|
@@ -33,9 +33,417 @@ required config block throws with the section of this file to read.
|
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
36
|
+
## 0.6.0 → 0.7.0
|
|
37
|
+
|
|
38
|
+
### 1. Manifest schema is now v15: diagnostic severity has three levels
|
|
39
|
+
|
|
40
|
+
`MANIFEST_SCHEMA_VERSION` is 15 (v14 → v15). Public diagnostic severity unions
|
|
41
|
+
now include `info`, so a client that treated "not an error" as "a warning"
|
|
42
|
+
needs three edits:
|
|
43
|
+
|
|
44
|
+
1. A client asserting `MANIFEST_SCHEMA_VERSION` by exact equality expects 15.
|
|
45
|
+
2. Widen any hand-written `'error' | 'warning'` type over manifest diagnostics
|
|
46
|
+
to `'error' | 'warning' | 'info'`. `ConsistencyDiagnostic.severity` is now
|
|
47
|
+
`'warning' | 'info'`.
|
|
48
|
+
3. In `scripts/compile-manifest.ts` (and any other consumer), filter on
|
|
49
|
+
`severity === 'warning'` before printing or counting warnings. A script that
|
|
50
|
+
counts all of `manifest.diagnostics.consistency` as "Tier-3 findings" now
|
|
51
|
+
over-reports:
|
|
52
|
+
|
|
53
|
+
```diff
|
|
54
|
+
-const consistencyByCode = consistencyCounts(consistency);
|
|
55
|
+
-const consistencyTotal = consistency.length;
|
|
56
|
+
+const consistencyWarnings = consistency.filter(
|
|
57
|
+
+ (diagnostic) => diagnostic.severity === 'warning',
|
|
58
|
+
+);
|
|
59
|
+
+const consistencyByCode = consistencyCounts(consistencyWarnings);
|
|
60
|
+
+const consistencyTotal = consistencyWarnings.length;
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
These codes moved from `warning` to `info`: `eq-key-unused`, every keyed-float
|
|
64
|
+
`*-key-unused`, `unused-definition`, `weak-local`, `gloss-wants-promoting`, and
|
|
65
|
+
`card-wants-demoting`. Their code strings and container fields did not change,
|
|
66
|
+
the `lint-ignore.yml` lines that already worked for `weak-local`,
|
|
67
|
+
`gloss-wants-promoting`, and `card-wants-demoting` still match, and nothing
|
|
68
|
+
blocks the build. They no longer appear in `pnpm content warnings`; read them
|
|
69
|
+
with `pnpm content diagnostics info`.
|
|
70
|
+
|
|
71
|
+
Run `pnpm validate:content` twice. The committed `build/resolution/*` files
|
|
72
|
+
(including `consistency-report.json`) change because those findings now carry
|
|
73
|
+
`info` severity and `numerals-tagged` findings are gone (item 2); commit them.
|
|
74
|
+
|
|
75
|
+
### 2. Retired diagnostic: `numerals-tagged`
|
|
76
|
+
|
|
77
|
+
`ConsistencyCode` no longer contains `numerals-tagged`, and the engine never
|
|
78
|
+
emits it. Delete every `numerals-tagged` line from `lint-ignore.yml` (a stale
|
|
79
|
+
line is inert but misleads the next reader) and every course script, test, or
|
|
80
|
+
type narrowing that names the code — `tsc`/`astro check` flags the latter as a
|
|
81
|
+
comparison against a non-member of the union.
|
|
82
|
+
|
|
83
|
+
### 3. `explicoContentRefresh()` fails the build on a missing remark plugin (rule N14 and its siblings)
|
|
84
|
+
|
|
85
|
+
This is the enforcement half of rule N14's Astro wiring (see item 4 of the
|
|
86
|
+
0.4.x → 0.5.0 section). Its `astro:config:setup` hook now compares the manifest
|
|
87
|
+
against the configured remark plugins and throws, naming each gap, when a
|
|
88
|
+
non-empty table has no matching plugin registered:
|
|
89
|
+
|
|
90
|
+
| Manifest table is non-empty | Plugin that must be registered |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| `manifest.abbreviations` | `[remarkAbbreviations, { abbreviations: manifest.abbreviations }]` from `explico/reference/remark-abbreviations.mjs` |
|
|
93
|
+
| `manifest.sources` | `[remarkCitation, { sources: manifest.sources }]` from `explico/reference/remark-citation.mjs` |
|
|
94
|
+
| `manifest.notation.raw` | `[remarkNotation, createRemarkNotationOptions(manifest)]` from `explico/reference/remark-notation.mjs` |
|
|
95
|
+
|
|
96
|
+
Check `astro.config.mjs` against that table. The check reads both wiring
|
|
97
|
+
surfaces Astro offers — the flat `markdown.remarkPlugins` array and a
|
|
98
|
+
`markdown.processor` such as `unified({ remarkPlugins: [...] })` — and accepts
|
|
99
|
+
either the bare plugin or a `[plugin, options]` tuple. It compares by identity
|
|
100
|
+
with the module the `explico/reference/*.mjs` specifier resolves to, so register
|
|
101
|
+
the imported function itself rather than a local wrapper around it. A course
|
|
102
|
+
that was already fully wired needs no edit; one that skipped a plugin was
|
|
103
|
+
silently rendering triggers as plain text and now fails `astro build` /
|
|
104
|
+
`astro dev` until it adds the missing registration.
|
|
105
|
+
|
|
106
|
+
### 4. Removed markup: popup "Copy LaTeX", glossary `#` copy-link, formula scroll region
|
|
107
|
+
|
|
108
|
+
None of these has a replacement selector; update course-owned CSS and
|
|
109
|
+
end-to-end tests that target them:
|
|
110
|
+
|
|
111
|
+
- `.notation-popup-copy` / `[data-popup-copy]` — the button in a notation
|
|
112
|
+
popup. Copying is now a click on the equation itself (item 8).
|
|
113
|
+
- `[data-glossary-anchor]` and its "Link copied" flash — a glossary entry's `#`
|
|
114
|
+
button that wrote its URL to the clipboard. The entry title is now a link to
|
|
115
|
+
`#notation-<key>` (`.glossary-term-link`), and a hover-revealed link-icon
|
|
116
|
+
anchor (`.glossary-anchor`) simply navigates; nothing is copied.
|
|
117
|
+
- `NotationFormula`'s `tabindex="0"` scroll region moved from
|
|
118
|
+
`.notation-formula-math` to a nested `.notation-formula-scroll`. A test that
|
|
119
|
+
focuses or scrolls `.notation-formula-math` must target the inner element.
|
|
120
|
+
|
|
121
|
+
No source or config change is needed beyond selectors.
|
|
122
|
+
|
|
123
|
+
### 5. Rule N14: every occurrence of a catalogued abbreviation is now wrapped
|
|
124
|
+
|
|
125
|
+
Two changes ride under rule N14, neither of which needs a config edit:
|
|
126
|
+
|
|
127
|
+
- **Rendered output changed.** `remarkAbbreviations` used to wrap only the first
|
|
128
|
+
occurrence of each catalogued abbreviation per page; it now wraps every
|
|
129
|
+
occurrence (`a.abbreviation-term[data-abbr-key]`). A course-owned e2e test or
|
|
130
|
+
snapshot that expected exactly one such link per term per page, or CSS that
|
|
131
|
+
assumed a page's later occurrences were plain text, must be updated.
|
|
132
|
+
`AbbreviationLayer.astro` already resolved markers independently by
|
|
133
|
+
`data-abbr-key`, so no island change is needed.
|
|
134
|
+
- **The shipped baseline grew** (`base-abbreviations.mjs`): `AM`, `PM`, `A.M.`,
|
|
135
|
+
`P.M.`, and `e.t.c.` join `a.m.`, `p.m.`, `e.g.`, `i.e.`, and `etc.`. This only
|
|
136
|
+
loosens the gate. A now-redundant `abbreviations.allow` line or
|
|
137
|
+
`content/abbreviations/*.md` entry for one of them is harmless and can stay; a
|
|
138
|
+
course that wants one explained anyway lists it in `abbreviations.deny`.
|
|
139
|
+
|
|
140
|
+
### 6. Rule N16 and rule N17: delimiter conventions and sizes
|
|
141
|
+
|
|
142
|
+
Rule N16 (alternate `()`, `[]`, `\{\}` for purely stylistic nested grouping,
|
|
143
|
+
never for conventional delimiters such as `f(x)`, `\mathbb{E}[X]`, or
|
|
144
|
+
intervals) is **review-only**: nothing checks it and nothing needs to change to
|
|
145
|
+
keep building. Rule N17 (every outer scalable pair in a nest grows strictly
|
|
146
|
+
larger than the pairs inside it: `\left…\right` → `\Bigl…\Bigr` → `\biggl…\biggr`
|
|
147
|
+
→ `\Biggl…\Biggr`) is a **Tier-3 warning**, `delimiter-size-hierarchy`, reported
|
|
148
|
+
at the outer pair's line and column by the normal math gate for lesson math,
|
|
149
|
+
notation formulas, and assessment math. It never fails a build, so no course
|
|
150
|
+
needs to change to keep building. To clear the warnings, run
|
|
151
|
+
`pnpm content diagnostics warning`, and enlarge each named outer pair to the
|
|
152
|
+
next manual size without changing its delimiter shape. Rule N15's build-enforced
|
|
153
|
+
behavior is unchanged — its documentation now also accepts an N17 manual pair as
|
|
154
|
+
"sized". See [`notation.md#n16`](notation.md#n16) and
|
|
155
|
+
[`notation.md#n17`](notation.md#n17).
|
|
156
|
+
|
|
157
|
+
### 7. Rule P1: "or" never introduces a second name for the same thing
|
|
158
|
+
|
|
159
|
+
Rule P1 opens the new `P` (prose) rule area and is **review-only**: nothing is
|
|
160
|
+
checked at build time and no course change is required. When editing lessons,
|
|
161
|
+
replace "the residual or error term" with "the residual (i.e., the error
|
|
162
|
+
term)"-style wording. See [`prose.md#p1`](prose.md#p1).
|
|
163
|
+
|
|
164
|
+
### 8. Optional: click-to-copy equations, glossary equation numbers, and live lab LaTeX
|
|
165
|
+
|
|
166
|
+
Nothing to do for a course that wires `Footer` to `LessonFooter.astro`: a
|
|
167
|
+
click on any `[data-notation-formula]` box now copies its `data-latex`, and every
|
|
168
|
+
glossary formula gets a `G.<n>` number and copy button, automatically.
|
|
169
|
+
|
|
170
|
+
Only a course with an interactive lab island that renders math through
|
|
171
|
+
`renderLabMath()` can opt that equation into the gesture, and keep the copied
|
|
172
|
+
LaTeX in step with the sliders, with `plainLatexTemplate` and the new
|
|
173
|
+
`slotPlaceholder` export:
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
import {
|
|
177
|
+
slotPlaceholder,
|
|
178
|
+
type RenderedLabMath,
|
|
179
|
+
} from 'explico/reference/render-lab-math';
|
|
180
|
+
|
|
181
|
+
// On the math root element:
|
|
182
|
+
<div
|
|
183
|
+
className="lab-math"
|
|
184
|
+
data-notation-formula
|
|
185
|
+
data-latex={rendered.plainLatexTemplate}
|
|
186
|
+
/* … */
|
|
187
|
+
/>
|
|
188
|
+
|
|
189
|
+
// Where the island writes each slot's live value (`values`: slot name → text):
|
|
190
|
+
let latex = rendered.plainLatexTemplate;
|
|
191
|
+
for (const [name, value] of Object.entries(values)) {
|
|
192
|
+
latex = latex.split(slotPlaceholder(name)).join(value);
|
|
193
|
+
}
|
|
194
|
+
root.dataset.latex = latex;
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Rebuild `latex` from the template on every update, not from the previous result.
|
|
198
|
+
A lab that does not set these attributes is unchanged. `RenderedLabMath` gained
|
|
199
|
+
the required `plainLatexTemplate` field; a course that constructs one by hand
|
|
200
|
+
(a test double, for instance) must add it.
|
|
201
|
+
|
|
202
|
+
### 9. Only if you override `Footer` yourself: mount `AnchorScrollEnhancer`
|
|
203
|
+
|
|
204
|
+
The new smooth-scroll behavior for in-page anchor links ships in
|
|
205
|
+
`AnchorScrollEnhancer.astro`, which `LessonFooter.astro` mounts. A course whose
|
|
206
|
+
Starlight `components.Footer` is `explico/components/starlight/LessonFooter.astro`
|
|
207
|
+
gets it with no change. A course that swapped in its own footer component must
|
|
208
|
+
render it (`import AnchorScrollEnhancer from
|
|
209
|
+
'explico/components/starlight/AnchorScrollEnhancer.astro'`, then
|
|
210
|
+
`<AnchorScrollEnhancer />`) or its anchor links keep the browser's native jump.
|
|
211
|
+
|
|
212
|
+
### 10. Optional: wire `rehypeBaseLinks` for a course deployed under a subpath
|
|
213
|
+
|
|
214
|
+
Skip this for a course served from a domain root (`base` omitted or `'/'`); the
|
|
215
|
+
plugin is a no-op there. For a course under a subpath (a GitHub Pages *project*
|
|
216
|
+
site, `base: '/my-course'`), Starlight prefixes only its own navigation, so
|
|
217
|
+
every root-relative link the Markdown pipeline produces — prose links,
|
|
218
|
+
equation cross-references, citation links — 404s without this:
|
|
219
|
+
|
|
220
|
+
```diff
|
|
221
|
+
+ import rehypeBaseLinks from 'explico/reference/rehype-base-links.mjs';
|
|
222
|
+
…
|
|
223
|
+
rehypePlugins: [
|
|
224
|
+
[rehypeKatex, createNotationKatexOptions()],
|
|
225
|
+
rehypeFailKatexErrors,
|
|
226
|
+
+ [rehypeBaseLinks, base],
|
|
227
|
+
]
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`base` is the same value passed to `defineConfig({ base })`. **Undo any manual
|
|
231
|
+
workaround first:** the plugin prefixes every `href` beginning with a single
|
|
232
|
+
`/`, so a lesson link already hand-written as `/my-course/other/` would become
|
|
233
|
+
`/my-course/my-course/other/`. Write lesson links without the base. A lesson's
|
|
234
|
+
Starlight frontmatter (`hero.actions[].link`) never passes through this
|
|
235
|
+
pipeline; write those as paths relative to the current page.
|
|
236
|
+
|
|
237
|
+
### 11. Optional: run logs for `pnpm validate:content`
|
|
238
|
+
|
|
239
|
+
Route the course's `scripts/compile-manifest.ts` through `createRunLog()` to
|
|
240
|
+
record every diagnostic to `build/logs/<timestamp>/{error,warning,info}.log`
|
|
241
|
+
(Python `logging` format, `build/logs/latest` symlinks the newest run):
|
|
242
|
+
|
|
243
|
+
```diff
|
|
244
|
+
+ import { createRunLog } from 'explico/compiler/logging';
|
|
245
|
+
…
|
|
246
|
+
+ const log = createRunLog();
|
|
247
|
+
const manifest = await compileManifest(courseConfig);
|
|
248
|
+
…
|
|
249
|
+
- console.warn(`[${warning.code}] ${warning.message}`);
|
|
250
|
+
+ console.warn(log.warning('notation', `[${warning.code}] ${warning.message}`));
|
|
251
|
+
…
|
|
252
|
+
+ const summary = log.close();
|
|
253
|
+
+ console.log(
|
|
254
|
+
+ `Run log: ${summary.relativeDirectory} ` +
|
|
255
|
+
+ `(${summary.counts.ERROR} error(s), ${summary.counts.WARNING} warning(s), ${summary.counts.INFO} info).`,
|
|
256
|
+
+ );
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Each `log.error/warning/info(source, message)` call returns its message, so
|
|
260
|
+
printing and recording share one expression; `log.infoDiagnostics(manifest.diagnostics)`
|
|
261
|
+
records the severity-`info` findings the console never showed. Call
|
|
262
|
+
`log.close()` before any `throw` so a failing run's log is complete
|
|
263
|
+
(`playground/scripts/compile-manifest.ts` is a full worked example). Add
|
|
264
|
+
`build/logs/` to the course's `.gitignore` — a course commits
|
|
265
|
+
`build/resolution/*`, and nothing prunes old runs.
|
|
266
|
+
|
|
267
|
+
### 12. Optional: the `content diagnostics` / `content warnings` commands and VS Code tasks
|
|
268
|
+
|
|
269
|
+
`content diagnostics [info|warning|error] [--json]` and `content warnings
|
|
270
|
+
[--json]` are new, and `content status` now reports an `info` count
|
|
271
|
+
(`report.diagnostics.infos`). The engine implements them in
|
|
272
|
+
`explico/compiler/cli`, but a course's own `scripts/content.ts` dispatches
|
|
273
|
+
commands, so it must route them:
|
|
274
|
+
|
|
275
|
+
```diff
|
|
276
|
+
import {
|
|
277
|
+
ContentCliError,
|
|
278
|
+
contentCheck,
|
|
279
|
+
contentContext,
|
|
280
|
+
+ contentDiagnostics,
|
|
281
|
+
contentStatus,
|
|
282
|
+
+ contentWarnings,
|
|
283
|
+
…
|
|
284
|
+
} from 'explico/compiler/cli';
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Add a `case 'warnings'` (`contentWarnings(manifest)`) and a `case 'diagnostics'`
|
|
288
|
+
(validate the one positional as `info`/`warning`/`error`, default `info`, then
|
|
289
|
+
`contentDiagnostics(manifest, severity)`) beside `case 'status'`, printing
|
|
290
|
+
`file:line:column: severity code: message` lines — copy
|
|
291
|
+
`playground/scripts/content.ts`. To surface findings in VS Code's Problems
|
|
292
|
+
panel, copy the three **Explico: Show content diagnostics** tasks from the
|
|
293
|
+
engine repository's `.vscode/tasks.json`, replacing the `--filter` package name
|
|
294
|
+
and the problem matcher's `fileLocation` root with the course's own.
|
|
295
|
+
|
|
296
|
+
### 13. No action: other changes in this release
|
|
297
|
+
|
|
298
|
+
- Every `<a>` back-link (`↩`) in a page's References section now also carries a
|
|
299
|
+
`title` tooltip; `remark-citation.mjs` does this itself.
|
|
300
|
+
- Standalone HTML export now inlines a `<link>` only when its `rel` is
|
|
301
|
+
`stylesheet` or an icon type, and leaves other `<link>`s (`canonical`,
|
|
302
|
+
`alternate`, `preload`, …) as authored.
|
|
303
|
+
|
|
304
|
+
### Verification
|
|
305
|
+
|
|
306
|
+
`pnpm validate:content` (run it **twice** — the first run regenerates
|
|
307
|
+
`build/resolution/*`, item 1), then `pnpm content check --changed`, then
|
|
308
|
+
`astro check`, then `astro build`. `astro build` is the step that reports item 3.
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## 0.5.0 → 0.6.0
|
|
313
|
+
|
|
314
|
+
### 1. Rule S1: no heading or float title runs past 65 characters
|
|
315
|
+
|
|
316
|
+
Every Markdown heading (`##` through `######`), a lesson's own
|
|
317
|
+
`frontmatter.title`, and the `title`/`label` prop on `Figure`, `Diagram`,
|
|
318
|
+
`Memo`, and `ShortNote` is now capped at 65 characters; `Table` is exempt (it
|
|
319
|
+
has only a `caption`). No wiring is required — the check runs as part of
|
|
320
|
+
`pnpm validate:content` / `astro build` the same as N9/N13/N15. Audit for
|
|
321
|
+
existing violations and shorten them, moving the rest of the sentence into
|
|
322
|
+
the paragraph after a heading or into a float's `caption`. See
|
|
323
|
+
[`docs/authoring/structure-rules.md#s1`](structure-rules.md#s1).
|
|
324
|
+
|
|
325
|
+
### 2. Removed markup: `.notation-pin`, `[data-notation-control]`, `.notation-layer-heading`
|
|
326
|
+
|
|
327
|
+
The "Page notation" panel's "Pin explanation" button (`.notation-pin`,
|
|
328
|
+
`[data-notation-control]`) and its separate `<h2>` (`.notation-layer-heading`)
|
|
329
|
+
are both gone from the rendered DOM. Pinning a card now works the same way an
|
|
330
|
+
inline prose symbol always has — click its glyph — and the panel's
|
|
331
|
+
`<summary>` is its only heading. Update any course-owned CSS or end-to-end
|
|
332
|
+
test that targets these selectors; no other action is required.
|
|
333
|
+
|
|
334
|
+
### 3. Removed prop: `<Diagram description>`
|
|
335
|
+
|
|
336
|
+
`Diagram`'s `description` prop and its collapsed "Diagram description"
|
|
337
|
+
fallback block (`.diagram-fallback`) no longer exist. `astro check` fails on
|
|
338
|
+
an excess prop, so remove every `description="…"` passed to `<Diagram>`; fold
|
|
339
|
+
that text into the diagram's `label` (caption) instead.
|
|
340
|
+
|
|
341
|
+
### 4. Optional: collapsible "Page notation" panel and References section
|
|
342
|
+
|
|
343
|
+
`NotationLayer` gains `defaultOpen`/`rememberState` props (mirroring
|
|
344
|
+
`Figure`'s own), and `remark-citation.mjs`'s generated References heading now
|
|
345
|
+
accepts a `defaultOpen` plugin option — both ride the same persisted,
|
|
346
|
+
deep-linkable disclosure machinery `Figure`/`CollapsibleSections` already use,
|
|
347
|
+
in place of the previous always-native-default `<details>`. No action is
|
|
348
|
+
required to keep building: both default to closed, matching prior behavior,
|
|
349
|
+
and the References option only takes effect on a course whose
|
|
350
|
+
`astro.config.mjs` already wires `rehypeHeadingAnchors` into its rehype
|
|
351
|
+
pipeline. To opt into a different default, set `CourseConfig.disclosureDefaults`:
|
|
352
|
+
|
|
353
|
+
```ts
|
|
354
|
+
disclosureDefaults: {
|
|
355
|
+
notation: true, // "Page notation" panel starts open for a reader with nothing saved yet
|
|
356
|
+
references: true, // generated References section starts open
|
|
357
|
+
},
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### 5. Manifest schema is now v14 (additive: v13 → v14)
|
|
361
|
+
|
|
362
|
+
`CourseConfig.disclosureDefaults` is new and additive — nothing existing
|
|
363
|
+
changed shape — but a client asserting on `MANIFEST_SCHEMA_VERSION` by exact
|
|
364
|
+
equality needs the bump.
|
|
365
|
+
|
|
366
|
+
### 6. Re-run `pnpm validate:content` — the notation auto-annotator's silent-failure bugs are fixed
|
|
367
|
+
|
|
368
|
+
Several shapes that previously either dropped a symbol's tooltip silently (no
|
|
369
|
+
build error) or produced malformed output are now fixed at the resolver
|
|
370
|
+
(`resolveMathGlyphs`), not just documented as traps to avoid: a bare
|
|
371
|
+
`\mathrm{…}`-only symbol (`\mathrm{SSR}`, `\mathrm{SST}`) can now auto-resolve
|
|
372
|
+
at every later bare occurrence, a bare symbol immediately next to an
|
|
373
|
+
`\explain{…}{…}` call no longer has its span corrupted, and a partial
|
|
374
|
+
`\explain{key}{…}` wrap no longer produces unparseable doubled output. No
|
|
375
|
+
course-side wiring changes, but re-running `pnpm validate:content` may surface
|
|
376
|
+
two new classes of error that previously passed silently:
|
|
377
|
+
|
|
378
|
+
- **"Unresolved notation"** for a symbol that was relying on one of the fixed
|
|
379
|
+
bugs to appear resolved when it was not (rare — the bugs mostly hid symbols
|
|
380
|
+
entirely rather than falsely resolving them) or for the uncovered remainder
|
|
381
|
+
of a partial `\explain{key}{…}` wrap. Fix by explaining the symbol, or by
|
|
382
|
+
wrapping the key's *entire* declared `latex`, not just its base glyph.
|
|
383
|
+
- **"Page glyphs … have structurally identical LaTeX"** for two different
|
|
384
|
+
notation keys whose declared `latex` is the same `\operatorname{…}` or
|
|
385
|
+
`\mathrm{…}` form (e.g. two keys both `\operatorname{Var}`) — this check
|
|
386
|
+
previously silently skipped every such glyph and could not catch this. Give
|
|
387
|
+
the colliding keys distinct canonical forms, or reach for
|
|
388
|
+
`\explain{key}{…}` at every occurrence of whichever one keeps the shared
|
|
389
|
+
form.
|
|
390
|
+
|
|
36
391
|
## 0.4.x → 0.5.0
|
|
37
392
|
|
|
38
|
-
### 1. Rule
|
|
393
|
+
### 1. Rule N9: wrap every plain-text quantity, unit, and operator in `$…$`
|
|
394
|
+
|
|
395
|
+
Every physical quantity, unit abbreviation, or math operator ever typed as
|
|
396
|
+
plain text — in lesson prose, a table cell, or (new in 0.5.0) an assessment
|
|
397
|
+
item's `prompt` / `explanation` string — must now be inside `$…$`. `45 m/s`,
|
|
398
|
+
`t (s)`, `vx`, `\|v\|`, `KE/m` are all the same mistake. This is build-enforced
|
|
399
|
+
with **no `lint-ignore.yml` escape hatch**: `pnpm validate:content` / `astro
|
|
400
|
+
build` fails on every existing violation. Fix per
|
|
401
|
+
[`docs/authoring/notation.md#n9`](notation.md#n9) — wrap the symbol in `$…$`
|
|
402
|
+
and fold its unit into the *same* span as `\text{}` (`$t\ \text{(s)}$`, not two
|
|
403
|
+
adjacent spans).
|
|
404
|
+
|
|
405
|
+
Also wire the accessible-table-header plugin this rule ships with — the build
|
|
406
|
+
works without it, but a table header that is now 100% KaTeX (a bare `$t$`
|
|
407
|
+
column, since its unit moved inside `$…$` too) renders with no
|
|
408
|
+
screen-reader-visible name until this is wired:
|
|
409
|
+
|
|
410
|
+
```diff
|
|
411
|
+
+ import rehypeTableHeaderLabels from 'explico/reference/rehype-table-header-labels.mjs';
|
|
412
|
+
…
|
|
413
|
+
rehypePlugins: [
|
|
414
|
+
[rehypeKatex, createNotationKatexOptions()],
|
|
415
|
+
rehypeFailKatexErrors,
|
|
416
|
+
+ rehypeTableHeaderLabels,
|
|
417
|
+
]
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
It reads the `\explain{key}{…}` key(s) a header's LaTeX names and backfills an
|
|
421
|
+
`sr-only` label from that key's notation metadata — the one prerequisite is
|
|
422
|
+
that the header's symbol resolves to a key at all, so a `\mathrm{…}` compound
|
|
423
|
+
(`\mathrm{KE}/m`) needs each side explicitly `\explain{}`-wrapped.
|
|
424
|
+
|
|
425
|
+
### 2. Rule N13: a nonlinear function always takes a parenthesized argument
|
|
426
|
+
|
|
427
|
+
`\sin x`, `\log t`, `\exp\theta` — every trig/inverse-trig/hyperbolic function
|
|
428
|
+
plus `exp`/`log`/`ln`/`lg` — is now a hard error unless its argument is
|
|
429
|
+
parenthesized: `\sin(x)` or `\sin\left(x\right)` is required. Same enforcement
|
|
430
|
+
shape as N9: build-enforced, no `lint-ignore.yml` escape. It fires on lesson
|
|
431
|
+
body math, `notation.formula`, assessment `prompt`/`explanation`, `Diagram`
|
|
432
|
+
formulas, and interactive lab math alike, since all of them resolve through
|
|
433
|
+
the same glyph walker. Fix every occurrence; see
|
|
434
|
+
[`docs/authoring/notation.md#n13`](notation.md#n13).
|
|
435
|
+
|
|
436
|
+
### 3. Rule N15: size every level of a nested visible delimiter
|
|
437
|
+
|
|
438
|
+
Once a `(`, `[`, `\{`, or `|` sits inside another one of those four — same
|
|
439
|
+
type or mixed, e.g. `(a + [b])` — **every level of that nest** must switch to
|
|
440
|
+
`\left`/`\right` sizing: `\sin(2(90°-\theta))` is now a hard error,
|
|
441
|
+
`\sin\left(2\left(90°-\theta\right)\right)` is required. Same enforcement
|
|
442
|
+
shape as N9/N13: build-enforced, no escape hatch. A single, non-nested bare
|
|
443
|
+
delimiter (`(x)`) is untouched. Fix every nest; see
|
|
444
|
+
[`docs/authoring/notation.md#n15`](notation.md#n15).
|
|
445
|
+
|
|
446
|
+
### 4. Rule N14: catalogue every abbreviation used in lesson prose
|
|
39
447
|
|
|
40
448
|
Every acronym (`OLS`, `MSE`) or dotted abbreviation (`w.r.t.`, `i.i.d.`) used in
|
|
41
449
|
plain prose must now be on the shipped baseline
|
|
@@ -69,14 +477,75 @@ every `abbreviation-explained` diagnostic by adding a
|
|
|
69
477
|
`content/abbreviations/<key>.md` entry or an `allow` entry in
|
|
70
478
|
`course.config.ts`.
|
|
71
479
|
|
|
72
|
-
|
|
480
|
+
The catalog check above runs regardless of Astro wiring, but the inline
|
|
481
|
+
hover/click card on a lesson page's first occurrence of a catalogued
|
|
482
|
+
abbreviation needs its remark plugin wired in too:
|
|
73
483
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
484
|
+
```diff
|
|
485
|
+
+ import remarkAbbreviations from 'explico/reference/remark-abbreviations.mjs';
|
|
486
|
+
…
|
|
487
|
+
remarkPlugins: [
|
|
488
|
+
…
|
|
489
|
+
[remarkCitation, { sources: manifest.sources }],
|
|
490
|
+
+ [remarkAbbreviations, { abbreviations: manifest.abbreviations }],
|
|
491
|
+
]
|
|
492
|
+
```
|
|
78
493
|
|
|
79
|
-
|
|
494
|
+
Skipping this second half is now **build-enforced**, not just documented:
|
|
495
|
+
`explicoContentRefresh()`'s `astro:config:setup` hook checks
|
|
496
|
+
`markdown.remarkPlugins` against the manifest and throws if a catalogued
|
|
497
|
+
manifest table (`manifest.abbreviations`, `manifest.sources`, or
|
|
498
|
+
`manifest.notation.raw`) has no matching plugin (`remarkAbbreviations`,
|
|
499
|
+
`remarkCitation`, `remarkNotation` respectively) registered — so a
|
|
500
|
+
half-completed migration like this one fails `astro build`/`astro dev`
|
|
501
|
+
instead of silently rendering plain text with `pnpm validate:content` still
|
|
502
|
+
green.
|
|
503
|
+
|
|
504
|
+
### 5. Optional: rule N10 warns on an unexplained `\mathrm{…}` label
|
|
505
|
+
|
|
506
|
+
A `\mathrm{…}` multi-letter label (`\mathrm{KE}`, `\mathrm{PV}`) not on the
|
|
507
|
+
shipped roman-label baseline (`base-roman-labels.mjs`) or `course.config.ts`'s
|
|
508
|
+
new `romanLabels.allow` now needs a notation entry the reader can hover — the
|
|
509
|
+
`\mathrm{…}` counterpart to N8. Unlike N9/N13/N14/N15, this is a **Tier-3
|
|
510
|
+
warning** (`roman-label-explained`), not a build failure: it never blocks
|
|
511
|
+
`astro build`, and an existing violation can be silenced with a reviewed
|
|
512
|
+
`lint-ignore.yml` line (`roman-label-explained:KE — <reason>`) while content is
|
|
513
|
+
cleaned up. `pnpm validate:content` surfaces it. See
|
|
514
|
+
[`docs/authoring/notation.md#n10`](notation.md#n10).
|
|
515
|
+
|
|
516
|
+
### 6. Only if you render `AssessmentRunner` directly (bypassing `AssessmentSet.astro`)
|
|
517
|
+
|
|
518
|
+
`AssessmentRunner`'s `Item` props changed shape: `prompt` / `explanation`
|
|
519
|
+
(`string`) are now `promptContent` / `explanationContent`
|
|
520
|
+
(`MixedContentNode[]`), rendered with the new `RenderedContent` component,
|
|
521
|
+
because `AssessmentSet.astro` now pre-renders assessment math through the same
|
|
522
|
+
KaTeX pipeline as lesson body math instead of handing `AssessmentRunner` a raw
|
|
523
|
+
string. A course that only uses `<AssessmentSet>` needs no change here — this
|
|
524
|
+
only applies to a course that imports and renders `AssessmentRunner` itself.
|
|
525
|
+
|
|
526
|
+
### 7. Manifest schema is v13 (additive: v7 → v8 → v9 → v10 → v11 → v12 → v13)
|
|
527
|
+
|
|
528
|
+
Every step is additive — nothing existing changed shape — but a client
|
|
529
|
+
asserting on `MANIFEST_SCHEMA_VERSION` by exact equality needs the final
|
|
530
|
+
number:
|
|
531
|
+
|
|
532
|
+
- **v8** — `assessmentContent`: every assessment item's `prompt` /
|
|
533
|
+
`explanation`, pre-split and resolved for `AssessmentSet.astro` (see item 6
|
|
534
|
+
above).
|
|
535
|
+
- **v9** — `diagrams`, `lessons[].diagrams`, `lessons[].numbering.diagrams`,
|
|
536
|
+
`diagnostics.diagrams`: `<Diagram>` becomes a first-class keyed float with
|
|
537
|
+
its own number stream and `[[dia-<id>]]` references.
|
|
538
|
+
- **v10** — `checks`, `lessons[].knowledgeChecks`, `lessons[].numbering.checks`,
|
|
539
|
+
`diagnostics.checks`: numbered, referenceable knowledge checks.
|
|
540
|
+
- **v11** — `lessons[].lessonExports`-derived fields: standalone HTML / print
|
|
541
|
+
export settings (item 8 below).
|
|
542
|
+
- **v12** — `manifest.abbreviations` (rule N14, item 4 above).
|
|
543
|
+
- **v13** — `manifest.diagnostics.rawFloats`: a raw Markdown/HTML table, an
|
|
544
|
+
unkeyed `<Diagram>`, or a `<Diagram>` nested outside
|
|
545
|
+
`<Memo>`/`<ShortNote>`/`<Table>`/`<Figure>` — none of these reach
|
|
546
|
+
keyed-float validation, so this diagnostic flags them separately.
|
|
547
|
+
|
|
548
|
+
### 8. Optional: enable standalone HTML / print lesson exports
|
|
80
549
|
|
|
81
550
|
No action required to keep building. To opt in, add to
|
|
82
551
|
`content/course.config.ts`:
|
|
@@ -89,7 +558,7 @@ lessonExports: {
|
|
|
89
558
|
canonicalBaseUrl: 'https://your-course.example.com',
|
|
90
559
|
```
|
|
91
560
|
|
|
92
|
-
###
|
|
561
|
+
### 9. Optional: turn on strict numbering cross-checks
|
|
93
562
|
|
|
94
563
|
`remarkNotation`'s new `strict: true` option — recommended via
|
|
95
564
|
`createRemarkNotationOptions(manifest, { strict: true })` — fails the build on
|