feat: Guest history, a Guest holds the Seat and owns its decided Games #515

Merged
root merged 64 commits from claude/guest-history-spec-355-385bb1 into main 2026-10-14 09:31:56 +00:00
root commented 2026-10-13 14:34:03 +00:00 (Migrated from gitlab.core-project.space)

Summary

A browser's Guest replaces the Seat token as the only proof of a Seat. Each decided Online game is stored once, owned by the Guest in each Seat, listed in "My games", readable by link and exportable as PGN.

sequenceDiagram
    participant Front
    participant RoomController
    participant PlayService
    participant RoomService
    participant GamesService
    Front->>RoomController: seat.take (x-guest, or none)
    RoomController->>RoomService: arrive → GuestService mints a Guest only when none came
    Front->>RoomController: resignation.submit
    RoomController->>PlayService: resign
    PlayService->>GamesService: onDecided(record), never awaited
    PlayService->>RoomService: fan out the snapshot
    Front->>GamesService: game.list waits on in-flight writes, then reads
 apps/api/src/
 ├── common/
+│   ├── database.service.ts  # global: opens, checks at boot, closes at shutdown, exposes `db`
+│   ├── guest.service.ts     # global: mints a Guest, hashes it (SHA-256), compares occupants
 │   └── rpc-context.ts       # hashes x-guest on arrival through GuestService, no I/O
+├── games/                   # storage, game.list, game.get
 └── room/
-    ├── room.ts              # the framework-free Room (#393)
     ├── room.service.ts      # the place: codes, Seats, Connections, eviction
+    └── play.service.ts      # the Game in it: Moves, Offers, restart, the decided report
 apps/front/src/
 ├── lib/
+│   ├── guest.ts             # one Guest per browser, sent on every call
+│   ├── api-client.ts        # one oRPC client for every vertical
+│   └── copy-link.ts, refusal.ts, rpc.handlers.ts
-├── room/services/seat-token.ts
+└── games/                   # "My games" (/games) and the Game page (/games/$id)
  • Wire: create and take answer { mintedGuest?, snapshot }; a refused take mints nothing. game.get answers you: owner of a Color | reader. RoomOutcome now shares GameEnding (resignation, draw with reason agreed).
  • Schema: migration 20261013144201_decided_games: guests (unique hash), games (a nullable Guest per Color, CHECKs on winner and draw reason, an index per owner column with ended_at).
  • Engine: Game.pgn takes a caller's Result tag; Game.boardEnding() is the one place that reads an ending off the board.

Evidence

  • Before: an ended Online game is gone; a reload holds the Seat through a per-Room Seat token.
    After: the gate is green: lint, typecheck, test (engine, API on the in-process Postgres, front), build and format:check. e2e passes 36/36, including the new my-games.spec.ts:
White and Black play 1. e4 e5; White resigns
  each opens "My games" from the nav → White: "Lost", Black: "Won", both "Resignation"
  White opens the row → /games/<id>
  a stranger context with no Guest opens that link → reads "Resignation" and "1. e4 e5"

Story 12 (read-after-decide) is pinned by holding the database's transactions: the test fails once game.list stops waiting on writes still in flight.

Merge Danger

Door: two-way for the code; the migration only adds tables.

Blast Radius: wire

  • Every browser loses its Seat in Rooms open at deploy time. Rooms live in memory and a redeploy drops them anyway (ADR 0015).
  • RoomOutcome's variants change on the wire. Front and API ship together.
  • A front test, "the Room is read again after a write", flaked twice in CI (pipelines 54, 58) and never reproduced locally or in the CI image. It looks like a stalled runner against a 1 s wait; watch it.

Rule changes

