close guardrail gaps and fix the scoring pipeline top to bottom

Constraint resolver: aggregate mass/footprint across a combo instead of
pairwise-only checks, treat medium/atmosphere as agreement not supply/demand,
reduce multi-provider checks by best/sum instead of AND-ing every provider,
fail closed on unrecognized mutex values, add a propulsion-viability
(thrust-to-weight) rule. Seed data updated to match (nuclear/solar-sail
footprint floors, water-medium exclusions, explicit ground/gravity providers).

Domain metric units were stored globally per metric name instead of
per-domain, silently corrupting cost_efficiency for every domain but the
first one seeded — fixed with a schema migration.

Stub estimator's cost_efficiency/safety/availability/reliability were a
backwards formula and flat constants; replaced with heuristics grounded in
each entity's thrust_profile/energy_form/infrastructure.

LLM estimate_physics() now receives each metric's unit and expected range
instead of a bare name, fixing wildly miscalibrated estimates traced back to
the prompt's own hardcoded example anchoring the model to the wrong order of
magnitude. Sharpened the safety-estimation and plausibility-review prompts.
Deduped provider parsing logic into llm/parsing.py.

Web pipeline form can now pick an LLM provider per run instead of only via
server env var.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 00:13:16 -05:00
parent 63295ab80e
commit 434df718d7
18 changed files with 836 additions and 175 deletions

View File

