21 KiB
Proposed pilot: completion-bearing research replacement
Status: proposed. This is a contract design, not replacement acceptance. Current architecture
owner is Astra pilot architect in the architecture-review role on openai/gpt-5.6-sol;
subsequent implementation and independent verification use distinct campaign executions.
The target is a bounded replacement of Game::TechTree::ProcessResearch, its SetResearched
cascade and required completion callback writes on explicitly certified workloads. Broad research
displacement remains unproved. No new live address, remote deployment or dependency policy is
authorized by this document.
1. Evidence inspected independently (2026-09-09)
Sources: findings/subsystems/research-replace.md; archived CR compare JSON, raw compressed
traces, shim logs and saves; current engine research, tech-effect and event interfaces. Archived
engine build is cr-618ccb1-20260909T131556Z, not the rollout's current source snapshot.
Recomputed SHA-256:
| RE-relative file | bytes | SHA-256 |
|---|---|---|
verify/results/saves/turn3-state.sav |
67219 | 978041acd168b56ed8eb3f5e42e78d5e70eae6e6517d75e659a5eb7ca3d60921 |
verify/results/saves/cr/cr-oracle-endturn.sav |
67212 | e00eed0c03a31d27a81b7470a9dcc9ba08a2ac48c20baeee4f34749164743e3f |
verify/results/saves/cr/cr-oracle-autosave.sav |
67811 | 79df50475a7b83afa927d992b9f030dcf45710f4bda0133b8b1fa4800a72e420 |
verify/results/saves/cr/cr-replace0-autosave.sav |
67511 | 6b51db992b158caa5424d71b2dccf72924af7198b4165bfcfc870e0d438fb6d5 |
verify/results/saves/cr/cr-replace1-autosave.sav |
67537 | 8a4309ee4fe0b3177a2820600b5016c7c256d0f51b065df469ecd0b4f2342235 |
Local reproduction (diagnostic tool exit alone is not an equality verdict):
python3 verify/state-checksum/state_checksum.py verify/results/saves/cr/cr-oracle-autosave.sav verify/results/saves/cr/cr-replace1-autosave.sav --limit 40
This reports 16 exact-bit, unmasked leaf differences. Oracle -> R1: OutMod 1.25 -> 1.1; ConMod[0..2] 0.9 -> 1; ResTNm empty -> IND_Waldo; EvNxID 7 -> 5; events 5/6 absent and turn-bucket count 3 -> 1; observed-tech element 11 absent and count 11 -> 10; BnkPr/BnkEl, RepCur/RepMax and Summary.Checksum differ. These are five primary scalar fields, collection writes/counts and five derived leaves. They are not permission to patch five downstream values.
verify/results/compare/cr-compare.json:289-357 reports partial coverage: three comparisons,
six undeclared spans in one call and eight unmodelled notes. In
verify/traces/cr-R1.jsonl.gz, call 1 is replace, allocation tech 144 / 2898, input turn 4,
order counter 22, observed count 10, roll_pending false, RNG left 413 and CW 4735 (0x127f).
Its RNG digest/index/left are unchanged. Logs verify/results/shim/cr/cr-R1.log:116-118
count one completion and three unlocks, then two zero-point calls. otch_appends=1 counts a
decision; it does not mean an element was constructed live.
Corrections to inherited narrative
- R1 log lines 75-94 show seven drawsite detours and twelve probes in addition to the six sites enumerated in CR findings. Instrumentation is broader than the template-hook config. Every fresh run needs a complete installed-site manifest, not an “exhaustive config” assertion.
- R1 runtime CW is
0x127f, including the research trace argument; initialization prints0x027f. Preserve the full measured word and precision/rounding separately. - Runtime string lookup is already an engine interface (
research_events.h:95-105,app/event_phase.cpp:10-14). The absence of bundled game prose does not establish that originalPostEventis mandatory. Runtime asset loading is a concrete route to investigate. shim/hooks/tech_effects.cpp:354-365already writes player state/design masks and delegates node-bore updates in replace mode. The research hook does not integrate that complete callback; calling the helper “host-tested” is not evidence its full live boundary is implemented.
2. Workloads and access paths
W1 — primary positive workload, exact LOAD route
On a future explicitly leased lab with operator-supplied executable/data paths: restore the hashed turn3 input as the only selected input save; start a fresh process; use Load Game, select the input, enter its lobby/map at Turn 3, then one End Turn to Turn 4. Verify UI/state transitions rather than sleep-and-assume. Preserve both output saves before any reset. Bind save selection, route, process identity, executable hash, assets, shim hash, config and instrumentation to evidence.
Historical predictions to re-certify before measuring candidate results:
- Exactly three research calls, owners 32/496/512 in order, allocations 144:2898, 90:0, 9:0.
- One IND_Waldo completion: progress 5768 -> 7500, state 3 -> 4, turn_researched -1 -> 4, order -1 -> 22, counter 22 -> 23, refund 1166. Flag unchanged.
- Nodes 132/136/142 unlock, costs 10000/16000/8000, available turn 4. Save tree slots are 94/98/104; tech 144 is slot 106. Never equate tech id with serialized slot.
- One full ObservedTech record, two full events (completion followed by unlocked-techs), event next id 5 -> 7; primary effect fields reach oracle values; target clears.
- Zero RNG words in this workload. This is a negative RNG control, not evidence for draws.
W0 — regression control, insufficient for completion acceptance
verify/results/saves/turn2-state.sav, one End Turn via LOAD, reaches the turn3 input above.
This exercises the research pass/overbudget event and a RNG word, but zero completions. Re-certify
its two-process oracle independently and pin its input hash before use. Do not substitute W0
for W1, or use zero-allocation calls as the positive execution threshold.
W2 — path to broader completion evidence (not yet certified)
Select a different, archived completion-bearing input from the unlock continuations, or generate one under an approved lab contract; record the input hash and exact LOAD/continuation route before prediction. Require a different tech/effect family, a positive RNG draw and a second completion that observes the advanced order counter. The existing U/V evidence motivates selection but is not a ready executable workload contract. Separate controls are required for that exact route. Until W2 exists, any accepted pilot claim is restricted to W1 plus its declared regression checks.
3. Full write boundary and responsibilities
| Boundary | Required state / behavior | Existing interface and current gap |
|---|---|---|
| Research pass | all node progress/state/flag writes; signed capped spend and refund accumulator; decay of other Available nodes; RNG state, left and next index | sim::ProcessResearchTurn, ResearchCompletionHook; current CR pass writes live |
| Unlock cascade | node costRP, availability/researched turn, order; tree order counter; child/prerequisite availability; recursive zero-cost completions and ordering | sim::TechGraph / SetResearched; replace cascade opt-in exists, transcription failures can currently skip it |
| Completion callback | target pointer/ResTNm; pending-roll flags; every applicable player economy float, masks, boolean/species flags, design-option masks; node-bore storage/lifetime | ApplyTechCompletion, RunCompletionTail, tfx::ReadPlayerState/WritePlayerState; integrate with research on pre-call inputs, avoid already-researched guard |
| Observed technology | dedup/update semantics, entire 0x2c record (name, first/last turns, detected, with), vector content/count/capacity and allocator ownership | research hook currently alters scratch span only; full live construction and update semantics need evidence |
| Events | complete turn buckets and ordered records: id, summary, message, location, position, image, action, chainId; next id; dedup and pruning; all owned allocations | events::EventStorage, PostResearchPassEvents; research hook is count-only/compare-only; runtime text and live ABI adapter missing |
| Callback outcomes beyond player | owned-system AI flags/caps/addiction/plague; ships' plague state; recursive Zuul tech grants; pending research-event RNG and plague/rebellion consequences including allocations/cancel research | TechApplyOutcome reports work, does not execute it; broader closure remains incomplete |
| Downstream observation | budget/bankruptcy/repair/checksum consequences of primary effects | let ordinary turn processing derive them; full oracle must expose them, never harvest original post-state or hardcode expected leaves |
The W1 observed write set is a subset of this boundary. The complete callback has conditional system/ship/object writes absent on W1. A narrow pilot must preflight its supported class and fail closed before mutating on unsupported branches. Suppressed writes, unavailable graph/text, unknown pointers, unreadable names, failed allocation, or unmodelled fired rolls are blockers, not successful no-ops. General displacement requires separate evidence for all reachable effects.
Events require exact formatting/dedup order, FLT_MAX no-position values, action conversion,
the original prune-window behavior and preexisting event contents. KeylessEventText substitutes
tokens for prose and must never be serialized as a passing oracle. Completion message length
above 255 has an explicitly documented divergence/undefined-original boundary; exclude or resolve
it explicitly. Seed comparisons from pre-call state, not the original callback's output.
4. Inputs and original dependencies
Required immutable input manifest before ready:
- Exact engine and RE baseline commits plus actual source-content hashes; paired worktrees; compiler/toolchain/build flags, host and shim binaries, generated-address provenance.
- The hashed W1 input and oracle archive above, plus selected W0/W2 inputs as applicable.
- Operator-owned game executable and proxy originals with hashes. The archived trace reports exe
SHA-256
970b7de729956a53094c7eb98aba4270aee98e2fed5daf0d39e290013c90c841; remeasure it. - Explicit runtime data root, manifest of tech definitions/graph, tuning/constants/species inputs, localized string-table files and locale/encoding/load order. Existing parser data must come from user assets, not copies of game prose embedded in source. Missing table/key is not empty text for acceptance. Asset paths and hashes are not yet supplied for this pilot.
- Full configs and actually installed interceptors (template hooks, init, FPU sampling, probes, drawsites), FPU CW per call, input route/process-reset record, output/log/trace file hashes.
Original dependency ledger (each needs a lead decision and explicit qualification):
- Existing: research calls original
TechTree::Costfor effective cost and cascade cost lookup (shim/hooks/research.cpp:568-573,916-919). Formula and applicable bonus-tech discovery are not displaced by this pilot merely because a host formula exists. - Existing separate B2 hook: original has-researched lookup and node-bore updater
(
tech_effects.cpp:325-328,358-365). Node-bore updater allocates/frees state; it is not read-only despite the source comment's analogy. Reuse requires disclosure and effect accounting. - Proposed, undecided: original string lookup / allocator / event posting helpers versus a runtime-asset text adapter and compatible live allocation. No selected policy or guessed address.
- Outside replaced root: original turn driver, budget allocator and remaining simulation, asset loading and save serializer still run in the shim experiment. Whole standalone turn equality is a different acceptance axis and cannot be inferred from this partial replacement.
5. Executable acceptance to provide before ready
The contract must eventually name real, versioned commands and dependencies for this sequence; the following are precise requirements, not a presently implemented runner:
- Fresh full gate on hashed source/inputs, expected test identities, positive corpus execution, asset-dependent tests and shim build. A host-only pass is insufficient. Bind full gate manifest and resulting binary to every experiment and reject source/input changes.
- Two fresh-process C1/C2 controls with hooks off, same proxy, input, assets and exact W1 route; both output pairs equal byte-for-byte. Archive independent process logs; one saved oracle copy is not independent proof that two processes agreed.
- Compare-neutral N with the candidate binary and complete instrumentation manifest; both output saves byte-equal controls; positive W1 counters and decoded state. Zero compared calls, partial required-region coverage or undeclared required writes cannot pass.
- Replace R, same baseline and binary, bypass original ProcessResearch and required displaced callback implementation (count explicit original helper calls separately). Require exactly one W1 completion/three unlocks, real element/event writes, zero failures/unreadable inputs, and full declared state validation including nonserialized order counter and RNG state.
- Require post-turn autosave byte equality, inflated equality and exact-bit unmasked state equality independently, with reader reconstruction coverage. Pre-turn EndTurn equality alone cannot satisfy acceptance. No masks for event text, callback fields or derived discrepancies.
- Negative controls must fail: archived R0 (27 differences) and R1 (16); zero-completion W0 cannot satisfy W1 threshold; omit callback/event/ObservedTech write or use wrong input hash; remove a trace/log/output; mark unknown RNG as zero. Checker rejects all.
- Independently assigned verifier re-runs the checks and ties verdict to contract, source, binary, asset and evidence digests. Implementation worker cannot self-certify acceptance. Integration requires revalidation of integrated source; changed inputs invalidate evidence.
W2 and branch-specific tests must be added before expanding the claim to RNG-consuming, Zuul/early-completion, nonzero-decay, zero-cost recursion, prerequisite/no-auto-available, re-observed/deduplicated, temperance, plague or rebellion cases. Their absence is visible coverage debt, not satisfied execution. Local simulation tests alone do not establish live allocator safety.
5.1 Acceptance interface fixed before implementation (2026-09-10)
The accepted research-completion-abi contract closes the static record/container dependency only.
It does not close live allocation safety or any replacement criterion. The pilot checker and run
driver do not yet exist, so the commands below are required interfaces and remain blockers, not
executable claims:
python3 tools/research_replacement.py preflight --package MANIFEST.json --workload W1
python3 tools/gate.py --engine ENGINE --corpus CORPUS --out NEW_GATE_DIR \
--profile full --data DATA --shim --sots-input SOTS_EXE=EXE --sots-input SOTS_PROXY=PROXY
python3 tools/research_replacement.py certify-controls --package MANIFEST.json --workload W1 \
--c1 C1_DIR --c2 C2_DIR --compare N_DIR
python3 tools/research_replacement.py check-replace --package MANIFEST.json --workload W1 \
--replace R_DIR --oracle C1_DIR
python3 tools/research_replacement.py negative-controls --package MANIFEST.json \
--replace0 verify/results/saves/cr/cr-replace0-autosave.sav \
--replace1 verify/results/saves/cr/cr-replace1-autosave.sav --w0 W0_DIR
MANIFEST.json must bind paired source manifests, the full-gate manifest and shim binary, owner
executable/proxy, generated addresses, data root and every consumed tech/tuning/species/string file,
locale/encoding/load order, exact configs and installed-site manifest, W1/W0 saves, process route,
and output/log/trace hashes. Each command must fail on an absent or extra required artifact, hash or
source drift, stale output directory, zero required execution, unexpected skip, unreadable input,
unsupported branch, or unknown RNG. check-replace must separately report file bytes, inflated
bytes, exact-bit typed state, reader coverage, nonserialized order counter, complete RNG state and
actual words, callback/helper counters, allocations and complete event/ObservedTech elements.
Before any implementation contract can become ready, an independent verifier must turn these interfaces into an executable falsifier plan covering archived R0 and R1, a wrong W1 hash, each missing callback/event/ObservedTech write, an omitted output/log/trace/site manifest, W0 presented as the positive, unknown RNG presented as zero, original displaced-root fallback, and same-HEAD source-byte drift. Verifier and implementer executions must be different sessions.
5.2 Bounded W1 architecture and dependency decisions
The replacement is one ordered coordinator with a dry-run preflight, not three independently
acceptable leaf patches. Preflight reads all three owner calls and computes the complete W1 plan on
scratch state before the first live write. It must positively identify the exact owner/allocation
sequence, one tech-144 IND_Waldo completion, the three unlocks, no pending research roll, no
unmodelled conditional system/ship/Zuul/plague/temperance/rebellion effect, and an explicit outcome
for every recursive-completion and decay branch. The eventual immutable W1 manifest must state the
certified expected outcomes; any mismatch is unsupported and blocks before mutation. This is a W1
classifier, not a general research implementation.
The coordinator then preserves original order: research arithmetic; SetResearched node/order
writes; full ObservedTech record operation; matched-target handling; full completion event; W1 player
effects and common tail; unlocked-tech event; remaining pass writes. It must use pre-call state for
all decisions. Allocation failure after mutation is an observed failed run and cannot pass; this
plan does not claim transactional rollback that the original does not provide.
Original-helper policy for this bounded pilot is explicit:
- Retain and count
TechTree::Costfor effective and cascade costs. Independent cost replacement is excluded from the claim. - Retain and count
TechTree::HasResearchedfor the common callback tail and design masks. The replacement owns the resulting mask and field writes; the helper is lookup only. - Retain and count
ServerPlayer::UpdateNodeBoreParamsat its original common-tail position. It may allocate/free through the game's CRT even when W1 does not select a bore tech. Independent node-bore maintenance is excluded. - Use the original MSVCR100 scalar new/delete family and accepted record/container ABI as a live memory bridge, with every allocation/copy/destruction operation counted. This is original-runtime allocation assistance, not standalone allocator replacement.
- Do not call original
ProcessResearch,SetResearched,OnTechResearched,RecordObservedTech,EventStorage::PostEvent, or original string lookup in replace mode. Runtime owner assets must supply localized text to an engine-side lookup; replacement code owns record contents, event IDs/order/dedup/pruning and callback effects. Keyless text is forbidden. - The original turn driver, budget allocation, asset loading and save serializer remain outside the replaced root and must be disclosed separately from retained helpers.
Static ABI acceptance unlocks exactly one preparatory dependency: a live record-bridge contract
must exercise ObservedTech, TurnEvents and PlayerEvent operations with empty/spare/full capacity,
short/long strings, repeated observed names, exact duplicate and description-only-different events,
normal destruction and a recorded failure path, under a lease. It owns only the bridge and fixtures
and may not wire research replacement. Only after independent acceptance of that bridge may one
complete W1 coordinator implementation own src/shim/hooks/research.{cpp,h} plus narrowly named
bridge/effect/event files and tests. No two workers may concurrently own those files or the same
VM/build directory.
6. Current blockers / stop conditions
- No executable pilot-specific acceptance runner or full input/asset manifest. W2 is not required for the W1-only pilot but remains required before any broader claim.
- Live research callback integration, complete ObservedTech/event construction, broader callback outcomes and unsupported-path preflight remain unimplemented/unverified.
- Static record/container ABI is accepted, but the live record bridge and its independent runtime safety evidence are missing. Retained Cost/HasResearched/node-bore/CRT helpers and forbidden displaced roots are fixed above; runtime asset paths and adapter execution remain unresolved.
- Archived C1/C2 equality is documented but independent raw control-run bundles are not established by the single oracle pair inspected here. Fresh controls are mandatory.
- Instrumentation and runtime FPU narrative need correction in acceptance inputs; archives are historical observations, not the current candidate's attestation.
- Stop on control disagreement, silent fallback, missing data, branch outside approved class, unexpected writes/draws, stale evidence, source drift, or scope/architecture surprises; persist checkpoint and escalate to Astra before changing the contract.
This proposal authorizes planning only. Keep lifecycle proposed until required dependencies, input manifests, bounded implementation scope and executable acceptance exist.