nmarshall commited on
Commit
8db10fe
·
1 Parent(s): 31f9605

Recover crosshair geometry and trace result routing

Browse files
docs/FINDINGS.md CHANGED
@@ -276,3 +276,9 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
276
  **F-068 — Observed cached location contract:** nonzero object field 848 returns only when signed now < pointed-field 596; equality misses. Wrapper 268637 returns zero without formatting on NULL, otherwise formats pointed-field 592 and returns one. Cache writers, source validity, caller failure handling and signed-wrap conformance remain open. [LOC-002](research/CHAT_LOCATIONS.md).
277
 
278
  **F-069 — Observed location list/search structure:** guarded registration publishes unknown at configstring 640, numbers qualifying objects and inserts reverse-order links through *(object+524)+24. Static lookup retains first trigger_location in a 40/40/52 query box, then distance <= best plus visibility fallback. Geometry/engine services, raw tag identity, list lifecycle and runtime/platform parity remain unverified. [LOC-003](research/CHAT_LOCATIONS.md).
 
 
 
 
 
 
 
276
  **F-068 — Observed cached location contract:** nonzero object field 848 returns only when signed now < pointed-field 596; equality misses. Wrapper 268637 returns zero without formatting on NULL, otherwise formats pointed-field 592 and returns one. Cache writers, source validity, caller failure handling and signed-wrap conformance remain open. [LOC-002](research/CHAT_LOCATIONS.md).
277
 
278
  **F-069 — Observed location list/search structure:** guarded registration publishes unknown at configstring 640, numbers qualifying objects and inserts reverse-order links through *(object+524)+24. Static lookup retains first trigger_location in a 40/40/52 query box, then distance <= best plus visibility fallback. Geometry/engine services, raw tag identity, list lifecycle and runtime/platform parity remain unverified. [LOC-003](research/CHAT_LOCATIONS.md).
