--- title: "BDPD v0.6 — Release Notebook" subtitle: "Open Platform: registry refactors, plugin system, onboarding" author: "Roberto Brunelli" date: "2026-05-19" release_tag: "v0.6" release_type: "infrastructural" format: html: toc: true code-fold: true embed-resources: true --- # Overview {#sec-overview} v0.6 is the **Open Platform** release. The platform that was already plug-friendly for *agents* (HTTP, sandboxed JS, middle-man Python) is now plug-friendly for the *world* itself: resource dynamics, perturbations, schedulers, metrics, observation transforms, and victory functions are all registry-based, with auto-discovery from `plugins/`, six worked starter templates, and a conformance runner. Three quickstart guides ("Play with an AI", "Design an experiment", "Extend the engine") cover the three primary persona entry points. This is an **infrastructural** release: no new findings, no new physics, no behavioural change to the simulation. The contract is that all five canonical sweeps from the paper reproduce bit-identically against the v0.5.1 baseline. They do (see [Regression evidence](#sec-regression)). The architectural decisions inside v0.6 were chosen to be *nested-safe* — see `BDPD_ultimate_edition.md` §5 — so that v1.0's nested-arena dispatch does not require rewriting plugin signatures shipped here. # What changed {#sec-what-changed} ## Commits `git log v0.5.1..v0.6 --oneline`, topological order: ``` 18ee44e v0.6-dev: preflight — regression baseline + check_regression.sh 98499a8 v0.6-dev: refactor — PERTURBATION_REGISTRY (registry-based dispatch) 9ffde36 v0.6-dev: feat — provenance manifest MVP 4518230 v0.6-dev: fix — check_regression.sh skips *.manifest.json sidecars 7c8d78d v0.6-dev: feat — release notebook scaffold + figure provenance (v0.6.5 partial) 1d214e0 v0.6-dev: feat — seeded observation noise + P9 in regression (week 3a) acc86af v0.6-dev: feat — METRIC_REGISTRY + VICTORY_REGISTRY + engine context arg (week 3b) c078f5d v0.6-dev: feat — plugin scaffolding + conformance runner + remaining nested-safe (week 4) 908e7ad v0.6-dev: docs — two quickstarts for getting-started (week 4 wrap) 912a919 v0.6-dev: docs — third quickstart "design an experiment" (week 4 wrap) ``` ## High-level diff - **Six registry refactors.** Perturbation, scheduler, metric, victory, observation transform, and engine systems all moved from hardcoded switch/case dispatch to keyed registry tables. Each registry is a plain object that third-party plugins may extend at load time; nothing else in the core needs to know. - **Plugin loader + conformance runner.** `tools/plugin-loader.mjs` auto-discovers `plugins//*.js` at startup; `tools/plugin-check.mjs` validates a plugin against the per-type contract and runs a smoke test (engine: instantiate+step; perturbation: apply to stub arena; metric: compute over fixed wealth array; etc.). - **Six starter plugins** in `examples/plugins//`, one per category, 30–50 lines each. All six pass `plugin-check` for both contract and smoke. - **Nested-safe API decisions (8 of 8).** UUID agent IDs (already in v0.5), optional `context = {}` arg on engine `step`, observation `observe`, and perturbation `apply`; metric `aggregate` composability; perturbation `target` selector; `/api/v1/...` path alias; storage path constant `WORLDS_DATA_DIR`. See the matching table in `BDPD_ultimate_edition.md` §6. - **Three getting-started quickstarts** — [Play with an AI](../getting-started/play-with-an-ai.md), [Design an experiment](../getting-started/design-an-experiment.md), [Extend the engine](../getting-started/extend-the-engine.md). - **Provenance manifest MVP.** Every sweep run writes a `.manifest.json` sibling with content-addressed hashes, the producing git commit, the definition file SHA, and the artifact list. Figure-side provenance is half-wired: PNG tEXt embedding works via `tools/manifest_helper.py register-figure` but must be invoked manually; auto-wiring with `experiments/sweep.py` lands in v0.6.5. # Regression evidence {#sec-regression} Strict regression — bit-identical JSON, after stripping the three non-deterministic fields (`id`, `startedAt`, `finishedAt`) — is the contract that makes the registry refactor trustworthy. v0.6 was developed under that contract from commit `18ee44e` onward. ``` $ tools/check_regression.sh PASS aggressive_fraction PASS adaptive_effectiveness PASS observability_noise PASS perturbation_regen_shock PASS mule_strategy_override OK: 5/5 sweeps match baseline. ``` Per-sweep provenance, all from commit `912a919` (HEAD of `v0.6-dev`, clean working tree): | Sweep | Status | Wall | Manifest hash (truncated) | |------------------------------------|:------:|-------:|:-------------------------------------| | `aggressive_fraction` (P1) | PASS | 0.28s | `sha256:e4e4388a2a38…` | | `adaptive_effectiveness` (P8) | PASS | 0.77s | `sha256:3a4302e04424…` | | `observability_noise` (P9) | PASS | 0.75s | `sha256:0c529d241fb7…` | | `perturbation_regen_shock` (P10) | PASS | 0.45s | `sha256:2ff5e872192e…` | | `mule_strategy_override` (P11) | PASS | 0.55s | `sha256:1fe841ea91ec…` | Run IDs and full hashes live in the corresponding `experiments/results/_2026-05-19T04-55-*.manifest.json` files. P9 (`observability_noise`) joined the strict regression set in week 3a (commit `1d214e0`), once the Gaussian noise generator on the observation transform became RNG-seeded. The definition carries `seed: 42`. P7 (`scheduler_comparison`) remains stochastic and is deliberately excluded — see [Open items deferred](#sec-deferred). # Figures {#sec-figures} Each figure was generated from the corresponding result JSON in the 2026-05-19T04:55:xx batch. The `data-manifest` attribute below carries the producing run's manifest SHA-256; the PNG itself carries `bdpd_run_id`, `bdpd_results_sha256`, and `bdpd_manifest_path` in its tEXt chunk (inspect with `python tools/manifest_helper.py inspect-png `). ![P1 — Aggressive-fraction phase transition.](../../experiments/figures/platform/aggressive_fraction__light_paper.png){#fig-p1 data-manifest="sha256:ed824f45f2b550edc5aa894478460d2f438329177b4764881bee39298eaa8446" data-run-id="835adffc-c05c-4612-8cee-bb502fde0cb9"} ![P8 — Reactive-vs-conservative welfare gap.](../../experiments/figures/platform/adaptive_effectiveness__light_paper.png){#fig-p8 data-manifest="sha256:3a4302e044245184c4c66c2a7b49c2bab094605ac9e6162f7ec709e974609809" data-run-id="91e65953-6353-4ea5-bdc9-91e9e16b212d"} ![P9 — Observability noise as selective blunter.](../../experiments/figures/platform/observability_noise__light_paper.png){#fig-p9 data-manifest="sha256:0c529d241fb7993d46777a93b14fd3725bcbdbba578d410b377abf707cb50813" data-run-id="bfc91767-0e38-4a75-beb4-fe99afa4c585"} ![P10 — Regen shock sweep at turn 20 (Seneca asymmetry).](../../experiments/figures/platform/perturbation_regen_shock__light_paper.png){#fig-p10 data-manifest="sha256:2ff5e872192e31f5ce3159fe5642447a190da05732c2ad59b73a40b23dc69594" data-run-id="1319b6a7-4e94-40f0-af8a-7f4729f18e05"} ![P11 — Mule strategy override (defection timing).](../../experiments/figures/platform/mule_strategy_override__light_paper.png){#fig-p11 data-manifest="sha256:1fe841ea91ecfd81f236fb9eaeb429dd9c2e0a1c4b4cc51f8fb3e758f777e7da" data-run-id="258d7c02-fe34-43bc-bdcf-99ba0f0beb31"} # What didn't change (invariants) {#sec-invariants} v0.6 is back-compatible with v0.5.1 along every user-facing contract. Code written against v0.5.1 runs unchanged. - **HTTP API.** `/api/arenas/...` endpoints, payload shapes, response shapes all unchanged. The new `/api/v1/...` is an alias, not a replacement. - **Public function signatures.** `engine.step(demands, rng)`, `observation.observe(state, observability)`, and `applyPerturbation(arena, spec)` all still accept the original argument list. The new `context = {}` arg is optional and defaults to `{}`. - **Built-in strategies.** `aggressive`, `conservative`, `adaptive`, `rcp`, `random` — bit-identical decisions per turn, verified by the regression set. - **Built-in engines.** `logistic` and `seneca` produce identical trajectories given identical inputs. - **Card game engine** (`agents/cards_ai_play.py`, `sweep_card_tournaments.py`) — not touched in this release. - **Storage layout.** Arena state still lives under `worlds/default/arenas//...`; the path is now exposed as the `WORLDS_DATA_DIR` constant in `registry.js` but the write target is unchanged. - **Experiment definition JSON schema.** Every definition under `experiments/definitions/` runs unchanged; the runner's behaviour on those files is bit-identical. # Open items deferred {#sec-deferred} Tracked for v0.6.5 (provenance follow-on) or v0.7 (Replication Library): - **`scheduler_comparison` (P7) not yet in strict regression.** `SequentialRandom` and `WealthWeighted` schedulers still use `Math.random()` directly. Same fix shape as the v0.6 observation noise plugin: accept an RNG seeded by the arena. Deferred to v0.6.5 or v0.7. - **PNG-side provenance auto-wiring.** `register-figure` works but must be invoked manually. v0.6.5 wires it into `experiments/sweep.py` so figure provenance is automatic when plots are regenerated. - **`audit-paper`, `list-orphans`, `snapshot` subcommands** of `tools/manifest.mjs`. Useful for HAL/Zenodo deposit and orphan detection across `.qmd`. Tracked for v0.6.5. - **Observation transform pipeline.** Marker public, dispatch still hardcoded in `platform/observability.js`. Pipeline-based dispatch lands in v0.7 alongside the noise plugin seeding completion. - **MkDocs site light/dark toggle and README `` swap.** Polish docs items; assets already exist as light/dark pairs. Tracked in `BDPD_ultimate_edition.md` §15 "Decisioni ancora aperte". # How to reproduce {#sec-reproduce} ```bash # 1. Check out the exact code state git checkout v0.6 # 2. Install dependencies ./scripts/setup.sh source venv_py_bdpd/bin/activate # 3. Run the strict regression set (bit-identical contract) tools/check_regression.sh # → expects: OK: 5/5 sweeps match baseline. # 4. Regenerate the canonical figures from the fresh result JSONs for sweep in aggressive_fraction adaptive_effectiveness \ observability_noise perturbation_regen_shock \ mule_strategy_override ; do latest=$(ls -t experiments/results/${sweep}_*.json \ | grep -v manifest | head -1) python3 experiments/sweep.py "$latest" \ --theme light_paper --dpi 300 \ --out experiments/figures/platform done # 5. Re-register each figure into its manifest (PNG tEXt + artifact entry) for sweep in aggressive_fraction adaptive_effectiveness \ observability_noise perturbation_regen_shock \ mule_strategy_override ; do manifest=$(ls -t experiments/results/${sweep}_*.manifest.json | head -1) python3 tools/manifest_helper.py register-figure \ --manifest "$manifest" \ --figure "experiments/figures/platform/${sweep}__light_paper.png" \ --produced-by experiments/sweep.py done # 6. Verify every manifest and every figure for m in experiments/results/*.manifest.json ; do node tools/manifest.mjs verify "$m" || break done for png in experiments/figures/platform/*.png ; do python3 tools/manifest_helper.py verify-figure "$png" 2>/dev/null done ``` The provenance chain runs: code commit `912a919` → definition JSON (`sha256:604359a0…` etc., per sweep) → results JSON (`sha256:2a091c67…` etc., per sweep) → figure PNG with tEXt-embedded `bdpd_results_sha256`. Any link broken at any layer fails the corresponding `verify`. # Citing this release {#sec-citing} ```bibtex @software{bdpd_v0_6, title = {BDPD v0.6 — Open Platform}, author = {Brunelli, Roberto}, year = {2026}, version = {v0.6}, url = {https://gitlab.com/bdpd/bdpd/-/releases/v0.6}, note = {Regression manifest bundle: 5 canonical sweeps from commit 912a919, branch v0.6-dev, clean tree. Per-sweep manifest SHA-256s in §Regression evidence.} } ```