Refactor runtime ownership and clean up warnings

This commit is contained in:
Jan Petykiewicz 2026-04-21 15:40:17 -07:00
commit 486b061558
628 changed files with 97954 additions and 90763 deletions

View file

@ -13,18 +13,31 @@ project is already mature.
## Documents
- Stable docs
- `setup-workstation.md`: toolchain baseline and local environment setup.
- `re-workflow.md`: how to analyze the binary, record findings, and export reusable artifacts.
- `function-map.md`: canonical schema and conventions for function-by-function mapping.
- `control-loop-atlas.md`: compatibility index for the split atlas, preserving legacy anchors.
- `control-loop-atlas/`: canonical section files for the atlas narrative.
- `subsystem-views/`: curated cross-cut subsystem views over the atlas.
- `runtime-rehost-plan.md`: bottom-up runtime replacement plan and milestone breakdown.
- Active queue and history
- `rehost-queue.md`: active implementation and research queue.
- `rehost-queue/`: archived queue snapshots and related preserved worklog material.
- `history/progress-history.md`: preserved high-detail milestone narrative from the former root README.
- Artifact indexes
- `../artifacts/exports/rt3-1.06/README.md`: canonical 1.06 export manifest.
- `../artifacts/captures/README.md`: committed capture inventory and policy.
## Repo Conventions
- `docs/`: stable project guidance and durable design notes.
- `tools/py/`: committed Python helpers for analysis and validation.
- `artifacts/exports/`: committed derived outputs that can be regenerated.
- `artifacts/captures/`: committed logs, sample binaries, and retained capture evidence.
- `artifacts/tmp/`: scratch-only local working area; do not commit new files here.
- Local-only state stays untracked: `.venv/`, Ghidra projects, Rizin databases, crash dumps, and other
bulky/generated working files.

View file

@ -2,11 +2,11 @@
This atlas is now split by top-level section under
[docs/control-loop-atlas/](/home/jan/projects/rrt/docs/control-loop-atlas/README.md).
This file remains the compatibility index and keeps the original top-level anchors stable for
This file remains the compatibility index that keeps the original top-level anchors stable for
older links.
Subsystem notes still live under [docs/atlas](/home/jan/projects/rrt/docs/atlas/README.md) for
faster cross-cut navigation.
For curated cross-cut navigation, use
[docs/subsystem-views](/home/jan/projects/rrt/docs/subsystem-views/README.md).
## Section Index
@ -19,6 +19,20 @@ faster cross-cut navigation.
- [Input, Save/Load, and Simulation](/home/jan/projects/rrt/docs/control-loop-atlas/input-save-load-and-simulation.md)
- [Next Mapping Passes](/home/jan/projects/rrt/docs/control-loop-atlas/next-mapping-passes.md)
## Atlas Field Guide
This compatibility index keeps the original top-level anchors stable. The grounded atlas fields now
live in the split section files under
[docs/control-loop-atlas/](/home/jan/projects/rrt/docs/control-loop-atlas/README.md).
- Roots: see each section file's opening field block for the concrete root functions and entrypoints.
- Trigger/Cadence: see the split section files for the cadence notes attached to each loop or ingress.
- Key Dispatchers: see the section-local dispatcher bullets in the split atlas pages.
- State Anchors: see the state-anchor bullets in each split atlas section.
- Subsystem Handoffs: see the handoff bullets in each split atlas section.
- Evidence: see the section-local evidence bullets in the split atlas pages.
- Open Questions: see the section-local open-question bullets in the split atlas pages.
## CRT and Process Startup
Detailed section:

View file

@ -103,7 +103,7 @@ The same brush strip is tighter now too:
now as well, because it checks the per-node promotion-latch dword `[node+0x0c] == 1` rather than
reusing the queue kind field. `0x00438840` is the tiny
dispatch-or-fallback sibling: it forwards the currently active queue node at `[world+0x66aa]`
into `simulation_dispatch_runtime_effect_queue_record_by_kind_into_shell_or_world_handlers`
into `simulation_dispatch_runtime_effect_queue_node_by_kind`
`0x00437c00`, or opens the fixed custom modal rooted at localized id `0x153` when no active
node is staged.
company-credit side effect. One neighboring narrow counter is bounded too: `0x00422850`
@ -920,7 +920,7 @@ The same brush strip is tighter now too:
`[desc+0x24/+0x28]`, not an anonymous cargo-economy mode byte. Slot `34` `[0x006cec78+0x4b07]`
is similarly bounded
on the runtime side:
`world_run_company_start_or_city_connection_chooser_with_region_field_0x2d_temporarily_cleared_if_rule_0x4b07`
`world_try_publish_startup_company_or_city_connection_news_ignoring_territories`
`0x004013f0`, which sits immediately above the broader company-start or city-connection chooser
`0x00404ce0`, snapshots region dword `[entry+0x2d]` across all `0x18` live region records in
`0x006cfc9c`, zeros that field while the chooser runs, and then restores the original values on

View file

