API wiring: static feature modules, one clock and per-kind minters, a defined common/, an account/ layer #421

Closed
opened 2026-10-15 13:59:06 +00:00 by root · 21 comments
root commented 2026-10-15 13:59:06 +00:00 (Migrated from gitlab.core-project.space)

Problem Statement

The API's module wiring and its shared folder cost more than they return. The rules that describe them have fallen behind the code:

  • Every feature module is dynamic. One instance of the Auth and Games services is shared by passing configured module objects from one module's forRoot to the next. A new dependency between features therefore changes three signatures, and a module's dependencies cannot be read from its imports.
  • Every service carries its own clock and randomness as constructor options. One app can run several clocks, and tests set each feature's clock separately.
  • The production options type carries test-only seams (the sweep scheduler, the hash cost, per-feature clocks and random sources).
  • common/ has no admission rule. It holds the rate limiter, which only auth uses, and the doorbell, which only the change stream uses. The config folder loads Nest transitively, because it reads the rate-limit defaults from an injectable service file.
  • GuestService holds no state and wraps pure functions. Even so, it justifies a global module.
  • account.me and account.export live in the Games controller and account.delete in the Auth controller, because the layer order puts auth left of games.
  • ADR 0026 still gives the API's layer order as room → rpc. The API standards list four folders where the lint knows seven. ADR 0027 speaks of one flat feature module where there are five.

Source: the NestJS audit, docs/research/nestjs-api-audit.md. Its findings B-11, A-04, A-09, A-11, A-12, B-09, B-10, B-13 and B-19 apply. The owner settled the decisions below in a grilling session (Q1 to Q12).

Solution

  • The rules first. A new ADR takes over the API part of ADR 0026. The API standards are rewritten to match, in one dedicated change the owner asked for.
  • Static feature modules. The root module is the only dynamic module. It provides each feature's options, one shared clock and one minter per kind of identity.
  • A defined common/. It holds what at least two features use and no single feature owns. The rate limiter moves to auth, its defaults to config, and the doorbell to room.
  • Pure Guest functions. They replace GuestService and its global module.
  • An account/ composition layer. It answers every account.* procedure.
  • Test seams by token. Tests replace the clock, a minter, the sweep scheduler or the hash cost by token, so the production options type holds production config only.

Nothing a Player sees changes.

