Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 95 additions & 2 deletions .clue/id-ledger.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
counters:
ADR: "46"
ADR: "47"
AN: "1"
ARCH: "26"
C: "4"
CAP: "17"
CH: "30"
CH: "31"
G: "1"
GTD: "1"
IDR: "4"
LOG: "1"
P: "3"
PDR: "12"
RBC: "4"
RCL: "11"
TNP: "3"
entries:
- id: ADR-001
Expand Down Expand Up @@ -243,6 +245,11 @@ entries:
state: live
prefix: ADR
component: "46"
- id: ADR-047
kind: numeric
state: live
prefix: ADR
component: "47"
- id: AN-001
kind: numeric
state: live
Expand Down Expand Up @@ -640,6 +647,17 @@ entries:
- id: CH-030-tasks
kind: opaque
state: live
- id: CH-031
kind: numeric
state: live
prefix: CH
component: "31"
- id: CH-031-open-questions
kind: opaque
state: live
- id: CH-031-tasks
kind: opaque
state: live
- id: G-001
kind: numeric
state: live
Expand Down Expand Up @@ -750,6 +768,81 @@ entries:
state: live
prefix: PDR
component: "12"
- id: RBC-001
kind: numeric
state: live
prefix: RBC
component: "1"
- id: RBC-002
kind: numeric
state: live
prefix: RBC
component: "2"
- id: RBC-003
kind: numeric
state: live
prefix: RBC
component: "3"
- id: RBC-004
kind: numeric
state: live
prefix: RBC
component: "4"
- id: RCL-001
kind: numeric
state: live
prefix: RCL
component: "1"
- id: RCL-002
kind: numeric
state: live
prefix: RCL
component: "2"
- id: RCL-003
kind: numeric
state: retired
prefix: RCL
component: "3"
- id: RCL-004
kind: numeric
state: live
prefix: RCL
component: "4"
- id: RCL-005
kind: numeric
state: live
prefix: RCL
component: "5"
- id: RCL-006
kind: numeric
state: live
prefix: RCL
component: "6"
- id: RCL-007
kind: numeric
state: live
prefix: RCL
component: "7"
- id: RCL-008
kind: numeric
state: live
prefix: RCL
component: "8"
- id: RCL-009
kind: numeric
state: live
prefix: RCL
component: "9"
- id: RCL-010
kind: numeric
state: live
prefix: RCL
component: "10"
- id: RCL-011
kind: numeric
state: live
prefix: RCL
component: "11"
- id: TNP-001
kind: numeric
state: retired
Expand Down
8 changes: 8 additions & 0 deletions docs/capabilities/CAP-014-rumble-bot-catalog/criteria.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,12 @@ Feature: rumble-bot-catalog — Rumble bot catalog
When an unregistered account submits that name or an owner changes its source without increasing its version
Then validation rejects the submission
And an approved version increase supersedes the old active version without deleting its historical record

@RBC-004 @draft
Scenario: A TwinDuel team is published with immutable member identities
Test-type: Integration
Given a valid TwinDuel team entry names exactly two active member bots
When the generated catalog is synchronized for ranked clients
Then the team entry carries both member identities in `teamMembers` while individual entries carry an empty list
And generation rejects a missing, inactive, unknown, or nested team member
```
6 changes: 3 additions & 3 deletions docs/capabilities/CAP-014-rumble-bot-catalog/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ The external `rumble-bots` repository is the authoritative source of reviewed bo

`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.

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.
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.

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.
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.

## External evidence

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.
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.
9 changes: 9 additions & 0 deletions docs/capabilities/CAP-015-rumble-result-data/criteria.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,13 @@ Feature: rumble-result-data — Rumble result data
When a visitor selects a ranked game type
Then the dashboard requests its generated leaderboard projection and links each entry to its generated detail shard
And it does not require a live application backend

@RDA-005 @draft
Scenario: Result eligibility is derived from immutable catalog team membership
Test-type: Integration
Given a supported engine pin and a synchronized catalog containing active individual entries and TwinDuel teams with immutable `teamMembers`
When validation processes a ranked result and aggregation prepares matchmaking advice
Then `1v1` and `melee` admit only the pinned number of distinct active individual entries
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
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
```
4 changes: 3 additions & 1 deletion docs/capabilities/CAP-015-rumble-result-data/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ The external `robocode-dev/rumble-data` repository owns result storage and proje

`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.

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.

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.

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

## External evidence

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.
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.
18 changes: 17 additions & 1 deletion docs/capabilities/CAP-016-rumble-client/criteria.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,30 @@ Feature: rumble-client — Local ranked and practice battle client
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
And it refuses ranked execution when a required document is missing, unsupported, inconsistent, or fails its declared source identity

@RCL-003 @draft
@RCL-003 @retired
Scenario: Ranked selection turns published advice into a valid battle
Test-type: Unit
Given a validated snapshot contains active bots and matchmaking advice for `1v1`, `twinduel`, or `melee`
When the client selects a ranked battle with a recorded random seed
Then it selects the pinned number of distinct active participants, preferring advised pairings involving configured own bots before other high-priority advice
And it treats advice as non-exclusive and can select a valid fallback battle when no advised pairing is available

@RCL-010 @draft
Scenario: Ranked selection turns published advice into a valid executable battle
Test-type: Unit
Given a validated snapshot contains active individual bots, active TwinDuel teams with two member slots backed by active individuals, and matchmaking advice
When the client selects a ranked `1v1`, `twinduel`, or `melee` battle with a recorded random seed
Then it selects the pinned number of distinct individual entries or two distinct team entries whose expanded members equal the pinned participant count
And it prefers advised pairings involving configured own entries before selecting a valid seeded fallback

@RCL-011 @draft
Scenario: TwinDuel teams never face a shared member bot
Test-type: Unit
Given a validated snapshot contains active TwinDuel teams with immutable member identities
When the client selects a ranked TwinDuel battle
Then the two selected team entries have disjoint member identities
And it rejects selection when no two teams can satisfy that condition

@RCL-004 @draft
Scenario: Ranked and practice modes cannot mix result state
Test-type: Integration
Expand Down
4 changes: 2 additions & 2 deletions docs/capabilities/CAP-016-rumble-client/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ One versioned configuration selects `ranked` or `practice`, the initial bot and

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).

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.
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.

## Execution and mode boundary

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

## External evidence

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.
[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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
id: ADR-047
type: decision
status: verified
links: [CAP-014, CAP-015, CAP-016, ARCH-022, P-003]
title: Rumble catalog publishes immutable team membership
author: agent
accepted-by: Flemming N. Larsen (2026-08-30, Codex conversation)
---

# ADR-047 — Rumble catalog publishes immutable team membership

## Context

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`.

## Decision

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.

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.

## Consequences

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.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ CAP-016 requires the Rumble client to execute pinned battles through the Battle

## Decision

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.
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.

## Consequences

Expand Down
Loading
Loading