@@ -160,3 +160,231 @@ def test_domain_constraint_allows_matching_medium(bicycle, human_pedalling, food
constraints = [DomainConstraint("medium", ["ground", "air"])]
result = resolver.check_domain_constraints(combo, constraints)
assert result.status == "valid"
def _rotorcraft():
return Entity(
name="Rotorcraft", dimension="platform",
dependencies=[
Dependency("physical", "footprint", "20", "", "range_max"),
Dependency("physical", "footprint", "0.5", "", "range_min"),
Dependency("physical", "mass", "5000", "kg", "range_max"),
Dependency("physical", "mass", "1", "kg", "range_min"),
],
)
def _spaceship_with_footprint():
return Entity(
name="Spaceship", dimension="platform",
dependencies=[
Dependency("physical", "footprint", "500", "", "range_max"),
Dependency("physical", "footprint", "10", "", "range_min"),
Dependency("physical", "mass", "5000", "kg", "range_min"),
],
)
def _nuclear_thermal_drive_with_footprint():
return Entity(
name="Nuclear Thermal Drive", dimension="actuator",
dependencies=[
Dependency("physical", "footprint", "20", "", "range_min"),
Dependency("physical", "mass", "1500", "kg", "range_min"),
],
)
def _nuclear_fuel_with_footprint():
return Entity(
name="Nuclear Fuel", dimension="energy_storage",
dependencies=[
Dependency("physical", "footprint", "5", "", "range_min"),
Dependency("physical", "mass", "500", "kg", "range_min"),
],
)
def test_footprint_aggregation_blocks_reactor_on_rotorcraft():
"""P1: individual footprint floors each fit under the ceiling (20, 5 <= 20)
but their sum (25.5) doesn't — must block even though no single component
exceeds the ceiling on its own."""
resolver = ConstraintResolver()
combo = Combination(entities=[
_rotorcraft(), _nuclear_thermal_drive_with_footprint(), _nuclear_fuel_with_footprint(),
])
result = resolver.resolve(combo)
assert result.status == "p1_fail"
assert any("combined footprint" in v for v in result.violations)
def test_footprint_aggregation_still_passes_spaceship():
"""Same reactor + fuel, but a platform with enough footprint budget (500 m²)
must still pass — aggregation shouldn't over-block combos with real headroom."""
resolver = ConstraintResolver()
combo = Combination(entities=[
_spaceship_with_footprint(), _nuclear_thermal_drive_with_footprint(), _nuclear_fuel_with_footprint(),
])
result = resolver.resolve(combo)
assert result.status != "p1_fail"
assert not any("footprint" in v for v in result.violations)
def test_mass_aggregation_within_tolerance_warns_not_blocks():
"""Sum only slightly over the ceiling (65 vs 60, +8.3%) is a data-calibration
signal, not a hard physical impossibility — should warn, not block."""
platform = Entity(
name="Light Personal Vehicle", dimension="platform",
dependencies=[
Dependency("physical", "mass", "60", "kg", "range_max"),
Dependency("physical", "mass", "5", "kg", "range_min"),
],
)
actuator = Entity(
name="Piston Engine", dimension="actuator",
dependencies=[Dependency("physical", "mass", "45", "kg", "range_min")],
)
storage = Entity(
name="Compressed Natural Gas", dimension="energy_storage",
dependencies=[Dependency("physical", "mass", "15", "kg", "range_min")],
)
resolver = ConstraintResolver()
result = resolver.resolve(Combination(entities=[platform, actuator, storage]))
assert result.status == "conditional"
assert any("combined mass" in w for w in result.warnings)
def test_weak_secondary_provider_does_not_block_satisfied_requirement():
"""P3: a strong provider (nuclear fuel) already satisfies the requirement;
a weak secondary provider (solar panel) in the same combo must not
retroactively block it — a real backup power source shouldn't break a
vehicle that already has enough primary power."""
platform = Entity(
name="Spaceship", dimension="platform",
dependencies=[Dependency("physical", "energy_density", "7200000", "J/kg", "range_min")],
)
nuclear_fuel = Entity(
name="Nuclear Fuel", dimension="energy_storage",
dependencies=[Dependency("physical", "energy_density", "1800000000", "J/kg", "provides")],
)
solar_panel = Entity(
name="Solar Photovoltaic Panel", dimension="energy_storage",
dependencies=[Dependency("physical", "energy_density", "180000", "J/kg", "provides")],
)
resolver = ConstraintResolver()
result = resolver.resolve(Combination(entities=[platform, nuclear_fuel, solar_panel]))
assert result.status != "p1_fail"
assert not any("energy_density" in v for v in result.violations)
def test_unrecognized_mutex_value_fails_closed():
"""P4: a value not in any registered mutex set (e.g. a new 'medium' typed
into the admin UI) must conflict with a recognized value on the same key,
not silently pass."""
a = Entity(
name="A", dimension="platform",
dependencies=[Dependency("environment", "medium", "underground", None, "requires")],
)
b = Entity(
name="B", dimension="actuator",
dependencies=[Dependency("environment", "medium", "space", None, "requires")],
)
resolver = ConstraintResolver()
result = resolver.resolve(Combination(entities=[a, b]))
assert result.status == "p1_fail"
assert any("mutually exclusive" in v for v in result.violations)
def test_propulsion_viability_blocks_weak_actuator_regardless_of_scale():
"""G4: specific_thrust below min_effective_accel can never be fixed by
adding more actuator mass — must block unconditionally (Case 1)."""
platform = Entity(
name="Rotorcraft", dimension="platform",
dependencies=[
Dependency("physical", "mass", "5000", "kg", "range_max"),
Dependency("physical", "min_effective_accel", "10", "m/s²", "range_min"),
],
)
actuator = Entity(
name="Ion Drive", dimension="actuator",
dependencies=[
Dependency("physical", "mass", "8", "kg", "range_min"),
Dependency("force", "specific_thrust", "0.01", "N/kg", "provides"),
],
)
resolver = ConstraintResolver()
result = resolver.resolve(Combination(entities=[platform, actuator]))
assert result.status == "p1_fail"
assert any("regardless of scale" in v for v in result.violations)
def test_propulsion_viability_blocks_when_required_mass_exceeds_ceiling():
"""G4 Case 2: specific_thrust clears min_effective_accel, but the mass
needed to hit that thrust doesn't fit the vehicle's mass budget."""
platform = Entity(
name="Test Platform", dimension="platform",
dependencies=[
Dependency("physical", "mass", "50", "kg", "range_max"),
Dependency("physical", "mass", "10", "kg", "range_min"),
Dependency("physical", "min_effective_accel", "5", "m/s²", "range_min"),
],
)
actuator = Entity(
name="Weak Reaction Drive", dimension="actuator",
dependencies=[
Dependency("physical", "mass", "1", "kg", "range_min"),
Dependency("force", "specific_thrust", "6", "N/kg", "provides"),
],
)
storage = Entity(
name="Fuel", dimension="energy_storage",
dependencies=[Dependency("physical", "mass", "1", "kg", "range_min")],
)
resolver = ConstraintResolver()
result = resolver.resolve(Combination(entities=[platform, actuator, storage]))
assert result.status == "p1_fail"
assert any("would need >=" in v for v in result.violations)
def test_propulsion_viability_passes_with_enough_budget():
"""Same shape as above but with a generous mass ceiling — must pass."""
platform = Entity(
name="Test Platform", dimension="platform",
dependencies=[
Dependency("physical", "mass", "5000", "kg", "range_max"),
Dependency("physical", "mass", "10", "kg", "range_min"),
Dependency("physical", "min_effective_accel", "5", "m/s²", "range_min"),
],
)
actuator = Entity(
name="Weak Reaction Drive", dimension="actuator",
dependencies=[
Dependency("physical", "mass", "1", "kg", "range_min"),
Dependency("force", "specific_thrust", "6", "N/kg", "provides"),
],
)
storage = Entity(
name="Fuel", dimension="energy_storage",
dependencies=[Dependency("physical", "mass", "1", "kg", "range_min")],
)
resolver = ConstraintResolver()
result = resolver.resolve(Combination(entities=[platform, actuator, storage]))
assert not any("specific thrust" in v or "would need" in v for v in result.violations)
def test_propulsion_viability_skips_when_undeclared(bicycle, human_pedalling, food_calories):
"""Platforms/actuators that never declare min_effective_accel or
specific_thrust (most of the catalog, for now) must be unaffected."""
resolver = ConstraintResolver()
result = resolver.resolve(Combination(entities=[bicycle, human_pedalling, food_calories]))
assert not any("specific thrust" in v or "would need" in v for v in result.violations)
def test_agreement_key_reaches_valid_status(bicycle, human_pedalling, food_calories):
"""P2: medium/atmosphere are agreement keys, not supply/demand — a combo
with no other issues should reach 'valid', not get stuck at 'conditional'
forever because nothing 'provides' medium=ground."""
resolver = ConstraintResolver()
result = resolver.resolve(Combination(entities=[bicycle, human_pedalling, food_calories]))
assert result.status == "valid"
assert not any("medium" in w for w in result.warnings)