mirror of
https://github.com/diangogav/EDOpro-server-ts
synced 2026-08-24 00:23:05 -04:00
1 commit
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
83e8cd5a73
|
feat(edison): MR1 (2010) format — forked core, pre-errata pool, resource pipeline (#316)
* fix(chat): mark replay hint as system message * fix(ygopro): use full 256-bit seed entropy for server deck shuffle The pre-duel shuffle folded the 8-word seed into a 32-bit xorshift32 state, limiting the shuffle space to 2^32 permutations and discarding 224 bits of generated entropy. Seed the shuffle with xoshiro256** through per-lane SplitMix64 instead, preserving the full seed. Fisher-Yates and rejection sampling are unchanged. No replay or recovery impact: shuffled decks are stored in DuelRecord and never re-derived from the seed. * fix(edopro): preserve 64-bit duel seeds when launching CoreIntegrator Seeds were passed to the core child process through Number(), whose 53-bit mantissa rounds ~99.6% of random uint64 values. The core played with rounded seeds while the replay stored the exact ones, so replays re-simulated with a different RNG stream and desynced. Serialize the launch payload with the seeds spliced in as raw JSON integer literals. The splice runs only over the config serialization, so player-provided strings cannot forge the placeholder. * test(edison): add MR1 behavior suite against headless ocgcore WASM In-process harness (no worker threads) boots the bundled WASM core with deterministic seeds and drives scripted duels. Verifies MR1 era rules on the pinned binary (koishipro-core ^1.5.2): - turn-1 draw for the starting player - ignition priority (Exiled Force vs Trap Hole, duel_rule 2 differential) - single face-up Field Spell destroyed with REASON_RULE (rule 5 differential) - damage step: flip effects in substep 6, activation-window masking, Honest resolution-time ATK math Documents two confirmed gaps as it.failing executable documentation: - core implements modern 0 ATK vs 0 ATK battle (neither destroyed); 2010 rule requires mutual destruction — ungated by duel_rule - Honest script cannot activate during damage calculation (2010 ruling allowed substep 4; modern PSCT behavior) * docs(edison): add format compliance roadmap Living checklist for Edison (TCG March 2010) correctness across repos: MR1 rules verified in core source and now by the behavior suite, banlist audit results, April 2010 pool cutoff, pre-errata coverage (11 present, 25 missing), server wiring drift, client MR1 board layout gap, and matchmaking scope. Records the two suite-confirmed gaps (0-ATK battle core rule, Honest damage-calculation window). * feat(edison): verify core compliance + 3 duel_rule<=1 fork gates Re-verify all 13 official Edison rule-differences against the ocgcore WASM. Fix the 3 real core gaps in the fork, each gated by duel_rule<=1 so modern duels are untouched: - #3 Union 1-per-monster (card::get_union_count folds modern+old) - #13 0-ATK mutual destruction (field::calculate_battle_damage) - #10 LP-cost-to-0 refusal (field::check_lp_cost) Add the MR1 behavior + pre-errata behavior test suites (headless ocgcore), green on BOTH the stock and forked WASM. Fork patch + reproducible build in src/test-support/ocgcore/wasm/. * feat(build): private manifest override + GitHub token for private sources Generic add-on to fetch PRIVATE git sources (the pre-errata scripts moat today, any private repo tomorrow) without leaking them into the public repo: - resources.manifest.json stays PUBLIC (no private source/assembly). - resources.manifest.private.json (gitignored) declares the private source(s) + their assembly; resources-lib.sh merges it over the base into an effective manifest at build and runtime. Explicit MANIFEST_PATH (tests) skips the merge. - resources.manifest.private.example.json documents the format. - scripts/setup-git-credentials.sh: env-based git credential helper for github.com HTTPS using a read-only GH_PRIVATE_TOKEN. Never persisted to a layer or disk; no-op when unset. - Dockerfile: BuildKit secret (id=gh_private_token) for the resource builder; COPY resources.manifest*.json into builder + final image. - entrypoint.sh: set up credentials before the runtime updater loop. Host setup (not in repo): create resources.manifest.private.json; add GH_PRIVATE_TOKEN to .env; pass --secret to docker build. * feat(edison): switch server pool to pre-errata.es.cdb, drop classic from pool Eliminate classic from the server card pool (base + whitelist + pre-errata overlay model): - manifest: assemble pre-errata.es.cdb (bilingual pool, 28 cards) instead of the old edison-pre-errata.cdb; remove `classic` from runtime.standard. classic.cdb stays assembled (the ocgcore differential tests use its codes as baselines). - harness: load pre-errata.es.cdb. Suite green on both cores; ResourcePoolResolver + manifest bats unaffected. * feat(edison): deliver fork ocgcore as a resources add-on + boot verifier The Edison fork WASM is now delivered through the resources manifest (source "edison-core" → assembly ygopro/core/ocgcore-worker) instead of a bespoke Docker step, so it is fetched, seeded, and refreshed by the same pipeline as the cdbs/lflists and can be bumped by editing the manifest. verifyEdisonCore() runs at boot: it hashes the resolved core and logs loudly (or aborts when EDISON_CORE_REQUIRED=true) if it is missing or its sha256 does not match the expected fork build — ending the silent fallback to the stock core that koishipro-core.js does when the binary is absent. YGOProResourceLoader now resolves the core path through the shared edisonCorePath() so the loader and the verifier can never disagree. * test: relocate ocgcore integration tests to fork and pre-errata repos These 28 tests plus the HeadlessDuel harness exercise the core engine, not server code. They coupled npm test to assembled resources and private pre-errata scripts. Moved 9 engine/MR1 tests to evolution-ygopro-core and 19 pre-errata tests to the private repo. Production CardStorage stays; the harness is vendored into each destination. * chore: ignore local session dir and fetched core artifact The .claude/ session dir and the root ocgcore-worker WASM (fetched via the manifest add-on) are local artifacts and must not be versioned. * docs: move edison roadmap out of the public repo The roadmap is edison pre-errata research; it referenced relocated tests, the removed harness, and the private erratas doc. Preserved in the private repo. * chore(edison): remove damage-step window debug tracer The DUEL_DEBUG_DS_WINDOWS trace was pre-errata research instrumentation. Its purpose left with the relocated damage-step suite; dropped from the server. * refactor(core): rename edisonCore to generic ocgcoreFork The forked ocgcore is the single core the server loads for ALL rooms; its duel_rule gates make it behave like stock in modern formats and apply pre- errata rulings across legacy eras (Edison, GOAT, HAT). Naming it 'edisonCore' wrongly implied it was Edison-only. Renamed module + symbols; env var EDISON_CORE_REQUIRED -> OCGCORE_FORK_REQUIRED (new in this PR, no deployments affected). * refactor(core): collapse ocgcore fork verifier into a logged load decision Removed the separate boot verifier, the sha256 pin, and the OCGCORE_FORK_REQUIRED env var. The fork-vs-stock choice is now a single explicit decision logged at card-load time (resolveForkCorePath): fork present -> use it; absent -> loud warn + stock fallback. Download integrity belongs to the manifest delivery layer, and a corrupt WASM fails loudly at instantiation, so the per-boot sha check was redundant. * chore(docker): drop build-time token machinery; private sources are runtime-only The forked-core seed is assembled public-only at build; the private manifest override is .dockerignored (never in the build context) and mounted at runtime, with the token from the container env. Removes the dead --secret mount, GH_PRIVATE_TOKEN export, and build-time setup-git-credentials call; updates the manifest example + stale comments. * refactor(core): resolve fork-core path once, fix stale runtime comments resolveForkCorePath ran on every card-storage (re)load, re-logging the fork/stock decision each 10-min refresh. Cache it in the loader (logged once); the worker still re-reads the binary per load. Also drop the stale build-time BuildKit-secret mention in setup-git-credentials.sh (runtime-only now). |