Skip to content

Commit 0929c25

Browse files
committed
Close remaining audit follow-ups
1 parent 21b1b2f commit 0929c25

47 files changed

Lines changed: 3219 additions & 9179 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.gitattributes‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
# `src/asset_manifest.py` is generated by `scripts/fingerprint_assets.py`
2-
# and `src/example_sources_data.py` by `scripts/embed_example_sources.py`.
1+
# `src/asset_manifest.py` is generated by `scripts/fingerprint_assets.py`,
2+
# `src/example_sources_data.py` by `scripts/embed_example_sources.py`, and
3+
# `src/editorial_registry_data.py` by `scripts/embed_editorial_registry.py`.
34
# On merge/rebase, keep our side of the conflict — the post-merge and
4-
# post-rewrite hooks regenerate both files deterministically afterwards.
5+
# post-rewrite hooks regenerate these files deterministically afterwards.
56
# This works once `scripts/install-git-hooks.sh` has been run locally,
67
# which registers `merge.ours.driver = true` and points `core.hooksPath`
78
# at `.githooks/`.
89
src/asset_manifest.py merge=ours
910
src/example_sources_data.py merge=ours
11+
src/editorial_registry_data.py merge=ours

‎.githooks/post-merge‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
#!/usr/bin/env bash
2-
# Regenerate generated files after a merge or pull so embedded example
3-
# data and the asset manifest reflect the merged tree, not whichever
4-
# parent won the conflict.
2+
# Regenerate generated files after a merge or pull so embedded data,
3+
# asset manifests, fingerprints, and prototype pages reflect the merged
4+
# tree, not whichever parent won the conflict.
55
set -e
66
cd "$(git rev-parse --show-toplevel)"
7-
uv run --python 3.13 python scripts/embed_example_sources.py >/dev/null
8-
uv run --python 3.13 python scripts/fingerprint_assets.py >/dev/null
9-
if ! git diff --quiet src/example_sources_data.py src/asset_manifest.py public/_headers; then
7+
make build >/dev/null
8+
if ! git diff --quiet src/example_sources_data.py src/editorial_registry_data.py src/asset_manifest.py public/_headers public/prototyping; then
109
echo "post-merge: generated files regenerated; stage and amend if needed"
1110
fi

‎.githooks/post-rewrite‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
#!/usr/bin/env bash
2-
# Regenerate generated files after rebase/amend so embedded example data
3-
# and the asset manifest match the rewritten history, not whichever
4-
# commit happened to win each step.
2+
# Regenerate generated files after rebase/amend so embedded data,
3+
# asset manifests, fingerprints, and prototype pages match the rewritten
4+
# history, not whichever commit happened to win each step.
55
set -e
66
cd "$(git rev-parse --show-toplevel)"
7-
uv run --python 3.13 python scripts/embed_example_sources.py >/dev/null
8-
uv run --python 3.13 python scripts/fingerprint_assets.py >/dev/null
9-
if ! git diff --quiet src/example_sources_data.py src/asset_manifest.py public/_headers; then
7+
make build >/dev/null
8+
if ! git diff --quiet src/example_sources_data.py src/editorial_registry_data.py src/asset_manifest.py public/_headers public/prototyping; then
109
echo "post-rewrite: generated files regenerated; stage and amend if needed"
1110
fi

‎.github/pull_request_template.md‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
## Verification
66

77
- [ ] `make verify`
8-
- [ ] `scripts/check_example_migration_parity.py`
98
- [ ] `scripts/format_examples.py --check`
109
- [ ] `make verify-python-version VERSION=3.13`
1110
- [ ] `git diff --check`

‎.github/workflows/regenerate-generated-files.yml‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
name: Regenerate generated files
22

