rrt/docs/control-loop-atlas/event-editors-companydetail-and-loadscreen.md

36 KiB

Input, Save/Load, and Simulation: Event Editors, CompanyDetail, and LoadScreen

Event Editors and Scenario Action Windows

The event side is tighter too: that 0x00433130 pass in turn materializes each live event record through scenario_event_refresh_runtime_record_from_packed_state 0x0042db20. Current shell-side xrefs now tighten that event branch too: the first rebuilt linked row family under 0x0042db20 aligns with the standalone condition list later queried by EventConditions.win, while the second rebuilt family aligns with the four grouped effect lists later deep-copied through scenario_event_clone_runtime_record_deep_copy 0x0042e050 during event duplication and effect staging. The condition side is tighter now too: the tiny helper cluster 0x0042df30/0x0042df70/0x0042dfb0/0x0042dff0 is no longer just "some adjacent list scans". Current evidence bounds it as four predicates over the standalone 0x1e-row condition list, testing class bits 0x01, 0x02, 0x04, or any of those bits in the static table 0x005f3e04 + id*0x81, with special fallback checks through event fields [event+0x7f9], [event+0x7fa], and [event+0x7f0] == 0x63. The shell side is tighter too: vtable slot 0x005d0cd8 now binds shell_event_conditions_window_handle_message 0x004d59e0, and vtable slot 0x005d0cf8 binds shell_event_effects_window_handle_message 0x004d7060. The effects side is tighter too: the lower helper trio is no longer anonymous. 0x004d5d00 now reads as the effect-type selector refresh under control family 0x4fb2, 0x004d5f50 reads as the selected effect parameter-row repaint, 0x004d6090 is the heavier staged-effect editor refresh over the 0x4fc7/0x4fce/0x4ff6/0x4ff9/0x4ffc/0x5041/0x5044/0x5046/0x5047 bands, and 0x004d67f0 commits the current editor state back into the staged effect row at [this+0x78]. The verb side is tighter now too: shell_open_event_conditions_modal_and_return_result 0x004d9dc0 and shell_open_event_effects_modal_and_return_result 0x004d9e40 are the shared modal openers above the two editor windows; 0x004da640, 0x004da700, and 0x004d9ed0 now read as the add, edit, and remove verbs for standalone condition rows; 0x004da7c0, 0x004da860, and 0x004da920 are the matching add, edit, and remove verbs for grouped effect rows; and 0x004d8120 is now the heavier condition-row list panel refresh those condition-side verbs re-enter after mutation. The conditions-side refresh split is tighter too: 0x0042d700 aggregates standalone condition-list class or modifier flags, 0x0042d740 aggregates grouped effect-row type flags for one selected grouped list, 0x004d9970 owns the condition-class summary and grouped-row status bands, 0x004d77b0 owns the grouped summary-band affordance gate for 0x4fed..0x4ff0 when selector 0x5000 lands on 0x5002, 0x004d9d10 owns the smaller grouped-effect territory-target affordance on control 0x500b, 0x004d9f50 owns the selected-event mode strip and summary text panels, and 0x004d9390 is the mode-dependent detail-row switch beneath that strip. 0x004da0f0 is tighter too: selector 0x5001 now has the strongest current RT3.lng fit as the condition-side Test against... mode above 0x004d9970, while selector 0x5002 has the strongest current fit as the grouped-effect-side Apply effects... mode. That 0x5002 branch now clearly builds control 0x5014 from RT3.lng 1160..1164 as to the company/player/player (i.e. chairman)/territory for which the condition is TRUE before enabling the adjacent 0x5005, 0x500a, and 0x5014..0x501c family. The strongest current RT3.lng fit for the remaining visible target-scope strip is now 0x5015 = to the whole game, 0x5016..0x5018 = to all/human/AI companies, 0x5019 + 0x500b = to territories, and 0x501a..0x501c = to all/human/AI players; the grouped effect-row type mask matches that split directly through bits 0x08, 0x01, 0x04, and 0x02. The selected-event strip is tighter now too: 0x004db120 is the broader selected-event repaint and navigation refresh above those smaller helpers, 0x004db520 and 0x004db5e0 are the previous and next selected-event stepping verbs, 0x004db8b0 is the add-or-clone event modal helper, 0x004dba90 is the rename verb, 0x004d9360 is the delete verb, 0x004db6a0 is the live selected-event id setter behind control 0x4e84, and 0x004db6f0 is the callback-binding plus pending-selection bootstrap path that seeds the strip during window bring-up. The larger dispatcher at 0x004dbb80 now makes the strip explicit: 0x4e85..0x4e8a are previous, next, add blank, clone selected, rename, and delete event, while the later grouped band commits current summary state through 0x004d8d50 before changing grouped selector [this+0x9c] via 0x004dbf93. The selection bootstrap side is tighter too: 0x004daf40 is now the placeholder reset helper for the selected-event summary controls 0x4eaf, 0x4eac, 0x4ed9, 0x4edb, and 0x4fdf..0x4fe2. The grouped target-scope side is tighter too: 0x004d8ea0 now reads as the commit helper for current selected-event text panels before selection or grouped-action changes, 0x004d8d50 now records the hidden selector family 0x5006..0x500e -> 0..8, and 0x004dab60 projects that ordinal one-to-one onto the visible grouped-effect target-scope display strip 0x5014..0x501c. That split is firmer now: 0x5006..0x500e are the canonical hidden selectors that get stored into [event + group + 0x7fb], while 0x5014..0x501c are the visible mirror rows republished from that same ordinal rather than a second independently named selector family. The grouped row and stored-summary refresh side is tighter too: 0x004d88f0 is now the selected grouped-effect row-list renderer for 0x4ed5, formatting the grouped 0x28-byte rows through RT3.lng 1154..1159, and 0x004da9a0 is the current grouped-summary-state republisher that reloads 0x500a, 0x500b, and visible action selection 0x5014..0x501c from [event + group + ...] before tailing back into 0x004da0f0, 0x004dbfca as the grouped target-scope mode selector that persists the chosen control id into 0x00622074, with 0x5001/0x5002 now strongest-fit as Test against... and Apply effects..., 0x004dbeeb as the pending shared summary-text triplet publish helper for 0x4eac/0x4ed9/0x4edb, 0x004d91e0 as the selected-event summary-header and grouped-mode commit helper above 0x004d8d50, and 0x004dbe7a as the narrower 0x4ec6/0x4ec7 choice-event single-player-only warning modal branch rooted at RT3.lng 3887. The remaining gaps on this lane are narrower again because the grouped-band 0x4dc09c table now closes one earlier overclaim: controls 0x5001/0x5002 are the only 0x4fed..0x501c entries that route into 0x004dbfca on the 0xcf side, while visible rows 0x5014..0x501c only route to the smaller 0x004d9d10 affordance path and the rest of 0x4ff1..0x5013 are default no-ops. The open question is therefore no longer whether those visible target-scope rows are direct selector verbs; current evidence says they are not. The local slot records are rooted at [world+0x69d8], [slot+0x01] polarity and the external role gate at [world+0x0bc3+slot*9] are now grounded, and [slot+0x03] now looks like the distinguished primary-human-seat marker because current grounded writes seed it only on slot zero and later logic moves it solely by whole-record compaction. The open question is no longer whether the seeded trio lands in the visible shell company roster; current evidence says it does, and ordinary Start New Company now looks like a fresh-company allocator through start_new_company_dialog_commit_create_company and start_new_company_request_create_company, not like the path that claims one of the seeded named railroads. The immediate post-roster station branch is now clearly separate: current grounded resource names and handlers put mode 8 on StationDetail.win, mode 5 on StationList.win, and the subordinate modal selector helper on StationPick.win through shell_station_pick_window_open_modal_and_return_selected_station_id above shell_station_pick_window_construct. The company-side ownership question has therefore moved down a layer rather than staying open. We now have a recovered CompanyDetail.win owner family through shell_company_detail_window_refresh_controls, shell_company_detail_window_construct, and shell_company_detail_window_handle_message; the same owner now has one broader bounded read-side lane too, because control 0x9470 uses shell_company_detail_render_financial_history_panel to draw the five-step Revenue or Expenses or Interest or Profit or Lifetime strip, sibling control 0x9471 reuses shell_format_company_financial_summary_card through shell_company_detail_render_company_summary_card, controls 0x947d and 0x947e now ground a bond maturity and repay panel through shell_company_detail_render_bond_maturity_and_repay_panel, control 0x9488 now grounds the debt or credit or rate summary block through shell_company_detail_render_debt_credit_and_rate_summary_panel, control 0x948a now grounds the share-value and dividend-payout block through shell_company_detail_render_share_value_and_dividend_summary_panel, while the broader six-row per-share stock-data family is now bounded under shell_format_company_stock_data_panel, and the adjacent territory selector lane is bounded through shell_company_detail_select_territory_access_row, shell_company_detail_render_territory_access_row, shell_company_detail_sync_selected_territory_from_picker, and shell_company_detail_refresh_selected_territory_access_summary; the first finance-action layer beneath it is bounded through the bond, stock-issue, stock-buyback, and dividend-rate helpers; the territory-access side is bounded too through shell_company_detail_refresh_selected_territory_access_summary, shell_company_detail_buy_territory_access_rights_flow, and the underlying company access-rights helpers; and the full takeover and merger vote-result lane is now grounded through shell_resolve_chairmanship_takeover_vote_and_commit_outcome, shell_present_chairmanship_takeover_vote_outcome_dialog, shell_resolve_merger_vote_and_commit_outcome, and shell_present_merger_vote_outcome_dialog. The remaining company-side uncertainty is therefore narrower than before: the broader support and valuation side is now tighter too because company_compute_cached_recent_per_share_performance_subscore, company_compute_five_year_weighted_shareholder_return, and company_compute_public_support_adjusted_share_price_scalar bound the recent per-share performance and investor-support/share-price blend beneath those vote resolvers; the recent per-share feeder now has a grounded four-lane tail too, with current partial-year weight (5 * [world+0x0f]) - 5, prior full-year weights 48/36/24/12 on 0x1f/0x1e, dividend non-decline pair weights 9/8/7/6 on 0x20, lane weights 40/10/20/30, the startup age ramp 0/0/0/100 -> 25/25/35/100 -> 50/50/65/100 -> 75/75/85/100 -> 100/100/100/100, a strongest-lane *1.25 boost, a weakest-lane *0.8 reduction, and separate bounded-intermediate versus final difficulty applications under 0x005f33b8; the next consumer 0x00424fd0 is also tighter now, with the young-company interpolation against [company+0x57], caller pressure clamped to [-0.2, 0.2], one (shares / 20000)^0.33 share-count growth term, and the later threshold ladder 0.6 / 0.45 / 0.3 / 1.7 / 2.5 / 4.0 / 6.0 before the issue-0x37 multiplier, scenario_state_compute_issue_opinion_multiplier now bounds the next layer of optional company, chairman, and territory-specific opinion overrides on the active scenario state, and the broader stat-reader family around company_read_control_transfer_metric_slot and company_read_year_or_control_transfer_metric_value is no longer just a merger-premium helper. Current grounded callers show the same metric family feeding the annual shareholder-revolt and creditor-liquidation lane surfaced by localized ids 300..304, while the debt-side shell and bond lane now separately close 0x38 as Credit Rating and 0x39 as Prime Rate. That means the remaining gap is now mostly gone on the UI side too: issue 0x37 is already bounded to the same investor-confidence family as the equity-support and governance-pressure paths, and current grounded UI evidence still stops at the investor-attitude sentence family rather than one standalone caption. The calendar side is tighter now too: [world+0x15] is the absolute counter for the same mixed-radix 12 x 28 x 3 x 60 year-plus-subfield tuple packed by 0x0051d3c0 and unpacked by 0x0051d460, not just a vague “calendar-like” blob. The TrackLay.win family now clearly owns Lay single track. Lay double track. and Bulldoze as its three primary modes, its bridge selector, its wrapped frequency preferences, and a strongly aligned pair of Auto-Hide Trees During Track Lay and Auto-Show Grade During Track Lay toggles; the StationPlace.win family now clearly owns its six top-level category buttons, the station-style scroller, and the station-rotation controls. The older Building placement center string 671 no longer looks like a live StationPlace control label in the current recovered flow, because the active constructor, preview, refresh, and dispatcher paths all use neighboring ids such as 669 and 2208 without a direct recovered lookup of 671. On save or load the broad serialize-versus-restore split is now grounded, the non-Quicksave .gmp/.gmx/.gmc/.gms families are separated, and the auxiliary .gmt path is at least bounded to the preview-surface side owner. The higher-value shell-facing gap has therefore shifted upward to the remaining semantics of the post-load generation phases, the later recurring structure-population cadence, the deeper vote-weight formulas inside takeover and merger resolution, and the still-open meaning of the packed simulation calendar tuple.

