nmarshall commited on
Commit
182167b
·
1 Parent(s): e0c5881

gameplay: compose eligible ranking

Browse files
crates/urt-gameplay/src/bin/urt-lifecycle.rs CHANGED
@@ -328,6 +328,29 @@ fn run() -> Result<(), String> {
328
  second.cached_ping as u32
329
  );
330
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  "rank-sort" if w.len() >= 2 && w[1] <= 64 => {
332
  let n = w[1] as usize;
333
  if w.len() != 2 + 11 * n {
@@ -363,7 +386,7 @@ fn run() -> Result<(), String> {
363
  urt_gameplay::ranking::compare(w[0] as i32, client(&w[1..11]), client(&w[11..]))
364
  );
365
  }
366
- "rank-words" if w.len() >= 4 && w[3] <= 6 => {
367
  let n = w[3] as usize;
368
  if w.len() != 4 + 11 * n {
369
  return Err("invalid ranking words".into());
 
328
  second.cached_ping as u32
329
  );
330
  }
331
+ "rank-compose" if w.len() >= 4 && w[3] <= 64 => {
332
+ let n = w[3] as usize;
333
+ if w.len() != 4 + 10 * n {
334
+ return Err("invalid composed ranking words".into());
335
+ }
336
+ let clients: Vec<_> = w[4..].chunks_exact(10).map(ranking_client).collect();
337
+ let (order, ranks) =
338
+ urt_gameplay::ranking::ranked(w[0] as i32, &clients, [w[1] as i32, w[2] as i32])
339
+ .map_err(|e| format!("unsupported input: {e:?}"))?;
340
+ println!(
341
+ "{{\"order\":[{}],\"ranks\":[{}]}}",
342
+ order
343
+ .iter()
344
+ .map(|v| v.to_string())
345
+ .collect::<Vec<_>>()
346
+ .join(","),
347
+ ranks
348
+ .iter()
349
+ .map(|v| v.to_string())
350
+ .collect::<Vec<_>>()
351
+ .join(",")
352
+ );
353
+ }
354
  "rank-sort" if w.len() >= 2 && w[1] <= 64 => {
355
  let n = w[1] as usize;
356
  if w.len() != 2 + 11 * n {
 
386
  urt_gameplay::ranking::compare(w[0] as i32, client(&w[1..11]), client(&w[11..]))
387
  );
388
  }
389
+ "rank-words" if w.len() >= 4 && w[3] <= 64 => {
390
  let n = w[3] as usize;
391
  if w.len() != 4 + 11 * n {
392
  return Err("invalid ranking words".into());
crates/urt-gameplay/src/ranking.rs CHANGED
@@ -74,7 +74,7 @@ pub enum RankError {
74
  InvalidOrder,
75
  }
76
  /// Caller supplies a complete ordering. This primitive does not execute a sort
77
- /// or publication callbacks. Source parity fixtures use eligible n<7 clients.
78
  pub fn rank_words(
79
  mode: i32,
80
  clients: &[Client],
@@ -132,6 +132,18 @@ pub fn rank_words(
132
  }
133
  Ok(result)
134
  }
 
 
 
 
 
 
 
 
 
 
 
 
135
  #[cfg(test)]
136
  mod tests {
137
  use super::*;
@@ -150,6 +162,24 @@ mod tests {
150
  }
151
  }
152
  #[test]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  fn raw_prefilter_quirks_remain_nonordering() {
154
  let c = Client {
155
  spectator_state: 3,
 
74
  InvalidOrder,
75
  }
76
  /// Caller supplies a complete ordering. This primitive does not execute a sort
77
+ /// or publication callbacks. Source parity fixtures include eligible populations through64 clients.
78
  pub fn rank_words(
79
  mode: i32,
80
  clients: &[Client],
 
132
  }
133
  Ok(result)
134
  }
135
+ /// Complete eligible-client sorting and rank-word composition. Publication
136
+ /// callbacks and runtime/global ownership remain the caller's responsibility.
137
+ pub fn ranked(
138
+ mode: i32,
139
+ clients: &[Client],
140
+ scores: [i32; 2],
141
+ ) -> Result<(Vec<usize>, Vec<u32>), RankError> {
142
+ let mut order: Vec<_> = (0..clients.len()).collect();
143
+ crate::rank_sort::sort(mode, clients, &mut order)?;
144
+ let ranks = rank_words(mode, clients, &order, scores)?;
145
+ Ok((order, ranks))
146
+ }
147
  #[cfg(test)]
148
  mod tests {
149
  use super::*;
 
162
  }
163
  }
164
  #[test]
165
+ fn composed_rank_sort_handles64_and_global_team_result() {
166
+ let c: Vec<_> = (0..64)
167
+ .map(|j| Client {
168
+ score: j % 2,
169
+ ..client()
170
+ })
171
+ .collect();
172
+ let (order, ranks) = ranked(0, &c, [0, 0]).unwrap();
173
+ assert!(order[..32].iter().all(|j| j % 2 == 1));
174
+ assert!(
175
+ ranks
176
+ .iter()
177
+ .enumerate()
178
+ .all(|(j, &v)| v == if j % 2 == 1 { 16384 } else { 16384 | 32 })
179
+ );
180
+ assert_eq!(ranked(3, &c, [1, 2]).unwrap().1, vec![1; 64]);
181
+ }
182
+ #[test]
183
  fn raw_prefilter_quirks_remain_nonordering() {
184
  let c = Client {
185
  spectator_state: 3,
docs/FINDINGS.md CHANGED
@@ -1382,3 +1382,6 @@ RE-780–789 exposes and bounds legacy resumer timing/byte-state flaws, migrates
1382
 
1383
 
1384
  **RE-794:** Rust now executes the recovered insertion/partition/median/ninther sort without assuming comparator Ord; source parity includes unstable tie permutations. [Evidence](research/RUST_RANK_SORT.md).
 
 
 
 
1382
 
1383
 
1384
  **RE-794:** Rust now executes the recovered insertion/partition/median/ninther sort without assuming comparator Ord; source parity includes unstable tie permutations. [Evidence](research/RUST_RANK_SORT.md).
1385
+
1386
+
1387
+ **RE-795:** Rust composes recovered source sorting and rank writes, matching exact order and tied/team rank words for128 full caller fixtures. [Evidence](research/RUST_RANKING_COMPLETE.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -1386,3 +1386,6 @@ RE-793: Ranking count globals follow connection/team/bot gates, but deferred rec
1386
 
1387
 
1388
  RE-794: Rust now executes the recovered insertion/partition/median/ninther sort without assuming comparator Ord; source parity includes unstable tie permutations. Full runtime completion remains open. [Evidence](research/RUST_RANK_SORT.md).
 
 
 
 
1386
 
1387
 
1388
  RE-794: Rust now executes the recovered insertion/partition/median/ninther sort without assuming comparator Ord; source parity includes unstable tie permutations. Full runtime completion remains open. [Evidence](research/RUST_RANK_SORT.md).
1389
+
1390
+
1391
+ RE-795: Rust composes recovered source sorting and rank writes, matching exact order and tied/team rank words for128 full caller fixtures. Full runtime completion remains open. [Evidence](research/RUST_RANKING_COMPLETE.md).
docs/RESEARCH_LEDGER.md CHANGED
@@ -1634,3 +1634,8 @@ Ranking count globals follow connection/team/bot gates, but deferred records can
1634
  ## 2026-10-26 — RE-794 Rust source-shaped aligned ranking sort with exact tie order
1635
 
1636
  Rust now executes the recovered insertion/partition/median/ninther sort without assuming comparator Ord; source parity includes unstable tie permutations. Focused `cargo xtask test-group rust-rank-sort` 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.
 
 
 
 
 
 
1634
  ## 2026-10-26 — RE-794 Rust source-shaped aligned ranking sort with exact tie order
1635
 
1636
  Rust now executes the recovered insertion/partition/median/ninther sort without assuming comparator Ord; source parity includes unstable tie permutations. Focused `cargo xtask test-group rust-rank-sort` 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.
1637
+
1638
+
1639
+ ## 2026-10-26 — RE-795 Rust eligible ranking composition through64 clients
1640
+
1641
+ Rust composes recovered source sorting and rank writes, matching exact order and tied/team rank words for128 full caller fixtures. Focused `cargo xtask test-group rust-ranking-complete` 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.
docs/REVERSE_ENGINEERING_TODO.md CHANGED
@@ -1432,3 +1432,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
1432
 
1433
 
1434
  - [x] RE-794 Rust source-shaped aligned ranking sort with exact tie order ([evidence](research/RUST_RANK_SORT.md)).
 
 
 
 
1432
 
1433
 
1434
  - [x] RE-794 Rust source-shaped aligned ranking sort with exact tie order ([evidence](research/RUST_RANK_SORT.md)).
1435
+
1436
+
1437
+ - [x] RE-795 Rust eligible ranking composition through64 clients ([evidence](research/RUST_RANKING_COMPLETE.md)).
docs/research/README.md CHANGED
@@ -972,3 +972,6 @@ The extension collector adds five focused tests for native tail calls, command-r
972
 
973
 
974
  [RE-794: Rust source-shaped aligned ranking sort with exact tie order](RUST_RANK_SORT.md).
 
 
 
 
972
 
973
 
974
  [RE-794: Rust source-shaped aligned ranking sort with exact tie order](RUST_RANK_SORT.md).
975
+
976
+
977
+ [RE-795: Rust eligible ranking composition through64 clients](RUST_RANKING_COMPLETE.md).
docs/research/RUST_RANKING_COMPLETE.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Rust eligible ranking composition through64 clients
2
+
3
+ RE-795. Reproduce with `python3 scripts/analyze_rust_ranking_complete.py`; focused validation: `cargo xtask test-group rust-ranking-complete`. [Machine report](rust-ranking-complete.json).
4
+
5
+ The public ranked function owns sorting rather than requiring a precomputed order. Source parity covers both earlier48 small and80 larger caller fixtures, including zero participants, partial ties, all team-score outcomes and mode-specific keys. A64-client unit test independently checks tied ranks and team results. The CLI rank-word primitive accepts the now-verified larger eligible domain. Mixed-population collection and publication/native side effects remain separate contracts.
6
+
7
+ Original executable/native runtime and complete Linux/macOS Rust/Bevy/Solari acceptance remain unverified.
docs/research/rust-health-impulse.json CHANGED
@@ -2985,7 +2985,7 @@
2985
  "exit_code": 2
2986
  }
2987
  ],
2988
- "rust_unit_tests": 57,
2989
  "source_report": "docs/research/qvm-health-impulse.json",
2990
  "source_report_sha256": "625fd8064004ea6dbdf398d51d0af844d9c635ff04c0a0790886dddb6ab81e71"
2991
  }
 
2985
  "exit_code": 2
2986
  }
