The chain built its own worst moment: hero and tail deadlock at orientations 0
and +2 and open only at +1, with +3/+4/+5 left entirely to chance. That is why
some levels released at exactly one of six orientations, and why every model
kept writing "I don't know which way to turn" — at +2 one direction was right
and the other five were dead ends.
createDeepLock now traces candidates at all six orientations and requires the
tail to also release at +3, certified with the real swept tracer. A player
stuck at +2 turns either way and something moves. Measured by the rule bot
over the regenerated set: blind rotations, wrong-way turns and extra rotations
all go to zero, from 1.17 / 0.44 / 1.22 per level. Endgame orientation counts
shift from {1:4, 2:10, 3:4} to {2:3, 3:13, 4:1}.
It costs yield: switchback r3 and crossing r3 now produce nothing, and the set
comes out at 17 levels rather than 18. The test witnesses moved with it — a
witness is whichever seed still satisfies the construction, so they are
re-derived from the sweep rather than pinned.
docs/level-board.html is the task board for getting to 50 levels. Task state is
in bench/board.json; every number on the page — candidate count, rotation
quota, blind turns, monkey actions-per-piece, the agent batches — is measured
from the level set and the run archive at build time.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Regenerating levels/prototypes/d5.json renumbers every level, so the previous
build — which resolved runs through the current set's ordinals — silently
dropped every run played against an earlier set. The report I committed one
commit ago was built that way: 130 runs instead of 229, and the test-retest
table down to 7 paired levels from 18.
Levels are now keyed by id throughout. Runs carry their own level, so ids the
current set no longer contains are read back out of the archive and given an
ordinal after the live ones; the cross-model table intersects on ids rather
than assuming two sets number the same level alike.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every model that played the D5 set complained about the same moment: two
pieces left, interlocked, and nothing on the board saying which way to turn.
codex-spark took it to the end — it cycled all six orientations on L18 and
gave up on a level that was solvable, with clarity rated 5. Replaying the
position shows exactly one of the six orientations releases anything.
deadTurnAudit now reports endgameMinOpen: across reachable states with three
pieces or fewer left, the fewest orientations that release anything. It is
computed inside the walk that was already happening, so it costs nothing. The
generator requires at least two.
The gate picks out precisely the four levels every model stalled on, with no
false positives — the other fourteen already had two or three. Regenerating
drops the spiral family entirely: its structure produces single-exit endgames
by construction, not by unlucky seed.
Measured on the regenerated set, rule bot first and then grok-4.6 xhigh over
all 18:
blind rotations 1.17 -> 0.29 per level
extra rotations 1.22 -> 0.35
dead taps 2 -> 0
run time 55.5s -> 34.7s
stuck rating 1.89 -> 1.41 (this metric repeats at r = 0.85)
"which way do I turn" complaints 22% -> 12% of levels
The gate is a floor, not a difficulty dial: difficulty also fell, 2.39 -> 2.12,
because the levels it removes are the hard ones. And it treats a symptom — the
t0/t3 interlock is what the four-piece chain in createDeepLock builds by
construction, so the complaint is halved rather than gone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
One batch of 18 runs was recorded as codex-spark at xhigh but had actually run
as gpt-6-astra at low effort: the CLI config was rewritten between the check
and the batch, and codex resolved the new model silently. The archives are
relabelled from the CLI's own startup header rather than from what the agent
was told to call itself, and the report now says to trust that header over the
self-reported name. The re-run verifies the resolved model after every level
and aborts the batch on a mismatch.
With the real codex-spark batch added, five independent runs of four models
from three vendors now cover the same 18 levels on the fixed board, and 16 of
17 comparable levels agree exactly on the rotation triple.
codex-spark gave up on L18 after cycling all six orientations, reporting no
exit anywhere — replaying the position shows orientation 1 releases t0, and
that it is the only one of the six that does. The level is solvable and the
routes are legible (it rated clarity 5), but nothing on the board says which
way to turn: a 1-in-6 guess with a dead end behind every other door. That is
the terminal-interlock complaint the other models kept raising, at its limit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds the kimi-k3 and codex-spark batches, so the rotation counters are now
compared across four independent runs of three models from three vendors on
the fixed board: 17 of 18 levels agree exactly, triple for triple.
The clean test-retest (same model, same harness, same board, run twice) also
corrects two earlier readings taken from data that had a board-format change
mixed in. Difficulty ratings reproduce at r = 0.93 rather than 0.63 — the
earlier low figure was the format change, not the metric — so an agent can be
trusted to rank 1000 levels by difficulty even though its absolute scale may
be offset. And the mechanical counters are highly reproducible rather than
deterministic: 0.82-0.92, not the 1.00 the confounded pair suggested.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
design-review.html is the gameplay and UI read on the shipped campaign, with
boards rendered from the repo's own geometry rather than redrawn.
bench-reliability.html asks which of the bench's numbers are worth acting on,
and answers it by running the same 18 levels twice under identical conditions.
The mechanical rotation counters reproduce (r = 0.82-0.92) and three different
models agree on them level for level, so they measure the level rather than
the player — a 12-second rule-bot sweep gets the same answer as hours of
model time. Difficulty and stuck ratings also hold up (r = 0.93 / 0.85), but
the ratings for rotation, clarity and fun do not (0.32 / 0.19 / 0.56): asking
a model whether rotation matters is noise, while counting blind rotations is
not.
Every figure is computed from bench/runs by build-bench-report.mjs; nothing in
the page is hand-written, so it can be regenerated as runs accumulate.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The shipped 1000 levels have a hole: 568 of them need no rotation at all, and
none needs more than two — the mechanic the game is built on is mostly
decoration. This fills the empty band with levels that need at least three.
createDeepLock builds a four-piece chain where each link only releases at a
later orientation, and growDeepLevel packs the rest of the board around it
without opening a shortcut. Candidate pools are built per orientation and left
untruncated; ranking by bend count first starved the packer and capped levels
at four to six pieces instead of twelve.
deadTurnAudit enumerates every reachable (orientation, remaining-set) state to
prove no dead ends exist, and counts how long a player can be left with
nothing to do — solvable and feeling solvable are different things, which is
what "level 2 is impossible" turned out to be about.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four ways in, depending on what you have: a shell agent driving bench.mjs, a
direct-API loop for models with only an endpoint (plain text in, one JSON line
out, so weak and local models can play), a rule-following bot that sweeps 1000
levels in 12 seconds, and a folder you can hand to someone else.
bench-kit.mjs builds that folder: CLI, engine, level pack, observer page and
tile atlas, about 1.5 MB, needing only Node 20 — no repo, no install, no
network. The engine files are discovered by following imports so a new module
can't be left behind, every path rewrite is asserted so a rename fails the
build loudly, and the builder plays a real game inside the result before
declaring it done.
bench-report.mjs aggregates two ways: per level (is this level any good) and
per model (how does this agent play). bench-import.mjs brings runs played
elsewhere back in under a tag.
bench-pack.mjs is the earlier, smaller export with no observer page; superseded
by bench-kit but kept in history rather than dropped silently.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Watch an agent play in real time, replayed with the main game's renderer and
animations. The board holds the stage with the live panel beside it: a
millisecond stopwatch, how long the current step has been thinking, steps,
decisions, pieces cleared, dead taps and rotations, then the agent's running
commentary. A banner over the board names who is playing, self-reported by the
agent via --agent.
The page polls unconditionally; the checkbox only decides whether the cursor
chases the newest step, and it follows the agent into its next run once this
one ends. Clicking any step in the feed replays the board at that moment, and
the arrow keys walk it — there is no scrub bar, since the feed already is one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Let any agent with a shell play a level the way a person does: look at the
board, decide what to tap or which way to turn, read the feedback, decide
again. Every step carries the agent's own reason, so a human can watch and
judge the level from how it was played.
observe() returns what the eye sees — each piece's drawn route, which cells it
crosses, who is sitting on it, and who it brushes past — never "which pieces
can leave". act() goes through the real Game rules; metrics() scores the run
afterwards with the solver.
Pieces are wide, so a route with nobody standing on it can still be blocked by
a neighbour the curve hugs. That is invisible in a cell listing, so every
obstacle is reported, on-route and grazing alike: reporting only the leading
one hid the rest, and in 113 of 581 such cases clearing the blocker sprang a
collision the agent had never been shown.
AGENT.md is the single file an agent reads — rules, board reading, commands,
rating scale, worked example.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Run archives, the aggregated report and the packaged standalone kit are all
regenerated from scripts; bench/runs alone is 16 MB across 1140 files.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add the paper direction with thin tracks, outlined hexagons and line arrows, without exterior color markers or piece numbers. Add a unified catalog for five designs and their 25 themes, with direct review links.
Organize each design into an authored design.md, generated tokens.json and preview. Add Agent routing, shared integration guidance, a machine-readable manifest and an executable rendering example. Preserve legacy preview and document links.
Validation: 16 focused design, theme and package tests passed; npm run design and static build passed. Confirmed all eight authored documents survive generation unchanged. Browser checks covered mobile, tablet and desktop layouts, theme links and migrated previews. Native engine integration and visual verification remain pending.
Restore v0.1 and v0.2 archives with separate progress, publish the curved v0.3 campaign, and document the original 24-level design with reproducible evidence. Refine board presentation and movement, and keep video lab tooling within its own directory.