---
title: "BDPD v0.9 — Release Notebook"
subtitle: "Governance: cheap talk, pacts, sanctioning — Paper 1 MVP closed"
author: "Roberto Brunelli"
date: "2026-05-28"
release_tag: "v0.9"
release_type: "scientific"
format:
  html:
    toc: true
    code-fold: true
    embed-resources: true
---

# Overview {#sec-overview}

v0.9 is the **Governance** release. It closes the three "*Not
directly implemented*" rows of the Ostrom table from Paper 0 (§4):
pact tracking, cheap-talk surface, sanctioning perturbation. Opened
2026-05-22 on branch `v0.9-dev` from `d63436d`. The Paper 1 MVP
critical path is complete: A1 + A3 + B1 + B3 + C1 + D1, plus D2 + D3
ladder sweeps that anchor the headline finding.

This is a **scientific** release: it introduces a new agent channel
(cheap talk), a new violation tracker (pacts), a new sanction
mechanism (`sanction` perturbation), new metrics
(`cooperation_index`, `lie_score`, `silent_defection`,
`announce_frequency`, `sanction_rate`), and a new
sanctioning-meta-agent class (`SanctionerAgent`,
`VoluntarySanctionerAgent`). Paper 1 is the citable artefact;
v0.9 is the platform underneath it.

# Headline empirical finding (D1) {#sec-d1}

*Pure cheap talk does not solve the cliff.* In a 6-agent canonical
cliff setup (5 conservative + 1 aggressive, K=150, regen=0.12,
threshold=10, 30-turn max), enabling cheap talk for all six LLM
agents (`broadcast`, `send_private`, `announce_intended_harvest`,
`pact_propose`, `pact_accept`) results in **earlier collapse** at
N=5 (mean preservation 0/5 in A, 2/5 in B). The aggressor wins in
wealth (105 vs mean 64) even with cheap talk on, announcements are
honoured (`lie_score ≈ 0`) but communication decays from 8 → 1
messages/turn after T7. This is the Farrell–Rabin negative result
that motivates the Phase B → C transition in Paper 1: sanctioning
is required.

The N=5 sweep also reveals that **`silent_defection`** is the robust
diagnostic for the aggressive archetype: `lie_score` is dead at
honour=100%, but `silent_defection = 0.38 ± 0.07` in cheap-talk
condition vs `0.72` in the mechanically-pinned baseline.

# What changed {#sec-what-changed}

## A — State foundations

- **A1 — PactRegistry** (`platform/pacts.js`). Per-arena pact
  lifecycle: propose / accept / decline / cancel. Term types:
  `harvest_cap`, `commons_floor`, `reciprocity`. Automatic
  violation tracking via `checkViolations()` called by `arena.tick`.
- **A2 — ReputationRegistry** (P1, included). EMA per-player
  cooperation score, exposed via `query_reputation` tool. Mirrored
  in middle-man for prompt observation.
- **A3 — Governance metrics in METRIC_REGISTRY**
  (`engine/metrics.js`). Five entries: `cooperation_index`,
  `lie_score`, `sanction_rate`, `announce_frequency`,
  `silent_defection`. All populated per-turn in
  `turnRecord.governance` by `governanceSnapshot`.

## B — Communication (cheap talk)

- **B1a — MessageBus** (`platform/messages.js`). Append-only,
  recipient-filtered cheap-talk channel with broadcast / private /
  announcement scopes.
- **B1b — Arena action protocol + SDK cheap-talk tools.** Agents
  return `actions[]` alongside `harvest`. SDK exposes `broadcast`,
  `send_private`; inbox surfaced in `buildObservation` with one-turn
  lag.
- **B1c — Pact actions** on both sides. Arena consumes
  `pact_propose` / `pact_accept` / `pact_decline` / `pact_cancel`;
  SDK exposes the same tool surface.
- **B1d — `announce_intended_harvest`** as both a tool and a JSON
  field on the structured response. Empirical finding: agents prefer
  the JSON field over the tool when both exist.
- **B3 — Lie score + announce_frequency + silent_defection bundle.**
  `lie_score` is dead at honour=100%; `silent_defection` is the
  diagnostic for D1.

## C — Mechanisms (sanctioning)

- **C1 — `sanction` perturbation + `pact_violation` trigger**
  (`platform/perturbation.js`). New perturbation type
  (`amount + factor` penalty model) and trigger kind that fires on
  each violation recorded by `PactRegistry`.
- **C3.a — Arena-level governance meta-agent class.** New
  `role: 'meta'` channel on `Arena.addAgent`.
  `SanctionerAgent` (reflexive) and `VoluntarySanctionerAgent`
  (discretion: `triggerStockRatio` + `repeatThreshold`) shipped.

## D — Science

- **D1 — Cliff under active cheap talk** (`scripts/pilot_d1.mjs`).
  Side-by-side 2-cell mini-pilot at the canonical cliff. Output:
  `data/pilot/d1/{cell_A_off,cell_B_on,comparison}.json` + headline
  figure rendered in all three themes.
- **D2 — Graduated ladder** (`scripts/pilot_d2.mjs`). 5-agent Mule
  scenario, ladder `[1, 3, 10]` vs constant `3`. Ladder dominates
  (28 vs 21 turns survival, −50% violations, mule wealth −40%).
  Mechanism: wealth ablation in built-in, not pure deterrence.
- **D3 — Voluntary sanctioner ladder sweep**
  (`scripts/pilot_d3.mjs`). N=5 × 3 ladders (soft `[1,2,4]`,
  canonical `[1,3,10]`, hard `[1,5,25]`). Graduated ladders
  preserve ≥ 4/5 vs flat-5 1/5. Soft preserves 4/5 with mule
  wealth 77.8; hard preserves 5/5 with mule wealth 21.6 (−72%
  deterrence). Pareto trade-off identified.

# Storage and reproducibility {#sec-storage}

- **§5 #8 storage path world-prefix** (commit `36c914c`). Arena
  files now write to `data/worlds/default/arenas/<id>/` instead of
  `data/arenas/<id>/`, honouring nested-safety decision #8.
  `default` is the implicit `world_id`; v1.0 nested-arena dispatch
  populates other worlds without code changes. Idempotent migration
  script ships in `scripts/migrate_storage_world_prefix.mjs`.
- **`max_history` 6/8 → 32** (commit `61d7d62`). DeepSeek
  prompt-cache hit ~89% T1-T9 dropped to ~27% from T10 onwards
  because `deque(maxlen=max_history*2)` evicted earlier turns and
  changed the cache-stable prefix. Default `32` covers 30-turn BDPD
  games without eviction; ~3-4× cheaper input tokens for full-game
  runs.

# Smoke coverage {#sec-smoke}

15 smokes green pre-pilot: 11 Node (`smoke_governance_arena`,
`smoke_messages`, `smoke_pact_actions`, `smoke_pacts`,
`smoke_reputation`, `smoke_action_protocol`, `smoke_b1d1`,
`smoke_b3`, `smoke_c1`, `smoke_world_prefix`, `smoke_b1b2`) + 4
Python. Plus 3 optional DeepSeek pilots (`pilot_c1`, `pilot_d1`,
`smoke_b1d_pilot`).

# References {#sec-refs}

- [Paper 1 — Governance MVP](../publications/paper_01/_site/index.html)
- [Governance meta-agents](../platform/governance.md)
- [Perturbations — `sanction`](../platform/perturbations.md)
- [V0.9_PLAN.md](../dev/V0.9_PLAN.md)
- [Changelog v0.9](../dev/changelog.md)
