qvm: recover exit timers and reset effects
Browse files- 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_EXIT_TIMERS.md +7 -0
- docs/research/README.md +3 -0
- docs/research/qvm-exit-timers.json +0 -0
- scripts/analyze_qvm_exit_timers.py +27 -0
- scripts/test_qvm_exit_timers.py +31 -0
- xtask/checks.tsv +4 -0
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
|