qvm: recover mixed ranking populations
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_RANKING_POPULATION.md +9 -0
- docs/research/README.md +3 -0
- docs/research/qvm-ranking-population.json +0 -0
- scripts/analyze_qvm_ranking_population.py +25 -0
- scripts/qvm_rank_large_sort_support.py +1 -1
- scripts/qvm_trace_support.py +3 -2
- scripts/test_qvm_ranking_population.py +26 -0
- xtask/checks.tsv +6 -0
docs/FINDINGS.md
CHANGED
|
@@ -1376,3 +1376,6 @@ RE-780–789 exposes and bounds legacy resumer timing/byte-state flaws, migrates
|
|
| 1376 |
|
| 1377 |
|
| 1378 |
**RE-792:** 5864 now composes actual35095 sorting and rank writes over80 larger eligible populations with explicit publication captures. [Evidence](research/QVM_RANKING_LARGE_CALLER.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1376 |
|
| 1377 |
|
| 1378 |
**RE-792:** 5864 now composes actual35095 sorting and rank writes over80 larger eligible populations with explicit publication captures. [Evidence](research/QVM_RANKING_LARGE_CALLER.md).
|
| 1379 |
+
|
| 1380 |
+
|
| 1381 |
+
**RE-793:** Ranking count globals follow connection/team/bot gates, but deferred records can move active clients out of the positional prefix that receives rank words. [Evidence](research/QVM_RANKING_POPULATION.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1380,3 +1380,6 @@ RE-791: Both resumers can synchronize new and changed child words into byte lane
|
|
| 1380 |
|
| 1381 |
|
| 1382 |
RE-792: 5864 now composes actual35095 sorting and rank writes over80 larger eligible populations with explicit publication captures. Full runtime completion remains open. [Evidence](research/QVM_RANKING_LARGE_CALLER.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1380 |
|
| 1381 |
|
| 1382 |
RE-792: 5864 now composes actual35095 sorting and rank writes over80 larger eligible populations with explicit publication captures. Full runtime completion remains open. [Evidence](research/QVM_RANKING_LARGE_CALLER.md).
|
| 1383 |
+
|
| 1384 |
+
|
| 1385 |
+
RE-793: Ranking count globals follow connection/team/bot gates, but deferred records can move active clients out of the positional prefix that receives rank words. Full runtime completion remains open. [Evidence](research/QVM_RANKING_POPULATION.md).
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -1624,3 +1624,8 @@ Both resumers can synchronize new and changed child words into byte lanes withou
|
|
| 1624 |
## 2026-10-26 — RE-792 Complete ranking caller with actual partitioned sorting through64 clients
|
| 1625 |
|
| 1626 |
5864 now composes actual35095 sorting and rank writes over80 larger eligible populations with explicit publication captures. Focused `cargo xtask test-group ranking-large-caller` 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1624 |
## 2026-10-26 — RE-792 Complete ranking caller with actual partitioned sorting through64 clients
|
| 1625 |
|
| 1626 |
5864 now composes actual35095 sorting and rank writes over80 larger eligible populations with explicit publication captures. Focused `cargo xtask test-group ranking-large-caller` 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.
|
| 1627 |
+
|
| 1628 |
+
|
| 1629 |
+
## 2026-10-26 — RE-793 Mixed ranking populations and positional rank-prefix behavior
|
| 1630 |
+
|
| 1631 |
+
Ranking count globals follow connection/team/bot gates, but deferred records can move active clients out of the positional prefix that receives rank words. Focused `cargo xtask test-group ranking-population` passes (13 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
|
@@ -1426,3 +1426,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1426 |
|
| 1427 |
|
| 1428 |
- [x] RE-792 Complete ranking caller with actual partitioned sorting through64 clients ([evidence](research/QVM_RANKING_LARGE_CALLER.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 1426 |
|
| 1427 |
|
| 1428 |
- [x] RE-792 Complete ranking caller with actual partitioned sorting through64 clients ([evidence](research/QVM_RANKING_LARGE_CALLER.md)).
|
| 1429 |
+
|
| 1430 |
+
|
| 1431 |
+
- [x] RE-793 Mixed ranking populations and positional rank-prefix behavior ([evidence](research/QVM_RANKING_POPULATION.md)).
|
docs/research/QVM_RANKING_POPULATION.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Mixed ranking populations and positional rank-prefix behavior
|
| 2 |
+
|
| 3 |
+
RE-793. Reproduce with `python3 scripts/analyze_qvm_ranking_population.py`; focused validation: `cargo xtask test-group ranking-population`. [Machine report](qvm-ranking-population.json).
|
| 4 |
+
|
| 5 |
+
Sixty-four full caller fixtures cover empty and8/16/64-slot populations with connecting, disconnected, spectator, bot and deferred records. Independent tests verify collection membership, all eight globals, spectator-time order and source-prefix rank writes. The comparator prefilters are asymmetric, so mixed deferred/connecting populations are deliberately not treated as a Rust Ord domain. Source results remain evidence of bounded behavior, not proof that these synthetic states are legal live-game populations.
|
| 6 |
+
|
| 7 |
+
Original executable/native runtime and complete Linux/macOS Rust/Bevy/Solari acceptance remain unverified.
|
| 8 |
+
|
| 9 |
+
The64-record asymmetric comparator cases exceed the previous512 segment budget while still making finite source progress. The sort opts into4096 segments; the shared default stays512 and the configurable range is capped at8192. This is a bounded research allowance, not a native runtime complexity claim.
|
docs/research/README.md
CHANGED
|
@@ -966,3 +966,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 966 |
|
| 967 |
|
| 968 |
[RE-792: Complete ranking caller with actual partitioned sorting through64 clients](QVM_RANKING_LARGE_CALLER.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 966 |
|
| 967 |
|
| 968 |
[RE-792: Complete ranking caller with actual partitioned sorting through64 clients](QVM_RANKING_LARGE_CALLER.md).
|
| 969 |
+
|
| 970 |
+
|
| 971 |
+
[RE-793: Mixed ranking populations and positional rank-prefix behavior](QVM_RANKING_POPULATION.md).
|
docs/research/qvm-ranking-population.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_ranking_population.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
import itertools
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from qvm_research_support import source
|
| 5 |
+
from qvm_ranking_caller_support import ranking
|
| 6 |
+
from analyze_qvm import write_json
|
| 7 |
+
|
| 8 |
+
def population(n,pattern):
|
| 9 |
+
rows=[]
|
| 10 |
+
for j in range(n):
|
| 11 |
+
c={'468':j%3,'3096':1+(j//3)%3,'248':j%5,'280':j%3,'3032':j%2,'308':j%5,'696':j%3,'3104':n-j,'flags':8 if j%2 else 0}
|
| 12 |
+
if pattern=='spectators':c.update({'468':2,'3096':3})
|
| 13 |
+
if pattern=='inactive':c['468']=0
|
| 14 |
+
if pattern=='flags':c.update({'468':2,'3096':1+j%2})
|
| 15 |
+
if pattern=='deferred' and j%3==2:c['3108']=3 if j%2 else 0;c['3112']=-1 if not j%2 else 0
|
| 16 |
+
rows.append(c)
|
| 17 |
+
return rows
|
| 18 |
+
|
| 19 |
+
def main():
|
| 20 |
+
q,raw,h,ins=source();rows=[]
|
| 21 |
+
for mode,n,pattern in itertools.product([0,3,9,11],[8,16,64],['cycling','spectators','inactive','flags','deferred']):
|
| 22 |
+
p=ranking(ins,mode,population(n,pattern),[1,2],1)[1];p['pattern']=pattern;rows.append(p)
|
| 23 |
+
for mode in [0,3,9,11]:p=ranking(ins,mode,[],[0,0],1)[1];p['pattern']='empty';rows.append(p)
|
| 24 |
+
write_json(Path('docs/research/qvm-ranking-population.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'limits':'Complete5864 over64 mixed/empty population fixtures with actual sort. Active count and rank prefix differ in deferred fixtures: source ranks a positional prefix, not a freshly filtered active set. Connecting/deferred comparator results are not an Ord contract; no independent total-order claim is made for those raw cases. Publication remains captured.'})
|
| 25 |
+
if __name__=='__main__':main()
|
scripts/qvm_rank_large_sort_support.py
CHANGED
|
@@ -10,5 +10,5 @@ def sort(ins,m,args,depth=0):
|
|
| 10 |
for o,v in args.items():m[base+116+o]=v
|
| 11 |
before=[m[args[8]+4*j]&0xffffffff for j in range(args[12])]
|
| 12 |
def recursive(i,m,a):return sort(i,m,a,depth+1)
|
| 13 |
-
m,e=resume(ins,35096,36036,m,base,handlers={5441:compare,34829:swap,34964:median,35095:recursive},result_offsets={35229:80,35560:88,35644:96,35810:88},repeated_calls=True,limit=16384)
|
| 14 |
return m,0,{'arguments':args,'initial':before,'final':[m[args[8]+4*j]&0xffffffff for j in range(args[12])],'depth':depth,'callback_after':m[base+136],'execution':e}
|
|
|
|
| 10 |
for o,v in args.items():m[base+116+o]=v
|
| 11 |
before=[m[args[8]+4*j]&0xffffffff for j in range(args[12])]
|
| 12 |
def recursive(i,m,a):return sort(i,m,a,depth+1)
|
| 13 |
+
m,e=resume(ins,35096,36036,m,base,handlers={5441:compare,34829:swap,34964:median,35095:recursive},result_offsets={35229:80,35560:88,35644:96,35810:88},repeated_calls=True,limit=16384,segment_limit=4096)
|
| 14 |
return m,0,{'arguments':args,'initial':before,'final':[m[args[8]+4*j]&0xffffffff for j in range(args[12])],'depth':depth,'callback_after':m[base+136],'execution':e}
|
scripts/qvm_trace_support.py
CHANGED
|
@@ -3,12 +3,13 @@ from analyze_deferred_auth import trace_slice
|
|
| 3 |
from analyze_bsp_references import trace_fields
|
| 4 |
from qvm_call_result_support import patch_result
|
| 5 |
|
| 6 |
-
def resume(ins,start,stop,m,base,pc=None,handlers=None,boundaries=(),byte_inputs=None,limit=8192,result_offsets=None,repeated_calls=False,sync_child_words=False):
|
|
|
|
| 7 |
from qvm_child_memory_support import sync_words
|
| 8 |
if sync_child_words and not repeated_calls:raise ValueError('child synchronization requires corrected reentry')
|
| 9 |
handlers=handlers or {};pc=start if pc is None else pc;m=dict(m);trace=[];calls=[];children=[];writes=[];bytes_map=dict(byte_inputs or {});ret=None
|
| 10 |
points=[i['index']+2 for i in ins[start:stop] if i['opcode']=='CALL']+list(boundaries)
|
| 11 |
-
for _ in range(
|
| 12 |
t=trace_slice(ins,start,stop,m,{},resume_at=pc,stop_targets=points if repeated_calls else [p for p in points if p!=pc],local_base=base,byte_memory=bytes_map,halt_on_leave=True,capture_stack=True,limit=limit,skip_initial_stop=repeated_calls);m=t['memory'];pc=t.get('stop',stop);trace+=t['trace'];calls+=t['calls'];writes+=t['byte_writes'];bytes_map=t['byte_memory']
|
| 13 |
if repeated_calls and t['calls'] and t['stack'] and not (t['trace'] and ins[t['trace'][-1]]['opcode']=='LEAVE'):
|
| 14 |
raise ValueError('nonempty bounded CALL return boundary')
|
|
|
|
| 3 |
from analyze_bsp_references import trace_fields
|
| 4 |
from qvm_call_result_support import patch_result
|
| 5 |
|
| 6 |
+
def resume(ins,start,stop,m,base,pc=None,handlers=None,boundaries=(),byte_inputs=None,limit=8192,result_offsets=None,repeated_calls=False,sync_child_words=False,segment_limit=512):
|
| 7 |
+
if type(segment_limit) is not int or not 1<=segment_limit<=8192:raise ValueError('invalid bounded segment budget')
|
| 8 |
from qvm_child_memory_support import sync_words
|
| 9 |
if sync_child_words and not repeated_calls:raise ValueError('child synchronization requires corrected reentry')
|
| 10 |
handlers=handlers or {};pc=start if pc is None else pc;m=dict(m);trace=[];calls=[];children=[];writes=[];bytes_map=dict(byte_inputs or {});ret=None
|
| 11 |
points=[i['index']+2 for i in ins[start:stop] if i['opcode']=='CALL']+list(boundaries)
|
| 12 |
+
for _ in range(segment_limit):
|
| 13 |
t=trace_slice(ins,start,stop,m,{},resume_at=pc,stop_targets=points if repeated_calls else [p for p in points if p!=pc],local_base=base,byte_memory=bytes_map,halt_on_leave=True,capture_stack=True,limit=limit,skip_initial_stop=repeated_calls);m=t['memory'];pc=t.get('stop',stop);trace+=t['trace'];calls+=t['calls'];writes+=t['byte_writes'];bytes_map=t['byte_memory']
|
| 14 |
if repeated_calls and t['calls'] and t['stack'] and not (t['trace'] and ins[t['trace'][-1]]['opcode']=='LEAVE'):
|
| 15 |
raise ValueError('nonempty bounded CALL return boundary')
|
scripts/test_qvm_ranking_population.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from test_qvm_ranking_large_caller import ranks
|
| 4 |
+
|
| 5 |
+
def globals_for(c):
|
| 6 |
+
connected=[j for j,v in enumerate(c) if v.get('468',2)!=0];nonspec=[j for j in connected if c[j].get('3096',1)!=3];playing=[j for j in nonspec if c[j].get('468',2)==2];humans=[j for j in playing if not c[j].get('flags',0)&8];first=(playing+[-1,-1])[:2]
|
| 7 |
+
return {'34992848':first[0],'34992852':first[1],'34992580':len(connected),'34992584':len(nonspec),'34992588':len(playing),'34994928':len(humans),'34997012':sum(c[j].get('3096',1)==1 for j in humans),'34997016':sum(c[j].get('3096',1)==2 for j in humans)}
|
| 8 |
+
class RankingPopulationTests(unittest.TestCase):
|
| 9 |
+
@classmethod
|
| 10 |
+
def setUpClass(cls):cls.ps=json.loads(Path('docs/research/qvm-ranking-population.json').read_text())['probes']
|
| 11 |
+
def test_independent_scan_membership_and_globals(self):
|
| 12 |
+
self.assertEqual(len(self.ps),64)
|
| 13 |
+
for p in self.ps:
|
| 14 |
+
c=p['input']['clients'];self.assertEqual(p['globals'],globals_for(c));self.assertEqual(sorted(p['order']),[j for j,v in enumerate(c) if v.get('468',2)!=0]);self.assertEqual(p['execution']['stop'],6326)
|
| 15 |
+
def test_rank_assignment_uses_source_prefix_not_recomputed_active_filter(self):
|
| 16 |
+
for p in self.ps:
|
| 17 |
+
a=p['input'];self.assertEqual(p['ranks'],ranks(a['mode'],a['clients'],p['order'],a['team_scores'],playing=p['globals']['34992588']))
|
| 18 |
+
def test_inactive_ranks_preserved_and_spectator_time_order(self):
|
| 19 |
+
for p in self.ps:
|
| 20 |
+
c=p['input']['clients']
|
| 21 |
+
for j,v in enumerate(c):
|
| 22 |
+
if v.get('468',2)==0:self.assertEqual(p['ranks'][j],77)
|
| 23 |
+
if p['pattern']=='spectators':self.assertEqual(p['order'],list(reversed(range(len(c)))))
|
| 24 |
+
def test_deferred_rank_prefix_mismatch_is_recorded(self):
|
| 25 |
+
self.assertTrue(any(set(p['order'][:p['globals']['34992588']])!={j for j,c in enumerate(p['input']['clients']) if c['468']==2 and c['3096']!=3} for p in self.ps if p['pattern']=='deferred'))
|
| 26 |
+
if __name__=='__main__':unittest.main()
|
xtask/checks.tsv
CHANGED
|
@@ -1786,3 +1786,9 @@ edge docs/research/qvm-ranking-large-caller.json scripts/test_qvm_ranking_large_
|
|
| 1786 |
group ranking-large-caller scripts/analyze_qvm_ranking_large_caller.py
|
| 1787 |
edge scripts/analyze_qvm_ranking_large_caller.py scripts/analyze_qvm_resumer_audit.py
|
| 1788 |
edge scripts/qvm_ranking_caller_support.py scripts/analyze_qvm_resumer_audit.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1786 |
group ranking-large-caller scripts/analyze_qvm_ranking_large_caller.py
|
| 1787 |
edge scripts/analyze_qvm_ranking_large_caller.py scripts/analyze_qvm_resumer_audit.py
|
| 1788 |
edge scripts/qvm_ranking_caller_support.py scripts/analyze_qvm_resumer_audit.py
|
| 1789 |
+
report scripts/analyze_qvm_ranking_population.py docs/research/qvm-ranking-population.json
|
| 1790 |
+
edge docs/research/qvm-ranking-population.json scripts/test_qvm_ranking_population.py
|
| 1791 |
+
group ranking-population scripts/analyze_qvm_ranking_population.py
|
| 1792 |
+
edge scripts/analyze_qvm_ranking_population.py scripts/analyze_qvm_resumer_audit.py
|
| 1793 |
+
|
| 1794 |
+
group ranking-population scripts/analyze_qvm_rank_large_sort.py
|