3.4 KiB
Independent cross-check: RecordObservedTech
GPT-6 Astra, local instruction stream from fingerprinted dumps/sots.exe, 2026-09-09.
MD5 9969481c39f4b33a8a21c48b62abee4c exactly matches the analyst's ReVa program metadata;
the same local file's SHA-256 is 970b7de729956a53094c7eb98aba4270aee98e2fed5daf0d39e290013c90c841.
This closes the previously reported missing ReVa/local fingerprint linkage.
Fresh disassembly: verify/results/research-callback/record-observed-tech-objdump.txt.
Corrections to the first analyst pass
- The constructor/push path is name not found, NOT vector full capacity. The function scans first at observer+0x274 through last at +0x278; +0x27c capacity is not read in this wrapper. Empty list or exhausted search reaches 0x007ba274. Capacity handling belongs to 0x007b7320.
- The observer is stack argument 1 (
[ebp+8]), not argument 2. Stack argument 2 ([ebp+0xc]) supplies observation eligibility bytes and the field used to select the with-mask bit. - Stack argument 3 is a TechDef-like object whose string starts at object+4. It is not a bare string pointer: source length is object+0x14 and capacity object+0x18. The comparison uses destination string at record+0x0c. Confirm semantic TechDef identity using the caller/schema.
Pinned instructions / static callable boundary
Wrapper 0x007ba1a0 uses this in ECX, three stack arguments, returns with ret 0x0c at 0x007ba32b. Its ECX-derived object supplies the 16-bit turn at +0x0c. The owner callback caller prepares ECX from player+8 minus four and pushes (technology, player, player) in reverse argument order.
Before searching it requires three non-null arguments and rejects a subject with
NPC && !RebAI (offsets +0xfb/+0xfc, names cross-checked with the existing serializer/address
contract). It then calls 0x0057e6d0 on argument 3; a nonzero result suppresses recording.
Fresh disassembly now resolves that helper: read the technology's name string at def+4,
find its first underscore, and compare the suffix with _Root using _stricmp.
The literal is at 0x00a00040; imported comparator IAT is 0x009dd328 (MSVCR100.dll entry 115).
Thus root technologies are excluded, case-insensitively. It is not a costly master-tree query;
ECX is unused in this helper. Capture: observed-tech-exclusion-objdump.txt and
observed-tech-exclusion-literal.txt. The underscore scan has no terminator check in the binary;
valid tech-name syntax is a precondition, not evidence of safe arbitrary-string handling.
Search increments by 0x2c, compares full names via 0x004236a0, and preserves an existing element if found. On absence it constructs a stack temporary (0x008562a0), appends via 0x007b7320, then operates on the newly appended element at last-0x2c:
- first/last turns are 16-bit offsets +4/+6;
- name assignment targets the string at +0x0c via 0x00425430;
- both new and existing paths update last turn +6 and OR a bit into +0x28, using subject+0x28 as the x86 shift count;
- existing-path first-turn/name stay unchanged in this wrapper.
Append is followed by conditional destruction of the TEMPORARY string when capacity >=16. The temporary lifetime does not permit stealing its buffer into the appended element. Copy/ reallocation/destruction inside 0x007b7320 must be recovered before implementation.
These facts are static ABI/ordering evidence. They do not prove live allocation safety.