User Stories

  1. As a maintainer, I want an ADR that states the API's wiring, its layer order and what belongs in common/, so that a reader finds the decision without reading the lint config.
  2. As a maintainer, I want ADR 0026 to point to that ADR for the API, so that no ADR states a stale layer order.
  3. As a maintainer, I want the API standards to list the seven folders and which of their files may import Nest, so that review and lint agree.
  4. As a maintainer, I want the rule on non-determinism to name the shared clock and the minters, so that a new service knows where its time and its identities come from.
  5. As a maintainer, I want the testing rule to say that tests replace providers by token, so that nobody adds a test seam to the production options again.
  6. As a maintainer, I want ADR 0027 to stop calling the API one flat feature module, so that it matches the code.
  7. As a maintainer, I want each feature module to declare the modules it imports, so that its dependencies show in one place.
  8. As a maintainer, I want one shared Auth service and one shared Games service without passing module objects by hand, so that adding a dependency between features touches only the module that needs it.
  9. As a maintainer, I want the root module to be the only place where configuration enters the app, so that a new option has one path in.
  10. As a maintainer, I want each feature to define the tokens of its own options, so that the lint's layer order still holds.
  11. As a maintainer, I want the devtools module imported only on stacks that enable devtools, as today, so that ADR 0039 still holds.
  12. As a maintainer, I want the oRPC module imported once, at the root, so that a global module is registered once.
  13. As a maintainer, I want one clock for the whole app, so that Rooms, Sessions, Games and rate limits agree on the time.
  14. As a test author, I want to replace that clock once, so that a scenario cannot drift between two clocks.
  15. As a test author, I want to replace the minter of one kind (Room code, Game id, Guest, secret) without touching the others, so that a forced collision on Game ids leaves Sessions and Guests random.
  16. As a test author, I want to construct the Room and Play services by hand with a clock and minters, so that Room logic stays testable without Nest or a database.
  17. As a test author, I want to override the sweep scheduler and the hash cost by token, so that those seams no longer live in the production options.
  18. As an operator, I want the production options to hold only what a stack configures (secret, URLs, mail, rate limits, database, devtools), so that the config surface is what production reads.
  19. As a maintainer, I want the rate-limit types and defaults in the config folder, so that config and the migration script stop loading Nest.
  20. As a maintainer, I want the rate-limit service in auth, its only client, so that common/ holds only what is shared.
  21. As a maintainer, I want the doorbell in room, beside the change stream that alone uses it, so that common/ holds only what is shared.
  22. As a maintainer, I want minting a Guest, hashing a Guest and comparing two occupants to be plain functions, so that no global module exists for stateless code.
  23. As a maintainer, I want the Guest functions and the occupant types in one framework-free file in common/, so that room, games and the RPC context share them through the layer order.
  24. As a maintainer, I want minting a Guest to go through the Guest minter, so that a test still fixes the minted Guest.
  25. As a maintainer, I want an account/ layer right of games, so that a procedure composing auth and games has a home the lint allows.
  26. As a maintainer, I want account.me, account.export and account.delete answered by one Account controller, so that the account contract lives in one place.
  27. As a maintainer, I want the Account's lifecycle (sign-up, sign-in, deletion, persistence) to stay in auth, so that games can still read and lock Account rows.
  28. As a maintainer, I want guest.claim and guest.get to stay where they are, so that the guest contract does not move with this change.
  29. As a Signed-in Player, I want my Account view, my export and my Account deletion to behave as before, so that the refactor is invisible.
  30. As a Player, I want Rooms, Games and Sessions to behave as before, so that the refactor is invisible.

Seams

  • S1, the wire through the real app (API integration tests, connect() on createApp, requests handed in process). It is extended with token overrides. It covers 7-15, 17-18, 24 and 26-30:

    • the app boots with static modules;
    • one clock override reaches Rooms, Sessions, Games and rate limits;
    • a minter override affects only its kind;
    • the account.* procedures answer as before.

    Existing tests that pass per-feature clocks, games.randomBytes or guests.mintGuest move to overrides.

  • S2, the Room through its services (RoomService and PlayService public methods with the Room fixtures). It covers 16 and 22-24: the constructors take the clock and the Room-code and Guest minters directly, in place of random, now and GuestService.

  • S3, the API lint through its test (the framework-imports lint test). It covers 3, 19-21, 23 and 25:

    • the Guest file and the config folder stay framework-free;
    • the account/ module and controller files may import Nest;
    • the doorbell and the rate-limit service sit at their new paths.

    The layer order itself stays guarded by repo/layer-order.

No e2e seam: nothing changes that a Player can perceive. The pure Guest functions are tested through S1 and S2, not on their own (root rule 27).

