nmarshall commited on
Commit
41cce5d
·
1 Parent(s): a598ebb

qvm: rewind snapshot restoration

Browse files
docs/ASSET_PIPELINE_TODO.md CHANGED
@@ -577,3 +577,6 @@ Research progress: RE-631 [report](research/QVM_TRACE_RESPONSE_CHAIN.md); remain
577
 
578
 
579
  Research progress: RE-632 [report](research/QVM_REWIND_SNAPSHOT.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
577
 
578
 
579
  Research progress: RE-632 [report](research/QVM_REWIND_SNAPSHOT.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.
docs/FINDINGS.md CHANGED
@@ -929,3 +929,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
929
 
930
 
931
  **RE-632 — Rewind snapshot prefix and packed animation bytes:** 143100 saves entity vectors and selected client state, sets client4408 and packs low animation bytes before history selection. [Evidence](research/QVM_REWIND_SNAPSHOT.md).
 
 
 
 
929
 
930
 
931
  **RE-632 — Rewind snapshot prefix and packed animation bytes:** 143100 saves entity vectors and selected client state, sets client4408 and packs low animation bytes before history selection. [Evidence](research/QVM_REWIND_SNAPSHOT.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).
docs/PROVISIONAL_TODO.md CHANGED
@@ -897,3 +897,6 @@ Research progress: RE-631 [report](research/QVM_TRACE_RESPONSE_CHAIN.md); remain
897
 
898
 
899
  Research progress: RE-632 [report](research/QVM_REWIND_SNAPSHOT.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
897
 
898
 
899
  Research progress: RE-632 [report](research/QVM_REWIND_SNAPSHOT.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.
docs/RESEARCH_LEDGER.md CHANGED
@@ -837,3 +837,8 @@ Whole291641 now follows supplied world/entity traces through retry, ordered reli
837
  ## 2026-10-20 — RE-632 Rewind snapshot prefix and packed animation bytes (separate task commit)
838
 
839
  143100 saves entity vectors and selected client state, sets client4408 and packs low animation bytes before history selection. 16 raw-word/animation/null-client fixtures independently check every snapshot word, byte-store order and unchanged entity records. Full suite: 1011 tests pass. Report regenerates byte-identically (199100 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
 
 
 
 
 
 
837
  ## 2026-10-20 — RE-632 Rewind snapshot prefix and packed animation bytes (separate task commit)
838
 
839
  143100 saves entity vectors and selected client state, sets client4408 and packs low animation bytes before history selection. 16 raw-word/animation/null-client fixtures independently check every snapshot word, byte-store order and unchanged entity records. Full suite: 1011 tests pass. Report regenerates byte-identically (199100 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
840
+
841
+
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.
docs/REVERSE_ENGINEERING_TODO.md CHANGED
@@ -940,3 +940,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
940
 
941
 
942
  - [x] RE-632 Rewind snapshot prefix and packed animation bytes ([report](research/QVM_REWIND_SNAPSHOT.md)).
 
 
 
 
940
 
941
 
942
  - [x] RE-632 Rewind snapshot prefix and packed animation bytes ([report](research/QVM_REWIND_SNAPSHOT.md)).
943
+
944
+
945
+ - [x] RE-633 Complete rewind record restoration and byte widening ([report](research/QVM_REWIND_RESTORE.md)).
docs/research/QVM_REWIND_RESTORE.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Complete rewind record restoration and byte widening
2
+
3
+ RE-633. Reproduce with `python3 scripts/analyze_qvm_rewind_restore.py`; check with `python3 scripts/test_qvm_rewind_restore.py`. The [machine report](qvm-rewind-restore.json) retains source identity and bounded fixtures.
4
+
5
+ Actual144166–144410 returns without effects when client4408==0. Otherwise it clears4408, copies saved vectors back into entity24/60/488/36, restores entity200/196 from bytes4448/4449 and restores six selected client words. Native−31 is requested only after all those writes. The report composes the recovered snapshot with explicitly supplied rewound live values, not actual history interpolation. Independent full-state checks verify the reverse map and expected animation truncation: original high bits are not recovered from byte snapshots. A second actual call performs no link or state change. Null-client legality and full143100 interpolation remain outside this helper contract; no native relink effect executes.
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
@@ -498,3 +498,6 @@ The extension collector adds five focused tests for native tail calls, command-r
498
 
499
 
500
  [RE-632: Rewind snapshot prefix and packed animation bytes](QVM_REWIND_SNAPSHOT.md). Reproduce with `python3 scripts/analyze_qvm_rewind_snapshot.py`; check with `python3 scripts/test_qvm_rewind_snapshot.py`.
 
 
 
 
498
 
499
 
500
  [RE-632: Rewind snapshot prefix and packed animation bytes](QVM_REWIND_SNAPSHOT.md). Reproduce with `python3 scripts/analyze_qvm_rewind_snapshot.py`; check with `python3 scripts/test_qvm_rewind_snapshot.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`.
docs/research/qvm-rewind-restore.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_qvm_rewind_restore.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Complete144165 snapshot restore, including LOAD1 and native link boundary."""
3
+ import itertools
4
+ from pathlib import Path
5
+ from qvm_research_support import source,execute
6
+ from qvm_server_fire_support import ENTITY
7
+ from analyze_qvm_rewind_snapshot import fixture,snapshot,client_state
8
+ from analyze_qvm_temp_event import record
9
+ from analyze_qvm import write_json
10
+ LOCAL=0x79a00000
11
+
12
+ def restore_player(ins,m,pointer=ENTITY):
13
+ m=dict(m);client=m[pointer+520];initial=record(m,pointer);before=client_state(m,client);requests=[];m[LOCAL+68]=pointer;packed=m[client+4448]
14
+ def link(i,m,a,c):e={'arguments':a,'record_at_request':record(m,pointer),'client_at_request':client_state(m,client),'native_effect_not_executed':True};requests.append(e);return m,c,0,e
15
+ m,_,e=execute(ins,144166,144411,m,(0,0,0),LOCAL,{-31:link},byte_inputs={client+4448:packed&255,client+4449:(packed>>8)&255})
16
+ return m,{'pointer':pointer,'client':client,'initial_entity':initial,'initial_client':before,'final_entity':record(m,pointer),'final_client':client_state(m,client),'requests':requests,'execution':e}
17
+
18
+ def main():
19
+ q,raw,h,ins=source();rows=[]
20
+ for canary,animation in itertools.product([0,0x12345678,0xffffffff],[0,255,256,0x1234,0xffffffff]):
21
+ m=fixture(raw,h,canary,animation);m,s=snapshot(ins,m);client=m[ENTITY+520]
22
+ for o in [24,28,32,36,40,44,60,64,68,488,492,496,196,200]:m[ENTITY+o]=0x99887766
23
+ for o in [4380,4384,4388,4392,6204,6256]:m[client+o]=0x11223344
24
+ m,r=restore_player(ins,m);_,second=restore_player(ins,m);r['original_entity']=s['initial_entity'];r['original_client']=s['initial_client'];r['second_execution']=second['execution'];r['second_entity']=second['final_entity'];rows.append(r)
25
+ m=fixture(raw,h);m[m[ENTITY+520]+4408]=0;rows.append(restore_player(ins,m)[1])
26
+ write_json(Path('docs/research/qvm-rewind-restore.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'limits':'Complete144166–144410 using recovered snapshot plus explicitly supplied rewound live fields; native−31 captured only. Animation restore zero-extends saved bytes. No actual history interpolation, engine relink or full143100 rewind executes.'})
27
+ if __name__=='__main__':main()
scripts/test_qvm_rewind_restore.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json,unittest
2
+ from pathlib import Path
3
+
4
+ def expected(p):
5
+ entity=dict(p['initial_entity']);client=dict(p['initial_client'])
6
+ if not client['4408']:return entity,client
7
+ client['4408']=0
8
+ for dst,src in [(24,4424),(60,4436),(488,4412),(36,4452)]:
9
+ for j in range(3):entity[str(dst+4*j)]=client[str(src+4*j)]
10
+ entity['200']=client['4448']&255;entity['196']=(client['4448']>>8)&255
11
+ for dst,src in [(4380,4468),(4384,4464),(4388,4476),(4392,4472),(6204,4484),(6256,4488)]:client[str(dst)]=client[str(src)]
12
+ return entity,client
13
+ class RewindRestoreTests(unittest.TestCase):
14
+ @classmethod
15
+ def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-rewind-restore.json').read_text())
16
+ def test_independent_full_restore_oracle(self):
17
+ self.assertEqual(len(self.r['probes']),16)
18
+ for p in self.r['probes']:self.assertEqual((p['final_entity'],p['final_client']),expected(p))
19
+ def test_original_values_and_animation_byte_loss(self):
20
+ for p in self.r['probes'][:-1]:
21
+ original=dict(p['original_entity']);original['200']&=255;original['196']&=255;self.assertEqual(p['final_entity'],original)
22
+ for o in [4380,4384,4388,4392,6204,6256]:self.assertEqual(p['final_client'][str(o)],p['original_client'][str(o)])
23
+ def test_link_after_complete_restore_and_idempotent_guard(self):
24
+ for p in self.r['probes'][:-1]:
25
+ self.assertEqual([c['target'] for c in p['execution']['calls']],[-31]);self.assertEqual(p['requests'][0]['record_at_request'],p['final_entity']);self.assertEqual(p['requests'][0]['client_at_request'],p['final_client']);self.assertEqual(p['second_execution']['calls'],[]);self.assertEqual(p['second_entity'],p['final_entity'])
26
+ def test_inactive_guard_preserves_every_word(self):
27
+ p=self.r['probes'][-1];self.assertEqual(p['initial_entity'],p['final_entity']);self.assertEqual(p['initial_client'],p['final_client']);self.assertEqual(p['requests'],[])
28
+ if __name__=='__main__':unittest.main()