nmarshall commited on
Commit
b7af4bd
·
1 Parent(s): e119955

qvm: complete original model contacts

Browse files
docs/ASSET_PIPELINE_TODO.md CHANGED
@@ -826,3 +826,6 @@ Research progress: RE-719 [report](research/QVM_CONTACT_FEEDBACK.md); remaining
826
 
827
 
828
  Research progress: RE-720 [report](research/QVM_CONTACT_IMPACT.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
826
 
827
 
828
  Research progress: RE-720 [report](research/QVM_CONTACT_IMPACT.md); remaining native/content/runtime/platform scope stays open.
829
+
830
+
831
+ Research progress: RE-721 [report](research/QVM_CONTACT_COMPLETE.md); remaining native/content/runtime/platform scope stays open.
docs/FINDINGS.md CHANGED
@@ -1172,3 +1172,6 @@ RE-703–712 batch complete: [damage factor and contact dispatch](research/QVM_D
1172
 
1173
 
1174
  **RE-720 — Complete impact-only contact branch:** Impact-only contacts return0 and emit event109 for weapon30 or63 otherwise only with nonzero flag and clear trace surface bit32; weapon27 copies exact muzzle. [Evidence](research/QVM_CONTACT_IMPACT.md).
 
 
 
 
1172
 
1173
 
1174
  **RE-720 — Complete impact-only contact branch:** Impact-only contacts return0 and emit event109 for weapon30 or63 otherwise only with nonzero flag and clear trace surface bit32; weapon27 copies exact muzzle. [Evidence](research/QVM_CONTACT_IMPACT.md).
1175
+
1176
+
1177
+ **RE-721 — Complete contact on original-model contexts:** Complete292545 now composes eligibility, ordinary/special factors, event/impact branches, actual feedback, direction basis, health request and return using original-model contexts. [Evidence](research/QVM_CONTACT_COMPLETE.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -1161,3 +1161,6 @@ Research progress: RE-719 [report](research/QVM_CONTACT_FEEDBACK.md); remaining
1161
 
1162
 
1163
  Research progress: RE-720 [report](research/QVM_CONTACT_IMPACT.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
1161
 
1162
 
1163
  Research progress: RE-720 [report](research/QVM_CONTACT_IMPACT.md); remaining native/content/runtime/platform scope stays open.
1164
+
1165
+
1166
+ Research progress: RE-721 [report](research/QVM_CONTACT_COMPLETE.md); remaining native/content/runtime/platform scope stays open.
docs/RESEARCH_LEDGER.md CHANGED
@@ -1240,3 +1240,8 @@ Contact event104 receives truncated global forward×500 or exact muzzle for weap
1240
  ## 2026-10-21 — RE-720 Complete impact-only contact branch (separate task commit)
1241
 
1242
  Impact-only contacts return0 and emit event109 for weapon30 or63 otherwise only with nonzero flag and clear trace surface bit32; weapon27 copies exact muzzle. 48 weapon/flag/surface/normal combinations check every event word, actual child order, early suppression and numeric return. Full suite: 1328 tests pass. Report regenerates byte-identically (490508 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
 
 
 
 
 
 
1240
  ## 2026-10-21 — RE-720 Complete impact-only contact branch (separate task commit)
1241
 
1242
  Impact-only contacts return0 and emit event109 for weapon30 or63 otherwise only with nonzero flag and clear trace surface bit32; weapon27 copies exact muzzle. 48 weapon/flag/surface/normal combinations check every event word, actual child order, early suppression and numeric return. Full suite: 1328 tests pass. Report regenerates byte-identically (490508 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
1243
+
1244
+
1245
+ ## 2026-10-21 — RE-721 Complete contact on original-model contexts (separate task commit)
1246
+
1247
+ Complete292545 now composes eligibility, ordinary/special factors, event/impact branches, actual feedback, direction basis, health request and return using original-model contexts. 35 complete-call fixtures verify independent branch/float32/event-record/ABI oracles and exact original hit/miss context identity. Full suite: 1333 tests pass. Report regenerates byte-identically (997739 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
@@ -1204,3 +1204,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
1204
 
1205
 
1206
  - [x] RE-720 Complete impact-only contact branch ([report](research/QVM_CONTACT_IMPACT.md)).
 
 
 
 
1204
 
1205
 
1206
  - [x] RE-720 Complete impact-only contact branch ([report](research/QVM_CONTACT_IMPACT.md)).
1207
+
1208
+
1209
+ - [x] RE-721 Complete contact on original-model contexts ([report](research/QVM_CONTACT_COMPLETE.md)).
docs/research/QVM_CONTACT_COMPLETE.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Complete contact on original-model contexts
2
+
3
+ RE-721. Reproduce with `python3 scripts/analyze_qvm_contact_complete.py`; check with `python3 scripts/test_qvm_contact_complete.py`. The [machine report](qvm-contact-complete.json) retains source identity and bounded fixtures.
4
+
5
+ Complete292545 executes292546–293729 through every numeric return with actual289594,32155/32117,33715,277695/278138,60317 and285142 children. Original context rows are copied verbatim into separate memory; nearest point and normal words supply the trace. Ordinary/special/impact/nonclient, empty/null context, same-team/friendly-fire, protection and mode9 cases are included. An independent source-order oracle composes complete factor results, caller scalar rules, all220 event words and211239 request arguments. Native trig/sqrt are modeled; allocation is supplied; native link, formatted announcements/protection notifications and health damage are captured. Geometry is cached original-model output, not recomputed or live world collision. These boundaries remain open despite the complete caller control flow.
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
@@ -762,3 +762,6 @@ The extension collector adds five focused tests for native tail calls, command-r
762
 
763
 
764
  [RE-720: Complete impact-only contact branch](QVM_CONTACT_IMPACT.md). Reproduce with `python3 scripts/analyze_qvm_contact_impact.py`; check with `python3 scripts/test_qvm_contact_impact.py`.
 
 
 
 
762
 
763
 
764
  [RE-720: Complete impact-only contact branch](QVM_CONTACT_IMPACT.md). Reproduce with `python3 scripts/analyze_qvm_contact_impact.py`; check with `python3 scripts/test_qvm_contact_impact.py`.
765
+
766
+
767
+ [RE-721: Complete contact on original-model contexts](QVM_CONTACT_COMPLETE.md). Reproduce with `python3 scripts/analyze_qvm_contact_complete.py`; check with `python3 scripts/test_qvm_contact_complete.py`.
docs/research/qvm-contact-complete.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_qvm_contact_complete.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Complete292545 with original hit/miss contexts and recovered bounded children."""
3
+ import hashlib,itertools,json
4
+ from pathlib import Path
5
+ from qvm_research_support import source
6
+ from qvm_contact_support import seed,run,L,CONTEXT,TRACE,EXTRA,V_CLIENT,A_CLIENT
7
+ from analyze_qvm_acceleration import number
8
+ from analyze_qvm import write_json
9
+
10
+ def main():
11
+ q,raw,h,ins=source();path=Path('docs/research/md3-original-model-hit.json');data=path.read_bytes();contexts=json.loads(data)['probes'];rows=[]
12
+ cases=[dict(context_row=i,weapon=w,flag=flag,announce=1,vest_slot=0,helmet_slot=15) for i,(w,flag) in itertools.product([1,2,4,5],[(3,0),(3,1),(4,0),(4,1),(27,1),(30,1)])]
13
+ cases += [dict(context_row=1,**changes) for changes in [dict(damageable=0,flag=0),dict(damageable=0,flag=1),dict(damageable=0,weapon=4,flag=1),dict(client=False,flag=1),dict(null_context=True),dict(same_team=True),dict(same_team=True,friendly_fire=1,flag=1),dict(now=3999,flag=1),dict(mode=9,flag=1),dict(entity_flags=16,flag=1)]]
14
+ cases += [dict(context_row=0,flag=1)]
15
+ for supplied in cases:
16
+ a=dict(supplied);a.setdefault('weapon',3);context=contexts[a['context_row']]['context'];a.update(location=context[17],distance=number(context[21]),count=context[16]);m=seed(raw,h,**a)
17
+ for j,v in enumerate(context):m[CONTEXT+4*j]=v
18
+ for p,values in [(TRACE+12,context[3:6]),(TRACE+24,context[9:12])]:
19
+ for j,v in enumerate(values):m[p+4*j]=v
20
+ if a.get('null_context'):m[L+144]=0
21
+ weapon=a.get('weapon',3);fixture={'input':a,'initial':{'extra':m[EXTRA]&0xffffffff,'client':{str(o):m[V_CLIENT+o]&0xffffffff for o in [192,220,4300,4304,4312,4316,6304]}},'descriptor_words':{str(loc):[m[4068+432*weapon+8*loc],m[4072+432*weapon+8*loc]] for loc in range(15)},'range_integer':m[4188+432*weapon]}
22
+ base_factor=m[4068+432*weapon];method=m[4200+432*weapon];m,p=run(ins,m,292546,293730,include_event=True);p.update(input=a,factor_fixture=fixture,base_factor_word=base_factor,method_word=method,context_words=context,feedback_pair=[m[A_CLIENT+2520+8*64],m[A_CLIENT+2524+8*64]]);rows.append(p)
23
+ write_json(Path('docs/research/qvm-contact-complete.json'),{'source':q['source'],'sha256':q['sha256'],'context_report':str(path),'context_report_sha256':hashlib.sha256(data).hexdigest(),'probes':rows,'limits':'Complete292545 with actual289594/inventory/mode/constructor/codec/285142 and modeled native trig/sqrt. Original context bytes copied verbatim. Allocation supplied; native link, announcements, protection notifications and211239 health effects captured. Geometry is cached original-model output, not recomputed/live world collision.'})
24
+ if __name__=='__main__':main()
scripts/test_qvm_contact_complete.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import hashlib,json,math,unittest
2
+ from pathlib import Path
3
+ from test_qvm_ground import word,n,f
4
+ from test_qvm_damage_complete import expected as factor_expected
5
+ from test_qvm_temp_event import event_record
6
+ from test_qvm_direction_codec import best
7
+ from test_qvm_contact_event_value import normalized
8
+ from qvm_contact_support import ATTACKER,TARGET,TRACE
9
+ from analyze_qvm_contact_dispatch import FORWARD
10
+
11
+ def expected(p):
12
+ a=p['input'];w=a.get('weapon',3);flag=a.get('flag',0);special=w==4 and flag!=0;impact=not a.get('damageable',1) and not special
13
+ if impact:return 0,0,bool(flag),'impact',False
14
+ if not a.get('client',True):return word(f(n(p['base_factor_word'])*100)),0,False,'nonclient',False
15
+ mode=a.get('mode',3);enabled=mode>=3 and mode not in (9,11)
16
+ if a.get('null_context') or not a['count'] or (enabled and a.get('same_team',False) and not a.get('friendly_fire',0)):return 0,0,False,'rejected',False
17
+ if special:
18
+ loc=a['location']
19
+ if loc in (1,2):loc=2 if a.get('helmet_slot',-1)>=0 else 1
20
+ if loc in (3,4):loc=4 if a.get('vest_slot',-1)>=0 else 3
21
+ return word(1),loc,bool(flag),'special',False
22
+ v,loc,*_=factor_expected(p['factor_fixture'])
23
+ if mode==9 or a.get('now',5000)<4000:loc=0
24
+ scalar=word(0 if loc==0 else f(n(v)*100));return scalar,loc,bool(flag and n(scalar)!=0),'ordinary',n(scalar)!=0
25
+
26
+ class CompleteContactTests(unittest.TestCase):
27
+ @classmethod
28
+ def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-contact-complete.json').read_text());cls.ps=cls.r['probes'];cls.table=json.loads(Path('docs/research/qvm-direction-codec.json').read_text())['table']
29
+ def test_independent_complete_return_and_branch_outcomes(self):
30
+ for p in self.ps:
31
+ v,loc,event,kind,damage=expected(p);self.assertEqual(p['execution']['return']&0xffffffff,v,p['input']);self.assertEqual(len(p['effects']['events']),int(event),p['input'])
32
+ if kind in ('ordinary','special','nonclient'):self.assertEqual(p['location'],loc)
33
+ if kind=='nonclient':damage=n(v)!=0
34
+ self.assertEqual(len(p['effects']['damage']),int(damage),p['input'])
35
+ def test_all_event_words_composed_independently(self):
36
+ for p in self.ps:
37
+ a=p['input'];scalar,loc,event,kind,_=expected(p);w=a.get('weapon',3)
38
+ if not event:self.assertTrue(all(v==0 for v in p['event_record'].values()));continue
39
+ e=p['effects']['events'][0];self.assertEqual(e['input_origin'],p['context_words'][3:6]);r=event_record(e);normal=p['context_words'][9:12]
40
+ if kind=='impact':r.update({'184':best(normal,self.table),'192':w,'88':99,'140':7,'204':1})
41
+ else:
42
+ encoded=math.trunc(n(scalar)) if w!=4 else min(100,math.trunc(f(n(p['extra_word'])*100)))
43
+ r.update({'424':32,'184':best(normal,self.table),'140':7,'144':65,'88':loc,'84':p['context_words'][15],'200':int(f(100-n(scalar))<=0),'204':encoded&0xffffffff,'196':w})
44
+ for j,v in enumerate(p['context_words'][3:6]):r[str(24+4*j)]=v
45
+ for j,v in enumerate(normalized((3,4,0),(0,0,0))):r[str(36+4*j)]=v
46
+ for j,v in enumerate([0.3333,-0.002,1]):r[str(104+4*j)]=word(float(math.trunc(f(f(v)*500))))
47
+ if w==27:
48
+ for j,v in enumerate([1.25,-2.5,3.75]):r[str(104+4*j)]=word(v)
49
+ self.assertEqual(p['event_record'],r,a)
50
+ def test_health_request_arguments_and_unapplied_effects(self):
51
+ for p in self.ps:
52
+ scalar,loc,*_=expected(p)
53
+ for c in p['effects']['damage']:self.assertEqual(c['arguments'],{'8':TARGET,'12':ATTACKER,'16':ATTACKER,'20':FORWARD,'24':TRACE+12,'28':math.trunc(n(scalar)),'32':0,'36':p['method_word'],'40':loc})
54
+ self.assertEqual(p['target_health'],100);self.assertEqual(p['feedback_pair'],[0,0])
55
+ def test_exact_original_context_identity(self):
56
+ data=Path(self.r['context_report']).read_bytes();self.assertEqual(hashlib.sha256(data).hexdigest(),self.r['context_report_sha256']);rows=json.loads(data)['probes']
57
+ for p in self.ps:self.assertEqual(p['context_words'],rows[p['input']['context_row']]['context'])
58
+ def test_expected_actual_call_families_and_count(self):
59
+ self.assertEqual(len(self.ps),35)
60
+ allowed={33715,289594,32155,7259,277695,60317,-107,-104,-105,285142,211239}
61
+ for p in self.ps:self.assertTrue(all(c['target'] in allowed for c in p['execution']['calls']))
62
+ if __name__=='__main__':unittest.main()