A manifest-wide search for INLET, OUTLET and VESSEL returns exactly two
names: COOLANT_CORE_QUANTITY_IN_VESSEL and COOLANT_CORE_VESSEL_TEMPERATURE.
There is no reactor vessel inlet temperature variable and no outlet
temperature variable anywhere in the manifest.
This is not a hypothetical gap. The in-game gauge for VESSEL INLET TEMPERATURE is what the human operator actually uses to make primary-pump- speed decisions; one such adjustment was made specifically because "vessel inlet temp is too high," read straight off that gauge, on a plant where the API has no variable of that name to offer in its place.
COOLANT_CORE_VESSEL_TEMPERATURE is the closest named thing the API exposes,
and tools/monitor.py now carries it alongside CORE_TEMP (see
value-semantics.md, section 14). It is not proven to be
the same signal as vessel inlet temperature. Measured so far it reads byte
identical to CORE_TEMP, which if anything suggests it may be neither the
inlet reading nor a distinct measurement at all, rather than confirming it as
a stand-in.
State the consequence plainly: an advisory client built on this API cannot see the variable the operator is actually steering by, and an autonomous controller would be operating without an instrument the operator considers primary. This is the same pattern already documented elsewhere in this repository for other balance-of-plant thresholds, the pressurizer heater cutoff and the SG low-low level trip among them: the real threshold lives on an in-game gauge or in operator judgement, not in anything the API exposes. See protection-system.md, "The calibration gap".
The in-game "Efficiency Factor" gauge read 87.47 at capture time, and there
is no API variable for it.
This is provable, not merely a failed search. An exhaustive scan of all 332
readable GET variables at multiple scales, plus the contents of every JSON
payload the API serves, found nothing matching. And the manifest is
complete with respect to the game's own advertised variable list: 388 of
388 names accounted for both directions, see
../tools/check_manifest.py. That is not the
same claim as "the webserver serves nothing outside the manifest": this
repository documents 55 valve identifiers the webserver actually serves
outside it, with 0 overlap against the 332 GET plus 91 POST names (see
valves.md), so the manifest is provably complete only against
the game's own advertised list, not against everything the webserver can be
made to return. That narrower completeness is still what turns "nothing
matched" into a real instrumentation gap instead of a documentation
failure. A search that might have missed a name proves nothing; a search
that is checked complete against the advertised list does.
This is plausibly 100 minus a wear percentage, but 12.53 itself is not
a measured value. It is back-computed from the hypothesis:
100 - 87.47 = 12.53. No component was observed at 12.53 percent wear
anywhere in this session's data. Describing it as sitting among the wear
values maintenance_summary reported would imply it was observed; it was
not. It is the number the hypothesis requires for the subtraction to come
out even, nothing more.
The wear values that were observed in maintenance_summary (15.91,
13.79, 13.04, 19.29, see diagnostics-endpoint.md)
came from a capture with age_minutes 1431, roughly 23 game-hours stale by
the time it was read. A reading that old cannot confirm or refute a live
gauge value regardless of what it says, so those four numbers cannot be used
to test the 12.53 hypothesis either way. This is a genuine weakness in the
hypothesis, not a footnote: the one piece of maintenance data available to
check against it is too stale to check anything against, and the figure the
hypothesis actually needs was never independently observed at all.
Label this an unconfirmed hypothesis fitted to a single observation, and
treat it that way. One observation cannot identify a formula: a
brute-force search over variable pairs returned 74 spurious matches at a
0.05 tolerance, including a pressurizer temperature divided by a pump
status code. Nothing about that search distinguishes a real formula from
coincidence, it only shows that at this tolerance, coincidence is common.
The 100 - 12.53 match is not stronger evidence than any of those 74, it
is simply the one that happens to have a plausible-sounding story attached.
This is the second operator-critical, API-invisible signal, after reactor vessel inlet temperature above. State the consequence plainly: an advisory client built on this API cannot see two of the signals the operator actually steers by.
VALVE_M01_OPEN, VALVE_M02_OPEN and VALVE_M03_OPEN are GET-only
telemetry for the plant's manual hand valves.
They are in the 332-entry GET list, absent from the 91-entry POST list, and absent from the 55-entry valve panel. There is no API path to actuate them. You can read their position and nothing else.
This closes a question that consumed two full sessions of probing.
The general rule: anything in the GET list with no POST counterpart and no valve panel entry is instrumentation, not a control surface. Temperatures, pressures, flow rates, and the rest of the sensor set are all in this category.
Seven community clients were read at source level and cross-referenced against the manifest. 36 harvested write-names did not exact-match the 91-entry POST list. Of those:
- 29 are valve identifiers. Expected, and they are what revealed the indirection documented in valves.md. Not a discrepancy.
- 4 are template placeholders (
MSCV_{n}_OPENING_ORDERED,RESISTOR_BANK_#{num}_SWITCH) where the harvester left the interpolation syntax unexpanded. They resolve cleanly to already-matched numbered instances. - 1 is the
FUN_DECERASE_INTEGRITYtypo, covered in fun-family.md.
That leaves two genuine cases:
| Name | Client | Assessment |
|---|---|---|
FREIGHT_PUMP_CONDENSER_ACTIVE |
nathanctech | RESOLVED 2026-07-28: not writable. POSTing it returns HTTP 404 (The writable variable ... does not exist.) for both True and 1. A positive control on _SWITCH in the same run worked and carried _ACTIVE with it. So _ACTIVE is purely the read-back twin, auto_nuke has it right (auto_nuke:api/pumps.ex:59-60), and nathanctech's POST at Condenser.cs:56 is a client bug whose code path has never worked. |
ROD_BANK_{bank}_{rod}_POS |
nathanctech | Structurally different from the manifest's ROD_BANK_POS_{n}_ORDERED: two-dimensional bank-and-rod addressing, no _ORDERED suffix. Either a stale API surface the client was written against, or a naming error. Not present in the current manifest in this form. |
That question is now settled, and it settles a larger one: the manifest is ground truth for the writable surface. It was the only outstanding candidate for the live API being wider than the game advertises, and it is not writable. Everything in this repository that treats the manifest as authoritative stands.
This is the genuinely unexplored frontier. These appear in the manifest's POST list and no surveyed client reads or writes them.
CORE_SCRAM_BUTTON EMERGENCY_GENERATOR_1_START_STOP
CORE_EMERGENCY_STOP EMERGENCY_GENERATOR_2_START_STOP
CORE_END_EMERGENCY_STOP EMERGENCY_GENERATOR_1_MODE (read-observed)
STEAM_TURBINE_TRIP EMERGENCY_GENERATOR_2_MODE (read-observed)
RESET_AO EMERGENCY_BATTERIES_MODE (read-observed)
FUN_WEATHER_CONTROL FUN_FIRE_DRILL
FUN_DECREASE_INTEGRITY (correct spelling; only the typo variant is used)
Three of them (EMERGENCY_GENERATOR_1_MODE, EMERGENCY_GENERATOR_2_MODE,
EMERGENCY_BATTERIES_MODE) have read-observed enum values from mct_nuke and
nuclearesOA even though no client writes them.
10 of these 13 have now been live-tested, with results in
emergency-controls.md. Nine resolved. The remaining
untested three are the FUN_* members, deliberately left alone because the
in-game consent gate was declined.
Notably, no client uses CORE_SCRAM_BUTTON at all. Every one of them emulates a
scram by posting RODS_ALL_POS_ORDERED=100
(nathanctech:Settables/General.cs:13). The dedicated scram endpoint was
entirely unexplored territory until it was tested here, and it works.
Stated plainly so nobody mistakes absence for completeness.
Value ranges are unconfirmed for 9 variables.Closed 2026-07-28. All 16 instances across 6 families were swept. The finding is that the question was malformed: there is no API-side range validation at all._ORDEREDstores raw values including negatives and 1000, and clamping happens at the actuator. See value-semantics.md.CORE_OPERATION_MODE's non-shutdown enum is disputed. auto_nuke writesNOMINAL, GHXX readsMAXIMUM. The manifest gives no enum. Unresolved, and flagged rather than guessed. A live read at build V 2.2.25.220 returnedNOMINAL, which supports auto_nuke but does not rule outMAXIMUMbeing a separate valid mode.- The decimal-comma locale hazard is untested. See wire-format.md.
- Three pressure variables have unreliable attribution from the emergency probe harness, due to the disclosed null-probe aliasing bug.
- The
FUN_*effects are undocumented in detail because the family was never enabled. Effects listed in fun-family.md are inferred from names and client comments, not observed.
Ranked by value per unit of effort.
Three of the original five are now closed. Struck through with their outcomes, so the record shows what was asked and what came back.
-
Test whetherClosed: it does not, HTTP 404. Manifest confirmed as ground truth.FREIGHT_PUMP_CONDENSER_ACTIVEaccepts writes. -
Establish the generator 1 versus generator 2 asymmetry.Closed: generator 2 hadFUEL = 0. Plant state, not an API defect. -
Brute-forceClosed as negative: 12 values tried, none set it, against a verified working harness. Appears not to be settable in practice.EMERGENCY_BATTERIES_MODE's enum. -
ConfirmClosed as negative: no change inRESET_AO.AO_AGENT_STATUSorPOWER_FROM_EXTERNAL_KWagainst a matched null.AO_AGENT_STATUSreportsruntime_state: NoInstaladoanddlc_installed: false, so there is no agent to reset. The earlier 60 kW delta was coincidence.Qualify this, do not generalise it. "No agent to reset" is true of the AO's LLM runtime specifically. It is not true of
AO_AGENT_DIAGNOSTICS_JSONas a whole: that endpoint'smaintenance_summarysection returnsavailable: true,status: ready, and real per-component data, in the same payload whereAO_AGENT_STATUSreportsdlc_installed: false. The maintenance journal runs without the DLC. Only the conversational agent is absent. See diagnostics-endpoint.md, "Gotcha: it works with the AO DLC uninstalled".
Still open, ranked by value per unit of effort:
Re-runClosed 2026-07-28: it works. Signature isSTEAM_TURBINE_TRIPunder exclusive control.STEAM_TURBINE_{n}_PRESSUREdropping to 1. Coastdown is exactly -1.00 Hz/s. It does not trip the reactor. See emergency-controls.md.- Determine whether
CORE_SCRAM_BUTTONandCORE_EMERGENCY_STOPdiffer internally. Indistinguishable through the API. - Measure the integrity-to-leak relationship directly. The game states
<70%integrity causes continuous bleed. Nobody has measured the rate, or established whether it is pressure only or mass as well. Requires a vessel below 70% and a clean inventory recording from t=0. ProbeClosed 2026-07-28: both are genuine rated-output constants. 400 and 1200 respectively, held constant across repeated sampling, ratio exactly 3.000 against this plant's three secondary loops. Only one turbine is installed (POWER_MAX_THEORETICAL_PLANT_OUTPUT_MWandPOWER_MAX_THEORETICAL_FINAL_PLANT_OUTPUT_MW.STEAM_TURBINE_2_INSTALLEDis the only one readingTrue), so 400 is this plant's rated output in its installed configuration, the correct denominator for a percent-of-rated-power calculation here. 1200 is the full three-loop buildout. Two honest limits remain: it is not proven that 400 tracks installed equipment rather than being a fixed per-loop constant, and these are electrical MW, not the thermal MW the real P-7 permissive is defined against, so any gate built on 400 is a proxy and must be labelled as one.POWER_FROM_TURBINE_KWturned out not to be usable as a cross-check at all, it does not track generation. See value-semantics.md.
An earlier version of this work recorded that pressure "falls about 0.2 bar every 5 to 10 seconds with no command issued", and treated that as a property of the simulation.
It is not. A 140-sample read-only capture over 280 simulated seconds found
CORE_PRESSURE, PRESSURIZER_PRESSURE and PRESSURIZER_PRESSURE_DEVIATION
completely static, zero changes, while CORE_TEMP moved on a roughly 2
second step.
The drift is plant-state dependent. It was real when originally measured, during a pressurisation transient, and absent under different conditions.
The consequence for anyone building a probe harness: you cannot calibrate one global settle window and reuse it. Drift rate is a function of plant condition, so every probe has to derive its own baseline from its own matched null, taken adjacent in time. A constant measured in an earlier session is not a constant.
Related: several vessel volumes fill in steps, not smoothly.
VACUUM_RETENTION_TANK_VOLUME was observed holding a value for 10 seconds and
then jumping. Sampling such a signal at a fixed rate and differencing yields a
confident and meaningless rate.
Verified live-probe at build V 2.2.25.220. PRESSURIZER appears 8 times in
the 332-entry GET list and zero times in the 91-entry POST list. Seven
plausible write names were probed and all returned HTTP 404:
PRESSURIZER_HEATERS_ON PRESSURIZER_THERMOSTAT
PRESSURIZER_HEATERS PRESSURIZER_AUTO_THERMOSTAT
PRESSURIZER_HEATERS_SWITCH PRESSURIZER_HEATERS_REQUESTED
PRESSURIZER_HEATER_POWER
You can read pressure, temperature, fill level, integrity, both *_OPERATIVE
references and the heater state. You cannot set any of them.
This is the largest gap in the commandable surface. In a PWR the pressurizer is the primary pressure-control system, so an autonomous controller can observe a pressurizer fault and has no direct means to correct it.
The only indirect path is the actuated valve panel, which does expose
Valvula_Pressurizer_Spray, Valvula_Pressurizer_Vent and
Valvula_Pressurizer_Relief_Vent through the VALVE_OPEN/VALVE_CLOSE/
VALVE_OFF meta-commands.
Safety note on that path: community reports state that an open spray valve degrades pressurizer integrity very quickly while the thermostat is on. Since the thermostat is also not commandable, an automated client cannot establish the precondition that makes spraying safe. Treat the pressurizer spray valve as requiring a human in the loop.