replace stub estimator with a requirement-derived physics engine

pass 2's no-LLM fallback previously used broken/placeholder formulas:
power_density passed an actuator's own intensive W/kg straight through
without scaling by vehicle mass, range_fuel multiplied energy_density by a
flat unitless constant, and cost_efficiency was a categorical guess.

Replaces all three with formulas grounded in each entity's own declared
attributes. Actuator and storage mass are sized to what's actually
necessary -- enough power to sustain a platform's target_velocity against
resistance (or real thrust/accel requirements where already declared, for
aircraft/rocket combos), enough energy to reach the domain's own declared
range ceiling -- solved as a closed-form 2x2 linear system rather than an
invented mass-fraction table. Platform mass uses the geometric mean of its
declared range instead of the bare floor, since a category as broad as
Road Vehicle (50kg-36,000kg) is closer to log-uniformly distributed than
uniformly distributed. cost_efficiency is now real operating cost (energy
price x resistance) plus amortized upfront cost (materials cost by medium
x lifetime distance), replacing the old flat per-energy-form guess.

Also fixes two bugs found while validating the above against real-world
reference values: entities whose power source isn't their own carried mass
(Human Muscle, Solar Sail) degenerated to zero power; and combos blocked
by a domain-specific constraint kept combinations.status stuck at "valid"
forever, which silently miscounted them as passing in two repository
queries (count_combinations_by_status, get_pipeline_summary) even though
the per-domain result row was correctly marked blocked.

Adds target_velocity to platforms that had no declared performance
requirement at all, and raises OllamaLLMProvider's HTTP timeout (120s to
300s) to match observed real review-call latency.

Validated against 4 real-world reference combos (commuter car, bicycle,
delivery drone) and a full 2,970-combination domain run (0 pass-2
failures); all 100 existing tests still pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-15 13:45:01 -05:00
parent 45ad1e8d44
commit be25a837ff
4 changed files with 342 additions and 55 deletions

View File

@@ -24,6 +24,7 @@ GROUND_PLATFORMS: list[Entity] = [
Dependency("physical", "mass", "50", "kg", "range_min"),
Dependency("infrastructure", "road_network", "true", None, "requires"),
Dependency("environment", "medium", "ground", None, "requires"),
Dependency("physical", "target_velocity", "25", "m/s", "provides"),
],
),
Entity(
@@ -41,6 +42,7 @@ GROUND_PLATFORMS: list[Entity] = [
Dependency("physical", "mass", "5", "kg", "range_min"),
Dependency("infrastructure", "road_network", "true", None, "requires"),
Dependency("environment", "medium", "ground", None, "requires"),
Dependency("physical", "target_velocity", "6", "m/s", "provides"),
],
),
Entity(
@@ -58,6 +60,7 @@ GROUND_PLATFORMS: list[Entity] = [
Dependency("physical", "mass", "10000", "kg", "range_min"),
Dependency("infrastructure", "rail_network", "true", None, "requires"),
Dependency("environment", "medium", "ground", None, "requires"),
Dependency("physical", "target_velocity", "30", "m/s", "provides"),
],
),
]
@@ -79,6 +82,7 @@ WATER_PLATFORMS: list[Entity] = [
Dependency("physical", "mass", "100000", "kg", "range_max"),
Dependency("physical", "mass", "30", "kg", "range_min"),
Dependency("environment", "medium", "water", None, "requires"),
Dependency("physical", "target_velocity", "8", "m/s", "provides"),
],
),
Entity(
@@ -94,6 +98,7 @@ WATER_PLATFORMS: list[Entity] = [
Dependency("physical", "mass", "10000", "kg", "range_min"),
Dependency("environment", "medium", "water", None, "requires"),
Dependency("physical", "energy_density", "720000", "J/kg", "range_min"),
Dependency("physical", "target_velocity", "8", "m/s", "provides"),
],
),
]
@@ -118,6 +123,7 @@ AIR_PLATFORMS: list[Entity] = [
Dependency("environment", "medium", "air", None, "requires"),
Dependency("physical", "energy_density", "1440000", "J/kg", "range_min"),
Dependency("physical", "min_effective_accel", "2.0", "m/s²", "range_min"),
Dependency("physical", "target_velocity", "60", "m/s", "provides"),
],
),
Entity(
@@ -135,6 +141,7 @@ AIR_PLATFORMS: list[Entity] = [
Dependency("environment", "medium", "air", None, "requires"),
Dependency("physical", "energy_density", "720000", "J/kg", "range_min"),
Dependency("physical", "min_effective_accel", "10", "m/s²", "range_min"),
Dependency("physical", "target_velocity", "30", "m/s", "provides"),
],
),
Entity(
@@ -214,6 +221,7 @@ FICTIONAL_PLATFORMS: list[Entity] = [
Dependency("physical", "mass", "5000", "kg", "range_min"),
Dependency("infrastructure", "hyperloop_tube", "true", None, "requires"),
Dependency("environment", "medium", "ground", None, "requires"),
Dependency("physical", "target_velocity", "270", "m/s", "provides"), # near-sonic, per its own description
],
),
]
@@ -302,7 +310,7 @@ BIOLOGICAL_ACTUATORS: list[Entity] = [
Dependency("energy", "energy_form", "biological", None, "requires"),
Dependency("physical", "mass", "0", "kg", "range_min"),
Dependency("force", "thrust_profile", "low_continuous", None, "provides"),
Dependency("force", "power_density", "1.5", "W/kg", "provides"),
Dependency("force", "power_density", "5.5", "W/kg", "provides"),
],
),
Entity(