Implementation Decisions

  • Rules, as one dedicated change the owner asked for (CLAUDE.md, "No rule edits in feature work"). It lands before any code.
    • A new ADR (0043) states the decision. Feature modules are static. The root module alone is dynamic and provides the options, the clock and the minters. The API layers are common → config → mail → auth → games → account → devtools → room → .. common/ admits what at least two features use and none owns.
    • ADR 0026 keeps the engine; its API line points to the new ADR. Its index row and the new ADR's row follow.
    • ADR 0027's sentence about one flat feature module is corrected.
    • In the API standards:
      • the preamble lists the seven folders and the common/ rule;
      • rule 1 lists the files of auth/, mail/, devtools/ and account/ that may import Nest;
      • rule 2 becomes: the clock and each identity minter are shared providers, and only their default may call Date.now, Math.random or randomBytes;
      • rule 6 adds that tests replace providers by token through createApp's overrides.
  • Module wiring.
    • The Auth, Games, Room, Mail and Database modules become static and declare their imports: Room imports Games, Games imports Auth, Auth imports Mail.
    • A global options module, built by the root module from the app options, provides every feature's option tokens once. Each token stays defined in its feature.
    • The Database module reads its source from a token.
    • The devtools module is static and added to the root's imports only when devtools are enabled.
    • Room's factories that turn Games into its isClaimed and onDecided callbacks stay as they are.
  • Clock and minters.
    • One clock token, defined in common/.
    • One minter per kind of identity, each a provider defined by its owning feature: Room code (room), Game id (games), Guest (common, beside the Guest functions), secret (common, used by auth and games).
    • Each minter's default draws from randomBytes or Math.random. Services inject what they use instead of taking now, random or randomBytes options.
    • The sweep scheduler and the hash cost stay auth options, provided by token.
  • App options and overrides.
    • The app options keep only production configuration: allowed origins, database source, session secret, public URL, mail, rate limits, devtools flag, Mailpit URL, front dist directory.
    • createApp takes an optional second argument, a list of { token, value } pairs applied as provider overrides before the app boots.
    • The test fixture's connect() passes its overrides there.
  • common/ contents.
    • The rate-limit types and defaults move into the config module's file. That avoids a file under 20 lines (root rule 19).
    • The rate-limit service moves to auth, which imports its types from config.
    • The doorbell moves to room.
    • The database files, the schema, the RPC context, the origin middleware, the aborted-stream interceptor, the token hash and the time constants stay.
  • Guest.
    • GuestService and its global module go. A framework-free file in common/ named after Guest holds the occupant types, the occupant of a Guest (its hash) and the comparison of two occupants.
    • Minting a Guest is the Guest minter.
    • The RPC context computes the Guest occupant with the plain function. Its content is unchanged; oRPC itself is out of scope.
    • The Room service takes the Guest minter in place of GuestService.
    • The name Occupant stays as a code type; the glossary is not changed.
  • account/.
    • A new folder, right of games in the layer order, with a module and an Account controller implementing account.me, account.export and account.delete. It injects the Auth and Games services.
    • A service is added only if a procedure composes more than one call per feature.
    • The Games and Auth controllers lose these procedures, and the lint config gains the folder.
  • ADRs touched: 0026 (API part taken over), 0027 (sentence corrected), 0039 (devtools import unchanged), 0041 (rate limiter unchanged, only moved), 0042 and 0035 (Guest and claim behaviour unchanged).

Testing Decisions

  • A good test drives the app through its contract or the Room through its public service methods, and asserts what a caller observes. It never asserts which module provides what.
  • Prior art: test/rpc.fixtures.ts and the RPC integration tests (S1), room.fixtures.ts with the Room tests (S2), and test/framework-imports.lint.test.ts (S3).
  • A moved test may change only how it builds the app or the services, never what it asserts. One exception: the profiles test.
  • The profiles test runs today with a moving Room clock and a fixed Account clock, "so no Session expires mid-test". On one shared clock it keeps its Session alive itself, by refreshing or by moving forward in steps shorter than the access-token lifetime.
  • New cases:
    • one clock override makes a Room's timestamps and a Session's expiry follow the same time;
    • a forced Game-id collision leaves two Guests minted in the same test distinct;
    • account.me, account.export and account.delete answer as before, signed in and signed out;
    • S3 covers each moved file and each new Nest-allowed account/ file, in both directions.

Out of Scope

  • Errors and the app's lifecycle at shutdown (audit findings A-01, A-02, A-03, A-08): the next spec.
  • Domain boundaries in Room and Auth (B-01, B-06, B-07, B-08, A-16): a later grilling.
  • Moving Account persistence or the Account lifecycle out of auth.
  • A guest/ or database/ folder: the owner chose the "shared" rule for common/.
  • Renaming Occupant, or adding it to the glossary.
  • Splitting GamesService (B-04, B-05).
  • oRPC itself: the contract, its implementation and the RPC context's content.

