Skip to content

Commit 59bde1b

Browse files
Merge pull request #247 from robocode-dev/ch-031-complete-rumble-client
feat(CH-031): complete Rumble client
2 parents a35ef5a + af10d7d commit 59bde1b

11 files changed

Lines changed: 166 additions & 10 deletions

File tree

.clue/id-ledger.yaml

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
counters:
2-
ADR: "46"
2+
ADR: "47"
33
AN: "1"
44
ARCH: "26"
55
C: "4"
66
CAP: "17"
7-
CH: "30"
7+
CH: "31"
88
G: "1"
99
GTD: "1"
1010
IDR: "4"
1111
LOG: "1"
1212
P: "3"
1313
PDR: "12"
14+
RBC: "4"
15+
RCL: "11"
1416
TNP: "3"
1517
entries:
1618
- id: ADR-001
@@ -243,6 +245,11 @@ entries:
243245
state: live
244246
prefix: ADR
245247
component: "46"
248+
- id: ADR-047
249+
kind: numeric
250+
state: live
251+
prefix: ADR
252+
component: "47"
246253
- id: AN-001
247254
kind: numeric
248255
state: live
@@ -640,6 +647,17 @@ entries:
640647
- id: CH-030-tasks
641648
kind: opaque
642649
state: live
650+
- id: CH-031
651+
kind: numeric
652+
state: live
653+
prefix: CH
654+
component: "31"
655+
- id: CH-031-open-questions
656+
kind: opaque
657+
state: live
658+
- id: CH-031-tasks
659+
kind: opaque
660+
state: live
643661
- id: G-001
644662
kind: numeric
645663
state: live
@@ -750,6 +768,81 @@ entries:
750768
state: live
751769
prefix: PDR
752770
component: "12"
771+
- id: RBC-001
772+
kind: numeric
773+
state: live
774+
prefix: RBC
775+
component: "1"
776+
- id: RBC-002
777+
kind: numeric
778+
state: live
779+
prefix: RBC
780+
component: "2"
781+
- id: RBC-003
782+
kind: numeric
783+
state: live
784+
prefix: RBC
785+
component: "3"
786+
- id: RBC-004
787+
kind: numeric
788+
state: live
789+
prefix: RBC
790+
component: "4"
791+
- id: RCL-001
792+
kind: numeric
793+
state: live
794+
prefix: RCL
795+
component: "1"
796+
- id: RCL-002
797+
kind: numeric
798+
state: live
799+
prefix: RCL
800+
component: "2"
801+
- id: RCL-003
802+
kind: numeric
803+
state: retired
804+
prefix: RCL
805+
component: "3"
806+
- id: RCL-004
807+
kind: numeric
808+
state: live
809+
prefix: RCL
810+
component: "4"
811+
- id: RCL-005
812+
kind: numeric
813+
state: live
814+
prefix: RCL
815+
component: "5"
816+
- id: RCL-006
817+
kind: numeric
818+
state: live
819+
prefix: RCL
820+
component: "6"
821+
- id: RCL-007
822+
kind: numeric
823+
state: live
824+
prefix: RCL
825+
component: "7"
826+
- id: RCL-008
827+
kind: numeric
828+
state: live
829+
prefix: RCL
830+
component: "8"
831+
- id: RCL-009
832+
kind: numeric
833+
state: live
834+
prefix: RCL
835+
component: "9"
836+
- id: RCL-010
837+
kind: numeric
838+
state: live
839+
prefix: RCL
840+
component: "10"
841+
- id: RCL-011
842+
kind: numeric
843+
state: live
844+
prefix: RCL
845+
component: "11"
753846
- id: TNP-001
754847
kind: numeric
755848
state: retired

