nmarshall commited on
Commit
e1e058d
·
1 Parent(s): 213e61c

gameplay: resolve connect suffix child policies

Browse files
crates/urt-gameplay/src/bin/urt-native-policy.rs CHANGED
@@ -990,6 +990,50 @@ fn run() -> Result<String, String> {
990
  notices_json(&sends)
991
  ))
992
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
993
  _ => Err("unknown command".into()),
994
  }
995
  }
 
990
  notices_json(&sends)
991
  ))
992
  }
993
+ "resolved-connect-tail" => {
994
+ if w.len() != 8 {
995
+ return Err("invalid resolved tail words".into());
996
+ }
997
+ let mut client = 0xaabbccddu32.to_le_bytes().repeat(1584);
998
+ client[3096..3100].copy_from_slice(&w[1].to_le_bytes());
999
+ client[504..516].fill(0);
1000
+ client[504..507].copy_from_slice(b"old");
1001
+ let mut entity = ConnectTailEntity {
1002
+ flags: 32,
1003
+ in_use: 0,
1004
+ };
1005
+ let mut selector = 0;
1006
+ let out = resolved_connect_tail(
1007
+ &mut client,
1008
+ &mut entity,
1009
+ ConnectTailInput {
1010
+ mode: w[0] as i32,
1011
+ slot: 3,
1012
+ first_time: w[3] as i32,
1013
+ bot: w[2] as i32,
1014
+ bot_answer: w[4] as i32,
1015
+ clock: w[6] as i32,
1016
+ seconds: w[7] as i32,
1017
+ after_team: if w[5] != 0 { Some(2) } else { None },
1018
+ name: b"new^1name",
1019
+ },
1020
+ b"\\characterfile\\bots/a.c\\skill\\1.5\\team\\red",
1021
+ w[4] as i32,
1022
+ &mut selector,
1023
+ )
1024
+ .map_err(|e| format!("{e:?}"))?;
1025
+ let bot = out
1026
+ .bot
1027
+ .as_ref()
1028
+ .map(|b| bot_settings_json(b, selector))
1029
+ .unwrap_or("null".into());
1030
+ Ok(format!(
1031
+ r#"{{"parent":{},"bot":{bot},"notices":{},"ring":{},"info_ring":{selector}}}"#,
1032
+ tail_json(&out.tail, &client, &entity),
1033
+ notices_json(&out.notices),
1034
+ out.ring_advance
1035
+ ))
1036
+ }
1037
  _ => Err("unknown command".into()),
1038
  }
1039
  }
crates/urt-gameplay/src/native_policy.rs CHANGED
@@ -2840,3 +2840,136 @@ mod announcement_tests {
2840
  assert_eq!(r, 7);
2841
  }
2842
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2840
  assert_eq!(r, 7);
2841
  }
2842
  }
