Analyze QVM think routing inactivity and mode gates
Browse files- docs/ASSET_PIPELINE_TODO.md +2 -0
- docs/FINDINGS.md +6 -0
- docs/PROVISIONAL_TODO.md +2 -0
- docs/RESEARCH_LEDGER.md +6 -0
- docs/REVERSE_ENGINEERING_TODO.md +5 -0
- docs/research/QVM_THINK_GATES.md +65 -0
- docs/research/QVM_USERCMD.md +2 -0
- docs/research/README.md +2 -0
- docs/research/qvm-think-gates.json +0 -0
- scripts/analyze_deferred_auth.py +2 -2
- scripts/analyze_qvm_think_gates.py +44 -0
- scripts/test_qvm_think_gates.py +79 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -246,3 +246,5 @@ Research progress: [usercmd caller/hash/bundle evidence](research/USERCMD_CALLER
|
|
| 246 |
Research progress: [server usercmd acceptance](research/USERCMD_ACCEPTANCE.md) completes bounded RE-401–403. RE-400/404 retain producers/time clamping/QVM effects/full packet/runtime/platform work; game/network/rendering milestones remain open.
|
| 247 |
|
| 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.
|
|
|
|
|
|
|
|
|
| 246 |
Research progress: [server usercmd acceptance](research/USERCMD_ACCEPTANCE.md) completes bounded RE-401–403. RE-400/404 retain producers/time clamping/QVM effects/full packet/runtime/platform work; game/network/rendering milestones remain open.
|
| 247 |
|
| 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.
|
docs/FINDINGS.md
CHANGED
|
@@ -468,3 +468,9 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
|
|
| 468 |
**F-164 — Game selector7 bridge:** qagame case65 calls155718, which requests trap36(index, entity[+520]+472), stores game time at client+4044 and gates helper154089 on entity bit8/global34084868. Native copy results are mapped into synthetic QVM word memory; flag meanings/full runtime bridge remain open. [QCMD-002](research/QVM_USERCMD.md).
|
| 469 |
|
| 470 |
**F-165 — Game-side command time prefix:** helper154089 preserves raw time, sequentially clamps command time to signed game-time bounds -1000/+200, computes/caps elapsed independently and optionally adjusts timestamp in eight-unit steps afterward. Early returns retain preceding mutations; signed-boundary fixtures do not establish legal gameplay. [QCMD-003](research/QVM_USERCMD.md).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 468 |
**F-164 — Game selector7 bridge:** qagame case65 calls155718, which requests trap36(index, entity[+520]+472), stores game time at client+4044 and gates helper154089 on entity bit8/global34084868. Native copy results are mapped into synthetic QVM word memory; flag meanings/full runtime bridge remain open. [QCMD-002](research/QVM_USERCMD.md).
|
| 469 |
|
| 470 |
**F-165 — Game-side command time prefix:** helper154089 preserves raw time, sequentially clamps command time to signed game-time bounds -1000/+200, computes/caps elapsed independently and optionally adjusts timestamp in eight-unit steps afterward. Early returns retain preceding mutations; signed-boundary fixtures do not establish legal gameplay. [QCMD-003](research/QVM_USERCMD.md).
|
| 471 |
+
|
| 472 |
+
**F-166 — QVM think routing/suppression:** post-time branches record special helpers or normal processing; independent gates restore saved angles versus capturing current angles, and clear movement/buttons. Bit0-only angle lock differs from the inactivity helper's nonzero special-time gate. Global/field semantics remain provisional. [THINK-001](research/QVM_THINK_GATES.md).
|
| 473 |
+
|
| 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).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -558,3 +558,5 @@ Research progress: [usercmd caller/hash/bundle evidence](research/USERCMD_CALLER
|
|
| 558 |
Research progress: [server usercmd acceptance](research/USERCMD_ACCEPTANCE.md) completes bounded RE-401–403. RE-400/404 retain producers/time clamping/QVM effects/full packet/runtime/platform work; game/network/rendering milestones remain open.
|
| 559 |
|
| 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.
|
|
|
|
|
|
|
|
|
| 558 |
Research progress: [server usercmd acceptance](research/USERCMD_ACCEPTANCE.md) completes bounded RE-401–403. RE-400/404 retain producers/time clamping/QVM effects/full packet/runtime/platform work; game/network/rendering milestones remain open.
|
| 559 |
|
| 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.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -277,3 +277,9 @@ Validation: all preceding composition reports regenerated byte-identically; the
|
|
| 277 |
Completed bounded RE-405–407 with `analyze_qvm_usercmd.py`: two verified native retrieval graphs, two file-backed trap36 cases, shipped qagame selector/table/case/helper evidence, 112 native guard/copy probes, 108 native-to-QVM wrapper compositions and 147 game-side time-prefix probes. QCMD-001–003/F-163–165 confirm explicit retrieval stride0x2df40, destination conversion before signed index errors, full 24-byte valid copies and zero EAX at the dispatch return jump; connect selector7/case65/helper155718/trap36 to client+472; recover metadata time and wrapper flag/global gates; and recover helper154089 state/raw-time/observed-time/clamp/elapsed/mode/alignment sequence. Native copy bytes map into synthetic QVM word memory under supplied pointer/address-space translation. Calls and Com_Error boundaries stop; no original executable/native callee/full QVM executes. The time prefix ends before remaining simulation, and signed-boundary arithmetic is modeled rather than runtime/legality evidence. Eight independent tests verify native signed guards/conversion ordering/copies/canaries/retention, switch slot/file identities and stride, selector/argument mapping, wrapper words/metadata/gates, signed time clamps/raw-time/elapsed/cap/rounding, paired outcomes, provenance and restricted optional slice-stop behavior. All 423 tests pass; storage/links/whitespace checks pass. RE-404 remains open; RE-408 tracks flag/global/state producers, allocation/translation, command generation and elapsed consumers, remaining movement/simulation and VM mutation effects, other trap36 callers, full packet-to-game/runtime/all-platform behavior and Rust/Bevy/Solari goals.
|
| 278 |
|
| 279 |
Validation: all preceding composition reports regenerated byte-identically; final QVM usercmd report reproduced twice byte-identically, including explicit negative-time rounding fixtures. Deferred-auth and engine-control reports also remain byte-identical after the optional slice-stop extension. Final suite: 423 passing tests. Storage policy/filter setup, documentation links and whitespace checks pass.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 277 |
Completed bounded RE-405–407 with `analyze_qvm_usercmd.py`: two verified native retrieval graphs, two file-backed trap36 cases, shipped qagame selector/table/case/helper evidence, 112 native guard/copy probes, 108 native-to-QVM wrapper compositions and 147 game-side time-prefix probes. QCMD-001–003/F-163–165 confirm explicit retrieval stride0x2df40, destination conversion before signed index errors, full 24-byte valid copies and zero EAX at the dispatch return jump; connect selector7/case65/helper155718/trap36 to client+472; recover metadata time and wrapper flag/global gates; and recover helper154089 state/raw-time/observed-time/clamp/elapsed/mode/alignment sequence. Native copy bytes map into synthetic QVM word memory under supplied pointer/address-space translation. Calls and Com_Error boundaries stop; no original executable/native callee/full QVM executes. The time prefix ends before remaining simulation, and signed-boundary arithmetic is modeled rather than runtime/legality evidence. Eight independent tests verify native signed guards/conversion ordering/copies/canaries/retention, switch slot/file identities and stride, selector/argument mapping, wrapper words/metadata/gates, signed time clamps/raw-time/elapsed/cap/rounding, paired outcomes, provenance and restricted optional slice-stop behavior. All 423 tests pass; storage/links/whitespace checks pass. RE-404 remains open; RE-408 tracks flag/global/state producers, allocation/translation, command generation and elapsed consumers, remaining movement/simulation and VM mutation effects, other trap36 callers, full packet-to-game/runtime/all-platform behavior and Rust/Bevy/Solari goals.
|
| 278 |
|
| 279 |
Validation: all preceding composition reports regenerated byte-identically; final QVM usercmd report reproduced twice byte-identically, including explicit negative-time rounding fixtures. Deferred-auth and engine-control reports also remain byte-identical after the optional slice-stop extension. Final suite: 423 passing tests. Storage policy/filter setup, documentation links and whitespace checks pass.
|
| 280 |
+
|
| 281 |
+
## 2026-10-11 — Game-QVM think routes, inactivity and mode-word selection
|
| 282 |
+
|
| 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.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -492,3 +492,8 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 492 |
- [x] RE-406 Connect shipped qagame selector7 to helper155718/trap36, entity/client command placement, metadata time and think gates using supplied native/QVM address mapping. [QCMD-002](research/QVM_USERCMD.md).
|
| 493 |
- [x] RE-407 Recover bounded helper154089 state guard, raw/observed timestamps, sequential signed clamps, elapsed early-return/cap and eight-unit timestamp adjustment with independent arithmetic probes. [QCMD-003](research/QVM_USERCMD.md).
|
| 494 |
- [ ] RE-408 Confirm wrapper/prefix flag/global/state meanings and producers; trace input generation, elapsed/timestamp consumers and remaining movement/simulation; audit trap36 callers/VM mutation/address translation, compose full packet-to-game processing and validate real traffic/all-platform behavior. Continue entity/player/snapshot and Rust/Bevy/Solari implementation.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 492 |
- [x] RE-406 Connect shipped qagame selector7 to helper155718/trap36, entity/client command placement, metadata time and think gates using supplied native/QVM address mapping. [QCMD-002](research/QVM_USERCMD.md).
|
| 493 |
- [x] RE-407 Recover bounded helper154089 state guard, raw/observed timestamps, sequential signed clamps, elapsed early-return/cap and eight-unit timestamp adjustment with independent arithmetic probes. [QCMD-003](research/QVM_USERCMD.md).
|
| 494 |
- [ ] RE-408 Confirm wrapper/prefix flag/global/state meanings and producers; trace input generation, elapsed/timestamp consumers and remaining movement/simulation; audit trap36 callers/VM mutation/address translation, compose full packet-to-game processing and validate real traffic/all-platform behavior. Continue entity/player/snapshot and Rust/Bevy/Solari implementation.
|
| 495 |
+
|
| 496 |
+
- [x] RE-409 Recover bounded post-time QVM special routes and normal angle-save/restore/movement/button suppression with exact recorded calls and byte canaries. [THINK-001](research/QVM_THINK_GATES.md).
|
| 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.
|
docs/research/QVM_THINK_GATES.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Game-QVM think routes, inactivity and mode selection
|
| 2 |
+
|
| 3 |
+
RE-409–411 / F-166–168. [qvm-think-gates.json](qvm-think-gates.json) retains shipped qagame instruction slices, helper150382 and file-backed inactivity literals. Reproduce with `python3 scripts/analyze_qvm_think_gates.py`; verify with `python3 scripts/test_qvm_think_gates.py`.
|
| 4 |
+
|
| 5 |
+
This continues [the game-side time prefix](QVM_USERCMD.md). All results use bounded synthetic QVM memory. No complete QVM, original executable or native callee runs. External helpers/traps are recorded with default return zero and no side effects. The mode-selection slice receives the evaluated inactivity helper's result explicitly. Remaining movement inputs, simulation, syscall action effects and runtime conformance remain open.
|
| 6 |
+
|
| 7 |
+
## THINK-001 — Special routes and command suppression (RE-409)
|
| 8 |
+
|
| 9 |
+
After timestamp handling, helper154089 routes as follows:
|
| 10 |
+
|
| 11 |
+
- Nonzero global34999596 calls151133(client) and exits. An intermission role is a candidate, not a recovered global producer contract.
|
| 12 |
+
- Otherwise client[+3096] ==3 or client[+4324] !=0 enters another special route. Client[+3108] ==3 exits without its helper; other values call149671(entity, client+472), then exit. Spectator/team semantics remain provisional.
|
| 13 |
+
- Remaining paths reach normal command processing.
|
| 14 |
+
|
| 15 |
+
On the normal route, angles at client+476/+480/+484 are restored from saved words +4060/+4064/+4068 when `(global35000452 &1) !=0`, or when global34090788 ==10 and `(client[+104] &16) !=0`. This path clears three movement bytes at +493/+494/+495 and buttons word +488. Otherwise it copies the current angles into the saved words.
|
| 16 |
+
|
| 17 |
+
After either angle path, any nonzero global35000472 independently clears the same movement bytes and buttons. This later gate does not restore angles. Global35000452 bit1 alone (supplied word2) does not trigger the bit0 angle lock, although the inactivity helper below treats any nonzero word as its separate special-time gate.
|
| 18 |
+
|
| 19 |
+
Forty fixtures cover special-route combinations and independent angle/button/movement gate combinations. Checks verify exact calls/arguments, early-return retention, both angle-copy directions, byte stores, button clearing and neighboring weapon/record byte canaries. Semantic names for the globals, game mode10 and flag bits remain open.
|
| 20 |
+
|
| 21 |
+
## THINK-002 — Inactivity helper150382 (RE-410)
|
| 22 |
+
|
| 23 |
+
The complete linear helper partition is retained. Bounded entry evaluation starts after ENTER and stops on the native QVM LEAVE boundary. Source/record/global meanings are inferred from operations and file-backed messages; no callback or trap action executes.
|
| 24 |
+
|
| 25 |
+
| Observed condition, in order | Evaluated result and mutation |
|
| 26 |
+
| --- | --- |
|
| 27 |
+
| Entity flag bit8 selected by client[+140] and stride880 | Return1, retain timer/warning |
|
| 28 |
+
| Global34085460 ==0 | Deadline client+3140 = signed32(game time+60000); warning client+4144 =0; return1 |
|
| 29 |
+
| Global35000452 !=0 | Extend deadline to at least signed32(global35000456 + global34085460*1000); retain warning; return1 |
|
| 30 |
+
| Any signed movement byte nonzero, or buttons+488 bit0 set | Extend deadline to at least signed32(game time + global34085460*1000); clear warning; return1 |
|
| 31 |
+
| Client[+208] <=0 | Add supplied elapsed to deadline modulo32; return1 |
|
| 32 |
+
| Client[+500] !=0 | Return1, retain timer/warning |
|
| 33 |
+
| Signed game time > deadline | Record expiry actions; return0 |
|
| 34 |
+
| Signed game time > signed32(deadline-10000), warning zero | Set warning1, record warning message; return1 |
|
| 35 |
+
| Remaining cases | Return1, retain timer/warning |
|
| 36 |
+
|
| 37 |
+
Movement loads sign-extend bytes, so both positive and negative nonzero values count as activity. The button predicate is **bit0 only**: supplied bit1 does not refresh the deadline. Positive timeout values act as seconds in the observed multiply-by-1000 expression; registration/range/producer policy is not established here.
|
| 38 |
+
|
| 39 |
+
The expiry/warning predicates are strict: equality with deadline does not expire, and equality with deadline-10000 does not warn. Refresh clears the warning. This helper does not count arbitrary changes in angles, weapon or other button bits as activity in the retained graph.
|
| 40 |
+
|
| 41 |
+
Global34063260 ==1 selects an expiry request to helper183102(entity, "s",0), followed by target-18 with the forced-spectator message. Other sampled modes record target-17 with the inactivity-drop reason. Warning target-18 uses the policy-specific message. Encoded negative targets correspond to traps17/16 respectively; native syscall signatures, action effects and helper183102's complete semantics are still open in this composition.
|
| 42 |
+
|
| 43 |
+
Literal evidence at VM addresses63149/63190/63237/63263 includes the inactivity-drop, forced-spectator and ten-second warning messages; address63316 contains "s". Strings support the inactivity interpretation without proving that a recorded request performs a drop or team change.
|
| 44 |
+
|
| 45 |
+
Ninety-four fixtures cover bit8 exemption, disabled timeout, special-time gate, each movement direction including high bytes, attack/other-button distinction, strict deadline/warning boundaries, existing warnings, two policy values, health-like/exemption words and signed overflow boundaries. An independent sequential oracle verifies deadline/warning/return and every recorded action argument. Signed-boundary results are modeled arithmetic, not legal game-time or runtime evidence.
|
| 46 |
+
|
| 47 |
+
## THINK-003 — Helper result and mode-word precedence (RE-411)
|
| 48 |
+
|
| 49 |
+
The normal think path calls150382(client, elapsed), stores its return in local352 and exits if it is zero. For a nonzero result, it sets client+4 in this order:
|
| 50 |
+
|
| 51 |
+
1. Client+4040 nonzero selects1.
|
| 52 |
+
2. Otherwise client+208 <=0 selects3.
|
| 53 |
+
3. Otherwise select0.
|
| 54 |
+
|
| 55 |
+
Client+4 is a movement-type candidate; these numeric stores do not establish the physics associated with each type. In particular, the +4040 meaning remains a producer/consumer task. Its branch precedes the health-like test.
|
| 56 |
+
|
| 57 |
+
Twelve compositions use the evaluated inactivity helper result with matching supplied health/command state, then exercise each +4040/health combination in the caller. A false helper return retains the initial +4 word; a true result reaches mode selection and follows the recovered precedence. Calls within the helper still have omitted effects, so the composition is conditional on that supplied-state model.
|
| 58 |
+
|
| 59 |
+
The shared slice evaluator now accepts explicit per-instruction call-result overrides, preserving its original zero-placeholder default. A focused check verifies the override changes only the supplied operand result and keeps the recorded call request unchanged. It does not execute a callee or create implicit side effects.
|
| 60 |
+
|
| 61 |
+
## Validation and remaining work
|
| 62 |
+
|
| 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.
|
docs/research/QVM_USERCMD.md
CHANGED
|
@@ -51,3 +51,5 @@ The evaluator adds an optional explicit stop-target boundary, allowing state gua
|
|
| 51 |
Eight tests verify native signed guards/pointer ordering/copy retention, file-backed trap slot and explicit stride, selector/table/argument mapping, wrapper copy/metadata/gates, game-side signed clamps/elapsed/mode/alignment, paired results, source identities and optional stop behavior.
|
| 52 |
|
| 53 |
RE-404 remains open for complete callback/producer/allocation/runtime work. RE-408 must confirm the global/record flag meanings, recover command generation and all timestamp/elapsed consumers, continue helper154089 into movement/simulation, characterize selector7 trap/VM mutation effects and address translation, audit other trap36 callers, compose packets through native acceptance/retrieval/game-side processing and validate real traffic/all-platform behavior. Full entity/player/snapshot codecs and Rust/Bevy/Solari implementation remain open.
|
|
|
|
|
|
|
|
|
| 51 |
Eight tests verify native signed guards/pointer ordering/copy retention, file-backed trap slot and explicit stride, selector/table/argument mapping, wrapper copy/metadata/gates, game-side signed clamps/elapsed/mode/alignment, paired results, source identities and optional stop behavior.
|
| 52 |
|
| 53 |
RE-404 remains open for complete callback/producer/allocation/runtime work. RE-408 must confirm the global/record flag meanings, recover command generation and all timestamp/elapsed consumers, continue helper154089 into movement/simulation, characterize selector7 trap/VM mutation effects and address translation, audit other trap36 callers, compose packets through native acceptance/retrieval/game-side processing and validate real traffic/all-platform behavior. Full entity/player/snapshot codecs and Rust/Bevy/Solari implementation remain open.
|
| 54 |
+
|
| 55 |
+
Follow-up: [think gates](QVM_THINK_GATES.md) continues the timestamp prefix through special routing, command suppression, inactivity decisions and mode-word selection. Gravity/speed, complete movement inputs, action effects and simulation/runtime validation remain open.
|
docs/research/README.md
CHANGED
|
@@ -159,3 +159,5 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 159 |
[Server usercmd acceptance and VM boundary](USERCMD_ACCEPTANCE.md) adds RE-401–403. Reproduce with `python3 scripts/analyze_usercmd_acceptance.py`; check with `python3 scripts/test_usercmd_acceptance.py`. Supplied state/decoded records and stopped external/VM boundaries do not validate live packets or game simulation.
|
| 160 |
|
| 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.
|
|
|
|
|
|
|
|
|
| 159 |
[Server usercmd acceptance and VM boundary](USERCMD_ACCEPTANCE.md) adds RE-401–403. Reproduce with `python3 scripts/analyze_usercmd_acceptance.py`; check with `python3 scripts/test_usercmd_acceptance.py`. Supplied state/decoded records and stopped external/VM boundaries do not validate live packets or game simulation.
|
| 160 |
|
| 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.
|
docs/research/qvm-think-gates.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_deferred_auth.py
CHANGED
|
@@ -15,7 +15,7 @@ def signed32(value):
|
|
| 15 |
|
| 16 |
|
| 17 |
def trace_slice(instructions, start, stop, memory, locals_map, limit=256, byte_memory=None, capture_stack=False,
|
| 18 |
-
halt_on_leave=False, stop_targets=()):
|
| 19 |
"""Evaluate only a selected straight/bounded slice against synthetic memory.
|
| 20 |
|
| 21 |
Record calls rather than entering callees. Reject unknown reads/opcodes and
|
|
@@ -94,7 +94,7 @@ def trace_slice(instructions, start, stop, memory, locals_map, limit=256, byte_m
|
|
| 94 |
elif op == 'CALL':
|
| 95 |
calls.append({'instruction': ins['index'], 'target': stack.pop(), 'args': dict(args)})
|
| 96 |
args = {}
|
| 97 |
-
stack.append(0) #
|
| 98 |
elif op == 'POP':
|
| 99 |
stack.pop()
|
| 100 |
elif op == 'JUMP':
|
|
|
|
| 15 |
|
| 16 |
|
| 17 |
def trace_slice(instructions, start, stop, memory, locals_map, limit=256, byte_memory=None, capture_stack=False,
|
| 18 |
+
halt_on_leave=False, stop_targets=(), call_results=None):
|
| 19 |
"""Evaluate only a selected straight/bounded slice against synthetic memory.
|
| 20 |
|
| 21 |
Record calls rather than entering callees. Reject unknown reads/opcodes and
|
|
|
|
| 94 |
elif op == 'CALL':
|
| 95 |
calls.append({'instruction': ins['index'], 'target': stack.pop(), 'args': dict(args)})
|
| 96 |
args = {}
|
| 97 |
+
stack.append(0 if call_results is None else call_results.get(ins['index'], 0)) # explicit supplied result or default placeholder
|
| 98 |
elif op == 'POP':
|
| 99 |
stack.pop()
|
| 100 |
elif op == 'JUMP':
|
scripts/analyze_qvm_think_gates.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Bounded QVM think routes, command suppression and inactivity decisions."""
|
| 3 |
+
import itertools
|
| 4 |
+
import json
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
from analyze_bsp_references import trace_fields
|
| 7 |
+
from analyze_deferred_auth import partition_function,signed32,trace_slice
|
| 8 |
+
from analyze_qvm import decode,write_json
|
| 9 |
+
from analyze_vm_extensions import verified
|
| 10 |
+
|
| 11 |
+
CLIENT=0x10000
|
| 12 |
+
ENTITY=0x20000
|
| 13 |
+
NOW=1000
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def route_probe(ins,intermission,team,other,mode,lock,game,flags,block):
|
| 17 |
+
m={34999596:intermission,CLIENT+3096:team,CLIENT+4324:other,CLIENT+3108:mode,35000452:lock,34090788:game,CLIENT+104:flags,35000472:block,CLIENT+488:0x1234}
|
| 18 |
+
for o,v in zip([476,480,484],[101,202,303]):m[CLIENT+o]=v
|
| 19 |
+
for o,v in zip([4060,4064,4068],[901,902,903]):m[CLIENT+o]=v
|
| 20 |
+
b={CLIENT+492:7,CLIENT+493:0x80,CLIENT+494:0xff,CLIENT+495:1,CLIENT+496:0x7b};t=trace_slice(ins,154210,155716,m,{52:CLIENT,444:ENTITY,324:CLIENT+472},stop_targets=[154389],byte_memory=b)
|
| 21 |
+
return {'intermission_word':intermission,'team_word':team,'other_word':other,'mode_word':mode,'lock_word':lock,'game_word':game,'flags_word':flags,'block_word':block,'continued':t['stop']==154389,'calls':t['calls'],'angles':[t['memory'][CLIENT+o] for o in [476,480,484]],'saved_angles':[t['memory'][CLIENT+o] for o in [4060,4064,4068]],'buttons_word':t['memory'][CLIENT+488],'movement_bytes':[t['byte_memory'][CLIENT+o] for o in [493,494,495]],'byte_canaries':[t['byte_memory'][CLIENT+492],t['byte_memory'][CLIENT+496]],**trace_fields(t,False)}
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def idle_probe(ins,bot=0,timeout=60,intermission=0,activity='none',deadline=10000,warning=0,mode=0,health=100,immune=0,now=NOW,elapsed=16):
|
| 25 |
+
movement={'none':[0,0,0],'forward':[1,0,0],'negative':[255,0,0],'side':[0,128,0],'up':[0,0,1],'attack':[0,0,0],'other_button':[0,0,0]}[activity];buttons=1 if activity=='attack' else 2 if activity=='other_button' else 0;m={CLIENT+140:3,34091792+880*3:bot,34085460:timeout,35000452:intermission,35000456:777,34992532:signed32(now),CLIENT+3140:signed32(deadline),CLIENT+4144:warning,CLIENT+488:buttons,CLIENT+208:health,CLIENT+500:immune,34063260:mode,34992496:CLIENT};b={CLIENT+493+i:v for i,v in enumerate(movement)};t=trace_slice(ins,150383,150690,m,{36:CLIENT,40:elapsed},byte_memory=b,capture_stack=True,halt_on_leave=True,limit=512)
|
| 26 |
+
p={'bot_flags_word':bot,'timeout_word':timeout,'intermission_word':intermission,'activity':activity,'movement_bytes':movement,'buttons_word':buttons,'deadline_word':deadline&0xffffffff,'warning_word':warning,'mode_word':mode,'health_word':health,'immune_word':immune,'now_word':now&0xffffffff,'elapsed_word':elapsed,'result_word':t['stack'][-1],'result_deadline_word':t['memory'][CLIENT+3140]&0xffffffff,'result_warning_word':t['memory'][CLIENT+4144],'calls':t['calls'],**trace_fields(t,False)}
|
| 27 |
+
return p,t['memory']
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def decision_probe(ins,active,freeze,health):
|
| 31 |
+
p,m=idle_probe(ins,activity='forward' if active else 'none',deadline=999,health=health);m[CLIENT+4040]=freeze;m[CLIENT+208]=health;m[CLIENT+4]=0x1234;t=trace_slice(ins,154389,155716,m,{52:CLIENT,328:16},stop_targets=[154441],call_results={154397:p['result_word']})
|
| 32 |
+
return {'helper_probe':p,'freeze_word':freeze,'health_word':health,'continued':t['stop']==154441,'movement_type_word':t['memory'][CLIENT+4],'calls':t['calls'],**trace_fields(t,False)}
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def main():
|
| 36 |
+
r=json.loads(Path('docs/research/qvm/qagame.json').read_text());data=verified(Path(r['source']['member']['output']).read_bytes(),r['sha256']);header,ins=decode(data);routes=[(i,t,o,m,0,0,0,0) for i,t,o,m in itertools.product([0,1],[0,3],[0,1],[0,3])]+[(0,0,0,0,l,g,f,b) for l,g,f,b in itertools.product([0,1,2],[0,10],[0,16],[0,1])];idles=[]
|
| 37 |
+
for bot,timeout,intermission,activity in itertools.product([0,8],[0,60],[0,1],['none','forward','negative','side','up','attack','other_button']):idles.append(idle_probe(ins,bot,timeout,intermission,activity)[0])
|
| 38 |
+
for deadline,warning,mode in itertools.product([999,1000,1001,10999,11000,11001],[0,1],[0,1]):idles.append(idle_probe(ins,deadline=deadline,warning=warning,mode=mode)[0])
|
| 39 |
+
for health,immune,deadline in itertools.product([-1,0,1],[0,1],[999,1000]):idles.append(idle_probe(ins,health=health,immune=immune,deadline=deadline)[0])
|
| 40 |
+
idles += [idle_probe(ins,now=0x7fffffff,deadline=0x80000000,activity='forward')[0],idle_probe(ins,now=0x80000000,deadline=0x7fffffff,health=0)[0]]
|
| 41 |
+
literals={str(a):data[header['data_offset']+a:].split(b'\0',1)[0].decode('ascii') for a in [63149,63190,63237,63263,63316]};out={'source':r['source'],'sha256':r['sha256'],'think_gate_instructions':ins[154210:154441],'inactivity_helper':partition_function(ins,150382,data,header),'literals':literals,'route_probes':[route_probe(ins,*v) for v in routes],'idle_probes':idles,'decision_probes':[decision_probe(ins,*v) for v in itertools.product([0,1],[0,1],[-1,0,1])],'limitations':'Synthetic bounded shipped-QVM instruction slices only; no full QVM/original process/native callee executes. External helper/trap calls recorded with default return0 and no side effects. Decision slice receives the evaluated inactivity helper result explicitly, while external action effects remain omitted. Global/state/field semantic names are candidates except literal-backed inactivity messages. No complete movement inputs/simulation/time producers/packet/runtime/all-platform conformance.'};write_json(Path('docs/research/qvm-think-gates.json'),out);print('Recovered bounded think routing command suppression inactivity and type gates')
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
if __name__=='__main__':main()
|
scripts/test_qvm_think_gates.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Independent routing, inactivity timer and movement-type gate oracles."""
|
| 3 |
+
import hashlib
|
| 4 |
+
import json
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
import unittest
|
| 7 |
+
from analyze_deferred_auth import trace_slice
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def s32(v):
|
| 11 |
+
v&=0xffffffff;return v if v<2**31 else v-2**32
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def idle_oracle(p):
|
| 15 |
+
deadline=s32(p['deadline_word']);warning=p['warning_word'];now=s32(p['now_word']);result=1;calls=[]
|
| 16 |
+
if p['bot_flags_word']&8:return result,deadline,warning,calls
|
| 17 |
+
if p['timeout_word']==0:return result,s32(now+60000),0,calls
|
| 18 |
+
if p['intermission_word']!=0:return result,max(deadline,s32(777+p['timeout_word']*1000)),warning,calls
|
| 19 |
+
if any(p['movement_bytes']) or p['buttons_word']&1:return result,max(deadline,s32(now+p['timeout_word']*1000)),0,calls
|
| 20 |
+
if p['health_word']<=0:return result,s32(deadline+p['elapsed_word']),warning,calls
|
| 21 |
+
if p['immune_word']!=0:return result,deadline,warning,calls
|
| 22 |
+
if now>deadline:
|
| 23 |
+
result=0
|
| 24 |
+
if p['mode_word']==1:calls=[(183102,{'8':34091368+3*880,'12':63316,'16':0}),(-18,{'8':0,'12':63263})]
|
| 25 |
+
else:calls=[(-17,{'8':0,'12':63237})]
|
| 26 |
+
elif now>s32(deadline-10000) and warning==0:
|
| 27 |
+
warning=1;calls=[(-18,{'8':0,'12':63190 if p['mode_word']==1 else 63149})]
|
| 28 |
+
return result,deadline,warning,calls
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class QvmThinkGateTests(unittest.TestCase):
|
| 32 |
+
@classmethod
|
| 33 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-think-gates.json').read_text())
|
| 34 |
+
|
| 35 |
+
def test_routes_return_before_normal_command_mutations(self):
|
| 36 |
+
self.assertEqual(len(self.r['route_probes']),40)
|
| 37 |
+
for p in self.r['route_probes']:
|
| 38 |
+
if p['intermission_word']:expected=[(151133,{'8':0x10000})];continued=False
|
| 39 |
+
elif p['team_word']==3 or p['other_word']!=0:expected=[] if p['mode_word']==3 else [(149671,{'8':0x20000,'12':0x10000+472})];continued=False
|
| 40 |
+
else:expected=[];continued=True
|
| 41 |
+
self.assertEqual(p['continued'],continued);self.assertEqual([(c['target'],c['args']) for c in p['calls']],expected)
|
| 42 |
+
if not continued:self.assertEqual(p['angles'],[101,202,303]);self.assertEqual(p['saved_angles'],[901,902,903]);self.assertEqual(p['movement_bytes'],[128,255,1]);self.assertEqual(p['buttons_word'],0x1234)
|
| 43 |
+
|
| 44 |
+
def test_normal_angle_restore_capture_and_movement_buttons_suppression(self):
|
| 45 |
+
for p in self.r['route_probes']:
|
| 46 |
+
if not p['continued']:continue
|
| 47 |
+
locked=bool(p['lock_word']&1) or (p['game_word']==10 and p['flags_word']&16!=0);blocked=locked or p['block_word']!=0;self.assertEqual(p['angles'],[901,902,903] if locked else [101,202,303]);self.assertEqual(p['saved_angles'],[901,902,903] if locked else [101,202,303]);self.assertEqual(p['movement_bytes'],[0,0,0] if blocked else [128,255,1]);self.assertEqual(p['buttons_word'],0 if blocked else 0x1234);self.assertEqual(p['byte_canaries'],[7,0x7b])
|
| 48 |
+
|
| 49 |
+
def test_inactivity_all_deadline_warning_return_and_call_outputs(self):
|
| 50 |
+
self.assertEqual(len(self.r['idle_probes']),94)
|
| 51 |
+
for p in self.r['idle_probes']:
|
| 52 |
+
result,deadline,warning,calls=idle_oracle(p);self.assertEqual(p['result_word'],result);self.assertEqual(p['result_deadline_word'],deadline&0xffffffff);self.assertEqual(p['result_warning_word'],warning);self.assertEqual([(c['target'],c['args']) for c in p['calls']],calls)
|
| 53 |
+
|
| 54 |
+
def test_inactivity_strict_deadline_and_warning_thresholds(self):
|
| 55 |
+
rows=[p for p in self.r['idle_probes'] if p['activity']=='none' and p['bot_flags_word']==0 and p['intermission_word']==0 and p['timeout_word']==60 and p['health_word']==100 and p['immune_word']==0 and p['warning_word']==0 and p['mode_word']==0]
|
| 56 |
+
for deadline,result,warning in [(999,0,0),(1000,1,1),(10999,1,1),(11000,1,0),(11001,1,0)]:
|
| 57 |
+
p=next(p for p in rows if p['deadline_word']==deadline);self.assertEqual((p['result_word'],p['result_warning_word']),(result,warning))
|
| 58 |
+
|
| 59 |
+
def test_evaluated_inactivity_result_controls_movement_type_precedence(self):
|
| 60 |
+
self.assertEqual(len(self.r['decision_probes']),12)
|
| 61 |
+
for p in self.r['decision_probes']:
|
| 62 |
+
ret=idle_oracle(p['helper_probe'])[0];self.assertEqual(p['continued'],bool(ret));expected=0x1234 if not ret else 1 if p['freeze_word'] else 3 if p['health_word']<=0 else 0;self.assertEqual(p['movement_type_word'],expected);self.assertEqual(p['calls'],[{'instruction':154397,'target':150382,'args':{'8':0x10000,'12':16}}])
|
| 63 |
+
|
| 64 |
+
def test_literal_file_provenance_and_source_identity(self):
|
| 65 |
+
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']);data_offset=r['header']['data_offset'] if 'header' in r else int.from_bytes(raw[16:20],'little')
|
| 66 |
+
for address,literal in self.r['literals'].items():self.assertEqual(raw[data_offset+int(address):].split(b'\0',1)[0].decode('ascii'),literal)
|
| 67 |
+
|
| 68 |
+
def test_signed_movements_attack_bit_and_other_button_distinction(self):
|
| 69 |
+
rows=[p for p in self.r['idle_probes'] if p['bot_flags_word']==0 and p['timeout_word']==60 and p['intermission_word']==0 and p['deadline_word']==10000 and p['warning_word']==0 and p['mode_word']==0 and p['health_word']==100]
|
| 70 |
+
for activity in ['forward','negative','side','up','attack']:
|
| 71 |
+
p=next(p for p in rows if p['activity']==activity);self.assertEqual(p['result_deadline_word'],61000);self.assertEqual(p['result_warning_word'],0)
|
| 72 |
+
p=next(p for p in rows if p['activity']=='other_button');self.assertEqual(p['result_deadline_word'],10000);self.assertEqual(p['result_warning_word'],1)
|
| 73 |
+
|
| 74 |
+
def test_explicit_call_result_override_and_default_placeholder(self):
|
| 75 |
+
ins=[{'index':0,'opcode':'CONST','operand':123},{'index':1,'opcode':'CALL','operand':None},{'index':2,'opcode':'POP','operand':None}]
|
| 76 |
+
a=trace_slice(ins,0,2,{}, {},capture_stack=True);b=trace_slice(ins,0,2,{}, {},capture_stack=True,call_results={1:7});self.assertEqual(a['stack'],[0]);self.assertEqual(b['stack'],[7]);self.assertEqual(a['calls'],b['calls'])
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
if __name__=='__main__':unittest.main()
|