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:
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.
session_id
instance-attribute
¶
session_id: UUID4
Execution identifier used to join rows recorded by different players.
output
instance-attribute
¶
output: PlayerOutputType | KtaneGameplayInput
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
¶
Prior conversation rendered as message history before the current model call.
new_messages
class-attribute
instance-attribute
¶
Request and response messages added by the current model call.
observation
instance-attribute
¶
observation: Observation | Path | None
Captured observation, stored as its temporary file path before record rebuilding.
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.
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.
Footer¶
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.
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
¶
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¶
communication_style
property
¶
Communication style used by the players.
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.
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.