qvm: final firing delay
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_FIRE_DELAY.md +11 -0
- docs/research/README.md +3 -0
- docs/research/qvm-fire-delay.json +0 -0
- scripts/analyze_qvm_fire_delay.py +24 -0
- scripts/test_qvm_fire_delay.py +21 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -451,3 +451,6 @@ Research progress: RE-587 [report](research/QVM_FIRE_COUNTER.md); remaining nati
|
|
| 451 |
|
| 452 |
|
| 453 |
Research progress: RE-588 [report](research/QVM_FIRE_RESOURCE.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 451 |
|
| 452 |
|
| 453 |
Research progress: RE-588 [report](research/QVM_FIRE_RESOURCE.md); remaining native/content/runtime/platform scope stays open.
|
| 454 |
+
|
| 455 |
+
|
| 456 |
+
Research progress: RE-589 [report](research/QVM_FIRE_DELAY.md); remaining native/content/runtime/platform scope stays open.
|
docs/FINDINGS.md
CHANGED
|
@@ -809,3 +809,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
|
|
| 809 |
|
| 810 |
|
| 811 |
**RE-588 — Firing resource snapshot capacity arithmetic and reset:** 52873..52988 snapshots resource188 into PS216, adds truncated30000/capacity with only an upper30000 clamp and sets a mode cooldown; mode flag16 instead zeros all three fields. [Evidence](research/QVM_FIRE_RESOURCE.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 809 |
|
| 810 |
|
| 811 |
**RE-588 — Firing resource snapshot capacity arithmetic and reset:** 52873..52988 snapshots resource188 into PS216, adds truncated30000/capacity with only an upper30000 clamp and sets a mode cooldown; mode flag16 instead zeros all three fields. [Evidence](research/QVM_FIRE_RESOURCE.md).
|
| 812 |
+
|
| 813 |
+
|
| 814 |
+
**RE-589 — Final firing delay and last-round exception:** 52989..53045 adds the retained selected delay to PS44 only if the post-debit magazine is nonzero or selectedID27; other empty magazines return without adding it. [Evidence](research/QVM_FIRE_DELAY.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -767,3 +767,6 @@ Research progress: RE-587 [report](research/QVM_FIRE_COUNTER.md); remaining nati
|
|
| 767 |
|
| 768 |
|
| 769 |
Research progress: RE-588 [report](research/QVM_FIRE_RESOURCE.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 767 |
|
| 768 |
|
| 769 |
Research progress: RE-588 [report](research/QVM_FIRE_RESOURCE.md); remaining native/content/runtime/platform scope stays open.
|
| 770 |
+
|
| 771 |
+
|
| 772 |
+
Research progress: RE-589 [report](research/QVM_FIRE_DELAY.md); remaining native/content/runtime/platform scope stays open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -633,3 +633,8 @@ RE-580 additional regression: all19 reports from RE-560–569 and RE-571–579 r
|
|
| 633 |
## 2026-10-20 — RE-588 Firing resource snapshot capacity arithmetic and reset (separate task commit)
|
| 634 |
|
| 635 |
52873..52988 snapshots resource188 into PS216, adds truncated30000/capacity with only an upper30000 clamp and sets a mode cooldown; mode flag16 instead zeros all three fields. 101 independent probes check integer quotient, signed wrap, negative/near-limit resources, capacity7/32/255, flag16 and zero-capacity bypass; an unguarded zero divisor is explicitly rejected. Full suite: 867 tests pass. Report regenerates byte-identically (337475 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 633 |
## 2026-10-20 — RE-588 Firing resource snapshot capacity arithmetic and reset (separate task commit)
|
| 634 |
|
| 635 |
52873..52988 snapshots resource188 into PS216, adds truncated30000/capacity with only an upper30000 clamp and sets a mode cooldown; mode flag16 instead zeros all three fields. 101 independent probes check integer quotient, signed wrap, negative/near-limit resources, capacity7/32/255, flag16 and zero-capacity bypass; an unguarded zero divisor is explicitly rejected. Full suite: 867 tests pass. Report regenerates byte-identically (337475 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
| 636 |
+
|
| 637 |
+
|
| 638 |
+
## 2026-10-20 — RE-589 Final firing delay and last-round exception (separate task commit)
|
| 639 |
+
|
| 640 |
+
52989..53045 adds the retained selected delay to PS44 only if the post-debit magazine is nonzero or selectedID27; other empty magazines return without adding it. 108 independent timer/delay/ID/magazine probes plus actual debit handoffs for IDs22/27 check wrap and last-round timer behavior without reloading the delay record. Full suite: 871 tests pass. Report regenerates byte-identically (376037 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
|
@@ -808,3 +808,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 808 |
|
| 809 |
|
| 810 |
- [x] RE-588 Firing resource snapshot capacity arithmetic and reset ([report](research/QVM_FIRE_RESOURCE.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 808 |
|
| 809 |
|
| 810 |
- [x] RE-588 Firing resource snapshot capacity arithmetic and reset ([report](research/QVM_FIRE_RESOURCE.md)).
|
| 811 |
+
|
| 812 |
+
|
| 813 |
+
- [x] RE-589 Final firing delay and last-round exception ([report](research/QVM_FIRE_DELAY.md)).
|
docs/research/QVM_FIRE_DELAY.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Final firing delay and last-round exception
|
| 2 |
+
|
| 3 |
+
RE-589. Reproduce with `python3 scripts/analyze_qvm_fire_delay.py`; check with `python3 scripts/test_qvm_fire_delay.py`. The [machine report](qvm-fire-delay.json) retains source identity and bounded fixtures.
|
| 4 |
+
|
| 5 |
+
The final predicate reads the current selected magazine after debit. If nonzero it adds parent local20 to PS44. If zero, only ID27 still adds it. Other empty magazines branch directly to the void epilogue53046. Addition uses32-bit integer semantics without a clamp or timer replacement.
|
| 6 |
+
|
| 7 |
+
108 finite probes include negative/supplied delays and overflow timers, proving the delay is the retained local selected earlier rather than re-read from a mode record. Two explicit debit→delay handoffs start with magazine1: both debit to0, but ID22 retains timer10 while ID27 becomes110 with supplied selected delay100. Intermediate animation/resource slices are explicitly omitted in these two focused handoffs.
|
| 8 |
+
|
| 9 |
+
This closes the final numerical weapon-body slice. It does not validate native firing or gameplay reachability of standalone values. Next: compose all recovered50746 branches in one call, preserve locals and publish actual per-frame requests to their outer event consumer.
|
| 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
|
@@ -368,3 +368,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 368 |
|
| 369 |
|
| 370 |
[RE-588: Firing resource snapshot capacity arithmetic and reset](QVM_FIRE_RESOURCE.md). Reproduce with `python3 scripts/analyze_qvm_fire_resource.py`; check with `python3 scripts/test_qvm_fire_resource.py`.
|
|
|
|
|
|
|
|
|
|
|
|
| 368 |
|
| 369 |
|
| 370 |
[RE-588: Firing resource snapshot capacity arithmetic and reset](QVM_FIRE_RESOURCE.md). Reproduce with `python3 scripts/analyze_qvm_fire_resource.py`; check with `python3 scripts/test_qvm_fire_resource.py`.
|
| 371 |
+
|
| 372 |
+
|
| 373 |
+
[RE-589: Final firing delay and last-round exception](QVM_FIRE_DELAY.md). Reproduce with `python3 scripts/analyze_qvm_fire_delay.py`; check with `python3 scripts/test_qvm_fire_delay.py`.
|
docs/research/qvm-fire-delay.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_fire_delay.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""52989..53045 final post-debit magazine predicate and selected delay addition."""
|
| 3 |
+
import itertools
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from qvm_research_support import source
|
| 6 |
+
from qvm_firing_support import seed,segment
|
| 7 |
+
from analyze_qvm_weapon_prefix import LOCAL
|
| 8 |
+
from analyze_qvm_fire_ammo import ammo
|
| 9 |
+
from analyze_qvm_acceleration import PS
|
| 10 |
+
from analyze_qvm import write_json
|
| 11 |
+
|
| 12 |
+
def delay(ins,m,cmd=(0,0,0),preserve_locals=False,selected_delay=None):
|
| 13 |
+
if selected_delay is not None:m[LOCAL+20]=selected_delay
|
| 14 |
+
selected=m[LOCAL+20]&0xffffffff;m,p=segment(ins,m,52989,[],cmd,preserve_locals);p['selected_delay']=selected;return m,p
|
| 15 |
+
|
| 16 |
+
def main():
|
| 17 |
+
q,raw,h,ins=source();rows=[]
|
| 18 |
+
for ident,mag,timer,selected in itertools.product([1,22,27],[0,1,2],[-1,0,123,0x7fffffff],[-100,0,100]):
|
| 19 |
+
m=seed(raw,h,ident,mag);m[PS+44]=timer;rows.append(delay(ins,m,selected_delay=selected)[1])
|
| 20 |
+
chains=[]
|
| 21 |
+
for ident in [22,27]:
|
| 22 |
+
m=seed(raw,h,ident,1);m[PS+44]=10;m,a=ammo(ins,m);m,b=delay(ins,m,selected_delay=100);chains.append({'ammo':a,'delay':b})
|
| 23 |
+
write_json(Path('docs/research/qvm-fire-delay.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'debit_then_delay':chains,'limits':'Finite52989..53045; selected delay supplied except retained parent-local composition. Last-round chains omit intermediate pose/resource slices explicitly. No native shot or full tick executes.'})
|
| 24 |
+
if __name__=='__main__':main()
|
scripts/test_qvm_fire_delay.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,unittest,copy
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from test_qvm_fire_ammo import ammo_state
|
| 4 |
+
|
| 5 |
+
def delay_state(p):
|
| 6 |
+
a=copy.deepcopy(p['initial'])
|
| 7 |
+
if a['packed']&65280 or a['packed']&255==27:a['weapon_timer']=(a['weapon_timer']+p['selected_delay'])&0xffffffff
|
| 8 |
+
return a,53046
|
| 9 |
+
class FireDelayTests(unittest.TestCase):
|
| 10 |
+
@classmethod
|
| 11 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-fire-delay.json').read_text())
|
| 12 |
+
def test_exact_post_debit_timer_predicate_and_wrap(self):
|
| 13 |
+
self.assertEqual(len(self.r['probes']),108)
|
| 14 |
+
for p in self.r['probes']:self.assertEqual(p['final'],delay_state(p)[0])
|
| 15 |
+
def test_last_round_vs_id27_actual_debit_handoff(self):
|
| 16 |
+
a,b=self.r['debit_then_delay'];self.assertEqual(a['delay']['final']['weapon_timer'],10);self.assertEqual(b['delay']['final']['weapon_timer'],110)
|
| 17 |
+
for p in self.r['debit_then_delay']:self.assertEqual(p['ammo']['final'],ammo_state(p['ammo'])[0]);self.assertEqual(p['ammo']['final'],p['delay']['initial']);self.assertEqual(p['delay']['final']['packed']>>8&255,0)
|
| 18 |
+
def test_only_timer_can_mutate_and_no_calls(self):
|
| 19 |
+
for p in self.r['probes']:self.assertEqual(p['execution']['calls'],[]);a=dict(p['initial']);a['weapon_timer']=p['final']['weapon_timer'];self.assertEqual(a,p['final'])
|
| 20 |
+
def test_selected_local_delay_not_reloaded_from_record(self):self.assertTrue(any(p['selected_delay']!=p['config']['delay'] and p['initial']['packed']&65280 for p in self.r['probes']))
|
| 21 |
+
if __name__=='__main__':unittest.main()
|