@ -2494,11 +2494,11 @@ Current evidence grounds the shell-controller-backed input and frame path as the
actual field-seeding layer beneath that allocator. The old unresolved higher placement chooser is
bounded more cleanly now too: the `0x00403ed5` and `0x0040446b` direct-placement commits sit
inside one larger helper,
`city_connection_try_build_route_with_optional_direct_site_placement` `0x00402cb0`. That shared
`city_connection_try_build_route_and_optionally_place_direct_site` `0x00402cb0`. That shared
heavy builder is now the common target of the compact wrapper `0x00404640`, the peer-route
candidate builder `0x004046a0`, the region-entry pair wrapper
`city_connection_try_build_route_between_region_entry_pair` `0x00404c60`, and the direct retry
paths inside `simulation_try_select_and_publish_company_start_or_city_connection_news`
paths inside `simulation_try_publish_startup_company_or_city_connection_news`
`0x00404ce0`. Internally it now has three bounded lanes:
an early route-entry search or synthesis attempt through
`route_entry_collection_try_build_path_between_optional_endpoint_entries` `0x004a01a0`,
@ -3830,11 +3830,11 @@ The low helper strip beneath that shared family is tighter now too: `0x0052ecd0`
against the scenario-side scale returned by `0x00437d20(index)` and rounds the result through
`0x005a10d0`.
The broader company-side owner above these pieces is tighter now too. The periodic service pass
`company_service_periodic_city_connection_finance_and_linked_transit_lanes` `0x004019e0` now
`company_service_periodic_city_connection_finance_and_linked_transit` `0x004019e0` now
reads as the current outer owner for this branch: it sequences the city-connection announcement
lanes, the linked-transit train-roster balancer, the acquisition-side sibling
`company_try_buy_unowned_industry_near_city_and_publish_news` `0x004014b0`, the annual finance-policy helper
`company_evaluate_annual_finance_policy_and_publish_news` `0x00401c50`, and the shorter-versus-
`company_try_acquire_unowned_industry_near_city_and_publish_news` `0x004014b0`, the annual finance-policy helper
`company_apply_annual_finance_policy_and_publish_news` `0x00401c50`, and the shorter-versus-
longer linked-transit cache refresh tail through `0x004093d0` and `0x00407bd0`. That outer pass
also has one tighter temporary-state role now: it clears company bytes `0x0d17/0x0d18/0x0d56`,
mirrors `0x0d17` into scenario field `0x006cec78+0x4c74` only while the earlier route-building
@ -3898,7 +3898,7 @@ The low helper strip beneath that shared family is tighter now too: `0x0052ecd0`
support-adjusted-share-price-times-factor-times-`1000`-times-`1.2` affordability gate before the
repeated `1000`-share buyback commits behind RT3.lng `2887`. The ordering above this helper is
tighter now too:
`company_service_periodic_city_connection_finance_and_linked_transit_lanes` clears those latches
`company_service_periodic_city_connection_finance_and_linked_transit` clears those latches
first, runs the city-connection and linked-transit branches, and only then enters the annual
finance helper, so these look like same-cycle reaction gates rather than long-lived balance-sheet
flags.

View file

@ -65,7 +65,7 @@ One reusable site helper is grounded now too.
before choosing whether a scanned site should carry `3871` `Connected By Another Company` or
`3872` `Already Connected by Another Company`. The larger caller boundary is no longer open
either: the first bounded announcement owner above this formatter family is now
`company_evaluate_and_publish_city_connection_bonus_news` at `0x00406050`, which re-enters the
`company_try_publish_city_connection_bonus_news` at `0x00406050`, which re-enters the
peer-route candidate builder at `0x004046a0` and later publishes one of the localized
city-connection bonus news strings `2888`, `2890`, or `2921` through the shell news path.
#### Peer-selector side
@ -88,7 +88,7 @@ The reusable bridge between the status formatter and the
`0x004046a0` reuses `city_connection_bonus_select_first_matching_peer_site` with both selector
flags forced on, rounds both the source-city and selected-peer normalized coordinates through
`0x005a10d0`, and then first tries the shared heavy builder
`city_connection_try_build_route_with_optional_direct_site_placement` `0x00402cb0` when the
`city_connection_try_build_route_and_optionally_place_direct_site` `0x00402cb0` when the
caller already supplied a live route-anchor tuple. When that direct attempt does not apply or no
peer survives, it falls back to the smaller wrapper
`city_connection_bonus_try_compact_route_builder_from_region_entry` `0x00404640`; and when both
@ -119,7 +119,7 @@ The reusable bridge between the status formatter and the
debt headline family, then publishes `2887` separately from the accumulated repurchased-share
count. The sibling news owner above the same
city-pair route family is bounded now too:
`simulation_try_select_and_publish_company_start_or_city_connection_news` `0x00404ce0`
`simulation_try_publish_startup_company_or_city_connection_news` `0x00404ce0`
filters and scores candidate city entries, re-enters the same shared heavy builder through
`city_connection_try_build_route_between_region_entry_pair` `0x00404c60` for the dense pair
sweep and the final retry, and then publishes `2889` `%1 has started a new company - the %2`

View file

