Collapse Tetris' variable clusters, and give the long runs a home
Next move held four clusters of Set variable in a row, fourteen single nodes
in all; clear-lines read three variables one after the other. They are now
one plural node each, which takes Next move 40 -> 30 nodes and clear-lines
25 -> 23. Every remaining single node was checked and really is single: ok/no
are the same variable in opposite branches, take/keep the same one across a
write, and the three key setters hang on three different events.
Two contracts carry those merges, both pinned as tests. Set variables writes
per port with writeTyped exactly as the singular node does, so a Pack{rot}
still merges instead of overwriting - without it, turning would have erased
the other three fields. And the interpreter collects every input before the
node runs, so no input may come from a variable the same node writes; a data
node is evaluated once per pulse and keeps its answer. That second rule is
invisible in the game, because OnUpdate re-reads each frame and heals it, so
it lives in a unit test rather than in the smoke.
/opt/node22 and /opt/npm are gone from the tree. build.sh ran into the empty
path once they were moved away; the other seven mentions were documentation.
e2e.sh and check.sh replace the bare npm calls. A long run does not survive
the end of its shell - four full e2e runs died mid-suite with oom_kill 0 -
so e2e.sh start hands the run to a transient game-maker-e2e.service, which
does. e2e.sh status reports the running job or the last result, and calls a
log without a closing line ABORTED rather than reporting the passes it got
to. Both scripts end on an explicit exit line, because set -o pipefail inside
a script does not protect the caller: measured, ./check.sh | tail still
reports 0. Logs carry a timestamp and land in logs/, which is ignored.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f60358c951
commit
fe3c63c48c
15 files changed
+439
-183
No files matched your search
@@ -575,7 +575,7 @@ and reasons, not what the code does: a `/** */` on every export whose name does
|
||||
|
||||
## Development
|
||||
|
||||
Node 22 is required (on this machine: `PATH=/opt/node22/bin:$PATH`).
|
||||
Node 22 is required (`/usr/bin/node`, in the default PATH).
|
||||
|
||||
```bash
|
||||
npm install
|
||||
@@ -585,10 +585,14 @@ npm run typecheck
|
||||
npm run lint # ESLint, type-aware; --fix for the fixable half
|
||||
npm run format # Prettier over src, tests and tools
|
||||
npm run check # typecheck + lint + format:check + tests, what CI would run
|
||||
./check.sh # the same, ending in `=== CHECK EXIT n ===`: piped into `tail` npm's exit
|
||||
# code is lost (tail's is reported), so a red run reads as green
|
||||
npm run build # writes dist/ and regenerates index.html
|
||||
export GM_REMOTE=user@host # optional: run the browser elsewhere; see below
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 456 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 465 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 – a subset while working on one step
|
||||
./e2e.sh start [GM_STEPS] # the same run detached, see below
|
||||
./e2e.sh status # live progress, or the last run's result
|
||||
node tools/seed-jumprun.mjs && node tools/smoke-jumprun.mjs # 24 checks: the example game, played end to end
|
||||
node tools/seed-tetris.mjs && node tools/smoke-tetris.mjs # 19 checks: the Tetris example, played end to end
|
||||
```
|
||||
@@ -606,6 +610,17 @@ four cores of this box (60% renderer, 18% GPU process, load ~1.0), which it carr
|
||||
step is being worked on, `GM_STEPS` keeps a run to seconds – take the whole suite before a commit,
|
||||
or when a change touches drawing, the widget toolkit or anything else every step sees.
|
||||
|
||||
**`./e2e.sh start` runs the suite detached**, in a transient `game-maker-e2e.service`, and returns at
|
||||
once; output goes to `logs/e2e-<date>_<time>.log` (gitignored) and ends in `=== E2E EXIT n ===`.
|
||||
Backgrounding it from a shell instead is not enough – four runs in a row died mid-suite with no
|
||||
closing line, because the whole process group is killed when the calling shell exits (`nohup` only
|
||||
covers SIGHUP, and `/proc/vmstat` confirmed `oom_kill 0`, so it was never memory). The unit outlives
|
||||
its caller. It takes the same `GM_STEPS` argument and refuses to start a second run over a live one.
|
||||
|
||||
**`./e2e.sh status`** reports the live run (elapsed, PASS/FAIL so far, the check it is on) or, when
|
||||
nothing is running, the newest log's result plus its FAIL lines. A log without a closing line is
|
||||
reported as `ABORTED`, not as its PASS count: a run that was cut short is not a result.
|
||||
|
||||
**`GM_REMOTE=user@host` moves the browser to another machine** – `tools/lib/browser.mjs` starts it
|
||||
over SSH and forwards its CDP port back to `127.0.0.1`, so the harness itself is unchanged. The
|
||||
checks load the public base URL, so the remote side needs only a browser and internet: no repo, no
|
||||
@@ -677,6 +692,16 @@ parallel variables copied back and forth, and each strand packs only the field i
|
||||
(`mergeStruct` keeps the rest). Reading a cell is `((shape · 4 + rot) · 4 + corner)` into that
|
||||
list instead of the same index doubled and read twice.
|
||||
|
||||
Where a step needs several variables at once, one `Get variables` / `Set variables` stands for the
|
||||
lot: the call to `Next move` has **one node at each side** of it rather than five, and the master
|
||||
graph is **44 nodes / 64 edges** where the same game in single nodes was 69 / 76. Inside `Next
|
||||
move` each strand writes its whole answer – the candidate, what kind of move it was and the wish
|
||||
it used up – in one node rather than three to five, which is **30 nodes** against 40. Two things
|
||||
bound how far such a node may reach: a data node answers once per frame and keeps that answer, so
|
||||
a `Get variables` must not straddle a write of one of its variables (which is why the board is
|
||||
read a second time after the lines were cleared), and a `Set variables` reads all its inputs
|
||||
before it writes any, so none of them may come from a variable it writes.
|
||||
|
||||
It is **ten behaviors**, not one graph. `Tetris` owns the state and does none of the work: each
|
||||
step of a frame is a behavior of its own, called as a node – `Spawn piece`, `Next move`, `Fits`,
|
||||
`Draw piece`, `Lock piece`, `Clear lines`, `Show lines`, `Draw board`, with `Piece cell` (where
|
||||
|
||||
Reference in new issue
Block a user