2843
+
2844
+ #[derive(Clone, Debug, PartialEq, Eq)]
2845
+ pub struct ResolvedConnectTail {
2846
+ pub tail: ConnectTail,
2847
+ pub bot: Option<BotSettingsPolicy>,
2848
+ pub notices: Vec<TeamNotice>,
2849
+ pub ring_advance: u32,
2850
+ }
2851
+ /// Execute recovered wrapper/announcement policies at their parent request
2852
+ /// boundaries. The historical Join event identifies182896 announcement only.
2853
+ pub fn resolved_connect_tail(
2854
+ client: &mut [u8],
2855
+ entity: &mut ConnectTailEntity,
2856
+ mut input: ConnectTailInput<'_>,
2857
+ userinfo: &[u8],
2858
+ setup_answer: i32,
2859
+ info_ring: &mut u32,
2860
+ ) -> Result<ResolvedConnectTail, Error> {
2861
+ let mut bytes = client.to_vec();
2862
+ let mut e = entity.clone();
2863
+ let mut selector = *info_ring;
2864
+ let bot = if input.bot != 0 {
2865
+ let out = bot_settings(
2866
+ input.slot,
2867
+ i32::from(input.first_time == 0),
2868
+ userinfo,
2869
+ setup_answer,
2870
+ &mut selector,
2871
+ )?;
2872
+ input.bot_answer = i32::from(out.result);
2873
+ Some(out)
2874
+ } else {
2875
+ None
2876
+ };
2877
+ let tail = finish_connect(&mut bytes, &mut e, input)?;
2878
+ let mut counter = 0;
2879
+ let mut notices = vec![];
2880
+ for event in &tail.events {
2881
+ if let ConnectTailEvent::Join { choice, .. } = event {
2882
+ notices.extend(team_announcement(
2883
+ raw_word(&bytes, 3096) as i32,
2884
+ *choice,
2885
+ &bytes[504..],
2886
+ &mut counter,
2887
+ )?);
2888
+ }
2889
+ }
2890
+ let ring_advance = tail.ring_advance.wrapping_add(counter);
2891
+ client.copy_from_slice(&bytes);
2892
+ *entity = e;
2893
+ *info_ring = selector;
2894
+ Ok(ResolvedConnectTail {
2895
+ tail,
2896
+ bot,
2897
+ notices,
2898
+ ring_advance,
2899
+ })
2900
+ }
2901
+ #[cfg(test)]
2902
+ mod resolved_tail_tests {
2903
+ use super::*;
2904
+ #[test]
2905
+ fn wrapper_failure_returns_drop_and_preserves_entity_mutations() {
2906
+ let mut client = vec![0; CLIENT_BYTES];
2907
+ let mut entity = ConnectTailEntity {
2908
+ flags: 32,
2909
+ in_use: 0,
2910
+ };
2911
+ let mut selector = 0;
2912
+ let out = resolved_connect_tail(
2913
+ &mut client,
2914
+ &mut entity,
2915
+ ConnectTailInput {
2916
+ mode: 3,
2917
+ slot: 0,
2918
+ first_time: 1,
2919
+ bot: 1,
2920
+ bot_answer: 1,
2921
+ clock: 100,
2922
+ seconds: 0,
2923
+ after_team: Some(2),
2924
+ name: b"new",
2925
+ },
2926
+ b"\\skill\\1.5",
2927
+ 0,
2928
+ &mut selector,
2929
+ )
2930
+ .unwrap();
2931
+ assert!(!out.tail.accepted);
2932
+ assert!(matches!(
2933
+ out.bot.unwrap().calls.last(),
2934
+ Some(BotSettingsCall::Drop { .. })
2935
+ ));
2936
+ assert_eq!(selector, 1);
2937
+ assert_eq!(entity.flags, 40);
2938
+ assert!(out.notices.is_empty());
2939
+ }
2940
+ #[test]
2941
+ fn unsupported_settings_do_not_commit_parent() {
2942
+ let mut client = vec![0; CLIENT_BYTES];
2943
+ let before = client.clone();
2944
+ let mut entity = ConnectTailEntity {
2945
+ flags: 32,
2946
+ in_use: 0,
2947
+ };
2948
+ let old = entity.clone();
2949
+ let mut selector = 0;
2950
+ assert_eq!(
2951
+ resolved_connect_tail(
2952
+ &mut client,
2953
+ &mut entity,
2954
+ ConnectTailInput {
2955
+ mode: 3,
2956
+ slot: 0,
2957
+ first_time: 1,
2958
+ bot: 1,
2959
+ bot_answer: 1,
2960
+ clock: 100,
2961
+ seconds: 0,
2962
+ after_team: None,
2963
+ name: b"n"
2964
+ },
2965
+ b"\\skill\\1E2",
2966
+ 1,
2967
+ &mut selector
2968
+ ),
2969
+ Err(Error::InvalidInput)
2970
+ );
2971
+ assert_eq!(client, before);
2972
+ assert_eq!(entity, old);
2973
+ assert_eq!(selector, 0);
2974
+ }
2975
+ }
docs/FINDINGS.md CHANGED
@@ -1784,3 +1784,6 @@ RE-813–822 replaces the scoreboard decimal assumption with actual37914 executi
1784
 
1785
 
