Narrow Tier2 bank-byte writer census

This commit is contained in:
Jan Petykiewicz 2026-04-19 14:07:56 -07:00
commit 4d002d7da8
2 changed files with 31 additions and 0 deletions

View file

@ -1225,6 +1225,21 @@
`".\\Data\\BuildingTypes\\"`. So the remaining bank-byte divergence is not hidden inside a `".\\Data\\BuildingTypes\\"`. So the remaining bank-byte divergence is not hidden inside a
second caller of the BCA parser; it has to happen after the fixed stock `BuildingTypes/*.bca` second caller of the BCA parser; it has to happen after the fixed stock `BuildingTypes/*.bca`
import has already run, or through some later non-stock projection seam above it. import has already run, or through some later non-stock projection seam above it.
The direct `+0xba/+0xbb` writer census now rules out a broad false lead too. The obvious new
stores at `0x004ecd42/0x004ecdaa` and `0x004ed5d5/0x004ed625` are only shell-side
portrait/string refresh helpers over a different id-keyed collection rooted through
`0x0053f830`: they free and replace heap strings at dword `[entry+0xba]` and mirror shell text
from `[0x006cec74+0x1ef]`. The other surfaced dword writers at `0x00540251/0x0054034d`,
`0x0055fd40`, `0x0055bdc4/0x0055bf01`, `0x0055ca78`, `0x0055f290`, `0x005b5168`, and
`0x005b6718` likewise belong to wider non-candidate heap objects with their own vtables and
layouts, not to the live `0x005c93cc` candidate rows.
The positive candidate-side bound is tighter now too: `0x004120b0` explicitly declares
`[candidate+0xba]` and `[candidate+0xbb]` as one-byte parser fields through `0x00531150`, and
the later helper `0x00412d70` can clone an already-materialized whole candidate row through
`rep movsl`, including those bytes, before `0x00412f02` picks the `Port%02d` vs `Warehouse%02d`
naming branch from cloned bit `[candidate+0xba]`. So the unresolved Tier-2 seam is no longer
“find any direct writer to candidate `+0xba/+0xbb`”; it is “find the earlier seed or projection
owner that first makes some source/live rows reach that clone path with nonzero bank bytes.”
That candidate-side table now has a grounded fixed record layout too: each entry is a `0x22`-byte That candidate-side table now has a grounded fixed record layout too: each entry is a `0x22`-byte
blob with a zero-terminated candidate-name slot at `[entry+0x00..+0x1d]` and one trailing blob with a zero-terminated candidate-name slot at `[entry+0x00..+0x1d]` and one trailing
availability dword at `[entry+0x1e]`, read through `0x00434ea0` and mirrored later into availability dword at `[entry+0x1e]`, read through `0x00434ea0` and mirrored later into

View file

@ -732,6 +732,22 @@ Working rule:
package path. So the remaining Tier-2 mystery is not “which hidden caller invokes the BCA package path. So the remaining Tier-2 mystery is not “which hidden caller invokes the BCA
parser?”; it is “which later non-stock writer or projection seam makes live parser?”; it is “which later non-stock writer or projection seam makes live
`[candidate+0xba/+0xbb]` diverge after the fixed stock BCA import has already run?” `[candidate+0xba/+0xbb]` diverge after the fixed stock BCA import has already run?”
The direct `+0xba/+0xbb` writer census is narrower now too. The obvious newly surfaced stores
at `0x004ecd42/0x004ecdaa` and `0x004ed5d5/0x004ed625` are only shell-side portrait/string
refresh helpers: they walk a separate id-keyed collection through `0x0053f830`, free and
replace heap strings at dword `[entry+0xba]`, and mirror shell text from `[0x006cec74+0x1ef]`.
The other new dword writers at `0x00540251/0x0054034d`, `0x0055fd40`, `0x0055bdc4/0x0055bf01`,
`0x0055ca78`, `0x0055f290`, `0x005b5168`, and `0x005b6718` likewise belong to wider
non-candidate heap objects with their own vtables and field layouts, not to the live
`0x005c93cc` candidate rows.
The actual candidate import strip now has a tighter positive bound instead: `0x004120b0`
explicitly declares `[candidate+0xba]` and `[candidate+0xbb]` as one-byte parser fields through
`0x00531150`, while `0x00412d70` can later clone a whole already-materialized candidate row
through `rep movsl`, including those byte fields, before `0x00412f02` chooses the
`Port%02d`/`Warehouse%02d` naming branch from the cloned `[candidate+0xba]` bit. So the live
divergence frontier is narrower again: not generic direct stores into candidate rows, but the
earlier seed or projection seam that first makes some source/live rows reach that clone path
with nonzero bank bytes.
So the honest next queue head is now one step earlier again: 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 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 reach those later consumer strips with nonzero `[candidate+0xba/+0xbb]` despite the observed