diff --git a/artifacts/exports/rt3-1.06/runtime-effect-kind8-tier2-named-availability-note.md b/artifacts/exports/rt3-1.06/runtime-effect-kind8-tier2-named-availability-note.md index dc5c9da..a0cb78c 100644 --- a/artifacts/exports/rt3-1.06/runtime-effect-kind8-tier2-named-availability-note.md +++ b/artifacts/exports/rt3-1.06/runtime-effect-kind8-tier2-named-availability-note.md @@ -87,3 +87,135 @@ So the next Tier 2 recovery question is now tighter still: or cargo-membership/runtime-record reconstruction under `0x00437737 / 0x00412c10 / 0x00412bd0 / 0x00412d70 / 0x00412fb0`, rather than in the direct named availability bit for `Warehouse05` itself. + +## Nearest Single-Import Peer Check + +The same boundary now holds against the nearest single-import recipe peer too: + +- `Louisiana.gmp` +- `South East USA.gmp` + +Direct `inspect-candidate-table` checks still keep the key port/warehouse rows aligned: + +- `Warehouse05` + - `Louisiana.gmp = 1` + - `South East USA.gmp = 1` +- `Port01` + - `Louisiana.gmp = 1` + - `South East USA.gmp = 1` + +So even after the recipe-side frontier moved from “same coarse mode shape” to “same single-import +family,” the direct named-availability table still does not provide the missing Tier 2 split for +the shipped `5200 :: [7:0]` `Add Building Warehouse05` row. + +That leaves the same later owners as the honest next focus: + +- `0x00412d70` template-bank and runtime-record rebuild +- `0x00411ce0 / 0x00411ee0` dependent mode-flag and cargo-summary refresh +- `0x00412c10` latch refresh after those runtime records already exist + +## Port Versus Warehouse Runtime Roots + +One broader binary pass now closes the fixed-root ambiguity inside `0x00412d70`. + +Direct `objdump` over `RT3.exe` shows the two built-in format roots are: + +- `0x005c93d8 = "Warehouse%02d"` +- `0x005c93e8 = "Port%02d"` + +And the candidate rebuild chooses between them exactly as: + +- if `[candidate+0xba] != 0` + - use `Port%02d` +- else + - use `Warehouse%02d` + +So the later Tier 2 runtime-record frontier is no longer an abstract “two built-in roots” question. +It is specifically: + +- how `0x00412d70` bank or template selection and the live availability bytes + `[candidate+0xba/+0xbb]` determine which rebuilt candidates land on the `Warehouse%02d` side + versus the `Port%02d` side +- and why the `Warehouse%02d` side in `Louisiana.gmp` is the one that later lines up with the + shipped `5200 :: [7:0]` `Add Building Warehouse05` strip + +That also keeps the direct named-availability boundary honest: + +- `Warehouse05 = 1` in the fixed scenario table still does not explain the runtime split by itself +- the next meaningful owner seam is the later port-versus-warehouse runtime-record rebuild under + `0x00412d70`, before `0x00412c10` mirrors anything into `[candidate+0x7ac]` + +## Writer-Side Split Above The Availability Bytes + +One more direct disassembly pass narrows that owner seam further. + +`structure_candidate_stream_load_runtime_record_and_rebuild_cargo_state` `0x004120b0` does +rebuild a substantial portion of each live candidate record: + +- clears dependent runtime pointers and flags such as + `[candidate+0x79c/+0x7a0/+0x78c/+0x790/+0x794/+0x7b0]` +- reads the fixed per-record stream fields at + `[candidate+0x04/+0x22/+0x26/+0x28/+0x2a/+0x2e/+0x32/+0x33]` +- restores the selector-bank bytes + `[candidate+0xb9/+0xba/+0xbb]` +- allocates and streams the packed `0xbc` descriptor array into `[candidate+0x37]` + +So the current strongest ownership split is now: + +- direct named-availability table `[state+0x66b2]` is not the missing differentiator by itself +- both source-record import `0x00414490` and per-record stream-load `0x004120b0` do carry the + relevant selector-bank bytes from persisted/source state into the live candidate family +- but the stock `Data/BuildingTypes/*.bca` corpus currently keeps `[record+0xb8/+0xb9/+0xba/+0xbb]` + at zero across every observed file, including `Warehouse.bca` and `Port.bca` +- so the surviving frontier is no longer “does the lower loader import `[candidate+0xba/+0xbb]`?” + but rather which later owner or alternate content path makes the live bank-qualified split differ + from that all-zero shipped BCA corpus before `0x00412d70` clones or reuses one bank-qualified + live candidate + +That makes the next Tier 2 question more concrete still: + +- how any nonzero bank-qualified template source under `[candidate+0xba]` versus `[candidate+0xbb]` + is actually seeded above the stock all-zero BCA corpus, and then + drives the later `Warehouse%02d` side in `Louisiana.gmp` +- and whether that preserved bank/template state is the real bridge from the minimal recipe cluster + to the shipped `5200 :: [7:0]` `Add Building Warehouse05` row + +## Later Consumer-Side Reads Already Narrowed + +One broader non-hook pass now rules several tempting later neighbors onto the consumer side rather +than the missing writer or projection seam. + +- `aux_candidate_collection_rebank_or_clone_records_by_availability_pass_and_refresh_owner_links` + `0x00419230` does not seed `[candidate+0xba/+0xbb]` into the live candidate pool. It walks the + already-imported auxiliary/source pool at `0x0062b2fc`, selects template records only when the + linked live owner candidate at `[entry+0x173]` already passes the current bank test (`+0xba` on + pass `0`, `+0xbb` on pass `1`), and then clones or reuses auxiliary entries before stamping the + built-in `Port%02d` / `Warehouse%02d` roots back into `[entry+0x22]` and `[entry+0x04]`. +- `world_grid_refresh_projected_rect_sample_band_and_flag_mask` `0x00418610` is also only a + consumer of the same candidate-bank state. It resolves the current candidate through helper + accessors, uses `candidate[0xba]` and the subtype/class predicates as mode inputs for the + projected-rectangle sample pass, and never writes the candidate bank bytes. +- the broader projected-offset lane at `0x0041a5fd..0x0041a944` is the same shape: after geometric + reuse tests it resolves the current candidate owner, immediately branches on `candidate[0xba]`, + and then either runs one world-cell occupancy sweep or falls back to localized status strings. + Current direct disassembly still shows this path consuming the bank byte as a gate, not + reconstructing it. + +So the surviving frontier is narrower again: + +- `0x00414490`, `0x004120b0`, and the shipped `BuildingTypes/*.bca` corpus explain how the stock + zero bank bytes enter the source and live candidate families +- `0x00419230`, `0x00418610`, and `0x0041a5fd..0x0041a944` explain how later auxiliary and + projected-placement consumers react to already-materialized bank bytes +- the `.smp` restore-side auxiliary temp-bank path is ruled out as a hidden bank-byte source too: + `0x00413f80` restores queued temporary images with scalar runs, inline dword runs, and paired + byte streams, but not the auxiliary fixed body or selector bytes `[+0xb8..+0xbb]`; and + `0x0041a950`, when the restore flags demand it, only releases the current live aux collection and + tail-jumps back into the same `0x004196c0 -> 0x00419230` import-plus-follow-on chain +- the world-entry load branch does not add a hidden title-specific selector in between either: + `0x00438c70` allocates the live candidate pool through `0x004131f0` and the auxiliary/source + pool through `0x0041aa50`, and both constructors tail directly into the same fixed tagged-import + families rooted at `0x005c93fc` and `.\Data\BuildingTypes\` +- but the still-missing owner is the earlier non-stock writer or restore-time projection seam that + makes some live candidates reach those later consumers with nonzero `[candidate+0xba/+0xbb]` + despite the observed all-zero BCA corpus diff --git a/artifacts/exports/rt3-1.06/runtime-effect-kind8-tier2-recipe-signature-note.md b/artifacts/exports/rt3-1.06/runtime-effect-kind8-tier2-recipe-signature-note.md index 3e73ad6..b7356b8 100644 --- a/artifacts/exports/rt3-1.06/runtime-effect-kind8-tier2-recipe-signature-note.md +++ b/artifacts/exports/rt3-1.06/runtime-effect-kind8-tier2-recipe-signature-note.md @@ -144,3 +144,155 @@ So the current checked downstream split is sharper than a generic “same mode-s That makes `Louisiana.gmp` the first checked member of that mode-shape family whose distinct exact token-bearing `book00` signature also lines up with the add-building runtime path. + +## Compact-family split inside the checked peers + +The current runtime-facing split is not just “dispatch rows present versus absent.” The checked +peer maps also diverge inside the broader `nondirect-ge1e-h0001-0007` compact family: + +- `Louisiana.gmp` reaches the checked add-building strip on + - `nondirect-ge1e-h0001-0007-0000-5200-0200-p0000-0000-0000-ffff :: [7:0]` + - with decoded label `Add Building Warehouse05` +- `Britain.gmp` keeps `nondirect-ge1e-h0001-0007-0000-4a00-0200-p0000-0000-0000-ffff` + but no add-building dispatch-strip rows +- `South East USA.gmp` keeps several other `0007` mids + - `...-3100-...` + - `...-3500-...` + - `...-3800-...` + - `...-3b00-...` + - `...-4200-...` + and again no add-building dispatch-strip rows + +So the current checked peer split is now: + +- same coarse mode-shape family +- different exact token-bearing `book00` signature +- different `h0001-0007` mid-word family at runtime +- only `Louisiana.gmp` currently reaches the `5200 :: [7:0]` add-building strip + +## Minimal imported-cluster split + +The next corpus pass sharpens that again. + +`Louisiana.gmp` is not the only map that reuses pieces of the apparent `lC / 0x00080000 / +0x00004080` cluster: + +- `Ireland.gmp` carries + - `book02.line01 = demanded 0x6c430000` + - `book02.line02 = mode 0x00080000, supplied 0x00004080` + - plus additional active rows in `book00`, `book01`, and `book03` +- `Eastern China.gmp` carries + - `book02.line00 = demanded 0x00010000` + - `book02.line01 = demanded 0x6c430000` + - `book02.line02 = mode 0x00080000, supplied 0x00004080` + - plus additional active rows in `book00` and `book01` + +But the exact three-row cluster as the *entire* nonzero imported recipe surface is unique to +`Louisiana.gmp` in the 41-map corpus: + +- `book00.line00 = demanded 0x00010000` +- `book00.line01 = demanded 0x6c430000` +- `book00.line02 = mode 0x00080000, supplied 0x00004080` + +No other bundled map keeps exactly that three-line imported set and nothing else. + +That matters on the runtime side too: + +- `Ireland.gmp` still has no add-building dispatch-strip rows at all + - `add_building_dispatch_strip_records_missing_trigger_kind = 0` + - checked `0007` family stays on `...-6300-...` +- `Eastern China.gmp` also has no add-building dispatch-strip rows at all + - `add_building_dispatch_strip_records_missing_trigger_kind = 0` + - checked `0007` mids stay on other families such as `...-a100-...`, `...-a600-...`, + `...-b100-...`, `...-b700-...`, `...-cf00-...`, and `...-d100-...` + +So the stronger current read is no longer just “the `0x00080000 / 0x00004080` triplet exists +somewhere.” It is: + +- `Louisiana.gmp` is the only bundled map whose whole imported nonzero recipe surface collapses to + that exact three-row cluster +- maps that merely reuse pieces of the cluster do not currently reach the same add-building strip + +That makes the next Tier 2 question smaller again: + +- whether the `5200 :: [7:0]` add-building strip is tied to that minimal imported-cluster shape + specifically, rather than to the presence of any one of its component token rows in a broader + recipe profile + +## Single-import-row family + +The broader 41-map corpus narrows the same point one step further. + +There are multiple bundled maps whose imported runtime side still materializes only one nonzero +recipe row: + +- `Britain.gmp` +- `Crossing the Alps.gmp` +- `France.gmp` +- `Germantown.gmp` +- `Louisiana.gmp` +- `Mississippi Valley.gmp` +- `South East USA.gmp` +- `Third Republic.gmp` + +But `Louisiana.gmp` is the narrowest member of that family. + +Among those eight single-import maps: + +- `Louisiana.gmp` is the only one with just **two** remaining mode-zero token rows + - `book00.line00 = demanded 0x00010000` + - `book00.line01 = demanded 0x6c430000` + - `book00.line02 = mode 0x00080000, supplied 0x00004080` +- every other checked single-import map keeps **three or four** additional token-bearing rows + +And the runtime split stays aligned with that narrower read: + +- `Louisiana.gmp` is currently the only checked single-import map that reaches an add-building + dispatch-strip row at all + - `nondirect-ge1e-h0001-0007-0000-5200-0200-p0000-0000-0000-ffff :: [7:0]` + - `Add Building Warehouse05` +- `Britain.gmp` and `South East USA.gmp`, the nearest earlier mode-shape peers, do not +- `Ireland.gmp` and `Eastern China.gmp`, which reuse the `0x00080000 / 0x00004080` triplet inside + broader profiles, also do not + +So the next checked discriminator is narrower again than “single imported row” by itself: + +- the current strongest recipe-side predictor is the exact **minimal** imported cluster + (`two demand rows + one imported row`) rather than either + - the coarse `book00.line02` mode shape + - the presence of one `0x00080000 / 0x00004080` imported row somewhere + - or the broader “only one imported row exists” family + +## Importer-side boundary + +One more direct `inspect-smp` check now trims the next step again. + +At the first importer bridge itself, `Louisiana.gmp` does **not** separate cleanly from the nearest +single-import peers: + +- `Louisiana.gmp` + - exactly one line with `imports_to_runtime_descriptor = true` + - that line is `runtime_import_branch_kind = nonzero-supply-branch` +- `Britain.gmp` + - also exactly one imported line + - also `runtime_import_branch_kind = nonzero-supply-branch` +- `South East USA.gmp` + - also exactly one imported line + - also `runtime_import_branch_kind = nonzero-supply-branch` + +By contrast, the broader reuse case stays broader at the importer too: + +- `Ireland.gmp` imports four nonzero supply-branch rows + +So the current checked boundary is now explicit: + +- the exact minimal `two demand rows + one imported row` cluster still narrows the recipe-side + frontier strongly +- but the first importer bridge does not by itself explain the `5200 :: [7:0]` split among the + nearest single-import peers + +That shifts the next Tier 2 question one layer later: + +- the likely differentiator now lives after the first `0x00435630` import step, in the later + `0x00412d70 / 0x00412fb0 / 0x00412c10` runtime-record and named-availability interaction rather + than in the coarse importer branch-kind classification alone diff --git a/crates/rrt-fixtures/src/load.rs b/crates/rrt-fixtures/src/load.rs index 9504c8e..4efd0d8 100644 --- a/crates/rrt-fixtures/src/load.rs +++ b/crates/rrt-fixtures/src/load.rs @@ -286,6 +286,10 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, + region_fixed_row_run_summary: None, + placed_structure_collection: None, + placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, event_runtime_collection: None, notes: vec![], @@ -431,6 +435,10 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, + region_fixed_row_run_summary: None, + placed_structure_collection: None, + placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, event_runtime_collection: Some( rrt_runtime::SmpLoadedEventRuntimeCollectionSummary { @@ -448,6 +456,20 @@ mod tests { live_entry_ids: vec![7], decoded_record_count: 1, imported_runtime_record_count: 0, + records_with_trigger_kind: 0, + records_missing_trigger_kind: 0, + nondirect_compact_record_count: 0, + nondirect_compact_records_missing_trigger_kind: 0, + trigger_kinds_present: vec![], + add_building_dispatch_strip_record_indexes: vec![], + add_building_dispatch_strip_descriptor_labels: vec![], + add_building_dispatch_strip_records_with_trigger_kind: 0, + add_building_dispatch_strip_records_missing_trigger_kind: 0, + add_building_dispatch_strip_row_shape_families: vec![], + add_building_dispatch_strip_signature_families: vec![], + add_building_dispatch_strip_condition_tuple_families: vec![], + add_building_dispatch_strip_signature_condition_clusters: vec![], + control_lane_notes: vec![], records: vec![rrt_runtime::SmpLoadedPackedEventRecordSummary { record_index: 0, live_entry_id: 7, diff --git a/crates/rrt-runtime/src/building.rs b/crates/rrt-runtime/src/building.rs index e42cd74..f369735 100644 --- a/crates/rrt-runtime/src/building.rs +++ b/crates/rrt-runtime/src/building.rs @@ -17,6 +17,10 @@ pub struct BuildingTypeSourceFile { pub raw_stem: String, pub canonical_stem: String, pub source_kind: BuildingTypeSourceKind, + #[serde(default)] + pub byte_len: Option, + #[serde(default)] + pub bca_selector_probe: Option, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -27,6 +31,29 @@ pub struct BuildingTypeSourceEntry { pub file_names: Vec, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct BuildingTypeBcaSelectorProbe { + pub byte_0xb8: u8, + pub byte_0xb8_hex: String, + pub byte_0xb9: u8, + pub byte_0xb9_hex: String, + pub byte_0xba: u8, + pub byte_0xba_hex: String, + pub byte_0xbb: u8, + pub byte_0xbb_hex: String, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct BuildingTypeBcaSelectorPatternSummary { + pub byte_len: usize, + pub byte_0xb8_hex: String, + pub byte_0xb9_hex: String, + pub byte_0xba_hex: String, + pub byte_0xbb_hex: String, + pub file_count: usize, + pub sample_file_names: Vec, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct BuildingTypeNamedBindingComparison { pub bindings_path: String, @@ -42,9 +69,11 @@ pub struct BuildingTypeSourceReport { pub bca_file_count: usize, pub bty_file_count: usize, pub unique_canonical_stem_count: usize, + pub bca_selector_pattern_count: usize, #[serde(default)] pub named_binding_comparison: Option, pub notes: Vec, + pub bca_selector_patterns: Vec, pub files: Vec, pub entries: Vec, } @@ -78,6 +107,7 @@ pub fn inspect_building_types_dir_with_bindings( "bty" => BuildingTypeSourceKind::Bty, _ => continue, }; + let bytes = fs::read(entry.path())?; let raw_stem = Path::new(&file_name) .file_stem() .and_then(|stem| stem.to_str()) @@ -90,7 +120,12 @@ pub fn inspect_building_types_dir_with_bindings( file_name, canonical_stem: canonicalize_building_stem(&raw_stem), raw_stem, - source_kind, + source_kind: source_kind.clone(), + byte_len: Some(bytes.len()), + bca_selector_probe: match source_kind { + BuildingTypeSourceKind::Bca => Some(probe_bca_selector_bytes(&bytes)), + BuildingTypeSourceKind::Bty => None, + }, }); } @@ -141,10 +176,45 @@ pub fn inspect_building_types_dir_with_bindings( .iter() .filter(|file| matches!(file.source_kind, BuildingTypeSourceKind::Bty)) .count(); + let mut grouped_selector_patterns = + BTreeMap::<(usize, String, String, String, String), Vec>::new(); + for file in &files { + let Some(probe) = &file.bca_selector_probe else { + continue; + }; + grouped_selector_patterns + .entry(( + file.byte_len.unwrap_or_default(), + probe.byte_0xb8_hex.clone(), + probe.byte_0xb9_hex.clone(), + probe.byte_0xba_hex.clone(), + probe.byte_0xbb_hex.clone(), + )) + .or_default() + .push(file.file_name.clone()); + } + let bca_selector_patterns = grouped_selector_patterns + .into_iter() + .map( + |( + (byte_len, byte_0xb8_hex, byte_0xb9_hex, byte_0xba_hex, byte_0xbb_hex), + file_names, + )| BuildingTypeBcaSelectorPatternSummary { + byte_len, + byte_0xb8_hex, + byte_0xb9_hex, + byte_0xba_hex, + byte_0xbb_hex, + file_count: file_names.len(), + sample_file_names: file_names.into_iter().take(12).collect(), + }, + ) + .collect::>(); let notes = vec![ "BuildingTypes sources are grouped by a canonical stem that lowercases and strips spaces, underscores, and hyphens so paired .bca/.bty variants collapse onto one asset token.".to_string(), "This report is an offline asset-pool view only; it does not by itself assign live candidate ids or prove scenario candidate-table availability.".to_string(), + "For .bca files, the report also exposes the narrow selector-byte window at offsets 0xb8..0xbb used by the grounded aux-candidate and live-candidate stream decoders.".to_string(), ]; let named_binding_comparison = if let Some(bindings_path) = bindings_path { @@ -158,13 +228,32 @@ pub fn inspect_building_types_dir_with_bindings( bca_file_count, bty_file_count, unique_canonical_stem_count: entries.len(), + bca_selector_pattern_count: bca_selector_patterns.len(), named_binding_comparison, notes, + bca_selector_patterns, files, entries, }) } +fn probe_bca_selector_bytes(bytes: &[u8]) -> BuildingTypeBcaSelectorProbe { + let byte_0xb8 = bytes.get(0xb8).copied().unwrap_or(0); + let byte_0xb9 = bytes.get(0xb9).copied().unwrap_or(0); + let byte_0xba = bytes.get(0xba).copied().unwrap_or(0); + let byte_0xbb = bytes.get(0xbb).copied().unwrap_or(0); + BuildingTypeBcaSelectorProbe { + byte_0xb8, + byte_0xb8_hex: format!("0x{byte_0xb8:02x}"), + byte_0xb9, + byte_0xb9_hex: format!("0x{byte_0xb9:02x}"), + byte_0xba, + byte_0xba_hex: format!("0x{byte_0xba:02x}"), + byte_0xbb, + byte_0xbb_hex: format!("0x{byte_0xbb:02x}"), + } +} + fn load_named_binding_comparison( bindings_path: &Path, entries: &[BuildingTypeSourceEntry], @@ -214,3 +303,24 @@ struct BuildingBindingRow { #[serde(default)] candidate_name: Option, } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn probes_bca_selector_bytes_from_fixed_offsets() { + let mut bytes = vec![0u8; 0xbc + 1]; + bytes[0xb8] = 0x12; + bytes[0xb9] = 0x34; + bytes[0xba] = 0x56; + bytes[0xbb] = 0x78; + let probe = probe_bca_selector_bytes(&bytes); + assert_eq!(probe.byte_0xb8, 0x12); + assert_eq!(probe.byte_0xb9, 0x34); + assert_eq!(probe.byte_0xba, 0x56); + assert_eq!(probe.byte_0xbb, 0x78); + assert_eq!(probe.byte_0xb8_hex, "0x12"); + assert_eq!(probe.byte_0xbb_hex, "0x78"); + } +} diff --git a/crates/rrt-runtime/src/smp.rs b/crates/rrt-runtime/src/smp.rs index 8740b20..be16ac6 100644 --- a/crates/rrt-runtime/src/smp.rs +++ b/crates/rrt-runtime/src/smp.rs @@ -5597,6 +5597,9 @@ fn build_periodic_company_service_trace_report( notes.push( "The per-company cache-cell layout is bounded now too: 0x004093d0 and 0x00407bd0 use bytes +0x00/+0x01 as the initial participation gates, dword +0x02 as the peer-row count, dword +0x06 as the peer-row pointer, dword +0x0a as the shorter peer-cache refresh stamp, and floats +0x0e/+0x12/+0x16 as the weighted/raw/final linked-transit score lanes. The candidate-table and route-entry-tracker owners are bounded above that too: 0x0062ba8c is constructed through 0x0041f4e0 -> 0x0041ede0 -> 0x0041e970, while 0x004a6360 / 0x004a6630 sit under owner-notify refresh 0x00494fb0. The remaining linked-transit gap is narrower again: subtype-4 follow-on 0x0040eba0 already republishes [site+0x2a4] through 0x004814c0 / 0x00481480 and world-cell chain helpers 0x0042c9f0 / 0x0042c9a0, and direct inspection of 0x0040ea96..0x0040eb65 shows that owner-company branch only consumes [site+0x276] rather than rehydrating it. That pushes the open question one level earlier to whichever restore or service owner feeds [site+0x276] and the live linked-peer rows before this replay continuation runs.".to_string(), ); + notes.push( + "One nearby live helper strip is narrower now too: 0x004337a0 is exactly the raw selected-company getter over [world+0x21], used in the replay-side sibling around 0x0040e775 only to compare the current selection against [site+0x276]. The adjacent world-side helpers 0x00452d80 / 0x00452db0 / 0x00452fa0 are separate live selected-site or active service-state setters/dispatchers over [world+0x217d/+0x2181] gated by mode byte [world+0x2175]; they can clear or republish currently-selected site ids through 0x00413620 / 0x00413750, but they do not repopulate [site+0x276] for already-restored rows.".to_string(), + ); notes.push( "Direct disassembly now closes the negative persistence side too: the direct 0x36b1 per-record callbacks serialize the shared base scalar triplets rooted at [this+0x206/+0x20a/+0x20e] plus the subordinate payload callback strip, while the 0x4a9d/0x4a3a/0x4a3b side-buffer owner only persists route-entry lists, three byte arrays, five proximity buckets, and the sampled-cell list. That means neither checked-in save owner seam currently persists the core peer-site identity fields [site+0x04], [site+0x2a8], or [peer+0x08] directly.".to_string(), ); @@ -5748,6 +5751,10 @@ fn build_region_service_trace_report( "0x004c7520 kind-7 region-focused custom-modal owner".to_string(), "0x004358d0 pending region bonus service owner".to_string(), "0x00438710 recurring queued-notice service owner".to_string(), + "0x00420410 world_region_refresh_profile_availability_summary_bytes_0x2f6_0x2fa_0x2fe" + .to_string(), + "0x004204c0 world_region_refresh_profile_availability_display_strings_for_cached_selector_0x2f2" + .to_string(), "0x00420030 / 0x00420280 city-connection peer probes".to_string(), "0x0047efe0 placed-structure linked-company resolver".to_string(), ]; @@ -5773,6 +5780,8 @@ fn build_region_service_trace_report( .to_string(), "0x00455930 region triplet-band tagged serializer callback (world-region vtable +0x4c)" .to_string(), + "0x00420410 region profile availability-summary rebuild helper".to_string(), + "0x004204c0 region profile availability-display rebuild helper".to_string(), "0x004cc930 selected-region severity/source editor helper".to_string(), "0x00438150 fixed-region severity/source reseed owner".to_string(), "0x00442cc0 fixed-region severity/source clamp owner".to_string(), @@ -5800,6 +5809,7 @@ fn build_region_service_trace_report( evidence: vec![ "atlas already bounds this owner as the direct consumer of [region+0x276], [region+0x302], and [region+0x316]".to_string(), "the new region trace already proves the record envelope and profile subcollection, so the remaining gap is the separate persisted latch seam rather than the service owner".to_string(), + "the neighboring region-profile summary/display strip is now grounded as rebuild-only follow-on work: 0x00420410 and 0x004204c0 walk the restored profile collection [region+0x37f], resolve backing candidates through 0x00412b70, and then rebuild [region+0x2f6/+0x2fa/+0x2fe] plus cached-selector display strings [region+0x2f2] from candidate bytes [candidate+0xba/+0xbb] rather than reading persisted region-owned copies".to_string(), "direct disassembly now shows 0x004358d0 calling 0x00420030 twice plus 0x00420280, resolving the linked company through 0x0047efe0, posting company stat slot 4, and then clearing [region+0x276] while stamping [region+0x302] or [region+0x316]".to_string(), "that same direct disassembly now also tightens the branch meaning: the linked-company branch formats the localized region-name notice from [region+0x356], posts it through 0x004554e0 and 0x0042a080, clears [region+0x276], and stamps [region+0x302]=1, while the fallback branch only runs when [region+0x316]==0 and then flips that one-shot latch to 1 before emitting its alternate notice".to_string(), "the checked-in constructor owner 0x00421200 now also proves these latches are initialized locally at record construction time, which narrows the remaining gap to post-construction restore or rebuild rather than basic field identity".to_string(), @@ -5903,8 +5913,11 @@ fn build_region_service_trace_report( "the checked-in shell-load subgraph and function map now place world_load_saved_runtime_state_bundle 0x00446d40 directly ahead of world_run_post_load_generation_pipeline 0x004384d0, so the first later non-hook owner family after the ruled-down 0x00444887 continuation is the post-load generation strip rather than another tagged region payload callback".to_string(), "0x004384d0 already exposes the stage ordering tightly enough to subdivide the next search: id 319 refreshes the route-entry collection, auxiliary route trackers, and then 0x004133b0 placed-structure local-runtime replay; id 320 runs 0x00421c20(1.0, 1) for the region-owned building setup strip; id 321 runs 0x00437b20 and then sweeps regions through 0x00423d30".to_string(), "the 319 placed-structure replay strip is now grounded as more than generic setup glue: 0x004133b0 drains queued site ids through 0x0040e450, sweeps every live placed structure through 0x0040ee10, and then reaches the already-grounded linked-site follow-on 0x00480710, which is a stronger structural bridge into acquisition-side site or peer state than the ruled-down territory/support loaders".to_string(), + "the surrounding 319 helpers are ruled down further now too: 0x00437220 and 0x004377a0 stay on chairman-slot selector/profile materialization over [world+0x69d8/+0x69db] and scenario selector bytes [0x006cec7c+0x87], while 0x00434d40 only seeds the subtype-2 candidate runtime latch [candidate+0x7b0] after the later burst".to_string(), "the 320 building setup strip is narrower but still relevant: 0x00421c20 dispatches every live region into 0x004235c0, and that worker consults the region profile collection [region+0x37f], the placed-instance registry 0x0062b26c, and demand-balancing helpers like 0x00422900/0x00422be0/0x00422ee0, so current evidence keeps it in the same acquisition-adjacent owner family even though it is not yet a direct writer to [region+0x2a4] or [region+0x310/+0x338/+0x360]".to_string(), + "direct worker recovery now narrows 0x004235c0 further: it stays inside the live region demand-and-placement family by routing through 0x00422900 cached category accumulation, 0x004234e0 projected structure-count scalars, 0x00422be0 placed-count subtraction, and 0x00422ee0 placement attempts over 0x0062b26c rather than any restore-time field republisher".to_string(), "the 321 economy-seeding tail is also now bounded as a narrower cache refresh rather than generic noise: 0x00437b20 only stages a fast-forward guard and then sweeps 0x0062bae0 through 0x00423d30, which refreshes the cached category band [region+0x27a/+0x27e/+0x282/+0x286], so it remains a weaker but still explicit post-load owner family to rule in or out before returning to the deeper 0x00446d40 continuation".to_string(), + "direct local disassembly now narrows 0x00423d30 as well: it only republishes [region+0x27a/+0x27e/+0x282/+0x286] through 0x00422900 after the 0x00437b20 burst and does not touch [region+0x2a4] or [region+0x310/+0x338/+0x360]".to_string(), ], blockers: vec![ "current grounded evidence still does not show which post-load subphase actually republishes [region+0x2a4] or the cached tri-lane [region+0x310/+0x338/+0x360]".to_string(), @@ -6011,6 +6024,9 @@ fn build_region_service_trace_report( notes.push( "The later post-load per-region sweep is ruled down further now too: in the 0x00444887 restore strip, the follow-on loop at 0x00444b90 dispatches 0x00420560 over each live region, but that helper only zeroes and recomputes [region+0x312] from the embedded profile collection [region+0x37f]/[region+0x383] and lazily seeds the year-driven [region+0x317/+0x31b] band through 0x00420350, not [region+0x276/+0x302/+0x316].".to_string(), ); + notes.push( + "The immediate profile-summary/display strip is ruled onto the rebuild side too: 0x00420410 rebuilds summary dwords [region+0x2f6/+0x2fa/+0x2fe] and 0x004204c0 refreshes cached-selector display strings [region+0x2f2] by walking the restored profile collection [region+0x37f], resolving backing candidates through 0x00412b70, and consuming candidate bytes [candidate+0xba/+0xbb]. Those bytes are therefore consumer-side summaries, not hidden persisted region lanes.".to_string(), + ); notes.push( "The current region seam is strong enough to prove record-envelope ownership, profile subcollection ownership, and the absence of hidden 0x55f3 tail padding on grounded saves.".to_string(), ); @@ -30597,7 +30613,7 @@ mod tests { assert_eq!(trace.queued_notice_record_count, 0); assert!(!trace.atlas_candidate_consumers.is_empty()); assert_eq!(trace.known_owner_bridge_fields.len(), 6); - assert_eq!(trace.known_bridge_helpers.len(), 14); + assert_eq!(trace.known_bridge_helpers.len(), 16); assert_eq!(trace.next_owner_questions.len(), 5); assert_eq!(trace.candidate_consumer_hypotheses.len(), 6); assert_eq!( diff --git a/docs/control-loop-atlas/post-load-generation-paintterrain-and-save-load-restore.md b/docs/control-loop-atlas/post-load-generation-paintterrain-and-save-load-restore.md index fc54633..c837cf1 100644 --- a/docs/control-loop-atlas/post-load-generation-paintterrain-and-save-load-restore.md +++ b/docs/control-loop-atlas/post-load-generation-paintterrain-and-save-load-restore.md @@ -788,6 +788,22 @@ The same brush strip is tighter now too: way: when startup latch `0x006cd8d8` is clear it stamps `[0x006cec7c+0x79] = 1`, ensures `[world+0x6a6c] >= 1`, forces chairman-seat byte `[world+0x69db] = 1`, and then re-enters `0x004377a0` before the later route-entry and placed-structure refresh families. The + region-side setup branches are narrower in the same negative way now too: `0x00421c20` is just + the collection dispatcher, and its worker `0x004235c0` stays inside live region demand and + placement by routing through `0x00422900` cached category accumulation, `0x004234e0` projected + structure-count scalars, `0x00422be0` placed-count subtraction, and `0x00422ee0` placement + attempts over the live placed-structure registry `0x0062b26c`. Likewise the `321` tail + `0x00437b20 -> 0x00423d30` only refreshes cached category slots + `[region+0x27a/+0x27e/+0x282/+0x286]` through `0x00422900`. So these post-load branches stay + ruled down as setup and cache-maintenance work rather than the missing restore-time republisher + for `[region+0x2a4]` or `[region+0x310/+0x338/+0x360]`. + The surrounding `319` helpers are narrower in the same negative way now too: `0x00437220` and + `0x004377a0` stay on chairman-slot selector and profile materialization over + `[world+0x69d8/+0x69db]` and scenario selector bytes `[0x006cec7c+0x87]`, while `0x00434d40` + only seeds the subtype-`2` candidate runtime latch `[candidate+0x7b0]` across live placed + structures. That leaves the placed-structure replay strip `0x004133b0` as the only region- + adjacent bridge inside the `319` plateau worth chasing for the missing restore seam. + The editor-side read path is explicit on the same seam: `map_editor_economic_cost_panel_refresh_preview_curve_and_numeric_rows` `0x004caaf0` reads the same six-float band, builds the live preview curve on control `0x5be1`, and republishes the six diff --git a/docs/control-loop-atlas/runtime-roots-camera-and-support-families.md b/docs/control-loop-atlas/runtime-roots-camera-and-support-families.md index a0d13a6..b92bf1f 100644 --- a/docs/control-loop-atlas/runtime-roots-camera-and-support-families.md +++ b/docs/control-loop-atlas/runtime-roots-camera-and-support-families.md @@ -3704,6 +3704,14 @@ The low helper strip beneath that shared family is tighter now too: `0x0052ecd0` `0x00409720`, strips route lists from company-owned trains in modes `0x0a/0x13`, and then re-enters `train_try_append_linked_transit_autoroute_entry` `0x00409770` only when a train's route list has become empty. + One nearby live helper strip is narrower now too. Direct inspection of the replay-side sibling + around `0x0040e775` shows `0x004337a0` is exactly the raw selected-company getter over + `[world+0x21]`, used there only to compare the current selection against placed-structure lane + `[site+0x276]`. The adjacent world-side helpers `0x00452d80 / 0x00452db0 / 0x00452fa0` are + separate live selected-site or active service-state setters/dispatchers over + `[world+0x217d/+0x2181]` gated by mode byte `[world+0x2175]`; they can clear or republish + currently-selected site ids through `0x00413620 / 0x00413750`, but they do not repopulate + `[site+0x276]` for already-restored rows. On the wider chooser question, the current evidence is also tighter than before: every recovered external owner of `0x00402cb0` is still in the city-connection family, so the two later direct placement lanes currently read as city-connection fallback behavior rather than a broadly shared diff --git a/docs/rehost-queue.md b/docs/rehost-queue.md index 5911cee..2b5cafa 100644 --- a/docs/rehost-queue.md +++ b/docs/rehost-queue.md @@ -62,6 +62,11 @@ Working rule: - the owner-company branch is tighter now too: direct inspection of `0x0040ea96..0x0040eb65` shows that it consumes `[site+0x276]` and branches through owner/company helpers, but does not itself rehydrate `[site+0x276]` + - the nearby selected-company and live-site helper strip is tighter now too: + `0x004337a0` is the raw selected-company getter over `[world+0x21]`, and the adjacent + world-side helpers `0x00452d80 / 0x00452db0 / 0x00452fa0` are live selected-site or active + service-state setters/dispatchers over `[world+0x217d/+0x2181]` gated by mode byte + `[world+0x2175]`, not restore-time republishers for `[site+0x276]` - that makes the next linked-transit question narrower: identify which earlier restore or service owner feeds `[site+0x276]` and the live linked-peer rows before replay continuation `0x0040e360..0x0040edf6`, beyond the already-grounded @@ -633,6 +638,81 @@ Working rule: but neither has any add-building dispatch-strip trigger rows at all. So `Louisiana.gmp` is now the first checked member of that `book00.line02` mode-shape family whose exact token-bearing signature also lines up with the shipped add-building runtime path. + - the next corpus split is tighter now too: + the apparent `0x00010000 / 0x6c430000 / 0x00080000+0x00004080` three-row cluster is no longer + just a local `Louisiana.gmp` curiosity; `Ireland.gmp` and `Eastern China.gmp` both reuse parts + of it, but only inside broader multi-book imported profiles, and neither currently reaches any + add-building dispatch-strip rows. `Louisiana.gmp` is the only bundled map whose *entire* + nonzero imported recipe surface collapses to that exact three-row cluster. So the current + queue head is now narrower again: + test whether the shipped `5200 :: [7:0]` `Add Building Warehouse05` strip is tied to that + minimal imported-cluster shape specifically, rather than to the mere presence of one reused + `0x00080000 / 0x00004080` triplet inside a broader recipe profile. + - the same split is tighter even inside the broader “single imported row” family: + eight bundled maps currently materialize only one nonzero recipe row, but `Louisiana.gmp` is + the only one whose supporting token surface is just two additional demand rows instead of three + or four extra token-bearing rows. So the next checked discriminator is now narrower than + “single imported row” too: + test whether the `5200 :: [7:0]` add-building strip tracks that exact two-demand-plus-one- + imported minimal cluster, not just the existence of one imported row or one reused + `0x00080000 / 0x00004080` triplet. + - the importer-side boundary is tighter now too: + direct `inspect-smp` checks show `Louisiana.gmp`, `Britain.gmp`, and `South East USA.gmp` all + collapse to the same first importer shape of exactly one + `imports_to_runtime_descriptor = true` line on `nonzero-supply-branch`, while the broader + reuse case `Ireland.gmp` imports four such rows. So the next queue head is no longer + “prove the first importer branch differs”; it is: + recover the later runtime-record / named-availability consequence under + `0x00412d70 / 0x00412fb0 / 0x00412c10` that makes the minimal cluster land on + `5200 :: [7:0]` only in `Louisiana.gmp`. + - the direct named-availability table is still not that consequence: + the nearest single-import peer `South East USA.gmp` keeps `Warehouse05 = 1` and `Port01 = 1` + just like `Louisiana.gmp`, matching the earlier `Dutchlantis.gmp` read. So the next later + Tier 2 question is now even narrower: + recover the runtime-record bank/template consequences under `0x00412d70` + (plus dependent `0x00411ce0 / 0x00411ee0`) before `0x00412c10` mirrors anything into + `[candidate+0x7ac]`. + - the `0x00412d70` runtime-record roots are grounded now too: + direct `objdump` over `RT3.exe` shows `0x005c93d8 = "Warehouse%02d"` and + `0x005c93e8 = "Port%02d"`, with the rebuild choosing the `Port%02d` root only when + `[candidate+0xba] != 0` and the `Warehouse%02d` root otherwise. That turns the next queue head + into a concrete port-versus-warehouse runtime-record question: + recover how the bank/template pass and live availability bytes `[candidate+0xba/+0xbb]` + make `Louisiana.gmp` land on the `Warehouse%02d` side that later lines up with + `5200 :: [7:0]`. + - the writer-side split is narrower now too: + direct disassembly of `0x004120b0` shows that the per-record stream-load helper clears + `[candidate+0x79c/+0x7a0/+0x78c/+0x790/+0x794/+0x7b0]`, restores the fixed fields through + `[candidate+0x33]`, restores `[candidate+0xb9/+0xba/+0xbb]`, and streams the packed `0xbc` + descriptor array into `[candidate+0x37]`. Direct disassembly of upstream source-record import + `0x00414490` also restores `[record+0xb8/+0xb9/+0xba/+0xbb]`. The new checked-in building + source inspector now shows the stock `Data/BuildingTypes/*.bca` corpus keeps those four bytes + zero across every observed file, including `Warehouse.bca` and `Port.bca`. So the next + concrete recovery target is no longer the lower tagged-record reader itself: + recover which later owner or alternate content path makes the live + `[candidate+0xba/+0xbb]` bank/template state diverge from that all-zero shipped BCA corpus + before `0x00411ee0 / 0x00411ce0 / 0x00412c10` run. + - the broader consumer strip above that split is narrower now too: + direct disassembly now rules three more neighbors onto the read-only side of the bank bytes. + `0x00419230` only scans already-linked owner candidates and runs two rebank-or-clone passes + keyed by `candidate[+0xba]` and `candidate[+0xbb]` before stamping `Port%02d` / + `Warehouse%02d` labels into the auxiliary pool. `0x00418610` only feeds `candidate[+0xba]` + plus subtype/class predicates into the projected-rectangle sample-band helper. And the broader + projected-offset lane at `0x0041a5fd..0x0041a944` resolves the same owner candidate and gates a + world-cell occupancy sweep on `candidate[+0xba]`, but still does not reconstruct the byte. + The `.smp` restore-side auxiliary branch is negative in the same way: `0x00413f80` only + restores queued temporary aux-record images without the fixed selector-byte body + `[+0xb8..+0xbb]`, and `0x0041a950` only releases the live aux collection before re-entering + the same `0x004196c0 -> 0x00419230` import-plus-follow-on strip when the restore flags demand + it. + The outer world-entry load branch is fixed in the same way: `0x00438c70` allocates the live + candidate pool through `0x004131f0` and the auxiliary/source pool through `0x0041aa50`, and + both constructors tail directly into the same fixed tagged-import families rather than taking a + title-specific source-selection branch in between. + So the honest next queue head is now one step earlier again: + recover the non-stock writer or restore-time projection owner that makes some live candidates + reach those later consumer strips with nonzero `[candidate+0xba/+0xbb]` despite the observed + all-zero `BuildingTypes/*.bca` corpus. kinds”; it is the smaller set of scenario-specific records where that sweep explicitly writes `[event+0x7ef]` itself or a still-later owner does. - two explicit trigger-kind materializations are now grounded inside that retagger: @@ -1490,6 +1570,22 @@ Working rule: `[region+0x27a/+0x27e/+0x282/+0x286]`. So the next non-hook region work should start from the post-load `319` placed-structure replay seam and only then revisit the narrower region-side `320/321` branches if the exact field bridge is still missing. +- The `319` plateau is split more cleanly now too: its neighboring world helpers are no longer + plausible region-body owners. `0x00437220` and `0x004377a0` are the chairman-slot selector and + profile materialization family over `[world+0x69d8]`, `[world+0x69db]`, and scenario selector + bytes `[0x006cec7c+0x87]`, while `0x00434d40` is only the subtype-`2` candidate runtime-latch + seeder over live placed structures. That leaves `0x004133b0` as the only region-adjacent `319` + bridge worth chasing for the missing restore seam. +- The `320` branch is narrower than that headline now too: direct worker recovery shows + `0x004235c0` staying inside the live region demand-and-placement family by routing through + `0x00422900` cached category accumulation, `0x004234e0` projected structure-count scalars, + `0x00422be0` placed-count subtraction, and `0x00422ee0` placement attempts over the live + placed-structure registry `0x0062b26c`. That keeps it on live setup and maintenance work rather + than any restore-time republisher for `[region+0x2a4]` or `[region+0x310/+0x338/+0x360]`. +- The `321` branch is narrower in the same way: `0x00437b20` only stages the fast-forward burst, + then re-enters the live region collection through `0x00423d30`, and that helper only republishes + `[region+0x27a/+0x27e/+0x282/+0x286]` via `0x00422900`. It should stay ruled down as a cached + summary refresh instead of a plausible owner for the missing restore-side body lanes. - The later restore-side region owners are narrowed further now too: the `0x00421ce0 -> 0x0041fb00 -> 0x00421730` sweep is class-`0` raster/id rebuild, `0x004881b0` is a companion region-set cell-count rebuild over `[region+0x3d/+0x41]`, `0x00487de0` is a border-segment