279
+
280
+ **F-070 — Observed crosshair arithmetic:** offset-4 >=3/override bypasses geometry; other paths use paired angle-service outputs, object-position plus integer height, and forward times 30000. Finite cardinal instruction fixtures verify basis/endpoint routing while native trig and coordinate conventions remain open. [AIM-001](research/CHAT_CROSSHAIR.md).
281
+
282
+ **F-071 — Observed crosshair trace arguments:** service 24 receives result/origin/NULL/NULL/endpoint pointers, sender-record field 140 and mask 1. G_TRACE remains a pinned upstream candidate; full shipped structure/service semantics and runtime collision are unverified. [AIM-002](research/CHAT_CROSSHAIR.md).
283
+
284
+ **F-072 — Observed crosshair result handling:** trace word +4 exactly 1 requests unknown then sender location. Other observed words build a cache-cleared temporary object from result +12/+16/+20; a subsequent comparison return zero triggers sender fallback. Calls/returns remain synthetic placeholders or isolated supplied inputs, so actual endpoint output/failure behavior is open. [AIM-003](research/CHAT_CROSSHAIR.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -33,7 +33,7 @@ For implementation items, the minimum done condition is a documented contract, a
33
 
34
  ### First research batch
35
 
36
- Progress: [RE-232–234 / TIME-001–003](research/FRAME_TIMING.md) now cover Linux ELF64 elapsed modification, event sources and pause predicates. The [RE-237–239 follow-up](research/EVENT_QUEUES.md) resolves the pause-field address/bot chain and adds queue/journal evidence. The [RE-241–243 announcement pass](research/AUTH_ANNOUNCEMENTS.md) recovers label tables and recipient paths; The [RE-245–247 cvar pass](research/GAME_CVARS.md) adds all 126 main registration rows and resolves auth_verbosity/callers. The [RE-249–251 change pass](research/CVAR_CHANGES.md) adds cache/notification behavior, four numeric correction branches and direct registration coverage. The [RE-253–255 query pass](research/AUTH_QUERIES.md) adds selector helpers, command-role routing and internal authentication modes. The [RE-257–259 bounds/entry pass](research/SELECTOR_BOUNDS.md) adds integer parsing, selector storage/count evidence and native/QVM/chat route connections. The [RE-261–263 chat pass](research/CHAT_PATHS.md) adds native command metadata/filter evidence and bounded message/recipient paths, including the documented argument-mapping correction. The [RE-265–267 delivery pass](research/CHAT_DELIVERY.md) adds bounded dead-chat predicates, formatter argument routing and echo/fanout calls. The [RE-269–271 expansion pass](research/CHAT_EXPANSION.md) adds marker states, twelve key comparisons and health/momo branches. The [RE-273–275 item/time pass](research/CHAT_ITEMS_TIME.md) adds packed ammunition fields, sampled names and countdown branches. The [RE-277–279 location pass](research/CHAT_LOCATIONS.md) adds leader selection, cache/format boundaries and location-list/spatial evidence. PROV-002 remains open for full output/reset coverage. PROV-001 remains open for complete scheduling and platform coverage.
37
 
38
  Start with the open questions raised by the current binary evidence. These tasks depend on the linked reports, not on a working rewrite.
39
 
 
33
 
34
  ### First research batch
35
 
36
+ Progress: [RE-232–234 / TIME-001–003](research/FRAME_TIMING.md) now cover Linux ELF64 elapsed modification, event sources and pause predicates. The [RE-237–239 follow-up](research/EVENT_QUEUES.md) resolves the pause-field address/bot chain and adds queue/journal evidence. The [RE-241–243 announcement pass](research/AUTH_ANNOUNCEMENTS.md) recovers label tables and recipient paths; The [RE-245–247 cvar pass](research/GAME_CVARS.md) adds all 126 main registration rows and resolves auth_verbosity/callers. The [RE-249–251 change pass](research/CVAR_CHANGES.md) adds cache/notification behavior, four numeric correction branches and direct registration coverage. The [RE-253–255 query pass](research/AUTH_QUERIES.md) adds selector helpers, command-role routing and internal authentication modes. The [RE-257–259 bounds/entry pass](research/SELECTOR_BOUNDS.md) adds integer parsing, selector storage/count evidence and native/QVM/chat route connections. The [RE-261–263 chat pass](research/CHAT_PATHS.md) adds native command metadata/filter evidence and bounded message/recipient paths, including the documented argument-mapping correction. The [RE-265–267 delivery pass](research/CHAT_DELIVERY.md) adds bounded dead-chat predicates, formatter argument routing and echo/fanout calls. The [RE-269–271 expansion pass](research/CHAT_EXPANSION.md) adds marker states, twelve key comparisons and health/momo branches. The [RE-273–275 item/time pass](research/CHAT_ITEMS_TIME.md) adds packed ammunition fields, sampled names and countdown branches. The [RE-277–279 location pass](research/CHAT_LOCATIONS.md) adds leader selection, cache/format boundaries and location-list/spatial evidence. The [RE-281–283 crosshair pass](research/CHAT_CROSSHAIR.md) adds finite geometry fixtures, trace arguments and result routing. PROV-002 remains open for full output/reset coverage. PROV-001 remains open for complete scheduling and platform coverage.
37
 
38
  Start with the open questions raised by the current binary evidence. These tasks depend on the linked reports, not on a working rewrite.
39
 
docs/RESEARCH_LEDGER.md CHANGED
@@ -141,3 +141,7 @@ Completed bounded milestones RE-273–275 with `analyze_chat_items_time.py`: 32
141
  ## 2026-10-11 — Team leader and location lookup paths
142
 
143
  Completed RE-277–279 bounded/static milestones with `analyze_chat_locations.py`: six leader scans, three name chains, five cache boundaries, two wrapper returns, four registration paths, literal-reference windows and file-backed box extents. LOC-001–003/F-067–069 separate executed synthetic integer slices from retained floating-point/engine spatial code and distinguish upstream ABI candidates from native proof. Seven tests check first-match/nonzero semantics, strict expiry, failure/success formatting requests, guard/filter/numbering/reverse links and static spatial constants/branches. RE-272 remains open; RE-280 tracks writers/ownership/reset/geometry/client/runtime/platform composition. No original process/full QVM or recorded callee executes.
 
 
 
 
 
141
  ## 2026-10-11 — Team leader and location lookup paths
142
 
143
  Completed RE-277–279 bounded/static milestones with `analyze_chat_locations.py`: six leader scans, three name chains, five cache boundaries, two wrapper returns, four registration paths, literal-reference windows and file-backed box extents. LOC-001–003/F-067–069 separate executed synthetic integer slices from retained floating-point/engine spatial code and distinguish upstream ABI candidates from native proof. Seven tests check first-match/nonzero semantics, strict expiry, failure/success formatting requests, guard/filter/numbering/reverse links and static spatial constants/branches. RE-272 remains open; RE-280 tracks writers/ownership/reset/geometry/client/runtime/platform composition. No original process/full QVM or recorded callee executes.
144
+
145
+ ## 2026-10-11 — Crosshair geometry and result routing
146
+
147
+ Completed bounded milestones RE-281–283 with `analyze_chat_crosshair.py`: five dead gates, three origin/height cases, five supplied cardinal basis/endpoint cases, exact trace arguments, three result paths and three isolated comparison-return paths. AIM-001–003/F-070–072 separate finite straight-line binary32 arithmetic from native trig/collision and explicit zero callee-return placeholders. Eight tests check basis/origin/endpoints, seven-word ABI requests, exact-one status and temporary writes, fallback predicates and fail-closed float/memory/opcode/copy bounds. Added a separate restricted arithmetic evaluator without expanding the integer evaluator's domain. RE-272/280 remain open; RE-284 tracks full layout/float/temporary-object/output/runtime/platform contracts. No original process/full QVM or recorded callee executes.
docs/REVERSE_ENGINEERING_TODO.md CHANGED
@@ -332,3 +332,8 @@ Purpose: turn the supplied installation into an evidence-backed specification of
332
  - [x] RE-278 Recover strict location cache-expiry boundaries and isolated NULL/nonzero formatter-wrapper returns ([LOC-002](research/CHAT_LOCATIONS.md)).
333
  - [x] RE-279 Recover bounded location registration/filter/numbering/reverse-link paths and retain static box/distance/visibility search evidence ([LOC-003](research/CHAT_LOCATIONS.md)).
334
  - [ ] RE-280 Recover leader/cache/state writers, count/slot bounds, location class-tag derivation/list ownership/reset, caller failure/default behavior, full float/box/PVS search, configstring client consumption and original-runtime/platform fixtures.
 
 
 
 
 
 
332
  - [x] RE-278 Recover strict location cache-expiry boundaries and isolated NULL/nonzero formatter-wrapper returns ([LOC-002](research/CHAT_LOCATIONS.md)).
333
  - [x] RE-279 Recover bounded location registration/filter/numbering/reverse-link paths and retain static box/distance/visibility search evidence ([LOC-003](research/CHAT_LOCATIONS.md)).
334
  - [ ] RE-280 Recover leader/cache/state writers, count/slot bounds, location class-tag derivation/list ownership/reset, caller failure/default behavior, full float/box/PVS search, configstring client consumption and original-runtime/platform fixtures.
335
+
336
+ - [x] RE-281 Recover crosshair dead-state precondition, raw angle/distance constants, origin copy/height adjustment and finite cardinal basis/endpoint instruction fixtures ([AIM-001](research/CHAT_CROSSHAIR.md)).
337
+ - [x] RE-282 Recover exact seven-word crosshair trace argument contract and supplied field-140 forwarding ([AIM-002](research/CHAT_CROSSHAIR.md)).
338
+ - [x] RE-283 Recover trace offset-4 exact-one branch, endpoint temporary-object/cache-clear writes and isolated comparison-controlled sender fallback ([AIM-003](research/CHAT_CROSSHAIR.md)).
339
+ - [ ] RE-284 Confirm native trig services, full record/vector/trace layouts, float exceptional/angle domains, temporary-object requirements, location/comparison/default composition, collision masks and original-runtime/platform fixtures.
docs/research/CHAT_CROSSHAIR.md ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Crosshair substitution geometry and result routing
2
+
3
+ Static pass, 2026-10-11. Reproduce with `python3 scripts/analyze_chat_crosshair.py`; check with `python3 scripts/test_chat_crosshair.py`. [Generated evidence](chat-crosshair.json) includes verified qagame partitions, raw constants, bounded gate/argument/result traces and a separate finite binary32 arithmetic evaluator. No original process, complete QVM, native trig/collision service or recorded callee executes. Trig outputs, trace words/endpoints and isolated comparison returns are supplied fixture inputs. This extends the [location lookup findings](CHAT_LOCATIONS.md).
4
+
5
+ ## AIM-001: precondition, origin and direction arithmetic
6
+
7
+ The `crosshair` key's branch in lookup 185212 first tests sender-record offset **4324 !=0** or offset **4 >=3**. Either condition calls location wrapper 268637 with sender/shared buffer/capacity 150 and returns the buffer pointer without computing a crosshair ray. The wrapper return is discarded. Synthetic state 0/2 reaches geometry; 3/4 or override reaches fallback. Failure/default output composition remains open.
8
+
9
+ For the other path, record fields **152/156/160** are multiplied by raw float bits **1016003125**, value **0.01745329238474369**, before six encoded service calls, alternating **-104/-105** (service numbers 103/104). The supplied syscall candidate report does not identify these two names. The conventional sine/cosine interpretation of their paired outputs is used only to label the synthetic direction fixtures; the native service bodies and their accuracy remain unverified here.
10
+
11
+ The subsequent instruction arithmetic forms three vectors. With supplied variables sp/cp at locals 1092/1108, sy/cy at 1096/1104 and sr/cr at 1088/1100, the recovered expressions are:
12
+
13
+ ```
14
+ forward = (cp*cy, cp*sy, -sp)
15
+ right = (-sr*sp*cy + cr*sy, -sr*sp*sy - cr*cy, -sr*cp)
16
+ up = (cr*sp*cy + sr*sy, cr*sp*sy - sr*cy, cr*cp)
17
+ ```
18
+
19
+ Only forward feeds this endpoint. Five supplied cardinal-output fixtures cover forward, yaw 90, pitch 90, yaw 180 and roll 90. The actual MULF/ADDF/NEGF sequence is evaluated with a binary32 pack after each operation. Those fixtures produce orthogonal unit bases, expected cardinal forward vectors and a roll-independent endpoint. They do not establish angle conventions against camera coordinates or all-angle/native trigonometric conformance.
20
+
21
+ Origin helper **288871** copies three words from object offsets **24/28/32** into the caller vector, then adds signed integer sender-record field **164**, converted by CVIF, to its third component. Three synthetic position/height cases evaluate that BLOCK_COPY/CVIF/ADDF sequence. The endpoint then evaluates:
22
+
23
+ ```
24
+ endpoint = origin + forward * 30000.0
25
+ ```
26
+
27
+ Distance bits **1189765120** decode to **30000.0**. The finite evaluator supports only straight-line CONST/LOCAL/word load/store/address add, finite MULF/ADDF/NEGF/CVIF and aligned 12-byte fixture copies. Unknown memory, unsupported operations, stack underflow, nonfinite inputs/results, overflow and slice limits fail closed. It is separate from the existing integer evaluator and does not model byte aliasing, native rounding modes, exceptional floats or full VM frame unwinding. Tests include binary32 integer-rounding and signed zero.
28
+
29
+ ## AIM-002: trace argument contract
30
+
31
+ The ray call uses encoded target **-25**, service **24**, labeled **G_TRACE** by the [pinned ABI candidate report](qvm/qagame.abi-candidates.json). The collector checks that report's qagame hash. Its exact seven argument words are:
32
+
33
+ | Argument offset | Value |
34
+ | ---: | --- |
35
+ | 8 | result structure pointer, local 144 |
36
+ | 12 | origin pointer, local 120 |
37
+ | 16 | zero |
38
+ | 20 | zero |
39
+ | 24 | endpoint pointer, local 132 |
40
+ | 28 | sender-record word 140 |
41
+ | 32 | integer **1** |
42
+
43
+ The fixture supplies field 140 as 7 and records it without interpreting its complete identity. Null extents and mask 1 are raw call evidence; point-ray/content/pass-entity semantics still require native structure/service confirmation across targets. The origin-helper and trace callees are not entered in this argument slice. The ray result structure layout is only partly observed by subsequent word reads.
44
+
45
+ ## AIM-003: trace status, temporary object and comparison fallback
46
+
47
+ After the trace call, local **148**, the word at result base **+4**, is compared to **exactly 1**. This is the second result word; its full status-field identity is not assigned here.
48
+
49
+ When that word equals 1, the code requests copy helper 36185 to set the shared output to literal **`unknown`**, then calls 268637 for the sender and reaches the buffer-return tail. Neither helper executes in the fixture, so failure of the second call does not prove its actual final output.
50
+
51
+ For other tested words **0 and 2**, it copies result words at offsets **+12/+16/+20** into a temporary object beginning at local **200**, specifically object-relative offsets **488/492/496**. It clears temporary offset **848**, then requests location wrapper 268637 with that temporary object, output buffer 35738436 and capacity 150. Clearing offset 848 ensures this temporary lookup cannot take the observed nonzero-cache fast path; the rest of the object's initialization/lifetime remains open.
52
+
53
+ The wrapper return is discarded. Next helper **36306** receives the shared buffer and literal `unknown`. A comparison return **zero** invokes sender location fallback; supplied returns **1/-1** skip it. Full comparison-string execution is retained in the helper partition but not evaluated by this pass. Whole bounded result fixtures have zero CALL return placeholders and therefore take this fallback; those traces must not be mistaken for evidence that the real endpoint lookup always fails or yields unknown.
54
+
55
+ ## Remaining work and Rust dependencies
56
+
57
+ RE-281–283 cover bounded geometry, trace arguments and result routing. RE-272/280 remain open; RE-284 tracks native service-103/104 trig identity/accuracy, real record/vector/trace layouts, exceptional float and angle domains, full temporary-object memory requirements, location/comparison/default composition, collision/content masks and original-runtime/platform fixtures. Rust crosshair text needs both sender and endpoint location routes, exact status predicates and validated coordinate/trace contracts before claiming gameplay parity.
docs/research/CHAT_LOCATIONS.md CHANGED
@@ -46,3 +46,5 @@ The [pinned ABI candidate report](qvm/qagame.abi-candidates.json), checked again
46
  ## Remaining work and Rust dependencies
47
 
48
  RE-277–279 record these bounded/static milestones; RE-272 remains open for full substitution behavior. RE-280 tracks leader-flag/state writers, count/slot invariants, caller failure/default behavior, cache writers/expiry/reset, raw class tag derivation, linked-field ownership, full floating-point/box/PVS selection, configstring clients and original-runtime/platform fixtures. Rust location lookup needs explicit cache/ordering/tie rules and ownership backed by that evidence; a generic nearest-point search would not reproduce the observed two-stage control flow by itself.
 
 
 
46
  ## Remaining work and Rust dependencies
47
 
48
  RE-277–279 record these bounded/static milestones; RE-272 remains open for full substitution behavior. RE-280 tracks leader-flag/state writers, count/slot invariants, caller failure/default behavior, cache writers/expiry/reset, raw class tag derivation, linked-field ownership, full floating-point/box/PVS selection, configstring clients and original-runtime/platform fixtures. Rust location lookup needs explicit cache/ordering/tie rules and ownership backed by that evidence; a generic nearest-point search would not reproduce the observed two-stage control flow by itself.
49
+
50
+ The [AIM-001–003 follow-up](CHAT_CROSSHAIR.md) recovers the crosshair caller's geometry/trace/result routes. Full spatial services, caller output and runtime behavior remain open under RE-280/284.
docs/research/README.md CHANGED
@@ -40,10 +40,11 @@ python3 scripts/test_chat_delivery.py
40
  python3 scripts/test_chat_expansion.py
41
  python3 scripts/test_chat_items_time.py
42
  python3 scripts/test_chat_locations.py
 
43
  python3 scripts/storage_policy.py check --require-setup
44
  ```
45
 
46
- The pipeline runs `fetch_analysis_references.py`, `analyze_qvm.py`, `analyze_native.py`, `analyze_vm_abi.py`, `analyze_native_dispatch.py`, `analyze_vm_extensions.py`, `analyze_native_metadata.py`, `analyze_native_coverage.py`, `analyze_auth_drop.py`, `analyze_deferred_auth.py`, `analyze_engine_control.py`, `analyze_frame_timing.py`, `analyze_event_queues.py`, `analyze_auth_announcements.py`, `analyze_game_cvars.py`, `analyze_cvar_changes.py`, `analyze_auth_queries.py`, `analyze_selector_bounds.py`, `analyze_chat_paths.py`, `analyze_chat_delivery.py`, `analyze_chat_expansion.py`, `analyze_chat_items_time.py`, and `analyze_chat_locations.py` in that order. Python 3.9+ and **LLVM objdump** with x86 ELF/COFF/Mach-O support are required. This pass used Apple LLVM 17.0.0 on macOS arm64; it disassembled x86 images without running them. Upstream references are downloaded only if absent, checked against the committed SHA-256 manifest, and cached under `.cache/research/upstream/`. A clone also needs `git lfs pull` to obtain the derived artifacts/extracted members.
47
 
48
  Generated JSON/JSONL and compressed evidence are regenerated in place; keep prose notes in Markdown. Rerunning the four analysis stages reproduced every generated report and gzip artifact byte-for-byte on the same toolchain. gzip timestamps and stored filenames are fixed. Different objdump versions can produce different disassembly text, so tool version and uncompressed evidence hashes are recorded. Reports are UTF-8 normal Git text, with individual files below the storage policy's 2 MiB limit.
49
 
@@ -91,3 +92,5 @@ The extension collector adds five focused tests for native tail calls, command-r
91
  [Chat ammunition, item names and countdowns](CHAT_ITEMS_TIME.md) adds RE-273–275: packed byte extraction, thirty sampled name words/game-item branches and timer/cvar/gate evidence. Reproduce with `python3 scripts/analyze_chat_items_time.py`; check with `python3 scripts/test_chat_items_time.py`. Complete item tables/producers and timing/output/runtime contracts remain open.
92
 
93
  [Team-leader and location lookup paths](CHAT_LOCATIONS.md) adds RE-277–279: first-match leader scan, strict cache/format boundaries, location registration/list order and retained spatial control flow/constants. Reproduce with `python3 scripts/analyze_chat_locations.py`; check with `python3 scripts/test_chat_locations.py`. Geometry/services, ownership, caller output and runtime/platform contracts remain open.
 
 
 
40
  python3 scripts/test_chat_expansion.py
41
  python3 scripts/test_chat_items_time.py
42
  python3 scripts/test_chat_locations.py
43
+ python3 scripts/test_chat_crosshair.py
44
  python3 scripts/storage_policy.py check --require-setup
45
  ```
46
 
47
+ The pipeline runs `fetch_analysis_references.py`, `analyze_qvm.py`, `analyze_native.py`, `analyze_vm_abi.py`, `analyze_native_dispatch.py`, `analyze_vm_extensions.py`, `analyze_native_metadata.py`, `analyze_native_coverage.py`, `analyze_auth_drop.py`, `analyze_deferred_auth.py`, `analyze_engine_control.py`, `analyze_frame_timing.py`, `analyze_event_queues.py`, `analyze_auth_announcements.py`, `analyze_game_cvars.py`, `analyze_cvar_changes.py`, `analyze_auth_queries.py`, `analyze_selector_bounds.py`, `analyze_chat_paths.py`, `analyze_chat_delivery.py`, `analyze_chat_expansion.py`, `analyze_chat_items_time.py`, `analyze_chat_locations.py`, and `analyze_chat_crosshair.py` in that order. Python 3.9+ and **LLVM objdump** with x86 ELF/COFF/Mach-O support are required. This pass used Apple LLVM 17.0.0 on macOS arm64; it disassembled x86 images without running them. Upstream references are downloaded only if absent, checked against the committed SHA-256 manifest, and cached under `.cache/research/upstream/`. A clone also needs `git lfs pull` to obtain the derived artifacts/extracted members.
48
 
49
  Generated JSON/JSONL and compressed evidence are regenerated in place; keep prose notes in Markdown. Rerunning the four analysis stages reproduced every generated report and gzip artifact byte-for-byte on the same toolchain. gzip timestamps and stored filenames are fixed. Different objdump versions can produce different disassembly text, so tool version and uncompressed evidence hashes are recorded. Reports are UTF-8 normal Git text, with individual files below the storage policy's 2 MiB limit.
50
 
 
92
  [Chat ammunition, item names and countdowns](CHAT_ITEMS_TIME.md) adds RE-273–275: packed byte extraction, thirty sampled name words/game-item branches and timer/cvar/gate evidence. Reproduce with `python3 scripts/analyze_chat_items_time.py`; check with `python3 scripts/test_chat_items_time.py`. Complete item tables/producers and timing/output/runtime contracts remain open.
93
 
94
  [Team-leader and location lookup paths](CHAT_LOCATIONS.md) adds RE-277–279: first-match leader scan, strict cache/format boundaries, location registration/list order and retained spatial control flow/constants. Reproduce with `python3 scripts/analyze_chat_locations.py`; check with `python3 scripts/test_chat_locations.py`. Geometry/services, ownership, caller output and runtime/platform contracts remain open.
95
+
96
+ [Crosshair substitution geometry and results](CHAT_CROSSHAIR.md) adds RE-281–283: bounded origin/basis/endpoint arithmetic, exact trace arguments and status/temp-object/fallback routes. Reproduce with `python3 scripts/analyze_chat_crosshair.py`; check with `python3 scripts/test_chat_crosshair.py`. Engine trig/collision and complete output/runtime/platform conformance remain open.
docs/research/chat-crosshair.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_binaries.py CHANGED
@@ -14,7 +14,7 @@ def main():
14
  'analyze_deferred_auth.py', 'analyze_engine_control.py', 'analyze_frame_timing.py',
15
  'analyze_event_queues.py', 'analyze_auth_announcements.py', 'analyze_game_cvars.py',
16
  'analyze_cvar_changes.py', 'analyze_auth_queries.py', 'analyze_selector_bounds.py',
17
- 'analyze_chat_paths.py', 'analyze_chat_delivery.py', 'analyze_chat_expansion.py', 'analyze_chat_items_time.py', 'analyze_chat_locations.py'):
18
  subprocess.run([sys.executable, str(Path('scripts')/script)], check=True)
