qvm: recover add-filter client and kick routing
Browse files- 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/QVM_FILTER_ADD_COMMAND.md +5 -0
- docs/research/README.md +2 -0
- docs/research/qvm-filter-add-command.json +0 -0
- scripts/analyze_qvm_filter_add_command.py +12 -0
- scripts/qvm_filter_commands_oracle.py +27 -0
- scripts/qvm_filter_commands_support.py +41 -0
- scripts/test_qvm_filter_add_command.py +11 -0
- xtask/checks.tsv +4 -0
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
|