Made here, at the owner's request (#393 and review threads on this MR):

  • apps/api/CODING_STANDARDS.md: the layout paragraph and rules 1, 3 and 6 name RoomService, PlayService, games/, and the global DatabaseService and GuestService in common/. Rule 2 now reads: "only that option's default may call Date.now, Math.random or randomBytes", with no list of services.
  • .oxlintrc.json: import/max-dependencies is off, and its two per-file caps are gone.
  • apps/api/.oxlintrc.json: typescript/parameter-properties allows private readonly; common/*.module.ts and common/*.service.ts may import Nest.
  • docs/adr/README.md: row 0021 points at room.service.ts and game/lib/replay.ts; row 0027 follows the client's move to lib/api-client.ts.
  • Lint config: games/ declared in both apps (with games.controller.ts beside room.controller.ts in the API's errors override); unicorn/no-null moved to room.service.ts.

Proposed, for a dedicated PR (also: the now-unused Optional exception in apps/api/.oxlintrc.json's new-cap):

  1. apps/api/CODING_STANDARDS.md rule 5: "The Guest arrives in the RPC context from the x-guest header, which the context hashes into the caller's occupant; it is never in a procedure's input (ADR 0034). [review]"
  2. apps/e2e/CODING_STANDARDS.md rule 5: "…each Player is a separate browser context, so each holds its own Guest." Rule 7's helper list could name stranger.
  3. packages/contracts/CODING_STANDARDS.md rule 3: "Identifiers (RoomCode, Guest) are branded strings with no format check: an unknown value is a domain answer (ROOM_NOT_FOUND, a Guest with nothing to its name), not a validation error."
  4. apps/front/CODING_STANDARDS.md rule 1 and ADR 0011's list of verticals gain games/.

Closes #355
Closes #372
Closes #373
Closes #374
Closes #375
Closes #376
Closes #377
Closes #393

## Summary A browser's **Guest** replaces the **Seat token** as the only proof of a **Seat**. Each decided **Online game** is stored once, owned by the **Guest** in each **Seat**, listed in "My games", readable by link and exportable as PGN. ```mermaid sequenceDiagram participant Front participant RoomController participant PlayService participant RoomService participant GamesService Front->>RoomController: seat.take (x-guest, or none) RoomController->>RoomService: arrive → GuestService mints a Guest only when none came Front->>RoomController: resignation.submit RoomController->>PlayService: resign PlayService->>GamesService: onDecided(record), never awaited PlayService->>RoomService: fan out the snapshot Front->>GamesService: game.list waits on in-flight writes, then reads ``` ```diff apps/api/src/ ├── common/ +│ ├── database.service.ts # global: opens, checks at boot, closes at shutdown, exposes `db` +│ ├── guest.service.ts # global: mints a Guest, hashes it (SHA-256), compares occupants │ └── rpc-context.ts # hashes x-guest on arrival through GuestService, no I/O +├── games/ # storage, game.list, game.get └── room/ - ├── room.ts # the framework-free Room (#393) ├── room.service.ts # the place: codes, Seats, Connections, eviction + └── play.service.ts # the Game in it: Moves, Offers, restart, the decided report apps/front/src/ ├── lib/ +│ ├── guest.ts # one Guest per browser, sent on every call +│ ├── api-client.ts # one oRPC client for every vertical +│ └── copy-link.ts, refusal.ts, rpc.handlers.ts -├── room/services/seat-token.ts +└── games/ # "My games" (/games) and the Game page (/games/$id) ``` - **Wire:** create and take answer `{ mintedGuest?, snapshot }`; a refused take mints nothing. `game.get` answers `you: owner of a Color | reader`. `RoomOutcome` now shares `GameEnding` (`resignation`, `draw` with reason `agreed`). - **Schema:** migration `20261013144201_decided_games`: `guests` (unique hash), `games` (a nullable Guest per Color, CHECKs on winner and draw reason, an index per owner column with `ended_at`). - **Engine:** `Game.pgn` takes a caller's `Result` tag; `Game.boardEnding()` is the one place that reads an ending off the board. ## Evidence - **Before:** an ended Online game is gone; a reload holds the Seat through a per-Room Seat token. **After:** the gate is green: lint, typecheck, test (engine, API on the in-process Postgres, front), build and format:check. e2e passes 36/36, including the new `my-games.spec.ts`: ```text White and Black play 1. e4 e5; White resigns each opens "My games" from the nav → White: "Lost", Black: "Won", both "Resignation" White opens the row → /games/<id> a stranger context with no Guest opens that link → reads "Resignation" and "1. e4 e5" ``` Story 12 (read-after-decide) is pinned by holding the database's transactions: the test fails once `game.list` stops waiting on writes still in flight. ## Merge Danger **Door:** two-way for the code; the migration only adds tables. **Blast Radius:** wire - Every browser loses its Seat in Rooms open at deploy time. Rooms live in memory and a redeploy drops them anyway (ADR 0015). - `RoomOutcome`'s variants change on the wire. Front and API ship together. - A front test, "the Room is read again after a write", flaked twice in CI (pipelines 54, 58) and never reproduced locally or in the CI image. It looks like a stalled runner against a 1 s wait; watch it. ## Rule changes Made here, at the owner's request (#393 and review threads on this MR): - `apps/api/CODING_STANDARDS.md`: the layout paragraph and rules 1, 3 and 6 name `RoomService`, `PlayService`, `games/`, and the global `DatabaseService` and `GuestService` in `common/`. Rule 2 now reads: "only that option's default may call `Date.now`, `Math.random` or `randomBytes`", with no list of services. - `.oxlintrc.json`: `import/max-dependencies` is off, and its two per-file caps are gone. - `apps/api/.oxlintrc.json`: `typescript/parameter-properties` allows `private readonly`; `common/*.module.ts` and `common/*.service.ts` may import Nest. - `docs/adr/README.md`: row 0021 points at `room.service.ts` and `game/lib/replay.ts`; row 0027 follows the client's move to `lib/api-client.ts`. - Lint config: `games/` declared in both apps (with `games.controller.ts` beside `room.controller.ts` in the API's errors override); `unicorn/no-null` moved to `room.service.ts`. Proposed, for a dedicated PR (also: the now-unused `Optional` exception in `apps/api/.oxlintrc.json`'s `new-cap`): 1. `apps/api/CODING_STANDARDS.md` rule 5: "The Guest arrives in the RPC context from the `x-guest` header, which the context hashes into the caller's occupant; it is never in a procedure's input (ADR 0034). [review]" 2. `apps/e2e/CODING_STANDARDS.md` rule 5: "…each Player is a separate browser context, so each holds its own Guest." Rule 7's helper list could name `stranger`. 3. `packages/contracts/CODING_STANDARDS.md` rule 3: "Identifiers (`RoomCode`, `Guest`) are branded strings with no format check: an unknown value is a domain answer (`ROOM_NOT_FOUND`, a Guest with nothing to its name), not a validation error." 4. `apps/front/CODING_STANDARDS.md` rule 1 and ADR 0011's list of verticals gain `games/`. Closes #355 Closes #372 Closes #373 Closes #374 Closes #375 Closes #376 Closes #377 Closes #393
root commented 2026-10-13 14:51:34 +00:00 (Migrated from gitlab.core-project.space)

added 3 commits

  • f3153324 - feat(contracts): define once how a Game ended, and let the Room's outcome share it
  • 57d73a71 - chore(api): declare the games folder in the layer order and framework-import rules
  • ffe0ddb2 - feat(api): store each decided Online game once, owned by the Guest in each Seat

Compare with previous version

added 3 commits <ul><li>f3153324 - feat(contracts): define once how a Game ended, and let the Room&#39;s outcome share it</li><li>57d73a71 - chore(api): declare the games folder in the layer order and framework-import rules</li><li>ffe0ddb2 - feat(api): store each decided Online game once, owned by the Guest in each Seat</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=77&start_sha=d5b42b7f115b57cf8fbcaef5b4142701b76cc769)
root commented 2026-10-13 15:07:55 +00:00 (Migrated from gitlab.core-project.space)

added 5 commits

  • 10df84db - refactor(api): keep the games module's storage in its service, with no side file
  • 43149e45 - refactor(api): hand a decided Game to an onDecided option, not to a games argument
  • 5adf62ba - feat(contracts): add the game router, listing the caller's Games and reading one by id
  • e9f281c4 - refactor(api): name the oRPC module where the RPC context is typed, for every feature to import
  • e4a70f56 - feat(api): read stored Games over the wire: the caller's list and one Game by id

Compare with previous version

added 5 commits <ul><li>10df84db - refactor(api): keep the games module&#39;s storage in its service, with no side file</li><li>43149e45 - refactor(api): hand a decided Game to an onDecided option, not to a games argument</li><li>5adf62ba - feat(contracts): add the game router, listing the caller&#39;s Games and reading one by id</li><li>e9f281c4 - refactor(api): name the oRPC module where the RPC context is typed, for every feature to import</li><li>e4a70f56 - feat(api): read stored Games over the wire: the caller&#39;s list and one Game by id</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=79&start_sha=ffe0ddb2e112730fda98693fb7974c6b72835f6c)
root commented 2026-10-13 15:22:15 +00:00 (Migrated from gitlab.core-project.space)

added 4 commits

  • c0c83659 - refactor(front): read how a Game ended from the contracts, not a second copy of it
  • 81190c5b - refactor(front): replay the server's line in game/, for every vertical that reads one
  • 536c1b57 - chore(front): declare the games vertical in the per-vertical import rules
  • a47684a9 - feat(front): read a stored Game by its link, oriented to its owner, and copy the link

Compare with previous version

added 4 commits <ul><li>c0c83659 - refactor(front): read how a Game ended from the contracts, not a second copy of it</li><li>81190c5b - refactor(front): replay the server&#39;s line in game/, for every vertical that reads one</li><li>536c1b57 - chore(front): declare the games vertical in the per-vertical import rules</li><li>a47684a9 - feat(front): read a stored Game by its link, oriented to its owner, and copy the link</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=87&start_sha=e4a70f568a567a0d91d7cd4d86e35609b36addff)
root commented 2026-10-13 15:27:10 +00:00 (Migrated from gitlab.core-project.space)

why do we need to import useLocal at each screen ?

why do we need to import useLocal at each screen ?
root commented 2026-10-13 15:27:11 +00:00 (Migrated from gitlab.core-project.space)

should we handle at the loader state the not found case it seems mor tanstack router mind

should we handle at the loader state the not found case it seems mor tanstack router mind
root commented 2026-10-13 15:27:11 +00:00 (Migrated from gitlab.core-project.space)

it seems a bad idea to do that it is not a big issue to load oRPC client not that we add the account featur we will use it every where (we need to do this change at multple place)

it seems a bad idea to do that it is not a big issue to load oRPC client not that we add the account featur we will use it every where (we need to do this change at multple place)
root commented 2026-10-13 15:27:11 +00:00 (Migrated from gitlab.core-project.space)

this could be simplifed

this could be simplifed
root commented 2026-10-13 15:27:12 +00:00 (Migrated from gitlab.core-project.space)

left review comments

left review comments
root commented 2026-10-13 15:28:41 +00:00 (Migrated from gitlab.core-project.space)

added 2 commits

  • 559f1c01 - feat(engine): take the PGN result from the caller for an ending Status cannot express
  • e56f3670 - feat(front): export a stored Game as PGN, its result taken from how it ended

Compare with previous version

added 2 commits <ul><li>559f1c01 - feat(engine): take the PGN result from the caller for an ending Status cannot express</li><li>e56f3670 - feat(front): export a stored Game as PGN, its result taken from how it ended</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=89&start_sha=a47684a92dde0d246eaab5cdcd6c59984183d2a5)
root commented 2026-10-13 15:31:34 +00:00 (Migrated from gitlab.core-project.space)

changed the description

changed the description
root commented 2026-10-13 15:34:34 +00:00 (Migrated from gitlab.core-project.space)

added 4 commits

  • e400720d - refactor(front): name how a decided Game ended in game/, for every reader of it
  • fa03a05c - feat(front): list this browser's decided Games in My games, reachable from the navigation
  • 0629dbca - test(e2e): both Players find a resigned Game in My games, and a stranger reads it by link
  • 97d67ee2 - Merge branch 'claude/guest-history-spec-355-385bb1' into spec-355/376-my-games

Compare with previous version

added 4 commits <ul><li>e400720d - refactor(front): name how a decided Game ended in game/, for every reader of it</li><li>fa03a05c - feat(front): list this browser&#39;s decided Games in My games, reachable from the navigation</li><li>0629dbca - test(e2e): both Players find a resigned Game in My games, and a stranger reads it by link</li><li>97d67ee2 - Merge branch &#39;claude/guest-history-spec-355-385bb1&#39; into spec-355/376-my-games</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=91&start_sha=e56f3670b8637174b68533536b96b93d3ebab55a)
root commented 2026-10-13 15:40:12 +00:00 (Migrated from gitlab.core-project.space)

added 2 commits

  • 762ca9dc - refactor(front): share the copy-link helper between Room and stored Game pages
  • e7e86a79 - refactor(front): read refusal codes in lib and map only Room refusals to Room text

Compare with previous version

added 2 commits <ul><li>762ca9dc - refactor(front): share the copy-link helper between Room and stored Game pages</li><li>e7e86a79 - refactor(front): read refusal codes in lib and map only Room refusals to Room text</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=93&start_sha=97d67ee20711500083c4bcdbec07cb8e841f6960)
root commented 2026-10-13 15:43:30 +00:00 (Migrated from gitlab.core-project.space)

added 3 commits

  • 448e4b87 - refactor(api): fold the Room into RoomService, keyed by Room code
  • d6bf9899 - docs(api): describe the Room living in RoomService
  • 084e96e1 - Merge branch 'claude/guest-history-spec-355-385bb1' into spec-355/393-room-fold

Compare with previous version

added 3 commits <ul><li>448e4b87 - refactor(api): fold the Room into RoomService, keyed by Room code</li><li>d6bf9899 - docs(api): describe the Room living in RoomService</li><li>084e96e1 - Merge branch &#39;claude/guest-history-spec-355-385bb1&#39; into spec-355/393-room-fold</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=95&start_sha=e7e86a79fc22e17a94eda5d778e07bda5a02326b)
root commented 2026-10-13 16:08:30 +00:00 (Migrated from gitlab.core-project.space)

added 2 commits

  • 07d0e617 - refactor(api): split the Game played in a Room into PlayService
  • db5853c5 - docs(api): name RoomService and PlayService in the standards

Compare with previous version

added 2 commits <ul><li>07d0e617 - refactor(api): split the Game played in a Room into PlayService</li><li>db5853c5 - docs(api): name RoomService and PlayService in the standards</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=97&start_sha=084e96e11f26ebae8ee21282ea6cf0cfc0c952b8)
root commented 2026-10-13 16:14:29 +00:00 (Migrated from gitlab.core-project.space)

changed this line in version 10 of the diff

changed this line in [version 10 of the diff](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=98&start_sha=db5853c536fe1588947f9738a469288ca7886059#fd74065e105759b382905bfc813a5a1859664e92_22_20)
root commented 2026-10-13 16:14:29 +00:00 (Migrated from gitlab.core-project.space)

changed this line in version 10 of the diff

changed this line in [version 10 of the diff](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=98&start_sha=db5853c536fe1588947f9738a469288ca7886059#fd74065e105759b382905bfc813a5a1859664e92_17_14)
root commented 2026-10-13 16:14:29 +00:00 (Migrated from gitlab.core-project.space)

changed this line in version 10 of the diff

changed this line in [version 10 of the diff](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=98&start_sha=db5853c536fe1588947f9738a469288ca7886059#fd74065e105759b382905bfc813a5a1859664e92_10_9)
root commented 2026-10-13 16:14:29 +00:00 (Migrated from gitlab.core-project.space)

changed this line in version 10 of the diff

changed this line in [version 10 of the diff](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=98&start_sha=db5853c536fe1588947f9738a469288ca7886059#adb14d00063cca4fc17695bde3d018266cdf5daf_39_52)
root commented 2026-10-13 16:14:30 +00:00 (Migrated from gitlab.core-project.space)

added 6 commits

  • 269a090e - refactor(front): load the oRPC routes with the default code split
  • 0d41f227 - refactor(front): find the caller's Color once in the fake Games server
  • 71bd517b - refactor(front): throw notFound from the Game loader for an unknown Game
  • db2af629 - refactor(front): follow the language from the router, not from each route
  • 1ed89e96 - Merge remote-tracking branch 'origin/claude/guest-history-spec-355-385bb1'...
  • c393b4a8 - refactor(front): hand the unknown Game's notFound back as the Room loader hands its redirect

Compare with previous version

added 6 commits <ul><li>269a090e - refactor(front): load the oRPC routes with the default code split</li><li>0d41f227 - refactor(front): find the caller&#39;s Color once in the fake Games server</li><li>71bd517b - refactor(front): throw notFound from the Game loader for an unknown Game</li><li>db2af629 - refactor(front): follow the language from the router, not from each route</li><li>1ed89e96 - Merge remote-tracking branch &#39;origin/claude/guest-history-spec-355-385bb1&#39;...</li><li>c393b4a8 - refactor(front): hand the unknown Game&#39;s notFound back as the Room loader hands its redirect</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=98&start_sha=db5853c536fe1588947f9738a469288ca7886059)
root commented 2026-10-13 16:14:35 +00:00 (Migrated from gitlab.core-project.space)

Done in 269a090e: codeSplitGroupings and its comment are gone from games.$id.tsx, games.index.tsx and room.$code.tsx, so they use the default split. No test or config pinned it.

Done in 269a090e: `codeSplitGroupings` and its comment are gone from `games.$id.tsx`, `games.index.tsx` and `room.$code.tsx`, so they use the default split. No test or config pinned it.
root commented 2026-10-13 16:14:37 +00:00 (Migrated from gitlab.core-project.space)

Done in 71bd517b and c393b4a8: the loader (ensureGame in games/services/game-query.ts) turns GAME_NOT_FOUND into notFound(), and the route renders notFoundComponent: GameNotFoundView. The query no longer caches a not-found answer, and GamePageView has no match. The not-found tests (unknown id, malformed id, French) moved to app/game-page-route.test.tsx, since the router owns that page now. Type-aware lint rejects throw notFound(), so the error is returned and then thrown, the way enterRoom hands back its redirect.

Done in 71bd517b and c393b4a8: the loader (`ensureGame` in `games/services/game-query.ts`) turns `GAME_NOT_FOUND` into `notFound()`, and the route renders `notFoundComponent: GameNotFoundView`. The query no longer caches a not-found answer, and `GamePageView` has no match. The not-found tests (unknown id, malformed id, French) moved to `app/game-page-route.test.tsx`, since the router owns that page now. Type-aware lint rejects `throw notFound()`, so the error is returned and then thrown, the way `enterRoom` hands back its `redirect`.
root commented 2026-10-13 16:14:39 +00:00 (Migrated from gitlab.core-project.space)

Done in 0d41f227: one heldBy({ owners, guest }) holds the guard (an absent Guest must not match an ownerless side), and viewedBy and listedFor both use it. listedFor also lost its early return.

Done in 0d41f227: one `heldBy({ owners, guest })` holds the guard (an absent Guest must not match an ownerless side), and `viewedBy` and `listedFor` both use it. `listedFor` also lost its early return.
root commented 2026-10-13 17:30:29 +00:00 (Migrated from gitlab.core-project.space)

Tried twice to drive it from the root, and neither works:

  • the root already subscribes (useShownLocale in __root.tsx), but TanStack Router's MatchInner memoizes each route's element on the route's component, so a root re-render stops at <Outlet />;
  • router.invalidate() on a switch reloads the matches but hits the same memo: 8 of 16 language-switch tests stayed red;
  • <Outlet key={locale} /> would work but remounts the page, losing the selection, the review position and the Room's stream;
  • a wrapper patching every route through route.update (db2af629) worked but leans on TanStack internals.

So, as discussed, back to one useLocale() per route part (21e0973c, 179eef15), the /games/$id not-found page included, with the reason in the comment on useLocale in lib/locale.ts.

Tried twice to drive it from the root, and neither works: - the root already subscribes (`useShownLocale` in `__root.tsx`), but TanStack Router's `MatchInner` memoizes each route's element on the route's component, so a root re-render stops at `<Outlet />`; - `router.invalidate()` on a switch reloads the matches but hits the same memo: 8 of 16 language-switch tests stayed red; - `<Outlet key={locale} />` would work but remounts the page, losing the selection, the review position and the Room's stream; - a wrapper patching every route through `route.update` (db2af629) worked but leans on TanStack internals. So, as discussed, back to one `useLocale()` per route part (21e0973c, 179eef15), the `/games/$id` not-found page included, with the reason in the comment on `useLocale` in `lib/locale.ts`.
root commented 2026-10-13 17:30:30 +00:00 (Migrated from gitlab.core-project.space)

resolved all threads

resolved all threads
root commented 2026-10-13 17:30:31 +00:00 (Migrated from gitlab.core-project.space)

added 3 commits

  • 21e0973c - revert: follow the language from each route again, not from the router
  • 179eef15 - fix(front): have the unknown Game's page follow the language too
  • 13c662a0 - test(front): count the Room's streams from once the screen follows it

Compare with previous version

added 3 commits <ul><li>21e0973c - revert: follow the language from each route again, not from the router</li><li>179eef15 - fix(front): have the unknown Game&#39;s page follow the language too</li><li>13c662a0 - test(front): count the Room&#39;s streams from once the screen follows it</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=100&start_sha=c393b4a8949fe8123263541dd64eb208f2e41f29)
root commented 2026-10-13 17:55:07 +00:00 (Migrated from gitlab.core-project.space)

added 12 commits

  • 13c662a0...612b22cb - 2 earlier commits
  • ffe9363e - refactor(front): read the Room's refusal codes without nesting derived types
  • 1855d8cc - refactor(engine): tell the ending a Game's board decided
  • 2eab2914 - refactor(api): read the board's ending from the engine and name each ending by its source
  • 5d55a45e - refactor(front): read the board's ending from the engine
  • 5528fdf0 - refactor(api): have a run inside a Room return only its refusal
  • fbee4321 - refactor(api): name the stored Games' helpers for what they do
  • 12c91d3f - refactor(api): seat a pair through one wire fixture
  • d94acc98 - fix(api): check a Game id's shape through the encoding that mints it
  • 813d0986 - refactor(front): serve both fake servers through one MSW adapter
  • 5bac90bc - refactor(front): derive a Player's result from an ending once

Compare with previous version

added 12 commits <ul><li>13c662a0...612b22cb - 2 earlier commits</li><li>ffe9363e - refactor(front): read the Room&#39;s refusal codes without nesting derived types</li><li>1855d8cc - refactor(engine): tell the ending a Game&#39;s board decided</li><li>2eab2914 - refactor(api): read the board&#39;s ending from the engine and name each ending by its source</li><li>5d55a45e - refactor(front): read the board&#39;s ending from the engine</li><li>5528fdf0 - refactor(api): have a run inside a Room return only its refusal</li><li>fbee4321 - refactor(api): name the stored Games&#39; helpers for what they do</li><li>12c91d3f - refactor(api): seat a pair through one wire fixture</li><li>d94acc98 - fix(api): check a Game id&#39;s shape through the encoding that mints it</li><li>813d0986 - refactor(front): serve both fake servers through one MSW adapter</li><li>5bac90bc - refactor(front): derive a Player&#39;s result from an ending once</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=102&start_sha=13c662a020f5e4cfebee27b57962eb9c2a7fb2e7)
root commented 2026-10-13 17:55:39 +00:00 (Migrated from gitlab.core-project.space)

marked this merge request as ready

marked this merge request as **ready**
root commented 2026-10-13 17:55:39 +00:00 (Migrated from gitlab.core-project.space)

changed the description

changed the description
root commented 2026-10-14 07:52:27 +00:00 (Migrated from gitlab.core-project.space)

added 52 commits

  • 5bac90bc...ef8a7e4e - 4 commits from branch main
  • ef8a7e4e...6e1cb983 - 38 earlier commits
  • 6ba5de11 - refactor(front): read the Room's refusal codes without nesting derived types
  • 99ea300c - refactor(engine): tell the ending a Game's board decided
  • db3c8f1c - refactor(api): read the board's ending from the engine and name each ending by its source
  • 8fb0ac5a - refactor(front): read the board's ending from the engine
  • d9018869 - refactor(api): have a run inside a Room return only its refusal
  • 05795a3b - refactor(api): name the stored Games' helpers for what they do
  • 2f370e3f - refactor(api): seat a pair through one wire fixture
  • 49d4c0e2 - fix(api): check a Game id's shape through the encoding that mints it
  • 2ab3bdc3 - refactor(front): serve both fake servers through one MSW adapter
  • cc48e5be - refactor(front): derive a Player's result from an ending once

Compare with previous version

added 52 commits <ul><li>5bac90bc...ef8a7e4e - 4 commits from branch <code>main</code></li><li>ef8a7e4e...6e1cb983 - 38 earlier commits</li><li>6ba5de11 - refactor(front): read the Room&#39;s refusal codes without nesting derived types</li><li>99ea300c - refactor(engine): tell the ending a Game&#39;s board decided</li><li>db3c8f1c - refactor(api): read the board&#39;s ending from the engine and name each ending by its source</li><li>8fb0ac5a - refactor(front): read the board&#39;s ending from the engine</li><li>d9018869 - refactor(api): have a run inside a Room return only its refusal</li><li>05795a3b - refactor(api): name the stored Games&#39; helpers for what they do</li><li>2f370e3f - refactor(api): seat a pair through one wire fixture</li><li>49d4c0e2 - fix(api): check a Game id&#39;s shape through the encoding that mints it</li><li>2ab3bdc3 - refactor(front): serve both fake servers through one MSW adapter</li><li>cc48e5be - refactor(front): derive a Player&#39;s result from an ending once</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=104&start_sha=5bac90bc5e49de0e4ce014fb93e70081bd5b71ac)
project_1_bot_a8dd9262857d850eef8dca5206e61de5 commented 2026-10-14 07:56:27 +00:00 (Migrated from gitlab.core-project.space)

Screenshots

Before is production, after is this merge request's review app at 548839b.

Desktop

Page Before After
Home
Local game
Room

Mobile

Page Before After
Home
Local game
Room
<!-- chess-screenshots --> ### Screenshots Before is production, after is this merge request's review app at 548839b. #### Desktop | Page | Before | After | | --- | --- | --- | | Home | <img src="https://gitlab.core-project.space/amaurycoudr/chess-project/-/jobs/629/artifacts/raw/review-screenshots/before/home-desktop.png" width="400"> | <img src="https://gitlab.core-project.space/amaurycoudr/chess-project/-/jobs/629/artifacts/raw/review-screenshots/after/home-desktop.png" width="400"> | | Local game | <img src="https://gitlab.core-project.space/amaurycoudr/chess-project/-/jobs/629/artifacts/raw/review-screenshots/before/local-desktop.png" width="400"> | <img src="https://gitlab.core-project.space/amaurycoudr/chess-project/-/jobs/629/artifacts/raw/review-screenshots/after/local-desktop.png" width="400"> | | Room | <img src="https://gitlab.core-project.space/amaurycoudr/chess-project/-/jobs/629/artifacts/raw/review-screenshots/before/room-desktop.png" width="400"> | <img src="https://gitlab.core-project.space/amaurycoudr/chess-project/-/jobs/629/artifacts/raw/review-screenshots/after/room-desktop.png" width="400"> | #### Mobile | Page | Before | After | | --- | --- | --- | | Home | <img src="https://gitlab.core-project.space/amaurycoudr/chess-project/-/jobs/629/artifacts/raw/review-screenshots/before/home-mobile.png" width="200"> | <img src="https://gitlab.core-project.space/amaurycoudr/chess-project/-/jobs/629/artifacts/raw/review-screenshots/after/home-mobile.png" width="200"> | | Local game | <img src="https://gitlab.core-project.space/amaurycoudr/chess-project/-/jobs/629/artifacts/raw/review-screenshots/before/local-mobile.png" width="200"> | <img src="https://gitlab.core-project.space/amaurycoudr/chess-project/-/jobs/629/artifacts/raw/review-screenshots/after/local-mobile.png" width="200"> | | Room | <img src="https://gitlab.core-project.space/amaurycoudr/chess-project/-/jobs/629/artifacts/raw/review-screenshots/before/room-mobile.png" width="200"> | <img src="https://gitlab.core-project.space/amaurycoudr/chess-project/-/jobs/629/artifacts/raw/review-screenshots/after/room-mobile.png" width="200"> |
root commented 2026-10-14 08:10:52 +00:00 (Migrated from gitlab.core-project.space)

je comprned aps pourquoi ce fichier existe ca devrait etre dans un service je pense

je comprned aps pourquoi ce fichier existe ca devrait etre dans un service je pense
root commented 2026-10-14 08:10:52 +00:00 (Migrated from gitlab.core-project.space)

pourquoi le @optional ?

pourquoi le @optional ?
root commented 2026-10-14 08:10:52 +00:00 (Migrated from gitlab.core-project.space)

ca serait sans dout emieux de créer un service non N

ca serait sans dout emieux de créer un service non N
root commented 2026-10-14 08:10:53 +00:00 (Migrated from gitlab.core-project.space)

un point non nest traidtionnnel : normalmeent on defini tout dans le constructor pour un element (le fait qu'il est readonly

je pense qu'on doit abandonner les # pour le privé

un point non nest traidtionnnel : normalmeent on defini tout dans le constructor pour un element (le fait qu'il est readonly je pense qu'on doit abandonner les # pour le privé
root commented 2026-10-14 08:10:53 +00:00 (Migrated from gitlab.core-project.space)

on veut pas defnir des fonction en dehors du service comme ca

on veut pas defnir des fonction en dehors du service comme ca
root commented 2026-10-14 08:10:53 +00:00 (Migrated from gitlab.core-project.space)

je comprens pas ca

je comprens pas ca
root commented 2026-10-14 08:10:53 +00:00 (Migrated from gitlab.core-project.space)

c'est fonciton est etonnante

c'est fonciton est etonnante
root commented 2026-10-14 08:10:53 +00:00 (Migrated from gitlab.core-project.space)

ca parrait compliqué

ca parrait compliqué
root commented 2026-10-14 08:10:54 +00:00 (Migrated from gitlab.core-project.space)

left review comments

left review comments
root commented 2026-10-14 08:40:10 +00:00 (Migrated from gitlab.core-project.space)

changed this file in version 14 of the diff

changed this file in [version 14 of the diff](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=106&start_sha=cc48e5bee704a711e2433d6d1b9d647baf84bd15#3ac54f924d1346ef3edaf459446e9c291704fa30)
root commented 2026-10-14 08:40:11 +00:00 (Migrated from gitlab.core-project.space)

changed this line in version 14 of the diff

changed this line in [version 14 of the diff](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=106&start_sha=cc48e5bee704a711e2433d6d1b9d647baf84bd15#98a810fd403b0adb6a217fc2feb638b71f1387d8_52_52)
root commented 2026-10-14 08:40:11 +00:00 (Migrated from gitlab.core-project.space)

changed this line in version 14 of the diff

changed this line in [version 14 of the diff](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=106&start_sha=cc48e5bee704a711e2433d6d1b9d647baf84bd15#98a810fd403b0adb6a217fc2feb638b71f1387d8_51_52)
root commented 2026-10-14 08:40:11 +00:00 (Migrated from gitlab.core-project.space)

changed this line in version 14 of the diff

changed this line in [version 14 of the diff](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=106&start_sha=cc48e5bee704a711e2433d6d1b9d647baf84bd15#98a810fd403b0adb6a217fc2feb638b71f1387d8_145_154)
root commented 2026-10-14 08:40:11 +00:00 (Migrated from gitlab.core-project.space)

changed this line in version 14 of the diff

changed this line in [version 14 of the diff](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=106&start_sha=cc48e5bee704a711e2433d6d1b9d647baf84bd15#98a810fd403b0adb6a217fc2feb638b71f1387d8_178_164)
root commented 2026-10-14 08:40:12 +00:00 (Migrated from gitlab.core-project.space)

added 8 commits

  • 4fd863ea - refactor(api): own the database in a global DatabaseService
  • 9d3abb08 - refactor(api): require each service's options token
  • 4723cf5e - refactor(api): mark private members with private readonly, not #
  • 0eb73421 - refactor(api): keep the services' helpers inside their classes
  • 5b9be94a - refactor(api): mint and hash Guests in a global GuestService
  • da65949a - refactor(api): forget a stored Game's write with finally
  • 77a90074 - refactor(api): read a stored Game's ending with one match on its row
  • 65358f25 - refactor(api): write a stored Game's ending columns in its insert

Compare with previous version

added 8 commits <ul><li>4fd863ea - refactor(api): own the database in a global DatabaseService</li><li>9d3abb08 - refactor(api): require each service&#39;s options token</li><li>4723cf5e - refactor(api): mark private members with private readonly, not #</li><li>0eb73421 - refactor(api): keep the services&#39; helpers inside their classes</li><li>5b9be94a - refactor(api): mint and hash Guests in a global GuestService</li><li>da65949a - refactor(api): forget a stored Game&#39;s write with finally</li><li>77a90074 - refactor(api): read a stored Game&#39;s ending with one match on its row</li><li>65358f25 - refactor(api): write a stored Game&#39;s ending columns in its insert</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=106&start_sha=cc48e5bee704a711e2433d6d1b9d647baf84bd15)
root commented 2026-10-14 08:40:27 +00:00 (Migrated from gitlab.core-project.space)

Fait dans 5b9be94a : occupant.ts est supprimé. Un GuestService global (common/guest.service.ts) génère le Guest (mint()), le hache (occupantOf()) et compare deux occupants ; il exporte les types Occupant et GuestHash. RoomService l'injecte, et le contexte RPC l'obtient par ORPCModule.forRootAsync({ inject: [GuestService] }), donc le hachage reste fait à l'arrivée, synchrone et sans I/O.

Fait dans 5b9be94a : `occupant.ts` est supprimé. Un `GuestService` global (`common/guest.service.ts`) génère le Guest (`mint()`), le hache (`occupantOf()`) et compare deux occupants ; il exporte les types `Occupant` et `GuestHash`. RoomService l'injecte, et le contexte RPC l'obtient par `ORPCModule.forRootAsync({ inject: [GuestService] })`, donc le hachage reste fait à l'arrivée, synchrone et sans I/O.
root commented 2026-10-14 08:40:32 +00:00 (Migrated from gitlab.core-project.space)

Il ne servait à rien : chaque module fournit toujours son jeton d'options. Supprimé avec les = {} dans 9d3abb08.

Il ne servait à rien : chaque module fournit toujours son jeton d'options. Supprimé avec les `= {}` dans 9d3abb08.
root commented 2026-10-14 08:40:36 +00:00 (Migrated from gitlab.core-project.space)

On a traité le vrai problème : la base n'était pas un service. Dans 4fd863ea, un DatabaseModule global avec un DatabaseService possède le client drizzle : il le vérifie dans onModuleInit (une stack sans base ne devient jamais saine), le ferme dans onApplicationShutdown et expose db. Le symbole DATABASE disparaît, main.ts ne passe plus qu'une URL, et AppModule/GamesModule ne transportent plus la base. Le script de migration garde ses fonctions simples, hors Nest. GamesService reste un service Nest, qui injecte DatabaseService.

On a traité le vrai problème : la base n'était pas un service. Dans 4fd863ea, un `DatabaseModule` global avec un `DatabaseService` possède le client drizzle : il le vérifie dans `onModuleInit` (une stack sans base ne devient jamais saine), le ferme dans `onApplicationShutdown` et expose `db`. Le symbole `DATABASE` disparaît, `main.ts` ne passe plus qu'une URL, et `AppModule`/`GamesModule` ne transportent plus la base. Le script de migration garde ses fonctions simples, hors Nest. GamesService reste un service Nest, qui injecte `DatabaseService`.
root commented 2026-10-14 08:40:40 +00:00 (Migrated from gitlab.core-project.space)

Fait dans 0eb73421 : les helpers des trois services (GamesService, RoomService, PlayService) sont des méthodes privées. Ceux que PlayService importait de room.service.ts (holderOf, lineOf, roomEndingOf, isOver, seatHolding, resolve, endOffer) sont des méthodes publiques de RoomService.

Fait dans 0eb73421 : les helpers des trois services (GamesService, RoomService, PlayService) sont des méthodes privées. Ceux que PlayService importait de room.service.ts (`holderOf`, `lineOf`, `roomEndingOf`, `isOver`, `seatHolding`, `resolve`, `endOffer`) sont des méthodes publiques de RoomService.
root commented 2026-10-14 08:40:45 +00:00 (Migrated from gitlab.core-project.space)

Fait dans 77a90074 : present() est supprimé. Un seul match(row) lit les deux formes valides avec P.nonNullable, et une branche { drawReason: P.nullish }, { winner: P.nullish } lève une erreur pour une ligne qui viole les contraintes de la table.

Fait dans 77a90074 : `present()` est supprimé. Un seul `match(row)` lit les deux formes valides avec `P.nonNullable`, et une branche `{ drawReason: P.nullish }, { winner: P.nullish }` lève une erreur pour une ligne qui viole les contraintes de la table.
root commented 2026-10-14 08:40:49 +00:00 (Migrated from gitlab.core-project.space)

Fait dans 65358f25 : l'insert écrit directement ending, winner et drawReason, sans endingColumns.

Fait dans 65358f25 : l'insert écrit directement `ending`, `winner` et `drawReason`, sans `endingColumns`.
root commented 2026-10-14 08:41:04 +00:00 (Migrated from gitlab.core-project.space)

Fait dans da65949a : #forgetOnceSettled est remplacé par void write.finally(() => this.inFlight.delete(write)). La règle lint promise/prefer-await-to-then refuse .finally, donc la ligne porte un commentaire de désactivation avec sa raison.

Fait dans da65949a : `#forgetOnceSettled` est remplacé par `void write.finally(() => this.inFlight.delete(write))`. La règle lint `promise/prefer-await-to-then` refuse `.finally`, donc la ligne porte un commentaire de désactivation avec sa raison.
root commented 2026-10-14 08:41:08 +00:00 (Migrated from gitlab.core-project.space)

Les # sont remplacés par private readonly dans toute l'API (4723cf5e). Les propriétés déclarées dans le constructeur (constructor(@Inject(X) private readonly x: X)) ne sont pas faites : la règle lint typescript/parameter-properties de la config racine les refuse. Les dépendances restent donc des champs private readonly assignés dans le constructeur. Je laisse ce fil ouvert : on change la règle lint ici, ou dans une PR dédiée ?

Les `#` sont remplacés par `private readonly` dans toute l'API (4723cf5e). Les propriétés déclarées dans le constructeur (`constructor(@Inject(X) private readonly x: X)`) ne sont pas faites : la règle lint `typescript/parameter-properties` de la config racine les refuse. Les dépendances restent donc des champs `private readonly` assignés dans le constructeur. Je laisse ce fil ouvert : on change la règle lint ici, ou dans une PR dédiée ?
root commented 2026-10-14 08:57:05 +00:00 (Migrated from gitlab.core-project.space)

added 1 commit

  • 5e29aaaf - docs(api): state the non-determinism rule without listing services

Compare with previous version

added 1 commit <ul><li>5e29aaaf - docs(api): state the non-determinism rule without listing services</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=108&start_sha=65358f25406d0233852708b5786bfab911afc9c2)
root commented 2026-10-14 09:01:34 +00:00 (Migrated from gitlab.core-project.space)

Fait : typescript/parameter-properties autorise private readonly pour l'API seule (a2ef0718, dans apps/api/.oxlintrc.json), et les dépendances injectées sont maintenant @Inject(X) private readonly x: X (fe98c748). Les objets d'options restent des paramètres simples, puisqu'ils alimentent des valeurs par défaut (options.now ?? Date.now).

Fait : `typescript/parameter-properties` autorise `private readonly` pour l'API seule (a2ef0718, dans `apps/api/.oxlintrc.json`), et les dépendances injectées sont maintenant `@Inject(X) private readonly x: X` (fe98c748). Les objets d'options restent des paramètres simples, puisqu'ils alimentent des valeurs par défaut (`options.now ?? Date.now`).
root commented 2026-10-14 09:01:35 +00:00 (Migrated from gitlab.core-project.space)

resolved all threads

resolved all threads
root commented 2026-10-14 09:01:36 +00:00 (Migrated from gitlab.core-project.space)

added 8 commits

  • a2ef0718 - chore(api): allow private readonly parameter properties
  • fe98c748 - refactor(api): inject Nest dependencies as private readonly parameter properties
  • c3c89696 - chore(repo): drop the import/max-dependencies cap
  • dc67edfb - refactor(api): declare AppOptions back in the app module
  • faecb5ae - refactor(front): render My games from the games harness, beside the Game page
  • e2262bd7 - refactor(front): keep a Player's result from an ending in game-over.ts
  • 237ebbf9 - refactor(api): hash a Guest in the wire fixtures, not a fixture file of its own
  • b6b2172a - Merge remote-tracking branch 'origin/claude/guest-history-spec-355-385bb1' into spec-355/lint-rules

Compare with previous version

added 8 commits <ul><li>a2ef0718 - chore(api): allow private readonly parameter properties</li><li>fe98c748 - refactor(api): inject Nest dependencies as private readonly parameter properties</li><li>c3c89696 - chore(repo): drop the import/max-dependencies cap</li><li>dc67edfb - refactor(api): declare AppOptions back in the app module</li><li>faecb5ae - refactor(front): render My games from the games harness, beside the Game page</li><li>e2262bd7 - refactor(front): keep a Player&#39;s result from an ending in game-over.ts</li><li>237ebbf9 - refactor(api): hash a Guest in the wire fixtures, not a fixture file of its own</li><li>b6b2172a - Merge remote-tracking branch &#39;origin/claude/guest-history-spec-355-385bb1&#39; into spec-355/lint-rules</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=110&start_sha=5e29aaaf5e3dfbc3925e584d2062a003a2d39dbe)
root commented 2026-10-14 09:01:48 +00:00 (Migrated from gitlab.core-project.space)

changed the description

changed the description
root commented 2026-10-14 09:31:49 +00:00 (Migrated from gitlab.core-project.space)

added 68 commits

  • b6b2172a...60724862 - 4 commits from branch main
  • 60724862...81bfc7a1 - 54 earlier commits
  • c8aceba5 - refactor(api): read a stored Game's ending with one match on its row
  • 7fcf6015 - refactor(api): write a stored Game's ending columns in its insert
  • 8dfe0ba4 - chore(api): allow private readonly parameter properties
  • ad3ec9b4 - refactor(api): inject Nest dependencies as private readonly parameter properties
  • 4bfcccbd - chore(repo): drop the import/max-dependencies cap
  • b24f5e8c - refactor(api): declare AppOptions back in the app module
  • e2113736 - refactor(front): render My games from the games harness, beside the Game page
  • c6dffb64 - refactor(front): keep a Player's result from an ending in game-over.ts
  • 9858629e - refactor(api): hash a Guest in the wire fixtures, not a fixture file of its own
  • 548839b7 - docs(api): state the non-determinism rule without listing services

Compare with previous version

added 68 commits <ul><li>b6b2172a...60724862 - 4 commits from branch <code>main</code></li><li>60724862...81bfc7a1 - 54 earlier commits</li><li>c8aceba5 - refactor(api): read a stored Game&#39;s ending with one match on its row</li><li>7fcf6015 - refactor(api): write a stored Game&#39;s ending columns in its insert</li><li>8dfe0ba4 - chore(api): allow private readonly parameter properties</li><li>ad3ec9b4 - refactor(api): inject Nest dependencies as private readonly parameter properties</li><li>4bfcccbd - chore(repo): drop the import/max-dependencies cap</li><li>b24f5e8c - refactor(api): declare AppOptions back in the app module</li><li>e2113736 - refactor(front): render My games from the games harness, beside the Game page</li><li>c6dffb64 - refactor(front): keep a Player&#39;s result from an ending in game-over.ts</li><li>9858629e - refactor(api): hash a Guest in the wire fixtures, not a fixture file of its own</li><li>548839b7 - docs(api): state the non-determinism rule without listing services</li></ul> [Compare with previous version](/amaurycoudr/chess-project/-/merge_requests/15/diffs?diff_id=120&start_sha=b6b2172ad7728fb8eed432907b6bb32b692103ed)
root (Migrated from gitlab.core-project.space) merged commit into main 2026-10-14 09:31:56 +00:00
root commented 2026-10-15 21:19:13 +00:00 (Migrated from gitlab.core-project.space)

mentioned in merge request !537

mentioned in merge request !537
Sign in to join this conversation.
No description provided.