19
 
20
 
 
14
  'analyze_deferred_auth.py', 'analyze_engine_control.py', 'analyze_frame_timing.py',
15
  'analyze_event_queues.py', 'analyze_auth_announcements.py', 'analyze_game_cvars.py',
16
  'analyze_cvar_changes.py', 'analyze_auth_queries.py', 'analyze_selector_bounds.py',
17
+ 'analyze_chat_paths.py', 'analyze_chat_delivery.py', 'analyze_chat_expansion.py', 'analyze_chat_items_time.py', 'analyze_chat_locations.py', 'analyze_chat_crosshair.py'):
18
  subprocess.run([sys.executable, str(Path('scripts')/script)], check=True)
19
 
20
 
scripts/analyze_chat_crosshair.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Recover bounded crosshair gates, finite float arithmetic and result routing."""
3
+ import json
4
+ import math
5
+ import struct
6
+ from pathlib import Path
7
+ from analyze_deferred_auth import partition_function,trace_slice,signed32
8
+ from analyze_game_cvars import vm_string
9
+ from analyze_qvm import decode,write_json
10
+ from analyze_vm_extensions import verified
11
+
12
+ BASE=0x40000000
13
+
14
+
15
+ def bits(value):
16
+ if not math.isfinite(value):raise ValueError('nonfinite float input')
17
+ try:raw=struct.pack('<f',value)
18
+ except (OverflowError,struct.error) as e:raise ValueError('float outside finite binary32') from e
19
+ if not math.isfinite(struct.unpack('<f',raw)[0]):raise ValueError('float outside finite binary32')
20
+ return signed32(struct.unpack('<I',raw)[0])
21
+
22
+
23
+ def number(word):
24
+ value=struct.unpack('<f',struct.pack('<I',word&0xffffffff))[0]
25
+ if not math.isfinite(value):raise ValueError('nonfinite float word')
26
+ return value
27
+
28
+
29
+ def float_slice(ins,start,stop,memory,locals_map,limit=256):
30
+ """Isolated straight-line finite arithmetic, not a full QVM float runtime."""
31
+ if not 0<=start<=stop<=len(ins) or stop-start>limit:raise ValueError('invalid float slice bounds')
32
+ m=dict(memory);m.update({BASE+k:v for k,v in locals_map.items()});stack=[];trace=[]
33
+ def read(address):
34
+ if address not in m:raise ValueError('unknown float-slice word')
35
+ return m[address]
36
+ for pc in range(start,stop):
37
+ x=ins[pc];op,v=x['opcode'],x['operand'];trace.append(pc)
38
+ needed={'LOAD4':1,'STORE4':2,'ADD':2,'MULF':2,'ADDF':2,'NEGF':1,'CVIF':1,'BLOCK_COPY':2}.get(op,0)
39
+ if len(stack)<needed:raise ValueError('float-slice stack underflow')
40
+ if op=='CONST':stack.append(v)
41
+ elif op=='LOCAL':stack.append(BASE+v)
42
+ elif op=='LOAD4':stack.append(read(stack.pop()))
43
+ elif op=='STORE4':
44
+ value,address=stack.pop(),stack.pop();m[address]=signed32(value)
45
+ elif op=='ADD':
46
+ b,a=stack.pop(),stack.pop();stack.append(signed32(a+b))
47
+ elif op in ['MULF','ADDF']:
48
+ b,a=number(stack.pop()),number(stack.pop());stack.append(bits(a*b if op=='MULF' else a+b))
49
+ elif op=='NEGF':stack.append(bits(-number(stack.pop())))
50
+ elif op=='CVIF':stack.append(bits(float(signed32(stack.pop()))))
51
+ elif op=='BLOCK_COPY':
52
+ if v!=12:raise ValueError('unsupported block-copy width')
53
+ source,destination=stack.pop(),stack.pop()
54
+ if source%4 or destination%4:raise ValueError('unaligned block-copy fixture')
55
+ values=[read(source+i) for i in [0,4,8]]
56
+ for i,val in zip([0,4,8],values):m[destination+i]=val
57
+ else:raise ValueError('unsupported float-slice opcode '+op)
58
+ return {'trace':trace,'memory':m,'stack':stack}
59
+
60
+
61
+ def main():
62
+ q=json.loads(Path('docs/research/qvm/qagame.json').read_text())
63
+ d=verified(Path(q['source']['member']['output']).read_bytes(),q['sha256']);h,ins=decode(d)
64
+ obj,record=0x10000,0x20000
65
+ gates=[]
66
+ for state,override in [(0,0),(2,0),(3,0),(4,0),(0,1)]:
67
+ t=trace_slice(ins,186046,186084,{obj+520:record,record+4:state,record+4324:override},
68
+ {1144:obj},halt_on_leave=True,capture_stack=True)
69
+ gates.append({'raw_state':state,'override':override,'trace':t})
70
+ origins=[]
71
+ for position,height in [([1,2,3],0),([10,20,30],26),([-1,-2,-3],-8)]:
72
+ output=0x30000;m={obj+24+4*i:bits(v) for i,v in enumerate(position)}
73
+ m.update({obj+520:record,record+164:height})
74
+ t=float_slice(ins,288872,288901,m,{20:obj,24:output})
75
+ origins.append({'position':position,'height_integer':height,'trace':t,
76
+ 'origin':[number(t['memory'][output+4*i]) for i in range(3)]})
77
+ vectors=[]
78
+ # Supplied trig outputs: cardinal yaw/pitch and roll variation, not syscall execution.
79
+ for label,sp,cp,sy,cy,sr,cr in [('forward',0,1,0,1,0,1),('yaw90',0,1,1,0,0,1),
80
+ ('pitch90',1,0,0,1,0,1),('yaw180',0,1,0,-1,0,1),('roll90',0,1,0,1,1,0)]:
81
+ trig={1092:bits(sp),1108:bits(cp),1096:bits(sy),1104:bits(cy),1088:bits(sr),1100:bits(cr)}
82
+ t=float_slice(ins,186186,186297,{},trig)
83
+ basis=[[number(t['memory'][BASE+k]) for k in offsets] for offsets in
84
+ [[84,88,92],[96,100,104],[108,112,116]]]
85
+ ep=float_slice(ins,186305,186332,{}, {120:bits(10),124:bits(20),128:bits(30),
86
+ **{k:t['memory'][BASE+k] for k in [84,88,92]}})
87
+ vectors.append({'label':label,'supplied_trig_words':trig,'basis':basis,'trace':t,
88
+ 'origin':[10,20,30],'endpoint_trace':ep,
89
+ 'endpoint':[number(ep['memory'][BASE+k]) for k in [132,136,140]]})
90
+ trace_args=trace_slice(ins,186332,186356,{obj+520:record,record+140:7},{1144:obj})
91
+ results=[]
92
+ for flag in [0,1,2]:
93
+ t=trace_slice(ins,186356,186431,{}, {148:flag,156:bits(100),160:bits(200),164:bits(300),1144:obj})
94
+ results.append({'trace_word_offset4':flag,'endpoint':[100,200,300],'trace':t})
95
+ comparisons=[]
96
+ for result in [0,1,-1]:
97
+ t=trace_slice(ins,186411,186431,{}, {1084:result,1144:obj})
98
+ comparisons.append({'supplied_comparison_return':result,'trace':t})
99
+ abi=json.loads(Path('docs/research/qvm/qagame.abi-candidates.json').read_text())
100
+ if abi['sha256']!=q['sha256']:raise ValueError('ABI provenance mismatch')
101
+ out={'source':q['source'],'sha256':q['sha256'],'dead_gate_traces':gates,'origin_traces':origins,
102
+ 'basis_endpoint_traces':vectors,'trace_argument_trace':trace_args,'result_traces':results,
103
+ 'comparison_return_traces':comparisons,'abi_reference_revision':abi['reference_revision'],
104
+ 'trace_service_candidate':next(x for x in abi['syscalls'] if x['number']==24),
105
+ 'constants':{'angle_scale_bits':1016003125,'angle_scale_float':number(1016003125),
106
+ 'distance_bits':1189765120,'distance_float':number(1189765120)},
107
+ 'strings':{'78120':vm_string(d,h,78120)},
108
+ 'functions':{str(e):partition_function(ins,e,d,h) for e in [185212,288871,36306]},
109
+ 'limitations':'Bounded synthetic integer and separate finite binary32 straight-line arithmetic, not '
110
+ 'original runtime/full QVM. Trig outputs, trace status/endpoints and isolated comparison returns are '
111
+ 'supplied. CALLs return zero placeholders. Native trigonometry/collision, floating-point exceptional '
112
+ 'domains, actual string comparison/format/location output and platform parity remain open.'}
113
+ write_json(Path('docs/research/chat-crosshair.json'),out)
114
+ print('Recovered crosshair gate, origin/basis/endpoint arithmetic and trace-result routing')
115
+
116
+
117
+ if __name__=='__main__':main()
scripts/test_chat_crosshair.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Crosshair finite arithmetic and independently supplied result boundaries."""
3
+ import json
4
+ from pathlib import Path
5
+ import unittest
6
+ from analyze_chat_crosshair import BASE,bits,number,float_slice
7
+
8
+
9
+ class ChatCrosshairTests(unittest.TestCase):
10
+ @classmethod
11
+ def setUpClass(cls):cls.r=json.loads(Path('docs/research/chat-crosshair.json').read_text())
12
+
13
+ def test_dead_gate_preempts_direction(self):
14
+ rows=self.r['dead_gate_traces']
15
+ self.assertEqual([bool(x['trace']['calls']) for x in rows],[False,False,True,True,True])
16
+ for x in rows[2:]:
17
+ self.assertEqual(x['trace']['calls'][0]['target'],268637)
18
+ self.assertEqual(x['trace']['stack'],[35738436])
19
+ self.assertEqual(x['trace']['calls'][0]['args'],{'8':0x10000,'12':35738436,'16':150})
20
+
21
+ def test_origin_copy_and_integer_height(self):
22
+ for x in self.r['origin_traces']:
23
+ self.assertEqual(x['origin'],[x['position'][0],x['position'][1],x['position'][2]+x['height_integer']])
24
+ self.assertEqual(x['trace']['stack'],[])
25
+ self.assertEqual(self.r['constants']['distance_float'],30000.0)
26
+ self.assertAlmostEqual(self.r['constants']['angle_scale_float'],0.01745329238474369)
27
+
28
+ def test_basis_cardinals_and_roll_independence(self):
29
+ rows=self.r['basis_endpoint_traces']
30
+ self.assertEqual([x['basis'][0] for x in rows],[[1,0,0],[0,1,0],[0,0,-1],[-1,0,0],[1,0,0]])
31
+ for x in rows:
32
+ v=x['basis'];self.assertEqual([sum(a*a for a in axis) for axis in v],[1,1,1])
33
+ self.assertEqual([sum(a*b for a,b in zip(v[i],v[j])) for i,j in [(0,1),(0,2),(1,2)]],[0,0,0])
34
+ self.assertEqual(x['endpoint'],[o+30000*f for o,f in zip(x['origin'],v[0])])
35
+ self.assertNotEqual(rows[0]['basis'][1:],rows[-1]['basis'][1:])
36
+
37
+ def test_trace_argument_contract(self):
38
+ c=self.r['trace_argument_trace']['calls'];self.assertEqual(len(c),1)
39
+ self.assertEqual(c[0]['target'],-25)
40
+ self.assertEqual(c[0]['args'],{'8':BASE+144,'12':BASE+120,'16':0,'20':0,
41
+ '24':BASE+132,'28':7,'32':1})
42
+ self.assertEqual(self.r['trace_service_candidate']['upstream_name_candidate'],'G_TRACE')
43
+
44
+ def test_trace_status_exact_one_and_temp_object(self):
45
+ rows=self.r['result_traces']
46
+ self.assertEqual([[c['target'] for c in x['trace']['calls']] for x in rows],
47
+ [[268637,36306,268637],[36185,268637],[268637,36306,268637]])
48
+ for x in [rows[0],rows[2]]:
49
+ t=x['trace'];self.assertEqual(t['calls'][0]['args']['8'],BASE+200)
50
+ self.assertEqual([number(t['memory'][str(BASE+k)]) for k in [688,692,696]],[100,200,300])
51
+ self.assertEqual(t['memory'][str(BASE+1048)],0)
52
+ self.assertEqual(rows[1]['trace']['calls'][0]['args'],{'8':35738436,'12':78120})
53
+ self.assertEqual(self.r['strings']['78120'],'unknown')
54
+
55
+ def test_supplied_comparison_return_controls_fallback(self):
56
+ rows=self.r['comparison_return_traces']
57
+ self.assertEqual([len(x['trace']['calls']) for x in rows],[1,0,0])
58
+ self.assertEqual(rows[0]['trace']['calls'][0]['args']['8'],0x10000)
59
+
60
+ def test_finite_float_rounding_and_exception_bounds(self):
61
+ self.assertEqual(number(bits(16777217.0)),16777216.0)
62
+ self.assertEqual(bits(-0.0),-2147483648)
63
+ for value in [float('nan'),float('inf'),-float('inf'),1e39]:
64
+ with self.assertRaises(ValueError):bits(value)
65
+ for word in [0x7f800000,0x7fc00000]:
66
+ with self.assertRaises(ValueError):number(word)
67
+ ins=[{'opcode':op,'operand':value} for op,value in [('CONST',bits(3e38)),('CONST',bits(2)),('MULF',None)]]
68
+ with self.assertRaises(ValueError):float_slice(ins,0,3,{}, {})
69
+
70
+ def test_float_slice_unknown_reads_opcodes_and_copy_width(self):
71
+ with self.assertRaises(ValueError):float_slice([{'opcode':'LOAD4','operand':None}],0,1,{}, {})
72
+ # Provide the address before testing unknown-word rejection.
73
+ ins=[{'opcode':'CONST','operand':123},{'opcode':'LOAD4','operand':None}]
74
+ with self.assertRaises(ValueError):float_slice(ins,0,2,{}, {})
75
+ with self.assertRaises(ValueError):float_slice([{'opcode':'CALL','operand':None}],0,1,{}, {})
76
+ with self.assertRaises(ValueError):float_slice(ins,0,2,{}, {},limit=1)
77
+ copy=[{'opcode':'CONST','operand':0x20000},{'opcode':'CONST','operand':0x10000},
78
+ {'opcode':'BLOCK_COPY','operand':16}]
79
+ with self.assertRaises(ValueError):float_slice(copy,0,3,{}, {})
80
+
81
+
82
+ if __name__=='__main__':unittest.main()