nmarshall commited on
Commit
f93de71
·
1 Parent(s): 0113c21

Analyze QVM gravity command gates and movement frame assembly

Browse files
docs/ASSET_PIPELINE_TODO.md CHANGED
@@ -248,3 +248,5 @@ Research progress: [server usercmd acceptance](research/USERCMD_ACCEPTANCE.md) c
248
  Research progress: [native/QVM usercmd bridge](research/QVM_USERCMD.md) completes bounded RE-405–407. RE-404/408 retain producers/translation/VM effects/movement/full packet/runtime/platform contracts; broad game/network/rendering milestones remain open.
249
 
250
  Research progress: [QVM think routes/inactivity/mode gates](research/QVM_THINK_GATES.md) completes bounded RE-409–411. RE-408/412 retain producers/action effects/movement/simulation/full-command/runtime/platform work; broad game/rendering milestones remain open.
 
 
 
248
  Research progress: [native/QVM usercmd bridge](research/QVM_USERCMD.md) completes bounded RE-405–407. RE-404/408 retain producers/translation/VM effects/movement/full packet/runtime/platform contracts; broad game/network/rendering milestones remain open.
249
 
250
  Research progress: [QVM think routes/inactivity/mode gates](research/QVM_THINK_GATES.md) completes bounded RE-409–411. RE-408/412 retain producers/action effects/movement/simulation/full-command/runtime/platform work; broad game/rendering milestones remain open.
251
+
252
+ Research progress: [QVM movement-frame setup](research/QVM_MOVEMENT_FRAME.md) completes bounded RE-413–415. RE-412/416 retain consumers/physics/callbacks/producers/full simulation/runtime/platform work; broad game/rendering milestones remain open.
docs/FINDINGS.md CHANGED
@@ -474,3 +474,9 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
474
  **F-167 — Inactivity decisions:** helper150382 counts signed nonzero movement or button bit0, refreshes timer/warning, handles disable/exemption/health-like branches and uses strict expiry/ten-second-warning comparisons. File-backed strings identify inactivity action requests; recorded traps/helpers do not establish actual drop/team-change effects. [THINK-002](research/QVM_THINK_GATES.md).
475
 
476
  **F-168 — Think continuation/mode word:** zero inactivity result exits before client+4 mutation; nonzero result selects1 for +4040, else3 for +208<=0, else0. Matching-state helper/caller compositions verify precedence, with external action effects omitted. Mode physics and producer semantics remain open. [THINK-003](research/QVM_THINK_GATES.md).
 
 
 
 
 
 
 
474
  **F-167 — Inactivity decisions:** helper150382 counts signed nonzero movement or button bit0, refreshes timer/warning, handles disable/exemption/health-like branches and uses strict expiry/ten-second-warning comparisons. File-backed strings identify inactivity action requests; recorded traps/helpers do not establish actual drop/team-change effects. [THINK-002](research/QVM_THINK_GATES.md).
475
 
476
  **F-168 — Think continuation/mode word:** zero inactivity result exits before client+4 mutation; nonzero result selects1 for +4040, else3 for +208<=0, else0. Matching-state helper/caller compositions verify precedence, with external action effects omitted. Mode physics and producer semantics remain open. [THINK-003](research/QVM_THINK_GATES.md).