@ -34,9 +34,24 @@ Field meanings:
## Update Rules
- New rows must always include `address`, `name`, `subsystem`, `source_tool`, and `confidence`.
- Prefer names in the shape `owner_verb_object[_qualifier]`.
- Prefer one primary verb, one primary object, and at most one qualifier.
- If a rename is speculative, state that directly in `notes`.
- When two tools disagree on function boundaries, preserve the ambiguity in `notes` instead of hiding it.
- Prefer one row per concrete function, not per guessed feature.
- Prefer `try_` for best-effort helpers that may fall through without mutation or publication.
- Prefer `apply_` when a helper commits one selected policy or state transition.
- Reserve `evaluate_` for read-heavy helpers that classify or score state without committing the later action themselves.
- Prefer one stable family noun once a transient runtime structure is grounded.
- Use `queue_node` for transient linked-list allocations, and reserve `record` for persisted rows or document-style payloads.
- Prefer `startup_company` over `company_start` when the object is the newly started company.
- Prefer participial qualifiers such as `_ignoring_territories` over `_with_*_ignored` once the side condition is grounded.
- Drop filler tails such as `_lanes` once a broader owner is grounded well enough to carry the family directly.
- Prefer `_and_optionally_` over `_with_optional_` when a helper may take one secondary path but the main owner is still singular.
- Treat `_and_`, `_with_`, `_if_`, and `_via_` as fallback tools for still-uncertain seams, not the
default naming style.
- Raw offset tails such as `field_0xNN` are acceptable for direct accessors and low-confidence rows,
but should be replaced once a grounded semantic field name exists.
## Starter Subsystems

View file

