A bundle of small rules-vs-engine corrections:
- Science proportions: accept a sum that equals 1 only up to float
rounding (was an exact != 1 comparison); the rules example is reworded
so it is unambiguous that proportions are fractions summing to 1.
- Generation: super-big planets get a resource strictly above 0 (minimum
0.001, was a hard 0.1); the rules table is fixed for big planets (1-10,
not 0.1-10) and the false "0.1-20 / average 1.5" resource claim removed.
- Dismantle over a neutral planet now unloads the colonists and settles
it (the planet becomes the race's); over a foreign planet they are
still lost. The rules clause is clarified for own / neutral / foreign.
- Report: ship-production entries are written at the compacted report
index (was the planet's map index, which could write past the grown
slice and panic); the incoming-group "remaining distance" is measured
from the group's current hyperspace position, not its origin planet
(matching OtherGroup).
- validator: the cargo-value error now carries the cargo value, not the
shields value.
Tests added for each behavioural fix; rules.txt updated in the same patch.
Validation of a player's order now applies every command against a
transient game-state snapshot and records the per-command outcome
(cmdApplied, cmdErrorCode) in each command's meta. The order is
persisted even when some commands are rejected, and the response is
202 + UserGamesOrder so clients can surface the partial failure
without the chain collapsing into "downstream service is unavailable".
Pkg/error consts are reshelved onto three explicit ranges with a
package doc and helpers (IsInternalCode/IsInputCode/IsGameStateCode):
1xxx internal/server (500/501), 2xxx structural input (400), 3xxx
game-state per-command rejection (400 when escaping HTTP, otherwise
recorded as cmdErrorCode). Two pre-existing typos fixed mechanically
(ErrBeakGroupNumberNotEnough -> ErrBreakGroupNumberNotEnough,
ErrRaceExinct -> ErrRaceExtinct) along with all callsites.
Engine errorResponse maps *GenericError by shelf rather than mapping
everything to 500. The Quit-not-last structural check in
Controller.ValidateOrder is preserved and its type assertion fixed
(was a value assertion against a pointer-typed command, so the check
silently never fired).
Backend, gateway and UI are unchanged — they were already correct on
the 202 path; only the engine collapsing per-command rejection into
500 was needed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>