qvm: rewind and restore selectors
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_REWIND_SELECTORS.md +7 -0
- docs/research/README.md +3 -0
- docs/research/qvm-rewind-selectors.json +0 -0
- scripts/analyze_qvm_rewind_selectors.py +51 -0
- scripts/test_qvm_rewind_selectors.py +25 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -580,3 +580,6 @@ Research progress: RE-632 [report](research/QVM_REWIND_SNAPSHOT.md); remaining n
|
|
| 580 |
|
| 581 |
|
| 582 |
Research progress: RE-633 [report](research/QVM_REWIND_RESTORE.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 580 |
|
| 581 |
|
| 582 |
Research progress: RE-633 [report](research/QVM_REWIND_RESTORE.md); remaining native/content/runtime/platform scope stays open.
|
| 583 |
+
|
| 584 |
+
|
| 585 |
+
Research progress: RE-634 [report](research/QVM_REWIND_SELECTORS.md); remaining native/content/runtime/platform scope stays open.
|
docs/FINDINGS.md
CHANGED
|
@@ -932,3 +932,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
|
|
| 932 |
|
| 933 |
|
| 934 |
**RE-633 — Complete rewind record restoration and byte widening:** 144165 restores saved vectors/client fields, zero-extends the two animation bytes, clears4408 and links once; a second call is inactive. [Evidence](research/QVM_REWIND_RESTORE.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 932 |
|
| 933 |
|
| 934 |
**RE-633 — Complete rewind record restoration and byte widening:** 144165 restores saved vectors/client fields, zero-extends the two animation bytes, clears4408 and links once; a second call is inactive. [Evidence](research/QVM_REWIND_RESTORE.md).
|
| 935 |
+
|
| 936 |
+
|
| 937 |
+
**RE-634 — Fixed player rewind selection and actual restore enumeration:** 144082 and144413 scan exactly64 source slots using matching client/in-use/state/exclusion gates; the restore selector now executes recovered144165. [Evidence](research/QVM_REWIND_SELECTORS.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -900,3 +900,6 @@ Research progress: RE-632 [report](research/QVM_REWIND_SNAPSHOT.md); remaining n
|
|
| 900 |
|
| 901 |
|
| 902 |
Research progress: RE-633 [report](research/QVM_REWIND_RESTORE.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 900 |
|
| 901 |
|
| 902 |
Research progress: RE-633 [report](research/QVM_REWIND_RESTORE.md); remaining native/content/runtime/platform scope stays open.
|
| 903 |
+
|
| 904 |
+
|
| 905 |
+
Research progress: RE-634 [report](research/QVM_REWIND_SELECTORS.md); remaining native/content/runtime/platform scope stays open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -842,3 +842,8 @@ Whole291641 now follows supplied world/entity traces through retry, ordered reli
|
|
| 842 |
## 2026-10-20 — RE-633 Complete rewind record restoration and byte widening (separate task commit)
|
| 843 |
|
| 844 |
144165 restores saved vectors/client fields, zero-extends the two animation bytes, clears4408 and links once; a second call is inactive. 16 fixtures independently reconstruct all entity/client words, verify snapshot round-trip byte loss and native link ordering/idempotence. Full suite: 1015 tests pass. Report regenerates byte-identically (601178 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 842 |
## 2026-10-20 — RE-633 Complete rewind record restoration and byte widening (separate task commit)
|
| 843 |
|
| 844 |
144165 restores saved vectors/client fields, zero-extends the two animation bytes, clears4408 and links once; a second call is inactive. 16 fixtures independently reconstruct all entity/client words, verify snapshot round-trip byte loss and native link ordering/idempotence. Full suite: 1015 tests pass. Report regenerates byte-identically (601178 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
| 845 |
+
|
| 846 |
+
|
| 847 |
+
## 2026-10-20 — RE-634 Fixed player rewind selection and actual restore enumeration (separate task commit)
|
| 848 |
+
|
| 849 |
+
144082 and144413 scan exactly64 source slots using matching client/in-use/state/exclusion gates; the restore selector now executes recovered144165. 16 selector/exclusion/global-count/delta fixtures independently check all64 predicates, call order, time ABI and actual child restoration. Full suite: 1019 tests pass. Report regenerates byte-identically (1219554 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
|
@@ -943,3 +943,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 943 |
|
| 944 |
|
| 945 |
- [x] RE-633 Complete rewind record restoration and byte widening ([report](research/QVM_REWIND_RESTORE.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 943 |
|
| 944 |
|
| 945 |
- [x] RE-633 Complete rewind record restoration and byte widening ([report](research/QVM_REWIND_RESTORE.md)).
|
| 946 |
+
|
| 947 |
+
|
| 948 |
+
- [x] RE-634 Fixed player rewind selection and actual restore enumeration ([report](research/QVM_REWIND_SELECTORS.md)).
|
docs/research/QVM_REWIND_SELECTORS.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Fixed player rewind selection and actual restore enumeration
|
| 2 |
+
|
| 3 |
+
RE-634. Reproduce with `python3 scripts/analyze_qvm_rewind_selectors.py`; check with `python3 scripts/test_qvm_rewind_selectors.py`. The [machine report](qvm-rewind-selectors.json) retains source identity and bounded fixtures.
|
| 4 |
+
|
| 5 |
+
Actual144082 selects client!=0, in-use!=0, signed client3096<3, not excluded,3740==0 and4324==0. Its143100 calls are explicitly recorded under a nonmutating child contract, not treated as executed history rewind. Actual144413 uses the same64-slot gates and dispatches recovered144165 for each selected record. The source loops ignore global entity count; fixtures set count0/1024 and include slot63 to retain that distinction. Delta is passed unchanged only to rewind. Independent predicates check every slot, including inactive, no-client, states3/4, both exclusion fields and state2. Restore child records match independent full-state oracles. Native linking remains captured and full143100 interpolation remains unresolved.
|
| 6 |
+
|
| 7 |
+
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
|
@@ -501,3 +501,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 501 |
|
| 502 |
|
| 503 |
[RE-633: Complete rewind record restoration and byte widening](QVM_REWIND_RESTORE.md). Reproduce with `python3 scripts/analyze_qvm_rewind_restore.py`; check with `python3 scripts/test_qvm_rewind_restore.py`.
|
|
|
|
|
|
|
|
|
|
|
|
| 501 |
|
| 502 |
|
| 503 |
[RE-633: Complete rewind record restoration and byte widening](QVM_REWIND_RESTORE.md). Reproduce with `python3 scripts/analyze_qvm_rewind_restore.py`; check with `python3 scripts/test_qvm_rewind_restore.py`.
|
| 504 |
+
|
| 505 |
+
|
| 506 |
+
[RE-634: Fixed player rewind selection and actual restore enumeration](QVM_REWIND_SELECTORS.md). Reproduce with `python3 scripts/analyze_qvm_rewind_selectors.py`; check with `python3 scripts/test_qvm_rewind_selectors.py`.
|
docs/research/qvm-rewind-selectors.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_rewind_selectors.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Fixed64-slot rewind selection and actual recovered restoration selector."""
|
| 3 |
+
import itertools
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from qvm_research_support import source,execute
|
| 6 |
+
from analyze_qvm_rewind_snapshot import fixture as player_fixture,snapshot,CLIENT_OFFSETS
|
| 7 |
+
from analyze_qvm_rewind_restore import restore_player
|
| 8 |
+
from analyze_qvm_entity_init import POOL,STRIDE
|
| 9 |
+
from qvm_server_fire_support import ENTITY
|
| 10 |
+
from analyze_qvm import write_json
|
| 11 |
+
LOCAL=0x79b00000
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def pool_fixture(raw,h,ins):
|
| 15 |
+
template=player_fixture(raw,h);template,_=snapshot(ins,template);source_client=template[ENTITY+520];m={34992508:0}
|
| 16 |
+
for index in range(64):
|
| 17 |
+
p=POOL+index*STRIDE
|
| 18 |
+
for o in range(0,STRIDE,4):m[p+o]=template[ENTITY+o]
|
| 19 |
+
m[p]=index;m[p+520]=0;m[p+532]=1
|
| 20 |
+
for index in [0,1,2,3,4,5,6,7,8,63]:
|
| 21 |
+
p=POOL+index*STRIDE;client=0x200000+index*0x2000;m[p+520]=client
|
| 22 |
+
for o in CLIENT_OFFSETS:m[client+o]=template[source_client+o]
|
| 23 |
+
m[client+3096]=0;m[client+3740]=0;m[client+4324]=0
|
| 24 |
+
for o in [24,28,32,36,40,44,60,64,68,488,492,496,196,200]:m[p+o]=0x99887766
|
| 25 |
+
m[POOL+2*STRIDE+520]=0;m[POOL+3*STRIDE+532]=0;m[0x200000+4*0x2000+3096]=3;m[0x200000+5*0x2000+3096]=4;m[0x200000+6*0x2000+3740]=1;m[0x200000+7*0x2000+4324]=1;m[0x200000+8*0x2000+3096]=2
|
| 26 |
+
return m
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def select(ins,m,entry,excluded,delta=1200):
|
| 30 |
+
m=dict(m);rows=[]
|
| 31 |
+
for index in range(64):
|
| 32 |
+
p=POOL+index*STRIDE;client=m[p+520];rows.append({'index':index,'pointer':p,'client':client,'used':m[p+532],'state3096':m.get(client+3096) if client else None,'field3740':m.get(client+3740) if client else None,'field4324':m.get(client+4324) if client else None})
|
| 33 |
+
requests=[];effects=[]
|
| 34 |
+
if entry==144082:
|
| 35 |
+
base=LOCAL;m[base+36]=delta;m[base+40]=excluded
|
| 36 |
+
def capture(i,m,a,c):e={'arguments':a,'child_not_executed':True};requests.append(e);return m,c,0,e
|
| 37 |
+
m,_,e=execute(ins,144083,144163,m,(0,0,0),base,{143100:capture});scope='selection-only-nonmutating-child-contract'
|
| 38 |
+
else:
|
| 39 |
+
assert entry==144413;base=LOCAL+0x1000;m[base+32]=excluded
|
| 40 |
+
def child(i,m,a,c):m,r=restore_player(i,m,a[8]);requests.append({'arguments':a});effects.append(r);return m,c,0,r
|
| 41 |
+
m,_,e=execute(ins,144414,144491,m,(0,0,0),base,{144165:child});scope='actual144165-restoration'
|
| 42 |
+
if entry==144413:e['children']=[{'call':child['call'],'effect':{'restore_effect_index':j}} for j,child in enumerate(e['children'])]
|
| 43 |
+
return m,{'entry':entry,'excluded':excluded,'delta':delta,'global_entity_count':m[34992508],'slots':rows,'requests':requests,'restore_effects':effects,'execution':e,'scope':scope}
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def main():
|
| 47 |
+
q,raw,h,ins=source();rows=[]
|
| 48 |
+
for entry,excluded,count,delta in itertools.product([144082,144413],[0,20],[0,1024],[0,1200]):
|
| 49 |
+
m=pool_fixture(raw,h,ins);m[34992508]=count;rows.append(select(ins,m,entry,POOL+excluded*STRIDE,delta)[1])
|
| 50 |
+
write_json(Path('docs/research/qvm-rewind-selectors.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'limits':'Actual64-slot144082 selection with nonmutating captured143100 calls, and actual144413→144165 restore. Captured rewind callbacks are not full rewind execution. Entity count global is intentionally ignored by source fixed64 loops; native links captured.'})
|
| 51 |
+
if __name__=='__main__':main()
|
scripts/test_qvm_rewind_selectors.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from test_qvm_rewind_restore import expected
|
| 4 |
+
class RewindSelectorTests(unittest.TestCase):
|
| 5 |
+
@classmethod
|
| 6 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-rewind-selectors.json').read_text())
|
| 7 |
+
def test_independent_all64_slot_predicate(self):
|
| 8 |
+
self.assertEqual(len(self.r['probes']),16)
|
| 9 |
+
for p in self.r['probes']:
|
| 10 |
+
eligible=[s['pointer'] for s in p['slots'] if s['client'] and s['used'] and s['state3096']<3 and s['pointer']!=p['excluded'] and not s['field3740'] and not s['field4324']];self.assertEqual([r['arguments']['8'] for r in p['requests']],eligible);self.assertEqual([s['index'] for s in p['slots']],list(range(64)))
|
| 11 |
+
def test_global_count_does_not_change_fixed_pool_scope(self):
|
| 12 |
+
for entry in [144082,144413]:
|
| 13 |
+
for excluded in [34091368,34091368+20*880]:
|
| 14 |
+
rows=[p for p in self.r['probes'] if p['entry']==entry and p['excluded']==excluded];self.assertTrue(all([r['arguments']['8'] for r in p['requests']]==[r['arguments']['8'] for r in rows[0]['requests']] for p in rows))
|
| 15 |
+
def test_rewind_requests_pass_delta_without_fake_effects(self):
|
| 16 |
+
for p in self.r['probes']:
|
| 17 |
+
if p['entry']==144082:
|
| 18 |
+
self.assertEqual(p['restore_effects'],[])
|
| 19 |
+
for r in p['requests']:self.assertEqual(r['arguments']['12'],p['delta']);self.assertTrue(r['child_not_executed'])
|
| 20 |
+
def test_restore_selector_executes_recovered_child(self):
|
| 21 |
+
for p in self.r['probes']:
|
| 22 |
+
if p['entry']==144413:
|
| 23 |
+
self.assertEqual([c['target'] for c in p['execution']['calls']],[144165]*len(p['requests']))
|
| 24 |
+
for r in p['restore_effects']:self.assertEqual((r['final_entity'],r['final_client']),expected(r));self.assertEqual(r['final_client']['4408'],0)
|
| 25 |
+
if __name__=='__main__':unittest.main()
|