gameplay: port recent record awards
Browse files- crates/urt-gameplay/src/bin/urt-lifecycle.rs +46 -0
- crates/urt-gameplay/src/lib.rs +1 -0
- crates/urt-gameplay/src/recent_awards.rs +130 -0
- docs/ASSET_PIPELINE_TODO.md +3 -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_RECENT_AWARDS.md +7 -0
- docs/research/rust-health-impulse.json +1 -1
- docs/research/rust-recent-awards.json +0 -0
- scripts/analyze_rust_recent_awards.py +13 -0
- scripts/test_rust_recent_awards.py +13 -0
- xtask/checks.tsv +10 -0
crates/urt-gameplay/src/bin/urt-lifecycle.rs
CHANGED
|
@@ -223,6 +223,52 @@ fn run() -> Result<(), String> {
|
|
| 223 |
n.ratio.to_bits()
|
| 224 |
);
|
| 225 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
_ => return Err("unsupported contract or arguments".into()),
|
| 227 |
}
|
| 228 |
Ok(())
|
|
|
|
| 223 |
n.ratio.to_bits()
|
| 224 |
);
|
| 225 |
}
|
| 226 |
+
"award" if w.len() == 7 && w[6] <= 1 => {
|
| 227 |
+
use urt_gameplay::recent_awards::{Client, Rows, award};
|
| 228 |
+
let index = w[1] as i32;
|
| 229 |
+
let key = if (0..=64).contains(&index) {
|
| 230 |
+
index as usize
|
| 231 |
+
} else {
|
| 232 |
+
0
|
| 233 |
+
};
|
| 234 |
+
let mut rows: Rows = std::array::from_fn(|j| {
|
| 235 |
+
if [0, 1, 2, 3, 64].contains(&j) && (j != 2 || w[6] != 0) {
|
| 236 |
+
let mut pairs = [[0; 2]; 65];
|
| 237 |
+
pairs[64][0] = w[4] as i32;
|
| 238 |
+
pairs[key] = [w[2] as i32, (w[5] as i32).wrapping_sub(w[3] as i32)];
|
| 239 |
+
Some(Client {
|
| 240 |
+
id: j as i32,
|
| 241 |
+
team: if j == 1 || j == 64 { 1 } else { 2 },
|
| 242 |
+
pairs,
|
| 243 |
+
})
|
| 244 |
+
} else {
|
| 245 |
+
None
|
| 246 |
+
}
|
| 247 |
+
});
|
| 248 |
+
let awards = award(w[0] as i32, index, 2, w[5] as i32, &mut rows)
|
| 249 |
+
.map_err(|e| format!("unsupported input: {e:?}"))?;
|
| 250 |
+
let intents: Vec<_> = awards
|
| 251 |
+
.iter()
|
| 252 |
+
.map(|a| format!("[{},{},{}]", a.recipient, a.offender, a.victim))
|
| 253 |
+
.collect();
|
| 254 |
+
let values: Vec<_> = rows
|
| 255 |
+
.iter()
|
| 256 |
+
.enumerate()
|
| 257 |
+
.filter_map(|(j, r)| {
|
| 258 |
+
r.as_ref().map(|r| {
|
| 259 |
+
format!(
|
| 260 |
+
"{{\"slot\":{},\"awards\":{},\"count\":{}}}",
|
| 261 |
+
j, r.pairs[64][0] as u32, r.pairs[key][0] as u32
|
| 262 |
+
)
|
| 263 |
+
})
|
| 264 |
+
})
|
| 265 |
+
.collect();
|
| 266 |
+
println!(
|
| 267 |
+
"{{\"awards\":[{}],\"rows\":[{}]}}",
|
| 268 |
+
intents.join(","),
|
| 269 |
+
values.join(",")
|
| 270 |
+
);
|
| 271 |
+
}
|
| 272 |
_ => return Err("unsupported contract or arguments".into()),
|
| 273 |
}
|
| 274 |
Ok(())
|
crates/urt-gameplay/src/lib.rs
CHANGED
|
@@ -149,6 +149,7 @@ pub mod intercept_animation;
|
|
| 149 |
pub mod method_stats;
|
| 150 |
pub mod mode10;
|
| 151 |
pub mod protected;
|
|
|
|
| 152 |
pub mod record_clear;
|
| 153 |
pub mod score;
|
| 154 |
pub mod stat_totals;
|
|
|
|
| 149 |
pub mod method_stats;
|
| 150 |
pub mod mode10;
|
| 151 |
pub mod protected;
|
| 152 |
+
pub mod recent_awards;
|
| 153 |
pub mod record_clear;
|
| 154 |
pub mod score;
|
| 155 |
pub mod stat_totals;
|
crates/urt-gameplay/src/recent_awards.rs
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//! Source285227 record eligibility and award intent, without logging/networking.
|
| 2 |
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
| 3 |
+
pub struct Client {
|
| 4 |
+
pub id: i32,
|
| 5 |
+
pub team: i32,
|
| 6 |
+
pub pairs: [[i32; 2]; 65],
|
| 7 |
+
}
|
| 8 |
+
pub type Rows = [Option<Client>; 65];
|
| 9 |
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
| 10 |
+
pub struct Award {
|
| 11 |
+
pub recipient: i32,
|
| 12 |
+
pub offender: i32,
|
| 13 |
+
pub victim: i32,
|
| 14 |
+
}
|
| 15 |
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
| 16 |
+
pub enum AwardError {
|
| 17 |
+
UnsupportedOffender,
|
| 18 |
+
}
|
| 19 |
+
/// Rows0..63 are recipients; row64 is accepted as the victim. Pair64[0]
|
| 20 |
+
/// aliases the award counter, preserving the source3032 storage overlap.
|
| 21 |
+
pub fn award(
|
| 22 |
+
mode: i32,
|
| 23 |
+
index: i32,
|
| 24 |
+
offender: i32,
|
| 25 |
+
now: i32,
|
| 26 |
+
rows: &mut Rows,
|
| 27 |
+
) -> Result<Vec<Award>, AwardError> {
|
| 28 |
+
let Ok(index) = usize::try_from(index) else {
|
| 29 |
+
return Ok(vec![]);
|
| 30 |
+
};
|
| 31 |
+
if index > 64 || mode < 3 || mode == 9 || mode == 11 {
|
| 32 |
+
return Ok(vec![]);
|
| 33 |
+
}
|
| 34 |
+
let Some(victim) = rows[index].as_ref() else {
|
| 35 |
+
return Ok(vec![]);
|
| 36 |
+
};
|
| 37 |
+
let (victim_id, victim_team) = (victim.id, victim.team);
|
| 38 |
+
let actor_index = usize::try_from(offender)
|
| 39 |
+
.ok()
|
| 40 |
+
.filter(|i| *i <= 64)
|
| 41 |
+
.ok_or(AwardError::UnsupportedOffender)?;
|
| 42 |
+
let Some(actor) = rows[actor_index].as_ref() else {
|
| 43 |
+
return Ok(vec![]);
|
| 44 |
+
};
|
| 45 |
+
let actor_id = actor.id;
|
| 46 |
+
let mut requests = vec![];
|
| 47 |
+
for row in rows.iter_mut().take(64).flatten() {
|
| 48 |
+
if row.id == offender
|
| 49 |
+
|| row.team == victim_team
|
| 50 |
+
|| row.pairs[index][0] < 40
|
| 51 |
+
|| now.wrapping_sub(row.pairs[index][1]) > 30000
|
| 52 |
+
{
|
| 53 |
+
continue;
|
| 54 |
+
}
|
| 55 |
+
row.pairs[64][0] = row.pairs[64][0].wrapping_add(1);
|
| 56 |
+
requests.push(Award {
|
| 57 |
+
recipient: row.id,
|
| 58 |
+
offender: actor_id,
|
| 59 |
+
victim: victim_id,
|
| 60 |
+
});
|
| 61 |
+
}
|
| 62 |
+
Ok(requests)
|
| 63 |
+
}
|
| 64 |
+
#[cfg(test)]
|
| 65 |
+
mod tests {
|
| 66 |
+
use super::*;
|
| 67 |
+
fn rows() -> Rows {
|
| 68 |
+
std::array::from_fn(|j| {
|
| 69 |
+
if [0, 1, 2, 64].contains(&j) {
|
| 70 |
+
let mut pairs = [[0; 2]; 65];
|
| 71 |
+
pairs[1] = [40, 10000];
|
| 72 |
+
pairs[64] = [40, 10000];
|
| 73 |
+
Some(Client {
|
| 74 |
+
id: j as i32,
|
| 75 |
+
team: if j == 1 || j == 64 { 1 } else { 2 },
|
| 76 |
+
pairs,
|
| 77 |
+
})
|
| 78 |
+
} else {
|
| 79 |
+
None
|
| 80 |
+
}
|
| 81 |
+
})
|
| 82 |
+
}
|
| 83 |
+
#[test]
|
| 84 |
+
fn inclusive64_and_alias_counter() {
|
| 85 |
+
let mut r = rows();
|
| 86 |
+
assert_eq!(
|
| 87 |
+
award(10, 64, 2, 40000, &mut r).unwrap(),
|
| 88 |
+
vec![Award {
|
| 89 |
+
recipient: 0,
|
| 90 |
+
offender: 2,
|
| 91 |
+
victim: 64
|
| 92 |
+
}]
|
| 93 |
+
);
|
| 94 |
+
assert_eq!(r[0].unwrap().pairs[64], [41, 10000]);
|
| 95 |
+
}
|
| 96 |
+
#[test]
|
| 97 |
+
fn future_timestamp_and_counter_wrap() {
|
| 98 |
+
let mut r = rows();
|
| 99 |
+
r[0].as_mut().unwrap().pairs[1][1] = 40001;
|
| 100 |
+
r[0].as_mut().unwrap().pairs[64][0] = -1;
|
| 101 |
+
assert_eq!(award(10, 1, 2, 40000, &mut r).unwrap().len(), 1);
|
| 102 |
+
assert_eq!(r[0].unwrap().pairs[64][0], 0);
|
| 103 |
+
}
|
| 104 |
+
#[test]
|
| 105 |
+
fn strict_age_and_count_thresholds() {
|
| 106 |
+
let mut r = rows();
|
| 107 |
+
let original = r;
|
| 108 |
+
r[0].as_mut().unwrap().pairs[1][1] = 9999;
|
| 109 |
+
assert!(award(10, 1, 2, 40000, &mut r).unwrap().is_empty());
|
| 110 |
+
let mut r = original;
|
| 111 |
+
r[0].as_mut().unwrap().pairs[1][0] = 39;
|
| 112 |
+
assert!(award(10, 1, 2, 40000, &mut r).unwrap().is_empty());
|
| 113 |
+
}
|
| 114 |
+
#[test]
|
| 115 |
+
fn gates_missing_actor_and_unsupported_offender() {
|
| 116 |
+
for (mode, index) in [(9, 1), (11, 1), (2, 1), (10, -1), (10, 65)] {
|
| 117 |
+
let mut r = rows();
|
| 118 |
+
let before = r;
|
| 119 |
+
assert!(award(mode, index, -1, 40000, &mut r).unwrap().is_empty());
|
| 120 |
+
assert_eq!(r, before);
|
| 121 |
+
}
|
| 122 |
+
let mut r = rows();
|
| 123 |
+
r[2] = None;
|
| 124 |
+
assert!(award(10, 1, 2, 40000, &mut r).unwrap().is_empty());
|
| 125 |
+
assert_eq!(
|
| 126 |
+
award(10, 1, -1, 40000, &mut r),
|
| 127 |
+
Err(AwardError::UnsupportedOffender)
|
| 128 |
+
);
|
| 129 |
+
}
|
| 130 |
+
}
|
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -955,3 +955,6 @@ Research progress: RE-764 [report](research/QVM_RANKING_SETUP.md); original asse
|
|
| 955 |
|
| 956 |
|
| 957 |
Research progress: RE-765 [report](research/RUST_STAT_TOTALS.md); original assets unchanged.
|
|
|
|
|
|
|
|
|
|
|
|
| 955 |
|
| 956 |
|
| 957 |
Research progress: RE-765 [report](research/RUST_STAT_TOTALS.md); original assets unchanged.
|
| 958 |
+
|
| 959 |
+
|
| 960 |
+
Research progress: RE-766 [report](research/RUST_RECENT_AWARDS.md); original assets unchanged.
|
docs/FINDINGS.md
CHANGED
|
@@ -1301,3 +1301,6 @@ RE-725–734 batch: [health, contact and Rust impulse findings](research/QVM_HEA
|
|
| 1301 |
|
| 1302 |
|
| 1303 |
**RE-765 — Rust counter totals divisor and normalized ratio primitives:** Rust totals and normalized ratios match80 total,28 ratio and38 signed-divisor source fixtures while retaining20 slots. [Evidence](research/RUST_STAT_TOTALS.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1301 |
|
| 1302 |
|
| 1303 |
**RE-765 — Rust counter totals divisor and normalized ratio primitives:** Rust totals and normalized ratios match80 total,28 ratio and38 signed-divisor source fixtures while retaining20 slots. [Evidence](research/RUST_STAT_TOTALS.md).
|
| 1304 |
+
|
| 1305 |
+
|
| 1306 |
+
**RE-766 — Rust recent record awards timestamp gates and alias storage:** Rust recent-record awards match68 source fixtures, preserving future ages, wrapped clocks, ID gates and index64 award/count aliasing. [Evidence](research/RUST_RECENT_AWARDS.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1296,3 +1296,6 @@ Research progress: RE-764 [report](research/QVM_RANKING_SETUP.md); full native/p
|
|
| 1296 |
|
| 1297 |
|
| 1298 |
Research progress: RE-765 [report](research/RUST_STAT_TOTALS.md); full native/platform/game scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
| 1296 |
|
| 1297 |
|
| 1298 |
Research progress: RE-765 [report](research/RUST_STAT_TOTALS.md); full native/platform/game scope remains open.
|
| 1299 |
+
|
| 1300 |
+
|
| 1301 |
+
Research progress: RE-766 [report](research/RUST_RECENT_AWARDS.md); full native/platform/game scope remains open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -1481,3 +1481,8 @@ Additional RE-763 regression: `cargo xtask test-group recipient-single` passes6
|
|
| 1481 |
## 2026-10-21 — RE-765 Rust counter totals divisor and normalized ratio primitives
|
| 1482 |
|
| 1483 |
Rust totals and normalized ratios match80 total,28 ratio and38 signed-divisor source fixtures while retaining20 slots. Focused `cargo xtask test-group gameplay` passes (25 Python tests); selected reports regenerate twice byte-identically, with storage, links and whitespace guards. New report: 32451 bytes. Full-suite validation is deferred to the tenth batch commit. Rust gameplay crate changed; focused gameplay regenerates eight parity contracts and scoped package tests. No workspace/full-suite run before commit ten.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1481 |
## 2026-10-21 — RE-765 Rust counter totals divisor and normalized ratio primitives
|
| 1482 |
|
| 1483 |
Rust totals and normalized ratios match80 total,28 ratio and38 signed-divisor source fixtures while retaining20 slots. Focused `cargo xtask test-group gameplay` passes (25 Python tests); selected reports regenerate twice byte-identically, with storage, links and whitespace guards. New report: 32451 bytes. Full-suite validation is deferred to the tenth batch commit. Rust gameplay crate changed; focused gameplay regenerates eight parity contracts and scoped package tests. No workspace/full-suite run before commit ten.
|
| 1484 |
+
|
| 1485 |
+
|
| 1486 |
+
## 2026-10-21 — RE-766 Rust recent record awards timestamp gates and alias storage
|
| 1487 |
+
|
| 1488 |
+
Rust recent-record awards match68 source fixtures, preserving future ages, wrapped clocks, ID gates and index64 award/count aliasing. Focused `cargo xtask test-group gameplay` passes (28 Python tests); selected reports regenerate twice byte-identically, with storage, links and whitespace guards. New report: 143080 bytes. Full-suite validation is deferred to the tenth batch commit. Rust gameplay crate changed; focused gameplay regenerates nine parity contracts and scoped package tests. Full workspace suite remains deferred to commit ten.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -1339,3 +1339,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1339 |
|
| 1340 |
|
| 1341 |
- [x] RE-765 Rust counter totals divisor and normalized ratio primitives ([report](research/RUST_STAT_TOTALS.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 1339 |
|
| 1340 |
|
| 1341 |
- [x] RE-765 Rust counter totals divisor and normalized ratio primitives ([report](research/RUST_STAT_TOTALS.md)).
|
| 1342 |
+
|
| 1343 |
+
|
| 1344 |
+
- [x] RE-766 Rust recent record awards timestamp gates and alias storage ([report](research/RUST_RECENT_AWARDS.md)).
|
docs/research/README.md
CHANGED
|
@@ -891,3 +891,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 891 |
|
| 892 |
|
| 893 |
[RE-765: Rust counter totals divisor and normalized ratio primitives](RUST_STAT_TOTALS.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 891 |
|
| 892 |
|
| 893 |
[RE-765: Rust counter totals divisor and normalized ratio primitives](RUST_STAT_TOTALS.md).
|
| 894 |
+
|
| 895 |
+
|
| 896 |
+
[RE-766: Rust recent record awards timestamp gates and alias storage](RUST_RECENT_AWARDS.md).
|
docs/research/RUST_RECENT_AWARDS.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Rust recent record awards timestamp gates and alias storage
|
| 2 |
+
|
| 3 |
+
RE-766. Reproduce with `python3 scripts/analyze_rust_recent_awards.py`; validate with `cargo xtask test-group gameplay`. See the [machine report](rust-recent-awards.json).
|
| 4 |
+
|
| 5 |
+
Added typed65-row records,64-recipient scan, source signed/wrapping eligibility and returned log ID intents. Pair64[0] is the award counter rather than separate storage. Four Rust unit tests cover equality, future timestamps, count/counter wrap, empty/invalid gates and explicit unsupported offender indices. Log formatting, record lifetime ownership and native/platform parity remain open.
|
| 6 |
+
|
| 7 |
+
No original executable/full VM/native world collision or rendering runs. Supplied callback/native responses and fixture domains remain explicit; complete macOS/Linux Rust/Bevy/Solari gameplay remains open.
|
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": 38,
|
| 2989 |
"source_report": "docs/research/qvm-health-impulse.json",
|
| 2990 |
"source_report_sha256": "625fd8064004ea6dbdf398d51d0af844d9c635ff04c0a0790886dddb6ab81e71"
|
| 2991 |
}
|
docs/research/rust-recent-awards.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_rust_recent_awards.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Rust recent-award records and logging intent against source285227 fixtures."""
|
| 3 |
+
import hashlib,json
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from rust_lifecycle_support import binary,result
|
| 6 |
+
from analyze_qvm import write_json
|
| 7 |
+
|
| 8 |
+
def main():
|
| 9 |
+
b=binary();path=Path('docs/research/qvm-recent-awards.json');data=path.read_bytes();rows=[]
|
| 10 |
+
for p in json.loads(data)['probes']:
|
| 11 |
+
a=p['input'];args=[a.get('mode',10),a['index'],a.get('count',40),a.get('age',30000),a.get('initial',7),a.get('now',40000),int(a.get('actor_client',True))];expected={'awards':[[c['arguments'][str(k)] for k in [12,16,20]] for c in p['requests']],'rows':[{k:r[k] for k in ['slot','awards','count']} for r in p['final'] if r['present']]};rows.append({'input':a,'initial':p['initial'],'source':expected,'rust':result(b,'award',args)})
|
| 12 |
+
write_json(Path('docs/research/rust-recent-awards.json'),{'source_report':str(path),'source_report_sha256':hashlib.sha256(data).hexdigest(),'probes':rows,'limits':'Rust numeric recent awards and log ID intents match68 source fixtures.65 rows support victim64; only64 recipients are scanned. Pair64[0] shares award/count storage. Unsupported offender indices explicitly reject; live lifetime ownership/log formatting/native/platform parity remain open.'})
|
| 13 |
+
if __name__=='__main__':main()
|
scripts/test_rust_recent_awards.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import hashlib,json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from test_qvm_recent_awards import awarded
|
| 4 |
+
class RustRecentAwardTests(unittest.TestCase):
|
| 5 |
+
@classmethod
|
| 6 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/rust-recent-awards.json').read_text())
|
| 7 |
+
def test_exact_source_records_and_intents(self):
|
| 8 |
+
self.assertEqual(len(self.r['probes']),68)
|
| 9 |
+
for p in self.r['probes']:self.assertEqual(p['rust'],p['source'],p['input'])
|
| 10 |
+
def test_independent_gates_and_identifier_intent(self):
|
| 11 |
+
for p in self.r['probes']:self.assertEqual(p['rust']['awards'],[[j,2,p['input']['index']] for j in awarded(p)])
|
| 12 |
+
def test_source_identity(self):self.assertEqual(hashlib.sha256(Path(self.r['source_report']).read_bytes()).hexdigest(),self.r['source_report_sha256'])
|
| 13 |
+
if __name__=='__main__':unittest.main()
|
xtask/checks.tsv
CHANGED
|
@@ -1303,3 +1303,13 @@ edge crates/urt-gameplay/src/stat_totals.rs scripts/analyze_rust_health_impulse.
|
|
| 1303 |
group gameplay scripts/analyze_rust_stat_totals.py
|
| 1304 |
report scripts/analyze_rust_stat_totals.py docs/research/rust-stat-totals.json
|
| 1305 |
edge docs/research/rust-stat-totals.json scripts/test_rust_stat_totals.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1303 |
group gameplay scripts/analyze_rust_stat_totals.py
|
| 1304 |
report scripts/analyze_rust_stat_totals.py docs/research/rust-stat-totals.json
|
| 1305 |
edge docs/research/rust-stat-totals.json scripts/test_rust_stat_totals.py
|
| 1306 |
+
edge Cargo.toml scripts/analyze_rust_recent_awards.py
|
| 1307 |
+
edge Cargo.lock scripts/analyze_rust_recent_awards.py
|
| 1308 |
+
edge crates/urt-gameplay/Cargo.toml scripts/analyze_rust_recent_awards.py
|
| 1309 |
+
edge crates/urt-gameplay/src/lib.rs scripts/analyze_rust_recent_awards.py
|
| 1310 |
+
edge crates/urt-gameplay/src/recent_awards.rs scripts/analyze_rust_recent_awards.py
|
| 1311 |
+
edge crates/urt-gameplay/src/bin/urt-lifecycle.rs scripts/analyze_rust_recent_awards.py
|
| 1312 |
+
edge crates/urt-gameplay/src/recent_awards.rs scripts/analyze_rust_health_impulse.py
|
| 1313 |
+
group gameplay scripts/analyze_rust_recent_awards.py
|
| 1314 |
+
report scripts/analyze_rust_recent_awards.py docs/research/rust-recent-awards.json
|
| 1315 |
+
edge docs/research/rust-recent-awards.json scripts/test_rust_recent_awards.py
|