2987
  ],
2988
+ "rust_unit_tests": 58,
2989
  "source_report": "docs/research/qvm-health-impulse.json",
2990
  "source_report_sha256": "625fd8064004ea6dbdf398d51d0af844d9c635ff04c0a0790886dddb6ab81e71"
2991
  }
docs/research/rust-ranking-complete.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_rust_ranking_complete.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import hashlib,json
3
+ from pathlib import Path
4
+ from analyze_rust_ranking import words
5
+ from rust_lifecycle_support import binary,result,invoke
6
+ from analyze_qvm import write_json
7
+
8
+ def main():
9
+ b=binary();rows=[];sources={}
10
+ for name in ['qvm-ranking-complete','qvm-ranking-large-caller']:
11
+ p=Path('docs/research/'+name+'.json');data=p.read_bytes();sources[str(p)]=hashlib.sha256(data).hexdigest()
12
+ for row in json.loads(data)['probes']:
13
+ a=row['input'];c=a['clients'];rows.append({'input':a,'source_order':row['order'],'source_ranks':row['ranks'],'rust':result(b,'rank-compose',[a['mode'],*a['team_scores'],len(c),*[v for client in c for v in words(client)]])})
14
+ bad=invoke(b,'rank-compose',[0,0,0,1,*words({'3096':3})],check=False);assert bad.returncode
15
+ write_json(Path('docs/research/rust-ranking-complete.json'),{'source_reports':sources,'probes':rows,'rejections':[bad.returncode],'limits':'Rust source sort plus rank words matches128 complete5864 eligible compositions through64 clients, exact order and rank flags. Publication, collection of mixed clients and native/runtime ownership excluded.'})
16
+ if __name__=='__main__':main()
scripts/test_rust_ranking_complete.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import hashlib,json,unittest
2
+ from pathlib import Path
3
+ from test_qvm_ranking_large_caller import ranks
4
+ class RustRankingCompleteTests(unittest.TestCase):
5
+ def test_source_order_rank_and_independent_tie_oracle(self):
6
+ ps=json.loads(Path('docs/research/rust-ranking-complete.json').read_text())['probes'];self.assertEqual(len(ps),128)
7
+ for p in ps:a=p['input'];self.assertEqual(p['rust']['order'],p['source_order']);self.assertEqual(p['rust']['ranks'],p['source_ranks']);self.assertEqual(p['rust']['ranks'],ranks(a['mode'],a['clients'],p['source_order'],a['team_scores']))
8
+ def test_identity_and_unsupported_domain(self):
9
+ r=json.loads(Path('docs/research/rust-ranking-complete.json').read_text())
10
+ for p,h in r['source_reports'].items():self.assertEqual(hashlib.sha256(Path(p).read_bytes()).hexdigest(),h)
11
+ self.assertTrue(all(r['rejections']))
12
+ if __name__=='__main__':unittest.main()
xtask/checks.tsv CHANGED
@@ -1807,3 +1807,16 @@ report scripts/analyze_rust_rank_sort.py docs/research/rust-rank-sort.json
1807
  edge docs/research/rust-rank-sort.json scripts/test_rust_rank_sort.py