Further Notes

  • The audit and its research files are docs/research/nestjs-api-audit.md, nestjs-practices.md and nestjs-opinion.md. They are not merged yet.

  • Planned tickets, in order:

    1. rules and ADR;
    2. rate limit and doorbell;
    3. pure Guest;
    4. static modules, options, clock and minters;
    5. account/.

    Tickets 2, 3 and 5 depend on 1 only; ticket 4 depends on 3.

## Problem Statement The API's module wiring and its shared folder cost more than they return. The rules that describe them have fallen behind the code: - Every feature module is dynamic. One instance of the Auth and Games services is shared by passing configured module objects from one module's `forRoot` to the next. A new dependency between features therefore changes three signatures, and a module's dependencies cannot be read from its `imports`. - Every service carries its own clock and randomness as constructor options. One app can run several clocks, and tests set each feature's clock separately. - The production options type carries test-only seams (the sweep scheduler, the hash cost, per-feature clocks and random sources). - `common/` has no admission rule. It holds the rate limiter, which only auth uses, and the doorbell, which only the change stream uses. The config folder loads Nest transitively, because it reads the rate-limit defaults from an injectable service file. - `GuestService` holds no state and wraps pure functions. Even so, it justifies a global module. - `account.me` and `account.export` live in the Games controller and `account.delete` in the Auth controller, because the layer order puts auth left of games. - ADR 0026 still gives the API's layer order as `room → rpc`. The API standards list four folders where the lint knows seven. ADR 0027 speaks of one flat feature module where there are five. Source: the NestJS audit, `docs/research/nestjs-api-audit.md`. Its findings B-11, A-04, A-09, A-11, A-12, B-09, B-10, B-13 and B-19 apply. The owner settled the decisions below in a grilling session (Q1 to Q12). ## Solution - **The rules first.** A new ADR takes over the API part of ADR 0026. The API standards are rewritten to match, in one dedicated change the owner asked for. - **Static feature modules.** The root module is the only dynamic module. It provides each feature's options, one shared clock and one minter per kind of identity. - **A defined `common/`.** It holds what at least two features use and no single feature owns. The rate limiter moves to auth, its defaults to config, and the doorbell to room. - **Pure Guest functions.** They replace `GuestService` and its global module. - **An `account/` composition layer.** It answers every `account.*` procedure. - **Test seams by token.** Tests replace the clock, a minter, the sweep scheduler or the hash cost by token, so the production options type holds production config only. Nothing a Player sees changes. ## User Stories 1. As a maintainer, I want an ADR that states the API's wiring, its layer order and what belongs in `common/`, so that a reader finds the decision without reading the lint config. 2. As a maintainer, I want ADR 0026 to point to that ADR for the API, so that no ADR states a stale layer order. 3. As a maintainer, I want the API standards to list the seven folders and which of their files may import Nest, so that review and lint agree. 4. As a maintainer, I want the rule on non-determinism to name the shared clock and the minters, so that a new service knows where its time and its identities come from. 5. As a maintainer, I want the testing rule to say that tests replace providers by token, so that nobody adds a test seam to the production options again. 6. As a maintainer, I want ADR 0027 to stop calling the API one flat feature module, so that it matches the code. 7. As a maintainer, I want each feature module to declare the modules it imports, so that its dependencies show in one place. 8. As a maintainer, I want one shared Auth service and one shared Games service without passing module objects by hand, so that adding a dependency between features touches only the module that needs it. 9. As a maintainer, I want the root module to be the only place where configuration enters the app, so that a new option has one path in. 10. As a maintainer, I want each feature to define the tokens of its own options, so that the lint's layer order still holds. 11. As a maintainer, I want the devtools module imported only on stacks that enable devtools, as today, so that ADR 0039 still holds. 12. As a maintainer, I want the oRPC module imported once, at the root, so that a global module is registered once. 13. As a maintainer, I want one clock for the whole app, so that Rooms, Sessions, Games and rate limits agree on the time. 14. As a test author, I want to replace that clock once, so that a scenario cannot drift between two clocks. 15. As a test author, I want to replace the minter of one kind (Room code, Game id, Guest, secret) without touching the others, so that a forced collision on Game ids leaves Sessions and Guests random. 16. As a test author, I want to construct the Room and Play services by hand with a clock and minters, so that Room logic stays testable without Nest or a database. 17. As a test author, I want to override the sweep scheduler and the hash cost by token, so that those seams no longer live in the production options. 18. As an operator, I want the production options to hold only what a stack configures (secret, URLs, mail, rate limits, database, devtools), so that the config surface is what production reads. 19. As a maintainer, I want the rate-limit types and defaults in the config folder, so that config and the migration script stop loading Nest. 20. As a maintainer, I want the rate-limit service in auth, its only client, so that `common/` holds only what is shared. 21. As a maintainer, I want the doorbell in room, beside the change stream that alone uses it, so that `common/` holds only what is shared. 22. As a maintainer, I want minting a Guest, hashing a Guest and comparing two occupants to be plain functions, so that no global module exists for stateless code. 23. As a maintainer, I want the Guest functions and the occupant types in one framework-free file in `common/`, so that room, games and the RPC context share them through the layer order. 24. As a maintainer, I want minting a Guest to go through the Guest minter, so that a test still fixes the minted Guest. 25. As a maintainer, I want an `account/` layer right of games, so that a procedure composing auth and games has a home the lint allows. 26. As a maintainer, I want `account.me`, `account.export` and `account.delete` answered by one Account controller, so that the `account` contract lives in one place. 27. As a maintainer, I want the Account's lifecycle (sign-up, sign-in, deletion, persistence) to stay in auth, so that games can still read and lock Account rows. 28. As a maintainer, I want `guest.claim` and `guest.get` to stay where they are, so that the `guest` contract does not move with this change. 29. As a Signed-in Player, I want my Account view, my export and my Account deletion to behave as before, so that the refactor is invisible. 30. As a Player, I want Rooms, Games and Sessions to behave as before, so that the refactor is invisible. ## Seams - **S1, the wire through the real app** (API integration tests, `connect()` on `createApp`, requests handed in process). It is extended with token overrides. It covers 7-15, 17-18, 24 and 26-30: - the app boots with static modules; - one clock override reaches Rooms, Sessions, Games and rate limits; - a minter override affects only its kind; - the `account.*` procedures answer as before. Existing tests that pass per-feature clocks, `games.randomBytes` or `guests.mintGuest` move to overrides. - **S2, the Room through its services** (`RoomService` and `PlayService` public methods with the Room fixtures). It covers 16 and 22-24: the constructors take the clock and the Room-code and Guest minters directly, in place of `random`, `now` and `GuestService`. - **S3, the API lint through its test** (the framework-imports lint test). It covers 3, 19-21, 23 and 25: - the Guest file and the config folder stay framework-free; - the `account/` module and controller files may import Nest; - the doorbell and the rate-limit service sit at their new paths. The layer order itself stays guarded by `repo/layer-order`. No e2e seam: nothing changes that a Player can perceive. The pure Guest functions are tested through S1 and S2, not on their own (root rule 27). ## Implementation Decisions - **Rules, as one dedicated change the owner asked for** (`CLAUDE.md`, "No rule edits in feature work"). It lands before any code. - A new ADR (0043) states the decision. Feature modules are static. The root module alone is dynamic and provides the options, the clock and the minters. The API layers are `common → config → mail → auth → games → account → devtools → room → .`. `common/` admits what at least two features use and none owns. - ADR 0026 keeps the engine; its API line points to the new ADR. Its index row and the new ADR's row follow. - ADR 0027's sentence about one flat feature module is corrected. - In the API standards: - the preamble lists the seven folders and the `common/` rule; - rule 1 lists the files of `auth/`, `mail/`, `devtools/` and `account/` that may import Nest; - rule 2 becomes: the clock and each identity minter are shared providers, and only their default may call `Date.now`, `Math.random` or `randomBytes`; - rule 6 adds that tests replace providers by token through `createApp`'s overrides. - **Module wiring.** - The Auth, Games, Room, Mail and Database modules become static and declare their imports: Room imports Games, Games imports Auth, Auth imports Mail. - A global options module, built by the root module from the app options, provides every feature's option tokens once. Each token stays defined in its feature. - The Database module reads its source from a token. - The devtools module is static and added to the root's imports only when devtools are enabled. - Room's factories that turn Games into its `isClaimed` and `onDecided` callbacks stay as they are. - **Clock and minters.** - One clock token, defined in `common/`. - One minter per kind of identity, each a provider defined by its owning feature: Room code (room), Game id (games), Guest (common, beside the Guest functions), secret (common, used by auth and games). - Each minter's default draws from `randomBytes` or `Math.random`. Services inject what they use instead of taking `now`, `random` or `randomBytes` options. - The sweep scheduler and the hash cost stay auth options, provided by token. - **App options and overrides.** - The app options keep only production configuration: allowed origins, database source, session secret, public URL, mail, rate limits, devtools flag, Mailpit URL, front dist directory. - `createApp` takes an optional second argument, a list of `{ token, value }` pairs applied as provider overrides before the app boots. - The test fixture's `connect()` passes its overrides there. - **`common/` contents.** - The rate-limit types and defaults move into the config module's file. That avoids a file under 20 lines (root rule 19). - The rate-limit service moves to auth, which imports its types from config. - The doorbell moves to room. - The database files, the schema, the RPC context, the origin middleware, the aborted-stream interceptor, the token hash and the time constants stay. - **Guest.** - `GuestService` and its global module go. A framework-free file in `common/` named after Guest holds the occupant types, the occupant of a Guest (its hash) and the comparison of two occupants. - Minting a Guest is the Guest minter. - The RPC context computes the Guest occupant with the plain function. Its content is unchanged; oRPC itself is out of scope. - The Room service takes the Guest minter in place of `GuestService`. - The name `Occupant` stays as a code type; the glossary is not changed. - **`account/`.** - A new folder, right of games in the layer order, with a module and an Account controller implementing `account.me`, `account.export` and `account.delete`. It injects the Auth and Games services. - A service is added only if a procedure composes more than one call per feature. - The Games and Auth controllers lose these procedures, and the lint config gains the folder. - **ADRs touched:** 0026 (API part taken over), 0027 (sentence corrected), 0039 (devtools import unchanged), 0041 (rate limiter unchanged, only moved), 0042 and 0035 (Guest and claim behaviour unchanged). ## Testing Decisions - A good test drives the app through its contract or the Room through its public service methods, and asserts what a caller observes. It never asserts which module provides what. - Prior art: `test/rpc.fixtures.ts` and the RPC integration tests (S1), `room.fixtures.ts` with the Room tests (S2), and `test/framework-imports.lint.test.ts` (S3). - A moved test may change only how it builds the app or the services, never what it asserts. One exception: the profiles test. - The profiles test runs today with a moving Room clock and a fixed Account clock, "so no Session expires mid-test". On one shared clock it keeps its Session alive itself, by refreshing or by moving forward in steps shorter than the access-token lifetime. - New cases: - one clock override makes a Room's timestamps and a Session's expiry follow the same time; - a forced Game-id collision leaves two Guests minted in the same test distinct; - `account.me`, `account.export` and `account.delete` answer as before, signed in and signed out; - S3 covers each moved file and each new Nest-allowed `account/` file, in both directions. ## Out of Scope - Errors and the app's lifecycle at shutdown (audit findings A-01, A-02, A-03, A-08): the next spec. - Domain boundaries in Room and Auth (B-01, B-06, B-07, B-08, A-16): a later grilling. - Moving Account persistence or the Account lifecycle out of auth. - A `guest/` or `database/` folder: the owner chose the "shared" rule for `common/`. - Renaming `Occupant`, or adding it to the glossary. - Splitting `GamesService` (B-04, B-05). - oRPC itself: the contract, its implementation and the RPC context's content. ## Further Notes - The audit and its research files are `docs/research/nestjs-api-audit.md`, `nestjs-practices.md` and `nestjs-opinion.md`. They are not merged yet. - Planned tickets, in order: 1. rules and ADR; 2. rate limit and doorbell; 3. pure Guest; 4. static modules, options, clock and minters; 5. `account/`. Tickets 2, 3 and 5 depend on 1 only; ticket 4 depends on 3.
root commented 2026-10-15 14:45:05 +00:00 (Migrated from gitlab.core-project.space)