docs/capabilities/CAP-014-rumble-bot-catalog/criteria.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,12 @@ Feature: rumble-bot-catalog — Rumble bot catalog
3535
When an unregistered account submits that name or an owner changes its source without increasing its version
3636
Then validation rejects the submission
3737
And an approved version increase supersedes the old active version without deleting its historical record
38+
39+
@RBC-004 @draft
40+
Scenario: A TwinDuel team is published with immutable member identities
41+
Test-type: Integration
42+
Given a valid TwinDuel team entry names exactly two active member bots
43+
When the generated catalog is synchronized for ranked clients
44+
Then the team entry carries both member identities in `teamMembers` while individual entries carry an empty list
45+
And generation rejects a missing, inactive, unknown, or nested team member
3846
```

docs/capabilities/CAP-014-rumble-bot-catalog/design.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ The external `rumble-bots` repository is the authoritative source of reviewed bo
1616

1717
`bots/index.json` is generated after accepted changes and is never edited by contributors. Its top-level object contains a positive integer `schemaVersion`, an ISO-8601 `generatedAt` timestamp, the immutable generating Git `commit`, and a `bots` array.
1818

19-
Each bot entry contains `name`, `version`, `platform`, `path`, `sourceHash`, `owner`, `authors`, `addedAt`, and `status`. `sourceHash` uses the `sha256:<hex>` form and covers the source tree that clients run. Only `status: active` entries are eligible for matchmaking; `superseded`, `retired`, and `disqualified` entries remain historical metadata.
19+
Each bot entry contains `name`, `version`, `platform`, `path`, `sourceHash`, `owner`, `authors`, `addedAt`, and `status`. It also contains `teamMembers`, an immutable ordered list of catalog identities written as `name version`; the list is empty for an individual bot and contains exactly two active individual identities for a TwinDuel team. A member identity may occur twice because Battle Runner preserves repeated team slots. `sourceHash` uses the `sha256:<hex>` form and covers the entry's source tree, while the member identities let clients obtain and verify every source tree the team executes. Only `status: active` entries are eligible for matchmaking; `superseded`, `retired`, and `disqualified` entries remain historical metadata.
2020

21-
The catalog schema is additive within a schema version: readers ignore fields they do not understand, while a breaking structural change requires a new `schemaVersion`. A client verifies the source-tree hash after obtaining the cataloged source and must reject a mismatch.
21+
The catalog schema is additive within a schema version: readers ignore fields they do not understand, while a breaking structural change requires a new `schemaVersion`. Readers treat an absent `teamMembers` field as an empty list for compatibility. A client verifies every selected entry's source-tree hash after obtaining the cataloged source and must reject a mismatch.
2222

2323
## External evidence
2424

25-
The external `robocode-dev/rumble-bots` repository holds the implementation and focused integration tests for RBC-001 through RBC-003 at merged commit `c735e6ff4`. Its 4-test suite and `scripts/validate_bot.py --root . --owner flemming-n-larsen --smoke` check pass; during P-001/M-002, those tests will receive their RBC purpose tags and this criteria artifact can become active without changing the criterion meanings.
25+
The external `robocode-dev/rumble-bots` repository holds the implementation and focused integration tests for RBC-001 through RBC-003 at merged commit `c735e6ff4`. [rumble-bots#3](https://github.com/robocode-dev/rumble-bots/pull/3) at `d58e6b5` adds RBC-004 positive and negative evidence for TwinDuel membership, including rejection of malformed catalog entries. Run `python -m unittest discover -s tests -v` and `scripts/validate_bot.py --root . --owner flemming-n-larsen --smoke` in that repository to reproduce the evidence. During P-001/M-002, those tests will receive their RBC purpose tags and this criteria artifact can become active without changing the criterion meanings.

docs/capabilities/CAP-015-rumble-result-data/criteria.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,13 @@ Feature: rumble-result-data — Rumble result data
4343
When a visitor selects a ranked game type
4444
Then the dashboard requests its generated leaderboard projection and links each entry to its generated detail shard
4545
And it does not require a live application backend
46+
47+
@RDA-005 @draft
48+
Scenario: Result eligibility is derived from immutable catalog team membership
49+
Test-type: Integration
50+
Given a supported engine pin and a synchronized catalog containing active individual entries and TwinDuel teams with immutable `teamMembers`
51+
When validation processes a ranked result and aggregation prepares matchmaking advice
52+
Then `1v1` and `melee` admit only the pinned number of distinct active individual entries
53+
And `twinduel` admits exactly two distinct active teams whose catalog members are active individuals, expand to the pinned participant count, and have disjoint member identities
54+
And validation rejects a team in an individual game type, an individual in TwinDuel, or a result whose catalog membership, eligibility, or member disjointness is invalid
4655
```

