Skip to content

Player records and outcomes

Interactive execution writes one player-record Parquet file per role and session. Player-record format version 3 is the current contract. Format version 2 belongs to v1 tooling and is rejected.

Filename and atomic write

The recorder writes:

Filename pattern
experiment-<attempt-name>-<player-uuid>.parquet

It first writes a sibling <filename>.tmp, then atomically renames it. A remaining .parquet.tmp file is an interrupted write and is not completion evidence. The recorder does not write a file for a player with no step rows.

Step rows

ExperimentStep pydantic-model

Bases: DuckDBSchemaMixin

Record of one step in the experiment.

Attributes

step instance-attribute

step: int

One-based counter within one player record, including reflection rows.

timestamp instance-attribute

timestamp: float

Seconds from the shared experiment start to the beginning of output dispatch.

role instance-attribute

role: PlayerRole

session_id instance-attribute

session_id: UUID4

Execution identifier used to join rows recorded by different players.

player_uuid instance-attribute

player_uuid: UUID4

player_name instance-attribute

player_name: str

output instance-attribute

Parsed player action dispatched for this step.

raw_output instance-attribute

raw_output: str | None

Unparsed model response retained by parsing or recovery.

thoughts class-attribute instance-attribute

thoughts: str | None = None

Reasoning text extracted separately from the player action.

input_messages class-attribute instance-attribute

input_messages: ModelMessagesList = Field(default_factory=list)

Prior conversation rendered as message history before the current model call.

new_messages class-attribute instance-attribute

new_messages: ModelMessagesList = Field(default_factory=list)

Request and response messages added by the current model call.

bomb_state instance-attribute

bomb_state: BombState | None

observation instance-attribute

observation: Observation | Path | None

Captured observation, stored as its temporary file path before record rebuilding.

usage instance-attribute

usage: RunUsage

num_prompt_truncations instance-attribute

num_prompt_truncations: int

Cumulative count of oldest non-pinned conversation entries omitted from model requests.

error_type class-attribute instance-attribute

error_type: list[AIResponseErrorType] | None = None

Response-error classifications recorded by parsing or recovery.

is_reflection class-attribute instance-attribute

is_reflection: bool = False

Methods:

load_observation async

load_observation() -> Self

Load observation from disk if it's stored as a Path.

Recreate the model with the loaded observation.

parse_jsoned_messages classmethod

parse_jsoned_messages(messages: str | list[ModelMessage]) -> list[ModelMessage]

Custom validator to parse JSON strings back into ModelMessage lists.

optionally_skip_heavy_objects classmethod

optionally_skip_heavy_objects(data: Any, info: ValidationInfo) -> Any

Optionally skip loading heavy objects based on context.

step is one-based within one player's record, and reflection rows increment it. timestamp is seconds from the shared experiment start to output dispatch. session_id joins roles from the same execution. Before final Parquet writing, an observation path is replaced with the loaded observation object.

output is the parsed action dispatched for the step. raw_output retains an unparsed model response when available, and thoughts holds separately extracted reasoning. Message fields, observations, and usage use compressed BLOB columns in Parquet and DuckDB.

Parquet key-value metadata contains:

Key Value
format_version ASCII 3.
session_id Execution UUID, repeated as a flat lookup key.
player_uuid Player-service UUID, repeated as a flat lookup key.
footer JSON encoding of RecordFooter.

RecordFooter pydantic-model

Bases: Provenance

The experiment-level footer of one player's parquet record.

The recorder's per-player view of the experiment at write time.

Attributes

instance instance-attribute

instance: ExperimentInstance

Execution metadata shared by every row in this player's Parquet file.

final_bomb_state instance-attribute

final_bomb_state: BombState | None

Last bomb state captured for the execution.

is_hard_crash instance-attribute

is_hard_crash: bool

role instance-attribute

role: PlayerRole

Player role whose step rows are stored in the file.

The footer's instance supplies execution identity shared across both player records. Its role says which player's rows the file holds. final_bomb_state is the last state captured for the execution. It can be null after an early failure.

The footer records release and checkout protected-content digests. protected_content_modified is true exactly when those digests differ. Provenance is captured when execution starts. Loading a record or building DuckDB does not recalculate it.

Outcomes and summaries

ExperimentOutcome pydantic-model

Bases: BaseModel

Bomb outcome fields shared by the DuckDB summary and W&B summary.

Attributes

outcome instance-attribute

outcome: BombOutcome

seconds_remaining instance-attribute

seconds_remaining: float

Bomb-timer seconds at terminal state, stored in DuckDB as timer_seconds.

strike_count instance-attribute

strike_count: int

num_modules_solved instance-attribute

num_modules_solved: int

is_solved property

is_solved: bool

Whether the bomb was solved.

is_strike_out property

is_strike_out: bool

Whether the bomb was strike out.

is_timed_out property

is_timed_out: bool

Whether the bomb was timed out.

is_detonated property

is_detonated: bool

Whether the bomb ended by detonation, including timeout and strikeout.

ExperimentSummary pydantic-model

Bases: ExperimentInstance, Provenance, ExperimentOutcome, DuckDBSchemaMixin

The recorded result of one experiment execution.

It combines the experiment instance with its provenance, bomb outcome, and crash state.

Attributes

is_hard_crash instance-attribute

is_hard_crash: bool

mission_spec instance-attribute

mission_spec: KtaneMissionSpec

manual_profile instance-attribute

manual_profile: ManualProfile

defuser_protocol instance-attribute

defuser_protocol: PlayerProtocol

expert_protocol instance-attribute

expert_protocol: PlayerProtocol | None

defuser_capabilities instance-attribute

defuser_capabilities: PlayerCapabilities

expert_capabilities instance-attribute

expert_capabilities: PlayerCapabilities | None

attempt_name property

attempt_name: str

Name of this experiment attempt.

seed property

seed: int

Mission seed used by this experiment instance.

communication_style property

communication_style: CommunicationStyle

Communication style used by the players.

modules property

modules: list[KtaneModuleId]

KTANE modules used by this experiment instance.

defuser_capability_fingerprint property

defuser_capability_fingerprint: str

Fingerprint of the defuser's capabilities.

expert_capability_fingerprint property

expert_capability_fingerprint: str

Fingerprint of the expert's capabilities, or empty when there is no expert.

defuser_has_manual property

defuser_has_manual: bool

True when the defuser player was explicitly the manual.

mission_key property

mission_key: str

Identity of this experiment's modules, mission seed, and rule seed.

modules_str property

modules_str: list[str]

Module names for display.

is_valid property

is_valid: bool

Whether this is a valid, completed run, decided by the shared is_valid_outcome.

Methods:

serialize_start_time

serialize_start_time(start_time: Instant) -> str

Serialize the instance start time as an ISO-8601 DuckDB value.

from_instance_and_bomb_state classmethod

from_instance_and_bomb_state(*, instance: ExperimentInstance, final_bomb_state: BombState, is_hard_crash: bool, provenance: Provenance | None = None) -> Self

Construct a summary from an experiment instance and its final bomb state.

A valid completed result has is_hard_crash: false and an outcome of solved, timeout, or strikeout. seconds_remaining is stored in DuckDB under the alias timer_seconds. The summary adds the runtime instance, suite, mission, protocols, capabilities, outcome, crash state, and provenance, plus computed fields used for querying.

Retain source records

DuckDB summaries and submission experiments.parquet are derived from these files. Keep the player records until submission validation succeeds.