1786
  **RE-928:** 144 original173979 suffix cases execute actual161744 settings/drop wrapper and182896 announcement body instead of supplied bot booleans and captured team callback. Parent control/state remains source-identical; extra userinfo selector toggles, setup records, drops, exact announcement bytes and formatter carry are verified. Native125185 setup,171668 userinfo mutation, ranking/network/logging remain supplied/captured. [Evidence](research/QVM_RESOLVED_CONNECT_TAIL.md).
 
 
 
 
1784
 
1785
 
1786
  **RE-928:** 144 original173979 suffix cases execute actual161744 settings/drop wrapper and182896 announcement body instead of supplied bot booleans and captured team callback. Parent control/state remains source-identical; extra userinfo selector toggles, setup records, drops, exact announcement bytes and formatter carry are verified. Native125185 setup,171668 userinfo mutation, ranking/network/logging remain supplied/captured. [Evidence](research/QVM_RESOLVED_CONNECT_TAIL.md).
1787
+
1788
+
1789
+ **RE-929:** Rust matches144 original suffix compositions with actual161744/182896 policies, retaining caller mutations/messages while adding precise bot records, drop requests, announcement bytes and selector/counter carry. The wrapper stages typed errors and preserves ordinary rejection mutations. Native bot setup/userinfo/ranking/network/logging remain open. [Evidence](research/RUST_RESOLVED_CONNECT_TAIL.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -1827,3 +1827,6 @@ RE-927: Rust matches162 original182896 payload/counter cases, retaining exact cc
1827
 
1828
 
1829
  RE-928: 144 original173979 suffix cases execute actual161744 settings/drop wrapper and182896 announcement body instead of supplied bot booleans and captured team callback. Parent control/state remains source-identical; extra userinfo selector toggles, setup records, drops, exact announcement bytes and formatter carry are verified. Native125185 setup,171668 userinfo mutation, ranking/network/logging remain supplied/captured. Full runtime completion remains open. [Evidence](research/QVM_RESOLVED_CONNECT_TAIL.md).
 
 
 
 
1827
 
1828
 
1829
  RE-928: 144 original173979 suffix cases execute actual161744 settings/drop wrapper and182896 announcement body instead of supplied bot booleans and captured team callback. Parent control/state remains source-identical; extra userinfo selector toggles, setup records, drops, exact announcement bytes and formatter carry are verified. Native125185 setup,171668 userinfo mutation, ranking/network/logging remain supplied/captured. Full runtime completion remains open. [Evidence](research/QVM_RESOLVED_CONNECT_TAIL.md).
1830
+
1831
+
1832
+ RE-929: Rust matches144 original suffix compositions with actual161744/182896 policies, retaining caller mutations/messages while adding precise bot records, drop requests, announcement bytes and selector/counter carry. The wrapper stages typed errors and preserves ordinary rejection mutations. Native bot setup/userinfo/ranking/network/logging remain open. Full runtime completion remains open. [Evidence](research/RUST_RESOLVED_CONNECT_TAIL.md).
docs/RESEARCH_LEDGER.md CHANGED
@@ -2370,3 +2370,8 @@ Rust matches162 original182896 payload/counter cases, retaining exact ccprint/sp
2370
  ## 2026-10-28 — RE-928 Original connect suffix with bot wrapper and announcements
2371
 
2372
  144 original173979 suffix cases execute actual161744 settings/drop wrapper and182896 announcement body instead of supplied bot booleans and captured team callback. Parent control/state remains source-identical; extra userinfo selector toggles, setup records, drops, exact announcement bytes and formatter carry are verified. Native125185 setup,171668 userinfo mutation, ranking/network/logging remain supplied/captured. Focused `cargo xtask test-group qvm-resolved-connect-tail` passes (4 Python tests); selected reports regenerate twice deterministically, with storage, documentation links and whitespace guards. Full suite deferred to task ten. Original assets unchanged; source fixtures do not establish complete native/runtime parity.
 
 
 
 
 
 
2370
  ## 2026-10-28 — RE-928 Original connect suffix with bot wrapper and announcements
2371
 
2372
  144 original173979 suffix cases execute actual161744 settings/drop wrapper and182896 announcement body instead of supplied bot booleans and captured team callback. Parent control/state remains source-identical; extra userinfo selector toggles, setup records, drops, exact announcement bytes and formatter carry are verified. Native125185 setup,171668 userinfo mutation, ranking/network/logging remain supplied/captured. Focused `cargo xtask test-group qvm-resolved-connect-tail` passes (4 Python tests); selected reports regenerate twice deterministically, with storage, documentation links and whitespace guards. Full suite deferred to task ten. Original assets unchanged; source fixtures do not establish complete native/runtime parity.
2373
+
2374
+
2375
+ ## 2026-10-28 — RE-929 Rust connect suffix with recovered bot and announcement children
2376
+
2377
+ Rust matches144 original suffix compositions with actual161744/182896 policies, retaining caller mutations/messages while adding precise bot records, drop requests, announcement bytes and selector/counter carry. The wrapper stages typed errors and preserves ordinary rejection mutations. Native bot setup/userinfo/ranking/network/logging remain open. Focused `cargo xtask test-group rust-resolved-connect-tail` passes (11 Python tests); selected reports regenerate twice deterministically, with storage, documentation links and whitespace guards. Full suite deferred to task ten. Original assets unchanged; source fixtures do not establish complete native/runtime parity.
docs/REVERSE_ENGINEERING_TODO.md CHANGED
@@ -1864,3 +1864,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
1864
 
1865
 
1866
  - [x] RE-928 Original connect suffix with bot wrapper and announcements ([evidence](research/QVM_RESOLVED_CONNECT_TAIL.md)).
 
 
 
 
1864
 
1865
 
1866
  - [x] RE-928 Original connect suffix with bot wrapper and announcements ([evidence](research/QVM_RESOLVED_CONNECT_TAIL.md)).
1867
+
1868
+
1869
+ - [x] RE-929 Rust connect suffix with recovered bot and announcement children ([evidence](research/RUST_RESOLVED_CONNECT_TAIL.md)).
docs/research/README.md CHANGED
@@ -1399,3 +1399,6 @@ The extension collector adds five focused tests for native tail calls, command-r
1399
 
1400
 
1401
  [RE-928: Original connect suffix with bot wrapper and announcements](QVM_RESOLVED_CONNECT_TAIL.md).
 
 
 
 
1399
 
1400
 
1401
  [RE-928: Original connect suffix with bot wrapper and announcements](QVM_RESOLVED_CONNECT_TAIL.md).
1402
+
1403
+
1404
+ [RE-929: Rust connect suffix with recovered bot and announcement children](RUST_RESOLVED_CONNECT_TAIL.md).
docs/research/RUST_RESOLVED_CONNECT_TAIL.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Rust connect suffix with recovered bot and announcement children
2
+
3
+ RE-929. Reproduce with `python3 scripts/analyze_rust_resolved_connect_tail.py`; focused validation: `cargo xtask test-group rust-resolved-connect-tail`. [Machine report](rust-resolved-connect-tail.json).
4
+
5
+ Rust matches144 original suffix compositions with actual161744/182896 policies, retaining caller mutations/messages while adding precise bot records, drop requests, announcement bytes and selector/counter carry. The wrapper stages typed errors and preserves ordinary rejection mutations. Native bot setup/userinfo/ranking/network/logging 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": 180,
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": 182,
2989
  "source_report": "docs/research/qvm-health-impulse.json",
2990
  "source_report_sha256": "625fd8064004ea6dbdf398d51d0af844d9c635ff04c0a0790886dddb6ab81e71"
2991
  }
