Declarative simulation-test scenarios for horizontal proving on the DO fleet. Two kinds: combat_setpiece (hand-authored tactical board, known outcome) and fullgame (seeded full-game, invariant/liveness/determinism/balance assertions). - 10 combat set-pieces (data/sim-scenarios/combat/): rush/walls/pyrrhic, ranged kite, fortified hill, castle vs double-rush, siege catapult, last-stand, flanking, formation-vs-loose. - 10 fullgame (data/sim-scenarios/fullgame/): smoke, determinism, expansion, time-to-tier, economy invariant, no-soft-lock, trade, culture borders, clan fairness band, broad 150t systems run. - sim-scenarios.schema.json validates both kinds; assertion vocab enumerated, each mapped to a real engine signal (cities_captured, pvp_kills, surviving units, gold/pop, traded_luxuries, tech tier). - All clan personalities are the REAL 8 (balanced/boom/expansionist/merchant/ militarist/rusher/tech_rusher/turtle); the prior draft's ironhold/goldvein were fabricated. - SIM_SCENARIOS.md: S3->fleet pipeline, full catalog, schema, calibration rule (assertion values calibrated against real runs, never invented). Router wired. Removed the two old fake-schema drafts (smoke_duel_30t, game1_headless_systems_150t) whose assertions rode on fabricated metrics. Runner + calibration follow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
118 lines
4.3 KiB
JSON
118 lines
4.3 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "sim-scenarios",
|
|
"title": "Simulation Test Scenario",
|
|
"description": "A declarative scenario run headless by the `sim_scenario` bin against the real mc-turn/mc-combat resolver, on the DO fleet. Two kinds: combat_setpiece (hand-authored tactical board with a known outcome) and fullgame (seeded full-game run with statistical / invariant assertions). Assertion `value`s are CALIBRATED against real runs, never invented.",
|
|
"type": "object",
|
|
"required": ["id", "kind", "description", "expect"],
|
|
"properties": {
|
|
"id": { "type": "string", "pattern": "^[a-z0-9_]+$" },
|
|
"kind": { "enum": ["combat_setpiece", "fullgame"] },
|
|
"version": { "type": "integer", "minimum": 1 },
|
|
"description": { "type": "string" },
|
|
"map": {
|
|
"type": "object",
|
|
"properties": {
|
|
"size": { "type": "integer", "minimum": 8 },
|
|
"evolution_ticks": { "type": "integer", "minimum": 0 },
|
|
"seed_base": { "type": "integer" }
|
|
}
|
|
},
|
|
"terrain_overrides": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"required": ["at", "biome"],
|
|
"properties": {
|
|
"at": { "type": "array", "items": { "type": "integer" }, "minItems": 2, "maxItems": 2 },
|
|
"biome": { "type": "string" }
|
|
}
|
|
}
|
|
},
|
|
"defender": { "$ref": "#/$defs/side_combat" },
|
|
"attacker": { "$ref": "#/$defs/side_combat" },
|
|
"players": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"required": ["personality"],
|
|
"properties": {
|
|
"personality": { "type": "string" },
|
|
"seed_luxuries": { "type": "array", "items": { "type": "string" } }
|
|
}
|
|
}
|
|
},
|
|
"rules": {
|
|
"type": "object",
|
|
"properties": {
|
|
"max_turns": { "type": "integer", "minimum": 1 },
|
|
"victory_city_count": { "type": "integer" },
|
|
"victory_disabled": { "type": "boolean" }
|
|
}
|
|
},
|
|
"max_turns": { "type": "integer", "minimum": 1 },
|
|
"seeds": {
|
|
"oneOf": [
|
|
{ "type": "array", "items": { "type": "integer" } },
|
|
{ "type": "string", "pattern": "^sweep:[0-9]+\\.\\.[0-9]+$" }
|
|
]
|
|
},
|
|
"expect": { "type": "array", "items": { "$ref": "#/$defs/assertion" }, "minItems": 1 }
|
|
},
|
|
"$defs": {
|
|
"stack_entry": {
|
|
"type": "object",
|
|
"required": ["unit", "count"],
|
|
"properties": {
|
|
"unit": { "type": "string" },
|
|
"count": { "type": "integer", "minimum": 1 },
|
|
"at": { "type": "array", "items": { "type": "integer" }, "minItems": 2, "maxItems": 2 },
|
|
"fortified": { "type": "boolean" },
|
|
"formation": { "type": "boolean" }
|
|
}
|
|
},
|
|
"side_combat": {
|
|
"type": "object",
|
|
"properties": {
|
|
"player": { "type": "string" },
|
|
"approach_from": { "type": "array", "items": { "type": "integer" }, "minItems": 2, "maxItems": 2 },
|
|
"flank": { "type": "boolean" },
|
|
"capital": {
|
|
"type": "object",
|
|
"required": ["col", "row"],
|
|
"properties": {
|
|
"col": { "type": "integer" },
|
|
"row": { "type": "integer" },
|
|
"population": { "type": "integer", "minimum": 1 },
|
|
"is_last_city": { "type": "boolean" }
|
|
}
|
|
},
|
|
"buildings": { "type": "array", "items": { "type": "string" } },
|
|
"garrison": { "type": "array", "items": { "$ref": "#/$defs/stack_entry" } },
|
|
"stack": { "type": "array", "items": { "$ref": "#/$defs/stack_entry" } }
|
|
}
|
|
},
|
|
"assertion": {
|
|
"type": "object",
|
|
"required": ["type"],
|
|
"properties": {
|
|
"type": {
|
|
"enum": [
|
|
"capital_captured", "capital_held", "attacker_survivors", "defender_survivors",
|
|
"attacker_losses", "pvp_kills", "capture_by_turn",
|
|
"final_turn", "terminates", "turn_monotonic", "no_nan_economy",
|
|
"population_non_negative", "deterministic_end_hash", "more_cities",
|
|
"city_count", "total_pvp_combats", "median_tier_peak", "trades_formed",
|
|
"border_growth", "clan_winrate_max"
|
|
]
|
|
},
|
|
"op": { "enum": [">=", ">", "==", "<=", "<"] },
|
|
"value": { "type": "number" },
|
|
"by": { "type": "string" },
|
|
"player": { "type": "integer" },
|
|
"than": { "type": "integer" },
|
|
"min_margin": { "type": "integer" }
|
|
}
|
|
}
|
|
}
|
|
}
|