qvm: interaction requests
Browse files- docs/ASSET_PIPELINE_TODO.md +3 -0
- docs/FINDINGS.md +3 -0
- docs/PROVISIONAL_TODO.md +3 -0
- docs/RESEARCH_LEDGER.md +5 -0
- docs/REVERSE_ENGINEERING_TODO.md +3 -0
- docs/research/QVM_INTERACTION_REQUEST.md +11 -0
- docs/research/README.md +3 -0
- docs/research/qvm-interaction-request.json +0 -0
- scripts/analyze_qvm_interaction_request.py +38 -0
- scripts/qvm_research_support.py +1 -1
- scripts/test_qvm_interaction_request.py +36 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -382,3 +382,6 @@ Research progress: RE-562 [report](research/QVM_TORSO_SELECTOR.md); remaining na
|
|
| 382 |
|
| 383 |
|
| 384 |
Research progress: RE-563 [report](research/QVM_RELOAD_REQUEST.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 382 |
|
| 383 |
|
| 384 |
Research progress: RE-563 [report](research/QVM_RELOAD_REQUEST.md); remaining native/content/runtime/platform scope stays open.
|
| 385 |
+
|
| 386 |
+
|
| 387 |
+
Research progress: RE-564 [report](research/QVM_INTERACTION_REQUEST.md); remaining native/content/runtime/platform scope stays open.
|
docs/FINDINGS.md
CHANGED
|
@@ -740,3 +740,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
|
|
| 740 |
|
| 741 |
|
| 742 |
**RE-563 — Reload request gates and timer animation event effects:** 49652 gates reload on button32, packed magazine/reserve bytes and state flags, sets state bit8 and a configured timer, requests torso56/57 and emits event3 without transferring ammunition. [Evidence](research/QVM_RELOAD_REQUEST.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 740 |
|
| 741 |
|
| 742 |
**RE-563 — Reload request gates and timer animation event effects:** 49652 gates reload on button32, packed magazine/reserve bytes and state flags, sets state bit8 and a configured timer, requests torso56/57 and emits event3 without transferring ammunition. [Evidence](research/QVM_RELOAD_REQUEST.md).
|
| 743 |
+
|
| 744 |
+
|
| 745 |
+
**RE-564 — Interaction trace and direct action consumers:** 49918 chooses a contents-bit33554432 trace action or direct state128/256 action, applies ordered timers/events/animations, and uses a health-gated first16-slot item19 search to select750 versus1500. [Evidence](research/QVM_INTERACTION_REQUEST.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -694,3 +694,6 @@ Research progress: RE-562 [report](research/QVM_TORSO_SELECTOR.md); remaining na
|
|
| 694 |
|
| 695 |
|
| 696 |
Research progress: RE-563 [report](research/QVM_RELOAD_REQUEST.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 694 |
|
| 695 |
|
| 696 |
Research progress: RE-563 [report](research/QVM_RELOAD_REQUEST.md); remaining native/content/runtime/platform scope stays open.
|
| 697 |
+
|
| 698 |
+
|
| 699 |
+
Research progress: RE-564 [report](research/QVM_INTERACTION_REQUEST.md); remaining native/content/runtime/platform scope stays open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -516,3 +516,8 @@ RE-549–558 each has its own code/tests/report/documentation commit. All759 tes
|
|
| 516 |
## 2026-10-19 — RE-563 Reload request gates and timer animation event effects (separate task commit)
|
| 517 |
|
| 518 |
49652 gates reload on button32, packed magazine/reserve bytes and state flags, sets state bit8 and a configured timer, requests torso56/57 and emits event3 without transferring ammunition. 108 probes independently check special IDs14/23, capacity equality, reserve, weapon states, action argument, timer overrides, timed animation and queue writes. Full suite: 775 tests pass. Report regenerates byte-identically (501354 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 516 |
## 2026-10-19 — RE-563 Reload request gates and timer animation event effects (separate task commit)
|
| 517 |
|
| 518 |
49652 gates reload on button32, packed magazine/reserve bytes and state flags, sets state bit8 and a configured timer, requests torso56/57 and emits event3 without transferring ammunition. 108 probes independently check special IDs14/23, capacity equality, reserve, weapon states, action argument, timer overrides, timed animation and queue writes. Full suite: 775 tests pass. Report regenerates byte-identically (501354 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
| 519 |
+
|
| 520 |
+
|
| 521 |
+
## 2026-10-20 — RE-564 Interaction trace and direct action consumers (separate task commit)
|
| 522 |
+
|
| 523 |
+
49918 chooses a contents-bit33554432 trace action or direct state128/256 action, applies ordered timers/events/animations, and uses a health-gated first16-slot item19 search to select750 versus1500. 47 fixtures independently check gate priority, signed height division, trace geometry, first matching inventory slot including excluded slot16, timer/state/animation effects and event order. Full suite: 779 tests pass. Report regenerates byte-identically (345178 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -734,3 +734,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 734 |
|
| 735 |
|
| 736 |
- [x] RE-563 Reload request gates and timer animation event effects ([report](research/QVM_RELOAD_REQUEST.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 734 |
|
| 735 |
|
| 736 |
- [x] RE-563 Reload request gates and timer animation event effects ([report](research/QVM_RELOAD_REQUEST.md)).
|
| 737 |
+
|
| 738 |
+
|
| 739 |
+
- [x] RE-564 Interaction trace and direct action consumers ([report](research/QVM_INTERACTION_REQUEST.md)).
|
docs/research/QVM_INTERACTION_REQUEST.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Interaction trace and direct action consumers
|
| 2 |
+
|
| 3 |
+
RE-564. Reproduce with `python3 scripts/analyze_qvm_interaction_request.py`; check with `python3 scripts/test_qvm_interaction_request.py`. The [machine report](qvm-interaction-request.json) retains source identity and bounded fixtures.
|
| 4 |
+
|
| 5 |
+
Complete49918 runs to50248. Nonzero PS148, state bits1/512/1024, PS12 bit8, positive PS44 or absent button64 return. The later PS148==3 branch is unreachable under this initial guard in the bounded body. State128/256 selects direct action: PS44=1000, set512, timed torso46, event4, then clear state8. Otherwise an actual trace request uses start=origin with Z+trunc(PS164/2), end=start+64×forward basis, frame bounds184..204, entity7 and mask100663297. Its56-byte reply is supplied; only contents at+48 is consumed.
|
| 6 |
+
|
| 7 |
+
A hit with contents33554432 sets state1, queries32155(PS,19), assigns750 if true else1500, emits12 then requests timed torso46. Actual32155 rejects nonpositive health, then actual32117 scans low bytes of the first16 inventory words and returns the first matching index or−1. Slot16 is excluded. No item is consumed. The direct branch reverses event/animation request order compared with the trace branch. Animation duration321 is supplied, not a recovered live record.
|
| 8 |
+
|
| 9 |
+
The bounded call driver now handles numeric LEAVE results whose trace has no stop field; the interaction fixtures exercise this return path and the full prior regression suite remains required. Remaining: real native trace geometry, entity interaction consequences, legal state writers, animation assets and full main/weapon suffix integration.
|
| 10 |
+
|
| 11 |
+
No original executable/full QVM/native collision/physics/rendering executes. Native responses and legal input domains are supplied or unverified where stated; full runtime/macOS/Linux Rust/Bevy/Solari gameplay remains open.
|
docs/research/README.md
CHANGED
|
@@ -295,3 +295,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 295 |
|
| 296 |
|
| 297 |
[RE-563: Reload request gates and timer animation event effects](QVM_RELOAD_REQUEST.md). Reproduce with `python3 scripts/analyze_qvm_reload_request.py`; check with `python3 scripts/test_qvm_reload_request.py`.
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
|
| 296 |
|
| 297 |
[RE-563: Reload request gates and timer animation event effects](QVM_RELOAD_REQUEST.md). Reproduce with `python3 scripts/analyze_qvm_reload_request.py`; check with `python3 scripts/test_qvm_reload_request.py`.
|
| 298 |
+
|
| 299 |
+
|
| 300 |
+
[RE-564: Interaction trace and direct action consumers](QVM_INTERACTION_REQUEST.md). Reproduce with `python3 scripts/analyze_qvm_interaction_request.py`; check with `python3 scripts/test_qvm_interaction_request.py`.
|
docs/research/qvm-interaction-request.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_interaction_request.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""49918 interaction trace/direct branch and actual first16-slot item lookup."""
|
| 3 |
+
import itertools
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from qvm_research_support import source,execute
|
| 6 |
+
from qvm_suffix_support import seed,state,handlers
|
| 7 |
+
from analyze_qvm_acceleration import PS,FRAME,word
|
| 8 |
+
from analyze_qvm_slide_prefix import vec
|
| 9 |
+
from analyze_qvm import write_json
|
| 10 |
+
LOCAL=0x6e000000
|
| 11 |
+
LOOKUP=LOCAL+0x1000
|
| 12 |
+
CHECK=LOCAL+0x2000
|
| 13 |
+
|
| 14 |
+
def inventory_check(ins,m,args,cmd):
|
| 15 |
+
m=dict(m);m[CHECK+28]=args[8];m[CHECK+32]=args[12]
|
| 16 |
+
def lookup(i,m,a,c):
|
| 17 |
+
m[LOOKUP+20]=a[8];m[LOOKUP+24]=a[12];m,c,r=execute(i,32118,32153,m,c,LOOKUP);return m,c,r['return'],r
|
| 18 |
+
m,c,r=execute(ins,32156,32187,m,cmd,CHECK,{32117:lookup});return m,c,r['return'],r
|
| 19 |
+
|
| 20 |
+
def interaction(ins,m,contents=33554432,cmd=(0,0,0)):
|
| 21 |
+
initial=state(m);origin=vec(m,PS+20);basis=vec(m,35023892);height=m[PS+164];queries=[]
|
| 22 |
+
def trace(i,m,a,c):
|
| 23 |
+
r={'start':vec(m,a[12]),'end':vec(m,a[24]),'bounds':vec(m,a[16])+vec(m,a[20]),'entity':a[28],'mask':a[32],'supplied_contents':contents};queries.append(r)
|
| 24 |
+
for offset in range(0,56,4):m[a[8]+offset]=0
|
| 25 |
+
m[a[8]+48]=contents;return m,c,0,r
|
| 26 |
+
hs=handlers();hs.update({-25:trace,32155:inventory_check});m,c,r=execute(ins,49919,50248,m,cmd,LOCAL,hs)
|
| 27 |
+
return m,{'initial':initial,'buttons':m[FRAME+20],'kind':m[PS+4],'height':height,'origin':origin,'basis':basis,'contents':contents,'queries':queries,'execution':r,'final':state(m)}
|
| 28 |
+
|
| 29 |
+
def main():
|
| 30 |
+
q,raw,h,ins=source();rows=[]
|
| 31 |
+
for contents,health,slot,height in itertools.product([0,33554432],[0,100],[-1,0,15,16],[37,-37]):
|
| 32 |
+
m=seed(raw,h);m.update({FRAME+20:64,PS+44:0,PS+208:health,PS+164:height})
|
| 33 |
+
if slot>=0:m[PS+376+4*slot]=0xaa0013
|
| 34 |
+
rows.append(interaction(ins,m,contents)[1])
|
| 35 |
+
for changes in [{PS+148:1},{PS+148:3,PS+220:32},{PS+220:1},{PS+220:512},{PS+220:1024},{PS+12:8},{PS+44:1},{FRAME+20:0},{PS+220:128},{PS+220:256},{PS+220:128|8},{PS+220:256|8},{PS+4:3},{PS+80:100},{PS+376:19,PS+380:19}]:
|
| 36 |
+
m=seed(raw,h);m.update({FRAME+20:64,PS+44:0,PS+164:37});m.update(changes);p=interaction(ins,m)[1];p['supplied_changes']={str(k):v for k,v in changes.items()};rows.append(p)
|
| 37 |
+
write_json(Path('docs/research/qvm-interaction-request.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'limits':'Complete finite49918 plus actual32155/32117 and recovered animation/event children. Trace56 words supplied with contents only; native geometry/interaction legality and external item effects unverified.'})
|
| 38 |
+
if __name__=='__main__':main()
|
scripts/qvm_research_support.py
CHANGED
|
@@ -27,7 +27,7 @@ def execute(ins,start,stop,m,cmd,base,handlers=None,result_offsets=None,boundari
|
|
| 27 |
from analyze_qvm_acceleration import FRAME,word,number
|
| 28 |
handlers=handlers or {};result_offsets=result_offsets or {};points=[x['index']+2 for x in ins[start:stop] if x['opcode']=='CALL']+list(boundaries);pc=start;trace=[];calls=[];children=[];writes=[];ret=None
|
| 29 |
for _ in range(256):
|
| 30 |
-
t=trace_slice(ins,start,stop,m,{},resume_at=pc,stop_targets=[p for p in points if p!=pc],byte_memory={FRAME+25+i:v&255 for i,v in enumerate(cmd)},local_base=base,halt_on_leave=True,capture_stack=True,limit=8192);m=t['memory'];pc=t
|
| 31 |
for c in t['calls']:
|
| 32 |
if c['target']==-107:value=word(math.sqrt(number(c['args'][8])));r={'input':c['args'][8]&0xffffffff,'root':value}
|
| 33 |
else:
|
|
|
|
| 27 |
from analyze_qvm_acceleration import FRAME,word,number
|
| 28 |
handlers=handlers or {};result_offsets=result_offsets or {};points=[x['index']+2 for x in ins[start:stop] if x['opcode']=='CALL']+list(boundaries);pc=start;trace=[];calls=[];children=[];writes=[];ret=None
|
| 29 |
for _ in range(256):
|
| 30 |
+
t=trace_slice(ins,start,stop,m,{},resume_at=pc,stop_targets=[p for p in points if p!=pc],byte_memory={FRAME+25+i:v&255 for i,v in enumerate(cmd)},local_base=base,halt_on_leave=True,capture_stack=True,limit=8192);m=t['memory'];pc=t.get('stop',stop);trace+=t['trace'];calls+=t['calls'];writes+=t['byte_writes'];cmd=[t['byte_memory'][FRAME+25+i] for i in range(3)]
|
| 31 |
for c in t['calls']:
|
| 32 |
if c['target']==-107:value=word(math.sqrt(number(c['args'][8])));r={'input':c['args'][8]&0xffffffff,'root':value}
|
| 33 |
else:
|
scripts/test_qvm_interaction_request.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,unittest,copy
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from test_qvm_ground import word,n,f
|
| 4 |
+
from test_qvm_torso_selector import signed
|
| 5 |
+
from test_qvm_water_events import enqueue
|
| 6 |
+
|
| 7 |
+
def route(p):
|
| 8 |
+
a=p['initial']
|
| 9 |
+
if a['weapon_state'] or a['state220']&(1|512|1024) or a['flags']&8 or signed(a['weapon_timer'])>0 or not p['buttons']&64:return 'blocked'
|
| 10 |
+
if a['state220']&(128|256):return 'direct'
|
| 11 |
+
return 'hit' if p['contents']&33554432 else 'miss'
|
| 12 |
+
class InteractionRequestTests(unittest.TestCase):
|
| 13 |
+
@classmethod
|
| 14 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-interaction-request.json').read_text())
|
| 15 |
+
def test_gates_query_routing_and_first16_inventory(self):
|
| 16 |
+
self.assertEqual(len(self.r['probes']),47)
|
| 17 |
+
for p in self.r['probes']:
|
| 18 |
+
r=route(p);self.assertEqual(len(p['queries']),int(r in ['hit','miss']))
|
| 19 |
+
if r=='hit':
|
| 20 |
+
found=p['initial']['health']>0 and any(x&255==19 for x in p['initial']['inventory']);check=next(c for c in p['execution']['children'] if c['call']['target']==32155)['effect'];self.assertEqual(check['return'],int(found))
|
| 21 |
+
if check['children']:self.assertEqual(check['children'][0]['effect']['return'],next((j for j,x in enumerate(p['initial']['inventory']) if x&255==19),-1))
|
| 22 |
+
def test_trace_geometry_division_and_contract(self):
|
| 23 |
+
for p in self.r['probes']:
|
| 24 |
+
for q in p['queries']:
|
| 25 |
+
start=p['origin'][:];start[2]=word(f(n(start[2])+int(p['height']/2)));end=[word(f(n(x)+f(n(d)*64))) for x,d in zip(start,p['basis'])];self.assertEqual(q['start'],start);self.assertEqual(q['end'],end);self.assertEqual((q['entity'],q['mask']),(7,100663297))
|
| 26 |
+
def test_exact_state_and_source_event_animation_order(self):
|
| 27 |
+
for p in self.r['probes']:
|
| 28 |
+
r=route(p);a=copy.deepcopy(p['initial']);calls=[c['target'] for c in p['execution']['calls']]
|
| 29 |
+
if r in ['hit','direct']:
|
| 30 |
+
a['state220']=(a['state220']|1) if r=='hit' else (a['state220']|512)&~8;a['weapon_timer']=(750 if a['health']>0 and any(x&255==19 for x in a['inventory']) else 1500) if r=='hit' else 1000;a['queue']=enqueue(a['queue'],[12 if r=='hit' else 4]);a['torso_timer']=321
|
| 31 |
+
if p['kind']<3:a['torso']=((a['torso']&128)^128)|46
|
| 32 |
+
self.assertEqual(a,p['final']);self.assertEqual(calls,{'blocked':[],'miss':[-25],'hit':[-25,32155,39238,39552],'direct':[39552,39238]}[r])
|
| 33 |
+
def test_inventory_and_source_priority_remain_explicit(self):
|
| 34 |
+
for p in self.r['probes']:self.assertEqual(p['initial']['inventory'],p['final']['inventory']);self.assertEqual(p['initial']['packed'],p['final']['packed'])
|
| 35 |
+
self.assertTrue(any(p['initial']['weapon_state']==3 and route(p)=='blocked' for p in self.r['probes']))
|
| 36 |
+
if __name__=='__main__':unittest.main()
|