Skip to content

Observability

The BDPD Platform's observability layer intercepts the raw game state before it is passed to any agent, applying per-variable transformations that degrade, bucket, or suppress information. Agents never receive ground-truth state unless explicitly configured to do so.


Configuration Model

Each observable variable has three independent controls:

Control Type Effect
visible boolean If false, the variable is set to null — agents see nothing
noise float Gaussian noise standard deviation as a fraction of the true value (0 = exact)
resolution "exact" | "bucket" | "sign" How the (noisy) value is discretised before delivery

The observability config is fixed at arena creation and is part of the arena's public description — agents know what they can and can't see, but cannot infer the exact values of hidden or noisy variables.


Observable Variables

Variable Default Visibility Description
commonsStock Visible Current resource stock \(S_t\)
commonsRatio Visible \(S_t / K\) (0–1)
regenRate Hidden Regeneration rate \(r\)
nPlayers Visible Number of agents in the arena
othersWealth Visible Wealth \(w_{i,t}\) of each opponent
othersHarvest Visible Last turn's harvest of each opponent
capitalStock (Seneca) Hidden Capital \(C_t\) (Seneca mode only)
pollutionLevel (Seneca) Hidden Pollution \(P_t\) (Seneca mode only)

Per-Player and Governance Fields

Beyond the commons variables above, the observation object delivered to each agent includes per-player state and (when enabled) governance fields. These are not subject to the noise/resolution pipeline — they are passed through as-is.

Field Since Description
myWealth v0.4 The agent's own current wealth
myLastHarvest v0.4 The agent's harvest from the previous turn
inbox v0.9 Cheap-talk messages addressed to this agent since the last turn (array of { fromId, text, turn })
pacts v0.9 Active pacts visible to this agent (terms, acceptances, violations) via PactRegistry.viewFor(playerId)
reputation v0.9 Compact list of other players' reputation records (violation counts, honour rate); attached only when the arena has a governance layer

inbox, pacts, and reputation are omitted entirely when the arena has no governance configuration — pre-v0.9 arenas and experiments without pacts never see these fields.


Gaussian Noise

Noise is applied fresh each tick using the Box-Muller transform — agents cannot trivially average out the noise because the seed changes every call.

\[\text{observed} = \text{true} + \mathcal{N}(0, \sigma \times \text{true})\]

where \(\sigma\) is the noise fraction (e.g. 0.1 = ±10% standard deviation).

noise Effect
0.0 Exact value (no noise)
0.1 ±10% standard deviation: agent sees "82" when stock is 90
0.2 ±20%: agent sees "108" when stock is 90
0.5 ±50%: highly uncertain estimate

Resolution Modes

After noise is applied, the value is discretised according to the resolution setting:

exact

The full numeric value (post-noise), rounded to 3 decimal places.

commonsStock: 87.312

bucket

Mapped to qualitative labels based on position within [min, max]:

Fraction Label (3 buckets) Label (N buckets)
0.00–0.33 low 0
0.33–0.67 medium 1
0.67–1.00 high N-1
commonsStock: "medium"

sign

Only the direction of change relative to the last observation is revealed:

Change Returned
Positive 1
Zero 0
Negative -1
commonsStock: 1    (stock increased since last observation)

Per-Variable Configuration

{
  "observability": {
    "commonsStock": {
      "visible": true,
      "noise": 0.05,
      "resolution": "exact"
    },
    "regenRate": {
      "visible": false
    },
    "othersWealth": {
      "visible": true,
      "noise": 0.1,
      "resolution": "bucket"
    },
    "othersHarvest": {
      "visible": true,
      "noise": 0.0,
      "resolution": "exact"
    }
  }
}

Why hide regenRate by default?

Regen rate is hidden because real-world CPR users rarely know the exact regeneration function of their resource. Making it visible would enable agents to precisely compute sustainable yield — an unrealistic capability in practice.


Transform Pipeline

Under the hood, each variable's noise and resolution settings are compiled into a transform pipeline — an ordered list of small functions that the value flows through before reaching the agent.

The two built-in transforms are:

Transform Spec Field Pipeline Entry
gaussian_noise noise: 0.1 { kind: 'gaussian_noise', std_fraction: 0.1 }
resolution resolution: 'bucket' { kind: 'resolution', mode: 'bucket' }

Legacy syntax (noise, resolution as top-level fields) is translated automatically; explicit transforms: [...] lists are appended after the legacy entries, so adding a transforms list extends the pipeline rather than replacing it.

Example: combined legacy + explicit pipeline

{
  "commonsStock": {
    "visible": true,
    "noise": 0.5,
    "transforms": [
      { "kind": "clamp", "min": 0 }
    ]
  }
}

This compiles to: gaussian_noise(σ=0.5)clamp(min=0). The noisy value is clipped to non-negative before reaching the agent.

Plugin transforms

Plugins can register new transform types by adding entries to OBSERVATION_TRANSFORM_REGISTRY at load time. The plugin loader (tools/plugin-loader.mjs) handles this automatically for any file in plugins/observation_transforms/.

Transform signature:

(value, params, ctx) => transformedValue

where params is the transform's spec object and ctx contains runtime context ({ rng, min, max, ... }). An unknown kind in a pipeline throws at runtime — typos fail loudly.

A working example is at examples/plugins/observation_transforms/clamp.js.


Impact on Agent Behaviour

The P9 experiment systematically swept observability noise on the commons stock from 0% to 100% and measured welfare and Gini:

Noise Level Welfare Gini Interpretation
0% (perfect) Lower Higher Aggressive agents time extraction precisely against exact stock
35–50% Welfare-optimal Lower Noise limits precision of aggressive timing without crippling conservative decisions
50%+ Lower Higher All agents become effectively random — no strategic differentiation

Key finding: Some information degradation is collectively beneficial. Moderate-to-high noise (35–50%) limits the precision with which aggressive agents can time extraction, improving aggregate welfare. This is a computational demonstration of the "veil of ignorance" principle: when the most aggressive player cannot see the exact stock, the commons survives longer.

In the card game (CT3), observability noise had zero effect on heuristic agents — confirming that noise matters only when agents possess the cognitive architecture to exploit precise numerical signals. The dual-mode result (noise matters on one substrate, not the other) is itself a finding about the role of cognitive architecture.


Resolution and the Architecture of Agent Cognition

The resolution parameter operationalises a specific hypothesis: does the grain of information matter as much as its accuracy?

  • exact resolution enables agents that can compute precise marginal utilities (built-in heuristics, LLMs with numerical reasoning)
  • bucket resolution forces agents to reason in qualitative categories — closer to how humans perceive resource levels in practice
  • sign resolution provides only directional signals — the most degraded information regime

The interaction between resolution mode and agent type is a promising avenue for future experimental work with human subjects and LLM agents.