mentioned in issue #422

mentioned in issue #422
root commented 2026-10-15 14:45:16 +00:00 (Migrated from gitlab.core-project.space)

mentioned in issue #423

mentioned in issue #423
root commented 2026-10-15 14:45:20 +00:00 (Migrated from gitlab.core-project.space)

mentioned in issue #424

mentioned in issue #424
root commented 2026-10-15 14:45:27 +00:00 (Migrated from gitlab.core-project.space)

mentioned in issue #425

mentioned in issue #425
root commented 2026-10-15 14:45:39 +00:00 (Migrated from gitlab.core-project.space)

mentioned in issue #426

mentioned in issue #426
root commented 2026-10-15 14:45:40 +00:00 (Migrated from gitlab.core-project.space)

mentioned in issue #427

mentioned in issue #427
root commented 2026-10-15 14:45:48 +00:00 (Migrated from gitlab.core-project.space)

mentioned in issue #428

mentioned in issue #428
root commented 2026-10-15 14:45:56 +00:00 (Migrated from gitlab.core-project.space)

marked this issue as related to #422

marked this issue as related to #422
root commented 2026-10-15 14:45:57 +00:00 (Migrated from gitlab.core-project.space)

marked this issue as related to #423

marked this issue as related to #423
root commented 2026-10-15 14:45:59 +00:00 (Migrated from gitlab.core-project.space)

