gameplay: port post-map client callbacks
Browse files- crates/urt-gameplay/src/bin/urt-native-policy.rs +29 -0
- crates/urt-gameplay/src/native_policy.rs +68 -0
- 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/README.md +3 -0
- docs/research/RUST_POST_MAP_CLIENTS.md +7 -0
- docs/research/rust-health-impulse.json +1 -1
- docs/research/rust-post-map-clients.json +0 -0
- scripts/analyze_rust_post_map_clients.py +14 -0
- scripts/test_rust_post_map_clients.py +9 -0
- xtask/checks.tsv +13 -0
crates/urt-gameplay/src/bin/urt-native-policy.rs
CHANGED
|
@@ -70,6 +70,35 @@ fn run() -> Result<String, String> {
|
|
| 70 |
nested(&end)
|
| 71 |
))
|
| 72 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
_ => Err("unknown command".into()),
|
| 74 |
}
|
| 75 |
}
|
|
|
|
| 70 |
nested(&end)
|
| 71 |
))
|
| 72 |
}
|
| 73 |
+
"post" => {
|
| 74 |
+
if w.len() != 66 {
|
| 75 |
+
return Err("invalid post input".into());
|
| 76 |
+
}
|
| 77 |
+
let mut c = w[2..].iter().map(|v| *v as i32).collect::<Vec<_>>();
|
| 78 |
+
let mut calls = vec![];
|
| 79 |
+
post_map_clients(&mut c, w[0] as i32, |kind, j, c| {
|
| 80 |
+
let t = if kind == PostMapChild::First {
|
| 81 |
+
246746
|
| 82 |
+
} else {
|
| 83 |
+
246963
|
| 84 |
+
};
|
| 85 |
+
calls.push(vec![t, j as u32, c[j] as u32]);
|
| 86 |
+
if kind == PostMapChild::First {
|
| 87 |
+
if w[1] == 1 {
|
| 88 |
+
c[j] = 0
|
| 89 |
+
}
|
| 90 |
+
if w[1] == 2 && j + 1 < c.len() {
|
| 91 |
+
c[j + 1] = 2
|
| 92 |
+
}
|
| 93 |
+
}
|
| 94 |
+
})
|
| 95 |
+
.map_err(|e| format!("{e:?}"))?;
|
| 96 |
+
Ok(format!(
|
| 97 |
+
"{{\"calls\":{},\"after\":{}}}",
|
| 98 |
+
nested(&calls),
|
| 99 |
+
list(&c.iter().map(|v| *v as u32).collect::<Vec<_>>())
|
| 100 |
+
))
|
| 101 |
+
}
|
| 102 |
_ => Err("unknown command".into()),
|
| 103 |
}
|
| 104 |
}
|
crates/urt-gameplay/src/native_policy.rs
CHANGED
|
@@ -138,3 +138,71 @@ mod breed_tests {
|
|
| 138 |
assert_eq!(b, before);
|
| 139 |
}
|
| 140 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
assert_eq!(b, before);
|
| 139 |
}
|
| 140 |
}
|
| 141 |
+
|
| 142 |
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
| 143 |
+
pub enum PostMapChild {
|
| 144 |
+
First,
|
| 145 |
+
Second,
|
| 146 |
+
}
|
| 147 |
+
/// Check connection at iteration entry; callbacks may change this or later slots.
|
| 148 |
+
/// Count/base pointer are held stable in this typed subset.
|
| 149 |
+
pub fn post_map_clients<F>(clients: &mut [i32], count: i32, mut callback: F) -> Result<(), Error>
|
| 150 |
+
where
|
| 151 |
+
F: FnMut(PostMapChild, usize, &mut [i32]),
|
| 152 |
+
{
|
| 153 |
+
let count = count.max(0) as usize;
|
| 154 |
+
if clients.len() > 64 || count > clients.len() {
|
| 155 |
+
return Err(Error::InvalidCount);
|
| 156 |
+
}
|
| 157 |
+
for j in 0..count {
|
| 158 |
+
if clients[j] == 2 {
|
| 159 |
+
callback(PostMapChild::First, j, clients);
|
| 160 |
+
callback(PostMapChild::Second, j, clients);
|
| 161 |
+
}
|
| 162 |
+
}
|
| 163 |
+
Ok(())
|
| 164 |
+
}
|
| 165 |
+
#[cfg(test)]
|
| 166 |
+
mod post_tests {
|
| 167 |
+
use super::*;
|
| 168 |
+
#[test]
|
| 169 |
+
fn second_call_survives_disconnect_and_later_activation() {
|
| 170 |
+
let mut c = [2, 0];
|
| 171 |
+
let mut calls = vec![];
|
| 172 |
+
post_map_clients(&mut c, 2, |kind, j, c| {
|
| 173 |
+
calls.push((kind, j, c[j]));
|
| 174 |
+
if kind == PostMapChild::First {
|
| 175 |
+
c[j] = 0;
|
| 176 |
+
if j == 0 {
|
| 177 |
+
c[1] = 2
|
| 178 |
+
}
|
| 179 |
+
}
|
| 180 |
+
})
|
| 181 |
+
.unwrap();
|
| 182 |
+
assert_eq!(
|
| 183 |
+
calls,
|
| 184 |
+
[
|
| 185 |
+
(PostMapChild::First, 0, 2),
|
| 186 |
+
(PostMapChild::Second, 0, 0),
|
| 187 |
+
(PostMapChild::First, 1, 2),
|
| 188 |
+
(PostMapChild::Second, 1, 0)
|
| 189 |
+
]
|
| 190 |
+
);
|
| 191 |
+
}
|
| 192 |
+
#[test]
|
| 193 |
+
fn invalid_count_never_calls() {
|
| 194 |
+
let mut c = [2];
|
| 195 |
+
let mut called = false;
|
| 196 |
+
assert_eq!(
|
| 197 |
+
post_map_clients(&mut c, 2, |_, _, _| called = true),
|
| 198 |
+
Err(Error::InvalidCount)
|
| 199 |
+
);
|
| 200 |
+
assert!(!called);
|
| 201 |
+
assert_eq!(c, [2]);
|
| 202 |
+
assert_eq!(
|
| 203 |
+
post_map_clients(&mut c, -1, |_, _, _| called = true),
|
| 204 |
+
Ok(())
|
| 205 |
+
);
|
| 206 |
+
assert!(!called);
|
| 207 |
+
}
|
| 208 |
+
}
|
docs/FINDINGS.md
CHANGED
|
@@ -1634,3 +1634,6 @@ RE-813–822 replaces the scoreboard decimal assumption with actual37914 executi
|
|
| 1634 |
|
| 1635 |
|
| 1636 |
**RE-878:** 72 actual249007 cases recover signed live client-count iteration and connected-state2 gating. Each accepted client calls246746 then246963 unconditionally; a supplied first-child disconnect does not suppress its second child, and activation of a later slot affects subsequent dispatch. This uses level count34992524, not max-clients cvar34089604. Child bodies, native effects and callback changes to count/base pointer remain open. [Evidence](research/QVM_POST_MAP_CLIENTS.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1634 |
|
| 1635 |
|
| 1636 |
**RE-878:** 72 actual249007 cases recover signed live client-count iteration and connected-state2 gating. Each accepted client calls246746 then246963 unconditionally; a supplied first-child disconnect does not suppress its second child, and activation of a later slot affects subsequent dispatch. This uses level count34992524, not max-clients cvar34089604. Child bodies, native effects and callback changes to count/base pointer remain open. [Evidence](research/QVM_POST_MAP_CLIENTS.md).
|
| 1637 |
+
|
| 1638 |
+
|
| 1639 |
+
**RE-879:** Rust matches all72 original249007 schedules and state snapshots, including disconnect-before-second-child and activation-before-later-scan cases. The bounded API accepts typed callbacks and validates the count before invoking them. Count/base remain stable; actual246746/246963 child bodies and engine integration remain open. [Evidence](research/RUST_POST_MAP_CLIENTS.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1662,3 +1662,6 @@ RE-877: Rust matches all64 actual121987 fitness/selection/interbreed/mutation/re
|
|
| 1662 |
|
| 1663 |
|
| 1664 |
RE-878: 72 actual249007 cases recover signed live client-count iteration and connected-state2 gating. Each accepted client calls246746 then246963 unconditionally; a supplied first-child disconnect does not suppress its second child, and activation of a later slot affects subsequent dispatch. This uses level count34992524, not max-clients cvar34089604. Child bodies, native effects and callback changes to count/base pointer remain open. Full runtime completion remains open. [Evidence](research/QVM_POST_MAP_CLIENTS.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1662 |
|
| 1663 |
|
| 1664 |
RE-878: 72 actual249007 cases recover signed live client-count iteration and connected-state2 gating. Each accepted client calls246746 then246963 unconditionally; a supplied first-child disconnect does not suppress its second child, and activation of a later slot affects subsequent dispatch. This uses level count34992524, not max-clients cvar34089604. Child bodies, native effects and callback changes to count/base pointer remain open. Full runtime completion remains open. [Evidence](research/QVM_POST_MAP_CLIENTS.md).
|
| 1665 |
+
|
| 1666 |
+
|
| 1667 |
+
RE-879: Rust matches all72 original249007 schedules and state snapshots, including disconnect-before-second-child and activation-before-later-scan cases. The bounded API accepts typed callbacks and validates the count before invoking them. Count/base remain stable; actual246746/246963 child bodies and engine integration remain open. Full runtime completion remains open. [Evidence](research/RUST_POST_MAP_CLIENTS.md).
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -2095,3 +2095,8 @@ Rust matches all64 actual121987 fitness/selection/interbreed/mutation/reset tran
|
|
| 2095 |
## 2026-10-28 — RE-878 Original post-map connected-client callbacks
|
| 2096 |
|
| 2097 |
72 actual249007 cases recover signed live client-count iteration and connected-state2 gating. Each accepted client calls246746 then246963 unconditionally; a supplied first-child disconnect does not suppress its second child, and activation of a later slot affects subsequent dispatch. This uses level count34992524, not max-clients cvar34089604. Child bodies, native effects and callback changes to count/base pointer remain open. Focused `cargo xtask test-group qvm-post-map-clients` passes (4 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2095 |
## 2026-10-28 — RE-878 Original post-map connected-client callbacks
|
| 2096 |
|
| 2097 |
72 actual249007 cases recover signed live client-count iteration and connected-state2 gating. Each accepted client calls246746 then246963 unconditionally; a supplied first-child disconnect does not suppress its second child, and activation of a later slot affects subsequent dispatch. This uses level count34992524, not max-clients cvar34089604. Child bodies, native effects and callback changes to count/base pointer remain open. Focused `cargo xtask test-group qvm-post-map-clients` passes (4 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.
|
| 2098 |
+
|
| 2099 |
+
|
| 2100 |
+
## 2026-10-28 — RE-879 Rust post-map callback scheduling
|
| 2101 |
+
|
| 2102 |
+
Rust matches all72 original249007 schedules and state snapshots, including disconnect-before-second-child and activation-before-later-scan cases. The bounded API accepts typed callbacks and validates the count before invoking them. Count/base remain stable; actual246746/246963 child bodies and engine integration remain open. Focused `cargo xtask test-group rust-post-map-clients` 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
|
@@ -1699,3 +1699,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1699 |
|
| 1700 |
|
| 1701 |
- [x] RE-878 Original post-map connected-client callbacks ([evidence](research/QVM_POST_MAP_CLIENTS.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 1699 |
|
| 1700 |
|
| 1701 |
- [x] RE-878 Original post-map connected-client callbacks ([evidence](research/QVM_POST_MAP_CLIENTS.md)).
|
| 1702 |
+
|
| 1703 |
+
|
| 1704 |
+
- [x] RE-879 Rust post-map callback scheduling ([evidence](research/RUST_POST_MAP_CLIENTS.md)).
|
docs/research/README.md
CHANGED
|
@@ -1234,3 +1234,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 1234 |
|
| 1235 |
|
| 1236 |
[RE-878: Original post-map connected-client callbacks](QVM_POST_MAP_CLIENTS.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1234 |
|
| 1235 |
|
| 1236 |
[RE-878: Original post-map connected-client callbacks](QVM_POST_MAP_CLIENTS.md).
|
| 1237 |
+
|
| 1238 |
+
|
| 1239 |
+
[RE-879: Rust post-map callback scheduling](RUST_POST_MAP_CLIENTS.md).
|
docs/research/RUST_POST_MAP_CLIENTS.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Rust post-map callback scheduling
|
| 2 |
+
|
| 3 |
+
RE-879. Reproduce with `python3 scripts/analyze_rust_post_map_clients.py`; focused validation: `cargo xtask test-group rust-post-map-clients`. [Machine report](rust-post-map-clients.json).
|
| 4 |
+
|
| 5 |
+
Rust matches all72 original249007 schedules and state snapshots, including disconnect-before-second-child and activation-before-later-scan cases. The bounded API accepts typed callbacks and validates the count before invoking them. Count/base remain stable; actual246746/246963 child bodies and engine integration remain open.
|
| 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":
|
| 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": 135,
|
| 2989 |
"source_report": "docs/research/qvm-health-impulse.json",
|
| 2990 |
"source_report_sha256": "625fd8064004ea6dbdf398d51d0af844d9c635ff04c0a0790886dddb6ab81e71"
|
| 2991 |
}
|
docs/research/rust-post-map-clients.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_rust_post_map_clients.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
import hashlib,json
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from rust_native_policy_support import binary,result,invoke
|
| 5 |
+
from analyze_qvm import write_json
|
| 6 |
+
def encode(s):
|
| 7 |
+
a=s['input'];return [a['count'],a['mutation'],*a['records']]
|
| 8 |
+
def project(s):return {k:s[k] for k in ['calls','after']}
|
| 9 |
+
|
| 10 |
+
def main():
|
| 11 |
+
b=binary();p=Path('docs/research/qvm-post-map-clients.json');data=p.read_bytes();rows=[]
|
| 12 |
+
for s in json.loads(data)['probes']:rows.append({'source':project(s),'rust':result(b,'post',encode(s))})
|
| 13 |
+
write_json(Path('docs/research/rust-post-map-clients.json'),{'source_report':str(p),'source_report_sha256':hashlib.sha256(data).hexdigest(),'probes':rows,'limits':'Rust matches all72 original249007 schedules and state snapshots, including disconnect-before-second-child and activation-before-later-scan cases. The bounded API accepts typed callbacks and validates the count before invoking them. Count/base remain stable; actual246746/246963 child bodies and engine integration remain open.'})
|
| 14 |
+
if __name__=='__main__':main()
|
scripts/test_rust_post_map_clients.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import hashlib,json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
class PortTests(unittest.TestCase):
|
| 4 |
+
def test_all_original_cases(self):
|
| 5 |
+
r=json.loads(Path('docs/research/rust-post-map-clients.json').read_text());src=json.loads(Path(r['source_report']).read_text());self.assertEqual(len(r['probes']),len(src['probes']));self.assertGreater(len(r['probes']),20)
|
| 6 |
+
for p in r['probes']:self.assertEqual(p['rust'],p['source'])
|
| 7 |
+
def test_source_identity(self):
|
| 8 |
+
r=json.loads(Path('docs/research/rust-post-map-clients.json').read_text());self.assertEqual(hashlib.sha256(Path(r['source_report']).read_bytes()).hexdigest(),r['source_report_sha256'])
|
| 9 |
+
if __name__=='__main__':unittest.main()
|
xtask/checks.tsv
CHANGED
|
@@ -2556,3 +2556,16 @@ report scripts/analyze_qvm_post_map_clients.py docs/research/qvm-post-map-client
|
|
| 2556 |
edge docs/research/qvm-post-map-clients.json scripts/test_qvm_post_map_clients.py
|
| 2557 |
group qvm-post-map-clients scripts/analyze_qvm_post_map_clients.py
|
| 2558 |
edge scripts/analyze_qvm_post_map_clients.py scripts/analyze_qvm_resumer_audit.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2556 |
edge docs/research/qvm-post-map-clients.json scripts/test_qvm_post_map_clients.py
|
| 2557 |
group qvm-post-map-clients scripts/analyze_qvm_post_map_clients.py
|
| 2558 |
edge scripts/analyze_qvm_post_map_clients.py scripts/analyze_qvm_resumer_audit.py
|
| 2559 |
+
edge Cargo.toml scripts/analyze_rust_post_map_clients.py
|
| 2560 |
+
edge Cargo.lock scripts/analyze_rust_post_map_clients.py
|
| 2561 |
+
edge crates/urt-gameplay/Cargo.toml scripts/analyze_rust_post_map_clients.py
|
| 2562 |
+
edge crates/urt-gameplay/src/lib.rs scripts/analyze_rust_post_map_clients.py
|
| 2563 |
+
edge crates/urt-gameplay/src/native_policy.rs scripts/analyze_rust_post_map_clients.py
|
| 2564 |
+
edge crates/urt-gameplay/src/bin/urt-native-policy.rs scripts/analyze_rust_post_map_clients.py
|
| 2565 |
+
edge docs/research/qvm-post-map-clients.json scripts/analyze_rust_post_map_clients.py
|
| 2566 |
+
group rust-post-map-clients scripts/analyze_rust_health_impulse.py
|
| 2567 |
+
group gameplay scripts/analyze_rust_post_map_clients.py
|
| 2568 |
+
report scripts/analyze_rust_post_map_clients.py docs/research/rust-post-map-clients.json
|
| 2569 |
+
edge docs/research/rust-post-map-clients.json scripts/test_rust_post_map_clients.py
|
| 2570 |
+
group rust-post-map-clients scripts/analyze_rust_post_map_clients.py
|
| 2571 |
+
edge scripts/analyze_rust_post_map_clients.py scripts/analyze_qvm_resumer_audit.py
|