docs/research/rust-resolved-connect-tail.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_rust_resolved_connect_tail.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import hashlib,json
3
+ from pathlib import Path
4
+ from rust_native_policy_support import binary,result,invoke
5
+ from analyze_qvm import write_json
6
+ def encode(s):
7
+ a=s['input'];return [a[k] for k in ['mode','team','bot','first','answer','changed','now','seconds']]
8
+ def project(s):
9
+ bot=s['children'].get('bot');parent={k:s[k] for k in ['accepted','message','events','words','entity_flags','in_use']};parent['ring']=s['ring']-len(s['children'].get('announcements',[]));return {'parent':parent,'bot':None if bot is None else {k:bot[k] for k in ['settings','lookups','calls','result']}|{'ring':s['info_ring']},'notices':s['children'].get('announcements',[]),'ring':s['ring'],'info_ring':s['info_ring']}
10
+
11
+ def main():
12
+ b=binary();p=Path('docs/research/qvm-resolved-connect-tail.json');data=p.read_bytes();rows=[]
13
+ for s in json.loads(data)['probes']:rows.append({'source':project(s),'rust':result(b,'resolved-connect-tail',encode(s))})
14
+ write_json(Path('docs/research/rust-resolved-connect-tail.json'),{'source_report':str(p),'source_report_sha256':hashlib.sha256(data).hexdigest(),'probes':rows,'limits':'Rust matches144 original suffix compositions with actual161744/182896 policies, retaining caller mutations/messages while adding precise bot records, drop requests, announcement bytes and selector/counter carry. The wrapper stages typed errors and preserves ordinary rejection mutations. Native bot setup/userinfo/ranking/network/logging remain open.'})
15
+ if __name__=='__main__':main()
scripts/test_rust_resolved_connect_tail.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-resolved-connect-tail.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-resolved-connect-tail.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
@@ -3047,3 +3047,19 @@ report scripts/analyze_qvm_resolved_connect_tail.py docs/research/qvm-resolved-c
3047
  edge docs/research/qvm-resolved-connect-tail.json scripts/test_qvm_resolved_connect_tail.py