CompanyDetail and Section Ownership

The shell detail family now has an explicit section-selector lane in addition to the read-side panels already mapped. Controls 0x9472..0x9475 directly select the four visible CompanyDetail sections through 0x006cfe60, 0x9476..0x9479 are the companion visual controls for that same tab strip, and section 0 is now bounded more tightly as the chairman or governance slice around the portrait-backed chairman band on 0x9480 plus the dynamic overview widget 0x947f. That widget is no longer just a vague status line: the section-0 refresh binds it through a dedicated stack-built dynamic text path, and the strongest current shared formatter candidate is shell_format_company_governance_and_economy_status_panel at 0x004e5cf0, which first renders a five-line company-metric preamble through localized ids 1211..1215: Revenues from slot 0x2c, Profits from slot 0x2b, Load miles hauled from slot 0x17, Revenue per load mile from the derived slot 0x2c / slot 0x17 branch, and Average speed from slot 0x26 rendered through 1216 %1 m.p.h.. It then splits the governance summary more concretely: no linked chairman emits 3045, wholly owned companies emit 3046 for the scenario-selected chairman or 3047 for another linked chairman, and investor-owned companies emit the investor-attitude lines 3048/3049 with one adjective from the table at 0x00622170. That branch is no longer using unnamed helpers either: company_get_linked_chairman_profile_record 0x00426ef0 resolves the linked chairman profile and chairman_profile_owns_all_company_shares 0x004768c0 is the full-ownership test behind the 3046/3047 split. The salary side is tighter too: the formatter computes one signed delta from [company+0x14f] and [company+0x0d59], then chooses 3050..3052 for the scenario-selected chairman or 3053..3055 for another linked chairman depending on whether that delta is negative, positive, or zero. The bonus line is narrower still: it only appears when the display year matches [company+0x34f], using amount [company+0x353] with 3056 or 3057. It then appends the 1218 Economy status - %1. tail caption and stages the adjacent selected-company report or list help-title pairs 1219/1220 Income Statement, 1221/1222 Balance Sheet, 1223/1224 Haulage Report, 1225/1226 Stock Report, 1227/1228 Train List, 1229/1230 Station List, 1231/1232 Industry List, and 1233/1234 Cargo List. Current evidence still does not recover separate CompanyDetail.win action controls for that strip under shell_company_detail_window_handle_message, so it currently reads as staged overview text or help content rather than as a closed launcher family. The direct 0x947f formatter call is still indirect, but the widget boundary is tighter too: the generic shell helpers shell_control_refresh_matching_dynamic_text_payload 0x00540a47 and shell_control_release_dynamic_text_payload 0x005639d2 now show that type 0x6f controls free or swap one heap-backed text payload and then short-circuit as a special dynamic-text case, which strengthens the reading of 0x947f as a display-only overview widget rather than a normal callback control. One adjacent boundary is tighter now too: the broader overview wrapper at shell_render_company_overview_panel_header_and_optional_change_affordance 0x004e5a80 owns the fallback no-company texts 1210, 3043, and 3888, styles controls 0x3f06 and 0x3f07, and on the narrower selected-company branch appends 3044 Click to change company name and logo. plus the neighboring 1941 Change affordance before falling through into the shared 0x004e5cf0 text body. That keeps the name/logo affordance outside the ordinary CompanyDetail.win action dispatcher and makes the 0x947f alignment cleaner. The message-side action band is tighter too: 0x94b5 grounds territory-access purchase, 0x94b6 grounds bankruptcy, 0x94cf..0x94d2 ground bond issue, stock issue, stock buyback, and dividend-rate changes, 0x9493 routes into the destructive company-clear helper that deactivates the selected company and clears chairman/share links, 0x94d6 grounds bankruptcy, 0x94d7..0x94da ground bond issue, stock issue, stock buyback, and dividend-rate changes, 0x94db grounds merger, 0x94dc grounds resignation, and 0x9538 grounds chairmanship takeover. The finance-side dialog family is tighter too: the bond-issue lane now has the dedicated modal renderer shell_company_detail_render_issue_bond_offer_dialog 0x004c3560 for underwriter terms 968..972, the stock-issue lane has shell_company_detail_render_issue_stock_offer_dialog 0x004c3b50 for the staged offer lines 975..978, and the buyback lane has shell_company_detail_render_stock_buyback_offer_dialog 0x004c4300 for broker lines 981..984. The compact summary card on sibling control 0x9471 is tighter too: shell_format_company_financial_summary_card at 0x004bfb30 now clearly renders Cash:, Revenue:, and Profits: from company slots 0x0d, 0x2c, and 0x2b, rather than one looser unnamed finance block. The dividend lane is now split the same way: shell_company_detail_setup_dividend_rate_adjust_controls 0x004c4c70 binds the paired adjust controls 0x99e8 and 0xc0f9, shell_company_detail_render_change_dividend_rate_dialog 0x004c4e30 renders localized ids 988..990, and shell_company_detail_handle_change_dividend_rate_dialog_message 0x004c5140 clamps the staged dividend rate against company_compute_board_approved_dividend_rate_ceiling 0x00426260 and raises localized id 991 when the board refuses a higher dividend, all before the existing company commit path. All four finance verbs now converge through the shared callback-driven modal opener shell_open_custom_modal_dialog_with_callbacks 0x004c98a0, which is also reused by the multiplayer staged text-entry lane. The front controls in section 0 are tighter too: 0x948b is a tutorial-guarded escape or back control that shows localized id 3724 This option is disabled in the tutorial. before falling back to the shell detail-manager escape path, 0x9491 and 0x9492 only restyle the paired visuals 0x948f and 0x9490, and 0x9494 opens localized id 3635 Enter the amount that your company's cash should be and writes the accepted value directly into the selected company cash pair. The neighboring debt section is tighter now too: controls 0x947d and 0x947e no longer read as one-off bond widgets, but as the owners of two repayable bond-slot row bands, 0x94e8..0x950f and 0x9510..0x9537. Those row controls now clearly converge on the same repayment path in the message dispatcher: they reject unaffordable repayment through localized id 2990, open the early-repayment confirmation rooted at 2991, and then either commit through company_repay_bond_slot_and_compact_debt_table 0x00423d70 or package the request through the multiplayer shell transport. The render-side owner is tighter too: shell_company_detail_render_bond_maturity_and_repay_panel formats Due %1 and Repay this bond. for the selected debt slot while the tiny binder shell_company_detail_bind_bond_row_band_for_active_panel switches between the two row bands. Current 0xcb dispatch does not treat 0x948f, 0x9490, 0x94d4, or 0x94d5 as standalone action cases. The message-side jump table now makes that passive/action split explicit too: in the dispatch byte map rooted at 0x004c6640, controls 0x94d6..0x94dc map to cases 0x06..0x0c, control 0x9538 maps to case 0x0d, and the neighboring companion rows 0x94d4 and 0x94d5 stay on the default path. The refresh-side ownership is tighter too: the helper now explicitly loops over 0x94d4..0x9537 as the selected-company-owned band and over 0x9538..0x959b as the linked-chairman-owned band, and those two loops do not use the same style polarity. 0x94d4..0x9537 take style 0x65 when the selected company matches the scenario-selected company and 0x87 when it differs, while 0x9538..0x959b take style 0x87 when the selected company's linked chairman matches the scenario-selected chairman and 0x65 otherwise. The selected-company action side is tighter now too: scenario toggle 0x006cec78+0x4a8f re-enables bankruptcy 0x94d6 together with passive companion row 0x94d4, +0x4a8b re-enables issue bonds 0x94d7 together with passive companion row 0x94d5, +0x4a87 re-enables stock issue and stock buyback 0x94d8..0x94d9, +0x4a93 re-enables dividend 0x94da together with the same passive companion row 0x94d5, +0x4adb re-enables merger 0x94db, +0x4acb re-enables resignation 0x94dc, and +0x4acf re-enables chairmanship takeover 0x9538. That makes 0x94d4/0x94d5 read more like passive companion or heading widgets than hidden verbs. The constructor boundary is tighter too: current CompanyDetail.win setup still only binds explicit callbacks for 0x9470, 0x9471, 0x947d, 0x947e, and 0x948c..0x948e, not for the wider section-0 row bands. That keeps the remaining 0x94d4..0x959b content looking more like resource-defined display rows that are gated and restyled by refresh than like individually code-rendered widgets. That leaves the main remaining CompanyDetail-specific shell edge at the exact 0x947f formatter binding plus the still-unsplit render-side governance rows inside 0x94d4..0x959b.