1808
  group rust-rank-sort scripts/analyze_rust_rank_sort.py
1809
  edge scripts/analyze_rust_rank_sort.py scripts/analyze_qvm_resumer_audit.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1807
  edge docs/research/rust-rank-sort.json scripts/test_rust_rank_sort.py
1808
  group rust-rank-sort scripts/analyze_rust_rank_sort.py
1809
  edge scripts/analyze_rust_rank_sort.py scripts/analyze_qvm_resumer_audit.py
1810
+ edge Cargo.toml scripts/analyze_rust_ranking_complete.py
1811
+ edge Cargo.lock scripts/analyze_rust_ranking_complete.py
1812
+ edge crates/urt-gameplay/Cargo.toml scripts/analyze_rust_ranking_complete.py
1813
+ edge crates/urt-gameplay/src/lib.rs scripts/analyze_rust_ranking_complete.py
1814
+ edge crates/urt-gameplay/src/bin/urt-lifecycle.rs scripts/analyze_rust_ranking_complete.py
1815
+ edge crates/urt-gameplay/src/rank_sort.rs scripts/analyze_rust_ranking_complete.py
1816
+ edge crates/urt-gameplay/src/ranking.rs scripts/analyze_rust_ranking_complete.py
1817
+ group gameplay scripts/analyze_rust_ranking_complete.py
1818
+ group rust-ranking-complete scripts/analyze_rust_health_impulse.py
1819
+ report scripts/analyze_rust_ranking_complete.py docs/research/rust-ranking-complete.json
1820
+ edge docs/research/rust-ranking-complete.json scripts/test_rust_ranking_complete.py
1821
+ group rust-ranking-complete scripts/analyze_rust_ranking_complete.py
1822
+ edge scripts/analyze_rust_ranking_complete.py scripts/analyze_qvm_resumer_audit.py