@ -0,0 +1,311 @@
Preserved progress narrative from the former root README.
Analysis and reimplementation of Railroad Tycoon 3
The old executable is at ./rt3_wineprefix/drive_c/rt3/RT3.exe
Our first task is to understand the executable's high-level control loops and subsystem boundaries well
enough to choose good rewrite targets. As we go, we document evidence, keep a curated function map,
and stand up Rust tooling that can validate artifacts and later host replacement code.
The long-term direction is still a DLL we can inject into the original executable, patching in
individual functions as we build them out. The active implementation milestone is now a headless
runtime rehost layer that can execute deterministic world work, compare normalized state, and grow
subsystem breadth without depending on the shell or presentation path. The current packed-event
frontier is broader real grouped-descriptor coverage on top of the existing save-slice, snapshot,
overlay-import, compact-control, and symbolic company-target workflows. The runtime already carries
selected-company and controller-role context through overlay imports, and real descriptors `2`
`Company Cash`, `13` `Deactivate Company`, and `16` `Company Track Pieces Buildable` now parse and
execute through the ordinary runtime path, and descriptors `1` `Player Cash` and `14`
`Deactivate Player` now join that batch through the same service engine. Synthetic packed records
still exercise the same runtime without a parallel packed executor. The first grounded
chairman-profile runtime slice now exists too: save-slice or overlay-backed chairman/company
context plus the hidden grouped target-subject lane let those same real descriptors `1` and `14`
execute on the grounded chairman scope ordinals `0..3` (`condition_true`, `selected`, `human`,
`ai`), while wider chairman ordinals remain explicit parity. The first grounded
chairman and governance condition batch is broader now: selected-chairman cash / holdings / net
worth / purchasing-power thresholds and company book-value-per-share / investor-confidence /
management-attitude thresholds now import through the normal event-service path, while wider
chairman ordinals remain explicit frontier. Checked-in save-slice
documents can now also carry explicit company rosters and chairman-profile tables, so the current
company-targeted and chairman-targeted descriptor and condition batches can execute from standalone
save-slice fixtures without overlay snapshots when that context is present; raw `.gms` inspection
now reconstructs both collections automatically: the fixed save-side `0x32c8` world block still
supplies selected company/chairman ids plus the campaign override byte, the grounded issue-`0x37`
value/multiplier pair, and chairman slot/role-gate analysis bytes, and the tagged company /
chairman-profile direct-record families now populate
save-native roster entries for real `.gms` imports and exports. The current raw-save boundary is
narrower now: company/chairman identity, active flags, links, chairman cash, chairman holdings,
chairman purchasing power, company debt, and company track-laying capacity are grounded directly
from save records, while
broader company finance/governance scalars and controller-kind reconstruction still remain
conservative defaults until their raw lanes are pinned more strongly. The offline runtime analysis
surface also now exposes `runtime inspect-save-company-chairman <save.gms>` for those remaining raw
company/chairman scalar candidates, including fixed-world chairman slot / role-gate context,
explicit company dword candidate windows, richer chairman qword cache views, and derived
holdings-at-share-price / cached purchasing-power comparisons. The same fixed `0x32c8` world
block is now probed for the grounded issue-`0x37` pair at `[world+0x29/+0x2d]`, and the adjacent
raw issue-byte strip `0x37..0x3a` now also flows through save-slice/runtime restore state as
first-class owner data for later credit / prime-rate / management-attitude readers. One broader
fixed-dword finance neighborhood rooted at `[world+0x0d]` that now carries the saved calendar
tuple and absolute-counter owner lanes directly, and the separate
six-float economic tuning band, but current atlas evidence still keeps that editor-facing
tuning family distinct from the governance issue lanes behind investor confidence and prime-rate
math. The next shared company-side slice is now rehosted too: save-native company direct records
flow into a typed company market/cache map on runtime service state, carrying outstanding shares,
saved support/share-price/cache words, chairman salary lanes, calendar words, and connection
latches for each live company. That map now appears in runtime summaries and save-slice exports,
and it now also carries the first grounded stat-band root windows at `[company+0x0cfb]`,
`[company+0x0d7f]`, and `[company+0x1c47]`, so later company stat-family / finance readers can
build on owned state instead of another round of single-field save-offset guesses. The first
runtime-side `0x2329` stat-family reader seam is now rehosted too for the currently grounded slots
`0x0d` (`current_cash`) and `0x1d` (`book_value_per_share`), so later annual-finance logic can
extend one shared reader family instead of hard-coding more direct field accesses. Those saved
stat-band windows are now widened to 32 dwords per root in save-slice/runtime state so later
year-series finance closure has a broader owned raw state band to attach to. The matching world-side issue
reader seam is now also rehosted for the grounded `0x37` investor-confidence lane on top of the
save-native world-restore state. The selected-company summary path now also exposes the
unassigned share pool derived from outstanding shares minus chairman-held shares, so later
dividend / stock-capital logic can extend one owned market reader instead of another ad hoc
counter. The next bundled annual-finance reader seam is now rehosted on top of that same market
state too, deriving assigned shares, public float, and rounded cached share price from one shared
company market reader instead of scattering more finance helpers across the runtime. A checked-in
The fixed-world finance neighborhood itself is now widened to 17 dwords rooted at `[world+0x0d]`,
so later finance closure can build on a broader owned restore-state window rather than another
narrow one-off probe; that same owner surface now also carries the saved absolute counter
as first-class runtime restore state instead of leaving it on “requires shell context” metadata.
The same save-world owner surface now also carries the packed year word and partial-year progress
lane behind the annual-finance recent-history weighting path, so later finance readers can attach
to real world-calendar state instead of candidate bytes.
The next company-side seam is now bundled too: a shared company
market reader now exposes outstanding shares, assigned shares, public float, rounded cached share
price, salary lanes, bonus amount, and the full two-word current/prior issue-calendar tuples from
the owned annual-finance state instead of leaving that logic spread across summary helpers. The
same annual-finance state now also
derives elapsed years since founding, last dividend, and last bankruptcy from the runtime calendar,
which lines up directly with the grounded annual finance-policy gates in the atlas. Live bond-slot
count is now carried through the same owned company market and annual-finance state too, which
matches the stock-capital branch gate that requires at least two live bonds. The same grounded
bond table now also contributes both the largest live bond principal and the chosen
highest-coupon live bond principal into owned company market and annual-finance state, so the
stock-capital approval ladder can extend one rehosted owner-state surface instead of hunting
another isolated finance leaf. The same bond-slot owner state now also exposes the highest live
coupon rate, which is enough to run the stock-capital price-to-book approval ladder as another
save-native runtime reader instead of a notes-only threshold table. A checked-in
fixed-world finance-policy seam now also carries the raw stock, bond, bankruptcy, and dividend
policy bytes from the `0x32c8` save block, and the first annual creditor-pressure branch now runs
headlessly as a pure runtime reader over owned annual-finance state, support-adjusted share price,
and current world finance policy rather than as a notes-only atlas fragment. The later deep-
distress bankruptcy fallback is now rehosted on that same owner surface too, using the save-native
cash reader seam plus the first three trailing net-profit years instead of another ad hoc probe.
The annual bond lane now runs on that same owner surface too, using the simulated post-repayment
cash window plus the linked-transit threshold split to stage `500000` principal issue counts as a
pure runtime reader, and periodic boundary service now commits the same shellless matured-bond repayment-and-
compaction path before issuing the exact staged count. The annual dividend lane now runs there too: the runtime now rehosts the
shared year-or-control-transfer metric seam, the board-approved dividend ceiling helper, and the
full annual dividend adjustment branch over owned current cash, public float, current dividend,
building-growth policy, and recent profit history instead of leaving that policy on shell-side
dialog notes. The same periodic service now also carries the annual bond lane's retired-versus-
issued principal totals as first-class runtime summary state, which is the owner seam behind the
later debt-news family, and it now carries the paired issued-share and repurchased-share counts
behind the equity-offering and `2887` buyback news tails too. Runtime summaries now also expose the
grounded retired-versus-issued relation directly, and annual finance service now maps that same
comparison onto the exact debt headline selectors `2882..2886`. `simulation_service_periodic_boundary_work` is now beginning to use that same owner
surface too: the runtime chooses one annual-finance action per active company and already commits
the shellless creditor-pressure-bankruptcy, deep-distress-bankruptcy, dividend-adjustment,
stock-repurchase, stock-issue, and bond-issue branches by mutating owned company activity,
dividend, company stat-post, outstanding-share, issue-calendar, and live bond-slot state instead
of stopping at reader-only diagnostics. That same service state now also persists the last emitted
annual-finance news events as structured runtime records carrying company id, exact selector label,
action label, and the grounded debt/share payload totals used by the shell news layer.
Calendar stepping now also starts to use that same seam directly: `StepCount` and `AdvanceTo`
invoke the periodic-boundary service automatically on year rollover, so shellless calendar advance
can drive the annual finance stack instead of requiring a separate manual service command.
That stepped world-time path now also refreshes the rehosted selected-year gap scalar owner lane
instead of leaving `[world+0x4ca2]` as a frozen load-time residue.
The same save-native world restore surface now also carries the grounded locomotive-policy bytes
and cached available-locomotive rating from the fixed world block, so the `All
Steam/Diesel/Electric Locos Avail.` descriptor strip now writes through owner state instead of
living only as ad hoc world flags.
The selected-year seam is now doing the same thing: the checked-in `0x00433bd0` year ladder now
drives a derived selected-year bucket scalar in runtime restore state, and the economic-tuning
mirror `[world+0x0bde]` now rebuilds from tuning lane `0` instead of freezing one stale load-time
word. That same checked-in owner family now also rebuilds the direct bucket trio
`[world+0x65/+0x69/+0x6d]`, the complement trio `[world+0x71/+0x75/+0x79]`, and the scaled
companion trio `[world+0x7d/+0x81/+0x85]` from the selected-year bucket scalar instead of
preserving stale save-time residue.
Those bankruptcy branches now follow the grounded owner semantics too: they stamp the bankruptcy
year and halve live bond principals in place instead of treating bankruptcy as a liquidation path.
The same save-native live bond-slot surface now also carries per-slot maturity years all the way
through runtime summaries and annual bond policy state, which is the next owner seam needed for
shellless repayment and bond-burden simulation instead of another round of raw-slot guessing.
The same save-native company direct-record seam now also carries the full outer periodic-company
side-latch trio rooted at `0x0d17/0x0d18/0x0d56`, including the preferred-locomotive engine-type
chooser byte that sits beside the city-connection and linked-transit finance gates.
That same seam now also resolves the base world route-preference byte at `[world+0x4c74]`, the
effective electric-only override fed by `0x0d17`, and the matching `1.4x` versus `1.8x`
route-quality multiplier as a normal runtime reader instead of leaving that bridge in atlas notes.
That same seam now also owns the first route-preference mutation path directly: beginning the
electric-only periodic-company override rewrites the world route-preference byte to the effective
company preference, ending it restores the base world byte, and runtime service state now carries
both the active and last applied override instead of treating the route-preference lane as a
reader-only bridge.
Save inspection now also separates the shared `0x5209/0x520a/0x520b` save family correctly: the
smaller direct `0x1d5` collection is the live train family and now exposes a live-entry
directory rooted at metadata dword `16`, while the actual region collection is the larger
non-direct `Marker09` family. The tagged placed-structure header `0x36b1/0x36b2/0x36b3` is
grounded alongside them, so the remaining city-connection / linked-transit blocker is
record-body reconstruction rather than missing save-side collection identity.
That same seam now also derives the current live coupon burden directly from owned bond slots, so
later finance service work can consume a runtime reader instead of recomputing from scattered raw
fields.
The same seam now also carries the fixed-world building-density growth setting plus the linked
chairman personality byte, which is enough to run the annual stock-repurchase gate as another
pure reader over owned save-native state instead of a guessed finance-side approximation.
The working rule on the remaining frontier is explicit now too: when a lane is still ambiguous, we
should prefer rehosting the owning source state or the real reader/setter family rather than
guessing one more derived leaf field from nearby offsets, and the checked-in
[`docs/rehost-queue.md`](docs/rehost-queue.md) file is now the control surface for that loop:
after each commit, check the queue and continue unless the queue is empty, a real blocker remains
that cannot be advanced by any further non-hook work without guessing, or approval
is needed. `final` responses are stop-only there too: if no stop condition is true, keep working
and use `commentary` updates instead of placeholder status replies. A checked-in
The same runtime surface now also exposes higher-layer blocker probes:
`runtime inspect-periodic-company-service-trace <save.gms>`,
`runtime inspect-region-service-trace <save.gms>`, and
`runtime inspect-infrastructure-asset-trace <save.gms>`, so the next city-connection /
linked-transit slices can start from explicit owner-seam blockers instead of another generic save
scan. A checked-in
`EventEffects` export now exists too in
`artifacts/exports/rt3-1.06/event-effects-table.json`, and a checked-in semantic closure layer now
exists beside it in `artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json`. Recovered
descriptor rows now land on explicit semantic frontier buckets such as
`blocked_shell_owned_descriptor`, `blocked_evidence_blocked_descriptor`, and
`blocked_variant_or_scope_blocked_descriptor` instead of generic anonymous descriptor residue. The
first recovered governance descriptor tranche now imports through the generic
company-governance scalar effect surface:
descriptor `56` `Credit Rating` and descriptor `57` `Prime Rate` execute from ordinary real packed
rows, while adjacent recovered finance/control-transfer descriptors such as `55` `Stock Prices`
and `58` `Merger Premium` now land on explicit shell-owned parity instead of anonymous unmapped
descriptor residue, and tracked shell-owned fixtures now pin finance, scenario-outcome, and
control-transfer shell rows explicitly. The
recovered whole-game scalar economy/performance strip `59..104` now has a
bounded runtime landing surface too: representative descriptors import into
`RuntimeState.world_scalar_overrides` through stable normalized keys such as
`world.build_stations_cost`, `world.track_maintenance_cost`, `world.all_engine_speeds`, and
`world.hotel_revenue`. The runtime-variable strip `39..54` now executes too through bounded
event-owned scalar maps on world/company/player/territory state, and the matching ordinary
condition strip now gates records through those same maps too, without widening save-native
reconstruction or adding a second packed executor. The grounded aggregate cargo-economics
descriptors now have bounded
runtime landing surfaces too: descriptor `105` `All Cargo Prices` plus descriptors `177..179`
`All Cargo Production` / `All Factory Production` / `All Farm/Mine Production` import into
event-owned cargo override state, and the grounded named cargo-production strip `180..229` now
imports into named cargo production overrides too, and the named cargo-price strip `106..176` now
imports into named cargo price overrides as well. The checked-in static selector reconstruction is
now explicit: the broader 1.06 CargoTypes corpus has `51` names, the Cargo106 `cargoSkin` corpus
has `70`, and the rehosted offline selector builder now closes the `71`-row named price strip as
`cargoSkin` plus the core `Rock` carry-over. The checked-in
`artifacts/exports/rt3-1.06/economy-cargo-sources.json` report parses both `CargoTypes` and the
`Cargo106.PK4` `cargoSkin` descriptors, normalizes localized `~####Name` tokens into visible
names, builds a merged live cargo registry, and now derives exact named cargo-production and named
cargo-price selectors from the checked-in bindings. Dedicated CLI inspector commands now expose
both grounded selectors directly, while the same report still makes the residual live-registry gap
explicit by showing the nine excluded CargoTypes-only industrial names outside the 71-row price
strip. The
add-building strip `503..519` is now explicitly classified as recovered
shell-owned descriptor parity rather than generic unresolved residue. The first grounded
condition-side unlock now exists for negative-sentinel `raw_condition_id = -1` company scopes, and
the first ordinary nonnegative condition batch now executes too: numeric-threshold company
finance, company track, aggregate territory track, and company-territory track rows can import
through overlay-backed runtime context. Exact named-territory binding now executes, and the runtime
now also carries the minimal event-owned train roster and opaque economic-status lane needed for
real descriptors `8` `Economic Status`, `9` `Confiscate All`, and `15` `Retire Train` to execute
through the same path. Descriptor `3`
`Territory - Allow All` now executes too, reinterpreted as company-to-territory access rights
rather than a territory-owned policy bit. Whole-game ordinary-condition execution now exists too:
special-condition thresholds, candidate-availability thresholds, and economic-status-code
thresholds now gate imported runtime records through the same service path, and that world-side
condition batch now decodes from checked-in metadata instead of fixture-only ids: real
special-condition label ids, real economic-status ids, and the recovered `%1 Avail.` candidate
template plus candidate-name side strings all lower into the runtime condition model. Checked-in
whole-game descriptor metadata now drives the first real world-side effect batch too:
special-condition and candidate-availability setters import natively, and descriptor `110`
`Disable Stock Buying and Selling` now lowers into the keyed runtime flag
`world.disable_stock_buying_and_selling`. The recovered whole-game toggle batch is broader now
too: descriptors `111..138`, with descriptor `122` `Limited Track Building Amount` now landing in
the bounded `world_restore.limited_track_building_amount` scalar and the remaining boolean lanes
lowering into keyed `world_flags`, cover finance/trading, construction, and governance
restrictions. Explicit the late recovered special-condition toggles now execute too where current
evidence is equally
strong: `Use Bio-Accelerator Cars`, `Disable Cargo Economy`, `Disable Train Crashes`, `Disable
Train Crashes AND Breakdowns`, and `AI Ignore Territories At Startup`. Whole-game condition decode
is broader now too: checked-in world-flag condition ids can lower into `world_flag_equals` gates
for boolean equality/inequality forms, so real packed records can gate whole-game effects on
existing `world_flags` without fixture-authored placeholder ids. The tracked parity save-slice no
longer depends on a raw `unsupported_framing` placeholder either: its remaining residue is now one
recovered locomotives-page `real_packed_v1` record that now lands on explicit descriptor parity
instead of a generic unmapped bucket. The next recovered descriptor band is now partially
executable too: descriptors `454..456` (`All Steam/Diesel/Electric Locos Avail.`) now lower
through checked-in metadata into keyed `world_flags`, while the wider locomotive availability/cost
scalar bands are now save-native too. Raw `.smp` inspection/export reconstructs the persisted
`[world+0x66b6]` locomotive name table and derives a minimal `RuntimeState.locomotive_catalog`, so
standalone save-slice imports can now lower the grounded lower locomotive availability and
locomotive-cost rows directly into `RuntimeState.named_locomotive_availability` and
`RuntimeState.named_locomotive_cost` without needing overlay snapshots when the save carries enough
catalog context, and the grounded executable lower prefix now extends through save-backed
locomotive id `61` (`Zephyr`); the unresolved lower tail and upper locomotive bands now stay on
explicit parity instead of synthetic execution. The remaining recovered scalar world families
execute too:
cargo-production slots `230..240` lower into `cargo_production_overrides`, and descriptor `453`
lowers into
`world_restore.territory_access_cost`. Whole-game ordinary-condition breadth now aligns with those
same world-scalar runtime surfaces too: named locomotive availability thresholds, named
locomotive cost thresholds, named cargo-production slot thresholds, aggregate cargo-production
thresholds, factory/farm-mine/other cargo-production thresholds, limited-track-building-amount
thresholds, and territory-access-cost thresholds all gate imported runtime records through the
same service path. Explicit unmapped world-condition frontier buckets still remain where current
checked-in metadata stops, and
`blocked_missing_locomotive_catalog_context` is now reserved for intentionally incomplete save-side
catalog context instead of the normal save-slice path. Cargo slot identity and class metadata are
now save-native too: the recipe-book probe lowers into `RuntimeState.cargo_catalog`, so save-slice
documents can carry slot labels, class tags, and token-stem evidence alongside the executable
`cargo_production_overrides` surface without introducing a live cargo-economy model. Shell
purchase-flow, Trainbuy refresh,
cached locomotive-rating recomputation, and selected-profile parity remain out of scope. Mixed
supported/unsupported real rows still stay parity-only. The PE32 hook remains useful as capture and
integration tooling, but it is no longer the main execution milestone.
## Project Docs
Bootstrap design and workflow documents live in `docs/`.
- `docs/README.md`: handbook index and target hashes
- `docs/control-loop-atlas.md`: compatibility index for the split atlas
- `docs/control-loop-atlas/`: canonical atlas section files
- `docs/setup-workstation.md`: toolchain baseline and local setup
- `docs/re-workflow.md`: repeatable reverse-engineering workflow
- `docs/function-map.md`: canonical function-map schema and conventions
The first committed exports for the canonical 1.06 executable live in `artifacts/exports/rt3-1.06/`.
## Rust Workspace
The Rust workspace is split into focused crates:
- `rrt-model`: shared types for addresses, function-map rows, and control-loop concepts
- `rrt-runtime`: headless runtime state, stepping, normalized event service, and persistence-facing
runtime types
- `rrt-fixtures`: fixture schemas, loading, normalization, and diff helpers for rehost validation
- `rrt-cli`: validation, runtime fixture execution, state-diff tools, and repo-health checks
- `rrt-hook`: minimal Windows DLL scaffold for low-risk in-process loading, capture, and later
integration experiments under Wine
For the current headless runtime smoke path, use `cargo run -p rrt-cli -- runtime summarize-fixture
fixtures/runtime/minimal-world-step-smoke.json` or one of the broader runtime fixtures under
`fixtures/runtime/`.
For the current hook smoke test, run `tools/run_hook_smoke_test.sh`. It builds the PE32 proxy,
copies it into the local RT3 install, launches the game briefly under Wine with
`WINEDLLOVERRIDES=dinput8=n,b`, and expects `rrt_hook_attach.log` to appear.

