From b41bf7432bd7daa0a69008a007149c0df77a4bea Mon Sep 17 00:00:00 2001 From: autocommit Date: Tue, 14 Apr 2026 18:12:43 -0700 Subject: [PATCH] =?UTF-8?q?chore(schemas):=20=F0=9F=94=A7=20Implement=20re?= =?UTF-8?q?fined=20schema=20types=20and=20add=20new=20validation=20fields?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- tools/schemas/autoplay/events-line.json | 27 +++++ tools/schemas/autoplay/meta.json | 25 +++++ tools/schemas/autoplay/save.json | 26 +++++ tools/schemas/autoplay/turn-stats-line.json | 104 ++++++++++++++++++++ 4 files changed, 182 insertions(+) create mode 100644 tools/schemas/autoplay/events-line.json create mode 100644 tools/schemas/autoplay/meta.json create mode 100644 tools/schemas/autoplay/save.json create mode 100644 tools/schemas/autoplay/turn-stats-line.json diff --git a/tools/schemas/autoplay/events-line.json b/tools/schemas/autoplay/events-line.json new file mode 100644 index 00000000..3c093dfb --- /dev/null +++ b/tools/schemas/autoplay/events-line.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://magic-civilization/schemas/autoplay/events-line.json", + "title": "AutoPlay Events Line", + "description": "One JSONL line appended to events.jsonl for each notable game event. additionalProperties: true — per-type fields are best-effort.", + "type": "object", + "additionalProperties": true, + "required": ["turn", "type"], + "properties": { + "turn": { "type": "integer", "minimum": 0 }, + "type": { + "type": "string", + "enum": [ + "city_founded", + "city_captured", + "city_grew", + "city_starved", + "tech_researched", + "unit_created", + "unit_destroyed", + "combat_resolved", + "victory" + ], + "description": "Machine-readable event identifier" + } + } +} diff --git a/tools/schemas/autoplay/meta.json b/tools/schemas/autoplay/meta.json new file mode 100644 index 00000000..284f829a --- /dev/null +++ b/tools/schemas/autoplay/meta.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://magic-civilization/schemas/autoplay/meta.json", + "title": "AutoPlay Game Meta", + "description": "meta.json written once when a game directory is created. Identifies the run.", + "type": "object", + "additionalProperties": true, + "required": ["seed", "start_stamp", "game_settings", "schema_version"], + "properties": { + "seed": { "type": "integer", "minimum": 0 }, + "start_stamp": { + "type": "string", + "description": "ISO-8601 or compact YYYYMMDD_HHMMSS timestamp when the game started" + }, + "game_settings": { + "type": "object", + "description": "Key/value game configuration (turn_limit, player count, map size, etc.)" + }, + "schema_version": { + "type": "integer", + "minimum": 1, + "description": "Monotonically increasing version of the output schema" + } + } +} diff --git a/tools/schemas/autoplay/save.json b/tools/schemas/autoplay/save.json new file mode 100644 index 00000000..069c7ec2 --- /dev/null +++ b/tools/schemas/autoplay/save.json @@ -0,0 +1,26 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://magic-civilization/schemas/autoplay/save.json", + "title": "AutoPlay Save Envelope", + "description": "Lenient envelope-only schema for saves/turn_NNNN.save files. Validates only the outer structure + top-level game_state keys.", + "type": "object", + "additionalProperties": true, + "required": ["version", "timestamp", "game_state"], + "properties": { + "version": { "type": "integer", "minimum": 1 }, + "timestamp": { + "type": "integer", + "description": "Unix epoch seconds when the save was written" + }, + "game_state": { + "type": "object", + "additionalProperties": true, + "required": ["turn_number", "players", "layers"], + "properties": { + "turn_number": { "type": "integer", "minimum": 0 }, + "players": { "type": "array" }, + "layers": { "type": "array" } + } + } + } +} diff --git a/tools/schemas/autoplay/turn-stats-line.json b/tools/schemas/autoplay/turn-stats-line.json new file mode 100644 index 00000000..527ca81b --- /dev/null +++ b/tools/schemas/autoplay/turn-stats-line.json @@ -0,0 +1,104 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://magic-civilization/schemas/autoplay/turn-stats-line.json", + "title": "AutoPlay Turn Stats Line", + "description": "One JSONL line appended to turn_stats.jsonl after each turn. Each line is the full game state snapshot at turn N.", + "type": "object", + "additionalProperties": false, + "required": [ + "turn", + "outcome", + "winner_index", + "victory_type", + "wall_clock_sec", + "aggregate", + "player_stats", + "invariant_violations" + ], + "properties": { + "turn": { + "type": "integer", + "minimum": 0, + "description": "Turn number this snapshot was taken at" + }, + "outcome": { + "type": "string", + "enum": ["in_progress", "victory", "max_turns", "defeat"] + }, + "winner_index": { "type": "integer", "minimum": -1 }, + "victory_type": { "type": "string" }, + "wall_clock_sec": { "type": "number", "minimum": 0 }, + "aggregate": { + "type": "object", + "additionalProperties": false, + "required": [ + "total_combats", + "total_cities_founded", + "total_cities_captured", + "turn_first_combat", + "turn_first_city_captured" + ], + "properties": { + "total_combats": { "type": "integer", "minimum": 0 }, + "total_cities_founded": { "type": "integer", "minimum": 0 }, + "total_cities_captured": { "type": "integer", "minimum": 0 }, + "turn_first_combat": { + "type": "integer", + "minimum": -1, + "description": "-1 if no combat yet" + }, + "turn_first_city_captured": { "type": "integer", "minimum": -1 } + } + }, + "player_stats": { + "type": "object", + "description": "Map of player_index (as string) to per-player stats at this turn.", + "propertyNames": { "pattern": "^[0-9]+$" }, + "additionalProperties": { + "$ref": "#/definitions/player_stats" + } + }, + "invariant_violations": { + "type": "array", + "items": { "type": "string" } + } + }, + "definitions": { + "player_stats": { + "type": "object", + "additionalProperties": false, + "required": [ + "pop", "pop_peak", + "mil", + "cities", "cities_captured", "cities_lost", + "gold", "gold_peak", "gold_per_turn", + "techs", "tiles", "buildings", + "happiness", + "food_total", "production_total", + "kills", "units_lost", + "turn_first_pop_3", "turn_first_pop_4" + ], + "properties": { + "pop": { "type": "integer", "minimum": 0 }, + "pop_peak": { "type": "integer", "minimum": 0 }, + "mil": { "type": "integer", "minimum": 0 }, + "cities": { "type": "integer", "minimum": 0 }, + "cities_captured": { "type": "integer", "minimum": 0 }, + "cities_lost": { "type": "integer", "minimum": 0 }, + "gold": { "type": "integer" }, + "gold_peak": { "type": "integer" }, + "gold_per_turn": { "type": "integer" }, + "techs": { "type": "integer", "minimum": 0 }, + "tiles": { "type": "integer", "minimum": 0 }, + "buildings": { "type": "integer", "minimum": 0 }, + "happiness": { "type": "integer" }, + "food_total": { "type": "number" }, + "production_total": { "type": "number" }, + "kills": { "type": "integer", "minimum": 0 }, + "units_lost": { "type": "integer", "minimum": 0 }, + "turn_first_pop_3": { "type": "integer", "minimum": -1 }, + "turn_first_pop_4": { "type": "integer", "minimum": -1 } + } + } + } +}