Adjacent LoadScreen.win Report Family

The neighboring shell lane around controls 0x3ef6..0x4073 is now separated from CompanyDetail instead of being treated as one more extension of the 0x947f overview path. The real outer owner is shell_load_screen_window_construct 0x004ea620, which binds LoadScreen.win, randomizes the LoadScreen%d.imb background family, stores the singleton at 0x006d10b0, and seeds the first visible page-strip controls. Above the older page-specific work, the real message owner is now shell_load_screen_window_handle_message 0x004e3a80: it owns page id [this+0x78], page-local substate [this+0x7c], page-kind [this+0x80], current company [this+0x88], current chairman profile [this+0x8c], display year [this+0x9c], and the page-local report row latch [this+0x118], then fans back into the shared selector shell_load_screen_select_page_subject_and_refresh 0x004e2c10, the company-step helper 0x004e3a00, and narrower page branches such as 0x004e45d0. The matching render-side owner is now bounded too: shell_load_screen_render_active_page_panel at 0x004ea060 formats the common heading and panel frame, then switches on page id [this+0x78] and hands control down into the active page body. That older branch is now demoted to what it actually is: shell_load_screen_profile_stock_holdings_page_handle_message, the page-specific handler beneath the stock-holdings slice. Inside that same family, shell_load_screen_render_profile_stock_holdings_summary_panel at 0x004e5300 grounds the selected-profile holdings page: it resolves the current chairman profile from [this+0x8c], renders the top summary rows 1204 Stock Value:, 1205 Total Assets:, and 1206 Stock Holdings:, then walks the active company roster and formats one row per positive holding through 1201 Click to view details on %1., 1207 %1 Shares, and 1208 %1 Value, falling back to 1209 None when no positive holdings survive. It also appends 3029 Click to change player name and portrait. plus the adjacent 1941 Change affordance only when the rendered profile matches the scenario-selected chairman. The earlier pages are tighter now too: 0x004e68e0 is the selected-company financial ranking page using the active company roster plus 1235..1245 for revenue, profit, cash, track mileage, and report affordances; and 0x004e6ef0 is the active-chairman wealth ranking page using the chairman profile collection plus 1237, 1241, 1246..1250 for cash, stock, total, and purchasing-power style comparisons. The later sibling renderers are broader than that one holdings page now too: 0x004e7670 is the selected-company train list page using 1235..1267, 0x004e8270 is the selected-company building list page using 1268..1278, 0x004e8bb0 is the selected-company station list page using 1279..1288, and 0x004e9460 is the map-wide cargo list page using 1289..1298 over the live candidate collection rather than one company roster. The last broad early-page owner is tighter now too: 0x004e9b20 is the shared multi-year company report-table renderer for page 4 Income Statement, page 5 Balance Sheet, and page 6 Haulage Report, all driven from 0x004ea060 with one caller-supplied mode byte and yearly company rows built through company_read_year_or_control_transfer_metric_value. The row families are bounded too: income-statement rows 1301..1315, balance-sheet rows 2816 and 1317..1322, and haulage-report rows 1323..1335. The only special rows inside that family are now tighter too: 0x00425880 and 0x004258c0 provide the negative-cash and positive-cash interest-rate inserts for the %1/%2 placeholders in strings 2815 and 2816, so they are no longer anonymous private math blobs. The adjacent early siblings are tighter now too: 0x004e5130 is the selected-company Stock Data page wrapper that falls back through 1299 and otherwise reuses 0x004c0160 to render the Largest Shareholders, Shares, and Per Share Data family; 0x004e6ef0 is the Player List page; 0x004e5300 is the Player Detail holdings page; and 0x004e51ea is the Game Status briefing panel that pulls current scenario briefing text from the live scenario text store and appends the 1772/1773 Briefing affordance. The active-page renderer at 0x004ea060 is now tighter too because its 13-byte page descriptor table at 0x006220a0 has been decoded directly as { page kind, title string id, 0x3ef8 backlink page, selected-company-header flag }. The currently grounded rendered title order is: XXX, COMPANY OVERVIEW, COMPANY LIST, INCOME STATEMENT, BALANCE SHEET, HAULAGE REPORT, STOCK DATA, PLAYER LIST, PLAYER DETAIL, GAME STATUS, TRAIN LIST, TRAIN DETAIL, STATION LIST, STATION DETAIL, CARGO LIST, and INDUSTRY LIST. Its live body bindings are now bounded too: page 0 falls back to 1203 Unable to display page, page 1 is the company overview wrapper, page 2 is the company list page, pages 3..5 are income statement, balance sheet, and haulage report, page 6 is stock data, page 7 is player list, page 8 is player detail, page 9 is game status, page 0x0a is train list, page 0x0b currently falls back to 1203, page 0x0c is station list, page 0x0d currently falls back to 1203, page 0x0e is cargo list, and page 0x0f is industry list. The row-click path is tighter now too: player-list rows re-enter page 8 directly, but train, station, and industry rows leave LoadScreen.win through the shell detail-panel manager at 0x004ddbd0 instead of switching to title-table pages 0x0b or 0x0d. Page 0 is tighter now too: its descriptor is kind 0, title 1200 XXX, backlink 0, and header flag 0, and no current post-constructor selector path has been recovered for it. The descriptor side now also bounds the only known reverse route for the dormant detail titles: 0x3ef8 is the table-driven backlink affordance, so if page 0x0b or 0x0d were ever selected, the known reverse path would return to train-list page 0x0a or station-list page 0x0c respectively rather than through a separate detail-only owner. The launcher side is tighter too: current grounded shell_open_or_focus_load_screen_page callers cover pages 1, 2, 3, 4, 5, 6, 7, 9, 0x0a, 0x0c, 0x0e, and 0x0f, and no current recovered opener or row-click route selects 0x0b or 0x0d. So the LoadScreen.win family now has a much cleaner shape: one outer message owner 0x004e3a80, one active-page render owner 0x004ea060, and then the narrower page-specific handlers and renderers beneath them. The launcher side is tighter now too: 0x004e4ee0 is the shared open-or-focus ledger-page owner above this family. Outside sandbox it either re-enters shell_load_screen_select_page_subject_and_refresh on the live runtime at 0x006d10a8 or allocates that transient runtime, seeds it through 0x004e4b10, and enters the visible modal loop; inside sandbox it raises localized id 3899 The ledger is not available in sandbox mode. instead. The direct shell-command strip above that opener is now explicit too: 0x00440700..0x0044086e are just tiny scenario-present -> open page wrappers for pages 1, 3, 4, 5, 6, 0x0a, 0x0c, 0x0f, 0x0e, 2, 7, and 9 respectively. So the recovered launcher range is no longer only “callers of 0x004e4ee0” in the abstract; each of those small shell-command stubs now just forwards one fixed page id into the shared opener. instead. That narrows the remaining LoadScreen.win gap again: TRAIN DETAIL and STATION DETAIL now read as dormant title-table entries unless some still-unrecovered nonstandard selector reaches them. The live auto-load boundary is tighter now too: hook-driven shell_transition_mode(4, 0) now completes old-mode teardown, reconstructs and republishes LoadScreen.win, and returns cleanly, but the later post-transition service ticks still keep [0x006cec78] = 0, [shell_state+0x0c] on the same LoadScreen.win singleton, and [LoadScreen.win+0x78] = 0 through at least counts 2..8. So the next runtime edge is no longer the old mode-4 teardown or publish band; it is the LoadScreen.win message owner 0x004e3a80 itself, because later service alone is not promoting the plain load screen into the separate startup-runtime object path. One later runtime probe did not actually reach that edge: the 0x004e3a80 hook installed, but the run never produced any ready-count, staging, transition, post-transition, or load-screen-message lines, only ordinary shell node-vcall traffic. So that result is now treated as a gate-or-cadence miss rather than as evidence against the LoadScreen.win message path itself. The newer shell-state service trace tightens it again: on a successful staged run the later service ticks do execute in mode_id = 4, but the 0x004e3a80 message hook still stays silent while the state remains frozen in the plain LoadScreen.win shape. So the next runtime boundary is now the shell-runtime prime call 0x00538b60 beneath shell_state_service_active_mode_frame 0x00482160, not the message owner alone. The first direct 0x00538b60 probe run is not trustworthy yet, though: it stopped immediately after the first shell-state service-entry line, before any ready-count or runtime-prime entry logs. So that result is currently treated as probe validation work, not as a real boundary move inside RT3. The static service branch is conditional too: 0x00482160 only enters 0x00538b60 when [shell_state+0xa0] == 0, so silence from the runtime-prime hook does not yet prove the shell stops before that call unless the service-entry logs also show the +0xa0 gate open. The newer run now closes that condition: [shell_state+0xa0] is 0, and the 0x00538b60 runtime-prime hook enters and returns cleanly. The newer run closes the next owner too: 0x00520620 shell_service_frame_cycle also enters and returns cleanly on the same frozen mode-4 path, and the logged fields match its generic branch rather than a startup-promotion lane ([+0x1c] = 0, [+0x28] = 0, flag_56 = 0, [+0x58] pulsed then cleared, and 0x006cec78 stayed 0). The static body under the same owner is tighter now too: 0x00538b60 first re-enters 0x0054f6a0, refreshes the primary timed-text lane from [owner+0x1c] through 0x005386e0 when that deadline has expired, walks the registered shell-window list from tail [owner+0x04] backward through +0x54 while servicing each node through 0x0053fda0 and 0x0051f1d0, and only then conditionally presents the secondary and primary text lanes through 0x005519f0. So the next runtime boundary under the same shell-state service pass is now one level deeper: the per-object service walker 0x0053fda0 beneath 0x00538b60. The newer run closes that owner too: it enters and returns cleanly while servicing the LoadScreen.win object itself, with field_1d = 1, field_5c = 1, and a stable child list under [obj+0x70/+0x74], and its first child-service vcall target at slot +0x18 stays 0x005595d0. Since 0x006cec78 still stays 0 through those clean object-service passes, the next runtime boundary is now the child-service target 0x005595d0, not the higher object walker. The newer child-service run narrows that again: the first sixteen 0x005595d0 calls are stable child lanes under the same LoadScreen.win parent, with [child+0x86] pointing back to the load-screen object, field_b0 = 0, and a split where earlier children carry flag_68 = 0x03 and return 4 while later siblings carry flag_68 = 0x00 and return 0. The static body matches that read too: 0x005595d0 is gated by 0x00558670 and then spends most of its work in draw or overlay helpers 0x54f710, 0x54f9f0, 0x54fdd0, 0x53de00, and 0x552560, so it now reads as another presentation-side service lane rather than the missing startup-runtime promotion. The widened allocator-window trace then reconciled the runtime with the static mode-4 branch one step further: the first transition-window allocation is 0x7c, which matches the static pre-construct 0x48302a -> 0x53b070 alloc exactly, and the later 0x111/0x84/0x3a/0x25... allocations all occur before LoadScreen.win construct returns, so they now read as constructor-side child or control setup. That means the allocator probe did not disprove the still-silent startup-runtime slice; it simply exhausted its log budget inside the constructor before the post-construct block. The later reset-at-return run is now the decisive one: after LoadScreen.win construct returns there are still no further allocator hits before publish and transition return, which matches the corrected jump-table decode because mode 4 does not own the 0x46c40 -> 0x4336d0 -> 0x438890 startup-runtime path.