score-optimize actuator/storage/platform allocation, enforce structural feasibility

The saved composite score previously came from a requirement-solve that
only satisfied the platform's physical performance floor, not the
domain's actual weighted score -- a smaller/cheaper build could always
score higher by hand. _decide_masses now jointly searches platform,
actuator, and storage mass (coarse-to-fine grid, no external deps) to
maximize the domain's real weighted composite score, with the
requirement floor as a lower bound rather than the final answer.

Platform mass specifically was previously fixed at a geometric-mean
representative value, which could be too little structure to carry its
own required actuator+storage (reusing CARGO_KG_PER_STRUCTURAL_KG, the
existing structure-carries-N-times-its-mass ratio, applied to a
platform carrying its own powertrain instead of cargo). Growing
platform mass also raises that structural ceiling, so it has to be
searched jointly rather than fixed or bounded independently.

Because power_density/range_fuel/cost_efficiency are all per-kg
ratios, none of them naturally penalize a build whose absolute mass
exceeds its own platform's declared ceiling -- a Piston Engine sized
for a Hyperloop could still score well on a Light Personal Vehicle.
Pass 2 now detects genuine infeasibility (no platform mass within its
own declared ceiling can structurally carry the required floor) and
saves it as a per-domain block instead of a misleadingly good score.

Also adds an explore-panel warning (not a hard block, since exploration
is intentionally loose) when a manually-dragged slider build exceeds
the platform's mass ceiling or structural carrying capacity.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-15 18:59:20 -05:00
parent 76f460499a
commit d871635779
6 changed files with 742 additions and 139 deletions

View File

@@ -69,6 +69,12 @@ def test_blocked_combos_not_scored(seeded_repo):
score_threshold=0.0, passes=[1, 2, 3, 5],
)
# Estimated count should be less than total (blocked ones filtered)
# Estimated count should be less than total (blocked ones filtered).
# Not necessarily equal to pass1_valid + pass1_conditional: a combo can
# pass pass 1's entity-declared-floor checks but still turn out
# structurally infeasible once pass 2 solves the domain-specific
# actuator/storage requirement (e.g. an engine too big to fit its own
# platform's declared mass ceiling) -- that's a legitimate per-domain
# block, not a bug (see Pipeline._decide_masses' `feasible` return).
assert result.pass2_estimated < result.total_generated
assert result.pass2_estimated == result.pass1_valid + result.pass1_conditional
assert result.pass2_estimated <= result.pass1_valid + result.pass1_conditional