Commit graph

8 commits

Author SHA1 Message Date
Diango Gavidia
46e353c588
feat(room): join-command overhaul — pairing joins, room identity, edison bots (#319)
* chore(dependencies): update various package versions in package-lock.json

* feat(windbot): playable edison bots and format-scoped random pools

Edison bots join the botlist under short names that fit the utf16[20]
pass field. Botlist entries gain a format tag; random bot selection
resolves a pool from the join tokens (mirroring the room's rule-tier
precedence) so a format room can no longer roll a bot with an illegal
deck. Bot names are validated against the pass-field budget at boot,
and the bot-request failure path delivers its JOINERROR before the
canonical room teardown destroys the sockets.

* feat(ban-list): deterministic alias resolution with load-time format aliases

Format banlists carry an explicit alias captured from their
formats/<dir> path at load time. Alias resolution tries the alias
field, then the exact normalized name, and only then the substring
scan — now tie-broken by shortest normalized name instead of load
order, with a memoized warning on ambiguity. Adds getFirstOCGIndex
so OCG-list tokens stop hardcoding index 0.

* fix(room): rule-mapping clamps, state coherence, and boot-order hardening

The lp clamp compared a NaN (parseInt over the whole token) so lp0
started duels at 0 LP; clamps now act on the extracted number. The
edison rule set is shared between its two tokens. The room's DuelState
label and its state object now always transition together: waiting()
sets both and resets isStart/ready flags, and setDuelFinished disposes
the OCGCore before delegating — the ocgcore-error rewind no longer
leaks the core, lies to the room list, or leaves a stale TRY_START
armed. Missing banlist aliases warn once instead of silently
mislabeling rooms. Windbot bootstrap moved before socket init so a bad
botlist aborts pre-listen, and the never-initialized registry fallback
composes the full base chain.

* feat(room): exact-string pairing joins and (name,password) room identity

Empty-password commands made purely of recognized tokens become
pairing joins: they route to a waiting same-command room with a free
seat, an empty password, and a compatible league — or create a fresh
room. They never land in a dueling or full room. A disconnected
pairing player who re-sends the bare command is first matched as a
legitimate reconnector (same predicate as findReconnectingPlayer)
before the pairing scan runs.

Non-pairing joins now identify a room by the exact (name, password)
pair: a mismatched pair creates its own room instead of rejecting, so
a passwordless pairing room no longer blocks passworded rooms that
share its name. Spectating a room mid-duel with the correct password
is unchanged. docs/join-commands.md is the reference for the whole
command system.
2026-08-10 18:12:12 -04:00
Diango Gavidia
b8bbc32ab6
chore: migrate from ESLint + Prettier to Biome (#283)
* chore(tooling): replace ESLint + Prettier with Biome

- Add biome.json migrated from the ESLint flat config (preset: none,
  drop-in rules) with tab indentation, lineWidth 100, and the
  evolution-types submodule excluded.
- Enable unsafeParameterDecoratorsEnabled for DI/worker param decorators.
- Switch lint/lint:fix scripts and lint-staged to Biome; drop ESLint
  and Prettier devDependencies and their config files.
- Update .editorconfig to tabs and refresh CONTRIBUTING/testing docs.

No source reformatting in this commit.

* style: reformat codebase with Biome (spaces to tabs)

Mass-apply `biome format --write` across src/ and config files.
Indentation converted from 2 spaces to tabs, lineWidth 100, plus
Biome's default trailing commas. No logic changes — build and the
full test suite (704 tests) pass unchanged.

This is a formatting-only commit; see .git-blame-ignore-revs.

* chore: ignore the Biome reformat commit in git blame
2026-06-19 12:23:08 -04:00
Diango Gavidia
d3051549da
test: complete legacy test migration to co-location (groups B–F) (#249)
* test: co-locate message tests and dedupe processors

Group B of the legacy tests/ -> co-location migration (docs/testing.md).

Moves to co-location:
- JoinGameMessage, PlayerInfoMessage -> src/edopro/messages/client-to-server/
- JSONMessageProcessor (comprehensive) -> src/edopro/messages/
- MessageProcessor (comprehensive) -> src/shared/messages/

Dedupe the two test files that lived under tests/modules/message-processor/
and tested the same sources as the edopro/messages ones:
- JSONMessageProcessor: dropped (its 3 synthetic-mechanics cases were already
  covered by the comprehensive suite).
- MessageProcessor: its 3 cases used UNIQUE real wire-format fixtures
  (PLAYER_INFO/CREATE_GAME/RESPONSE/TIME_CONFIRM), merged into the comprehensive
  suite with descriptive titles, then dropped. No coverage lost.

Imports switched to same-dir relative. 501 tests green (was 504; -3 redundant).

* test: co-locate ban-list, client and deck tests

* test: co-locate edopro room tests

* test: co-locate mercury (ygopro) client and room tests

* test: co-locate room, duel, match and rps tests

* test: resolve Match.test.ts collision onto the comprehensive suite

The legacy Match suite (~35 cases) and a co-located 2-case suite (from the
draw-score fix 10551e3c) both tested the same Match source; the 2-case suite
was a strict subset. Keep the comprehensive suite co-located in src/, drop the
2-case file, and fold its only extra assertions (isFinished()===false after a
draw and after a win) into the matching cases. Fix a misleading title:
'should increment both scores when draw occurs' already asserted 0-0, renamed
to 'should NOT increment scores when a draw occurs'. No coverage lost.

* chore: drop emptied tests/ from jest roots and tsconfig

All legacy tests are now co-located under src/, so the root tests/ directory
is gone. Remove its references from jest roots, tsconfig.json exclude and
tsconfig.eslint.json include.

* docs: mark legacy test migration complete in testing conventions
2026-05-27 16:05:22 -04:00
Diango Gavidia
2a94ae1c48
chore: add .editorconfig for 2-space indentation (#247)
Editors apply 2-space indent, LF, UTF-8 and trailing-newline automatically.
Chosen over an eslint indent rule because the CI gates on `npm run lint` and
the eslint config intentionally omits stylistic rules — a global indent rule
would fail CI repo-wide or force a big-bang reformat. .editorconfig guides
without gating. Update docs/testing.md to match and mark completed migration
targets.
2026-05-27 15:02:24 -04:00
Diango Gavidia
c2aac4021a
docs: establish co-located testing conventions (#245)
* docs: establish co-located testing conventions

Add docs/testing.md as the testing standard: co-located tests in src/,
Object Mother for shared domain entities + inline make* factories for
suite-local stubs, shared Mock classes / jest.mock() / mock<T>() for
mocking, English describe/it naming, 2-space indent.

Reconcile AGENTS.md, which previously mandated the opposite (tests/ folder,
always-Mother, Spanish naming) — Prime Directive #1 and SOP-002/004 now
match the co-located reality the suite already drifted to. Link the doc
from CONTRIBUTING.md. Ignore the local .atl/ skill-registry cache.

* docs: remove stale api and node-cpp design docs
2026-05-27 14:23:29 -04:00
Diango Gavidia
7194e3f224
feat(api): add GET /api/rooms endpoint with display-ready DTO (#236) 2026-04-17 11:30:17 -04:00
Diango Gavidia
b5356172f7
feat: instrument Node↔C++ IPC metrics in EDOPro and add reproducible performance benchmarks 2026-02-13 21:17:52 -04:00
Diango Gavidia
c307e231be
feat: harden Node↔C++ IPC flow (backpressure queue, frame draining, safer core IO) (#220)
* docs: compare high-performance IPC protocols and channels

* feat: harden Node-C++ IPC backpressure and stream handling
2026-02-13 19:42:22 -04:00