nmarshall commited on
Commit
2a95afe
·
1 Parent(s): 6cae59c

qvm: recover timer phase loop and damage requests

Browse files
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