docs/capabilities/CAP-015-rumble-result-data/design.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ The external `robocode-dev/rumble-data` repository owns result storage and proje
1616

1717
`engine.json` pins a positive `behaviorVersion`, Tank Royale release and image references, and ranked settings for `1v1`, `twinduel`, and `melee`. `catalog.json` is the synchronized published bot catalog; only its active name-and-version entries can occur in ranked results. A contributor is admitted by a reviewed `clients/<forge-account>.json` registration that declares stable client IDs.
1818

19+
For every result, validation resolves each reported entry against the catalog before accepting or aggregating it. `1v1` and `melee` require the engine pin's exact number of distinct active individual entries, identified by an empty `teamMembers` list. `twinduel` requires exactly two distinct active team entries; each must have exactly two active individual catalog members, the teams' expanded members must equal the pinned participant count, and their member-identity sets must be disjoint. A team is ineligible for an individual game type, and an individual is ineligible for TwinDuel. This catalog lookup binds eligibility and membership without changing the result-envelope wire shape.
20+
1921
An issue-ops submission is one fenced JSON batch envelope with `schemaVersion`, `clientId`, `clientVersion`, and one to sixty result records. Each record includes a UUID `battleId`, completion time, matching nested client identity, behavior version, game type, pinned battle dimensions, and the complete Battle Runner participant result model. The validator checks the contract independently for every record, then normalizes valid records with the submitting account and payload hash. A content-addressed JSON file under `results/raw/<year>/<month>/` is the authoritative fact; issue bodies are transport, never state. The workflow publishes successful per-result receipts only after accepted facts reach the canonical repository, and an identical retry of an already retained result receives the same successful outcome.
2022

