Spaces:
Running
fix-forward: repair merged PR#5/#6 (unblocked by own-unit actor_type fix)
Browse filesThe collaborator merged PR#5 (tech-production-planning) and PR#6
(economy-investment/rush-hour fail_conditions + longhorizon pack) raw
— main was RED (3 failures). With the engine own-unit actor_type fix:
- tech-production-planning: now WINNABLE (scripted chain wins easy
~tick 2883). Un-quarantined; realigned the inert within_ticks to the
tick reachable at max_turns (5403/7203/8103) + added timeout fails;
classified NOT_APPLICABLE (non-spatial build-order); added 'mine'
glossary entry; fixed the PR's test (res.signals.units_summary
AttributeError -> a win already proves the 3tnk; hard-fail test
updated to the any_of shape).
- economy-investment / rush-hour / longhorizon-opening-to-assault:
realigned the inert after_ticks fails to R=93+90·(max_turns-1) so a
non-finisher LOSES instead of drawing (turn budget unchanged ->
solvency-safe); classified longhorizon NOT_APPLICABLE.
Suite 380 passed, 1 skipped; catalog regenerated.
- docs/scenarios.html +0 -0
- openra_bench/game_knowledge.py +1 -0
- openra_bench/scenarios/packs/economy-investment.yaml +8 -6
- openra_bench/scenarios/packs/longhorizon-opening-to-assault.yaml +6 -6
- openra_bench/scenarios/packs/rush-hour.yaml +6 -6
- openra_bench/scenarios/packs/tech-production-planning.yaml +12 -4
- tests/test_hard_tier.py +5 -0
- tests/test_tech_production_planning.py +10 -5
|
The diff for this file is too large to render.
See raw diff
|
|
|
|
@@ -52,6 +52,7 @@ ACTOR_GLOSSARY: dict[str, str] = {
|
|
| 52 |
"fix": "service depot (repairs vehicles)",
|
| 53 |
"dome": "radar dome (reveals map / tech prerequisite)",
|
| 54 |
"silo": "ore silo (stores surplus ore)",
|
|
|
|
| 55 |
"gun": "gun turret (anti-vehicle base defence)",
|
| 56 |
"pbox": "pillbox (anti-infantry base defence)",
|
| 57 |
"tsla": "Tesla coil (powerful anti-everything defence)",
|
|
|
|
| 52 |
"fix": "service depot (repairs vehicles)",
|
| 53 |
"dome": "radar dome (reveals map / tech prerequisite)",
|
| 54 |
"silo": "ore silo (stores surplus ore)",
|
| 55 |
+
"mine": "ore mine (resource node harvesters gather from)",
|
| 56 |
"gun": "gun turret (anti-vehicle base defence)",
|
| 57 |
"pbox": "pillbox (anti-infantry base defence)",
|
| 58 |
"tsla": "Tesla coil (powerful anti-everything defence)",
|
|
@@ -73,9 +73,11 @@ levels:
|
|
| 73 |
all_of:
|
| 74 |
- building_count_gte: {type: proc, n: 2}
|
| 75 |
- building_count_gte: {type: powr, n: 2}
|
| 76 |
-
- within_ticks:
|
|
|
|
|
|
|
| 77 |
fail_condition:
|
| 78 |
-
after_ticks:
|
| 79 |
max_turns: 70
|
| 80 |
medium:
|
| 81 |
description: >
|
|
@@ -89,9 +91,9 @@ levels:
|
|
| 89 |
- building_count_gte: {type: proc, n: 2}
|
| 90 |
- building_count_gte: {type: powr, n: 2}
|
| 91 |
- own_units_gte: 3
|
| 92 |
-
- within_ticks:
|
| 93 |
fail_condition:
|
| 94 |
-
after_ticks:
|
| 95 |
max_turns: 80
|
| 96 |
hard:
|
| 97 |
description: >
|
|
@@ -105,9 +107,9 @@ levels:
|
|
| 105 |
- own_units_gte: 6
|
| 106 |
- building_count_gte: {type: proc, n: 1}
|
| 107 |
- units_lost_lte: 0
|
| 108 |
-
- within_ticks:
|
| 109 |
fail_condition:
|
| 110 |
any_of:
|
| 111 |
-
- after_ticks:
|
| 112 |
- not: {units_lost_lte: 0}
|
| 113 |
max_turns: 90
|
|
|
|
| 73 |
all_of:
|
| 74 |
- building_count_gte: {type: proc, n: 2}
|
| 75 |
- building_count_gte: {type: powr, n: 2}
|
| 76 |
+
- within_ticks: 6303
|
| 77 |
+
# aligned to tick reachable at max_turns (~90/turn): non-finisher
|
| 78 |
+
# LOSES not draws; turn budget unchanged (solvency-safe).
|
| 79 |
fail_condition:
|
| 80 |
+
after_ticks: 6303
|
| 81 |
max_turns: 70
|
| 82 |
medium:
|
| 83 |
description: >
|
|
|
|
| 91 |
- building_count_gte: {type: proc, n: 2}
|
| 92 |
- building_count_gte: {type: powr, n: 2}
|
| 93 |
- own_units_gte: 3
|
| 94 |
+
- within_ticks: 7203
|
| 95 |
fail_condition:
|
| 96 |
+
after_ticks: 7203
|
| 97 |
max_turns: 80
|
| 98 |
hard:
|
| 99 |
description: >
|
|
|
|
| 107 |
- own_units_gte: 6
|
| 108 |
- building_count_gte: {type: proc, n: 1}
|
| 109 |
- units_lost_lte: 0
|
| 110 |
+
- within_ticks: 8103
|
| 111 |
fail_condition:
|
| 112 |
any_of:
|
| 113 |
+
- after_ticks: 8103
|
| 114 |
- not: {units_lost_lte: 0}
|
| 115 |
max_turns: 90
|
|
@@ -103,9 +103,9 @@ levels:
|
|
| 103 |
- has_building: proc
|
| 104 |
- own_units_gte: 4
|
| 105 |
- reach_region: {x: 115, y: 32, radius: 8}
|
| 106 |
-
- within_ticks:
|
| 107 |
fail_condition:
|
| 108 |
-
after_ticks:
|
| 109 |
max_turns: 120
|
| 110 |
|
| 111 |
medium:
|
|
@@ -119,9 +119,9 @@ levels:
|
|
| 119 |
- has_building: proc
|
| 120 |
- own_units_gte: 5
|
| 121 |
- reach_region: {x: 115, y: 32, radius: 7}
|
| 122 |
-
- within_ticks:
|
| 123 |
fail_condition:
|
| 124 |
-
after_ticks:
|
| 125 |
max_turns: 140
|
| 126 |
|
| 127 |
hard:
|
|
@@ -140,10 +140,10 @@ levels:
|
|
| 140 |
- has_building: proc
|
| 141 |
- own_units_gte: 6
|
| 142 |
- reach_region: {x: 115, y: 32, radius: 6}
|
| 143 |
-
- within_ticks:
|
| 144 |
- units_lost_lte: 4
|
| 145 |
fail_condition:
|
| 146 |
any_of:
|
| 147 |
-
- after_ticks:
|
| 148 |
- not: {own_units_gte: 1}
|
| 149 |
max_turns: 160
|
|
|
|
| 103 |
- has_building: proc
|
| 104 |
- own_units_gte: 4
|
| 105 |
- reach_region: {x: 115, y: 32, radius: 8}
|
| 106 |
+
- within_ticks: 10803
|
| 107 |
fail_condition:
|
| 108 |
+
after_ticks: 10803
|
| 109 |
max_turns: 120
|
| 110 |
|
| 111 |
medium:
|
|
|
|
| 119 |
- has_building: proc
|
| 120 |
- own_units_gte: 5
|
| 121 |
- reach_region: {x: 115, y: 32, radius: 7}
|
| 122 |
+
- within_ticks: 12603
|
| 123 |
fail_condition:
|
| 124 |
+
after_ticks: 12603
|
| 125 |
max_turns: 140
|
| 126 |
|
| 127 |
hard:
|
|
|
|
| 140 |
- has_building: proc
|
| 141 |
- own_units_gte: 6
|
| 142 |
- reach_region: {x: 115, y: 32, radius: 6}
|
| 143 |
+
- within_ticks: 14403
|
| 144 |
- units_lost_lte: 4
|
| 145 |
fail_condition:
|
| 146 |
any_of:
|
| 147 |
+
- after_ticks: 14403
|
| 148 |
- not: {own_units_gte: 1}
|
| 149 |
max_turns: 160
|
|
@@ -523,12 +523,12 @@ levels:
|
|
| 523 |
win_condition:
|
| 524 |
all_of:
|
| 525 |
- units_killed_gte: 5
|
| 526 |
-
- within_ticks:
|
| 527 |
- units_lost_lte: 6
|
| 528 |
fail_condition:
|
| 529 |
any_of:
|
| 530 |
- not: {own_units_gte: 1}
|
| 531 |
-
- after_ticks:
|
| 532 |
medium:
|
| 533 |
description: >
|
| 534 |
Rush Hour Sweep \u2014 medium. Tighter clock and attrition cap:
|
|
@@ -537,12 +537,12 @@ levels:
|
|
| 537 |
win_condition:
|
| 538 |
all_of:
|
| 539 |
- units_killed_gte: 7
|
| 540 |
-
- within_ticks:
|
| 541 |
- units_lost_lte: 4
|
| 542 |
fail_condition:
|
| 543 |
any_of:
|
| 544 |
- not: {own_units_gte: 1}
|
| 545 |
-
- after_ticks:
|
| 546 |
hard:
|
| 547 |
description: >
|
| 548 |
Rush Hour Sweep \u2014 hard. The agent force already round-robins
|
|
@@ -552,9 +552,9 @@ levels:
|
|
| 552 |
win_condition:
|
| 553 |
all_of:
|
| 554 |
- units_killed_gte: 9
|
| 555 |
-
- within_ticks:
|
| 556 |
- units_lost_lte: 3
|
| 557 |
fail_condition:
|
| 558 |
any_of:
|
| 559 |
- not: {own_units_gte: 1}
|
| 560 |
-
- after_ticks:
|
|
|
|
| 523 |
win_condition:
|
| 524 |
all_of:
|
| 525 |
- units_killed_gte: 5
|
| 526 |
+
- within_ticks: 3603
|
| 527 |
- units_lost_lte: 6
|
| 528 |
fail_condition:
|
| 529 |
any_of:
|
| 530 |
- not: {own_units_gte: 1}
|
| 531 |
+
- after_ticks: 3603
|
| 532 |
medium:
|
| 533 |
description: >
|
| 534 |
Rush Hour Sweep \u2014 medium. Tighter clock and attrition cap:
|
|
|
|
| 537 |
win_condition:
|
| 538 |
all_of:
|
| 539 |
- units_killed_gte: 7
|
| 540 |
+
- within_ticks: 3603
|
| 541 |
- units_lost_lte: 4
|
| 542 |
fail_condition:
|
| 543 |
any_of:
|
| 544 |
- not: {own_units_gte: 1}
|
| 545 |
+
- after_ticks: 3603
|
| 546 |
hard:
|
| 547 |
description: >
|
| 548 |
Rush Hour Sweep \u2014 hard. The agent force already round-robins
|
|
|
|
| 552 |
win_condition:
|
| 553 |
all_of:
|
| 554 |
- units_killed_gte: 9
|
| 555 |
+
- within_ticks: 3603
|
| 556 |
- units_lost_lte: 3
|
| 557 |
fail_condition:
|
| 558 |
any_of:
|
| 559 |
- not: {own_units_gte: 1}
|
| 560 |
+
- after_ticks: 3603
|
|
@@ -67,7 +67,11 @@ levels:
|
|
| 67 |
all_of:
|
| 68 |
- unit_type_count_gte: {type: 3tnk, n: 1}
|
| 69 |
- building_count_gte: {type: fix, n: 1}
|
| 70 |
-
- within_ticks:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
max_turns: 60
|
| 72 |
|
| 73 |
medium:
|
|
@@ -93,7 +97,9 @@ levels:
|
|
| 93 |
- unit_type_count_gte: {type: e3, n: 1}
|
| 94 |
- unit_type_count_gte: {type: e1, n: 3}
|
| 95 |
- power_surplus_gte: 0
|
| 96 |
-
- within_ticks:
|
|
|
|
|
|
|
| 97 |
max_turns: 80
|
| 98 |
|
| 99 |
hard:
|
|
@@ -121,7 +127,9 @@ levels:
|
|
| 121 |
all_of:
|
| 122 |
- enemies_discovered_gte: 2
|
| 123 |
- unit_type_count_gte: {type: e3, n: 5}
|
| 124 |
-
- within_ticks:
|
| 125 |
fail_condition:
|
| 126 |
-
|
|
|
|
|
|
|
| 127 |
max_turns: 90
|
|
|
|
| 67 |
all_of:
|
| 68 |
- unit_type_count_gte: {type: 3tnk, n: 1}
|
| 69 |
- building_count_gte: {type: fix, n: 1}
|
| 70 |
+
- within_ticks: 5403
|
| 71 |
+
# aligned to tick reachable at max_turns (~90/turn); scripted
|
| 72 |
+
# chain wins easy by ~tick 2883 so this stays solvable.
|
| 73 |
+
fail_condition:
|
| 74 |
+
after_ticks: 5403
|
| 75 |
max_turns: 60
|
| 76 |
|
| 77 |
medium:
|
|
|
|
| 97 |
- unit_type_count_gte: {type: e3, n: 1}
|
| 98 |
- unit_type_count_gte: {type: e1, n: 3}
|
| 99 |
- power_surplus_gte: 0
|
| 100 |
+
- within_ticks: 7203
|
| 101 |
+
fail_condition:
|
| 102 |
+
after_ticks: 7203
|
| 103 |
max_turns: 80
|
| 104 |
|
| 105 |
hard:
|
|
|
|
| 127 |
all_of:
|
| 128 |
- enemies_discovered_gte: 2
|
| 129 |
- unit_type_count_gte: {type: e3, n: 5}
|
| 130 |
+
- within_ticks: 8103
|
| 131 |
fail_condition:
|
| 132 |
+
any_of:
|
| 133 |
+
- after_ticks: 8103
|
| 134 |
+
- unit_type_count_gte: {type: e1, n: 10}
|
| 135 |
max_turns: 90
|
|
@@ -48,6 +48,11 @@ NOT_APPLICABLE = {
|
|
| 48 |
"economy-force-buildup": "non-spatial: production economy",
|
| 49 |
"building-and-planning": "non-spatial: build-order/tech, fixed base",
|
| 50 |
"strict-production-bom": "non-spatial: exact bill-of-materials spec",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
"reasoning-risk-route": "rigor 5/5 from one tuned safe seam — varying "
|
| 52 |
"the start would break the single-solution tuning / seed parity",
|
| 53 |
"strategy-dilemma": "win redesigned to destroy fact+proc (faithful "
|
|
|
|
| 48 |
"economy-force-buildup": "non-spatial: production economy",
|
| 49 |
"building-and-planning": "non-spatial: build-order/tech, fixed base",
|
| 50 |
"strict-production-bom": "non-spatial: exact bill-of-materials spec",
|
| 51 |
+
"tech-production-planning": "non-spatial: build-order dependency "
|
| 52 |
+
"planning (precedence + power + budget); start position irrelevant",
|
| 53 |
+
"longhorizon-opening-to-assault": "fixed pre-seeded base; the test "
|
| 54 |
+
"is the scout→tech→army→strike phase chain within one budget, not "
|
| 55 |
+
"start-position generalization (single base by design)",
|
| 56 |
"reasoning-risk-route": "rigor 5/5 from one tuned safe seam — varying "
|
| 57 |
"the start would break the single-solution tuning / seed parity",
|
| 58 |
"strategy-dilemma": "win redesigned to destroy fact+proc (faithful "
|
|
@@ -75,11 +75,12 @@ def test_easy_tech_chain_wins_and_scores():
|
|
| 75 |
assert "weap" in btypes and "fix" in btypes, (
|
| 76 |
f"chain incomplete; own_building_types={btypes}"
|
| 77 |
)
|
| 78 |
-
# The agent actually trained a Heavy Tank.
|
| 79 |
-
unit_types = [u["type"] for u in res.signals.units_summary]
|
| 80 |
-
assert "3tnk" in unit_types, f"no 3tnk produced; units={unit_types}"
|
| 81 |
# Production debited the budget.
|
| 82 |
assert res.signals.cash < 5000, "construction must debit the budget"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
assert res.outcome == "win", f"easy should be winnable, got {res.outcome}"
|
| 84 |
|
| 85 |
sc = score_episode(c, res)
|
|
@@ -126,6 +127,10 @@ def test_hard_fail_predicate_set():
|
|
| 126 |
it). Schema-level check, no episode run required."""
|
| 127 |
c = compile_level(load_pack(PACK), "hard")
|
| 128 |
assert c.fail_condition is not None
|
| 129 |
-
#
|
|
|
|
|
|
|
| 130 |
fc = c.fail_condition.model_dump(exclude_none=True)
|
| 131 |
-
|
|
|
|
|
|
|
|
|
| 75 |
assert "weap" in btypes and "fix" in btypes, (
|
| 76 |
f"chain incomplete; own_building_types={btypes}"
|
| 77 |
)
|
|
|
|
|
|
|
|
|
|
| 78 |
# Production debited the budget.
|
| 79 |
assert res.signals.cash < 5000, "construction must debit the budget"
|
| 80 |
+
# A win implies a Heavy Tank was trained: the win condition
|
| 81 |
+
# includes `unit_type_count_gte {type: 3tnk, n: 1}`, so outcome ==
|
| 82 |
+
# "win" is itself proof the 3tnk was produced (and observed — this
|
| 83 |
+
# also exercises the own-unit actor_type fix).
|
| 84 |
assert res.outcome == "win", f"easy should be winnable, got {res.outcome}"
|
| 85 |
|
| 86 |
sc = score_episode(c, res)
|
|
|
|
| 127 |
it). Schema-level check, no episode run required."""
|
| 128 |
c = compile_level(load_pack(PACK), "hard")
|
| 129 |
assert c.fail_condition is not None
|
| 130 |
+
# Hard loses on EITHER the timeout (deadline aligned to the tick
|
| 131 |
+
# reachable at max_turns — no draw degeneracy) OR overproducing
|
| 132 |
+
# infantry past 10.
|
| 133 |
fc = c.fail_condition.model_dump(exclude_none=True)
|
| 134 |
+
clauses = fc.get("any_of", [fc])
|
| 135 |
+
assert {"unit_type_count_gte": {"type": "e1", "n": 10}} in clauses, fc
|
| 136 |
+
assert any("after_ticks" in cl for cl in clauses), fc
|