477
+
478
+ **F-169 — Movement setup arithmetic:** bit0 of global35000452 zeroes candidate gravity/speed words; otherwise finite binary32 gravity optionally multiplies through a one-use pointer, truncates and sets speed220. Packed-word slices use raw shift/OR without byte masks. Semantic producers and exceptional arithmetic remain open. [FRAME-001](research/QVM_MOVEMENT_FRAME.md).
479
+
480
+ **F-170 — Command and mask gates:** a separate three-condition gate clears forward/right bytes and only signed-positive up bytes. Type/linked-helper/bit8/game-mode branches select four observed masks, with zero helper result clearing two link words. Physics and helper/bit meanings remain unverified. [FRAME-002](research/QVM_MOVEMENT_FRAME.md).
481
+
482
+ **F-171 — Movement frame assembly:** 160 bounded fixtures match every byte of a supplied-zero 268-byte frame containing pointer/command/mask/callback/flag inputs, plus vector copies and recorded helper54475 requests. No movement helper executes; consumer layout, callback/native collision effects and runtime parity remain open. [FRAME-003](research/QVM_MOVEMENT_FRAME.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -560,3 +560,5 @@ Research progress: [server usercmd acceptance](research/USERCMD_ACCEPTANCE.md) c
560
  Research progress: [native/QVM usercmd bridge](research/QVM_USERCMD.md) completes bounded RE-405–407. RE-404/408 retain producers/translation/VM effects/movement/full packet/runtime/platform contracts; broad game/network/rendering milestones remain open.
561
 
562
  Research progress: [QVM think routes/inactivity/mode gates](research/QVM_THINK_GATES.md) completes bounded RE-409–411. RE-408/412 retain producers/action effects/movement/simulation/full-command/runtime/platform work; broad game/rendering milestones remain open.
 
 
 
560
  Research progress: [native/QVM usercmd bridge](research/QVM_USERCMD.md) completes bounded RE-405–407. RE-404/408 retain producers/translation/VM effects/movement/full packet/runtime/platform contracts; broad game/network/rendering milestones remain open.
561
 
562
  Research progress: [QVM think routes/inactivity/mode gates](research/QVM_THINK_GATES.md) completes bounded RE-409–411. RE-408/412 retain producers/action effects/movement/simulation/full-command/runtime/platform work; broad game/rendering milestones remain open.
563
+
564
+ Research progress: [QVM movement-frame setup](research/QVM_MOVEMENT_FRAME.md) completes bounded RE-413–415. RE-412/416 retain consumers/physics/callbacks/producers/full simulation/runtime/platform work; broad game/rendering milestones remain open.
docs/RESEARCH_LEDGER.md CHANGED
@@ -283,3 +283,9 @@ Validation: all preceding composition reports regenerated byte-identically; fina
283
  Completed bounded RE-409–411 with `analyze_qvm_think_gates.py`: verified shipped qagame think slices/helper150382, five file-backed literal addresses, 40 special-route/command-suppression probes, 94 inactivity decision probes and twelve helper-to-caller mode compositions. THINK-001–003/F-166–168 distinguish special helper requests/early returns from normal input mutations, bit0 angle-lock behavior from nonzero special-time handling, signed movement/attack-bit activity from other buttons, strict expiry/warning comparisons from equality, and recorded action requests from actual drop/spectator effects. Matching supplied health/command state composes evaluated helper returns into caller exit/mode precedence. Entity/client/global/flag meanings and mode physics remain candidates where not supported by literals. External helper/trap calls use recorded requests/default return0 with omitted effects; no complete QVM/original executable/native callee executes. The shared evaluator adds explicit per-instruction result overrides, keeping its original default/output unchanged for existing callers. Eight independent tests verify routing/arguments/early retention, angle-copy directions/input suppression/canaries, all inactivity timer/warning/return/action outputs, strict boundaries, mode precedence, file/source identities, activity distinctions and override/default behavior. All 431 tests pass; storage/links/whitespace checks pass. RE-408 remains open; RE-412 tracks global/record/bit semantics and inactivity registrations, special/expiry helpers/native action effects, gravity/speed/full movement-frame inputs, remaining simulation/callback effects, full-command composition and real gameplay/traffic/all-platform conformance before Rust/Bevy/Solari claims.
284
 
285
  Validation: all preceding composition reports regenerated byte-identically, including reports using the shared QVM slice evaluator. The new think-gate report reproduced twice byte-identically. Final suite: 431 passing tests. Storage policy/filter setup, documentation links and whitespace checks pass.
 
 
 
 
 
 
 
283
  Completed bounded RE-409–411 with `analyze_qvm_think_gates.py`: verified shipped qagame think slices/helper150382, five file-backed literal addresses, 40 special-route/command-suppression probes, 94 inactivity decision probes and twelve helper-to-caller mode compositions. THINK-001–003/F-166–168 distinguish special helper requests/early returns from normal input mutations, bit0 angle-lock behavior from nonzero special-time handling, signed movement/attack-bit activity from other buttons, strict expiry/warning comparisons from equality, and recorded action requests from actual drop/spectator effects. Matching supplied health/command state composes evaluated helper returns into caller exit/mode precedence. Entity/client/global/flag meanings and mode physics remain candidates where not supported by literals. External helper/trap calls use recorded requests/default return0 with omitted effects; no complete QVM/original executable/native callee executes. The shared evaluator adds explicit per-instruction result overrides, keeping its original default/output unchanged for existing callers. Eight independent tests verify routing/arguments/early retention, angle-copy directions/input suppression/canaries, all inactivity timer/warning/return/action outputs, strict boundaries, mode precedence, file/source identities, activity distinctions and override/default behavior. All 431 tests pass; storage/links/whitespace checks pass. RE-408 remains open; RE-412 tracks global/record/bit semantics and inactivity registrations, special/expiry helpers/native action effects, gravity/speed/full movement-frame inputs, remaining simulation/callback effects, full-command composition and real gameplay/traffic/all-platform conformance before Rust/Bevy/Solari claims.
284
 
285
  Validation: all preceding composition reports regenerated byte-identically, including reports using the shared QVM slice evaluator. The new think-gate report reproduced twice byte-identically. Final suite: 431 passing tests. Storage policy/filter setup, documentation links and whitespace checks pass.
286
+
287
+ ## 2026-10-11 — Game-QVM gravity, command suppression and movement-frame assembly
288
+
289
+ Completed bounded RE-413–415 with `analyze_qvm_movement_frame.py`: verified shipped qagame setup/assembly slices, 72 finite gravity/speed probes, four raw packed-word probes and 160 complete supplied-zero frame probes. FRAME-001–003/F-169–171 recover bit0-controlled gravity/speed writes, finite binary32 multiply/truncate and one-use pointer consumption, unmasked shift/OR packing, signed-positive-up versus forward/right suppression, four observed mask words/precedence and linked-helper failure cleanup, and every byte of the 268-byte frame passed to helper54475. Two bit-preserving vector copies and raw-versus-Boolean flags/callback values are independently verified. Trap100 frame-zeroing and helper151954 results are supplied with omitted effects; helper54475 requests stop and no movement physics/full QVM/native callee/original runtime executes. Semantic names/mask bits/configuration/layout consumers and callback contracts remain candidates. Shared evaluator extensions are restricted aligned word-backed BLOCK_COPY with byte overlay, BOR and finite in-range binary32 MULF/CVFI; unknown/unaligned copy and exceptional float cases fail closed. Eight independent tests verify arithmetic/pointer behavior, raw packing, command bytes/canaries, full frame/vector output, mask/link/request precedence, source identities, copy overlay/failure domains and finite conversion/OR boundaries. All 439 tests pass; storage/links/whitespace checks pass. RE-412 remains open; RE-416 tracks helper54475 consumers/physics, callback/native collision ABI, helper151954/link/configuration/packed-word producers/legal ranges, copy/float/alias/runtime edge cases, post-movement mutation and full command-to-simulation/gameplay/macOS/Linux conformance before Rust/Bevy/Solari claims.
290
+
291
+ Validation: all preceding composition reports regenerated byte-identically, including shared-QVM-evaluator users. The new movement-frame report reproduced twice byte-identically. Final suite: 439 passing tests. Storage policy/filter setup, documentation links and whitespace checks pass.
docs/REVERSE_ENGINEERING_TODO.md CHANGED
@@ -497,3 +497,8 @@ Purpose: turn the supplied installation into an evidence-backed specification of
497
  - [x] RE-410 Recover bounded inactivity helper150382 activity/timer/warning/expiry decisions and literal-backed action requests using independent signed arithmetic/state oracles. [THINK-002](research/QVM_THINK_GATES.md).
498
  - [x] RE-411 Compose evaluated inactivity results into caller early-return/mode-word precedence with matching supplied state and explicit call-result overrides. [THINK-003](research/QVM_THINK_GATES.md).
499
  - [ ] RE-412 Confirm think global/field/flag semantics and inactivity policy producers; trace special-route/expiry helpers/native action effects; recover gravity/speed/movement-frame inputs and remaining simulation/callback mutations; compose full command processing and validate traffic/gameplay/all-platform behavior before Rust/Bevy/Solari claims.
 
 
 
 
 
 
497
  - [x] RE-410 Recover bounded inactivity helper150382 activity/timer/warning/expiry decisions and literal-backed action requests using independent signed arithmetic/state oracles. [THINK-002](research/QVM_THINK_GATES.md).
498
  - [x] RE-411 Compose evaluated inactivity results into caller early-return/mode-word precedence with matching supplied state and explicit call-result overrides. [THINK-003](research/QVM_THINK_GATES.md).
499
  - [ ] RE-412 Confirm think global/field/flag semantics and inactivity policy producers; trace special-route/expiry helpers/native action effects; recover gravity/speed/movement-frame inputs and remaining simulation/callback mutations; compose full command processing and validate traffic/gameplay/all-platform behavior before Rust/Bevy/Solari claims.
500
+
501
+ - [x] RE-413 Recover bounded finite gravity/speed setup, one-use multiplier pointer behavior and unmasked packed-word shift/OR inputs. [FRAME-001](research/QVM_MOVEMENT_FRAME.md).
502
+ - [x] RE-414 Recover bounded signed movement-byte suppression and movement-frame mask/helper/linked-pointer cleanup gates with independent request/byte oracles. [FRAME-002](research/QVM_MOVEMENT_FRAME.md).
503
+ - [x] RE-415 Recover complete supplied-zero 268-byte frame assembly, command/vector copies, raw/Boolean flags and encoded callback values; stop at helper54475 and verify every frame byte. [FRAME-003](research/QVM_MOVEMENT_FRAME.md).
504
+ - [ ] RE-416 Recover helper54475 frame consumers/physics, callback/native collision ABI, helper151954/link producers, setup globals/configuration/packed-word legal ranges, copy/float/alias/runtime edge cases and post-movement mutations; compose full command-to-simulation and validate gameplay/macOS/Linux before Rust/Bevy/Solari claims. Continue entity/player/snapshot/rendering work.
docs/research/QVM_MOVEMENT_FRAME.md ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Game-QVM movement setup and frame assembly
2
+
3
+ RE-413–415 / F-169–171. [qvm-movement-frame.json](qvm-movement-frame.json) retains verified shipped qagame instruction slices, 72 finite gravity/speed probes, four packed-word probes and 160 complete frame-assembly probes. Reproduce with `python3 scripts/analyze_qvm_movement_frame.py`; verify with `python3 scripts/test_qvm_movement_frame.py`.
4
+
5
+ This follows [think/inactivity gates](QVM_THINK_GATES.md). Results are bounded synthetic instruction evaluations. No complete QVM, original executable, native callee or movement physics runs. The earlier trap100 frame-zeroing effects are supplied. Helper151954 returns are supplied with omitted side effects; helper54475 receives a recorded request only. Semantic names for fields/masks/callbacks are candidates pending consumer/producer recovery.
6
+
7
+ ## FRAME-001 — Finite gravity/speed and packed words (RE-413)
8
+
9
+ At instructions154441–154507, global35000452 bit0 selects zero writes to client+48 and client+52. The branch retains any entity+852 pointer instead of consuming it.
10
+
11
+ Otherwise global34086640 is treated as binary32 and converted by truncation to client+48. When entity+852 is nonzero, the value is first multiplied by binary32 at that pointed record+628, rounded to binary32, then converted. The entity+852 pointer is cleared afterward. Client+52 becomes220 on both bit0-clear paths. Gravity and speed are provisional interpretations of these two player-state words; their configuration registration and physical consumers remain open.
12
+
13
+ 72 probes cover lock words0/1/2, finite base values0/800/801.9/-1.5 and absent or finite multiplier values0/0.5/1/1.5/2. Independent binary32 rounding/truncation verifies the two output words and pointer consumption. Nonfinite and out-of-int32 conversions fail closed in the model; they are not a specification of original-runtime exceptional behavior or floating-control state.
14
+
15
+ Instructions154507–154544 store `global34992556 OR (global34992560 <<8)` at client+288 and `global35000356 OR (global35000360 <<8)` at client+292, modulo32. There are **no byte masks** in these slices. Four fixtures include ordinary byte values and high/out-of-byte-range words, proving that an inferred two-byte packing rule would discard observed bits. Local332 preserves client+108 for later use. Meaning and legal ranges of these globals/packed words remain open.
16
+
17
+ ## FRAME-002 — Signed command suppression and mask gates (RE-414)
18
+
19
+ Before the frame copy, instructions154579–154653 suppress movement only when client+208 >0, client+4324 ==0 and `(client+220 &2) !=0`. They clear command forward/right bytes at client+493/+494. The up byte at +495 is sign-extended: it is cleared only when positive, while zero and negative values remain unchanged. Weapon, timestamps, angles and buttons are retained by this particular gate. This is separate from the earlier think gates that clear all three movement bytes/buttons.
20
+
21
+ The frame mask at local84 follows these branches:
22
+
23
+ | Condition, in priority order | Observed word |
24
+ | --- | --- |
25
+ | Client+4 ==3 | 65537 / 0x00010001 |
26
+ | Otherwise client+4396 nonzero and supplied helper151954(entity, linked entity) result nonzero | 65537 / 0x00010001 |
27
+ | Linked path with helper result zero | 33619969 / 0x02010001; clear own client+4396 and linked entity's client[+4396] |
28
+ | No linked path, entity+424 bit8 nonzero | 37814273 / 0x02410001 |
29
+ | Otherwise global34090788 ==9 and client+3704 nonzero | 67174401 / 0x04010001 |
30
+ | Remaining path | 33619969 / 0x02010001 |
31
+
32
+ The linked-client pointer comes from linked entity+520. Its validity, helper151954 semantics, legitimate links and cleanup effects outside these two stores remain open. Type3 takes precedence and bypasses the linked-helper call entirely. These words resemble movement trace/content masks, but this batch does not assign individual content-bit names or prove collision consumers.
33
+
34
+ Sixty command-gate fixtures cover health-like/other/flag words and up bytes0/1/127/128/255. Sixty-four mask fixtures exercise type/linked/helper/bit8/game9/condition branches. Independent checks verify exact command bytes, mask priority, pointer cleanup and recorded helper requests.
35
+
36
+ ## FRAME-003 — Complete supplied-zero movement frame (RE-415)
37
+
38
+ The earlier code requests trap target-101 with `(local56,0,268)`. This is a recorded zeroing request from instructions154544–154552; its actual trap effects are supplied explicitly in these assembly fixtures. The modeled frame spans 268 bytes at local56. Offsets below are relative to that frame, not absolute QVM record offsets.
39
+
40
+ | Frame offset | Observed input |
41
+ | --- | --- |
42
+ | 0 | Entity's client pointer (candidate player-state pointer) |
43
+ | 4–27 | Full 24-byte command copied from client+472 after suppression |
44
+ | 28 | Selected mask from FRAME-002 |
45
+ | 32 | Raw global34085164 word |
46
+ | 220 | Raw client+712 word |
47
+ | 224 | -25 encoded callback value |
48
+ | 228 | -26 encoded callback value |
49
+ | 232 | Boolean(global34992512 !=0) |
50
+ | 236 | Boolean(entity+424 bit8 !=0) |
51
+ | 244 | Boolean(global35000452 bit0 !=0) |
52
+ | 248 | Raw client+700 word |
53
+
54
+ All other bytes in the fixture retain supplied zero unless written by the recorded assembly. This is a complete fixture output, not a declaration that every unmodified frame word is unused by the real consumer. Callback values are retained literally; their call ABI, actual trace/point-content behavior and native bridge require consumer recovery.
55
+
56
+ The assembly also copies client+20's three words to client+4072 and client+152's three words into local336. These are bit-preserving 12-byte copies, with vector/origin meanings still requiring complete layout evidence.
57
+
58
+ At instruction154870 it records helper54475(local56), then stops before movement effects or subsequent post-processing. 160 assembly probes combine the 60 command and 64 mask fixtures with 36 independent raw/Boolean global/client flag combinations. Tests construct an independent 268-byte frame and compare every byte, both vectors, pointer mutations, neighboring command canaries and every recorded call. Nonzero global flag -1 becomes Boolean1, bit1 lock word2 becomes Boolean0, while client+712/+700 words pass through raw.
59
+
60
+ The shared evaluator adds restricted aligned word-backed BLOCK_COPY with a byte overlay so earlier STORE1 command mutations are included in copied words. It also adds BOR and finite binary32 MULF/CVFI. Unknown/unbacked or unaligned copies and nonfinite/out-of-range arithmetic fail closed. General overlapping/unaligned byte copies, aliasing, exceptional arithmetic and QVM runtime memory masking remain unverified.
61
+
62
+ ## Validation and remaining work
63
+
64
+ Eight independent tests verify finite arithmetic/pointer consumption, unmasked shift/OR packing, signed input suppression/canaries, complete frame/vector bytes, mask/cleanup/call precedence, provenance, byte-overlay copy/failure domains and finite conversion/OR boundaries. Existing report regeneration checks protect previous evaluator users.
65
+
66
+ RE-412 remains open for complete setup/producer/simulation/runtime work. RE-416 must recover helper54475 and its entire frame layout/consumers, callback ABI/native collision integration, helper151954 and link producers, gravity/speed and packed-word registrations/legal ranges, byte-copy/float/alias/runtime edge cases, post-movement mutations and full packet-to-simulation composition. Validate actual gameplay and macOS/Linux behavior before Rust/Bevy/Solari compatibility claims; entity/player/snapshot codecs and rendering also remain open.
docs/research/QVM_THINK_GATES.md CHANGED
@@ -63,3 +63,5 @@ The shared slice evaluator now accepts explicit per-instruction call-result over
63
  Eight independent tests verify routing/arguments, angle/movement/button mutations and canaries, all inactivity outputs/actions, strict thresholds, matching helper/caller mode composition, literal/source provenance, activity distinctions and explicit result overrides.
64
 
65
  RE-408 remains open for full think/simulation/producer/runtime work. RE-412 must confirm the global/record/bit semantics and inactivity policy registrations, trace special-route/expiry helpers and native trap action effects, recover gravity/speed and the complete movement-frame inputs, continue movement/simulation and callback mutations, compose full decoded-command processing, and validate actual traffic/gameplay/all-platform behavior before Rust/Bevy/Solari compatibility claims.
 
 
 
63
  Eight independent tests verify routing/arguments, angle/movement/button mutations and canaries, all inactivity outputs/actions, strict thresholds, matching helper/caller mode composition, literal/source provenance, activity distinctions and explicit result overrides.
64
 
65
  RE-408 remains open for full think/simulation/producer/runtime work. RE-412 must confirm the global/record/bit semantics and inactivity policy registrations, trace special-route/expiry helpers and native trap action effects, recover gravity/speed and the complete movement-frame inputs, continue movement/simulation and callback mutations, compose full decoded-command processing, and validate actual traffic/gameplay/all-platform behavior before Rust/Bevy/Solari compatibility claims.
66
+
67
+ Follow-up: [movement-frame setup](QVM_MOVEMENT_FRAME.md) recovers bounded finite gravity/speed, packed words, further input suppression and complete supplied-zero frame assembly. Movement consumers/physics, configuration/links/callback effects and runtime validation remain open.
docs/research/README.md CHANGED
@@ -161,3 +161,5 @@ The extension collector adds five focused tests for native tail calls, command-r
161
  [Native retrieval and game-QVM usercmd prefix](QVM_USERCMD.md) adds RE-405–407. Reproduce with `python3 scripts/analyze_qvm_usercmd.py`; check with `python3 scripts/test_qvm_usercmd.py`. Cross-address mapping is supplied and remaining VM/simulation/runtime effects are open.
162
 
163
  [QVM think routes, inactivity and mode selection](QVM_THINK_GATES.md) adds RE-409–411. Reproduce with `python3 scripts/analyze_qvm_think_gates.py`; check with `python3 scripts/test_qvm_think_gates.py`. External actions are recorded with omitted effects; full simulation/runtime work remains open.
 
 
 
161
  [Native retrieval and game-QVM usercmd prefix](QVM_USERCMD.md) adds RE-405–407. Reproduce with `python3 scripts/analyze_qvm_usercmd.py`; check with `python3 scripts/test_qvm_usercmd.py`. Cross-address mapping is supplied and remaining VM/simulation/runtime effects are open.
162
 
163
  [QVM think routes, inactivity and mode selection](QVM_THINK_GATES.md) adds RE-409–411. Reproduce with `python3 scripts/analyze_qvm_think_gates.py`; check with `python3 scripts/test_qvm_think_gates.py`. External actions are recorded with omitted effects; full simulation/runtime work remains open.
164
+
165
+ [QVM gravity and movement-frame assembly](QVM_MOVEMENT_FRAME.md) adds RE-413–415. Reproduce with `python3 scripts/analyze_qvm_movement_frame.py`; check with `python3 scripts/test_qvm_movement_frame.py`. Frame zeroing/helper results are supplied; movement physics and callback/runtime effects remain open.
docs/research/qvm-movement-frame.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_deferred_auth.py CHANGED
@@ -2,6 +2,8 @@
2
  """Static references and bounded synthetic-memory traces for deferred auth drops."""
3
  import gzip
4
  import json
 
 
5
  from pathlib import Path
6
  from analyze_qvm import decode, write_json
7
  from analyze_vm_extensions import verified, native_functions
@@ -73,9 +75,45 @@ def trace_slice(instructions, start, stop, memory, locals_map, limit=256, byte_m
73
  raise ValueError('shift outside bounded evaluator domain')
74
  shifted = left << right if op == 'LSH' else signed32(left) >> right if op == 'RSHI' else (left & 0xffffffff) >> right
75
  stack.append(signed32(shifted))
76
- elif op == 'BAND':
77
  right, left = stack.pop(), stack.pop()
78
- stack.append(signed32(left & right))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  elif op in ('DIVI', 'MODI'):
80
  right, left = signed32(stack.pop()), signed32(stack.pop())
81
  if right == 0 or (left == -(2**31) and right == -1):
 
2
  """Static references and bounded synthetic-memory traces for deferred auth drops."""
3
  import gzip
4
  import json
5
+ import math
6
+ import struct
7
  from pathlib import Path
8
  from analyze_qvm import decode, write_json
9
  from analyze_vm_extensions import verified, native_functions
 
75
  raise ValueError('shift outside bounded evaluator domain')
76
  shifted = left << right if op == 'LSH' else signed32(left) >> right if op == 'RSHI' else (left & 0xffffffff) >> right
77
  stack.append(signed32(shifted))
78
+ elif op in ('BAND', 'BOR'):
79
  right, left = stack.pop(), stack.pop()
80
+ stack.append(signed32(left & right if op == 'BAND' else left | right))
81
+ elif op == 'MULF':
82
+ right, left = stack.pop(), stack.pop()
83
+ a, b = [struct.unpack('<f', struct.pack('<I', v & 0xffffffff))[0] for v in (left, right)]
84
+ if not math.isfinite(a) or not math.isfinite(b):
85
+ raise ValueError('nonfinite bounded float multiply')
86
+ try:
87
+ result = struct.pack('<f', a*b)
88
+ except OverflowError as exc:
89
+ raise ValueError('overflow bounded float multiply') from exc
90
+ if not math.isfinite(struct.unpack('<f', result)[0]):
91
+ raise ValueError('nonfinite bounded float result')
92
+ stack.append(signed32(struct.unpack('<I', result)[0]))
93
+ elif op == 'CVFI':
94
+ value = struct.unpack('<f', struct.pack('<I', stack.pop() & 0xffffffff))[0]
95
+ if not math.isfinite(value) or not -(2**31) <= math.trunc(value) < 2**31:
96
+ raise ValueError('conversion outside bounded float domain')
97
+ stack.append(math.trunc(value))
98
+ elif op == 'BLOCK_COPY':
99
+ source, dest = stack.pop(), stack.pop()
100
+ if value % 4 or source % 4 or dest % 4:
101
+ raise ValueError('unaligned bounded word copy')
102
+ copied = []
103
+ for offset in range(0, value, 4):
104
+ if source+offset not in memory:
105
+ raise ValueError('unknown bounded copy read')
106
+ word = memory[source+offset] & 0xffffffff
107
+ if bytes_map is not None:
108
+ for byte in range(4):
109
+ if source+offset+byte in bytes_map:
110
+ word = (word & ~(255 << (8*byte))) | ((bytes_map[source+offset+byte] & 255) << (8*byte))
111
+ copied.append(word)
112
+ for offset, word in enumerate(copied):
113
+ memory[dest+offset*4] = signed32(word)
114
+ if bytes_map is not None:
115
+ for byte in range(4):
116
+ bytes_map[dest+offset*4+byte] = (word >> (8*byte)) & 255
117
  elif op in ('DIVI', 'MODI'):
118
  right, left = signed32(stack.pop()), signed32(stack.pop())
119
  if right == 0 or (left == -(2**31) and right == -1):
scripts/analyze_qvm_movement_frame.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Bounded finite gravity/speed and movement-frame assembly; no movement runs."""
3
+ import itertools
4
+ import json
5
+ import struct
6
+ from pathlib import Path
7
+ from analyze_bsp_references import trace_fields
8
+ from analyze_deferred_auth import signed32,trace_slice
9
+ from analyze_qvm import decode,write_json
10
+ from analyze_vm_extensions import verified
11
+
12
+ CLIENT=0x10000
13
+ ENTITY=0x20000
14
+ LINKED_CLIENT=0x30000
15
+ LINKED_ENTITY=0x40000
16
+ LOCAL=0x40000000
17
+
18
+
19
+ def bits(v):return struct.unpack('<I',struct.pack('<f',v))[0]
20
+
21
+
22
+ def gravity_probe(ins,lock,base,multiplier):
23
+ m={35000452:lock,ENTITY+852:LINKED_ENTITY if multiplier is not None else 0,34086640:bits(base),LINKED_ENTITY+628:bits(multiplier or 0),CLIENT+48:0x1234,CLIENT+52:0x5678};t=trace_slice(ins,154441,154507,m,{52:CLIENT,444:ENTITY});return {'lock_word':lock,'base_float_word':bits(base),'multiplier_float_word':None if multiplier is None else bits(multiplier),'gravity_word':t['memory'][CLIENT+48]&0xffffffff,'speed_word':t['memory'][CLIENT+52]&0xffffffff,'remaining_multiplier_pointer':t['memory'][ENTITY+852],**trace_fields(t,False)}
24
+
25
+
26
+ def packed_probe(ins,a,b,c,d):
27
+ m={ENTITY+520:CLIENT,34992556:a,34992560:b,35000356:c,35000360:d,CLIENT+108:0x12345678};t=trace_slice(ins,154507,154544,m,{444:ENTITY,52:CLIENT});return {'global_words':[a,b,c,d],'packed_words':[t['memory'][CLIENT+288]&0xffffffff,t['memory'][CLIENT+292]&0xffffffff],'saved_local332_word':t['memory'][LOCAL+332]&0xffffffff,**trace_fields(t,False)}
28
+
29
+
30
+ def frame_probe(ins,health=100,other=0,input_flags=0,up=1,kind=0,linked=0,helper=0,bot=0,game=0,condition=0,global_flag=0,lock=0,fixed=0,client700=0):
31
+ command=(1234).to_bytes(4,'little')+struct.pack('<4I',101,202,303,0x1234)+bytes([7,128,255,up]);m={ENTITY+520:CLIENT,ENTITY+424:bot,CLIENT+208:health,CLIENT+4324:other,CLIENT+220:input_flags,CLIENT+4:kind,CLIENT+4396:LINKED_ENTITY if linked else 0,LINKED_ENTITY+520:LINKED_CLIENT,LINKED_CLIENT+4396:0xaaaa,34090788:game,CLIENT+3704:condition,34085164:0x5555,34992512:global_flag,CLIENT+712:fixed,CLIENT+700:client700,35000452:lock}
32
+ for i in range(0,24,4):m[CLIENT+472+i]=signed32(int.from_bytes(command[i:i+4],'little'))
33
+ for i,v in enumerate([0x3f800000,0x40000000,0x40400000]):m[CLIENT+20+i*4]=v;m[CLIENT+152+i*4]=v+1
34
+ # Frame memset effects are supplied explicitly; trap100 is not evaluated.
35
+ for o in range(56,324,4):m[LOCAL+o]=0
36
+ b={CLIENT+472+i:v for i,v in enumerate(command)};b[CLIENT+471]=b[CLIENT+496]=0x7b;t=trace_slice(ins,154579,154872,m,{52:CLIENT,444:ENTITY,324:CLIENT+472},byte_memory=b,call_results={154704:helper});mem=t['memory'];frame=b''.join((mem[LOCAL+o]&0xffffffff).to_bytes(4,'little') for o in range(56,324,4));return {'health_word':health,'other_word':other,'input_flags_word':input_flags,'up_byte':up,'type_word':kind,'linked_word':linked,'supplied_helper_result':helper,'bot_flags_word':bot,'game_word':game,'condition_word':condition,'global_flag_word':global_flag,'lock_word':lock,'fixed_word':fixed,'client700_word':client700,'initial_command_hex':command.hex(),'result_command_hex':bytes(t['byte_memory'][CLIENT+472+i] for i in range(24)).hex(),'frame_hex':frame.hex(),'origin_copy_words':[mem[CLIENT+4072+i*4]&0xffffffff for i in range(3)],'saved_local_vector_words':[mem[LOCAL+336+i*4]&0xffffffff for i in range(3)],'remaining_link_pointer':mem[CLIENT+4396],'remaining_peer_pointer':mem[LINKED_CLIENT+4396],'canaries':[t['byte_memory'][CLIENT+471],t['byte_memory'][CLIENT+496]],'calls':t['calls'],**trace_fields(t,False)}
37
+
38
+
39
+ def main():
40
+ r=json.loads(Path('docs/research/qvm/qagame.json').read_text());data=verified(Path(r['source']['member']['output']).read_bytes(),r['sha256']);_,ins=decode(data);frames=[]
41
+ for health,other,flags,up in itertools.product([-1,0,1],[0,1],[0,2],[0,1,127,128,255]):frames.append(frame_probe(ins,health=health,other=other,input_flags=flags,up=up))
42
+ for kind,linked,helper,bot,game,condition in itertools.product([0,3],[0,1],[0,1],[0,8],[0,9],[0,1]):frames.append(frame_probe(ins,kind=kind,linked=linked,helper=helper,bot=bot,game=game,condition=condition))
43
+ for flag,lock,fixed,client700 in itertools.product([-1,0,1],[0,1,2],[0,1],[0,1]):frames.append(frame_probe(ins,global_flag=flag,lock=lock,fixed=fixed,client700=client700))
44
+ out={'source':r['source'],'sha256':r['sha256'],'gravity_instructions':ins[154441:154507],'packed_instructions':ins[154507:154579],'frame_instructions':ins[154579:154872],'gravity_probes':[gravity_probe(ins,*v) for v in itertools.product([0,1,2],[0.0,800.0,801.9,-1.5],[None,0.0,0.5,1.0,1.5,2.0])],'packed_probes':[packed_probe(ins,*v) for v in [(1,2,3,4),(255,255,255,255),(256,1,256,1),(0xffffffff,0xffffffff,0x80000000,0x1234)]],'frame_probes':frames,'limitations':'Bounded synthetic shipped-QVM instruction slices only; no full QVM/native callee/original runtime executes. Float multiply/conversion finite in-range model only. Frame268-byte zeroing supplied, not trap100 evaluation. Helper151954 result supplied with no effects; callback words and movement helper54475 requests recorded, not invoked. BLOCK_COPY modeled only aligned word-backed sources with byte overlay. Semantic field/global/mask names remain candidates. No movement physics/full-frame consumers/nonfinite/alias/packet/runtime/platform conformance.'};write_json(Path('docs/research/qvm-movement-frame.json'),out);print('Recovered bounded gravity speed packed words and movement-frame assembly')
45
+
46
+
47
+ if __name__=='__main__':main()
scripts/test_qvm_movement_frame.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Independent finite arithmetic, command-byte and complete-frame oracles."""
3
+ import hashlib
4
+ import json
5
+ import math
6
+ from pathlib import Path
7
+ import struct
8
+ import unittest
9
+ from analyze_deferred_auth import trace_slice
10
+
11
+
12
+ def f32(word):return struct.unpack('<f',struct.pack('<I',word))[0]
13
+ def round32(v):return struct.unpack('<f',struct.pack('<f',v))[0]
14
+ def store(raw,offset,value):raw[offset:offset+4]=(value&0xffffffff).to_bytes(4,'little')
15
+
16
+ def command(p):
17
+ raw=bytearray.fromhex(p['initial_command_hex'])
18
+ if p['health_word']>0 and p['other_word']==0 and p['input_flags_word']&2:
19
+ raw[21]=raw[22]=0
20
+ if 0<raw[23]<128:raw[23]=0
21
+ return raw
22
+
23
+
24
+ def mask(p):
25
+ if p['type_word']==3:return 65537
26
+ if p['linked_word']:return 65537 if p['supplied_helper_result'] else 33619969
27
+ if p['bot_flags_word']&8:return 37814273
28
+ if p['game_word']==9 and p['condition_word']!=0:return 67174401
29
+ return 33619969
30
+
31
+
32
+ class MovementFrameTests(unittest.TestCase):
33
+ @classmethod
34
+ def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-movement-frame.json').read_text())
35
+
36
+ def test_finite_gravity_scaling_truncation_speed_and_pointer_consumption(self):
37
+ self.assertEqual(len(self.r['gravity_probes']),72)
38
+ for p in self.r['gravity_probes']:
39
+ paused=p['lock_word']&1;value=f32(p['base_float_word']);mult=p['multiplier_float_word']
40
+ if mult is not None:value=round32(value*f32(mult))
41
+ self.assertEqual(p['gravity_word'],0 if paused else math.trunc(value)&0xffffffff);self.assertEqual(p['speed_word'],0 if paused else 220);self.assertEqual(p['remaining_multiplier_pointer'],0x40000 if paused and mult is not None else 0)
42
+
43
+ def test_packed_words_are_shift_or_without_byte_masks(self):
44
+ for p in self.r['packed_probes']:
45
+ a,b,c,d=p['global_words'];self.assertEqual(p['packed_words'],[(a|(b<<8))&0xffffffff,(c|(d<<8))&0xffffffff]);self.assertEqual(p['saved_local332_word'],0x12345678)
46
+
47
+ def test_input_gate_preserves_negative_up_weapon_and_other_bytes(self):
48
+ self.assertEqual(len(self.r['frame_probes']),160)
49
+ for p in self.r['frame_probes']:self.assertEqual(p['result_command_hex'],command(p).hex());self.assertEqual(p['canaries'],[0x7b]*2)
50
+
51
+ def test_complete_zero_based_frame_layout_copies_callbacks_and_flags(self):
52
+ for p in self.r['frame_probes']:
53
+ raw=bytearray(268);store(raw,0,0x10000);raw[4:28]=command(p)
54
+ for o,v in [(28,mask(p)),(32,0x5555),(220,p['fixed_word']),(224,-25),(228,-26),(232,int(p['global_flag_word']!=0)),(236,int(bool(p['bot_flags_word']&8))),(244,p['lock_word']&1),(248,p['client700_word'])]:store(raw,o,v)
55
+ self.assertEqual(p['frame_hex'],raw.hex());self.assertEqual(p['origin_copy_words'],[0x3f800000,0x40000000,0x40400000]);self.assertEqual(p['saved_local_vector_words'],[0x3f800001,0x40000001,0x40400001])
56
+
57
+ def test_mask_precedence_link_failure_cleanup_and_exact_requests(self):
58
+ for p in self.r['frame_probes']:
59
+ linked=p['linked_word'] and p['type_word']!=3;calls=[]
60
+ if linked:calls.append({'instruction':154704,'target':151954,'args':{'8':0x20000,'12':0x40000}})
61
+ calls.append({'instruction':154870,'target':54475,'args':{'8':0x40000038}});self.assertEqual(p['calls'],calls);cleared=linked and p['supplied_helper_result']==0;self.assertEqual(p['remaining_link_pointer'],0 if cleared or not p['linked_word'] else 0x40000);self.assertEqual(p['remaining_peer_pointer'],0 if cleared else 0xaaaa)
62
+
63
+ def test_source_and_instruction_boundaries(self):
64
+ r=json.loads(Path('docs/research/qvm/qagame.json').read_text());raw=Path(r['source']['member']['output']).read_bytes();self.assertEqual(hashlib.sha256(raw).hexdigest(),self.r['sha256']);self.assertEqual(r['source'],self.r['source']);self.assertEqual(self.r['frame_instructions'][-2]['opcode'],'CALL');self.assertEqual(self.r['frame_instructions'][-3]['operand'],54475)
65
+
66
+ def test_restricted_word_copy_uses_byte_overlay_and_rejects_unknown_unaligned(self):
67
+ ins=[{'index':0,'opcode':'CONST','operand':0x2000},{'index':1,'opcode':'CONST','operand':0x1000},{'index':2,'opcode':'BLOCK_COPY','operand':4}];r=trace_slice(ins,0,3,{0x1000:0x12345678},{},byte_memory={0x1001:0xff});self.assertEqual(r['memory'][0x2000],0x1234ff78)
68
+ with self.assertRaisesRegex(ValueError,'unknown bounded copy read'):trace_slice(ins,0,3,{}, {})
69
+ ins[2]['operand']=3
70
+ with self.assertRaisesRegex(ValueError,'unaligned bounded word copy'):trace_slice(ins,0,3,{0x1000:0}, {})
71
+
72
+ def test_finite_float_domain_and_bitwise_or(self):
73
+ ins=[{'index':0,'opcode':'CONST','operand':0x3fc00000},{'index':1,'opcode':'CVFI','operand':None}];self.assertEqual(trace_slice(ins,0,2,{}, {},capture_stack=True)['stack'],[1])
74
+ for word in [0x7fc00000,0x7f800000,0x4f000000]:
75
+ ins[0]['operand']=word
76
+ with self.assertRaisesRegex(ValueError,'outside bounded float domain'):trace_slice(ins,0,2,{}, {})
77
+ mul=[{'index':0,'opcode':'CONST','operand':0x7f800000},{'index':1,'opcode':'CONST','operand':0x3f800000},{'index':2,'opcode':'MULF','operand':None}]
78
+ with self.assertRaisesRegex(ValueError,'nonfinite bounded float multiply'):trace_slice(mul,0,3,{}, {})
79
+ mul[0]['operand']=0x7f7fffff;mul[1]['operand']=0x40000000
80
+ with self.assertRaisesRegex(ValueError,'overflow bounded float multiply'):trace_slice(mul,0,3,{}, {})
81
+ mul[0]['operand']=1;mul[1]['operand']=256;mul[2]['opcode']='BOR';self.assertEqual(trace_slice(mul,0,3,{}, {},capture_stack=True)['stack'],[257])
82
+
83
+
84
+ if __name__=='__main__':unittest.main()