marked this issue as related to #424

marked this issue as related to #424
root commented 2026-10-15 14:46:04 +00:00 (Migrated from gitlab.core-project.space)

marked this issue as related to #425

marked this issue as related to #425
root commented 2026-10-15 14:46:08 +00:00 (Migrated from gitlab.core-project.space)

marked this issue as related to #426

marked this issue as related to #426
root commented 2026-10-15 14:46:10 +00:00 (Migrated from gitlab.core-project.space)

marked this issue as related to #427

marked this issue as related to #427
root commented 2026-10-15 14:46:11 +00:00 (Migrated from gitlab.core-project.space)

marked this issue as related to #428

marked this issue as related to #428
root commented 2026-10-15 16:04:32 +00:00 (Migrated from gitlab.core-project.space)

mentioned in commit 7a1f8785f5

mentioned in commit 7a1f8785f5572d00d00e7a6e380ae16942abb9f4
root commented 2026-10-15 16:04:32 +00:00 (Migrated from gitlab.core-project.space)

mentioned in commit f669e0339f

mentioned in commit f669e0339fa90f65a37a6f69066f2efce08edf69
root commented 2026-10-15 16:04:33 +00:00 (Migrated from gitlab.core-project.space)

mentioned in commit 817ef0d477

mentioned in commit 817ef0d477ce9f2b918c2265510cb71c5f3b1ce2
root commented 2026-10-15 16:04:46 +00:00 (Migrated from gitlab.core-project.space)

mentioned in merge request !536

mentioned in merge request !536
root commented 2026-10-15 16:07:36 +00:00 (Migrated from gitlab.core-project.space)

mentioned in commit 52f99ce936

mentioned in commit 52f99ce9365bbd209410809e760b87da27e06744
root commented 2026-10-15 16:07:37 +00:00 (Migrated from gitlab.core-project.space)

mentioned in commit 658857e3cf

mentioned in commit 658857e3cfc0c4f82fb7545d731a810601cd686c
root commented 2026-10-15 16:07:37 +00:00 (Migrated from gitlab.core-project.space)

mentioned in commit 7388250063

mentioned in commit 738825006349a877877653513e35a5317a893245
root (Migrated from gitlab.core-project.space) closed this issue 2026-10-15 18:59:50 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
amaurycoudr/chess-project#421
No description provided.