View file

@ -172,11 +172,26 @@ directory included.
## Naming Rules
- Names should prefer behavior over implementation detail when behavior is known.
- Prefer the shape `owner_verb_object[_qualifier]`.
- Prefer one primary verb, one primary object, and at most one qualifier.
- If behavior is only partly known, keep a neutral prefix such as `subsystem_` or `unk_`.
- Address-derived placeholder names are acceptable, but only as temporary rows.
- Every renamed function should keep a short note explaining why the name is justified.
- For high-level passes, prioritize names that clarify loop role, ownership, or handoff semantics
over names that only describe a local helper's mechanics.
- Prefer `try_` for best-effort helpers that may fall through without mutation or publication.
- Prefer `apply_` when a helper commits one selected policy or state transition.
- Reserve `evaluate_` for read-heavy helpers that classify or score state without committing the later action themselves.
- Prefer one stable family noun once a transient runtime structure is grounded.
- Use `queue_node` for transient linked-list allocations, and reserve `record` for persisted rows or document-style payloads.
- Prefer `startup_company` over `company_start` when the object is the newly started company.
- Prefer participial qualifiers such as `_ignoring_territories` over `_with_*_ignored` once the side condition is grounded.
- Drop filler tails such as `_lanes` once a broader owner is grounded well enough to carry the family directly.
- Prefer `_and_optionally_` over `_with_optional_` when a helper may take one secondary path but the main owner is still singular.
- Treat `_and_`, `_with_`, `_if_`, and `_via_` as fallback tools for still-uncertain seams, not as
the default naming shape.
- Raw offset tails such as `field_0xNN` are acceptable for accessors and low-confidence rows, but
should be dropped once a stable semantic field meaning is grounded.
## Confidence Rules

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,6 @@
# Rehost Queue Archive
This directory preserves older queue snapshots and long-form implementation notes that are still
useful as evidence, but should not stay in the short active queue file.
- `archive-2026-04-19.md`: preserved detailed queue snapshot from the pre-index cleanup.

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,7 @@ Implemented today:
normalized runtime state validation
- periodic trigger dispatch exists, including ordered periodic maintenance, dirty rerun `0x0a`, and
a normalized runtime-effect surface with staged event-record mutation
- snapshots, state dumps, save-slice projection, and normalized state diffing already exist in the
- snapshots, state inputs, save-slice projection, and normalized state diffing already exist in the
CLI and fixture layers
- checked-in runtime fixtures already cover deterministic stepping, periodic service, direct trigger
service, snapshot-backed inputs, save-slice-backed inputs, overlay-import-backed inputs,
@ -498,7 +498,7 @@ Exit criteria:
Current status:
- runtime snapshots and state dumps are implemented
- runtime snapshots and state inputs are implemented
- `.smp` save inspection and partial save-slice projection already feed normalized runtime state
- the packed event-collection bridge now carries per-record summaries into loaded save slices,
projected runtime snapshots, normalized diffs, and fixtures
@ -636,9 +636,9 @@ camera work, or shell windows just because their names are nearby in the call gr
The currently implemented normalized runtime surface is:
- `CalendarPoint`, `RuntimeState`, `StepCommand`, `StepResult`, and `RuntimeSummary`
- fixture loading from inline state, snapshots, and state dumps
- fixture loading from inline state, snapshots, and state inputs
- `runtime validate-fixture`, `runtime summarize-fixture`, `runtime export-fixture-state`,
`runtime summarize-state`, `runtime import-state`, and `runtime diff-state`
`runtime summarize-state`, `runtime snapshot-state`, and `runtime diff-state`
- deterministic stepping, periodic trigger dispatch, one-shot event handling, dirty reruns, and a
normalized runtime-effect vocabulary with staged event-record mutation
- save-side inspection and partial state projection for `.smp` inputs, including per-record packed