33
# Merges made through the GitHub UI bypass the local git hooks that keep
4-
# src/asset_manifest.py and src/example_sources_data.py in sync, so a merge to
5-
# main can land with stale generated files (and a red Verify run). This
4+
# src/asset_manifest.py, src/example_sources_data.py, and
5+
# src/editorial_registry_data.py in sync, so a merge to main can land with
6+
# stale generated files (and a red Verify run). This
67
# workflow regenerates them and pushes a fix-up commit. Pushes made with
78
# GITHUB_TOKEN do not trigger other workflows, so the fix-up commit is not
89
# re-verified by CI; it only ever contains deterministic `make build` output.
@@ -43,7 +44,7 @@ jobs:
4344
for attempt in 1 2 3; do
4445
git pull --rebase origin main
4546
make build
46-
git add -A src/example_sources_data.py src/asset_manifest.py public
47+
git add -A src/example_sources_data.py src/editorial_registry_data.py src/asset_manifest.py public
4748
if git diff --cached --quiet; then
4849
echo "Generated files are current."
4950
exit 0

‎.github/workflows/verify.yml‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ jobs:
5151
CHROME_PATH: /usr/bin/google-chrome
5252
run: |
5353
make verify
54-
scripts/check_example_migration_parity.py
5554
scripts/format_examples.py --check
5655
make verify-python-version VERSION=3.13
5756
git diff --check

‎CONTRIBUTING.md‎

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ Then run:
4949

5050
```bash
5151
make verify
52-
scripts/check_example_migration_parity.py
5352
scripts/format_examples.py --check
5453
make verify-python-version VERSION=3.13
5554
git diff --check
@@ -68,9 +67,9 @@ These scripts enforce the catalog-level rules from `docs/example-quality-rubric.
6867

