sots-engine/src/app/construction_phase.h
lane-b6 0fcbb69ba5 game/sim + app: ship construction -- the build-queue completion bookkeeping, and S11's sub-pass wired in
game/sim/construction.{h,cpp}: Game::ShipRecords (four per-hull-class arrays plus the
per-design vector, sized by ENUMERATION against the wire, not by what the code touches)
and the completion bookkeeping BuildQueue::ProcessTurn performs -- the per-class built
counter, whose indexed increment has EXACTLY ONE writer in the whole image, and the
find-or-append per-design record keyed by the design's object id. RunSystemConstruction
wraps the point pass and keeps each completion's design id, which the point pass alone
does not report.

game/sim/colony: corrected from the instruction stream -- with points <= 0 the entry test
branches to the epilogue, so the REMOVAL SWEEP IS SKIPPED TOO. Carried as a labelled
hypothesis: no corpus save can reach the state that shows it.

app/construction_phase.{h,cpp}: S11's build-queue sub-pass, reported on its own line
because what blocks it is not what blocks the rest of the colony turn. It is blocked on
the per-system output term for points; it is NOT what the archived ship census waits on.

tests/game_sim/test_construction.cpp: 65 checks, including a corpus oracle the campaign
already owned and had not noticed -- zuul-turn16-noderoute -> zuul-turn17-rollpending is a
real consecutive-turn pair in which six orders complete and one is partially advanced.
The test SOLVES for the point total rather than assuming it, so a non-FIFO order, a
per-order budget or skip-instead-of-stop each falsify it.
2026-09-08 14:39:20 -04:00

58 lines
3 KiB
C++

// S11's build-queue sub-pass, wired to the save shapes.
//
// WHERE IT SITS
// -------------
// `StrategyServer::ProcessTurn` phase 11 walks the systems; each system's own turn runs the
// build queue between the plague pass and the population growth. The engine's S11 already
// runs the parts of the colony turn that need neither the tuning table nor a carrying
// capacity; this is the build-queue part, kept in its own file and reported as its own line
// so its contribution is never folded into S11's other writes.
//
// WHAT IT IS BLOCKED ON, and what it is NOT blocked on
// ----------------------------------------------------
// Two different things, and the campaign had them confused:
//
// * the POINTS. `BuildQueue::ProcessTurn` takes construction points by value. They come
// from the system's output vector -- `out[7]` scaled by the shipyard station bonus, then
// `out[8] = min(out[7], queue demand)` -- which is the per-system output term (roadmap
// item 1). Until that lands this phase has no points to spend and it says so with the
// demand named, rather than inventing a number.
//
// * the ORDERS. On BOTH reference pairs there are none. `turn1-state.sav` and
// `turn2-state.sav` each carry three build queues, one per owned system, and all three
// are empty; every `hbq` is false, so no ship-borne queue exists either; and the only
// `TurnCommands_v5` block is the human's, which is the byte-identical empty one. The
// destroyer the archived turn record counts is built from an order the AI creates
// *during* the turn. So the census leaf `shpt[0]` is blocked on AI order generation, not
// on this phase, and this phase closes nothing on either reference pair by design.
//
// Five of the eleven corpus saves DO carry orders (4, 7, 2, 2 and 1 of them), so the pass is
// exercised the moment the points arrive; the run log reports what it would do on each.
#pragma once
#include <string>
#include <vector>
#include "mars/stream/shapes.h"
namespace sots::app {
struct ConstructionPhaseResult {
int queuesVisited = 0; // systems that carry a build queue at all
int ordersPending = 0; // orders sitting in those queues
int pointsDemanded = 0; // sum of `conleft` over every pending order
int shipsBuilt = 0; // completions this run actually performed
int leafWrites = 0; // save leaves changed (0 while the points are blocked)
int wouldWrite = 0; // leaves a points-fed pass would change
bool blockedOnPoints = false;
std::vector<std::string> notes;
};
// Run the build-queue sub-pass over every system that owns a queue.
//
// `points` is not available from the save, so the pass is driven with zero points and
// reports the demand. Nothing is committed: an order that advanced with no ship behind it
// would leave the save in a state the game never produces, which is worse than not running.
ConstructionPhaseResult RunBuildQueues(mars::stream::shapes::SaveGame& game);
} // namespace sots::app