gameplay: resolve duration command persistence
Browse files- crates/urt-gameplay/src/bin/urt-filter-commands.rs +105 -0
- crates/urt-gameplay/src/filter_commands.rs +87 -0
- docs/FINDINGS.md +2 -0
- docs/PROVISIONAL_TODO.md +2 -0
- docs/RESEARCH_LEDGER.md +4 -0
- docs/REVERSE_ENGINEERING_TODO.md +2 -0
- docs/research/README.md +2 -0
- docs/research/RUST_FILTER_DURATION_EXPORT.md +5 -0
- docs/research/rust-filter-duration-export.json +0 -0
- docs/research/rust-health-impulse.json +1 -1
- scripts/analyze_rust_filter_duration_export.py +17 -0
- scripts/test_rust_filter_duration_export.py +9 -0
- xtask/checks.tsv +18 -0
crates/urt-gameplay/src/bin/urt-filter-commands.rs
CHANGED
|
@@ -149,6 +149,111 @@ fn main() {
|
|
| 149 |
let out = remove_filter_command(&mut rows, &text, issuer, &mut ring).unwrap();
|
| 150 |
println!("{}", command_json(out, &rows, n, ring, 0));
|
| 151 |
}
|
|
|
|
| 152 |
_ => panic!("unknown policy"),
|
| 153 |
}
|
| 154 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
let out = remove_filter_command(&mut rows, &text, issuer, &mut ring).unwrap();
|
| 150 |
println!("{}", command_json(out, &rows, n, ring, 0));
|
| 151 |
}
|
| 152 |
+
"duration-export" => println!("{}", duration_export(&w)),
|
| 153 |
_ => panic!("unknown policy"),
|
| 154 |
}
|
| 155 |
}
|
| 156 |
+
|
| 157 |
+
fn exported_json(p: Option<urt_gameplay::filter_lifecycle::FilterExport>) -> String {
|
| 158 |
+
let Some(p) = p else {
|
| 159 |
+
return r#"{"events":[],"formats":[],"buffer":"7374616c65"}"#.into();
|
| 160 |
+
};
|
| 161 |
+
use urt_gameplay::filter_lifecycle::FilterFileEffect;
|
| 162 |
+
let events = p
|
| 163 |
+
.effects()
|
| 164 |
+
.iter()
|
| 165 |
+
.map(|e| match e {
|
| 166 |
+
FilterFileEffect::Print(t) => format!(r#"{{"op":"print","text":"{}"}}"#, hex(t)),
|
| 167 |
+
FilterFileEffect::Open { path, mode } => {
|
| 168 |
+
format!(r#"{{"op":"open","path":"{}","mode":{}}}"#, hex(path), mode)
|
| 169 |
+
}
|
| 170 |
+
FilterFileEffect::Write { handle, bytes } => format!(
|
| 171 |
+
r#"{{"op":"write","handle":{},"text":"{}"}}"#,
|
| 172 |
+
handle,
|
| 173 |
+
hex(bytes)
|
| 174 |
+
),
|
| 175 |
+
FilterFileEffect::Close(h) => format!(r#"{{"op":"close","handle":{}}}"#, h),
|
| 176 |
+
})
|
| 177 |
+
.collect::<Vec<_>>()
|
| 178 |
+
.join(",");
|
| 179 |
+
let formats = p
|
| 180 |
+
.lines
|
| 181 |
+
.iter()
|
| 182 |
+
.map(|l| format!("\"{}\"", hex(l)))
|
| 183 |
+
.collect::<Vec<_>>()
|
| 184 |
+
.join(",");
|
| 185 |
+
format!(
|
| 186 |
+
r#"{{"events":[{}],"formats":[{}],"buffer":"{}"}}"#,
|
| 187 |
+
events,
|
| 188 |
+
formats,
|
| 189 |
+
hex(&p.text)
|
| 190 |
+
)
|
| 191 |
+
}
|
| 192 |
+
fn duration_export(w: &[u32]) -> String {
|
| 193 |
+
let mut p = 4;
|
| 194 |
+
let address = blob(w, &mut p);
|
| 195 |
+
let duration = blob(w, &mut p);
|
| 196 |
+
assert_eq!(p, w.len());
|
| 197 |
+
let fields = [13, w[0], 0, 4, 5, 126, 6, 0, 0];
|
| 198 |
+
let issuer = if w[1] == u32::MAX {
|
| 199 |
+
None
|
| 200 |
+
} else {
|
| 201 |
+
Some(w[1] as i32)
|
| 202 |
+
};
|
| 203 |
+
let mut ring = w[2];
|
| 204 |
+
let mut rows = [
|
| 205 |
+
FilterRecord {
|
| 206 |
+
mask: u32::MAX,
|
| 207 |
+
comparison: 0x04030201,
|
| 208 |
+
metadata: 77,
|
| 209 |
+
},
|
| 210 |
+
FilterRecord {
|
| 211 |
+
mask: u32::MAX,
|
| 212 |
+
comparison: 0x04030201,
|
| 213 |
+
metadata: 88,
|
| 214 |
+
},
|
| 215 |
+
];
|
| 216 |
+
let out = resolved_filter_duration(
|
| 217 |
+
&mut rows, &address, &duration, &fields, issuer, &mut ring, w[3],
|
| 218 |
+
)
|
| 219 |
+
.unwrap();
|
| 220 |
+
let exported = out
|
| 221 |
+
.export
|
| 222 |
+
.map(|p| exported_json(Some(p)))
|
| 223 |
+
.unwrap_or_default();
|
| 224 |
+
let out = out.command;
|
| 225 |
+
use urt_gameplay::filter_loading::FilterDurationEffect;
|
| 226 |
+
let events = out
|
| 227 |
+
.effects
|
| 228 |
+
.iter()
|
| 229 |
+
.map(|e| match e {
|
| 230 |
+
FilterDurationEffect::Console(t) => {
|
| 231 |
+
format!(r#"{{"op":"console","text":"{}"}}"#, hex(t))
|
| 232 |
+
}
|
| 233 |
+
FilterDurationEffect::Send { recipient, text } => format!(
|
| 234 |
+
r#"{{"op":"send","recipient":{},"text":"{}"}}"#,
|
| 235 |
+
recipient,
|
| 236 |
+
hex(text)
|
| 237 |
+
),
|
| 238 |
+
FilterDurationEffect::Time => r#"{"op":"time"}"#.into(),
|
| 239 |
+
FilterDurationEffect::Metadata { text, value } => format!(
|
| 240 |
+
r#"{{"op":"metadata","text":"{}","metadata":{},"save":1}}"#,
|
| 241 |
+
hex(text),
|
| 242 |
+
value
|
| 243 |
+
),
|
| 244 |
+
})
|
| 245 |
+
.collect::<Vec<String>>()
|
| 246 |
+
.join(",");
|
| 247 |
+
let updates = out
|
| 248 |
+
.update
|
| 249 |
+
.map(|p| children_json(&[p.into()]))
|
| 250 |
+
.unwrap_or_default();
|
| 251 |
+
format!(
|
| 252 |
+
r#"{{"events":[{}],"updates":[{}],"ring":{},"rows":[{}],"exported":[{}]}}"#,
|
| 253 |
+
events,
|
| 254 |
+
updates,
|
| 255 |
+
ring,
|
| 256 |
+
rows.into_iter().map(row_json).collect::<Vec<_>>().join(","),
|
| 257 |
+
exported
|
| 258 |
+
)
|
| 259 |
+
}
|
crates/urt-gameplay/src/filter_commands.rs
CHANGED
|
@@ -340,3 +340,90 @@ mod remove_tests {
|
|
| 340 |
assert_eq!(ring, 7);
|
| 341 |
}
|
| 342 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 340 |
assert_eq!(ring, 7);
|
| 341 |
}
|
| 342 |
}
|
| 343 |
+
|
| 344 |
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
| 345 |
+
pub struct ResolvedFilterDuration {
|
| 346 |
+
pub command: crate::filter_loading::FilterDuration,
|
| 347 |
+
pub export: Option<crate::filter_lifecycle::FilterExport>,
|
| 348 |
+
}
|
| 349 |
+
/// Compose252213/252127/252500, resolving a successful save request into exact
|
| 350 |
+
/// export bytes/effects while retaining captured native time/handle replies.
|
| 351 |
+
pub fn resolved_filter_duration(
|
| 352 |
+
records: &mut [FilterRecord],
|
| 353 |
+
address: &[u8],
|
| 354 |
+
duration: &[u8],
|
| 355 |
+
fields: &[u32; 9],
|
| 356 |
+
issuer: Option<i32>,
|
| 357 |
+
ring: &mut u32,
|
| 358 |
+
handle: u32,
|
| 359 |
+
) -> Result<ResolvedFilterDuration, Error> {
|
| 360 |
+
let mut staged = records.to_vec();
|
| 361 |
+
let mut counter = *ring;
|
| 362 |
+
let command = crate::filter_loading::filter_duration(
|
| 363 |
+
&mut staged,
|
| 364 |
+
address,
|
| 365 |
+
duration,
|
| 366 |
+
fields,
|
| 367 |
+
issuer,
|
| 368 |
+
&mut counter,
|
| 369 |
+
)?;
|
| 370 |
+
let export = if command.update.as_ref().is_some_and(|p| p.export) {
|
| 371 |
+
crate::filter_lifecycle::export_filters(&staged, handle)?
|
| 372 |
+
} else {
|
| 373 |
+
None
|
| 374 |
+
};
|
| 375 |
+
records.copy_from_slice(&staged);
|
| 376 |
+
*ring = counter;
|
| 377 |
+
Ok(ResolvedFilterDuration { command, export })
|
| 378 |
+
}
|
| 379 |
+
#[cfg(test)]
|
| 380 |
+
mod duration_export_tests {
|
| 381 |
+
use super::*;
|
| 382 |
+
#[test]
|
| 383 |
+
fn first_duplicate_updates_then_both_export_in_order_through_zero_handle() {
|
| 384 |
+
let row = FilterRecord {
|
| 385 |
+
mask: u32::MAX,
|
| 386 |
+
comparison: 0x04030201,
|
| 387 |
+
metadata: 7,
|
| 388 |
+
};
|
| 389 |
+
let mut rows = [row, FilterRecord { metadata: 8, ..row }];
|
| 390 |
+
let mut ring = 9;
|
| 391 |
+
let p = resolved_filter_duration(&mut rows, b"1.2.3.4", b"5", &[0; 9], None, &mut ring, 0)
|
| 392 |
+
.unwrap();
|
| 393 |
+
let export = p.export.unwrap();
|
| 394 |
+
assert_eq!(export.text, b"1.2.3.4:5\n1.2.3.4:8\n");
|
| 395 |
+
assert_eq!(export.handle, 0);
|
| 396 |
+
assert_eq!(ring, 9);
|
| 397 |
+
assert!(p.command.update.unwrap().export);
|
| 398 |
+
}
|
| 399 |
+
#[test]
|
| 400 |
+
fn usage_miss_and_unsupported_domains_do_not_export_or_partially_mutate() {
|
| 401 |
+
let row = FilterRecord {
|
| 402 |
+
mask: u32::MAX,
|
| 403 |
+
comparison: 0x04030201,
|
| 404 |
+
metadata: 7,
|
| 405 |
+
};
|
| 406 |
+
let mut rows = [row];
|
| 407 |
+
let mut ring = u32::MAX;
|
| 408 |
+
assert!(
|
| 409 |
+
resolved_filter_duration(&mut rows, b"", b"5", &[0; 9], Some(2), &mut ring, 7)
|
| 410 |
+
.unwrap()
|
| 411 |
+
.export
|
| 412 |
+
.is_none()
|
| 413 |
+
);
|
| 414 |
+
assert_eq!(ring, 0);
|
| 415 |
+
assert!(
|
| 416 |
+
resolved_filter_duration(&mut rows, b"2.3.4.5", b"5", &[0; 9], None, &mut ring, 7)
|
| 417 |
+
.unwrap()
|
| 418 |
+
.export
|
| 419 |
+
.is_none()
|
| 420 |
+
);
|
| 421 |
+
assert_eq!(rows, [row]);
|
| 422 |
+
assert!(
|
| 423 |
+
resolved_filter_duration(&mut rows, &[b'1'; 128], b"5", &[0; 9], None, &mut ring, 7)
|
| 424 |
+
.is_err()
|
| 425 |
+
);
|
| 426 |
+
assert_eq!(rows, [row]);
|
| 427 |
+
assert_eq!(ring, 0);
|
| 428 |
+
}
|
| 429 |
+
}
|
docs/FINDINGS.md
CHANGED
|
@@ -1849,3 +1849,5 @@ RE-956: Twenty-four actual253245 wrappers compose actual253296 removal and sourc
|
|
| 1849 |
RE-957: Rust matches24 original removal-wrapper cases, preserving exact client/console usage, formatter wrap, first-match duplicate/sentinel mutations, child diagnostics and conditional export. The API leaves caller table length and userinfo selector ownership untouched. Unit tests cover empty-input child suppression, duplicate metadata retention, ordinary parser failure and atomic unsupported-token rejection. Native effects remain captured plans. [Evidence](research/RUST_FILTER_REMOVE_COMMAND.md).
|
| 1850 |
|
| 1851 |
RE-958: Eighty actual252213/252127/252500 compositions resolve the prior captured export request into source-generated bytes and ordered print/open/write/close effects. Duplicate metadata updates only the first row, then export serializes both rows in order. Usage, invalid parsing and absent matches skip export. Supplied zero handles still reach write/close; time/network/file execution remains captured or supplied. [Evidence](research/QVM_FILTER_DURATION_EXPORT.md).
|
|
|
|
|
|
|
|
|
| 1849 |
RE-957: Rust matches24 original removal-wrapper cases, preserving exact client/console usage, formatter wrap, first-match duplicate/sentinel mutations, child diagnostics and conditional export. The API leaves caller table length and userinfo selector ownership untouched. Unit tests cover empty-input child suppression, duplicate metadata retention, ordinary parser failure and atomic unsupported-token rejection. Native effects remain captured plans. [Evidence](research/RUST_FILTER_REMOVE_COMMAND.md).
|
| 1850 |
|
| 1851 |
RE-958: Eighty actual252213/252127/252500 compositions resolve the prior captured export request into source-generated bytes and ordered print/open/write/close effects. Duplicate metadata updates only the first row, then export serializes both rows in order. Usage, invalid parsing and absent matches skip export. Supplied zero handles still reach write/close; time/network/file execution remains captured or supplied. [Evidence](research/QVM_FILTER_DURATION_EXPORT.md).
|
| 1852 |
+
|
| 1853 |
+
RE-959: Rust matches80 original duration/update/export compositions, deriving exact file payloads and typed effects from a successful metadata save request. Duplicate order, zero handles, usage/miss export suppression and formatter counters are retained. Unit tests cover first-row update with two-row export and atomic unsupported-domain rejection. Native time/file/network execution remains supplied or captured. [Evidence](research/RUST_FILTER_DURATION_EXPORT.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1899,3 +1899,5 @@ RE-944–953 completed bounded time/expiry/loading/duration and export/reload co
|
|
| 1899 |
- [x] RE-957 Rust remove-filter wrapper and source usage effects ([evidence](research/RUST_FILTER_REMOVE_COMMAND.md)).
|
| 1900 |
|
| 1901 |
- [x] RE-958 Original duration command with metadata and export resolved ([evidence](research/QVM_FILTER_DURATION_EXPORT.md)).
|
|
|
|
|
|
|
|
|
| 1899 |
- [x] RE-957 Rust remove-filter wrapper and source usage effects ([evidence](research/RUST_FILTER_REMOVE_COMMAND.md)).
|
| 1900 |
|
| 1901 |
- [x] RE-958 Original duration command with metadata and export resolved ([evidence](research/QVM_FILTER_DURATION_EXPORT.md)).
|
| 1902 |
+
|
| 1903 |
+
- [x] RE-959 Rust duration command with resolved persistence plan ([evidence](research/RUST_FILTER_DURATION_EXPORT.md)).
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -2501,3 +2501,7 @@ Rust matches24 original removal-wrapper cases, preserving exact client/console u
|
|
| 2501 |
## 2026-10-28 — RE-958 Original duration command with metadata and export resolved
|
| 2502 |
|
| 2503 |
Eighty actual252213/252127/252500 compositions resolve the prior captured export request into source-generated bytes and ordered print/open/write/close effects. Duplicate metadata updates only the first row, then export serializes both rows in order. Usage, invalid parsing and absent matches skip export. Supplied zero handles still reach write/close; time/network/file execution remains captured or supplied. Focused `cargo xtask test-group qvm-filter-duration-export` passes with deterministic report regeneration, relevant regressions and storage/documentation/whitespace checks. Full suite deferred to the tenth-commit boundary. Original assets unchanged; native IO effects remain captured.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2501 |
## 2026-10-28 — RE-958 Original duration command with metadata and export resolved
|
| 2502 |
|
| 2503 |
Eighty actual252213/252127/252500 compositions resolve the prior captured export request into source-generated bytes and ordered print/open/write/close effects. Duplicate metadata updates only the first row, then export serializes both rows in order. Usage, invalid parsing and absent matches skip export. Supplied zero handles still reach write/close; time/network/file execution remains captured or supplied. Focused `cargo xtask test-group qvm-filter-duration-export` passes with deterministic report regeneration, relevant regressions and storage/documentation/whitespace checks. Full suite deferred to the tenth-commit boundary. Original assets unchanged; native IO effects remain captured.
|
| 2504 |
+
|
| 2505 |
+
## 2026-10-28 — RE-959 Rust duration command with resolved persistence plan
|
| 2506 |
+
|
| 2507 |
+
Rust matches80 original duration/update/export compositions, deriving exact file payloads and typed effects from a successful metadata save request. Duplicate order, zero handles, usage/miss export suppression and formatter counters are retained. Unit tests cover first-row update with two-row export and atomic unsupported-domain rejection. Native time/file/network execution remains supplied or captured. Focused `cargo xtask test-group rust-filter-duration-export` passes with deterministic report regeneration, relevant regressions and storage/documentation/whitespace checks. Full suite deferred to the tenth-commit boundary. Original assets unchanged; native IO effects remain captured.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -1936,3 +1936,5 @@ RE-944–953 recover bounded time, expiry, loading, duration and persistence rou
|
|
| 1936 |
- [x] RE-957 Rust remove-filter wrapper and source usage effects ([evidence](research/RUST_FILTER_REMOVE_COMMAND.md)).
|
| 1937 |
|
| 1938 |
- [x] RE-958 Original duration command with metadata and export resolved ([evidence](research/QVM_FILTER_DURATION_EXPORT.md)).
|
|
|
|
|
|
|
|
|
| 1936 |
- [x] RE-957 Rust remove-filter wrapper and source usage effects ([evidence](research/RUST_FILTER_REMOVE_COMMAND.md)).
|
| 1937 |
|
| 1938 |
- [x] RE-958 Original duration command with metadata and export resolved ([evidence](research/QVM_FILTER_DURATION_EXPORT.md)).
|
| 1939 |
+
|
| 1940 |
+
- [x] RE-959 Rust duration command with resolved persistence plan ([evidence](research/RUST_FILTER_DURATION_EXPORT.md)).
|
docs/research/README.md
CHANGED
|
@@ -1471,3 +1471,5 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 1471 |
- [RE-957: Rust remove-filter wrapper and source usage effects](RUST_FILTER_REMOVE_COMMAND.md).
|
| 1472 |
|
| 1473 |
- [RE-958: Original duration command with metadata and export resolved](QVM_FILTER_DURATION_EXPORT.md).
|
|
|
|
|
|
|
|
|
| 1471 |
- [RE-957: Rust remove-filter wrapper and source usage effects](RUST_FILTER_REMOVE_COMMAND.md).
|
| 1472 |
|
| 1473 |
- [RE-958: Original duration command with metadata and export resolved](QVM_FILTER_DURATION_EXPORT.md).
|
| 1474 |
+
|
| 1475 |
+
- [RE-959: Rust duration command with resolved persistence plan](RUST_FILTER_DURATION_EXPORT.md).
|
docs/research/RUST_FILTER_DURATION_EXPORT.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Rust duration command with resolved persistence plan
|
| 2 |
+
|
| 3 |
+
RE-959. Focused validation: `cargo xtask test-group rust-filter-duration-export`. [Machine report](rust-filter-duration-export.json).
|
| 4 |
+
|
| 5 |
+
Rust matches80 original duration/update/export compositions, deriving exact file payloads and typed effects from a successful metadata save request. Duplicate order, zero handles, usage/miss export suppression and formatter counters are retained. Unit tests cover first-row update with two-row export and atomic unsupported-domain rejection. Native time/file/network execution remains supplied or captured.
|
docs/research/rust-filter-duration-export.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
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": 215,
|
| 2989 |
"source_report": "docs/research/qvm-health-impulse.json",
|
| 2990 |
"source_report_sha256": "625fd8064004ea6dbdf398d51d0af844d9c635ff04c0a0790886dddb6ab81e71"
|
| 2991 |
}
|
scripts/analyze_rust_filter_duration_export.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Compare recovered Rust policy with original QVM fixtures."""
|
| 2 |
+
import hashlib,json,os,subprocess
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from analyze_qvm import write_json
|
| 5 |
+
from rust_lifecycle_support import result
|
| 6 |
+
|
| 7 |
+
def main():
|
| 8 |
+
subprocess.run(['cargo','build','--offline','--package','urt-gameplay','--bin','urt-filter-commands'],check=True,capture_output=True)
|
| 9 |
+
binary=Path(os.environ.get('CARGO_TARGET_DIR','target'))/'debug'/'urt-filter-commands'
|
| 10 |
+
path=Path('docs/research/qvm-filter-duration-export.json');data=path.read_bytes();probes=[]
|
| 11 |
+
for p in json.loads(data)['probes']:
|
| 12 |
+
probes.append(dict(source={k:p[k] for k in ['events', 'updates', 'ring', 'rows', 'exported']},rust=result(binary,'duration-export',encode(p['input']))))
|
| 13 |
+
write_json(Path('docs/research/rust-filter-duration-export.json'),dict(source_report=str(path),source_report_sha256=hashlib.sha256(data).hexdigest(),probes=probes,limits='Finite source/Rust contract parity; native time/file/network replies remain supplied or captured.'))
|
| 14 |
+
|
| 15 |
+
def encode(a):
|
| 16 |
+
ip=bytes.fromhex(a['address']);d=bytes.fromhex(a['duration']);return [a['now'],a['client'],a['ring'],a['handle'],len(ip),*ip,len(d),*d]
|
| 17 |
+
if __name__=='__main__':main()
|
scripts/test_rust_filter_duration_export.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import hashlib,json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
class PortTests(unittest.TestCase):
|
| 4 |
+
def test_original_parity(self):
|
| 5 |
+
r=json.loads(Path('docs/research/rust-filter-duration-export.json').read_text());self.assertGreaterEqual(len(r['probes']),12)
|
| 6 |
+
for p in r['probes']:self.assertEqual(p['source'],p['rust'])
|
| 7 |
+
def test_identity(self):
|
| 8 |
+
r=json.loads(Path('docs/research/rust-filter-duration-export.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
|
@@ -3354,3 +3354,21 @@ report scripts/analyze_qvm_filter_duration_export.py docs/research/qvm-filter-du
|
|
| 3354 |
edge docs/research/qvm-filter-duration-export.json scripts/test_qvm_filter_duration_export.py
|
| 3355 |
group qvm-filter-duration-export scripts/analyze_qvm_filter_duration_export.py
|
| 3356 |
edge scripts/analyze_qvm_filter_duration_export.py scripts/analyze_qvm_resumer_audit.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3354 |
edge docs/research/qvm-filter-duration-export.json scripts/test_qvm_filter_duration_export.py
|
| 3355 |
group qvm-filter-duration-export scripts/analyze_qvm_filter_duration_export.py
|
| 3356 |
edge scripts/analyze_qvm_filter_duration_export.py scripts/analyze_qvm_resumer_audit.py
|
| 3357 |
+
report scripts/analyze_rust_filter_duration_export.py docs/research/rust-filter-duration-export.json
|
| 3358 |
+
edge docs/research/rust-filter-duration-export.json scripts/test_rust_filter_duration_export.py
|
| 3359 |
+
group rust-filter-duration-export scripts/analyze_rust_filter_duration_export.py
|
| 3360 |
+
edge scripts/analyze_rust_filter_duration_export.py scripts/analyze_qvm_resumer_audit.py
|
| 3361 |
+
edge Cargo.toml scripts/analyze_rust_filter_duration_export.py
|
| 3362 |
+
edge Cargo.lock scripts/analyze_rust_filter_duration_export.py
|
| 3363 |
+
edge crates/urt-gameplay/Cargo.toml scripts/analyze_rust_filter_duration_export.py
|
| 3364 |
+
edge crates/urt-gameplay/src/lib.rs scripts/analyze_rust_filter_duration_export.py
|
| 3365 |
+
edge crates/urt-gameplay/src/filter_loading.rs scripts/analyze_rust_filter_duration_export.py
|
| 3366 |
+
edge crates/urt-gameplay/src/filter_lifecycle.rs scripts/analyze_rust_filter_duration_export.py
|
| 3367 |
+
edge crates/urt-gameplay/src/native_policy.rs scripts/analyze_rust_filter_duration_export.py
|
| 3368 |
+
edge crates/urt-gameplay/src/bin/urt-filter-loading.rs scripts/analyze_rust_filter_duration_export.py
|
| 3369 |
+
edge crates/urt-gameplay/src/qvm_format.rs scripts/analyze_rust_filter_duration_export.py
|
| 3370 |
+
edge docs/research/qvm-filter-duration-export.json scripts/analyze_rust_filter_duration_export.py
|
| 3371 |
+
group rust-filter-duration-export scripts/analyze_rust_health_impulse.py
|
| 3372 |
+
group gameplay scripts/analyze_rust_filter_duration_export.py
|
| 3373 |
+
edge crates/urt-gameplay/src/filter_commands.rs scripts/analyze_rust_filter_duration_export.py
|
| 3374 |
+
edge crates/urt-gameplay/src/bin/urt-filter-commands.rs scripts/analyze_rust_filter_duration_export.py
|