Repository navigation
Engine lane into main - #51
Conversation
Exports everything the calculator reads at startup into a verified, language-neutral bundle (JSON with Map/Set/undefined tags plus named catalogue files, every file pinned by length and SHA-256). An opt-in bundle worker loads it without touching packs, defaults files or dataset environment variables; the normal scheduler is unchanged. Equivalence: 14 requests plus the ready catalogue on a copied real save and on open-f2p, zero differences. Duo startup median 3.9 s -> 2.3 s. docs/calculator-protocol.md lists every input with sizes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex review on #16. An installed profile adds capabilities.features after the legacy digest is computed, so every profile-selected export failed its own verification; those flags are now left out of the preimage and must match the profile's values. open-starter had no digest branch at all. Tests cover both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measurement only, no app changes. scripts/perf/engine-profile.mjs runs the reference calculator as a process worker per request type (cold and warm, five runs, CPU core-seconds, RSS, optional CPU and heap sampling). docs/perf/engine-profile.md records the baseline on a copied real save and open-f2p (duo: compile 1.8 s, cold play 4.8 s and 8.2 core-s, warm play 54 ms, 688 MiB at ready), the port surface, and the bake-off plan: port evaluate first behind supports, race an optimised-JS contender on the same boundary, compare at 1/8/32 pickers with zero checker differences. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
calculator/reference hosts the unchanged task worker behind protocol 1. tools/calc-check replays a corpus (generated games, harvested unit-test fixtures, a real save) against a reference and a candidate and compares every reply exactly. Only measurement fields listed in volatile.json are ignored, each with its source line. Reports hold paths and hashes only. Built in Codex Cloud (EN1). Integration fixes for Windows: module flags for fixture capture are passed as file URLs, and the wrong-candidate wrapper resolves its child with fileURLToPath instead of URL.pathname. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…anging A result part was decoded after its request left the pending map, so a decode error could no longer reject it and check() waited forever. Parts are now decoded first. init() now races its write against the watchdog and kills a candidate that never reads stdin; the ready promise is handled from construction, so a timeout no longer surfaces as an unhandled rejection that drops the report. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It runs three core test files in a child process. Under the full suite on GitHub it passed 30 s; locally it takes 10-13 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in P1 (plugin finished tasks and Roll 2 summaries, #22) and the worker protocol step (#23: worker supersession, state refs, cache inputs and cancel scoped by pickerId; absent pickerId is legacy-shared). The only conflict was scripts/test-selection.mjs, where both sides added entries; the resolution keeps both, with no duplicates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A single private run of the full 414-state corpus projects to about 12
hours: the calculator's own CPU dominates. So the private gate now runs
as N parallel shards and keeps every state, rather than a sample.
- --shard i/n assigns states by interleaving them in manifest order
after limits. Each shard report records:
- the corpus manifest and its hash;
- the seed, engine versions and configuration;
- its state ids, comparisons and differences.
- --merge-reports refuses mismatched manifests, seeds, versions or
configurations. It also refuses gaps, overlaps and wrong assignments.
Zero differences over full coverage is the passing gate. Partial
merges are not supported.
- Preparation per shard fell from 995 s to about 32 s:
- only the shard's save snapshots are loaded, lazily, with parsed
static data reused;
- comparisons walk values structurally and hash only differing
leaves.
Verdicts are unchanged: same public comparisons, and the wrong
candidate is caught at identical paths.
- New perf tools: calc-check-profile.mjs (numeric profiler) and
calc-check-normalized-parity.mjs (checks all 414 normalized inputs
against the earlier fingerprint).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes both Codex findings on #28: - Retained archives were decompressed while listing, and every archived document stayed reachable for the whole check. That included documents belonging to other shards. The listing now keeps only archive names and snapshot ids. A shard decompresses the archives holding its own states on demand, at most two at a time. - A small save has no static/ or history/ directory. The source inventory now treats a missing directory as empty, instead of failing with ENOENT. The reader test checks both cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two benchmarks under scripts/perf: one for the calculator protocol and one for the server. Both use released packs with fresh and grown pickers, plus the production transport. The report in docs/perf/engine-profile.md sizes the 6 vCPU / 11 GiB VPS: - MP4 as it stands: 2 contexts, 4 calculators. Cold median 8.11 s, warm p95 at most 47 ms, peak RSS 6.13 GiB. - With a global calculator cap (MP4 lacks one): 8 contexts sharing 2 calculators. Cold p95 6.36 s, warm p95 at most 0.93 s, peak RSS at most 6.26 GiB. - One worker shares compiled data across pickers. For 8 pickers, startup CPU drops from 2.33 to 0.26 core-seconds and RSS from 1,357 to 376 MiB. The earlier 32-context recommendation is withdrawn: it came from empty synthetic pickers. App code is unchanged. The smoke test runs on Linux only, because the benchmark reads /proc and getconf. Cloud task EN6 (START ff08cea): quick 2,466 passed, 0 failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Snapshot and eligibility caches are shared across pickers in a worker, admitted against one budget. At 384 MiB the two-picker warm round goes from 10.6 s to 6.5 s, the eight-picker p95 improves 16.8% and median peak RSS drops 261 MiB. 256 MiB was faster for eight pickers but made two pickers 39% slower: the proof reservation left too little room for snapshots. The EN6 capacity test now expects 4 engine evaluations: EN7 computes the four unique inputs and reuses the rest. Public calc-check: 4,067 states, 70,384 comparisons, 0 differences. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An empty sandbox request without a preview or planning chunk reuses the baseline snapshot, which belongs to the complete cache. The retained playResult and sandboxDelta were attached after the only refresh, and that refresh went to the sandbox cache, so their bytes stayed uncharged (the new test measures 75,651 bytes against 54,091 charged). Refresh both caches after the objects are assigned. Public calc-check 4,067 states and private sample 8 states: 0 differences. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 48-shard private check showed EN7 about 30% slower per request for one picker: every insert re-measured whole snapshot graphs. Snapshot sizes are now measured once per component and reused, and eligibility buffers are charged in full until idle compression replaces them, so the budget is never under-charged. Interleaved single-picker latency against the lane, 5 pairs per state: +6.0%, +2.5% and -1.6% (was +25% to +36%). Multi-picker gains kept at 384 MiB: two-picker warm round 17.0 s to 8.2 s, eight-picker p95 5.0 s to 2.4 s, eight-picker peak RSS 2.40 to 1.98 GiB. Public calc-check 4,067 states: 0 differences. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A caller that mutated a Buffer returned from a raw (not yet compressed) eligibility hit corrupted later results, and a compression failure in the idle callback escaped and ended the worker. Raw hits now decode from a copy, and a failed compression keeps the fully charged raw buffer. Found by the Cloud review of 2a35bcc; the new tests fail on it. Quick suite: 2,496 passed, 0 failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings main (the multiplayer lane and G15) into lane/engine so the lane can go to main. Only scripts/test-selection.mjs conflicted; both sides' registrations are kept. engine.mjs merged automatically and keeps both EN7's shared budget and main's slayer gates and ports-scroll rules. Adds tests/engine-cache-multi-picker.test.mjs (one picker can never read another picker's cached data through one shared calculator) and docs/audit/engine-main-gate.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Holding this merge. The gate run passed every correctness check (public 4,354 states, private 8 states, real duo in both modes, option-absent parity: all 0 differences), but on the private sample EN7 makes some interactive requests slower than main: chunk planning 336 to 1,161 ms, sandbox 3,178 to 5,052 ms, area check 9,969 to 13,441 ms (one trial, overlapping other checks). A Cloud task is reproducing and fixing this on lane/engine; the fix comes back here through a lane merge. |
Transactional cache admission (a rejected entry never evicts the baseline), cached-draft reuse, prediction bounds, sizing reused from the eligibility proof (137 -> 32 ms), and the temporary sizing buffer is released. Multi-picker gains hold at 384 MiB: 2 pickers 16.5 -> 7.8 s, 8 pickers 117.8 -> 60.5 s; peak worker RSS 1.97 / 2.03 GiB. Remaining over 5% (single picker): state-7 sandbox +6.7%, detailed first +7.6%, area +8.7 to +13.8%. Checker: 16 public shards and the private 8-state sample clean (0 differences). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # app/tasks/worker.mjs # scripts/test-selection.mjs
# Conflicts: # app/tasks/engine.mjs # app/tasks/worker.mjs # scripts/test-selection.mjs
…mates Main re-prepares chunk predictions when the revision changes (pending offers), reading state.revision. The lane's cached sandbox drafts keep their prediction but drop their state, so a cached detailed draft passed undefined state and threw. Compare against the caller's state (source) and rebuild the hypothetical state when a cached draft's prediction is stale. Main also added the first static JSON import in app/ (unknown-drop estimates). The calculator bundle forbids source JSON reads, so the estimates are now an .mjs module with identical contents. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Engine lane into main
This brings the engine rebuild lane into main. Nothing goes live until a release.
What the lane adds
EN7 results
This merge
scripts/test-selection.mjsconflicted; both sides' registrations are kept.app/tasks/engine.mjsmerged automatically.dcccaa8against this main): quick 2,932/0; public checker 4,354 states, private sample and real duo in both routing modes, all 0 differences.tests/engine-cache-multi-picker.test.mjs: one picker can't read another picker's cached data through a shared calculator.docs/audit/engine-main-gate.md.Open, not blocking: cold replies still spend ~0.23 s sizing the baseline snapshot. Moving it off the reply path needs size bounds from the calculator (a
worker.mjschange), so it's a later item.🤖 Generated with Claude Code