7.2 KiB
The value-domain census: a third of the save format has only ever held one value
Owner / date: integrator · 2026-09-09 · host only, no VM
Instrument: mars::stream::DomainArchive (sots-engine/src/mars/stream/probe.h),
tests/mars_stream/test_domains.cpp, run over the 22-save corpus.
Why this exists
Board row 402 predicted that lane AC's two new saves would break the coverage ratchet: they carry
CnRad, tscr = 253, three rt route records, and a StarFleet whose LocID is a TradeSector id —
the first fleet in the corpus located anywhere but a star.
The prediction was wrong, and being wrong is the finding. Both saves parse --strict clean, round
trip byte-identically, and score 100.0% typed. The ratchet did not move a hair.
The reason is structural, and it is the same shape as the defect the resolver found in lane Z's RNG
ledger. CoverageArchive is indexed by shape: it asks "does a field name this item". Lane Z's
audit was indexed by firing: it asked "did a draw happen here in a state we ran". Both instruments
are sound at what they measure, and both are blind along the axis where the surprises have actually
been coming from. A save can carry content nobody has ever modelled and still score 100%, because the
novelty lands in a field that was already typed. LocID holding a trade-sector id is still a LocID.
So the value-axis companion asks the other question: what has the corpus ever put in this field?
The number
Over 22 saves:
724 field(s) observed: 490 vary, 234 constant across the whole corpus
234 of 724 typed fields — 32% — have been seen holding exactly one value. We call this format
"99.99% typed" and mean it, but for nearly a third of it the typing has never been tested against more
than a single observation. tscr was one of those 234 until Commerce Raiding moved it, and every lane
that read 252 and inferred a fact about the game was reading a fact about our save set (rule 28,
practice 3).
This is rule 23's "thin coverage" with a number on it, and rule 8's eighteen fields generalised: those eighteen split a roster identically because nothing exercised them. There are 234.
Where the constants cluster
| Parent | Constants | Reading |
|---|---|---|
root.Sim.Player |
24 | incl. 11 in dipstats — no corpus game ever ran diplomacy to a treaty |
root.Sim.Sys |
19 | |
root.Sim.SvSctOb.EncObj |
16 | the random-encounter object; no corpus game triggered an encounter |
root.CD |
13 | |
root.Sim.spymgr.spy |
12 | see below — this is lane AS's ground |
root.Summary.Players.Slot |
11 | |
root.CD.CmbR.CRPlSv2.TacReports |
9 | tactical combat reports never populated |
root.Sim.trdmgr.rt |
5 | trade routes — even with AC's three rt records |
Two individually suspicious constants, both non-zero and non-round, i.e. written by something:
root.Sim.spymgr.spy.atto = 3728in all 22 saves.root.Sim.SvSctOb.EncObj.infest.mtrn = 2147483647(INT32_MAX) — a sentinel, almost certainly "no turn scheduled".root.CD.researchBoostFraction = 0.999215constant, withresearchBoostSpend = 216383.
Direct consequence for the lanes now running
Lane AS (the spy half) is looking for the detection roll gated inline in vslot13. The census says
the entire spy sub-object is unexercised: sdet = -1, cbh = 0, cm = 0, cmo = 0, deat = 0,
sdo = 0 in every save we own. sdet = -1 is a sentinel in the position a detection result would
occupy. That is consistent with the gate never having fired in the corpus, and it means the corpus
count for any spy-path predicate is 0 of 22 before AS starts — which is what rule 28 asks a lane to
state before it calls a zero a negative.
Lane AG (the gate-indexed audit) gets a corpus-count column it can compute mechanically rather than by hand: for a decoded predicate over save fields, the census already knows which fields never vary, so any predicate resting on one of the 234 has a corpus count of 0 by construction, and its "unread gate" status is not a matter of opinion.
What the instrument is not
It does not know why a field is constant. .Version is constant because we can only read one format
version; .GameType because every corpus save is single-player. Those two are whitelisted as explained.
The other 234 are unexplained, which is a statement about our reading, not an accusation against the
game. A constant field is a coincidence until its writer is found — the census names the candidates;
it does not resolve them.
It also folds array elements into one domain per field, deliberately: twenty fleets sharing a LocID
kind is the observation we want, not twenty rows.
Ratchet
kVaryingBaseline = 490, on the count of fields with observed variation. Growing the corpus must
exercise more of the format, never less; a drop means a save was removed or a shape stopped being
reached. Raise it deliberately (rule 27). The constant count is printed but not ratcheted — it is not
monotone, since a newly typed body can add constants as easily as it adds variation.
Full list: SOTS_DOMAIN_ALL=1 SOTS_SAVES_DIR=<corpus> mars_stream_test_domains.
Proposed board rows
| the coverage ratchet is blind along the value axis | verify | verified | high | 100% | 2026-09-09 | Board row 402 predicted AC's two saves would break the ratchet. They did not - both score 100.0% typed and round trip byte-identically, because their novelty (LocID at a TradeSector, tscr = 253, three rt records) lands in fields that were already typed. CoverageArchive is indexed by shape, exactly as lane Z's ledger was indexed by firing: both instruments are sound at what they measure and both are blind where the surprises come from. New instrument DomainArchive + test_domains measures the other axis |
| 234 of 724 typed fields have only ever held one value | verify | verified | high | 100% | 2026-09-09 | The census over 22 saves: 724 fields observed, 490 vary, 234 constant across the whole corpus - 32%. tscr was one of the 234 until a one-turn tech moved it. Clusters: Sim.Player.dipstats 11 (no corpus game reached a treaty), SvSctOb.EncObj 16 (no corpus game triggered a random encounter), spymgr.spy 12, CmbR.CRPlSv2.TacReports 9 (tactical reports never populated). Individually suspicious because non-zero and non-round: spy.atto = 3728, EncObj.infest.mtrn = INT32_MAX (a sentinel), CD.researchBoostFraction = 0.999215. This is rule 23's thin coverage with a number on it and rule 8's eighteen fields generalised. Ratchet at 490 varying; see findings/subsystems/value-domain-census.md |
| the spy sub-object is unexercised: 0 of 22 before lane AS starts | verify | verified | high | 100% | 2026-09-09 | Direct input to lane AS. The census reads spymgr.spy.sdet = -1 in all 22 saves, with cbh/cm/cmo/deat/sdo all 0 - sdet = -1 sits in the position a detection result would occupy and is a sentinel. So the corpus count for any spy-path predicate is 0 of 22 before the lane takes a single measurement, which is exactly the statement rule 28 requires before a zero may be called a negative. Also gives lane AG a mechanically computable corpus-count column: a predicate resting on any of the 234 constants has count 0 by construction |