The tail's last phase archives a per-player record whose 13 modelled fields were 7. The six ship counts join them: every player's designs (normal and legacy, one id space) are classified against the section catalog, and the global fleet list is walked keyed by Flt.PID against each player's OBJECT id, not its vector position. The census cannot come from a save. A design's hull size and its defence-platform flag are recomputed from the section catalog whenever the design changes and are never written down, so the standalone grows a data root -- `--data DIR`, or $SOTS_DATA_DIR. No game data is embedded, and without a root the six counters report themselves unmodelled instead of being written as six zeros that a wrong model would also produce. `--commit-blocked=IDS` and `--commit-blocked-except=IDS` narrow the commit switch to named phase ids. All-or-nothing across every blocked phase reports one closed count and one regressed count for all of them at once, which is the netting the campaign does not do. MEASURED, closed and regressed never netted, state_checksum leaves: turn1 -> turn2 default 209 -> 204 closed 5 regressed 0 (unchanged) turn1 -> turn2 --commit-blocked=T36 no data closed 29 regressed 9 turn1 -> turn2 --commit-blocked=T36 with data closed 29 regressed 7 turn2 -> turn3 default 108 -> 103 closed 5 regressed 0 (unchanged) turn2 -> turn3 --commit-blocked=T36 with data closed 13 regressed 7 The prediction written before the code said the regressed list would fall to 6 and 8 under a full --commit-blocked. It fell to 7 and 9. The prediction's first falsification case is what happened: two census leaves closed and the third did not, because the census is of the fleet list as it stands and no phase the standalone runs creates a ship. The archived count is higher than ours by exactly one destroyer on BOTH pairs for the one player whose build queue completes that turn, while the self-check on the input turn is exact. That leaf is short by the turn's construction, not wrong about classification. app_test_turn_record now compares the six counters against the record the game archived: 11 saves, 80 player-records, 1040 fields, 480 of them census leaves, 0 mismatches. That is lane D2's 480/480 reproduced through this code path, which visits a design's slots in the original's in-memory order (mission, command, engine) rather than the wire's. T36 stays Blocked, and on two named things, neither of them in this phase: sav and inc come from P01/P02, blocked on the per-system money output; and shpt[0] is short by the ships the turn builds. The archived record is one struct on the wire, so those words cannot be left out while the rest is written -- committing is all-or-nothing at the record, and there is no field-granular knob that could change that. Seven confidently-wrong leaves are not worth 29 that later lanes close for free. COVERAGE, as loudly as the verdict: only 32 of the 480 archived census leaves are nonzero anywhere in the corpus -- per leaf (cls0 shpt/satt, cls1 shpt/satt, cls2 shpt/satt) = 18/3, 0/0, 11/0. cls1 entirely and satt for cls2 have never been observed nonzero: three of the six counters are unexercised hypotheses. The four loss/kill words of each group are zero throughout and are written as zeros with no model behind them. Hull size is an assignment in slot order, and design rule A6 means no save can tell the memory order from the wire order. verified stays 0: nothing here was compared against a running game. Gates, separately: clean_room_check OK; host ctest 45/45 without SOTS_SAVES_DIR and 45/45 with it. No src/shim file touched; the shim cross-build was NOT run (no i686 mingw here).
28 lines
1.1 KiB
CMake
28 lines
1.1 KiB
CMake
# src/app — the standalone: load a save, run one strategic turn, write a save.
|
|
# Included from the root CMakeLists.txt via add_subdirectory(src/app).
|
|
#
|
|
# The turn logic is a library so the test can drive it in process; `sots_turn` is the CLI.
|
|
|
|
add_library(sots_app STATIC
|
|
alliance.cpp
|
|
phase_catalog.cpp
|
|
trade_raid.cpp
|
|
turn_record.cpp
|
|
turn.cpp
|
|
report.cpp)
|
|
target_include_directories(sots_app PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..)
|
|
# game_design (and game_data under it) is here for one phase only: the tail's turn record
|
|
# needs a design's hull size and defence-platform flag, which are recomputed from the section
|
|
# catalog and are nowhere on the wire. No game data is embedded; the root is supplied at run
|
|
# time and its absence costs exactly six fields.
|
|
target_link_libraries(sots_app PUBLIC mars_stream mars_rng sots_game_sim game_design)
|
|
target_compile_features(sots_app PUBLIC cxx_std_17)
|
|
if(NOT MSVC)
|
|
target_compile_options(sots_app PRIVATE -Wall -Wextra -Werror)
|
|
endif()
|
|
|
|
add_executable(sots_turn main.cpp)
|
|
target_link_libraries(sots_turn PRIVATE sots_app)
|
|
if(NOT MSVC)
|
|
target_compile_options(sots_turn PRIVATE -Wall -Wextra -Werror)
|
|
endif()
|