Skip to content

Treaties

A Treaty is a cross-arena constraint metadata record stored on a World. Treaties are data: the World does not enforce them at runtime, and the engines do not consult them at all. Instead, treaties are read by world-level meta-agents (C3.b, see Governance) which observe arenas, detect breaches against the treaty payload, and emit sanction perturbations.

This separation is intentional. The treaty payload is the contract; the choice of enforcement (collective vs targeted, immediate vs delayed, deterministic vs probabilistic) is the meta-agent's. The same treaty can be combined with different enforcers without changing either.


Treaty shape

new Treaty({
  name:     'cap_8',          // required, string, monitored by enforcers
  arenaIds: ['a0', 'a1', ],   // required, ≥ 2 signatory arenas
  payload:  { /* opaque */ },  // read by the enforcer meta-agent
  id,                          // optional, auto UUID if omitted
});
Field Type Required Notes
name string yes Treaty enforcers match by name, not by id — one logical treaty per scenario
arenaIds string[] yes (≥ 2) Signatories. removeArena drops any treaty that lost a signatory
payload object no Free-form; structure is a contract between treaty authors and enforcer agents

The Treaty.toJSON() view (used by world.summary() and the REST surface) is { id, name, arenaIds, payload, createdAt }.


Adding a treaty to a world

import { worldRegistry } from './platform/world.js';

const world = worldRegistry.getWorld(worldId);

world.addTreaty({
  name:    'cap_8',
  arenaIds: [a0, a1, a2],
  payload: {
    type:            'harvest_cap_per_arena_per_round',
    perRoundPerArena: 8.0,
  },
});

addTreaty validates that every signatory arena is already in the world; an unknown arenaId is rejected with a clear error. Treaties can be added at any time before or during running.

removeTreaty(treatyId) is the symmetric drop. There is no update — treaties are intentionally immutable once added; replace by remove-then-add if a parameter must change between scenarios.


Payload conventions

v1.0 ships one enforcer (TreatyEnforcerAgent, governance) which understands one payload shape:

payload: {
  type:             'harvest_cap_per_arena_per_round',
  perRoundPerArena: 8.0,
}

For each global round, the enforcer:

  1. Computes the total harvest of each signatory arena that ticked this round (sum of decision.actual across players in the last turn record).
  2. Flags arenas where totalHarvest > perRoundPerArena.
  3. Emits one wealth_shock perturbation spec per flagged arena, targeted via { arenaIds: [aid] }, with payload:
    { reason: 'treaty_breach(<name>: <h> > <cap>)',
      factor: <sanctionFactor>,        // default 0.9
      delta:  <sanctionDelta> | undefined }
    
  4. Collective sanction semantics: the wealth shock hits all members of the offending arena, not the individual high harvesters. The signatory community failed to police itself.

Other payload shapes (per-player caps, multi-round windows, cumulative-stock floors, …) are not shipped in v1.0. The pattern for adding one is:

  1. Define a new payload type string and document it here.
  2. Write a new meta-agent class that recognises that type in its observe() and emits perturbations.
  3. Register it in GOVERNANCE_REGISTRY.

The World itself stays untouched — treaties remain opaque to it.


Lifecycle and removal

A treaty has the same lifecycle as the World it lives in. It is not persisted independently in v1.0; replay reconstructs the treaty from the per-arena JSONL logs if needed.

If removeArena removes one of the signatories, the treaty is dropped automatically so the world invariants stay tight. This means treaty design should generally treat membership as fixed for the run — add the signatory arenas first, then the treaty, then start the world.


What treaties are not

For honest reading of v1.0:

  • Treaties are not pacts. Pacts (platform/pacts.js) are intra-arena, signed by players, and enforced by arena-level sanctioners (C3.a). Treaties are cross-arena, signed by arena IDs (not by players), and enforced by world-level meta-agents (C3.b).
  • Treaties are not hard limits. Agents can still harvest above the cap — the treaty defines what counts as a breach. The enforcer decides what happens after.
  • Treaties are not visible to players. The treaty payload is meta-level information. If a scenario wants players to know about the cap, the prompt template (LLM) or the strategy config (builtin) must surface it explicitly; the World does not broadcast it.

See also

  • World — the layer that holds treaties and runs the enforcement round.
  • Governance — the C3.a / C3.b agent registry and the four meta-strategies shipped in v1.0.
  • Perturbations — the wealth_shock and exclude specs that enforcers emit.