Files
room_glitch/labs/glitch_odin/design/glitch_implementation_contract.json
T

782 lines
19 KiB
JSON

{
"design_version": "1.0",
"status": "proposed_semantic_contract_not_existing_wire_schema",
"target_architecture": {
"authority": "Rust Glitch room controller",
"transport": "NATS",
"operator_ui": "Flutter",
"game_runtime": "Godot",
"persistence_proposal": "durable transactional journal and outbox with JetStream observation delivery"
},
"profiles": {
"guided": {
"time_limit_ms": 3600000,
"passes_per_station": 1,
"response_window_ms": 60000,
"stable_target_hold_ms": 1000,
"final_ack_window_ms": 30000,
"hint_1_inactivity_ms": 90000,
"next_hint_interval_ms": 60000,
"score_target_multiplier": 0.6,
"frogger_homes": 1
},
"standard": {
"time_limit_ms": 3600000,
"passes_per_station": 2,
"response_window_ms": 40000,
"stable_target_hold_ms": 2000,
"final_ack_window_ms": 20000,
"hint_1_inactivity_ms": 120000,
"next_hint_interval_ms": 90000,
"score_target_multiplier": 1.0,
"frogger_homes": 1
},
"challenge": {
"time_limit_ms": 3600000,
"passes_per_station": 3,
"response_window_ms": 25000,
"stable_target_hold_ms": 3000,
"final_ack_window_ms": 12000,
"hint_1_inactivity_ms": 180000,
"next_hint_interval_ms": 120000,
"score_target_multiplier": 1.4,
"frogger_homes": 1
}
},
"entities": [
{
"cabinet_id": "cabinet_01",
"first_state_id": "A01",
"game": "pacman",
"token_id": "T01",
"cell_id": "CELL01",
"socket_id": "SOCKET01",
"status": "existing_assignment"
},
{
"cabinet_id": "cabinet_02",
"first_state_id": "A02",
"game": "galaga",
"token_id": "T02",
"cell_id": "CELL02",
"socket_id": "SOCKET02",
"status": "existing_assignment"
},
{
"cabinet_id": "cabinet_03",
"first_state_id": "A03",
"game": "tempest",
"token_id": "T03",
"cell_id": "CELL03",
"socket_id": "SOCKET03",
"status": "existing_assignment"
},
{
"cabinet_id": "cabinet_04",
"first_state_id": "A04",
"game": "missile_command",
"token_id": "T04",
"cell_id": "CELL04",
"socket_id": "SOCKET04",
"status": "existing_assignment"
},
{
"cabinet_id": "cabinet_05",
"first_state_id": "A05",
"game": "frogger",
"token_id": "T05",
"cell_id": "CELL05",
"socket_id": "SOCKET05",
"status": "proposed_assignment"
},
{
"cabinet_id": "cabinet_06",
"first_state_id": "A06",
"game": "space_invaders",
"token_id": "T06",
"cell_id": "CELL06",
"socket_id": "SOCKET06",
"status": "proposed_assignment"
}
],
"boss": {
"cabinet_id": "cabinet_07",
"id": "B07",
"game_proposal": "robotron_or_bespoke_variant",
"unlock": "all_six_distinct_first_state_wins"
},
"durations_ms": {
"charge": 30000,
"passage_debounce": 300,
"cell_debounce": 500,
"ship_power_stable": 2000,
"retry_delay": 3000,
"countdown": 5000,
"agent_stale": 3000,
"agent_offline": 8000,
"command_accept": 2000,
"command_expiry": 5000,
"boot_completion": 10000
},
"staffing": {
"operator_count_rule": "max(1, min(party_size - 1, 6))",
"calibration_concurrency": "operator_count",
"solo": "assisted sequential ship/arcade interaction",
"finale": "sequential station arm, group readiness, navigator commit",
"solo_final_ack_window_ms": 90000
},
"event_envelope_schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Proposed Glitch normalized event envelope",
"type": "object",
"additionalProperties": false,
"required": [
"schema_version",
"event_id",
"type",
"room_id",
"run_id",
"entity_id",
"source_id",
"boot_id",
"source_seq",
"assignment_id",
"occurred_at_ms",
"received_at_ms",
"payload"
],
"properties": {
"schema_version": {
"type": "integer",
"minimum": 0,
"const": 1
},
"event_id": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string",
"minLength": 1
},
"room_id": {
"type": "string",
"minLength": 1
},
"run_id": {
"type": "string",
"minLength": 1
},
"entity_id": {
"type": "string",
"minLength": 1
},
"source_id": {
"type": "string",
"minLength": 1
},
"boot_id": {
"type": "string",
"minLength": 1
},
"source_seq": {
"type": "integer",
"minimum": 0
},
"assignment_id": {
"type": [
"string",
"null"
]
},
"occurred_at_ms": {
"type": "integer",
"minimum": 0
},
"received_at_ms": {
"type": "integer",
"minimum": 0
},
"payload": {
"type": "object"
},
"correlation_id": {
"type": "string",
"minLength": 1
},
"causation_id": {
"type": "string",
"minLength": 1
},
"actor_id": {
"type": "string",
"minLength": 1
},
"reason": {
"type": "string",
"minLength": 1
}
}
},
"room_state_example": {
"schema_version": 1,
"room_id": "glitch",
"run_id": "example-run-001",
"revision": 0,
"config_hash": "EXAMPLE_REPLACE_WITH_CONTENT_HASH",
"lifecycle": "READY",
"phase": "BRIEFING",
"outcome": null,
"active_elapsed_ms": 0,
"time_limit_ms": 3600000,
"difficulty": "standard",
"party_size": 2,
"controller_epoch": 1,
"seed": 42,
"cabinet_first_wins": [],
"cells_installed": [],
"calibration_passes": {},
"launch": {
"launch_epoch": 0,
"armed_stations": [],
"acknowledged_groups": [],
"committed": false
}
},
"simulation_cases": [
{
"id": "SIM01",
"scenario": "Golden path with 6 players, standard",
"assertion": "All acts, six cells and two calibration passes; one launch commit",
"execution_status": "specified_not_executed"
},
{
"id": "SIM02",
"scenario": "2 players, guided; one roaming operator",
"assertion": "All six stations completed; no simultaneous multi-station human input required",
"execution_status": "specified_not_executed"
},
{
"id": "SIM03",
"scenario": "1 assisted player; sequential ship and arcade interactions",
"assertion": "No deadlock; clearly assisted outcome/metadata",
"execution_status": "specified_not_executed"
},
{
"id": "SIM04",
"scenario": "8 players, challenge; six stations active",
"assertion": "Unused helper never required for a guard; three passes per station",
"execution_status": "specified_not_executed"
},
{
"id": "SIM05",
"scenario": "Wrong token, repeated scan, stale historical scan",
"assertion": "No credit for wrong/stale; only one authorization for correct scan",
"execution_status": "specified_not_executed"
},
{
"id": "SIM06",
"scenario": "Lose A03 twice then retry",
"assertion": "No extra token needed; other wins and charge retained",
"execution_status": "specified_not_executed"
},
{
"id": "SIM07",
"scenario": "Duplicate A01 win and missing A06 win",
"assertion": "Boss remains dark; unique set count stays 5",
"execution_status": "specified_not_executed"
},
{
"id": "SIM08",
"scenario": "Claw reward ACK but token delivery jam",
"assertion": "Reward pending; GM hand-delivery logged; no duplicate dispense",
"execution_status": "specified_not_executed"
},
{
"id": "SIM09",
"scenario": "Boss won; passage ACK without open sensor",
"assertion": "Reveal hold after 5 s; no assumed opening",
"execution_status": "specified_not_executed"
},
{
"id": "SIM10",
"scenario": "Wrong socket, duplicate cell identity, missing cell",
"assertion": "Ship power guard false; explicit diagnostic per conflict",
"execution_status": "specified_not_executed"
},
{
"id": "SIM11",
"scenario": "Cell removed during calibration and countdown",
"assertion": "Current wave/countdown canceled; completed passes retained; fresh IDs",
"execution_status": "specified_not_executed"
},
{
"id": "SIM12",
"scenario": "Late Ready for old challenge; Execute exactly at deadline",
"assertion": "Both rejected; current wave remains consistent",
"execution_status": "specified_not_executed"
},
{
"id": "SIM13",
"scenario": "One final group late, then retry",
"assertion": "Acknowledgements clear; calibration retained; launch once on valid retry",
"execution_status": "specified_not_executed"
},
{
"id": "SIM14",
"scenario": "Restart controller after durable boss win before output publish",
"assertion": "Recovered outbox sends same command ID; no repeated physical release",
"execution_status": "specified_not_executed"
},
{
"id": "SIM15",
"scenario": "Agent restarts after uncertain bay release",
"assertion": "No blind pulse replay; reconcile or GM inspect",
"execution_status": "specified_not_executed"
},
{
"id": "SIM16",
"scenario": "Network drop, duplicate and reordered events",
"assertion": "No regression/double reward; snapshot reconciliation reaches same state",
"execution_status": "specified_not_executed"
},
{
"id": "SIM17",
"scenario": "Teddy unavailable or stale queued hint",
"assertion": "Fallback text; stale hint discarded; gameplay can finish",
"execution_status": "specified_not_executed"
},
{
"id": "SIM18",
"scenario": "Pause 5 min; expire action while paused",
"assertion": "Active timer frozen; expired wall-time command rejected",
"execution_status": "specified_not_executed"
},
{
"id": "SIM19",
"scenario": "Time expires in calibration; extend 5 min",
"assertion": "TIME_EXPIRED then preserved phase; no automatic normal win",
"execution_status": "specified_not_executed"
},
{
"id": "SIM20",
"scenario": "Reset and inject old-run win/scan/launch",
"assertion": "All rejected; fresh run remains pristine",
"execution_status": "specified_not_executed"
}
],
"calibration_selections": {
"cabinet_01": {
"min": 0,
"max": 3
},
"cabinet_02": {
"min": 1,
"max": 5
},
"cabinet_03": {
"min": 0,
"max": 7
},
"cabinet_04": {
"min": 1,
"max": 3
},
"cabinet_05": {
"min": 1,
"max": 4
},
"cabinet_06": {
"min": 1,
"max": 4
}
},
"payload_schemas": {
"puzzle.solved": {
"type": "object",
"additionalProperties": false,
"properties": {
"puzzle_id": {
"type": "string",
"minLength": 1
},
"evidence": {
"type": "string",
"minLength": 1
}
},
"required": [
"puzzle_id",
"evidence"
]
},
"reward.delivered": {
"type": "object",
"additionalProperties": false,
"properties": {
"reward_id": {
"type": "string",
"minLength": 1
},
"evidence": {
"type": "string",
"minLength": 1
}
},
"required": [
"reward_id",
"evidence"
]
},
"token.observed": {
"type": "object",
"additionalProperties": false,
"properties": {
"reader_id": {
"type": "string",
"minLength": 1
},
"token_id": {
"type": "string",
"minLength": 1
}
},
"required": [
"reader_id",
"token_id"
]
},
"game.started": {
"type": "object",
"additionalProperties": false,
"properties": {
"attempt_id": {
"type": "string",
"minLength": 1
}
},
"required": [
"attempt_id"
]
},
"game.progress": {
"type": "object",
"additionalProperties": false,
"properties": {
"attempt_id": {
"type": "string",
"minLength": 1
},
"value": {
"type": "integer",
"minimum": 0
}
},
"required": [
"attempt_id",
"value"
]
},
"game.won": {
"type": "object",
"additionalProperties": false,
"properties": {
"attempt_id": {
"type": "string",
"minLength": 1
},
"objective_id": {
"type": "string",
"minLength": 1
},
"value": {
"type": "integer",
"minimum": 0
}
},
"required": [
"attempt_id",
"objective_id",
"value"
]
},
"game.lost": {
"type": "object",
"additionalProperties": false,
"properties": {
"attempt_id": {
"type": "string",
"minLength": 1
},
"reason": {
"type": "string",
"minLength": 1
}
},
"required": [
"attempt_id",
"reason"
]
},
"cell.observed": {
"type": "object",
"additionalProperties": false,
"properties": {
"cell_id": {
"type": "string",
"minLength": 1
},
"location": {
"type": "string",
"minLength": 1
},
"present": {
"type": "boolean"
}
},
"required": [
"cell_id",
"location",
"present"
]
},
"passage.observed": {
"type": "object",
"additionalProperties": false,
"properties": {
"open": {
"type": "boolean"
},
"sensor_id": {
"type": "string",
"minLength": 1
}
},
"required": [
"open",
"sensor_id"
]
},
"calibration.ready": {
"type": "object",
"additionalProperties": false,
"properties": {
"challenge_id": {
"type": "string",
"minLength": 1
},
"selection": {
"type": "integer",
"minimum": 0
},
"stable_for_ms": {
"type": "integer",
"minimum": 0
}
},
"required": [
"challenge_id",
"selection",
"stable_for_ms"
]
},
"calibration.ready_revoked": {
"type": "object",
"additionalProperties": false,
"properties": {
"challenge_id": {
"type": "string",
"minLength": 1
},
"reason": {
"type": "string",
"minLength": 1
}
},
"required": [
"challenge_id",
"reason"
]
},
"calibration.execute": {
"type": "object",
"additionalProperties": false,
"properties": {
"challenge_id": {
"type": "string",
"minLength": 1
}
},
"required": [
"challenge_id"
]
},
"launch.group_ready": {
"type": "object",
"additionalProperties": false,
"properties": {
"launch_epoch": {
"type": "integer",
"minimum": 0
},
"group_id": {
"type": "string",
"minLength": 1
}
},
"required": [
"launch_epoch",
"group_id"
]
},
"launch.commit_requested": {
"type": "object",
"additionalProperties": false,
"properties": {
"launch_epoch": {
"type": "integer",
"minimum": 0
}
},
"required": [
"launch_epoch"
]
},
"teddy.playback_status": {
"type": "object",
"additionalProperties": false,
"properties": {
"cue_id": {
"type": "string",
"minLength": 1
},
"status": {
"enum": [
"accepted",
"started",
"completed",
"failed"
]
}
},
"required": [
"cue_id",
"status"
]
}
},
"payload_validation": "Validate envelope, then select payload schema by event.type. Reject unknown event types unless separately defined as controller-internal events. Apply semantic guards after schema validation.",
"command_envelope_schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"schema_version": {
"const": 1
},
"command_id": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string",
"minLength": 1
},
"room_id": {
"type": "string",
"minLength": 1
},
"run_id": {
"type": "string",
"minLength": 1
},
"target_entity": {
"type": "string",
"minLength": 1
},
"target_boot_id": {
"type": "string",
"minLength": 1
},
"controller_epoch": {
"type": "integer",
"minimum": 0
},
"expected_revision": {
"type": "integer",
"minimum": 0
},
"expires_at_ms": {
"type": "integer",
"minimum": 0
},
"payload": {
"type": "object"
}
},
"required": [
"schema_version",
"command_id",
"type",
"room_id",
"run_id",
"target_entity",
"target_boot_id",
"controller_epoch",
"expected_revision",
"expires_at_ms",
"payload"
]
},
"command_result_schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"command_id": {
"type": "string",
"minLength": 1
},
"status": {
"enum": [
"ACCEPTED",
"REJECTED",
"COMPLETED",
"FAILED",
"DELIVERY_UNKNOWN"
]
},
"reason_code": {
"type": "string",
"minLength": 1
},
"snapshot_revision": {
"type": "integer",
"minimum": 0
}
},
"required": [
"command_id",
"status",
"reason_code",
"snapshot_revision"
]
},
"event_example": {
"schema_version": 1,
"event_id": "evt-example-001",
"type": "game.won",
"room_id": "glitch",
"run_id": "example-run-001",
"entity_id": "cabinet_01",
"source_id": "agent-cabinet-01",
"boot_id": "boot-example-001",
"source_seq": 14,
"assignment_id": "assignment-a01-001",
"occurred_at_ms": 1792260000000,
"received_at_ms": 1792260000010,
"payload": {
"attempt_id": "attempt-a01-001",
"objective_id": "score_500",
"value": 500
}
}
}