fix cargo_capacity direction: storage competes with cargo, doesn't pad it

cargo_capacity was based on floor_total (platform+actuator+storage), so
more battery/fuel made cargo capacity go UP -- backwards. Real deadweight
tonnage is a fixed allowance sized off the vessel's own empty (lightship)
mass -- hull + machinery, not fuel -- and fuel and cargo then SHARE that
one allowance: more fuel bunkered means less room left for cargo. Cargo
capacity is now (platform+actuator)*ratio - storage_mass, floored at 0,
so reducing battery/fuel now correctly frees up cargo room instead of
shrinking it.

Confirmed on combo #876: at the battery's declared 9kg floor, cargo is
6.3kg; increasing to 15kg drops it to 0.3kg, to 30kg+ drops it to 0 --
storage size and cargo capacity now trade off in the right direction.

Re-ran all five domains: urban_commuting's insufficient_structure count
went from 1 to 6 passing combos, since cargo_capacity's changed
incentives shifted where the optimizer lands relative to the structural
cap -- checked each one, all are 0.007-0.033% over the cap, the same
grid-search rounding-noise magnitude already established as acceptable,
just now triggered on a few more combos.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-15 20:35:48 -05:00
parent f786f3da79
commit fb38093e6c

View File

@@ -932,12 +932,12 @@ class Pipeline:
platform's representative mass (ctx.p_rep) -- pass an explicit
value to explore a specific weight class instead (see
evaluate_allocation). Cargo capacity is derived from THIS build's
actual assembled mass (floor_total below), not a separate
declared-floor constant -- a deadweight/lightship-style ratio of
"how much this vehicle could additionally carry, proportional to
its own (empty of cargo) mass" only makes sense against the mass
it's actually built to, so it responds to the same optimizer/
explore-slider choices every other metric here does."""
actual platform+actuator mass (not a separate declared-floor
constant), with storage_mass subtracted out of that allowance --
see the deadweight/lightship comment at its computation below for
why fuel/battery competes with cargo instead of padding it. It
responds to the same optimizer/explore-slider choices every other
metric here does."""
p_mass = ctx.p_rep if platform_mass is None else platform_mass
out: dict[str, float] = {}
floor_total = p_mass + actuator_mass + storage_mass
@@ -946,14 +946,27 @@ class Pipeline:
if "power_density" in bounds_by_name:
out["power_density"] = power_density_value
# Deadweight/lightship-style cargo capacity, proportional to this
# build's own actual mass -- two conventions coexist because heavy
# freight/maritime vehicles genuinely carry a much larger multiple
# of their own mass in cargo than light personal/delivery vehicles
# do (see CARGO_KG_PER_STRUCTURAL_KG's module comment); which one
# a domain scores is just which metric_name it declares.
cargo_capacity_2_5x = floor_total * CARGO_KG_PER_STRUCTURAL_KG
cargo_capacity_0_3x = floor_total * 0.3
# Deadweight/lightship cargo capacity. Real deadweight tonnage is a
# FIXED allowance sized off the vessel's own empty (lightship) mass
# -- hull + machinery, NOT fuel or cargo -- and fuel and cargo then
# SHARE that one allowance: a ship that bunkers more fuel has that
# much less room left for cargo, and vice versa. platform+actuator
# is the lightship analog here (the vehicle's own hardware);
# storage_mass is the fuel/battery competing with cargo for the
# same pool, not part of the base the pool is sized from -- get
# that backwards (basing the pool on platform+actuator+storage,
# as an earlier version of this did) and more battery looks like it
# BUYS more cargo room instead of using it up. Two ratio
# conventions coexist because heavy freight/maritime vehicles
# genuinely carry a much larger multiple of their own mass in
# cargo than light personal/delivery vehicles do (see
# CARGO_KG_PER_STRUCTURAL_KG's module comment); which one a domain
# scores is just which metric_name it declares. Floored at 0: a
# storage mass bigger than the whole allowance leaves no cargo
# room, not negative room.
lightship_mass = p_mass + actuator_mass
cargo_capacity_2_5x = max(0.0, lightship_mass * CARGO_KG_PER_STRUCTURAL_KG - storage_mass)
cargo_capacity_0_3x = max(0.0, lightship_mass * 0.3 - storage_mass)
if "cargo_capacity" in bounds_by_name:
out["cargo_capacity"] = cargo_capacity_2_5x
if "cargo_capacity_kg" in bounds_by_name: