docs: handoff (rulings, corrections, open items and deferred minors after the v2 extensions)
CI / Tool tests and sync-check (push) Successful in 13s
CI / Verify references (all modules, Rust and TS) (push) Successful in 2m1s
CI / Verify Expansion Drop solutions (all modules, Rust and TS) (push) Successful in 1m59s
CI / Coupling audit on references (push) Successful in 6s
CI / Differential fuzzing of the Rust and TS references (300 seeds) (push) Successful in 1m0s
CI / Mutation check (tools/mutants.json against the highest TS reference) (push) Successful in 41s
CI / Verify the SpellGrid level proofs (solver) (push) Successful in 6m13s
CI / Site build (push) Successful in 13s
CI / Naive engine tests (Module 0) (push) Successful in 20s
CI / Tool tests and sync-check (push) Successful in 13s
CI / Verify references (all modules, Rust and TS) (push) Successful in 2m1s
CI / Verify Expansion Drop solutions (all modules, Rust and TS) (push) Successful in 1m59s
CI / Coupling audit on references (push) Successful in 6s
CI / Differential fuzzing of the Rust and TS references (300 seeds) (push) Successful in 1m0s
CI / Mutation check (tools/mutants.json against the highest TS reference) (push) Successful in 41s
CI / Verify the SpellGrid level proofs (solver) (push) Successful in 6m13s
CI / Site build (push) Successful in 13s
CI / Naive engine tests (Module 0) (push) Successful in 20s
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
1 parent
85959ba5a0
commit
b6cbacbd42
1 file changed
+192
+192
@@ -0,0 +1,192 @@
|
||||
# Handoff: state of the course after the v2 extensions
|
||||
|
||||
Written 2026-11-11. This records what the two revision rounds changed, the
|
||||
decisions made along the way that the spec and plan do not show, and what is
|
||||
still open. The code, lessons and commit history are the record of *what*
|
||||
exists; this file is the record of *why* and *what next*.
|
||||
|
||||
## Where things stand
|
||||
|
||||
`main` is at `85959ba` and contains everything below. Two branches fed it and
|
||||
still exist on the remote:
|
||||
|
||||
- `revise/edge-cases-and-sources` (round 1): bug fixes, ordering tests,
|
||||
fact-checking, a "Stress it" beat in every lesson, the closing module, the
|
||||
level solver.
|
||||
- `extend/course-v2` (round 2, built on round 1): Modules 11 and 12, engine
|
||||
extensions in Modules 2, 4, 5, 9 and 10, seven new levels, new tools, the
|
||||
playable site page, three CI jobs.
|
||||
|
||||
Design documents:
|
||||
|
||||
- `docs/superpowers/specs/2026-11-11-course-v2-extensions-design.md` (spec)
|
||||
- `docs/superpowers/plans/2026-11-11-course-v2-extensions.md` (plan)
|
||||
|
||||
**The code departs from the spec and plan text in a few places.** Those
|
||||
documents were not updated afterwards. Where they disagree with the code, the
|
||||
code is right; see "Rulings" below.
|
||||
|
||||
Verification at the time of the merge: `npm run check` ok; 93 tool tests and
|
||||
13 site tests pass; `verify-references` and `--expansion` ok for Modules
|
||||
01–12; coupling audit ok; all 10 level proofs hold; all 13 mutants killed;
|
||||
the Rust and TypeScript tracks agree over the fuzz seeds; the site builds
|
||||
(20 pages).
|
||||
|
||||
## Round 1: what was found
|
||||
|
||||
Three bugs in the reference engines, all with every test green at the time:
|
||||
|
||||
- **Deathrattle summon position.** The Death Event remembered a board index,
|
||||
which went stale when a minion further left died in the same step. It now
|
||||
remembers the surviving right-hand neighbour by id.
|
||||
- **Negated conversion lost to a group noun.** `ALL IS ROCK` plus
|
||||
`BABA IS NOT ROCK` turned Baba into a rock.
|
||||
- **A pulled `YOU` object moved twice.** A key that was `YOU` and `PULL`
|
||||
behind Baba was dragged one tile, then took its own step.
|
||||
|
||||
Six ordering decisions that no test pinned were found by mutating the
|
||||
engines' order lists: two turn-phase reorderings, a dropped final parse, two
|
||||
hazard reorderings, and a live aura scan in place of the snapshot. Each now
|
||||
fails a named test.
|
||||
|
||||
Fact-check results:
|
||||
|
||||
- Two Branns: the lesson said the sources do not say how they combine. The
|
||||
wiki does ("Brann's effect does not stack with itself"). Fixed.
|
||||
- The rulebook's Acolyte of Pain example predates the 2023 change from 3 to
|
||||
4 Health (Patch 27.2.0.183876). The card data was right; the example is
|
||||
flagged as stale.
|
||||
- HearthSim's mirror of the game's tag names has `EXTRA_DEATHRATTLES_BASE`
|
||||
next to `EXTRA_DEATHRATTLES_ADDITIONAL`, which looks like the same split as
|
||||
Module 4's `stacking` field. The lesson presents this as a reading of the
|
||||
names, not a documented rule.
|
||||
- Level 1 cannot be solved without `DEATHRATTLE IS DOUBLE`, and Level 3 has
|
||||
no solution on the naive-timing engine (both by exhaustive search).
|
||||
|
||||
Decisions made in round 1:
|
||||
|
||||
- Module 9 requires the Module 7 Expansion Drop (`ALL`), the way Module 4
|
||||
already requires earlier drops. Without it the conversion bug has no test.
|
||||
- An object steps at most once per move, and a stepped object does not block
|
||||
a later mover. This keeps stacked `YOU AND PUSH` objects together. It is
|
||||
the course's rule; no source covers it.
|
||||
- Two dying neighbours summon their tokens in order of play, even if that
|
||||
reverses their board order. Unsourced, and labelled so.
|
||||
- Module 9 went from 8 tests to 14.
|
||||
- "Stress it" is a new optional lesson beat.
|
||||
|
||||
## Round 2: where each idea landed
|
||||
|
||||
| Idea | Result |
|
||||
|---|---|
|
||||
| Differential fuzzing of the two tracks | `tools/diff-tracks.mjs`. No divergence in 5,000 seeds. Three real track differences were found by reading side by side and fixed: the TypeScript `registerAssembled`, and two CLI parsing differences. |
|
||||
| Replacement effects | Module 4: `DAMAGE_STEPS = [redirect, armor]`, the `damageRedirect` aura, the `ArmorLost` event, the card Bolf Ramshield. |
|
||||
| Nesting guard and Death Phase cap | Module 5: a resolving stack in `World`; `DEATH_PHASE_LIMIT = 64`. |
|
||||
| Well-formed Assemble | Module 5: `wellFormed` / `well_formed`. |
|
||||
| Conditions | Module 11: `NOUN ON NOUN IS …`, evaluated per object at use; `NEAR` is the drop. |
|
||||
| Fourth SpellGrid seam | Module 10: a summoned minion with a noun enters the grid (`Summoned.by`); cards Clay Golem and Clay Shard. |
|
||||
| Combat and turns | Module 12: `orderAttack`, `canAttack`, `endTurn`, Taunt, defender-first as a queue priority; Bonechewer Brawler is the drop. |
|
||||
| More levels, solver-verified | Levels l4–l10 with `course/10-spellgrid/levels/proofs.json` and `tools/verify-levels.mjs`. |
|
||||
| Log tree printer | `logTree()` / `log_tree()` from Module 2; both SpellGrid CLIs print it. |
|
||||
| Designer capstone | `course/10-spellgrid/designer-capstone.md`, `designer-example/`, `tools/run-scenario.mjs`. |
|
||||
| CI | Three new jobs (`diff-tracks`, `mutation-check`, `verify-levels`). Never run on a real runner; see "Open items". |
|
||||
| Interactive site | `/play/` runs the Module 12 TypeScript reference unmodified in the browser. |
|
||||
| Undo | `undo()` on the grid engine from Module 9. SpellGrid deliberately reports it as not supported. |
|
||||
| Solver position key | Age-aware, via `stackAt`. |
|
||||
| Leftovers from round 1 | The Lesson 8 quote and the `count > 1` summon order are fixed. |
|
||||
|
||||
The closing module, "Break your own engine", was renumbered from 11 to 13.
|
||||
|
||||
## Rulings
|
||||
|
||||
Decisions made during round 2 that the spec and plan do not record, each with
|
||||
what it costs if it was the wrong call.
|
||||
|
||||
1. **Worked on a branch in the main checkout, not a separate worktree.** No
|
||||
lasting cost.
|
||||
2. **The CI jobs were validated by running their commands locally.** There is
|
||||
no runner. A workflow syntax error would only show on a real runner, and
|
||||
CI pins Rust 1.85.1 where the local runs used 1.99.
|
||||
3. **The plan gave tests as scenario prose, not code in two languages.**
|
||||
Reviewers had to check tests against scenarios more carefully.
|
||||
4. **The redirect test uses Armorsmith's reaction** as "the minion's damage
|
||||
trigger fires", since Bolf has no damage trigger.
|
||||
5. **`wellFormed` is stricter than the spec's wording.** It also rejects an
|
||||
effect after an aura or keyword. A future card with a keyword between
|
||||
trigger and effect would be rejected.
|
||||
6. **`Summoned.by` is set in `World.enter` from the innermost resolving
|
||||
trigger,** not threaded through the queue. A future summon outside a
|
||||
trigger block would have no summoner.
|
||||
7. **The fuzzer's generator was extended for conditions** in the Module 11
|
||||
task, outside that task's file list. Earlier modules' cases are unchanged.
|
||||
8. **The attack action is `orderAttack` / `order_attack`, not `attack`.**
|
||||
`attack(id)` has returned a character's Attack since Module 2. The spec
|
||||
and plan say `attack`.
|
||||
9. **No course test for closing a trigger block on error.** It is covered by
|
||||
reference-only tests. Learners' engines are not asked to do it.
|
||||
|
||||
## Where the course knowingly differs from the real games
|
||||
|
||||
Both are stated in the lessons as the course's choice.
|
||||
|
||||
- **Nesting guard.** The course drops the skipped activations. Hearthstone's
|
||||
rulebook says: "Instead it works the skipped times as a compensation after
|
||||
all other consequences of it are resolved."
|
||||
- **`ON ALL`.** The course means "any one other object". The Baba Is You wiki
|
||||
says "ALL in the noun2 part requires one of every object in ALL".
|
||||
|
||||
## Corrections made during round 2
|
||||
|
||||
Claims that were wrong in a draft and fixed before the merge. They are listed
|
||||
because each is easy to reintroduce.
|
||||
|
||||
- Lesson 2: two Bombs do not "hit each other once each"; the correct count is
|
||||
six activations.
|
||||
- Lesson 10: level 2 has 18,601 reachable positions, not "some 31,000".
|
||||
- Lesson 11: a wiki page does cover `ON ALL` (see above).
|
||||
- Lesson 12: several Hearthstone claims were not in the research log; they
|
||||
were re-fetched and logged in `docs/research/hearthstone.md`.
|
||||
- Module 13: the mutation table's rows follow `tools/mutants.json`, and the
|
||||
survivor count is five in both places it appears.
|
||||
|
||||
The final whole-branch review found three important issues, all fixed in
|
||||
`85959ba`:
|
||||
|
||||
- An engine error in the middle of a Sequence left a corrupt game in
|
||||
`run-scenario` and the TypeScript CLI. It is now fatal ("The Sequence did
|
||||
not finish, so the game cannot go on."), and trigger blocks close on error
|
||||
in Modules 2–12 (`try`/`finally`; `catch_unwind` in Rust).
|
||||
- The nesting guard was presented as Hearthstone's rule. It is now labelled
|
||||
as the course's.
|
||||
- The Node floor is 22.15, because the site's game test needs it.
|
||||
|
||||
## Changes to the learner contract
|
||||
|
||||
- Module 5 has a new test, `test_05_assemble_never_rewrites_an_earlier_card`.
|
||||
- Module 9 requires the Module 7 drop (`ALL`).
|
||||
- `package.json` `engines` is `>=22.15`.
|
||||
|
||||
## Open items
|
||||
|
||||
- **CI has never run on a real runner.** The Gitea workflow needs the
|
||||
`ubuntu-latest` label and access to GitHub for the actions it uses.
|
||||
- **The deploy subdomain is not set** (`COURSE_HOST` in `deploy/.env`).
|
||||
- The owner's read-through of the course is still to come.
|
||||
|
||||
## Known minor issues, deliberately deferred
|
||||
|
||||
- Level 9 is the weakest puzzle: its chain push is forced, not a decision.
|
||||
- The solver, `verify-levels`, `play-spellgrid` and `run-scenario` stage the
|
||||
Module 10 engine, while the site, fuzzer and mutation check use Module 12.
|
||||
It is the same game for the shipped levels, and the lessons say so.
|
||||
- The differential fuzzer rarely puts an Assembled minion on the grid and
|
||||
never draws Bolf.
|
||||
- Play page: focus is lost after a tile click, and arrow keys are captured
|
||||
page-wide.
|
||||
- No tests for: SpellGrid undo erroring, a conditional rule giving no aura,
|
||||
third-party defender priority, two Taunts.
|
||||
- `site/scripts/sync-content.mjs` duplicates `cardDirs` from `tools/lib.mjs`.
|
||||
- Lesson 11's hazard-board bullet has nested parentheses.
|
||||
- From v1: the coupling audit flags PascalCase names and string-literal noun
|
||||
words; the chooser type in `course/harness.md` does not match the code; the
|
||||
`registerCards` test is weak.
|
||||
Reference in new issue
Block a user