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