nmarshall commited on
Commit
ec64722
·
1 Parent(s): 696a479

qvm: recover add-filter client and kick routing

Browse files
docs/FINDINGS.md CHANGED
@@ -1839,3 +1839,5 @@ RE-951: Rust matches80 original duration/usage command fixtures, preserving wrap
1839
  RE-952: Twenty-four actual export/reload compositions transfer captured file bytes through explicit native replies. Empty-table export leaves the prior file intact, whereas all-hole export truncates. Reload loses masks, converts the original INT_MIN formatter punctuation to metadata0, routes duplicate updates to the first match and grows retained tables. Source formatter/parser/load bodies execute; actual filesystem acceptance and unlimited reload/capacity remain open. [Evidence](research/QVM_FILTER_ROUNDTRIP.md).
1840
 
1841
  RE-953: Rust matches24 original export/reload compositions, retaining stale prior files when export is absent, all-hole truncation, wildcard-mask loss, INT_MIN metadata reload as0, duplicate routing and retained-table growth. The staged loader rejects unsupported domains without mutation. Unit tests cover these losses, duplicate growth and atomic unsupported prior-file rejection. Captured write bytes are supplied as read replies; actual filesystem acceptance remains open. [Evidence](research/RUST_FILTER_ROUNDTRIP.md).
 
 
 
1839
  RE-952: Twenty-four actual export/reload compositions transfer captured file bytes through explicit native replies. Empty-table export leaves the prior file intact, whereas all-hole export truncates. Reload loses masks, converts the original INT_MIN formatter punctuation to metadata0, routes duplicate updates to the first match and grows retained tables. Source formatter/parser/load bodies execute; actual filesystem acceptance and unlimited reload/capacity remain open. [Evidence](research/QVM_FILTER_ROUNDTRIP.md).
1840
 
1841
  RE-953: Rust matches24 original export/reload compositions, retaining stale prior files when export is absent, all-hole truncation, wildcard-mask loss, INT_MIN metadata reload as0, duplicate routing and retained-table growth. The staged loader rejects unsupported domains without mutation. Unit tests cover these losses, duplicate growth and atomic unsupported prior-file rejection. Captured write bytes are supplied as read replies; actual filesystem acceptance remains open. [Evidence](research/RUST_FILTER_ROUNDTRIP.md).
