nmarshall commited on
Commit
c7c2586
·
1 Parent(s): 482cba7

qvm: weapon continuation guards

Browse files
docs/ASSET_PIPELINE_TODO.md CHANGED
@@ -415,3 +415,6 @@ Research progress: RE-574 [report](research/QVM_SPECIAL_QUERY.md); remaining nat
415
 
416
 
417
  Research progress: RE-575 [report](research/QVM_WEAPON_SELECTION_CALLER.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
415
 
416
 
417
  Research progress: RE-575 [report](research/QVM_WEAPON_SELECTION_CALLER.md); remaining native/content/runtime/platform scope stays open.
418
+
419
+
420
+ Research progress: RE-576 [report](research/QVM_WEAPON_GUARDS.md); remaining native/content/runtime/platform scope stays open.
docs/FINDINGS.md CHANGED
@@ -773,3 +773,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
773
 
774
 
775
  **RE-575 — Weapon prefix to actual selection handoff:** 50746 re-decodes the current ID after mode processing, requests48798 only when it differs from command byte24, and suppresses that request for currentID27 while its decremented timer is positive. [Evidence](research/QVM_WEAPON_SELECTION_CALLER.md).
 
 
 
 
773
 
774
 
775
  **RE-575 — Weapon prefix to actual selection handoff:** 50746 re-decodes the current ID after mode processing, requests48798 only when it differs from command byte24, and suppresses that request for currentID27 while its decremented timer is positive. [Evidence](research/QVM_WEAPON_SELECTION_CALLER.md).
776
+
777
+
778
+ **RE-576 — Weapon continuation guards timer floors and cancellation:** 50923..51206 applies ordered traversal/action guards, floors timers at300, conditionally cancels state512 and returns while timer is positive; two ID checks literally assign localID12 on their fallback paths. [Evidence](research/QVM_WEAPON_GUARDS.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -729,3 +729,6 @@ Research progress: RE-574 [report](research/QVM_SPECIAL_QUERY.md); remaining nat
729
 
730
 
731
  Research progress: RE-575 [report](research/QVM_WEAPON_SELECTION_CALLER.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
729
 
730
 
731
  Research progress: RE-575 [report](research/QVM_WEAPON_SELECTION_CALLER.md); remaining native/content/runtime/platform scope stays open.
732
+
733
+
734
+ Research progress: RE-576 [report](research/QVM_WEAPON_GUARDS.md); remaining native/content/runtime/platform scope stays open.
docs/RESEARCH_LEDGER.md CHANGED
@@ -571,3 +571,8 @@ Actual54444 reload/interaction order exposes timer interference before the weapo
571
  ## 2026-10-20 — RE-575 Weapon prefix to actual selection handoff (separate task commit)
572
 
573
  50746 re-decodes the current ID after mode processing, requests48798 only when it differs from command byte24, and suppresses that request for currentID27 while its decremented timer is positive. 41 source-order compositions check prefix oracles, equality and ID27 timer16/17 boundary, present/missing requested slot, helper rejection and actual early exits. Full suite: 819 tests pass. Report regenerates byte-identically (1148636 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
 
 
 
 
 
 
571
  ## 2026-10-20 — RE-575 Weapon prefix to actual selection handoff (separate task commit)
572
 
573
  50746 re-decodes the current ID after mode processing, requests48798 only when it differs from command byte24, and suppresses that request for currentID27 while its decremented timer is positive. 41 source-order compositions check prefix oracles, equality and ID27 timer16/17 boundary, present/missing requested slot, helper rejection and actual early exits. Full suite: 819 tests pass. Report regenerates byte-identically (1148636 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
574
+
575
+
576
+ ## 2026-10-20 — RE-576 Weapon continuation guards timer floors and cancellation (separate task commit)
577
+
578
+ 50923..51206 applies ordered traversal/action guards, floors timers at300, conditionally cancels state512 and returns while timer is positive; two ID checks literally assign localID12 on their fallback paths. 90 independent probes check exact state/stop/local-ID results, timer−1/0/1/299/300, state512/button priority and literal assignment for IDs outside11/13. Full suite: 823 tests pass. Report regenerates byte-identically (260588 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
@@ -769,3 +769,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
769
 
770
 
771
  - [x] RE-575 Weapon prefix to actual selection handoff ([report](research/QVM_WEAPON_SELECTION_CALLER.md)).
 
 
 
 
769
 
770
 
771
  - [x] RE-575 Weapon prefix to actual selection handoff ([report](research/QVM_WEAPON_SELECTION_CALLER.md)).
772
+
773
+
774
+ - [x] RE-576 Weapon continuation guards timer floors and cancellation ([report](research/QVM_WEAPON_GUARDS.md)).
docs/research/QVM_WEAPON_GUARDS.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Weapon continuation guards timer floors and cancellation
2
+
3
+ RE-576. Reproduce with `python3 scripts/analyze_qvm_weapon_guards.py`; check with `python3 scripts/test_qvm_weapon_guards.py`. The [machine report](qvm-weapon-guards.json) retains source identity and bounded fixtures.
4
+
5
+ This standalone slice starts at50923 with explicitly supplied parent local ID. PS12 bit8 plus state32 clears bits32/64, sets weapon state2 and exits. State16384 plus32 exits without those writes. In both groups IDs11/13 branch directly, while other IDs execute CONST12→local12 STORE and then branch on that nonzero value. The source therefore assigns12 rather than comparing ID to12; packed weapon is unchanged. Intended high-level logic is not inferred.
6
+
7
+ Next, state1024 or PS12 bit8 exits. State4 floors PS44 at300. State512 with button1 stays pending while timer is positive, otherwise clears512 and sets300. Without button1, state128/256 causes immediate exit retaining512; otherwise the timer is floored300 and512 clears. Finally positive PS44 exits; nonpositive timer reaches51207.
8
+
9
+ 90 fixtures independently check exact state and source stop boundaries. No prefix is run in these standalone probes, so input state32 is not silently cleared by an earlier absent button1. Remaining: compose these gates after actual selection and recover ready/ammo/reload/phase branches while preserving local state and caller legality.
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
@@ -330,3 +330,6 @@ The extension collector adds five focused tests for native tail calls, command-r
330
 
331
 
332
  [RE-575: Weapon prefix to actual selection handoff](QVM_WEAPON_SELECTION_CALLER.md). Reproduce with `python3 scripts/analyze_qvm_weapon_selection_caller.py`; check with `python3 scripts/test_qvm_weapon_selection_caller.py`.
 
 
 
 
330
 
331
 
332
  [RE-575: Weapon prefix to actual selection handoff](QVM_WEAPON_SELECTION_CALLER.md). Reproduce with `python3 scripts/analyze_qvm_weapon_selection_caller.py`; check with `python3 scripts/test_qvm_weapon_selection_caller.py`.
333
+
334
+
335
+ [RE-576: Weapon continuation guards timer floors and cancellation](QVM_WEAPON_GUARDS.md). Reproduce with `python3 scripts/analyze_qvm_weapon_guards.py`; check with `python3 scripts/test_qvm_weapon_guards.py`.
docs/research/qvm-weapon-guards.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_qvm_weapon_guards.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """50923..51206 weapon state guards, timer floors and bit512 cancellation."""
3
+ import itertools
4
+ from pathlib import Path
5
+ from qvm_research_support import source,execute
6
+ from qvm_weapon_support import weapon_seed,weapon_state
7
+ from analyze_qvm_weapon_prefix import LOCAL
8
+ from analyze_qvm_acceleration import PS,FRAME
9
+ from analyze_qvm import write_json
10
+
11
+ def guards(ins,m,cmd=(0,0,0)):
12
+ initial=weapon_state(m);ident=initial['packed']&255;m[LOCAL+12]=ident
13
+ m,c,r=execute(ins,50923,53046,m,cmd,LOCAL,boundaries=[51207])
14
+ return m,{'initial':initial,'buttons':m[FRAME+20],'initial_local_id':ident,'final_local_id':m[LOCAL+12],'execution':r,'final':weapon_state(m)}
15
+
16
+ def main():
17
+ q,raw,h,ins=source();rows=[]
18
+ for flags,special,ident in itertools.product([0,8],[0,32,32|16384],[1,11,12,13,22]):
19
+ m=weapon_seed(raw,h);m.update({PS+312:ident,PS+12:flags,PS+220:special,PS+44:0,FRAME+20:1});rows.append(guards(ins,m)[1])
20
+ for special,buttons,timer in itertools.product([0,1024,4,512,512|128,512|256],[0,1],[-1,0,1,299,300]):
21
+ m=weapon_seed(raw,h);m.update({PS+312:22,PS+220:special,PS+44:timer,FRAME+20:buttons});rows.append(guards(ins,m)[1])
22
+ write_json(Path('docs/research/qvm-weapon-guards.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'limits':'Finite50923..51206 with supplied entry state/local ID; no prefix performed for standalone probes. Stops51207 or actual exit53046. Assignment-to-local12 observed literally, not inferred intended logic.'})
23
+ if __name__=='__main__':main()
scripts/test_qvm_weapon_guards.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json,unittest,copy
2
+ from pathlib import Path
3
+ from test_qvm_torso_selector import signed
4
+
5
+ def guard_state(p):
6
+ a=copy.deepcopy(p['initial']);ident=p['initial_local_id'];s=a['state220'];stop=53046
7
+ if a['flags']&8 and s&32:
8
+ if ident not in [11,13]:ident=12
9
+ a['state220']&=~96;a['weapon_state']=2;return a,stop,ident
10
+ if s&16384 and s&32:
11
+ if ident not in [11,13]:ident=12
12
+ return a,stop,ident
13
+ if s&1024 or a['flags']&8:return a,stop,ident
14
+ if s&4 and signed(a['weapon_timer'])<300:a['weapon_timer']=300
15
+ if s&512:
16
+ if p['buttons']&1:
17
+ if signed(a['weapon_timer'])<=0:a['state220']&=~512;a['weapon_timer']=300
18
+ else:
19
+ if s&(256|128):return a,stop,ident
20
+ if signed(a['weapon_timer'])<300:a['weapon_timer']=300
21
+ a['state220']&=~512
22
+ if signed(a['weapon_timer'])<=0:stop=51207
23
+ return a,stop,ident
24
+ class WeaponGuardsTests(unittest.TestCase):
25
+ @classmethod
26
+ def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-weapon-guards.json').read_text())
27
+ def test_all_exact_states_and_boundaries(self):
28
+ self.assertEqual(len(self.r['probes']),90)
29
+ for p in self.r['probes']:a,stop,ident=guard_state(p);self.assertEqual(p['final'],a);self.assertEqual(p['execution']['stop'],stop);self.assertEqual(p['final_local_id'],ident)
30
+ def test_literal_assignment_not_equality_for_id12(self):
31
+ rows=[p for p in self.r['probes'] if p['initial']['state220']&32 and (p['initial']['flags']&8 or p['initial']['state220']&16384)];self.assertTrue(rows)
32
+ for p in rows:self.assertEqual(p['execution']['stop'],53046);self.assertEqual(p['final_local_id'],p['initial_local_id'] if p['initial_local_id'] in [11,13] else 12)
33
+ def test_no_child_or_packed_weapon_mutation(self):
34
+ for p in self.r['probes']:self.assertEqual(p['execution']['calls'],[]);self.assertEqual(p['initial']['weapons'],p['final']['weapons']);self.assertEqual(p['initial']['queue'],p['final']['queue'])
35
+ def test_positive_floor_and_bit512_priority(self):
36
+ self.assertTrue(any(p['initial']['state220']==4 and p['final']['weapon_timer']==300 for p in self.r['probes']));self.assertTrue(any(p['initial']['state220']==512 and p['final']['state220']==0 for p in self.r['probes']))
37
+ if __name__=='__main__':unittest.main()