qvm: complete health and impulse flow
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_HEALTH_COMPLETE.md +7 -0
- docs/research/README.md +3 -0
- docs/research/qvm-health-complete.json +0 -0
- scripts/analyze_qvm_health_complete.py +23 -0
- scripts/qvm_health_effects_support.py +1 -1
- scripts/test_qvm_health_complete.py +65 -0
- xtask/checks.tsv +2 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -859,3 +859,6 @@ Research progress: RE-730 [report](research/QVM_HEALTH_TERMINAL.md); original as
|
|
| 859 |
|
| 860 |
|
| 861 |
Research progress: RE-731 [report](research/QVM_HEALTH_IMPULSE.md); original assets unchanged.
|
|
|
|
|
|
|
|
|
|
|
|
| 859 |
|
| 860 |
|
| 861 |
Research progress: RE-731 [report](research/QVM_HEALTH_IMPULSE.md); original assets unchanged.
|
| 862 |
+
|
| 863 |
+
|
| 864 |
+
Research progress: RE-732 [report](research/QVM_HEALTH_COMPLETE.md); original assets unchanged.
|
docs/FINDINGS.md
CHANGED
|
@@ -1205,3 +1205,6 @@ RE-714–723 batch complete: [complete contact and health prefixes](research/QVM
|
|
| 1205 |
|
| 1206 |
|
| 1207 |
**RE-731 — Complete velocity impulse and movement timer:** Complete213009 adds direction×(global scale×knockback/200) in source float32 order, and only a zero existing timer gets clamp(trunc(knockback×2),50,200) plus movement flag64. [Evidence](research/QVM_HEALTH_IMPULSE.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1205 |
|
| 1206 |
|
| 1207 |
**RE-731 — Complete velocity impulse and movement timer:** Complete213009 adds direction×(global scale×knockback/200) in source float32 order, and only a zero existing timer gets clamp(trunc(knockback×2),50,200) plus movement flag64. [Evidence](research/QVM_HEALTH_IMPULSE.md).
|
| 1208 |
+
|
| 1209 |
+
|
| 1210 |
+
**RE-732 — Complete health function with actual velocity impulses:** Complete211239 now composes gates, routing, normalization, bookkeeping, special targets, health publication and terminal branches with actual RNG/meter/impulse children. Late health−999 clamp can leave client208 below the entity clamp. [Evidence](research/QVM_HEALTH_COMPLETE.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1194,3 +1194,6 @@ Research progress: RE-730 [report](research/QVM_HEALTH_TERMINAL.md); full native
|
|
| 1194 |
|
| 1195 |
|
| 1196 |
Research progress: RE-731 [report](research/QVM_HEALTH_IMPULSE.md); full native/platform/game scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
| 1194 |
|
| 1195 |
|
| 1196 |
Research progress: RE-731 [report](research/QVM_HEALTH_IMPULSE.md); full native/platform/game scope remains open.
|
| 1197 |
+
|
| 1198 |
+
|
| 1199 |
+
Research progress: RE-732 [report](research/QVM_HEALTH_COMPLETE.md); full native/platform/game scope remains open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -1298,3 +1298,8 @@ Terminal processing caps client228 low16 values above500 (except method26), clam
|
|
| 1298 |
## 2026-10-21 — RE-731 Complete velocity impulse and movement timer
|
| 1299 |
|
| 1300 |
Complete213009 adds direction×(global scale×knockback/200) in source float32 order, and only a zero existing timer gets clamp(trunc(knockback×2),50,200) plus movement flag64. Focused `cargo xtask test-group health` passes (36 Python tests); selected reports regenerate twice byte-identically, with storage, links and whitespace guards. New report: 74485 bytes. Full-suite validation is deferred to the tenth batch commit. No original assets, Rust runtime or shared VM evaluator changed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1298 |
## 2026-10-21 — RE-731 Complete velocity impulse and movement timer
|
| 1299 |
|
| 1300 |
Complete213009 adds direction×(global scale×knockback/200) in source float32 order, and only a zero existing timer gets clamp(trunc(knockback×2),50,200) plus movement flag64. Focused `cargo xtask test-group health` passes (36 Python tests); selected reports regenerate twice byte-identically, with storage, links and whitespace guards. New report: 74485 bytes. Full-suite validation is deferred to the tenth batch commit. No original assets, Rust runtime or shared VM evaluator changed.
|
| 1301 |
+
|
| 1302 |
+
|
| 1303 |
+
## 2026-10-21 — RE-732 Complete health function with actual velocity impulses
|
| 1304 |
+
|
| 1305 |
+
Complete211239 now composes gates, routing, normalization, bookkeeping, special targets, health publication and terminal branches with actual RNG/meter/impulse children. Late health−999 clamp can leave client208 below the entity clamp. Focused `cargo xtask test-group health` passes (41 Python tests); selected reports regenerate twice byte-identically, with storage, links and whitespace guards. New report: 804258 bytes. Full-suite validation is deferred to the tenth batch commit. No original assets, Rust runtime or shared VM evaluator changed.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -1237,3 +1237,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1237 |
|
| 1238 |
|
| 1239 |
- [x] RE-731 Complete velocity impulse and movement timer ([report](research/QVM_HEALTH_IMPULSE.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 1237 |
|
| 1238 |
|
| 1239 |
- [x] RE-731 Complete velocity impulse and movement timer ([report](research/QVM_HEALTH_IMPULSE.md)).
|
| 1240 |
+
|
| 1241 |
+
|
| 1242 |
+
- [x] RE-732 Complete health function with actual velocity impulses ([report](research/QVM_HEALTH_COMPLETE.md)).
|
docs/research/QVM_HEALTH_COMPLETE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Complete health function with actual velocity impulses
|
| 2 |
+
|
| 3 |
+
RE-732. Reproduce with `python3 scripts/analyze_qvm_health_complete.py`; validate with `cargo xtask test-group health`. See the [machine report](qvm-health-complete.json).
|
| 4 |
+
|
| 5 |
+
Complete211239 executes211240–213006 through all recovered branches on96 finite nonnull-client fixtures, using actual33715,36717,211197 and213009. Independent composed source-order oracles check every tracked entity/client field, attacker credit, direction, RNG and tracking flag. An observed ordering detail is preserved: client208 is published before the terminal entity−999 clamp and is not republished afterward. Native sqrt is modeled; intercept206128, protected update152386 and supplied pain/death/object callback pointers are captured without effects. Complete caller control flow therefore does not imply original callback/native/runtime parity. Null-client full-call legality remains unproven.
|
| 6 |
+
|
| 7 |
+
No original executable/full VM/native world collision or rendering runs. Supplied callback/native responses and fixture domains remain explicit; complete macOS/Linux Rust/Bevy/Solari gameplay remains open.
|
docs/research/README.md
CHANGED
|
@@ -795,3 +795,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 795 |
|
| 796 |
|
| 797 |
[RE-731: Complete velocity impulse and movement timer](QVM_HEALTH_IMPULSE.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 795 |
|
| 796 |
|
| 797 |
[RE-731: Complete velocity impulse and movement timer](QVM_HEALTH_IMPULSE.md).
|
| 798 |
+
|
| 799 |
+
|
| 800 |
+
[RE-732: Complete health function with actual velocity impulses](QVM_HEALTH_COMPLETE.md).
|
docs/research/qvm-health-complete.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_health_complete.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Complete211239 with actual impulse/meter/RNG and explicit callback boundaries."""
|
| 3 |
+
import itertools
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from qvm_research_support import source
|
| 6 |
+
from qvm_health_effects_support import seed,run,H,MAGIC
|
| 7 |
+
from analyze_qvm_health_impulse import impulse
|
| 8 |
+
from analyze_qvm import write_json
|
| 9 |
+
|
| 10 |
+
def complete(ins,m,args=None):
|
| 11 |
+
if args:
|
| 12 |
+
for o,v in args.items():m[H+108+o]=v
|
| 13 |
+
return run(ins,m,211240,213007,impulse_resolver=impulse,target=m[H+116])
|
| 14 |
+
|
| 15 |
+
def main():
|
| 16 |
+
q,raw,h,ins=source();rows=[];m=seed(raw,h);table=[{'method':m[4200+432*w],'knockback_word':m[4192+432*w]} for w in range(m[17412])]
|
| 17 |
+
cases=[dict(method=method,damage=damage,health=health,flags220=flags,pain=True,death=True) for method,damage,health,flags in itertools.product([12,22,24,26,37],[0,1,100,2000],[1,100],[0,16384])]
|
| 18 |
+
cases += [dict(**a) for a in [dict(mode=9),dict(now=3999),dict(entity_flags=16),dict(client4040=1),dict(same_team=True),dict(same_team=True,friendly_fire=1),dict(mode=10),dict(method=24,override=1,damage=1),dict(target_kind=4,callback=True),dict(target_kind=4,callback=False),dict(tracking=1),dict(direction=None,damage=1),dict(self=True)]]
|
| 19 |
+
cases += [dict(checksum=MAGIC,callback=True,**a) for a in [dict(method=25,**{'class':5},damage=101),dict(method=12,**{'class':6}),dict(method=34)]]
|
| 20 |
+
for a in cases:
|
| 21 |
+
m,p=complete(ins,seed(raw,h,**a));p.update(input=a,tracking=m[34999664]);rows.append(p)
|
| 22 |
+
write_json(Path('docs/research/qvm-health-complete.json'),{'source':q['source'],'sha256':q['sha256'],'descriptor_table':table,'probes':rows,'limits':'Complete211239 numeric body to void exit with actual33715,36717,211197 and213009. Native sqrt modeled;206128/152386 and supplied callback pointers captured without effects. Finite nonnull-client fixtures, no original executable or world runtime.'})
|
| 23 |
+
if __name__=='__main__':main()
|
scripts/qvm_health_effects_support.py
CHANGED
|
@@ -29,7 +29,7 @@ def seed(raw,h,**a):
|
|
| 29 |
|
| 30 |
def state(m,target=TARGET):
|
| 31 |
client=m[target+520]
|
| 32 |
-
return {'entity':{str(o):m[target+o]&0xffffffff for o in ENTITY_FIELDS},'client':{str(o):m[client+o]&0xffffffff for o in CLIENT_FIELDS} if client else None,'attacker_credits':m.get(m.get(m.get(H+124,ATTACKER)+520,0)+252,0)&0xffffffff,'direction':[m[DIRECTION+4*j]&0xffffffff for j in range(3)],'args':{str(o):m[H+o]&0xffffffff for o in [120,124,128,136,140,144,148]},'selected_damage':m[H+40]&0xffffffff,'knockback_word':m[H+32]&0xffffffff,'rng':m[21044]&0xffffffff}
|
| 33 |
|
| 34 |
def handlers(effects,impulse_resolver=None):
|
| 35 |
def root(i,m,a):v=word(math.sqrt(number(a[8])));return m,v,{'input_word':a[8]&0xffffffff,'result_word':v,'native_math_modeled':True}
|
|
|
|
| 29 |
|
| 30 |
def state(m,target=TARGET):
|
| 31 |
client=m[target+520]
|
| 32 |
+
return {'entity':{str(o):m[target+o]&0xffffffff for o in ENTITY_FIELDS},'client':{str(o):m[client+o]&0xffffffff for o in CLIENT_FIELDS} if client else None,'attacker_credits':m.get(m.get(m.get(H+124,ATTACKER)+520,0)+252,0)&0xffffffff,'direction':[m[(m[H+128] or DIRECTION)+4*j]&0xffffffff for j in range(3)],'args':{str(o):m[H+o]&0xffffffff for o in [120,124,128,136,140,144,148]},'selected_damage':m[H+40]&0xffffffff,'knockback_word':m[H+32]&0xffffffff,'rng':m[21044]&0xffffffff}
|
| 33 |
|
| 34 |
def handlers(effects,impulse_resolver=None):
|
| 35 |
def root(i,m,a):v=word(math.sqrt(number(a[8])));return m,v,{'input_word':a[8]&0xffffffff,'result_word':v,'native_math_modeled':True}
|
scripts/test_qvm_health_complete.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import copy,json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from test_qvm_ground import word,n,f
|
| 4 |
+
from test_qvm_health_gates import accepted
|
| 5 |
+
from test_qvm_health_knockback import oracle as knockback
|
| 6 |
+
from test_qvm_health_special_target import oracle as special_target
|
| 7 |
+
from test_qvm_health_impulse import expected as impulse_expected
|
| 8 |
+
from qvm_health_effects_support import MAGIC,ATTACKER,TARGET
|
| 9 |
+
|
| 10 |
+
def expected(p,table):
|
| 11 |
+
a=p['input'];r=copy.deepcopy(p['initial']);e=r['entity'];cl=r['client'];tracking=0
|
| 12 |
+
if not accepted(a):return r,tracking
|
| 13 |
+
cl['4328']=1
|
| 14 |
+
if a.get('tracking') and a.get('method',12)>11 and not a.get('same_team',False) and not a.get('self',False):tracking=1
|
| 15 |
+
if a.get('target_kind',1)==4 and a.get('checksum',0)!=MAGIC:return r,tracking
|
| 16 |
+
flags,direction,kb,stop=knockback(a,table);r['direction']=direction
|
| 17 |
+
if stop==213007:return r,tracking
|
| 18 |
+
method=a.get('method',12);same=a.get('self',False);attacker=TARGET if same else ATTACKER;attacker_id=65 if same else 7
|
| 19 |
+
if not same and a.get('health',100)>0 and a.get('target_kind',1) not in (0,3,4):r['attacker_credits']=(-1 if a.get('mode',3)>=3 and a.get('mode',3) not in (9,11) and a.get('same_team',False) else 1)&0xffffffff
|
| 20 |
+
take=max(1,a.get('damage',100));cl['272']=attacker_id;cl['4128']=attacker_id;cl['4132']=method;cl['4084' if method==23 else '4088']+=take
|
| 21 |
+
origin=method==23 or a.get('direction',[3,4,0]) is None;cl['4108']=int(origin)
|
| 22 |
+
for j,v in enumerate(list(map(word,[10,20,30])) if origin else direction):cl[str(4096+4*j)]=v
|
| 23 |
+
if method==6 and take>=30:cl['12']|=128
|
| 24 |
+
if a.get('checksum',0)==MAGIC:
|
| 25 |
+
inputs=dict(a,damage=take);health,selected,seed,called,_=special_target(inputs);e['684']=health&0xffffffff;r['rng']=seed
|
| 26 |
+
if called:e['720']=attacker
|
| 27 |
+
return r,tracking
|
| 28 |
+
intercept=a.get('mode',3)==10 and not same and a.get('health',100)-take<=0 and not a.get('flags220',0)&16384 and method not in (6,7,1,3,2,4,9,31,35,33,32)
|
| 29 |
+
if intercept:return r,tracking
|
| 30 |
+
def impulse_apply(zero_z):
|
| 31 |
+
if zero_z:r['direction'][2]=0
|
| 32 |
+
fake={'input':{'knockback':n(kb),'scale':a.get('scale',1000),'direction':list(map(n,r['direction']))},'initial':{str(o):cl[str(o)] for o in [12,16,32,36,40]}}
|
| 33 |
+
cl.update(impulse_expected(fake))
|
| 34 |
+
if method==24 and a.get('override',0):impulse_apply(True);return r,tracking
|
| 35 |
+
health=a.get('health',100)-take
|
| 36 |
+
if cl['220']&16384:
|
| 37 |
+
health=max(5,health);cl['220']&=~896;cl['236']&=~1;cl['6332']=word(f(n(cl['6332'])+f(f(take)*n(-1012924416))))
|
| 38 |
+
e.update({'684':health&0xffffffff,'836':attacker,'840':a.get('location',3)});cl['208']=health&0xffffffff;cl['184']=max(0,cl['184']-300*take)
|
| 39 |
+
if method!=26 and cl['228']&65535>500:cl['228']=500
|
| 40 |
+
if health<=0:
|
| 41 |
+
impulse_apply(False);e['684']=max(-999,health)&0xffffffff;e['720']=attacker
|
| 42 |
+
elif method in (16,43,22,25,29,24,37):impulse_apply(True)
|
| 43 |
+
return r,tracking
|
| 44 |
+
|
| 45 |
+
class CompleteHealthTests(unittest.TestCase):
|
| 46 |
+
@classmethod
|
| 47 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-health-complete.json').read_text());cls.ps=cls.r['probes']
|
| 48 |
+
def test_independent_composed_all_external_state(self):
|
| 49 |
+
for p in self.ps:
|
| 50 |
+
r,tracking=expected(p,self.r['descriptor_table'])
|
| 51 |
+
for key in ['entity','client','attacker_credits','direction','rng']:self.assertEqual(p['final'][key],r[key],(p['input'],key))
|
| 52 |
+
self.assertEqual(p['tracking'],tracking)
|
| 53 |
+
def test_actual_impulse_and_meter_children(self):
|
| 54 |
+
rows=[c for p in self.ps for c in p['execution']['children'] if c['call']['target']==213009];self.assertTrue(rows)
|
| 55 |
+
for c in rows:self.assertEqual(c['effect']['execution']['calls'],[]);self.assertIn('final',c['effect'])
|
| 56 |
+
self.assertTrue(any(c['target']==211197 for p in self.ps for c in p['execution']['calls']))
|
| 57 |
+
def test_late_entity_clamp_does_not_republish_client_health(self):
|
| 58 |
+
rows=[p for p in self.ps if p['input'].get('damage')==2000 and not p['input'].get('flags220',0)&16384];self.assertTrue(rows)
|
| 59 |
+
for p in rows:self.assertEqual(p['final']['entity']['684'],(-999)&0xffffffff);self.assertEqual(p['final']['client']['208'],(p['input']['health']-2000)&0xffffffff)
|
| 60 |
+
def test_void_exit_and_explicit_callback_boundaries(self):
|
| 61 |
+
self.assertEqual(len(self.ps),96)
|
| 62 |
+
for p in self.ps:self.assertEqual(p['execution']['stop'],213007);self.assertIsNone(p['execution']['return']);self.assertEqual(p['effects']['impulses'],[])
|
| 63 |
+
def test_native_math_only_sqrt_no_original_runtime(self):
|
| 64 |
+
for p in self.ps:self.assertTrue(all(c['target']>=0 or c['target']==-107 for c in p['execution']['calls']))
|
| 65 |
+
if __name__=='__main__':unittest.main()
|
xtask/checks.tsv
CHANGED
|
@@ -1157,3 +1157,5 @@ report scripts/analyze_qvm_health_terminal.py docs/research/qvm-health-terminal.
|
|
| 1157 |
edge docs/research/qvm-health-terminal.json scripts/test_qvm_health_terminal.py
|
| 1158 |
report scripts/analyze_qvm_health_impulse.py docs/research/qvm-health-impulse.json
|
| 1159 |
edge docs/research/qvm-health-impulse.json scripts/test_qvm_health_impulse.py
|
|
|
|
|
|
|
|
|
| 1157 |
edge docs/research/qvm-health-terminal.json scripts/test_qvm_health_terminal.py
|
| 1158 |
report scripts/analyze_qvm_health_impulse.py docs/research/qvm-health-impulse.json
|
| 1159 |
edge docs/research/qvm-health-impulse.json scripts/test_qvm_health_impulse.py
|
| 1160 |
+
report scripts/analyze_qvm_health_complete.py docs/research/qvm-health-complete.json
|
| 1161 |
+
edge docs/research/qvm-health-complete.json scripts/test_qvm_health_complete.py
|