qvm: recover timer phase loop and damage requests
Browse files- docs/FINDINGS.md +2 -0
- docs/PROVISIONAL_TODO.md +2 -0
- docs/RESEARCH_LEDGER.md +4 -0
- docs/REVERSE_ENGINEERING_TODO.md +2 -0
- docs/research/QVM_CLIENT_TIMER_TICKS.md +5 -0
- docs/research/README.md +2 -0
- docs/research/qvm-client-timer-ticks.json +0 -0
- scripts/analyze_qvm_client_timer_ticks.py +12 -0
- scripts/qvm_client_timer_oracle.py +17 -0
- scripts/qvm_client_timer_support.py +19 -0
- scripts/test_qvm_client_timer_ticks.py +11 -0
- xtask/checks.tsv +4 -0
docs/FINDINGS.md
CHANGED
|
@@ -1863,3 +1863,5 @@ RE-963: Rust matches40 original frame-prefix cases, retaining squared horizontal
|
|
| 1863 |
RE-964: A144-case source contract executes disjoint150791..150810 and151085..151131 fragments. Entity cooldown multiplication/addition wraps before signed comparison; exact equality preserves flags. Client bit2 clears only after a strict deadline, unrelated bits and deadline/stamp words survive, and elapsed-total accumulation wraps. Intervening loop and native scheduling remain outside this fragment contract. [Evidence](research/QVM_CLIENT_TIMER_TERMINAL.md).
|
| 1864 |
|
| 1865 |
RE-965: Rust matches144 original terminal-fragment cases, preserving wrapping cooldown arithmetic before signed comparisons, strict equality behavior, unrelated flag bits and elapsed-total wrap. Separate pre-loop and post-loop APIs allow later composition in original order. Unit tests cover equal/expired deadlines and signed overflow; this contract does not execute the intervening timer loop or native scheduling. [Evidence](research/RUST_CLIENT_TIMER_TERMINAL.md).
|
|
|
|
|
|
|
|
|
| 1863 |
RE-964: A144-case source contract executes disjoint150791..150810 and151085..151131 fragments. Entity cooldown multiplication/addition wraps before signed comparison; exact equality preserves flags. Client bit2 clears only after a strict deadline, unrelated bits and deadline/stamp words survive, and elapsed-total accumulation wraps. Intervening loop and native scheduling remain outside this fragment contract. [Evidence](research/QVM_CLIENT_TIMER_TERMINAL.md).
|
| 1864 |
|
| 1865 |
RE-965: Rust matches144 original terminal-fragment cases, preserving wrapping cooldown arithmetic before signed comparisons, strict equality behavior, unrelated flag bits and elapsed-total wrap. Separate pre-loop and post-loop APIs allow later composition in original order. Unit tests cover equal/expired deadlines and signed overflow; this contract does not execute the intervening timer loop or native scheduling. [Evidence](research/RUST_CLIENT_TIMER_TERMINAL.md).
|
| 1866 |
+
|
| 1867 |
+
RE-966: A288-case source loop contract covers signed residual thresholds, wrapping phase increments and signed remainder with rates0/1/2/5. Rate0 reads preceding word1120403456 instead of a zero divisor. Flag256 plus positive supplied health and phase0 request damage1, means23 and caller weapon/owner pointers. Damage effects remain captured and flag512 is disabled in this stage; health mutation and other branches remain open. [Evidence](research/QVM_CLIENT_TIMER_TICKS.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1915,3 +1915,5 @@ RE-954–963 completed add/remove wrappers, resolved duration export, full-capac
|
|
| 1915 |
- [x] RE-964 Original client timer deadline and terminal-counter fragments ([evidence](research/QVM_CLIENT_TIMER_TERMINAL.md)).
|
| 1916 |
|
| 1917 |
- [x] RE-965 Rust client timer deadlines and terminal accumulation ([evidence](research/RUST_CLIENT_TIMER_TERMINAL.md)).
|
|
|
|
|
|
|
|
|
| 1915 |
- [x] RE-964 Original client timer deadline and terminal-counter fragments ([evidence](research/QVM_CLIENT_TIMER_TERMINAL.md)).
|
| 1916 |
|
| 1917 |
- [x] RE-965 Rust client timer deadlines and terminal accumulation ([evidence](research/RUST_CLIENT_TIMER_TERMINAL.md)).
|
| 1918 |
+
|
| 1919 |
+
- [x] RE-966 Original100ms timer phase loop and damage-request ABI ([evidence](research/QVM_CLIENT_TIMER_TICKS.md)).
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -2531,3 +2531,7 @@ A144-case source contract executes disjoint150791..150810 and151085..151131 frag
|
|
| 2531 |
## 2026-10-28 — RE-965 Rust client timer deadlines and terminal accumulation
|
| 2532 |
|
| 2533 |
Rust matches144 original terminal-fragment cases, preserving wrapping cooldown arithmetic before signed comparisons, strict equality behavior, unrelated flag bits and elapsed-total wrap. Separate pre-loop and post-loop APIs allow later composition in original order. Unit tests cover equal/expired deadlines and signed overflow; this contract does not execute the intervening timer loop or native scheduling. Focused `cargo xtask test-group rust-client-timer-terminal` passes with deterministic report regeneration, relevant regressions and storage/documentation/whitespace checks. Full suite deferred to the tenth-commit boundary. Original assets unchanged; native IO effects remain captured.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2531 |
## 2026-10-28 — RE-965 Rust client timer deadlines and terminal accumulation
|
| 2532 |
|
| 2533 |
Rust matches144 original terminal-fragment cases, preserving wrapping cooldown arithmetic before signed comparisons, strict equality behavior, unrelated flag bits and elapsed-total wrap. Separate pre-loop and post-loop APIs allow later composition in original order. Unit tests cover equal/expired deadlines and signed overflow; this contract does not execute the intervening timer loop or native scheduling. Focused `cargo xtask test-group rust-client-timer-terminal` passes with deterministic report regeneration, relevant regressions and storage/documentation/whitespace checks. Full suite deferred to the tenth-commit boundary. Original assets unchanged; native IO effects remain captured.
|
| 2534 |
+
|
| 2535 |
+
## 2026-10-28 — RE-966 Original100ms timer phase loop and damage-request ABI
|
| 2536 |
+
|
| 2537 |
+
A288-case source loop contract covers signed residual thresholds, wrapping phase increments and signed remainder with rates0/1/2/5. Rate0 reads preceding word1120403456 instead of a zero divisor. Flag256 plus positive supplied health and phase0 request damage1, means23 and caller weapon/owner pointers. Damage effects remain captured and flag512 is disabled in this stage; health mutation and other branches remain open. Focused `cargo xtask test-group qvm-client-timer-ticks` passes with deterministic report regeneration, relevant regressions and storage/documentation/whitespace checks. Full suite deferred to the tenth-commit boundary. Original assets unchanged; native IO effects remain captured.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -1952,3 +1952,5 @@ RE-954–963 recover bounded command wrappers, resolved duration export, full-ca
|
|
| 1952 |
- [x] RE-964 Original client timer deadline and terminal-counter fragments ([evidence](research/QVM_CLIENT_TIMER_TERMINAL.md)).
|
| 1953 |
|
| 1954 |
- [x] RE-965 Rust client timer deadlines and terminal accumulation ([evidence](research/RUST_CLIENT_TIMER_TERMINAL.md)).
|
|
|
|
|
|
|
|
|
| 1952 |
- [x] RE-964 Original client timer deadline and terminal-counter fragments ([evidence](research/QVM_CLIENT_TIMER_TERMINAL.md)).
|
| 1953 |
|
| 1954 |
- [x] RE-965 Rust client timer deadlines and terminal accumulation ([evidence](research/RUST_CLIENT_TIMER_TERMINAL.md)).
|
| 1955 |
+
|
| 1956 |
+
- [x] RE-966 Original100ms timer phase loop and damage-request ABI ([evidence](research/QVM_CLIENT_TIMER_TICKS.md)).
|
docs/research/QVM_CLIENT_TIMER_TICKS.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Original100ms timer phase loop and damage-request ABI
|
| 2 |
+
|
| 3 |
+
RE-966. Focused validation: `cargo xtask test-group qvm-client-timer-ticks`. [Machine report](qvm-client-timer-ticks.json).
|
| 4 |
+
|
| 5 |
+
A288-case source loop contract covers signed residual thresholds, wrapping phase increments and signed remainder with rates0/1/2/5. Rate0 reads preceding word1120403456 instead of a zero divisor. Flag256 plus positive supplied health and phase0 request damage1, means23 and caller weapon/owner pointers. Damage effects remain captured and flag512 is disabled in this stage; health mutation and other branches remain open.
|
docs/research/README.md
CHANGED
|
@@ -1487,3 +1487,5 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 1487 |
- [RE-964: Original client timer deadline and terminal-counter fragments](QVM_CLIENT_TIMER_TERMINAL.md).
|
| 1488 |
|
| 1489 |
- [RE-965: Rust client timer deadlines and terminal accumulation](RUST_CLIENT_TIMER_TERMINAL.md).
|
|
|
|
|
|
|
|
|
| 1487 |
- [RE-964: Original client timer deadline and terminal-counter fragments](QVM_CLIENT_TIMER_TERMINAL.md).
|
| 1488 |
|
| 1489 |
- [RE-965: Rust client timer deadlines and terminal accumulation](RUST_CLIENT_TIMER_TERMINAL.md).
|
| 1490 |
+
|
| 1491 |
+
- [RE-966: Original100ms timer phase loop and damage-request ABI](QVM_CLIENT_TIMER_TICKS.md).
|
docs/research/qvm-client-timer-ticks.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_client_timer_ticks.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Original100ms loop with flag512 disabled and damage requests captured."""
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from analyze_qvm import write_json
|
| 4 |
+
from qvm_research_support import source
|
| 5 |
+
from qvm_client_timer_support import seed,seed_loop,tick_loop,tick_fixtures
|
| 6 |
+
|
| 7 |
+
def main():
|
| 8 |
+
q,raw,h,ins=source();probes=[]
|
| 9 |
+
for a in tick_fixtures():
|
| 10 |
+
m,b=seed(raw,h,a);seed_loop(m,a);m,p,b=tick_loop(ins,m,b,a);p['input']=a;probes.append(p)
|
| 11 |
+
write_json(Path('docs/research/qvm-client-timer-ticks.json'),dict(source=q['source'],sha256=q['sha256'],range=[150810,151085],divisors=[1120403456,9,4,3,2,1],probes=probes,limits='288 original100ms loop cases with flag512 disabled. Signed residual gates and wrapping phase increments feed signed remainder; rate0 aliases preceding1120403456 word. Flag256, positive health and phase0 request damage1/mod23/weapon with owner pointers. Damage effects remain captured, so health stays supplied. Float/flag512 branches recovered next.'))
|
| 12 |
+
if __name__=='__main__':main()
|
scripts/qvm_client_timer_oracle.py
CHANGED
|
@@ -3,3 +3,20 @@ def signed(v):v&=0xffffffff;return v if v<2**31 else v-2**32
|
|
| 3 |
|
| 4 |
def terminal(a):
|
| 5 |
return dict(entity_flag=0 if signed(a['stamp']+a['cooldown']*1000)<signed(a['tick']) else a['entity_flag'],client_flags=a['client_flags']&~2 if a['client_flags']&2 and signed(a['tick'])>signed(a['deadline']) else a['client_flags'],elapsed_total=(a['elapsed_total']+a['msec'])&0xffffffff,deadline=a['deadline']&0xffffffff,stamp=a['stamp']&0xffffffff)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
def terminal(a):
|
| 5 |
return dict(entity_flag=0 if signed(a['stamp']+a['cooldown']*1000)<signed(a['tick']) else a['entity_flag'],client_flags=a['client_flags']&~2 if a['client_flags']&2 and signed(a['tick'])>signed(a['deadline']) else a['client_flags'],elapsed_total=(a['elapsed_total']+a['msec'])&0xffffffff,deadline=a['deadline']&0xffffffff,stamp=a['stamp']&0xffffffff)
|
| 6 |
+
|
| 7 |
+
DIVISORS=[1120403456,9,4,3,2,1]
|
| 8 |
+
def ticks(a):
|
| 9 |
+
import struct
|
| 10 |
+
f32=lambda x:struct.unpack('<f',struct.pack('<f',x))[0]
|
| 11 |
+
bits=lambda x:int.from_bytes(struct.pack('<f',x),'little')
|
| 12 |
+
flags=a['flags'];status=a.get('status',3);rate=a['rate'];phase=a['phase'];timer=f32(a.get('timer',0.0));residual=signed(a['residual']);requests=[]
|
| 13 |
+
while residual>=100:
|
| 14 |
+
divisor=DIVISORS[rate];v=signed(phase+1);quotient=(abs(v)//divisor)*(-1 if v<0 else 1);phase=(v-quotient*divisor)&0xffffffff;residual-=100
|
| 15 |
+
if flags&256 and signed(a['health'])>0 and phase==0:requests.append(dict(target=2,inflictor=3,attacker=3,direction=0,point=0,amount=1,flags=0,means=23,weapon=a.get('weapon',7)))
|
| 16 |
+
if flags&512:
|
| 17 |
+
if flags&256 and timer<=0:flags&=~256;rate=0;timer=0.0
|
| 18 |
+
if timer>0:
|
| 19 |
+
timer=f32(timer-f32(0.1))
|
| 20 |
+
if timer<=0:flags&=~256;rate=0;timer=0.0
|
| 21 |
+
elif flags&128:flags&=~128;status&=~1
|
| 22 |
+
return dict(damage=requests,state=[flags,status,rate,phase,bits(timer),residual&0xffffffff],health=a['health']&0xffffffff)
|
scripts/qvm_client_timer_support.py
CHANGED
|
@@ -21,3 +21,22 @@ def terminal(ins,m,b,a):
|
|
| 21 |
def terminal_fixtures():
|
| 22 |
from itertools import product
|
| 23 |
return [dict(stamp=stamp,cooldown=cooldown,tick=tick,client_flags=flags,deadline=deadline,entity_flag=7,elapsed_total=0xffffffff,msec=2) for stamp,cooldown,tick,flags,deadline in product([7999,8000,8001,0xffffffff],[0,2,0x7fffffff],[10000,0x80000000],[0,2,7],[9999,10000])]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
def terminal_fixtures():
|
| 22 |
from itertools import product
|
| 23 |
return [dict(stamp=stamp,cooldown=cooldown,tick=tick,client_flags=flags,deadline=deadline,entity_flag=7,elapsed_total=0xffffffff,msec=2) for stamp,cooldown,tick,flags,deadline in product([7999,8000,8001,0xffffffff],[0,2,0x7fffffff],[10000,0x80000000],[0,2,7],[9999,10000])]
|
| 24 |
+
|
| 25 |
+
LOOP_FIELDS=[220,236,4304,4308,4312,4316]
|
| 26 |
+
DIVISORS=[1120403456,9,4,3,2,1]
|
| 27 |
+
def seed_loop(m,a):
|
| 28 |
+
from analyze_qvm_acceleration import word
|
| 29 |
+
for off,value in zip(LOOP_FIELDS,[a['flags'],a.get('status',3),a['rate'],a['phase'],word(a.get('timer',0.0)),a['residual']]):m[CLIENT+off]=value
|
| 30 |
+
m[CLIENT+208]=a['health'];m[ENTITY+836]=POOL+880*3;m[ENTITY+840]=a.get('weapon',7)
|
| 31 |
+
|
| 32 |
+
def damage_handler(requests):
|
| 33 |
+
def damage(i,m,args,bs):
|
| 34 |
+
requests.append(dict(target=(args[8]-POOL)//880,inflictor=(args[12]-POOL)//880,attacker=(args[16]-POOL)//880,direction=args[20],point=args[24],amount=args[28],flags=args[32],means=args[36],weapon=args[40]));return m,0,{'damage_effect_captured':True}
|
| 35 |
+
return damage
|
| 36 |
+
|
| 37 |
+
def tick_loop(ins,m,b,a):
|
| 38 |
+
requests=[];m,v,p,b=run(ins,m,150809,151085,92,{8:ENTITY,12:0},b,{211239:damage_handler(requests)},base=ROOT);p.update(damage=requests,state=[m[CLIENT+o]&0xffffffff for o in LOOP_FIELDS],health=m[CLIENT+208]&0xffffffff);return m,p,b
|
| 39 |
+
|
| 40 |
+
def tick_fixtures():
|
| 41 |
+
from itertools import product
|
| 42 |
+
return [dict(residual=residual,rate=rate,flags=flags,health=health,phase=phase,status=3,timer=0.0,weapon=7) for residual,rate,flags,health,phase in product([-1,99,100,250,500,1000],[0,1,2,5],[0,256],[0,1],[0,3,0x7fffffff])]
|
scripts/test_qvm_client_timer_ticks.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from qvm_client_timer_oracle import ticks
|
| 4 |
+
class TickTests(unittest.TestCase):
|
| 5 |
+
def test_original_loop(self):
|
| 6 |
+
r=json.loads(Path('docs/research/qvm-client-timer-ticks.json').read_text());self.assertEqual(len(r['probes']),288);self.assertEqual(r['divisors'],[1120403456,9,4,3,2,1])
|
| 7 |
+
for p in r['probes']:
|
| 8 |
+
for k,v in ticks(p['input']).items():self.assertEqual(p[k],v)
|
| 9 |
+
def test_rate_alias_and_negative_residual(self):
|
| 10 |
+
a=dict(residual=250,rate=0,phase=0,flags=256,health=1);p=ticks(a);self.assertEqual(p['state'][3],2);self.assertEqual(p['damage'],[]);a['residual']=-1;self.assertEqual(ticks(a)['state'][-1],0xffffffff)
|
| 11 |
+
if __name__=='__main__':unittest.main()
|
xtask/checks.tsv
CHANGED
|
@@ -3442,3 +3442,7 @@ edge crates/urt-gameplay/src/client_timer.rs scripts/analyze_rust_client_timer_t
|
|
| 3442 |
edge crates/urt-gameplay/src/bin/urt-client-timer.rs scripts/analyze_rust_client_timer_terminal.py
|
| 3443 |
edge crates/urt-gameplay/src/client_timer.rs scripts/analyze_rust_health_impulse.py
|
| 3444 |
edge crates/urt-gameplay/src/bin/urt-client-timer.rs scripts/analyze_rust_health_impulse.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3442 |
edge crates/urt-gameplay/src/bin/urt-client-timer.rs scripts/analyze_rust_client_timer_terminal.py
|
| 3443 |
edge crates/urt-gameplay/src/client_timer.rs scripts/analyze_rust_health_impulse.py
|
| 3444 |
edge crates/urt-gameplay/src/bin/urt-client-timer.rs scripts/analyze_rust_health_impulse.py
|
| 3445 |
+
report scripts/analyze_qvm_client_timer_ticks.py docs/research/qvm-client-timer-ticks.json
|
| 3446 |
+
edge docs/research/qvm-client-timer-ticks.json scripts/test_qvm_client_timer_ticks.py
|
| 3447 |
+
group qvm-client-timer-ticks scripts/analyze_qvm_client_timer_ticks.py
|
| 3448 |
+
edge scripts/analyze_qvm_client_timer_ticks.py scripts/analyze_qvm_resumer_audit.py
|