- tools/mutation-check.mjs with tools/mutants.json: thirteen mutants against the
Module 12 TypeScript reference (the eight of Module 13's first table, plus
Armor before redirect, conditions at parse time, no defender priority, and the
summon seam's noun check); all killed.
- tools/run-scenario.mjs with tools/scenario/run.ts: a designer's cards, words
and seam words as data, played on the Module 10 TypeScript reference.
- course/10-spellgrid/designer-capstone.md and designer-example/ (output.txt
is checked against the tool's output in the tools tests).
- CI: diff-tracks (300 seeds), mutation-check, verify-levels.
- Module 13: the mutation table is the tool's output; differential testing,
undo and the solver sections describe the repository as it is. Lesson 10
says what the level proofs prove for levels 6, 8 and 9.
- schema.mjs: a value that matches no oneOf branch is reported against the
branch its const fields pick.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds course/11-conditions: lesson, scenarios, nine test_11 tests in both
tracks, the cumulative reference (Module 10's plus conditions) and the NEAR
drop. The engine learns a condition role, rules carry conditions, and
Level.hasProperty and conversion evaluate content's condition checks against
the board whenever a rule is used. Resolution pairs only rules with the same
conditions. Catalog, harness contract, research notes and the diff-tracks
generator follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The solver's position key reads stackAt (each tile oldest first). New tool
tools/verify-levels.mjs checks course/10-spellgrid/levels/proofs.json: each
level's shortest solution, and that it exhausts without its idea (neverRule)
or on the naive engine. Levels 4-10, one course idea each, with
test_10_level_N_solution in both tracks, scenarios and Lesson 10's list;
l1 no longer matches l10, and proofs.json is not listed as a level.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A trigger is never queued while that same (minion, trigger) is resolving;
more than DEATH_PHASE_LIMIT = 64 Death Phases is an error ('Death Phase
limit'); Assemble refuses and never offers ill-formed text (wellFormed /
well_formed); summon count > 1 places tokens in summon order. Modules 05-10,
both tracks. Four new Module 5 tests, a tools test that every shipped card
is well-formed, lessons 2, 3, 5, 13 and harness.md updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Rename course/11-break-your-engine to 13-break-your-engine and update every
link and mention; start-module explains that Module 13 has no tests to start.
- tools/diff-tracks.mjs (npm run diff:tracks): stages both references of a
module, generates a seeded random SpellGrid level and script per seed, pipes
it to the Rust and TypeScript CLIs and diffs their output; crashes on one or
both sides fail. stagePlay takes a module number.
- register_assembled: the TypeScript track compared only the text of an
existing Assembled card, so a base re-registered with a new cost (or a
different split) silently rewrote the earlier card. It now compares every
field the engine reads, as Rust does (Modules 5-10).
New test_05_assemble_never_rewrites_an_earlier_card.
- SpellGrid CLIs: coordinates and chooser numbers are 1-9 plain digits in both
tracks (Rust accepted signs, TypeScript accepted "+2", "0x2", "1e0"); Rust
quotes card names verbatim instead of with Debug escapes; Rust joins the
minion list with "; " instead of rewriting ", ". Two new CLI tests per track.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- lessons 8 and 9 updated for the once-per-move rule, per-object negated
conversion and the new ordering tests
- tools/solve-spellgrid.mjs: breadth-first search over a SpellGrid level
with the TypeScript reference; --never-rule and --naive
- README, harness.md and the mentor skill know the new beat and module
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
- verify-references --expansion overlays expansion/solution on each reference and runs the
cumulative tests plus the drop test; refuses a solution that touches src/engine/
- CI job verify-expansions
- README: workspace-template + git init step, tool list, repo disclaimer link
- Cargo.lock for every Rust reference (staged with the reference, pins serde for rustc 1.85.1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lesson 10 and both M10 reference READMEs now give the real recipe
(node tools/play-spellgrid.mjs <rust|ts> [l1|l2|l3]); root script play:spellgrid.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- cardDirs: course/cards only from Module 5 (spec 6.2a); fixture modules 04/05 and tests
- coupling-audit: noun words match as UPPERCASE, PascalCase or a whole string literal;
lowercase identifiers like key/flag pass; card names keep every variant
- isMain() argv guard replaces import.meta.main in coupling-audit and verify-references;
engines.node >=22
- expansion-check: git diff --no-renames so moving engine code into content fails
- start-module and other tools: clear error when .course.json is missing
- check-links: malformed URLs reported as invalid URL instead of throwing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-verify Teikari article quotes and GDC speaker, soften unsourced
claims (lessons 01, 06, 07, 10), add course-simplification bullets to
lesson 07's differs box, qualify OPEN obstruction wording in research,
and add tools/check-links.mjs (report-only) with npm run check:links.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- SpellGrid cards move to course/10-spellgrid/cards; start-module and
verify-references stage course/cards plus module-local cards up to the module,
so M5-M9 workspaces get exactly the pre-M10 card set.
- cast() rejects a chosen-target spell without a target (checkCast/checkPlay);
new test_10_targeted_spell_needs_target.
- Rust CLI pre-validates instead of swapping the global panic hook.
- Catalog: CRIER noun; DEATHRATTLE/BATTLECRY note on lexicon vs catalog role.
- Lesson: design note on mid-movement reparse.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SpellGrid capstone: Part I's card engine and Part II's grid engine joined at
three seams (rules -> aura data, hazard victims -> one destroy Sequence,
Sequence end -> write text, remove the dead, reparse). Three levels with
scripted solutions, a naive-timing test via a harness-only hook that
reverses the END_OF_PHASE list, CLIs in both tracks, the BATTLECRY IS DOUBLE
Expansion Drop, SpellGrid cards and words in course/cards and the catalog,
level schema cards/hand, and tools staging/copying of module levels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cards become JSON data in course/cards (one file per card, validated
against card.schema.json and the catalog); the M5 references load them
via registerCards and interpret effects, replacing content closures.
Adds assemble(base, donor, half), the assemble/buffHand effects with an
injected chooser, Fleshshape as the data-only Expansion Drop, and stages
course/cards in verify-references and start-module.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
verify-references ran a bare `npx vitest run` in the staged reference, which
fetched an unrelated vitest that could not load the reference config. It now
installs the reference's devDependencies first. sync-check also checks each
module's expansion/tests against ### headings in expansion/README.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>