6968
| Script | What it gates |
7069
| --- | --- |
71-
| `scripts/check_registry_integrity.py` | Every owner slug in `docs/quality-registries.toml` exists in `manifest.toml`; tokens are present; each `paired_pages` pair is discoverable through `see_also`. |
72-
| `scripts/check_confusable_pairs.py` | Each confusable pair's owning page contains every token that signals the contrast; a token shadowed inside a longer sibling token (plain `def` inside `async def`) does not count. |
73-
| `scripts/check_broad_surface_tours.py` | Each broad-title page either covers every required form or sets `scope_first_pass = true` with `see_also` links to focused neighbors. |
70+
| `scripts/check_registry_integrity.py` | Every owner slug in `docs/quality-registries.toml` exists in `manifest.toml`; tokens are present; each `paired_pages` pair is discoverable through `see_also` and has registry-named cell tokens demonstrated inside a teaching cell. |
71+
| `scripts/check_confusable_pairs.py` | Each confusable pair's owning page contains every token inside teaching cells; a token shadowed inside a longer sibling token (plain `def` inside `async def`) does not count. |
72+
| `scripts/check_broad_surface_tours.py` | Each broad-title page either covers every required form or sets `scope_first_pass = true` with registry-named `focused_neighbors` linked through `see_also`. |
7473
| `scripts/check_footgun_coverage.py` | Each canonical Python footgun has a page that contains both broken-form and fixed-form tokens. |
7574
| `scripts/check_notes_supported.py` | Every `:::note` bullet (across all note blocks) shares at least one keyword with the page body outside the notes, so notes cannot assert behavior the page never demonstrates. |
7675
| `scripts/check_program_covers_cells.py` | Every executable cell shares substantive code with the `:::program` block, so the editor reproduces what the cells teach; `standalone_cells = true` opts out visibly. |
@@ -82,16 +81,16 @@ These scripts enforce the catalog-level rules from `docs/example-quality-rubric.
8281
| `scripts/check_journey_outcomes.py` | Every journey section declares learner outcomes. |
8382
| `scripts/audit_example_graph.py --check` | The `see_also` graph has no broken targets, self-links, over-linked pages, or orphaned examples. |
8483

85-
The single source of truth for the registries is `docs/quality-registries.toml`. Add a new pair, broad tour, or footgun there, then update the owning page so the tokens appear in cells or prose.
84+
The single source of truth for the registries is `docs/quality-registries.toml`. Add confusable pairs, broad tours, footguns, journey metadata, figure attachments, captions, and curated scores there, then update the owning page so the tokens appear in cells or prose.
8685

8786
## Adding a new example end to end
8887

8988
1. Write `src/example_sources/<slug>.md` (frontmatter, intro prose, one `:::program`, cells, notes) and add the slug to `manifest.toml`'s `order`.
9089
2. Add `see_also` links in both directions — `scripts/audit_example_graph.py --check` fails orphaned pages.
91-
3. Score the page against `docs/example-quality-rubric.md` and add the entry to `EXAMPLE_QUALITY_SCORES` in `src/marginalia.py`.
92-
4. Attach a figure in `src/marginalia.py` (or add a `no_figure_rationales` entry with a review date) and score it; review it on `public/prototyping/marginalia-gestalt.html`, which shows the production caption under every figure.
93-
5. Run `make build`, `make verify-examples`, `make quality-checks`, then `uv run python scripts/refresh_golden_fixture.py` and review the structural summary it prints.
94-
6. Run the full `make verify` with a local Worker running, then commit — including the regenerated `src/example_sources_data.py` and fixture.
90+
3. Score the page against `docs/example-quality-rubric.md` and add the `[[example_quality_scores]]` entry to `docs/quality-registries.toml`.
91+
4. Attach a figure by adding `[[figure_attachments]]` and `[[example_figure_scores]]` entries to `docs/quality-registries.toml` (or add a `no_figure_rationales` entry with a review date); keep only new paint functions in `src/marginalia.py`. Review the result on `public/prototyping/marginalia-gestalt.html`, which shows the production caption under every figure.
92+
5. Run `make build`, `make verify-examples`, `make quality-checks`, and `scripts/format_examples.py --check`.
93+
6. Run the full `make verify` with a local Worker running, then commit — including the regenerated `src/example_sources_data.py`, `src/editorial_registry_data.py`, `src/asset_manifest.py`, and fingerprinted assets.
9594

9695
## Secrets and deploy configuration
9796

‎docs/example-figure-rubric.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ the figure can merge.
185185

186186
## Page-level coherence (per slug, multi-figure)
187187

188-
A separate 0-1.0 score applied to slugs whose `ATTACHMENTS[slug]`
189-
list contains more than one figure. Multi-figure pages must form a
188+
A separate 0-1.0 score applied to slugs whose `[[figure_attachments]]`
189+
entries (loaded as `ATTACHMENTS[slug]`) contain more than one figure. Multi-figure pages must form a
190190
coherent set, not three angles on the same point.
191191

192192
- **1.0** — figures show distinct aspects of the lesson in a

‎docs/example-source-format-spec.md‎

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -547,26 +547,23 @@ The command should fail if:
547547

548548
`verify-python-version` is only meaningful when `uv` can run the requested Python version. Until Cloudflare exposes the same runtime locally, the migration also requires a Worker smoke test for representative examples and at least one POST execution through Dynamic Workers.
549549

550-
## Golden fixture policy
550+
## Golden fixture cleanup policy
551551

552-
`tests/fixtures/golden_examples.py` began as migration safety infrastructure and is now a reviewed **structural snapshot** of the parsed catalog: every example's metadata, program, expected output, and full cell sequence (prose, code, output, kind).
552+
`tests/fixtures/golden_examples.py` began as migration safety infrastructure: a frozen comparison point while the app switched from Python dictionaries to Markdown source files. That rollback window has passed, so the fixture and its refresh/parity scripts are removed rather than refreshed forever.
553553

554-
What the gate proves: an accidental loader/parser/renderer change cannot silently rewrite the teaching structure readers get — it surfaces in `scripts/check_example_migration_parity.py` as snapshot drift across many examples, while a deliberate content edit drifts only the files actually touched. The gate is not a freshness check on content; refreshes are part of editing.
554+
Current rules:
555555

556-
Rules:
557-
558-
- Never hand-edit the fixture. Regenerate it with `scripts/refresh_golden_fixture.py`, which prints a structural summary (examples changed/added/removed and which fields moved) for review.
559-
- Commit a refresh together with the content change it reflects, and read the summary before committing — it is the reviewable record of what the edit did to teaching structure.
560-
- A change to `src/example_loader.py` or the parser must never require a fixture refresh; if it does, the loader change altered parsed structure and that is the regression.
561-
- `scripts/check_example_migration_parity.py` remains a required verification command.
556+
- Do not add a new checked-in catalog snapshot for ordinary content edits.
557+
- Review intentional teaching changes through the Markdown diff, generated-source diff, `verify_examples.py`, content gates, browser layout check, and rubric audit.
558+
- Parser changes must be justified by focused loader/verifier tests, not by refreshing a broad snapshot until it agrees with the new behavior.
559+
- If a future source-format migration needs parity again, add a temporary fixture and delete it in the same migration plan once a stable deployment and rollback window have passed.
562560

563561
## CI policy
564562

565563
GitHub Actions must run the same checks expected locally:
566564

567565
```bash
568566
make verify
569-
scripts/check_example_migration_parity.py
570567
scripts/format_examples.py --check
571568
make verify-python-version VERSION=3.13
572569
git diff --check
@@ -576,7 +573,7 @@ CI must start `pywrangler dev --port 9696` before `make verify` so `browser-layo
576573

577574
## Contributor documentation policy
578575

579-
The README must describe Markdown example editing, `:::program`, `:::cell`, generated embedded source data, `make build`, `make verify-examples`, and the parity check. Contributors should not need to edit `src/examples.py` or `src/example_sources_data.py` by hand.
576+
The README must describe Markdown example editing, `:::program`, `:::cell`, generated embedded source data, `make build`, `make verify-examples`, and the TOML editorial registries. Contributors should not need to edit `src/examples.py` or `src/example_sources_data.py` by hand.
580577

581578
## Worker bundling policy
582579

@@ -599,15 +596,15 @@ The attempted migration failed at Worker startup because Markdown files were not
599596

600597
Native Markdown bundling remains unproven and is not on the production path. The accepted solution is embedded source data generated by `scripts/embed_example_sources.py`. A future native bundling change must be isolated as a spike and prove local dev, production deploy, imports, cache fingerprinting, and failure behavior before replacing embedded data.
601598

602-
## Golden parity script
599+
## Historical golden parity script
603600

604-
Add a dedicated migration script before switching the app:
601+
During the app switch, add a dedicated migration script before switching the app:
605602

606603
```text
607604
scripts/check_example_migration_parity.py
608605
```
609606

610-
Required behavior:
607+
Required migration-time behavior:
611608

612609
- Load the catalog through `src/example_loader.py` and the checked-in structural snapshot.
613610
- Compare example count and order.
@@ -619,7 +616,7 @@ Required behavior:
619616
- Fail on every semantic or teaching-structure difference. No allowlist is permitted for the app switch.
620617
- Print a short table of differences for review.
621618

622-
This script is temporary migration scaffolding. It can be removed only after the old catalog is deleted, one production deployment succeeds, and the rollback window has passed.
619+
This script was temporary migration scaffolding. The old catalog was deleted, production deployment succeeded, and the rollback window passed; the script and fixture have now been removed.
623620

624621
## Fourteen prerequisite verification gates
625622

‎docs/journey-visualisation-rubric.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ Score each section figure on a 10-point scale.
8888
- **Exactly one figure per section.** Section figures are not stacked.
8989
If the section needs two figures the section is doing two things.
9090
- **Caption present.** A figure without a `figcaption` is not allowed.
91-
- **Section summary aligns with caption.** The summary in
92-
`src/app.py`'s `JOURNEYS` list agrees with what the figure caption
93-
asserts. Disagreement means one or the other is wrong.
91+
- **Section summary aligns with caption.** The journey section summary in
92+
`docs/quality-registries.toml` agrees with what the figure caption asserts.
93+
Disagreement means one or the other is wrong.
9494
- **Renders within the centered figure block.** The figure obeys the
9595
width the layout gives it (`clamp(280px, 70vw, 640px)`); design at a
9696
viewBox whose rendered width fits the shared 640px ceiling.

0 commit comments

Comments
 (0)