nmarshall commited on
Commit
826c333
·
1 Parent(s): 29c0ea6

qvm: recover mixed ranking populations

Browse files
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(512):
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