1842
+
1843
+ RE-954: Ninety-six actual253100 wrappers recover length-under3 client-number routing, active-slot gating, supplied1024-byte userinfo and actual70503 ip lookup, insertion and exact usage/kick formatting. Non-numeric short input can select slot0. A clientkick command is queued even after missing-ip insertion failure. Selector and formatter wraps, invalid slots and direct masks are verified; exports and native effects remain captured. [Evidence](research/QVM_FILTER_ADD_COMMAND.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -1889,3 +1889,5 @@ RE-934–943 completed bounded filter export/removal/metadata and insertion/remo
1889
  - [x] RE-953 Rust export reload composition and persistence-loss regressions ([evidence](research/RUST_FILTER_ROUNDTRIP.md)).
1890
 
1891
  RE-944–953 completed bounded time/expiry/loading/duration and export/reload contracts. RE-954 tracks remaining commands/callers, native ownership and runtime acceptance. [Batch and next work](research/QVM_FILTER_LOADING_BATCH.md).
 
 
 
1889
  - [x] RE-953 Rust export reload composition and persistence-loss regressions ([evidence](research/RUST_FILTER_ROUNDTRIP.md)).
1890
 
1891
  RE-944–953 completed bounded time/expiry/loading/duration and export/reload contracts. RE-954 tracks remaining commands/callers, native ownership and runtime acceptance. [Batch and next work](research/QVM_FILTER_LOADING_BATCH.md).
1892
+
1893
+ - [x] RE-954 Original add-filter client lookup and queued kick command ([evidence](research/QVM_FILTER_ADD_COMMAND.md)).
docs/RESEARCH_LEDGER.md CHANGED
@@ -2481,3 +2481,7 @@ Twenty-four actual export/reload compositions transfer captured file bytes throu
2481
  Rust matches24 original export/reload compositions, retaining stale prior files when export is absent, all-hole truncation, wildcard-mask loss, INT_MIN metadata reload as0, duplicate routing and retained-table growth. The staged loader rejects unsupported domains without mutation. Unit tests cover these losses, duplicate growth and atomic unsupported prior-file rejection. Captured write bytes are supplied as read replies; actual filesystem acceptance remains open. Focused `cargo xtask test-group rust-filter-roundtrip` 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.
2482
 
2483
  Batch RE-944–953 boundary: the single `cargo xtask test-full --since ed9db0e6` run after commit ten passed with the flake-declared Nix Python: 1,838 Python tests, 249 Rust tests (assets10, gameplay209, xtask30), 96 deterministic report producers, storage policy, 524 documentation files and whitespace guards. No generated report drift. Focused dependency-selection regression covers all five new source/Rust pairs and shared loading/lifecycle/native-policy/formatter inputs, including gameplay test-count metadata. Validation notes were amended into task ten; original assets unchanged. See [batch findings and next work](research/QVM_FILTER_LOADING_BATCH.md).
 
 
 
 
 
2481
  Rust matches24 original export/reload compositions, retaining stale prior files when export is absent, all-hole truncation, wildcard-mask loss, INT_MIN metadata reload as0, duplicate routing and retained-table growth. The staged loader rejects unsupported domains without mutation. Unit tests cover these losses, duplicate growth and atomic unsupported prior-file rejection. Captured write bytes are supplied as read replies; actual filesystem acceptance remains open. Focused `cargo xtask test-group rust-filter-roundtrip` 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.
2482
 
2483
  Batch RE-944–953 boundary: the single `cargo xtask test-full --since ed9db0e6` run after commit ten passed with the flake-declared Nix Python: 1,838 Python tests, 249 Rust tests (assets10, gameplay209, xtask30), 96 deterministic report producers, storage policy, 524 documentation files and whitespace guards. No generated report drift. Focused dependency-selection regression covers all five new source/Rust pairs and shared loading/lifecycle/native-policy/formatter inputs, including gameplay test-count metadata. Validation notes were amended into task ten; original assets unchanged. See [batch findings and next work](research/QVM_FILTER_LOADING_BATCH.md).
2484
+
2485
+ ## 2026-10-28 — RE-954 Original add-filter client lookup and queued kick command
2486
+
2487
+ Ninety-six actual253100 wrappers recover length-under3 client-number routing, active-slot gating, supplied1024-byte userinfo and actual70503 ip lookup, insertion and exact usage/kick formatting. Non-numeric short input can select slot0. A clientkick command is queued even after missing-ip insertion failure. Selector and formatter wraps, invalid slots and direct masks are verified; exports and native effects remain captured. Focused `cargo xtask test-group qvm-filter-add-command` 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
@@ -1926,3 +1926,5 @@ RE-944–953 recover bounded time, expiry, loading, duration and persistence rou
1926
  - [x] RE-953 Rust export reload composition and persistence-loss regressions ([evidence](research/RUST_FILTER_ROUNDTRIP.md)).
1927
 
1928
  - [ ] RE-954 Recover remaining filter commands/callers and native time/file/network ownership, bot setup/userinfo and full Rust/Bevy/Solari acceptance ([next work](research/QVM_FILTER_LOADING_BATCH.md)).
 
 
 
1926
  - [x] RE-953 Rust export reload composition and persistence-loss regressions ([evidence](research/RUST_FILTER_ROUNDTRIP.md)).
1927
 
1928
  - [ ] RE-954 Recover remaining filter commands/callers and native time/file/network ownership, bot setup/userinfo and full Rust/Bevy/Solari acceptance ([next work](research/QVM_FILTER_LOADING_BATCH.md)).
1929
+
1930
+ - [x] RE-954 Original add-filter client lookup and queued kick command ([evidence](research/QVM_FILTER_ADD_COMMAND.md)).
docs/research/QVM_FILTER_ADD_COMMAND.md ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # Original add-filter client lookup and queued kick command
2
+
3
+ RE-954. Focused validation: `cargo xtask test-group qvm-filter-add-command`. [Machine report](qvm-filter-add-command.json).
4
+
5
+ Ninety-six actual253100 wrappers recover length-under3 client-number routing, active-slot gating, supplied1024-byte userinfo and actual70503 ip lookup, insertion and exact usage/kick formatting. Non-numeric short input can select slot0. A clientkick command is queued even after missing-ip insertion failure. Selector and formatter wraps, invalid slots and direct masks are verified; exports and native effects remain captured.
docs/research/README.md CHANGED
@@ -1461,3 +1461,5 @@ The extension collector adds five focused tests for native tail calls, command-r
1461
  - [RE-953: Rust export reload composition and persistence-loss regressions](RUST_FILTER_ROUNDTRIP.md).
1462
 
1463
  - [RE-944–953 filter loading batch and RE-954 next work](QVM_FILTER_LOADING_BATCH.md).
 
 
 
1461
  - [RE-953: Rust export reload composition and persistence-loss regressions](RUST_FILTER_ROUNDTRIP.md).
1462
 
1463
  - [RE-944–953 filter loading batch and RE-954 next work](QVM_FILTER_LOADING_BATCH.md).
1464
+
1465
+ - [RE-954: Original add-filter client lookup and queued kick command](QVM_FILTER_ADD_COMMAND.md).
docs/research/qvm-filter-add-command.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_qvm_filter_add_command.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Actual253100 with recovered length/integer/userinfo/insert/format children."""
2
+ from pathlib import Path
3
+ from analyze_qvm import write_json
4
+ from qvm_research_support import source
5
+ from qvm_filter_commands_support import environment,add_fixtures,command,SPARE,COUNT,snapshot
6
+
7
+ def main():
8
+ q,raw,h,ins=source();probes=[]
9
+ for a in add_fixtures():
10
+ m,b=environment(raw,h,[SPARE]*8);m[COUNT]=0;m,p,b=command(ins,m,b,a,'add');p.update(input=a,rows=snapshot(m,8));probes.append(p)
11
+ write_json(Path('docs/research/qvm-filter-add-command.json'),dict(source=q['source'],sha256=q['sha256'],root=253100,probes=probes,limits='96 original wrappers execute actual36038/37159/70503/252829/70458/37914. Text length<3 selects numeric client lookup; active slot userinfo is supplied and ip lookup toggles selector. Kick is queued even after insertion parse failure. Native console/network/userinfo/enqueue effects and export requests remain captured.'))
12
+ if __name__=='__main__':main()
scripts/qvm_filter_commands_oracle.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Independent wrapper decisions composed with reviewed table/parser semantics."""
2
+ from qvm_filter_loading_oracle import integer
3
+ from qvm_filter_insert_oracle import parse
4
+ from qvm_filter_loading_support import SPARE
5
+ from qvm_filter_persistence_support import mutation_oracle
6
+
7
+ def command(a,kind):
8
+ text=bytes.fromhex(a['text']).split(b'\0')[0];records=[list(SPARE) for _ in range(8)] if kind=='add' else [list(r) for r in a['rows']];count=0 if kind=='add' else len(records);events=[];children=[];ring=0xffffffff;selector=0
9
+ if not text:
10
+ message=(b'Usage: addip <ip-mask>\n' if kind=='add' else b'Usage: removeip <ip-mask>\n') if a['issuer']==-1 else (b'chat "^5[rcon] ^7Usage: /addip <ip-mask>"' if kind=='add' else b'chat "^5[rcon] ^7Usage: /removeip <ip-mask>"')
11
+ events=[dict(op='console',text=message.hex())] if a['issuer']==-1 else [dict(op='send',recipient=a['issuer'],text=message.hex())]
12
+ if a['issuer']!=-1:ring=0
13
+ elif kind=='remove':
14
+ events.append(dict(op='remove',text=text.hex()));p=mutation_oracle(dict(rows=records,text=text.hex(),metadata=0,save=0,handle=7),'remove');records=p['rows'];children=[{k:p[k] for k in ['result','diagnostics','exports']}]
15
+ else:
16
+ client=None;ip=text
17
+ if len(text)<3:
18
+ slot=integer(text);slot=slot if slot<2**31 else slot-2**32
19
+ if 0<=slot<64 and a['active']:
20
+ client=slot;selector=1;events.append(dict(op='userinfo',slot=slot));data=bytes.fromhex(a['userinfo']).split(b'\0')[0][:1023];parts=data.lstrip(b'\\').split(b'\\');ip=next((parts[j+1] for j in range(0,len(parts)-1,2) if parts[j].lower()==b'ip'),b'')
21
+ else:return dict(events=events,children=children,ring=ring,selector=selector,count=count,rows=records)
22
+ events.append(dict(op='insert',text=ip.hex(),save=1));pair,remaining=parse(ip);diagnostics=[]
23
+ if pair is None:records[0][1]=0xffffffff;diagnostics=[dict(op='bad-address',text=remaining.hex())]
24
+ else:records[0]=[*pair,0xffffffff]
25
+ count=1;children=[dict(result=1,diagnostics=diagnostics,exports=[252500])]
26
+ if client is not None:events.append(dict(op='enqueue',mode=1,text=f'clientkick {client}\n'.encode().hex()));ring=0
27
+ return dict(events=events,children=children,ring=ring,selector=selector,count=count,rows=records)
scripts/qvm_filter_commands_support.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Original add/remove filter wrappers and bounded native-effect compositions."""
2
+ from qvm_camera_world_support import B,run,string,POOL
3
+ from qvm_filter_loading_support import environment,SPARE
4
+ from qvm_exit_rules_support import CPOOL
5
+ from qvm_string_memory_support import cstring,strlen
6
+ from qvm_filter_update_support import insert,COUNT,snapshot
7
+ from qvm_filter_persistence_support import mutate
8
+ from qvm_persistence_support import info_lookup
9
+ from qvm_formatter_support import formatter
10
+ from qvm_scoreboard_wire_support import final_format
11
+ ROOT=B+0x210000
12
+
13
+ def add_fixtures():
14
+ from itertools import product
15
+ return [dict(text=t.hex(),issuer=issuer,active=active,userinfo=u.hex()) for t,issuer,active,u in product([b'',b'0',b'x',b'1x',b'3',b'63',b'64',b'-1',b'1.2',b'bad',b'255.255.255.255',b'1.2.3.4'],[-1,2],[0,1],[b'\\ip\\1.2.3.4:27960',b'\\name\\noip'])]
16
+
17
+ def command(ins,m,b,a,kind):
18
+ text=bytes.fromhex(a['text']);string(m,b,ROOT+0x4000,text);
19
+ from qvm_byte_memory_support import write_bytes
20
+ write_bytes(m,b,{ROOT+0x4000+len(text)+j:0 for j in range(1,9)});
21
+ m[23708]=0xffffffff;m[23712]=0;events=[];children=[]
22
+ entity=0 if a['issuer']==-1 else POOL+880*a['issuer'];m[34992496]=CPOOL
23
+ if entity:m[entity+520]=CPOOL+6336*a['issuer']
24
+ for j in range(64):m[34091900+880*j]=a.get('active',0)
25
+ def console(i,m,args,bs):events.append(dict(op='console',text=cstring(m,bs,args[8]).hex()));return m,0,{'console_captured':True}
26
+ def fmt(i,m,args,bs):return final_format(i,m,args,dict(bs),formatter)
27
+ def send(i,m,args,bs):events.append(dict(op='send',recipient=args[8],text=cstring(m,bs,args[12]).hex()));return m,0,{'network_send_captured':True}
28
+ def number(i,m,args,bs):
29
+ m,v,p,b=run(i,m,37159,37277,36,args,dict(bs),base=ROOT+0x10000);return m,v,{'actual_source_child':37159}
30
+ def get(i,m,args,bs):
31
+ events.append(dict(op='userinfo',slot=args[8]));data=bytes.fromhex(a['userinfo']).split(b'\0')[0][:args[16]-1];return m,0,{'native_userinfo_supplied':True,'child_memory_bytes':{args[12]+j:v for j,v in enumerate((data+b'\0').ljust(args[16],b'\0'))}}
32
+ def lookup(i,m,args,bs):
33
+ m,v,p,b=info_lookup(i,m,dict(bs),args);return m,v,{'actual_source_child':70503,'child_memory_bytes':{v+j:x for j,x in enumerate(cstring(m,b,v)+b'\0')}}
34
+ def add(i,m,args,bs):
35
+ t=cstring(m,bs,args[8]);events.append(dict(op='insert',text=t.hex(),save=args[12]));m,p,b=insert(i,m,dict(bs),t,args[12]);children.append({k:p[k] for k in ['result','diagnostics','exports']});return m,p['result'],{'actual_source_child':252829}
36
+ def remove(i,m,args,bs):
37
+ t=cstring(m,bs,args[8]);events.append(dict(op='remove',text=t.hex()));m,p,b=mutate(i,m,dict(bs),t,'remove');children.append({k:p[k] for k in ['result','diagnostics','exports']});return m,p['result'],{'actual_source_child':253296}
38
+ def enqueue(i,m,args,bs):events.append(dict(op='enqueue',mode=args[8],text=cstring(m,bs,args[12]).hex()));return m,0,{'console_command_captured':True}
39
+ start,stop,frame=(253100,253243,1072) if kind=='add' else (253245,253294,20)
40
+ m,v,p,b=run(ins,m,start,stop,frame,{8:entity,12:ROOT+0x4000},b,{2294:console,70458:fmt,-18:send,36038:strlen,37159:number,-21:get,70503:lookup,252829:add,253296:remove,-15:enqueue},base=ROOT)
41
+ p.update(events=events,children=children,ring=m[23708]&0xffffffff,selector=m[23712]&0xffffffff,count=m[COUNT]);return m,p,b
scripts/test_qvm_filter_add_command.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json,unittest
2
+ from pathlib import Path
3
+ from qvm_filter_commands_oracle import command
4
+ class AddTests(unittest.TestCase):
5
+ def test_original_wrapper(self):
6
+ rows=json.loads(Path('docs/research/qvm-filter-add-command.json').read_text())['probes'];self.assertEqual(len(rows),96)
7
+ for p in rows:
8
+ for k,v in command(p['input'],'add').items():self.assertEqual(p[k],v)
9
+ def test_missing_ip_still_enqueues_kick(self):
10
+ p=command(dict(text=b'x'.hex(),issuer=-1,active=1,userinfo=b'\\name\\noip'.hex()),'add');self.assertEqual(p['events'][-1]['op'],'enqueue');self.assertEqual(p['selector'],1);self.assertTrue(p['children'][0]['diagnostics'])
11
+ if __name__=='__main__':unittest.main()
xtask/checks.tsv CHANGED
@@ -3304,3 +3304,7 @@ edge crates/urt-gameplay/src/qvm_format.rs scripts/analyze_rust_filter_roundtrip
3304
  edge docs/research/qvm-filter-roundtrip.json scripts/analyze_rust_filter_roundtrip.py
3305
  group rust-filter-roundtrip scripts/analyze_rust_health_impulse.py
3306
  group gameplay scripts/analyze_rust_filter_roundtrip.py
 
 
 
 
 
3304
  edge docs/research/qvm-filter-roundtrip.json scripts/analyze_rust_filter_roundtrip.py
3305
  group rust-filter-roundtrip scripts/analyze_rust_health_impulse.py
3306
  group gameplay scripts/analyze_rust_filter_roundtrip.py
3307
+ report scripts/analyze_qvm_filter_add_command.py docs/research/qvm-filter-add-command.json
3308
+ edge docs/research/qvm-filter-add-command.json scripts/test_qvm_filter_add_command.py
3309
+ group qvm-filter-add-command scripts/analyze_qvm_filter_add_command.py
3310
+ edge scripts/analyze_qvm_filter_add_command.py scripts/analyze_qvm_resumer_audit.py