2123
## Projection and moderation contracts
@@ -26,4 +28,4 @@ CI serializes ingestion and is the sole writer of facts and projections on `main
2628

2729
## External evidence
2830

29-
The external `robocode-dev/rumble-data` repository holds the implementation and focused suite for RDA-001 through RDA-004. [rumble-data#4](https://github.com/robocode-dev/rumble-data/pull/4) added every-ranked-type matchmaking advice and catalog-synchronization coverage and was accepted at merge commit `18e916e4a381c8108568d7ca77e3e14d88dd4583`; M-007 is complete. During P-001/M-002, the external tests will receive purpose tags and this criteria artifact can become active without changing the criterion meanings.
31+
The external `robocode-dev/rumble-data` repository holds the implementation and focused suite for RDA-001 through RDA-004. [rumble-data#4](https://github.com/robocode-dev/rumble-data/pull/4) added every-ranked-type matchmaking advice and catalog-synchronization coverage and was accepted at merge commit `18e916e4a381c8108568d7ca77e3e14d88dd4583`; M-007 is complete. [rumble-data#7](https://github.com/robocode-dev/rumble-data/pull/7) at `83e71d4` adds RDA-005 positive and negative validation and advice-generation evidence, including TwinDuel member disjointness while preserving repeated member slots within a team. Run `python -m unittest discover -s tests -v` in that repository to reproduce the evidence. During P-001/M-002, the external-evidence reconciliation set must include RDA-001 through RDA-005 before this criteria artifact can become active without changing the criterion meanings.

docs/capabilities/CAP-016-rumble-client/criteria.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,30 @@ Feature: rumble-client — Local ranked and practice battle client
2828
Then the client follows the canonical location and accepts one mutually consistent snapshot with supported schemas, an active registered client ID, an immutable catalog commit, and advice for every selected game type
2929
And it refuses ranked execution when a required document is missing, unsupported, inconsistent, or fails its declared source identity
3030
31-
@RCL-003 @draft
31+
@RCL-003 @retired
3232
Scenario: Ranked selection turns published advice into a valid battle
3333
Test-type: Unit
3434
Given a validated snapshot contains active bots and matchmaking advice for `1v1`, `twinduel`, or `melee`
3535
When the client selects a ranked battle with a recorded random seed
3636
Then it selects the pinned number of distinct active participants, preferring advised pairings involving configured own bots before other high-priority advice
3737
And it treats advice as non-exclusive and can select a valid fallback battle when no advised pairing is available
3838
39+
@RCL-010 @draft
40+
Scenario: Ranked selection turns published advice into a valid executable battle
41+
Test-type: Unit
42+
Given a validated snapshot contains active individual bots, active TwinDuel teams with two member slots backed by active individuals, and matchmaking advice
43+
When the client selects a ranked `1v1`, `twinduel`, or `melee` battle with a recorded random seed
44+
Then it selects the pinned number of distinct individual entries or two distinct team entries whose expanded members equal the pinned participant count
45+
And it prefers advised pairings involving configured own entries before selecting a valid seeded fallback
46+
47+
@RCL-011 @draft
48+
Scenario: TwinDuel teams never face a shared member bot
49+
Test-type: Unit
50+
Given a validated snapshot contains active TwinDuel teams with immutable member identities
51+
When the client selects a ranked TwinDuel battle
52+
Then the two selected team entries have disjoint member identities
53+
And it rejects selection when no two teams can satisfy that condition
54+
3955
@RCL-004 @draft
4056
Scenario: Ranked and practice modes cannot mix result state
4157
Test-type: Integration

docs/capabilities/CAP-016-rumble-client/design.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ One versioned configuration selects `ranked` or `practice`, the initial bot and
1818

1919
A ranked session begins from the configured data repository's `wellknown/rumble.json` and follows its canonical location. From one data-repository revision it reads `engine.json`, `catalog.json`, `clients/<forge-account>.json`, and `matchmaking/matches_needed-<game-type>.json` for each selected game type. The client rejects unknown schema versions, an unregistered client ID, unsupported game types, inconsistent projections, or a catalog whose declared source commit cannot identify the reviewed source in [CAP-014](../CAP-014-rumble-bot-catalog/README.md).
2020

21-
The accepted snapshot pins all ranked work in the session. Cached bot source is addressed by the catalog's immutable `sourceCommit` and each entry's `sourceHash`; a hash disagreement rejects the bot before execution. Matchmaking files are advice rather than reservations, so seeded selection may safely fall back to other active catalog participants while preserving the engine pin's participant count.
21+
The accepted snapshot pins all ranked work in the session. Cached bot source is addressed by the catalog's immutable `sourceCommit` and each entry's `sourceHash`; a hash disagreement rejects the bot before execution. Individual entries have no team members. A TwinDuel team entry names exactly two active individual catalog identities in `teamMembers`, preserving repeated member slots, and cache preparation obtains and verifies the team entry plus each referenced member source tree. Matchmaking files are advice rather than reservations, so seeded selection may safely fall back to other eligible entries. `1v1` and `melee` select distinct individuals; `twinduel` selects two distinct team entries whose expanded member count equals the engine pin's participant count and whose member-identity sets are disjoint.
2222

2323
## Execution and mode boundary
2424

@@ -44,4 +44,4 @@ The primary distribution is a rebuildable container containing the pinned Tank R
4444

4545
## External evidence
4646

47-
The external repository records focused evidence for RCL-001 through RCL-009. The accepted configuration implementation at `robocode-dev/rumble-client` commit `d19a90e99649f87664785f1dc20b5aa2f42da7d6` provides initial configuration-loader coverage toward RCL-001; RCL-001 remains incomplete until practice mode accepts configuration without a client identity and integration evidence verifies rejection before side effects. Later CH-012 implementation commits must add the remaining evidence before M-008 can complete. During P-001/M-002, those tests will receive their RCL purpose tags and this criteria artifact can become active without changing the criterion meanings.
47+
[rumble-client#7](https://github.com/robocode-dev/rumble-client/pull/7) at `cec7c8b` holds focused RCL-001, RCL-002, and RCL-004 through RCL-011 evidence; retired RCL-003 has no active evidence obligation. Its tagged integration and unit tests cover configuration before repository access, one validated ranked snapshot, team-aware seeded selection, ranked/practice state separation, Battle Runner execution and replay evidence, durable journaling, and bounded Issues-only submission. Run `./gradlew --no-configuration-cache -PtankRoyaleSource=../tank-royale clean build` in that repository to reproduce the hermetic client and real Runner evidence. RCL-008 and RCL-009 remain deferred by the approved CH-031 split, so P-003/M-008 remains incomplete. During P-001/M-002, the external-evidence reconciliation set must include RCL-010 and RCL-011 before this criteria artifact can become active without changing the criterion meanings.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
id: ADR-047
3+
type: decision
4+
status: verified
5+
links: [CAP-014, CAP-015, CAP-016, ARCH-022, P-003]
6+
title: Rumble catalog publishes immutable team membership
7+
author: agent
8+
accepted-by: Flemming N. Larsen (2026-08-30, Codex conversation)
9+
---
10+
11+
# ADR-047 — Rumble catalog publishes immutable team membership
12+
13+
## Context
14+
15+
The V1 engine pin counts the four bot processes in a TwinDuel battle, while Battle Runner starts two team entries and result ingestion receives two team results. The catalog previously identified only individual entry fields, so a client could not distinguish two valid teams from four unrelated bots before starting untrusted code. ARCH-022 already defines a TwinDuel team as an entry with exactly two `teamMembers`.
16+
17+
## Decision
18+
19+
The generated bot catalog publishes `teamMembers` as immutable catalog identities. Individual entries use an empty list. A TwinDuel team names exactly two active individual entries and preserves repeated member slots, while catalog generation rejects a missing, inactive, unknown, or nested team member. Readers treat an absent field as an empty list for schema-version-one compatibility.
20+
21+
Ranked TwinDuel selection chooses two distinct active team entries and verifies that their expanded member count equals the engine pin. Cache preparation obtains and verifies the team entry and every member source tree before Battle Runner starts them. Individual game types select only entries without team members.
22+
23+
## Consequences
24+
25+
Selection, source preparation, execution identity, and result validation share one explicit team model. Existing individual-only catalogs remain readable, but they cannot satisfy TwinDuel selection until team entries are published.

docs/decisions/IDR-004-rumble-client-battle-runner-dependency.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ CAP-016 requires the Rumble client to execute pinned battles through the Battle
1616

1717
## Decision
1818

19-
During development, `robocode-dev/rumble-client` may consume the merged BR-049 implementation from a local Tank Royale build. Before the client is distributed for ranked use, it pins the first released `dev.robocode.tankroyale:robocode-tank-royale-runner` version that provides the BR-049 behavior-version precondition.
19+
During development, `robocode-dev/rumble-client` may consume the merged BR-049 implementation from a local Tank Royale build. Before the client is distributed for ranked use, it pins the first released `dev.robocode.tankroyale:robocode-tankroyale-runner` version that provides the BR-049 behavior-version precondition.
2020

2121
## Consequences
2222

0 commit comments

Comments
 (0)