gameplay: compose normal map command flow
Browse files- crates/urt-gameplay/src/bin/urt-map-commands.rs +124 -0
- crates/urt-gameplay/src/map_commands.rs +157 -0
- docs/FINDINGS.md +4 -1
- docs/PROVISIONAL_TODO.md +8 -2
- docs/RESEARCH_LEDGER.md +9 -0
- docs/REVERSE_ENGINEERING_TODO.md +7 -1
- docs/TESTING.md +5 -0
- docs/research/QVM_MAP_SELECT.md +1 -1
- docs/research/QVM_ROTATION_ADVANCE.md +2 -0
- docs/research/QVM_SPAWN_MAP_COMMAND_BATCH.md +44 -0
- docs/research/README.md +5 -0
- docs/research/RUST_NORMAL_MAP_FLOW.md +7 -0
- docs/research/rust-health-impulse.json +1 -1
- docs/research/rust-normal-map-flow.json +0 -0
- scripts/analyze_rust_normal_map_flow.py +15 -0
- scripts/test_rust_normal_map_flow.py +9 -0
- xtask/checks.tsv +15 -0
- xtask/src/lib.rs +10 -0
crates/urt-gameplay/src/bin/urt-map-commands.rs
CHANGED
|
@@ -79,6 +79,64 @@ fn run() -> Result<String, String> {
|
|
| 79 |
map_effects_json(&r.effects)
|
| 80 |
))
|
| 81 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
_ => Err("unknown command".into()),
|
| 83 |
}
|
| 84 |
}
|
|
@@ -111,3 +169,69 @@ fn map_effects_json(e: &[MapEffect]) -> String {
|
|
| 111 |
.join(",")
|
| 112 |
)
|
| 113 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
map_effects_json(&r.effects)
|
| 80 |
))
|
| 81 |
}
|
| 82 |
+
"flow" => {
|
| 83 |
+
if w.len() < 17 {
|
| 84 |
+
return Err("missing flow header".into());
|
| 85 |
+
}
|
| 86 |
+
let mut state = map_state(&w[..11]);
|
| 87 |
+
let mut rotation = Rotation {
|
| 88 |
+
enabled: w[11] as i32,
|
| 89 |
+
cursor: w[12] as i32,
|
| 90 |
+
limit: w[13] as i32,
|
| 91 |
+
filename: b"previous.cfg".to_vec(),
|
| 92 |
+
};
|
| 93 |
+
let n = w[16] as usize;
|
| 94 |
+
if n > 64 || w.len() < 17 + 5 * n {
|
| 95 |
+
return Err("invalid flow count".into());
|
| 96 |
+
}
|
| 97 |
+
let mut clients = w[17..17 + 5 * n]
|
| 98 |
+
.chunks_exact(5)
|
| 99 |
+
.map(|v| urt_gameplay::transition::MapClient {
|
| 100 |
+
score: v[0] as i32,
|
| 101 |
+
field304: v[1] as i32,
|
| 102 |
+
field308: v[2] as i32,
|
| 103 |
+
connection: v[3] as i32,
|
| 104 |
+
class: v[4] as i32,
|
| 105 |
+
})
|
| 106 |
+
.collect::<Vec<_>>();
|
| 107 |
+
let mut p = 17 + 5 * n;
|
| 108 |
+
let updated = bytes(&w, &mut p)?;
|
| 109 |
+
let mut mirror = bytes(&w, &mut p)?;
|
| 110 |
+
let current = bytes(&w, &mut p)?;
|
| 111 |
+
if p != w.len() {
|
| 112 |
+
return Err("trailing flow words".into());
|
| 113 |
+
}
|
| 114 |
+
let changes = if w[15] != 0 { vec![(0, 0)] } else { vec![] };
|
| 115 |
+
let out = normal_next_map(
|
| 116 |
+
&mut state,
|
| 117 |
+
&mut rotation,
|
| 118 |
+
&mut mirror,
|
| 119 |
+
&mut clients,
|
| 120 |
+
NormalInputs {
|
| 121 |
+
count: w[14] as usize,
|
| 122 |
+
updated_filename: &updated,
|
| 123 |
+
engine_map: ¤t,
|
| 124 |
+
connection_changes: &changes,
|
| 125 |
+
},
|
| 126 |
+
)
|
| 127 |
+
.map_err(|e| format!("{e:?}"))?;
|
| 128 |
+
Ok(format!(
|
| 129 |
+
"{{\"state\":{},\"cursor\":{},\"filename\":\"{}\",\"mirror\":\"{}\",\"middle\":{},\"clients\":{},\"rotation_operations\":{},\"map_operations\":{}}}",
|
| 130 |
+
map_json(&state),
|
| 131 |
+
rotation.cursor as u32,
|
| 132 |
+
hex(&rotation.filename),
|
| 133 |
+
hex(&mirror),
|
| 134 |
+
clients_json(&out.middle),
|
| 135 |
+
clients_json(&clients),
|
| 136 |
+
rotation_json(&out.rotation),
|
| 137 |
+
map_effects_json(&out.selection.effects)
|
| 138 |
+
))
|
| 139 |
+
}
|
| 140 |
_ => Err("unknown command".into()),
|
| 141 |
}
|
| 142 |
}
|
|
|
|
| 169 |
.join(",")
|
| 170 |
)
|
| 171 |
}
|
| 172 |
+
|
| 173 |
+
fn map_state(v: &[u32]) -> urt_gameplay::transition::MapState {
|
| 174 |
+
urt_gameplay::transition::MapState {
|
| 175 |
+
phase: v[0] as i32,
|
| 176 |
+
option: v[1] as i32,
|
| 177 |
+
flags: v[2],
|
| 178 |
+
mode: v[3] as i32,
|
| 179 |
+
scores: [v[4] as i32, v[5] as i32],
|
| 180 |
+
blocked: v[6] as i32,
|
| 181 |
+
pending: v[7] as i32,
|
| 182 |
+
saved: [v[8] as i32, v[9] as i32],
|
| 183 |
+
round: v[10] as i32,
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
fn map_json(s: &urt_gameplay::transition::MapState) -> String {
|
| 187 |
+
let keys = [
|
| 188 |
+
"phase",
|
| 189 |
+
"option",
|
| 190 |
+
"flags",
|
| 191 |
+
"mode",
|
| 192 |
+
"first",
|
| 193 |
+
"second",
|
| 194 |
+
"blocked",
|
| 195 |
+
"pending",
|
| 196 |
+
"saved_second",
|
| 197 |
+
"saved_first",
|
| 198 |
+
"round",
|
| 199 |
+
];
|
| 200 |
+
let values = [
|
| 201 |
+
s.phase as u32,
|
| 202 |
+
s.option as u32,
|
| 203 |
+
s.flags,
|
| 204 |
+
s.mode as u32,
|
| 205 |
+
s.scores[0] as u32,
|
| 206 |
+
s.scores[1] as u32,
|
| 207 |
+
s.blocked as u32,
|
| 208 |
+
s.pending as u32,
|
| 209 |
+
s.saved[0] as u32,
|
| 210 |
+
s.saved[1] as u32,
|
| 211 |
+
s.round as u32,
|
| 212 |
+
];
|
| 213 |
+
format!(
|
| 214 |
+
"{{{}}}",
|
| 215 |
+
keys.iter()
|
| 216 |
+
.zip(values)
|
| 217 |
+
.map(|(k, v)| format!("\"{k}\":{v}"))
|
| 218 |
+
.collect::<Vec<_>>()
|
| 219 |
+
.join(",")
|
| 220 |
+
)
|
| 221 |
+
}
|
| 222 |
+
fn clients_json(c: &[urt_gameplay::transition::MapClient]) -> String {
|
| 223 |
+
format!(
|
| 224 |
+
"[{}]",
|
| 225 |
+
c.iter()
|
| 226 |
+
.map(|c| format!(
|
| 227 |
+
"{{\"248\":{},\"304\":{},\"308\":{},\"468\":{},\"696\":{}}}",
|
| 228 |
+
c.score as u32,
|
| 229 |
+
c.field304 as u32,
|
| 230 |
+
c.field308 as u32,
|
| 231 |
+
c.connection as u32,
|
| 232 |
+
c.class as u32
|
| 233 |
+
))
|
| 234 |
+
.collect::<Vec<_>>()
|
| 235 |
+
.join(",")
|
| 236 |
+
)
|
| 237 |
+
}
|
crates/urt-gameplay/src/map_commands.rs
CHANGED
|
@@ -161,3 +161,160 @@ mod select_tests {
|
|
| 161 |
assert_eq!(select_map(&[1; 4097], b"x"), Err(Error::BytesTooLong));
|
| 162 |
}
|
| 163 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
assert_eq!(select_map(&[1; 4097], b"x"), Err(Error::BytesTooLong));
|
| 162 |
}
|
| 163 |
}
|
| 164 |
+
|
| 165 |
+
pub struct NormalInputs<'a> {
|
| 166 |
+
pub count: usize,
|
| 167 |
+
pub updated_filename: &'a [u8],
|
| 168 |
+
pub engine_map: &'a [u8],
|
| 169 |
+
pub connection_changes: &'a [(usize, i32)],
|
| 170 |
+
}
|
| 171 |
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
| 172 |
+
pub struct NormalFlow {
|
| 173 |
+
pub rotation: Vec<RotationEffect>,
|
| 174 |
+
pub selection: MapSelection,
|
| 175 |
+
pub middle: Vec<crate::transition::MapClient>,
|
| 176 |
+
}
|
| 177 |
+
/// Compose recovered normal6939 children. External callbacks are supplied inputs
|
| 178 |
+
/// and ordered intentions; the final scan observes supplied249007 connections.
|
| 179 |
+
pub fn normal_next_map(
|
| 180 |
+
state: &mut crate::transition::MapState,
|
| 181 |
+
rotation: &mut Rotation,
|
| 182 |
+
mirror: &mut Vec<u8>,
|
| 183 |
+
clients: &mut [crate::transition::MapClient],
|
| 184 |
+
input: NormalInputs<'_>,
|
| 185 |
+
) -> Result<NormalFlow, Error> {
|
| 186 |
+
if state.phase > 0 && crate::intermission::team_mode(state.mode) {
|
| 187 |
+
return Err(Error::ModeMismatch);
|
| 188 |
+
}
|
| 189 |
+
if clients.len() > 64
|
| 190 |
+
|| input.count > clients.len()
|
| 191 |
+
|| input
|
| 192 |
+
.connection_changes
|
| 193 |
+
.iter()
|
| 194 |
+
.any(|(j, _)| *j >= clients.len())
|
| 195 |
+
{
|
| 196 |
+
return Err(Error::InvalidCount);
|
| 197 |
+
}
|
| 198 |
+
let mut s = state.clone();
|
| 199 |
+
let mut r = rotation.clone();
|
| 200 |
+
let mut c = clients.to_vec();
|
| 201 |
+
let effects = advance_rotation(&mut r, input.updated_filename)?;
|
| 202 |
+
let selection = select_map(mirror, input.engine_map)?;
|
| 203 |
+
crate::transition::prepare_normal(&mut s, &mut c, input.count)
|
| 204 |
+
.map_err(|_| Error::InvalidCount)?;
|
| 205 |
+
let middle = c.clone();
|
| 206 |
+
for (j, v) in input.connection_changes {
|
| 207 |
+
c[*j].connection = *v;
|
| 208 |
+
}
|
| 209 |
+
crate::transition::mark_connecting(&mut c, input.count).map_err(|_| Error::InvalidCount)?;
|
| 210 |
+
*state = s;
|
| 211 |
+
*rotation = r;
|
| 212 |
+
*mirror = selection.mirror.clone();
|
| 213 |
+
clients.copy_from_slice(&c);
|
| 214 |
+
Ok(NormalFlow {
|
| 215 |
+
rotation: effects,
|
| 216 |
+
selection,
|
| 217 |
+
middle,
|
| 218 |
+
})
|
| 219 |
+
}
|
| 220 |
+
#[cfg(test)]
|
| 221 |
+
mod normal_flow_tests {
|
| 222 |
+
use super::*;
|
| 223 |
+
use crate::transition::{MapClient, MapState};
|
| 224 |
+
#[test]
|
| 225 |
+
fn child_connection_override_and_command_state() {
|
| 226 |
+
let mut s = MapState {
|
| 227 |
+
phase: 2,
|
| 228 |
+
mode: 9,
|
| 229 |
+
scores: [5, -7],
|
| 230 |
+
blocked: 123,
|
| 231 |
+
pending: 321,
|
| 232 |
+
..Default::default()
|
| 233 |
+
};
|
| 234 |
+
let mut r = Rotation {
|
| 235 |
+
enabled: 1,
|
| 236 |
+
cursor: 1,
|
| 237 |
+
limit: 2,
|
| 238 |
+
filename: b"previous".to_vec(),
|
| 239 |
+
};
|
| 240 |
+
let mut mirror = b"cycle".to_vec();
|
| 241 |
+
let mut c = [MapClient {
|
| 242 |
+
score: 4,
|
| 243 |
+
field304: 5,
|
| 244 |
+
field308: 6,
|
| 245 |
+
connection: 2,
|
| 246 |
+
class: 9,
|
| 247 |
+
}; 2];
|
| 248 |
+
let out = normal_next_map(
|
| 249 |
+
&mut s,
|
| 250 |
+
&mut r,
|
| 251 |
+
&mut mirror,
|
| 252 |
+
&mut c,
|
| 253 |
+
NormalInputs {
|
| 254 |
+
count: 2,
|
| 255 |
+
updated_filename: b"out",
|
| 256 |
+
engine_map: b"current",
|
| 257 |
+
connection_changes: &[(0, 0)],
|
| 258 |
+
},
|
| 259 |
+
)
|
| 260 |
+
.unwrap();
|
| 261 |
+
assert_eq!(
|
| 262 |
+
(
|
| 263 |
+
out.middle[0].score,
|
| 264 |
+
out.middle[0].field304,
|
| 265 |
+
out.middle[0].connection
|
| 266 |
+
),
|
| 267 |
+
(0, 0, 2)
|
| 268 |
+
);
|
| 269 |
+
assert_eq!((c[0].connection, c[1].connection), (0, 1));
|
| 270 |
+
assert_eq!(
|
| 271 |
+
(s.scores, s.blocked, s.pending, s.phase),
|
| 272 |
+
([0, 0], 0, 321, 2)
|
| 273 |
+
);
|
| 274 |
+
assert_eq!(out.selection.command, Some(b"map cycle\n".to_vec()));
|
| 275 |
+
assert_eq!(mirror, b"cycle");
|
| 276 |
+
assert_eq!(r.filename, b"out");
|
| 277 |
+
}
|
| 278 |
+
#[test]
|
| 279 |
+
fn reject_series_and_bad_callback_without_mutation() {
|
| 280 |
+
let mut s = MapState {
|
| 281 |
+
phase: 1,
|
| 282 |
+
mode: 3,
|
| 283 |
+
..Default::default()
|
| 284 |
+
};
|
| 285 |
+
let old = s.clone();
|
| 286 |
+
let mut r = Rotation {
|
| 287 |
+
enabled: 1,
|
| 288 |
+
cursor: 1,
|
| 289 |
+
limit: 2,
|
| 290 |
+
filename: vec![],
|
| 291 |
+
};
|
| 292 |
+
let before = r.clone();
|
| 293 |
+
let mut mirror = vec![];
|
| 294 |
+
let mut c = [];
|
| 295 |
+
let input = NormalInputs {
|
| 296 |
+
count: 0,
|
| 297 |
+
updated_filename: b"out",
|
| 298 |
+
engine_map: b"x",
|
| 299 |
+
connection_changes: &[],
|
| 300 |
+
};
|
| 301 |
+
assert_eq!(
|
| 302 |
+
normal_next_map(&mut s, &mut r, &mut mirror, &mut c, input),
|
| 303 |
+
Err(Error::ModeMismatch)
|
| 304 |
+
);
|
| 305 |
+
assert_eq!(s, old);
|
| 306 |
+
assert_eq!(r, before);
|
| 307 |
+
s.phase = 0;
|
| 308 |
+
let input = NormalInputs {
|
| 309 |
+
count: 0,
|
| 310 |
+
updated_filename: b"out",
|
| 311 |
+
engine_map: b"x",
|
| 312 |
+
connection_changes: &[(0, 0)],
|
| 313 |
+
};
|
| 314 |
+
assert_eq!(
|
| 315 |
+
normal_next_map(&mut s, &mut r, &mut mirror, &mut c, input),
|
| 316 |
+
Err(Error::InvalidCount)
|
| 317 |
+
);
|
| 318 |
+
assert_eq!(r, before);
|
| 319 |
+
}
|
| 320 |
+
}
|
docs/FINDINGS.md
CHANGED
|
@@ -1609,10 +1609,13 @@ RE-813–822 replaces the scoreboard decimal assumption with actual37914 executi
|
|
| 1609 |
**RE-869:** Rust matches192 original rotation cases, preserving signed cursor wrap, enable/threshold gating, refreshed filename C-string handling and ordered refresh/write/clear/reset intentions. Engine refresh input is explicit; invalid refreshed data rejects before boundary mutations. Native callbacks remain unimplemented. [Evidence](research/RUST_ROTATION_ADVANCE.md).
|
| 1610 |
|
| 1611 |
|
| 1612 |
-
**RE-870:** 90 original7188 cases compose actual strlen, bounded-copy wrapper and original formatter. A nonempty override mirror records current engine mapname in g_nextCycleMap, copies the override into
|
| 1613 |
|
| 1614 |
|
| 1615 |
**RE-871:** Rust matches90 original map-selection cases with empty/NUL mirror gates,127-byte engine-mapname truncation, raw non-UTF8 bytes, unchanged VM mirror and exact truncated-override mode2 map command text. The typed effect order matches source cvar/read/command requests. Engine callbacks, native copy and actual command dispatch remain outside the port. [Evidence](research/RUST_MAP_SELECT.md).
|
| 1616 |
|
| 1617 |
|
| 1618 |
**RE-872:** 192 actual6939 normal-path cases compose recovered rotation, map selection, mode classification, copy and formatter bodies on shared state. Optional supplied249007 connection changes prove the final scan sees child mutations. Cvar/engine bytes, native copy and lower callback/runtime effects remain explicit boundaries. [Evidence](research/QVM_NORMAL_MAP_FLOW.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1609 |
**RE-869:** Rust matches192 original rotation cases, preserving signed cursor wrap, enable/threshold gating, refreshed filename C-string handling and ordered refresh/write/clear/reset intentions. Engine refresh input is explicit; invalid refreshed data rejects before boundary mutations. Native callbacks remain unimplemented. [Evidence](research/RUST_ROTATION_ADVANCE.md).
|
| 1610 |
|
| 1611 |
|
| 1612 |
+
**RE-870:** 90 original7188 cases compose actual strlen, bounded-copy wrapper and original formatter. A nonempty override mirror records current engine mapname in g_nextCycleMap, copies the override into a128-byte local map-name buffer (127-byte payload), requests engine g_NextMap clear and emits mode2 map command. VM mirror bytes remain unchanged; engine/native-copy and lower effects remain supplied/captured. [Evidence](research/QVM_MAP_SELECT.md).
|
| 1613 |
|
| 1614 |
|
| 1615 |
**RE-871:** Rust matches90 original map-selection cases with empty/NUL mirror gates,127-byte engine-mapname truncation, raw non-UTF8 bytes, unchanged VM mirror and exact truncated-override mode2 map command text. The typed effect order matches source cvar/read/command requests. Engine callbacks, native copy and actual command dispatch remain outside the port. [Evidence](research/RUST_MAP_SELECT.md).
|
| 1616 |
|
| 1617 |
|
| 1618 |
**RE-872:** 192 actual6939 normal-path cases compose recovered rotation, map selection, mode classification, copy and formatter bodies on shared state. Optional supplied249007 connection changes prove the final scan sees child mutations. Cvar/engine bytes, native copy and lower callback/runtime effects remain explicit boundaries. [Evidence](research/QVM_NORMAL_MAP_FLOW.md).
|
| 1619 |
+
|
| 1620 |
+
|
| 1621 |
+
**RE-873:** Rust matches192 original normal6939 cases, staging rotation, override map-command intentions, global/client resets and post-callback connection changes atomically. The API refuses team-series inputs and invalid callback indices. VM mirrors/pending/series data remain source-faithful; native callbacks, engine refresh and runtime integration remain open. [Evidence](research/RUST_NORMAL_MAP_FLOW.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1613,7 +1613,7 @@ RE-862: 96 continuous setup→placement cases now execute class-hash, field/stri
|
|
| 1613 |
RE-863: Rust matches all96 composed source setup/placement fixtures across searches, actual RNG state transitions, checked angle-math transcripts and resolved player indirection. Fallible resolution stages RNG before committing it and performs placement only after success. Fallback selection and native math parity remain explicit boundaries; intermission/respawn/runtime integration is still open. Full runtime completion remains open. [Evidence](research/RUST_CAMERA_WORLD.md).
|
| 1614 |
|
| 1615 |
|
| 1616 |
-
- [
|
| 1617 |
|
| 1618 |
|
| 1619 |
RE-864: 112 original168114 cases execute actual class-hash search and RNG, recovering stable farthest-first insertion,64-entry cap, far-half draw at8+, first-class fallback when blocked, +9 Z and a no-spawn fatal boundary. Telefrag answers and finite sqrt remain supplied; collision/native/runtime parity is open. Full runtime completion remains open. [Evidence](research/QVM_SPAWN_FALLBACK.md).
|
|
@@ -1634,10 +1634,16 @@ RE-868: 192 original122230 cases execute actual strlen and recover signed counte
|
|
| 1634 |
RE-869: Rust matches192 original rotation cases, preserving signed cursor wrap, enable/threshold gating, refreshed filename C-string handling and ordered refresh/write/clear/reset intentions. Engine refresh input is explicit; invalid refreshed data rejects before boundary mutations. Native callbacks remain unimplemented. Full runtime completion remains open. [Evidence](research/RUST_ROTATION_ADVANCE.md).
|
| 1635 |
|
| 1636 |
|
| 1637 |
-
RE-870: 90 original7188 cases compose actual strlen, bounded-copy wrapper and original formatter. A nonempty override mirror records current engine mapname in g_nextCycleMap, copies the override into
|
| 1638 |
|
| 1639 |
|
| 1640 |
RE-871: Rust matches90 original map-selection cases with empty/NUL mirror gates,127-byte engine-mapname truncation, raw non-UTF8 bytes, unchanged VM mirror and exact truncated-override mode2 map command text. The typed effect order matches source cvar/read/command requests. Engine callbacks, native copy and actual command dispatch remain outside the port. Full runtime completion remains open. [Evidence](research/RUST_MAP_SELECT.md).
|
| 1641 |
|
| 1642 |
|
| 1643 |
RE-872: 192 actual6939 normal-path cases compose recovered rotation, map selection, mode classification, copy and formatter bodies on shared state. Optional supplied249007 connection changes prove the final scan sees child mutations. Cvar/engine bytes, native copy and lower callback/runtime effects remain explicit boundaries. Full runtime completion remains open. [Evidence](research/QVM_NORMAL_MAP_FLOW.md).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1613 |
RE-863: Rust matches all96 composed source setup/placement fixtures across searches, actual RNG state transitions, checked angle-math transcripts and resolved player indirection. Fallible resolution stages RNG before committing it and performs placement only after success. Fallback selection and native math parity remain explicit boundaries; intermission/respawn/runtime integration is still open. Full runtime completion remains open. [Evidence](research/RUST_CAMERA_WORLD.md).
|
| 1614 |
|
| 1615 |
|
| 1616 |
+
- [x] RE-864–873: Recover fallback spawn/camera and normal map command/reset contracts. Remaining native/runtime scope continues under RE-874. [Evidence](research/QVM_SPAWN_MAP_COMMAND_BATCH.md).
|
| 1617 |
|
| 1618 |
|
| 1619 |
RE-864: 112 original168114 cases execute actual class-hash search and RNG, recovering stable farthest-first insertion,64-entry cap, far-half draw at8+, first-class fallback when blocked, +9 Z and a no-spawn fatal boundary. Telefrag answers and finite sqrt remain supplied; collision/native/runtime parity is open. Full runtime completion remains open. [Evidence](research/QVM_SPAWN_FALLBACK.md).
|
|
|
|
| 1634 |
RE-869: Rust matches192 original rotation cases, preserving signed cursor wrap, enable/threshold gating, refreshed filename C-string handling and ordered refresh/write/clear/reset intentions. Engine refresh input is explicit; invalid refreshed data rejects before boundary mutations. Native callbacks remain unimplemented. Full runtime completion remains open. [Evidence](research/RUST_ROTATION_ADVANCE.md).
|
| 1635 |
|
| 1636 |
|
| 1637 |
+
RE-870: 90 original7188 cases compose actual strlen, bounded-copy wrapper and original formatter. A nonempty override mirror records current engine mapname in g_nextCycleMap, copies the override into a128-byte local map-name buffer (127-byte payload), requests engine g_NextMap clear and emits mode2 map command. VM mirror bytes remain unchanged; engine/native-copy and lower effects remain supplied/captured. Full runtime completion remains open. [Evidence](research/QVM_MAP_SELECT.md).
|
| 1638 |
|
| 1639 |
|
| 1640 |
RE-871: Rust matches90 original map-selection cases with empty/NUL mirror gates,127-byte engine-mapname truncation, raw non-UTF8 bytes, unchanged VM mirror and exact truncated-override mode2 map command text. The typed effect order matches source cvar/read/command requests. Engine callbacks, native copy and actual command dispatch remain outside the port. Full runtime completion remains open. [Evidence](research/RUST_MAP_SELECT.md).
|
| 1641 |
|
| 1642 |
|
| 1643 |
RE-872: 192 actual6939 normal-path cases compose recovered rotation, map selection, mode classification, copy and formatter bodies on shared state. Optional supplied249007 connection changes prove the final scan sees child mutations. Cvar/engine bytes, native copy and lower callback/runtime effects remain explicit boundaries. Full runtime completion remains open. [Evidence](research/QVM_NORMAL_MAP_FLOW.md).
|
| 1644 |
+
|
| 1645 |
+
|
| 1646 |
+
RE-873: Rust matches192 original normal6939 cases, staging rotation, override map-command intentions, global/client resets and post-callback connection changes atomically. The API refuses team-series inputs and invalid callback indices. VM mirrors/pending/series data remain source-faithful; native callbacks, engine refresh and runtime integration remain open. Full runtime completion remains open. [Evidence](research/RUST_NORMAL_MAP_FLOW.md).
|
| 1647 |
+
|
| 1648 |
+
|
| 1649 |
+
- [ ] RE-874: Recover telefrag/native math, respawn/slow setup, lower map/rotation callbacks, allocation/publication and actual macOS/Linux runtime integration. [Scope](research/QVM_SPAWN_MAP_COMMAND_BATCH.md).
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -2061,3 +2061,12 @@ Rust matches90 original map-selection cases with empty/NUL mirror gates,127-byte
|
|
| 2061 |
## 2026-10-27 — RE-872 Original normal next-map flow with recovered command children
|
| 2062 |
|
| 2063 |
192 actual6939 normal-path cases compose recovered rotation, map selection, mode classification, copy and formatter bodies on shared state. Optional supplied249007 connection changes prove the final scan sees child mutations. Cvar/engine bytes, native copy and lower callback/runtime effects remain explicit boundaries. Focused `cargo xtask test-group normal-map-flow` 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2061 |
## 2026-10-27 — RE-872 Original normal next-map flow with recovered command children
|
| 2062 |
|
| 2063 |
192 actual6939 normal-path cases compose recovered rotation, map selection, mode classification, copy and formatter bodies on shared state. Optional supplied249007 connection changes prove the final scan sees child mutations. Cvar/engine bytes, native copy and lower callback/runtime effects remain explicit boundaries. Focused `cargo xtask test-group normal-map-flow` 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.
|
| 2064 |
+
|
| 2065 |
+
|
| 2066 |
+
## 2026-10-27 — RE-873 Rust recovered normal next-map command and reset composition
|
| 2067 |
+
|
| 2068 |
+
Rust matches192 original normal6939 cases, staging rotation, override map-command intentions, global/client resets and post-callback connection changes atomically. The API refuses team-series inputs and invalid callback indices. VM mirrors/pending/series data remain source-faithful; native callbacks, engine refresh and runtime integration remain open. Focused `cargo xtask test-group rust-normal-map-flow` 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.
|
| 2069 |
+
|
| 2070 |
+
RE-873 final review: targeted xtask dependency-registry regression passes for all five parity report edges and shared camera/transition/intermission/map module consumers. Added the batch findings and RE-874 native/runtime follow-ups.
|
| 2071 |
+
|
| 2072 |
+
Batch RE-864–873 boundary: the single `cargo xtask test-full --since 171bd705` run after commit ten passed with the flake-declared Nix Python: 1,708 Python tests, 169 Rust tests (assets 10, gameplay 129, xtask 30), 56 deterministic producers, storage policy, 436 documentation files and whitespace guards. No generated report drift. Validation notes were amended into task ten; original assets unchanged.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -1650,7 +1650,7 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1650 |
- [x] RE-863 Rust composed camera world selection and placement ([evidence](research/RUST_CAMERA_WORLD.md)).
|
| 1651 |
|
| 1652 |
|
| 1653 |
-
- [
|
| 1654 |
|
| 1655 |
|
| 1656 |
- [x] RE-864 Original fallback spawn distance ranking and selection ([evidence](research/QVM_SPAWN_FALLBACK.md)).
|
|
@@ -1678,3 +1678,9 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1678 |
|
| 1679 |
|
| 1680 |
- [x] RE-872 Original normal next-map flow with recovered command children ([evidence](research/QVM_NORMAL_MAP_FLOW.md)).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1650 |
- [x] RE-863 Rust composed camera world selection and placement ([evidence](research/RUST_CAMERA_WORLD.md)).
|
| 1651 |
|
| 1652 |
|
| 1653 |
+
- [x] RE-864–873: Recover fallback spawn/camera and normal map command/reset contracts. Remaining native/runtime scope continues under RE-874. [Evidence](research/QVM_SPAWN_MAP_COMMAND_BATCH.md).
|
| 1654 |
|
| 1655 |
|
| 1656 |
- [x] RE-864 Original fallback spawn distance ranking and selection ([evidence](research/QVM_SPAWN_FALLBACK.md)).
|
|
|
|
| 1678 |
|
| 1679 |
|
| 1680 |
- [x] RE-872 Original normal next-map flow with recovered command children ([evidence](research/QVM_NORMAL_MAP_FLOW.md)).
|
| 1681 |
+
|
| 1682 |
+
|
| 1683 |
+
- [x] RE-873 Rust recovered normal next-map command and reset composition ([evidence](research/RUST_NORMAL_MAP_FLOW.md)).
|
| 1684 |
+
|
| 1685 |
+
|
| 1686 |
+
- [ ] RE-874: Recover telefrag/native math, respawn/slow setup, lower map/rotation callbacks, allocation/publication and actual macOS/Linux runtime integration. [Scope](research/QVM_SPAWN_MAP_COMMAND_BATCH.md).
|
docs/TESTING.md
CHANGED
|
@@ -152,3 +152,8 @@ Focused source/Rust pairs: `camera-place`/`rust-camera-place`, `camera-select`/`
|
|
| 152 |
## Entity search and composed world camera groups
|
| 153 |
|
| 154 |
Use the source/Rust pairs `entity-hash`/`rust-entity-hash`, `entity-field`/`rust-entity-field`, `target-pick`/`rust-target-pick`, `camera-angles`/`rust-camera-angles` and `camera-world`/`rust-camera-world`. Run them inside the flake shell. Registry regression checks report, module and shared transition dependencies; Rust groups refresh scoped gameplay test counts. Git hooks require the flake's absolute Nix-store `PYTHON` and refuse to fall back to system Python. Run `storage` after hook changes and one full suite after ten commits. [Batch evidence and limits](research/QVM_CAMERA_WORLD_BATCH.md).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
## Entity search and composed world camera groups
|
| 153 |
|
| 154 |
Use the source/Rust pairs `entity-hash`/`rust-entity-hash`, `entity-field`/`rust-entity-field`, `target-pick`/`rust-target-pick`, `camera-angles`/`rust-camera-angles` and `camera-world`/`rust-camera-world`. Run them inside the flake shell. Registry regression checks report, module and shared transition dependencies; Rust groups refresh scoped gameplay test counts. Git hooks require the flake's absolute Nix-store `PYTHON` and refuse to fall back to system Python. Run `storage` after hook changes and one full suite after ten commits. [Batch evidence and limits](research/QVM_CAMERA_WORLD_BATCH.md).
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
## Fallback spawn and normal map-command groups
|
| 158 |
+
|
| 159 |
+
Source/Rust pairs: `spawn-fallback`/`rust-spawn-fallback`, `camera-spawn`/`rust-camera-spawn`, `rotation-advance`/`rust-rotation-advance`, `map-select`/`rust-map-select`, and `normal-map-flow`/`rust-normal-map-flow`. Run one group per `cargo xtask test-group <name>` invocation with the flake's explicit PYTHON. Groups regenerate dependency closure; Rust groups include scoped gameplay tests/test-count metadata. Registry regression checks parity edges, module consumers and shared transition/intermission dependencies. Continue focused checks per task and one full run after ten commits. [Batch evidence and native boundaries](research/QVM_SPAWN_MAP_COMMAND_BATCH.md).
|
docs/research/QVM_MAP_SELECT.md
CHANGED
|
@@ -2,6 +2,6 @@
|
|
| 2 |
|
| 3 |
RE-870. Reproduce with `python3 scripts/analyze_qvm_map_select.py`; focused validation: `cargo xtask test-group map-select`. [Machine report](qvm-map-select.json).
|
| 4 |
|
| 5 |
-
90 original7188 cases compose actual strlen, bounded-copy wrapper and original formatter. A nonempty override mirror records current engine mapname in g_nextCycleMap, copies the override into
|
| 6 |
|
| 7 |
Original executable/native runtime and complete Linux/macOS Rust/Bevy/Solari acceptance remain unverified.
|
|
|
|
| 2 |
|
| 3 |
RE-870. Reproduce with `python3 scripts/analyze_qvm_map_select.py`; focused validation: `cargo xtask test-group map-select`. [Machine report](qvm-map-select.json).
|
| 4 |
|
| 5 |
+
90 original7188 cases compose actual strlen, bounded-copy wrapper and original formatter. A nonempty override mirror records current engine mapname in g_nextCycleMap, copies the override into a128-byte local map-name buffer (127-byte payload), requests engine g_NextMap clear and emits mode2 map command. VM mirror bytes remain unchanged; engine/native-copy and lower effects remain supplied/captured.
|
| 6 |
|
| 7 |
Original executable/native runtime and complete Linux/macOS Rust/Bevy/Solari acceptance remain unverified.
|
docs/research/QVM_ROTATION_ADVANCE.md
CHANGED
|
@@ -5,3 +5,5 @@ RE-868. Reproduce with `python3 scripts/analyze_qvm_rotation_advance.py`; focuse
|
|
| 5 |
192 original122230 cases execute actual strlen and recover signed counter wrapping, threshold priority and refresh→optional filename callback/clear→reset order. Engine-5 refresh writes are supplied explicitly, including empty, NUL and high-byte filenames. Actual122143/121987 callbacks and native runtime ownership remain open.
|
| 6 |
|
| 7 |
Original executable/native runtime and complete Linux/macOS Rust/Bevy/Solari acceptance remain unverified.
|
|
|
|
|
|
|
|
|
| 5 |
192 original122230 cases execute actual strlen and recover signed counter wrapping, threshold priority and refresh→optional filename callback/clear→reset order. Engine-5 refresh writes are supplied explicitly, including empty, NUL and high-byte filenames. Actual122143/121987 callbacks and native runtime ownership remain open.
|
| 6 |
|
| 7 |
Original executable/native runtime and complete Linux/macOS Rust/Bevy/Solari acceptance remain unverified.
|
| 8 |
+
|
| 9 |
+
The observed clear target is the cvar `bot_interbreedwrite`. Counter meaning is kept conservative; this contract does not establish a map-list rotation model or execute the bot-related callbacks.
|
docs/research/QVM_SPAWN_MAP_COMMAND_BATCH.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Fallback spawn and normal map commands: RE-864–873
|
| 2 |
+
|
| 3 |
+
This batch replaces the camera fallback stand-in with original instruction execution and composes normal next-map command children with their shared reset state. Rust ports match the finite source contracts; telefrag, engine refresh, native math/copy and lower callbacks remain explicit boundaries.
|
| 4 |
+
|
| 5 |
+
| Task | Evidence |
|
| 6 |
+
| --- | --- |
|
| 7 |
+
| RE-864 | [168114 fallback distance ranking and selection](QVM_SPAWN_FALLBACK.md) |
|
| 8 |
+
| RE-865 | [Rust fallback spawn selection](RUST_SPAWN_FALLBACK.md) |
|
| 9 |
+
| RE-866 | [Camera setup with actual fallback](QVM_CAMERA_SPAWN.md) |
|
| 10 |
+
| RE-867 | [Rust composed fallback camera](RUST_CAMERA_SPAWN.md) |
|
| 11 |
+
| RE-868 | [122230 cursor and refreshed filename policy](QVM_ROTATION_ADVANCE.md) |
|
| 12 |
+
| RE-869 | [Rust rotation callback intentions](RUST_ROTATION_ADVANCE.md) |
|
| 13 |
+
| RE-870 | [7188 override command, copy and original formatter](QVM_MAP_SELECT.md) |
|
| 14 |
+
| RE-871 | [Rust override command ownership](RUST_MAP_SELECT.md) |
|
| 15 |
+
| RE-872 | [6939 normal path with actual command children](QVM_NORMAL_MAP_FLOW.md) |
|
| 16 |
+
| RE-873 | [Rust normal map command/reset composition](RUST_NORMAL_MAP_FLOW.md) |
|
| 17 |
+
|
| 18 |
+
## Findings and evidence boundaries
|
| 19 |
+
|
| 20 |
+
Fallback selection has 112 cases. Actual 168114 searches class hash −103258081 through recovered 276433, skips supplied telefrag results, and inserts accepted candidates in stable descending f32 distance order. It keeps 64; the grid reaches 80 entities so this cap is exercised after class filtering. At 8 or more candidates, RNG 36717 selects modulo floor(count/2); below 8 it uses the entire set. A match always consumes one draw, even with one candidate. If every class match is blocked, it chooses the first class match without a draw; no class match reaches captured fatal 2319. It copies spawn angles and adds 9 to origin Z. Source sqrt responses are modeled and checked by Rust transcripts; actual collision/native math and unsafe pointer domains remain open.
|
| 21 |
+
|
| 22 |
+
The 128 camera fixtures execute 6717→6575 with actual 168114 fallback and the previously recovered searches, RNG and angle bodies. They combine fallback and existing intermission-camera branches with two entity-to-player pointers. Rust stages selection and places only after successful resolution. Telefrag inputs remain caller-provided; no-spawn handling is a typed error rather than executing original fatal termination.
|
| 23 |
+
|
| 24 |
+
Rotation has 192 cases. The observed write cvar is `bot_interbreedwrite`; the cursor is retained as a raw control counter rather than assumed to represent a map list. Original 122230 increments an enabled signed cursor with word wrapping, tests its threshold, then requests engine−5 refresh of the write cvar before inspecting its string through actual 36038. Only a refreshed nonempty filename requests 122143 and a cvar clear; 121987 follows either way at the boundary. VM filename bytes remain the refreshed value after the captured engine clear. Actual 122143/121987 behavior and engine ownership remain open.
|
| 25 |
+
|
| 26 |
+
Map selection has 90 cases and executes actual 7188, strlen, bounded-copy wrapper 69338, alternating formatter 70458 and formatter 37914. The nonempty override mirror branch reads the current engine mapname (127 bytes), sets g_nextCycleMap to that current name, then copies the override mirror into the local 128-byte command buffer. It requests an engine g_NextMap clear and emits mode 2 `map <override>\n`, truncated to 127 override bytes. The VM mirror remains unchanged until a future engine refresh. Empty mirror delegates 221662; its supplied return does not affect this body. Tests verify copy direction, NUL padding, unchanged guards/mirror, raw high bytes and exact original formatter output. Engine buffer writes, native−103 copy and actual cvar/command dispatch remain supplied/modeled/captured.
|
| 27 |
+
|
| 28 |
+
The final 192 cases execute the actual 6939 normal path with recovered 122230/7188 and mode classifier 33715, combining command order with global/client resets. A middle snapshot and optional supplied 249007 connection change prove the final state 2→1 scan observes callback mutations. Rust composes the same phases atomically with explicit supplied connection updates, rejects team-series inputs and invalid callback indices, and preserves pending/phase/series data. Native 249007 and downstream callbacks still remain open.
|
| 29 |
+
|
| 30 |
+
## Validation
|
| 31 |
+
|
| 32 |
+
All Python execution in this batch uses the already-resolved Nix Python 3.13.15 declared by flake.nix; PYTHON is explicit for xtask, nested scripts and Git hooks. No macOS Command Line Tools Python is used. Each task passed focused cargo xtask validation before its own commit, with deterministic double report regeneration, relevant Python/scoped gameplay Rust tests, storage, documentation links and whitespace checks. The registry regression verifies all five source-report parity edges, camera/map module consumers and shared transition/intermission dependencies. The single full-suite run after commit ten, `cargo xtask test-full --since 171bd705`, passed with the flake-declared Python: 1,708 Python tests and 169 Rust tests (assets 10, gameplay 129, xtask 30). All 56 affected report producers regenerated twice deterministically. Storage policy, links across 436 documentation files and whitespace checks passed. There was no generated report drift; notes were amended into task ten.
|
| 33 |
+
|
| 34 |
+
Use `cargo xtask test-group <name>` with `spawn-fallback`, `rust-spawn-fallback`, `camera-spawn`, `rust-camera-spawn`, `rotation-advance`, `rust-rotation-advance`, `map-select`, `rust-map-select`, `normal-map-flow` or `rust-normal-map-flow`, in the flake tool environment.
|
| 35 |
+
|
| 36 |
+
## Next work: RE-874
|
| 37 |
+
|
| 38 |
+
- [ ] Recover 167638 telefrag/collision queries and compare actual native sqrt/atan2; broaden spawn aliases, unsupported domains and original fatal semantics.
|
| 39 |
+
- [ ] Compose recovered camera fallback into actual 175123 respawn and 156523 slow setup, then the complete begin-intermission flow.
|
| 40 |
+
- [ ] Recover 122143/121987 rotation callbacks, 221662 fallback map selection and 249007 post-map state/command behavior.
|
| 41 |
+
- [ ] Compose complete 6939 series/normal handling into readiness, with real engine cvar refresh and command ownership.
|
| 42 |
+
- [ ] Recover 277165 allocation/initialization and integrate event caller-owned fields, native linking and lifetime.
|
| 43 |
+
- [ ] Execute 6328 publication and real formatting/configstring/network work; integrate ranking→intermission→camera/map/event→scoreboard state.
|
| 44 |
+
- [ ] Validate actual macOS/Linux Bevy/Solari gameplay/rendering and continue legacy tracer audits. These policies do not establish full-game completion.
|
docs/research/README.md
CHANGED
|
@@ -1214,3 +1214,8 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 1214 |
|
| 1215 |
|
| 1216 |
[RE-872: Original normal next-map flow with recovered command children](QVM_NORMAL_MAP_FLOW.md).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1214 |
|
| 1215 |
|
| 1216 |
[RE-872: Original normal next-map flow with recovered command children](QVM_NORMAL_MAP_FLOW.md).
|
| 1217 |
+
|
| 1218 |
+
|
| 1219 |
+
[RE-873: Rust recovered normal next-map command and reset composition](RUST_NORMAL_MAP_FLOW.md).
|
| 1220 |
+
|
| 1221 |
+
- [RE-864–873 fallback spawn and normal map command batch](QVM_SPAWN_MAP_COMMAND_BATCH.md).
|
docs/research/RUST_NORMAL_MAP_FLOW.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Rust recovered normal next-map command and reset composition
|
| 2 |
+
|
| 3 |
+
RE-873. Reproduce with `python3 scripts/analyze_rust_normal_map_flow.py`; focused validation: `cargo xtask test-group rust-normal-map-flow`. [Machine report](rust-normal-map-flow.json).
|
| 4 |
+
|
| 5 |
+
Rust matches192 original normal6939 cases, staging rotation, override map-command intentions, global/client resets and post-callback connection changes atomically. The API refuses team-series inputs and invalid callback indices. VM mirrors/pending/series data remain source-faithful; native callbacks, engine refresh and runtime 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": 129,
|
| 2989 |
"source_report": "docs/research/qvm-health-impulse.json",
|
| 2990 |
"source_report_sha256": "625fd8064004ea6dbdf398d51d0af844d9c635ff04c0a0790886dddb6ab81e71"
|
| 2991 |
}
|
docs/research/rust-normal-map-flow.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_rust_normal_map_flow.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
import hashlib,json
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from rust_map_commands_support import binary,result,invoke
|
| 5 |
+
from analyze_qvm import write_json
|
| 6 |
+
from rust_map_commands_support import blob
|
| 7 |
+
def encode(s):
|
| 8 |
+
a=s['input'];out=[s['before'][k] for k in ['phase','option','flags','mode','first','second','blocked','pending','saved_second','saved_first','round']];out.extend([a['enabled'],a['cursor'],2,a['max_clients'],int(a['disconnect']),len(s['clients_before'])]);out.extend(c[str(o)] for c in s['clients_before'] for o in [248,304,308,468,696]);out.extend([*blob(a['updated']),*blob(a['mirror']),*blob(b'current_map'.hex())]);return out
|
| 9 |
+
def project(s):return {k:s[k] for k in ['state','cursor','filename','mirror','middle','clients']}|{'rotation_operations':s['parts']['rotation']['operations'],'map_operations':s['parts']['map']['operations']}
|
| 10 |
+
|
| 11 |
+
def main():
|
| 12 |
+
b=binary();p=Path('docs/research/qvm-normal-map-flow.json');data=p.read_bytes();rows=[]
|
| 13 |
+
for s in json.loads(data)['probes']:rows.append({'source':project(s),'rust':result(b,'flow',encode(s))})
|
| 14 |
+
write_json(Path('docs/research/rust-normal-map-flow.json'),{'source_report':str(p),'source_report_sha256':hashlib.sha256(data).hexdigest(),'probes':rows,'limits':'Rust matches192 original normal6939 cases, staging rotation, override map-command intentions, global/client resets and post-callback connection changes atomically. The API refuses team-series inputs and invalid callback indices. VM mirrors/pending/series data remain source-faithful; native callbacks, engine refresh and runtime integration remain open.'})
|
| 15 |
+
if __name__=='__main__':main()
|
scripts/test_rust_normal_map_flow.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-normal-map-flow.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-normal-map-flow.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
|
@@ -2501,3 +2501,18 @@ report scripts/analyze_qvm_normal_map_flow.py docs/research/qvm-normal-map-flow.
|
|
| 2501 |
edge docs/research/qvm-normal-map-flow.json scripts/test_qvm_normal_map_flow.py
|
| 2502 |
group normal-map-flow scripts/analyze_qvm_normal_map_flow.py
|
| 2503 |
edge scripts/analyze_qvm_normal_map_flow.py scripts/analyze_qvm_resumer_audit.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2501 |
edge docs/research/qvm-normal-map-flow.json scripts/test_qvm_normal_map_flow.py
|
| 2502 |
group normal-map-flow scripts/analyze_qvm_normal_map_flow.py
|
| 2503 |
edge scripts/analyze_qvm_normal_map_flow.py scripts/analyze_qvm_resumer_audit.py
|
| 2504 |
+
edge Cargo.toml scripts/analyze_rust_normal_map_flow.py
|
| 2505 |
+
edge Cargo.lock scripts/analyze_rust_normal_map_flow.py
|
| 2506 |
+
edge crates/urt-gameplay/Cargo.toml scripts/analyze_rust_normal_map_flow.py
|
| 2507 |
+
edge crates/urt-gameplay/src/lib.rs scripts/analyze_rust_normal_map_flow.py
|
| 2508 |
+
edge crates/urt-gameplay/src/map_commands.rs scripts/analyze_rust_normal_map_flow.py
|
| 2509 |
+
edge crates/urt-gameplay/src/bin/urt-map-commands.rs scripts/analyze_rust_normal_map_flow.py
|
| 2510 |
+
edge docs/research/qvm-normal-map-flow.json scripts/analyze_rust_normal_map_flow.py
|
| 2511 |
+
group rust-normal-map-flow scripts/analyze_rust_health_impulse.py
|
| 2512 |
+
group gameplay scripts/analyze_rust_normal_map_flow.py
|
| 2513 |
+
edge crates/urt-gameplay/src/transition.rs scripts/analyze_rust_normal_map_flow.py
|
| 2514 |
+
edge crates/urt-gameplay/src/intermission.rs scripts/analyze_rust_normal_map_flow.py
|
| 2515 |
+
report scripts/analyze_rust_normal_map_flow.py docs/research/rust-normal-map-flow.json
|
| 2516 |
+
edge docs/research/rust-normal-map-flow.json scripts/test_rust_normal_map_flow.py
|
| 2517 |
+
group rust-normal-map-flow scripts/analyze_rust_normal_map_flow.py
|
| 2518 |
+
edge scripts/analyze_rust_normal_map_flow.py scripts/analyze_qvm_resumer_audit.py
|
xtask/src/lib.rs
CHANGED
|
@@ -1106,6 +1106,11 @@ mod integration_tests {
|
|
| 1106 |
("transition", "event_construct"),
|
| 1107 |
("transition", "camera_world"),
|
| 1108 |
("camera_world", "camera_world"),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1109 |
("leaderboard", "leaderboard"),
|
| 1110 |
("recipient_wire", "recipient_wire"),
|
| 1111 |
] {
|
|
@@ -1176,6 +1181,11 @@ mod integration_tests {
|
|
| 1176 |
("qvm-target-pick", "target_pick"),
|
| 1177 |
("qvm-camera-angles", "camera_angles"),
|
| 1178 |
("qvm-camera-world", "camera_world"),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1179 |
] {
|
| 1180 |
let selected = plan(
|
| 1181 |
&g,
|
|
|
|
| 1106 |
("transition", "event_construct"),
|
| 1107 |
("transition", "camera_world"),
|
| 1108 |
("camera_world", "camera_world"),
|
| 1109 |
+
("camera_world", "camera_spawn"),
|
| 1110 |
+
("map_commands", "normal_map_flow"),
|
| 1111 |
+
("transition", "camera_spawn"),
|
| 1112 |
+
("transition", "normal_map_flow"),
|
| 1113 |
+
("intermission", "normal_map_flow"),
|
| 1114 |
("leaderboard", "leaderboard"),
|
| 1115 |
("recipient_wire", "recipient_wire"),
|
| 1116 |
] {
|
|
|
|
| 1181 |
("qvm-target-pick", "target_pick"),
|
| 1182 |
("qvm-camera-angles", "camera_angles"),
|
| 1183 |
("qvm-camera-world", "camera_world"),
|
| 1184 |
+
("qvm-spawn-fallback", "spawn_fallback"),
|
| 1185 |
+
("qvm-camera-spawn", "camera_spawn"),
|
| 1186 |
+
("qvm-rotation-advance", "rotation_advance"),
|
| 1187 |
+
("qvm-map-select", "map_select"),
|
| 1188 |
+
("qvm-normal-map-flow", "normal_map_flow"),
|
| 1189 |
] {
|
| 1190 |
let selected = plan(
|
| 1191 |
&g,
|