3048
  group qvm-resolved-connect-tail scripts/analyze_qvm_resolved_connect_tail.py
3049
  edge scripts/analyze_qvm_resolved_connect_tail.py scripts/analyze_qvm_resumer_audit.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3047
  edge docs/research/qvm-resolved-connect-tail.json scripts/test_qvm_resolved_connect_tail.py
3048
  group qvm-resolved-connect-tail scripts/analyze_qvm_resolved_connect_tail.py
3049
  edge scripts/analyze_qvm_resolved_connect_tail.py scripts/analyze_qvm_resumer_audit.py
3050
+ edge Cargo.toml scripts/analyze_rust_resolved_connect_tail.py
3051
+ edge Cargo.lock scripts/analyze_rust_resolved_connect_tail.py
3052
+ edge crates/urt-gameplay/Cargo.toml scripts/analyze_rust_resolved_connect_tail.py
3053
+ edge crates/urt-gameplay/src/lib.rs scripts/analyze_rust_resolved_connect_tail.py
3054
+ edge crates/urt-gameplay/src/native_policy.rs scripts/analyze_rust_resolved_connect_tail.py
3055
+ edge crates/urt-gameplay/src/bin/urt-native-policy.rs scripts/analyze_rust_resolved_connect_tail.py
3056
+ edge docs/research/qvm-resolved-connect-tail.json scripts/analyze_rust_resolved_connect_tail.py
3057
+ group rust-resolved-connect-tail scripts/analyze_rust_health_impulse.py
3058
+ group gameplay scripts/analyze_rust_resolved_connect_tail.py
3059
+ edge crates/urt-gameplay/src/intermission.rs scripts/analyze_rust_resolved_connect_tail.py
3060
+ edge crates/urt-gameplay/src/qvm_format.rs scripts/analyze_rust_resolved_connect_tail.py
3061
+ group rust-resolved-connect-tail scripts/analyze_rust_connect_tail.py
3062
+ report scripts/analyze_rust_resolved_connect_tail.py docs/research/rust-resolved-connect-tail.json
3063
+ edge docs/research/rust-resolved-connect-tail.json scripts/test_rust_resolved_connect_tail.py
3064
+ group rust-resolved-connect-tail scripts/analyze_rust_resolved_connect_tail.py
3065
+ edge scripts/analyze_rust_resolved_connect_tail.py scripts/analyze_qvm_resumer_audit.py