nmarshall commited on
Commit
e0c0b4e
·
1 Parent(s): 9122099

qvm: recover exit timers and reset effects

Browse files
docs/FINDINGS.md CHANGED
@@ -1487,3 +1487,6 @@ RE-813–822 replaces the scoreboard decimal assumption with actual37914 executi
1487
 
1488
 
1489
  **RE-829:** Rust matches all125 source suffix decisions, including nonzero negative limits, playing-count gates and configured low-mode scans. [Evidence](research/RUST_EXIT_LIMITS.md).
 
 
 
 
1487
 
1488
 
1489
  **RE-829:** Rust matches all125 source suffix decisions, including nonzero negative limits, playing-count gates and configured low-mode scans. [Evidence](research/RUST_EXIT_LIMITS.md).
1490
+
1491
+
1492
+ **RE-830:** The active round gate bypasses time-limit evaluation; expired mode9 time limits reset qualifying clients and populate supplied event records before exit requests. [Evidence](research/QVM_EXIT_TIMERS.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -1500,3 +1500,6 @@ RE-828: The exit suffix requires at least two playing clients, selects limits ac
1500
 
1501
 
1502
  RE-829: Rust matches all125 source suffix decisions, including nonzero negative limits, playing-count gates and configured low-mode scans. Full runtime completion remains open. [Evidence](research/RUST_EXIT_LIMITS.md).
 
 
 
 
1500
 
1501
 
1502
  RE-829: Rust matches all125 source suffix decisions, including nonzero negative limits, playing-count gates and configured low-mode scans. Full runtime completion remains open. [Evidence](research/RUST_EXIT_LIMITS.md).
1503
+
1504
+
1505
+ RE-830: The active round gate bypasses time-limit evaluation; expired mode9 time limits reset qualifying clients and populate supplied event records before exit requests. Full runtime completion remains open. [Evidence](research/QVM_EXIT_TIMERS.md).
docs/RESEARCH_LEDGER.md CHANGED
@@ -1815,3 +1815,8 @@ The exit suffix requires at least two playing clients, selects limits across the
1815
  ## 2026-10-27 — RE-829 Rust source exit-limit selection and first-winner policy
1816
 
1817
  Rust matches all125 source suffix decisions, including nonzero negative limits, playing-count gates and configured low-mode scans. Focused `cargo xtask test-group rust-exit-limits` passes (9 Python tests); selected reports regenerate twice deterministically, with storage, documentation links and whitespace guards. Full suite deferred to task ten. Original assets unchanged; source fixtures do not establish complete native/runtime parity.
 
 
 
 
 
 
1815
  ## 2026-10-27 — RE-829 Rust source exit-limit selection and first-winner policy
1816
 
1817
  Rust matches all125 source suffix decisions, including nonzero negative limits, playing-count gates and configured low-mode scans. Focused `cargo xtask test-group rust-exit-limits` passes (9 Python tests); selected reports regenerate twice deterministically, with storage, documentation links and whitespace guards. Full suite deferred to task ten. Original assets unchanged; source fixtures do not establish complete native/runtime parity.
1818
+
1819
+
1820
+ ## 2026-10-27 — RE-830 Original exit timers round priority and mode9 reset effects
1821
+
1822
+ The active round gate bypasses time-limit evaluation; expired mode9 time limits reset qualifying clients and populate supplied event records before exit requests. Focused `cargo xtask test-group exit-timers` passes (5 Python tests); selected reports regenerate twice deterministically, with storage, documentation links and whitespace guards. Full suite deferred to task ten. Original assets unchanged; source fixtures do not establish complete native/runtime parity.
docs/REVERSE_ENGINEERING_TODO.md CHANGED
@@ -1537,3 +1537,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
1537
 
1538
 
1539
  - [x] RE-829 Rust source exit-limit selection and first-winner policy ([evidence](research/RUST_EXIT_LIMITS.md)).
 
 
 
 
1537
 
1538
 
1539
  - [x] RE-829 Rust source exit-limit selection and first-winner policy ([evidence](research/RUST_EXIT_LIMITS.md)).
1540
+
1541
+
1542
+ - [x] RE-830 Original exit timers round priority and mode9 reset effects ([evidence](research/QVM_EXIT_TIMERS.md)).
docs/research/QVM_EXIT_TIMERS.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Original exit timers round priority and mode9 reset effects
2
+
3
+ RE-830. Reproduce with `python3 scripts/analyze_qvm_exit_timers.py`; focused validation: `cargo xtask test-group exit-timers`. [Machine report](qvm-exit-timers.json).
4
+
5
+ 116 source timer fixtures cover threshold equality, pause/countdown suppression, signed clock/multiply wrap, raw round limits and collected-client scan bounds. Independent models verify all five reset fields, log ordering and event owner/time/flag writes. Event allocation and child transition/native effects remain explicit captures, and the stage stops before limit suffixes when no timer fires.
6
+
7
+ Original executable/native runtime and complete Linux/macOS Rust/Bevy/Solari acceptance remain unverified.
docs/research/README.md CHANGED
@@ -1077,3 +1077,6 @@ The extension collector adds five focused tests for native tail calls, command-r
1077
 
1078
 
1079
  [RE-829: Rust source exit-limit selection and first-winner policy](RUST_EXIT_LIMITS.md).
 
 
 
 
1077
 
1078
 
1079
  [RE-829: Rust source exit-limit selection and first-winner policy](RUST_EXIT_LIMITS.md).
1080
+
1081
+
1082
+ [RE-830: Original exit timers round priority and mode9 reset effects](QVM_EXIT_TIMERS.md).
docs/research/qvm-exit-timers.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_qvm_exit_timers.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import itertools
3
+ from pathlib import Path
4
+ from qvm_research_support import source
5
+ from qvm_exit_rules_support import seed,run,FIELDS,CPOOL
6
+ from analyze_qvm import write_json
7
+ CLIENTS=[]
8
+ for j in range(7):
9
+ c={str(o):0 for o in FIELDS};c.update({'468':2,'3096':0,'140':j,'304':1,'308':700,'300':0xaabbccff,'3692':1,'3700':123});CLIENTS.append(c)
10
+ CLIENTS[1]['468']=1;CLIENTS[2]['3096']=1;CLIENTS[3]['3692']=0;CLIENTS[4]['304']=0;CLIENTS[5]['304']=-1;CLIENTS[6]['3692']=-1
11
+
12
+ def cases():
13
+ rows=[]
14
+ for limit,active,count,window,mode in itertools.product([0,1,3],[0,1],[0,2,3],[0,1],[0,9]):rows.append(dict(mode=mode,now=120000,start=0,time_limit=1,round_limit=limit,round_active=active,round_count=count,countdown=124500+window))
15
+ for limit,pause,mode,elapsed in itertools.product([-1,0,1],[0,1],[0,9],[59999,60000]):rows.append(dict(mode=mode,now=elapsed,start=0,time_limit=limit,paused=pause))
16
+ for mode,active,countdown in itertools.product([0,9],[0,1],[0,1]):rows.append(dict(mode=mode,now=60000,start=0,time_limit=1,round_active=active,countdown=countdown))
17
+ for mode in [0,9]:
18
+ for extra in [dict(time_limit=35792,now=0,start=0),dict(time_limit=-1,now=0,start=0),dict(time_limit=1,now=-2147483648,start=2147483647),dict(time_limit=1,now=2147483647,start=-2147483648)]:rows.append(dict(mode=mode,**extra))
19
+ for count in [0,1,3,7]:rows.append(dict(mode=9,now=60000,start=0,time_limit=1,client_count=count))
20
+ return rows
21
+
22
+ def main():
23
+ q,raw,h,ins=source();rows=[]
24
+ for a in cases():
25
+ m,p=run(ins,seed(CLIENTS,**a),7955,[8227]);p.update(input=a,clients_after=[{str(o):m[CPOOL+6336*j+o]&0xffffffff for o in FIELDS} for j in range(len(CLIENTS))]);rows.append(p)
26
+ write_json(Path('docs/research/qvm-exit-timers.json'),{'source':q['source'],'sha256':q['sha256'],'clients':CLIENTS,'probes':rows,'limits':'Actual7955..8226 timer branch after supplied7662==0. Round gate bypasses time-limit evaluation when active; signed wrapped subtract/multiply preserved. Mode9 qualifying records reset five fields and write supplied-allocation event records.277695 allocation and all log/format/send/transition children captured or supplied. Runtime ownership/native effects unverified.'})
27
+ if __name__=='__main__':main()
scripts/test_qvm_exit_timers.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy,json,unittest
2
+ from pathlib import Path
3
+ from qvm_exit_rules_support import TEXT
4
+ from qvm_notification_support import CPOOL,POOL
5
+
6
+ def signed(v):return (v+2**31)%2**32-2**31
7
+
8
+ def timer(a):
9
+ v=lambda k:a.get(k,0)
10
+ if v('round_limit')!=0 and v('round_active')!=0:return 'round' if v('round_count')>=v('round_limit') and signed(v('countdown')-4500)>signed(v('now')) else None
11
+ if v('time_limit')==0 or v('paused')!=0 or v('round_active')!=0 and v('countdown')==0:return None
12
+ return 'time' if signed(v('now')-v('start'))>=signed(v('time_limit')*60000) else None
13
+
14
+ def eligible(clients,count):return [j for j,c in enumerate(clients[:count]) if c['468']==2 and c['3096']==0 and c['3692']!=0 and c['304']>0]
15
+ class ExitTimerTests(unittest.TestCase):
16
+ @classmethod
17
+ def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-exit-timers.json').read_text())
18
+ def test_timer_gates_priority_and_exact_exit_requests(self):
19
+ self.assertEqual(len(self.r['probes']),116)
20
+ for p in self.r['probes']:
21
+ a=p['input'];hit=timer(a);tail=[] if hit is None else [{'target':-18,'arguments':{'8':-1,'12':34593 if hit=='round' else 34476}},{'target':7367,'arguments':{'8':34577 if hit=='round' else 34461}}];self.assertEqual(p['requests'][-2:] if hit else p['requests'],tail);self.assertEqual(p['execution']['stop'],8227 if hit is None else 8416)
22
+ def test_mode9_shared_resets_log_order_and_supplied_event_writes(self):
23
+ for p in self.r['probes']:
24
+ a=p['input'];ids=eligible(self.r['clients'],a.get('client_count',7)) if timer(a)=='time' and a['mode']==9 else [];out=[{k:v&0xffffffff for k,v in c.items()} for c in self.r['clients']]
25
+ for id in ids:
26
+ for o in ['304','308','3692','3700']:out[id][o]=0
27
+ out[id]['300']&=0xffffff00
28
+ self.assertEqual(p['clients_after'],out,a);self.assertEqual(len(p['events']),len(ids));self.assertEqual([r['arguments']['12'] for r in p['requests'] if r['target']==7259],ids)
29
+ for e,id in zip(p['events'],ids):self.assertEqual(e['fields'],{'140':100+id,'428':100+id,'84':a['now']&0xffffffff,'424':272})
30
+ for r,id in zip([r for r in p['requests'] if r['target']==277695],ids):self.assertEqual(r['arguments'],{'8':POOL+880*id+24,'12':69})
31
+ if __name__=='__main__':unittest.main()
xtask/checks.tsv CHANGED
@@ -2112,3 +2112,7 @@ report scripts/analyze_rust_exit_limits.py docs/research/rust-exit-limits.json
2112
  edge docs/research/rust-exit-limits.json scripts/test_rust_exit_limits.py
2113
  group rust-exit-limits scripts/analyze_rust_exit_limits.py
2114
  edge scripts/analyze_rust_exit_limits.py scripts/analyze_qvm_resumer_audit.py
 
 
 
 
 
2112
  edge docs/research/rust-exit-limits.json scripts/test_rust_exit_limits.py
2113
  group rust-exit-limits scripts/analyze_rust_exit_limits.py
2114
  edge scripts/analyze_rust_exit_limits.py scripts/analyze_qvm_resumer_audit.py
2115
+ report scripts/analyze_qvm_exit_timers.py docs/research/qvm-exit-timers.json
2116
+ edge docs/research/qvm-exit-timers.json scripts/test_qvm_exit_timers.py
2117
+ group exit-timers scripts/analyze_qvm_exit_timers.py
2118
+ edge scripts/analyze_qvm_exit_timers.py scripts/analyze_qvm_resumer_audit.py