View file

@ -1,18 +1,18 @@
# Atlas Notes
# Subsystem Views
These notes are a finer-grained navigation layer over the canonical split atlas in
These files are a curated cross-cut navigation layer over the canonical split atlas in
[docs/control-loop-atlas/](/home/jan/projects/rrt/docs/control-loop-atlas/README.md), with
[control-loop-atlas.md](/home/jan/projects/rrt/docs/control-loop-atlas.md) retained as a
compatibility index.
Current subsystem views:
- [startup-shell-and-content.md](/home/jan/projects/rrt/docs/atlas/startup-shell-and-content.md)
- [multiplayer.md](/home/jan/projects/rrt/docs/atlas/multiplayer.md)
- [runtime-and-world-tools.md](/home/jan/projects/rrt/docs/atlas/runtime-and-world-tools.md)
- [route-entry-and-trackers.md](/home/jan/projects/rrt/docs/atlas/route-entry-and-trackers.md)
- [company-and-ledger.md](/home/jan/projects/rrt/docs/atlas/company-and-ledger.md)
- [editor-and-site-service.md](/home/jan/projects/rrt/docs/atlas/editor-and-site-service.md)
- [startup-shell-and-content.md](/home/jan/projects/rrt/docs/subsystem-views/startup-shell-and-content.md)
- [multiplayer.md](/home/jan/projects/rrt/docs/subsystem-views/multiplayer.md)
- [runtime-and-world-tools.md](/home/jan/projects/rrt/docs/subsystem-views/runtime-and-world-tools.md)
- [route-entry-and-trackers.md](/home/jan/projects/rrt/docs/subsystem-views/route-entry-and-trackers.md)
- [company-and-ledger.md](/home/jan/projects/rrt/docs/subsystem-views/company-and-ledger.md)
- [editor-and-site-service.md](/home/jan/projects/rrt/docs/subsystem-views/editor-and-site-service.md)
Scope policy:

View file

@ -13,12 +13,12 @@ Current grounded owners:
- `shell_company_detail_window_construct`
- `shell_company_detail_window_handle_message`
- `shell_load_screen_window_construct`
- `company_service_periodic_city_connection_finance_and_linked_transit_lanes`
- `company_evaluate_annual_finance_policy_and_publish_news`
- `company_service_periodic_city_connection_finance_and_linked_transit`
- `company_apply_annual_finance_policy_and_publish_news`
- `company_balance_linked_transit_train_roster`
- `company_try_buy_unowned_industry_near_city_and_publish_news`
- `company_evaluate_and_publish_city_connection_bonus_news`
- `simulation_try_select_and_publish_company_start_or_city_connection_news`
- `company_try_acquire_unowned_industry_near_city_and_publish_news`
- `company_try_publish_city_connection_bonus_news`
- `simulation_try_publish_startup_company_or_city_connection_news`
Current bounded finance verbs:

View file

@ -9,7 +9,7 @@ that are easy to lose inside the broader runtime section.
Current grounded owners:
- `city_connection_try_build_route_with_optional_direct_site_placement`
- `city_connection_try_build_route_and_optionally_place_direct_site`
- `route_entry_collection_try_build_path_between_optional_endpoint_entries`
- `route_entry_collection_search_path_between_entry_or_coord_endpoints`
- `route_entry_collection_create_endpoint_entry_from_coords_and_policy`