SCML
Supply-chain negotiation arena based on the ANAC Supply Chain Management League OneShot track.
Overview
SCML simulates a supply chain in which autonomous factory-manager agents negotiate contracts to buy and sell goods. The CodeClash arena uses the SCML2024 OneShot world because it focuses on negotiation and profit without requiring long-term production scheduling.
Each CodeClash player edits a restricted SCML decision policy. A round runs multiple independent SCML worlds and scores each player by average profit. The trusted runtime owns the SCML agent object, world state, and validation; submitted code only receives plain observations and returns negotiation intents.
Resources
Implementation
codeclash.arenas.scml.scml.SCMLOneShotArena
SCMLOneShotArena(config: dict, *, tournament_id: str, local_output_dir: Path, keep_containers: bool = False)
Bases: CodeArena
Source code in codeclash/arenas/arena.py
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | |
name
class-attribute
instance-attribute
name: str = 'SCML'
submission
class-attribute
instance-attribute
submission: str = 'scml_agent.py'
description
class-attribute
instance-attribute
description: str = 'SCML OneShot is a supply-chain negotiation simulator based on the ANAC Supply Chain Management League.\n\nYour bot is a Python file named `scml_agent.py` that defines a function named `decide`.\nThe trusted runtime owns the SCML agent object and passes plain decision observations to your code:\n\n def decide(observation):\n return {}\n\nEach round runs several two-process SCML2024 OneShot worlds. Your policy controls trusted SCML\nwrapper agents that negotiate with the other submitted policies to buy and sell goods in a simulated\nsupply chain. The objective is to maximize profit. The arena score is your average SCML score across\nall worlds in the round.\n'
default_args
class-attribute
instance-attribute
default_args: dict = {'sims_per_round': 3, 'n_steps': 10, 'n_lines': 2, 'decision_timeout': 3.0, 'max_policy_errors': 8, 'validation_timeout': 10, 'timeout': 180}
validate_code
validate_code(agent: Player) -> tuple[bool, str | None]
Source code in codeclash/arenas/scml/scml.py
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | |
execute_round
execute_round(agents: list[Player]) -> None
Source code in codeclash/arenas/scml/scml.py
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | |
get_results
get_results(agents: list[Player], round_num: int, stats: RoundStats)
Source code in codeclash/arenas/scml/scml.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | |
Agent Interface
Your bot must be a Python file named scml_agent.py that defines decide(observation).
Return {} or None to use the trusted greedy fallback. A valid starting point is:
def decide(observation):
return {}
For proposal events, return {"offer": [quantity, time, unit_price]}. The runtime validates that
the offer is inside SCML's current issue ranges before sending it to the simulator. For response
events, return {"response": "accept"}, {"response": "reject"}, or {"response": "end"}.
Invalid decisions fall back to the trusted greedy policy and are recorded in round details.
Configuration Example
tournament:
rounds: 1
game:
name: SCML
sims_per_round: 2
n_steps: 5
n_lines: 2
decision_timeout: 3.0
max_policy_errors: 8
validation_timeout: 10
timeout: 240
players:
- agent: dummy
name: alpha
- agent: dummy
name: beta
Scoring
The arena runs sims_per_round independent SCML2024 OneShot worlds. Each world has two supply-chain
process levels; every CodeClash player controls one trusted SCML wrapper agent at each level so the
submitted policies participate in actual buy/sell negotiations. The final per-world player score is
the mean SCML score across that player's controlled agents, and the final CodeClash score is the
average across worlds.
The runner rotates player ordering across simulations to reduce positional bias from factory assignment.
Smoke Test
From the repository root, run the dummy-player example:
uv run codeclash run configs/examples/SCML__dummy__r1__s2.yaml -o /tmp/codeclash-scml-smoke
Use a fresh -o directory when rerunning the smoke check.
Expected shape:
- the command exits with status 0;
- both players pass submission validation;
- stdout includes
In round 0, the winner is ...andIn round 1, the winner is ...; - each round summary contains floating-point average scores for
alphaandbeta; - per-simulation details include
decisions,policy_errors,invalid_decisions,disabled_policies, andpolicy_error_samples; - the output directory contains
metadata.json,game.log,tournament.log, androunds/round_0.tar.gz/rounds/round_1.tar.gz.
A representative metadata.json round contains a scores object with one floating-point SCML
profit score per player:
"scores": {
"alpha": 0.6536304953204003,
"beta": 0.5384855419684607
}
Exact values can change with simulation order and configuration; the smoke check is meant to verify the Docker/runtime adapter path, player-name mapping, and score/log artifact shape.
The exact tournament directory name includes a timestamp, so inspect the metadata with:
find /tmp/codeclash-scml-smoke -maxdepth 3 -name metadata.json -print