qvm: recover entity field string search
Browse files- 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/QVM_ENTITY_FIELD.md +7 -0
- docs/research/README.md +3 -0
- docs/research/qvm-entity-field.json +0 -0
- scripts/analyze_qvm_entity_field.py +24 -0
- scripts/qvm_camera_world_support.py +7 -0
- scripts/test_qvm_entity_field.py +21 -0
- xtask/checks.tsv +4 -0
docs/FINDINGS.md
CHANGED
|
@@ -1565,3 +1565,6 @@ RE-813–822 replaces the scoreboard decimal assumption with actual37914 executi
|
|
| 1565 |
|
| 1566 |
|
| 1567 |
**RE-855:** Rust matches 80 original class-hash search cases, including inactive/null class filtering, collisions, nonzero signed active values and cursors beyond the scan count. Bounded safe entity slices reject invalid cursors/counts; class text is intentionally not compared because the source does not compare it. [Evidence](research/RUST_ENTITY_HASH.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1565 |
|
| 1566 |
|
| 1567 |
**RE-855:** Rust matches 80 original class-hash search cases, including inactive/null class filtering, collisions, nonzero signed active values and cursors beyond the scan count. Bounded safe entity slices reject invalid cursors/counts; class text is intentionally not compared because the source does not compare it. [Evidence](research/RUST_ENTITY_HASH.md).
|
| 1568 |
+
|
| 1569 |
+
|
| 1570 |
+
**RE-856:** 150 original 276505 searches and 256 actual 69386 comparisons recover cursor/active/null-field filtering, ASCII folding, signed high-byte ordering, embedded NUL, nullable pointer order and zero-count behavior. Source calls the comparator with99999. Safe finite strings only; raw invalid pointers and runtime integration remain open. [Evidence](research/QVM_ENTITY_FIELD.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1587,3 +1587,6 @@ RE-854: 80 original 276433 cases recover nonzero active/class-pointer filtering,
|
|
| 1587 |
|
| 1588 |
|
| 1589 |
RE-855: Rust matches 80 original class-hash search cases, including inactive/null class filtering, collisions, nonzero signed active values and cursors beyond the scan count. Bounded safe entity slices reject invalid cursors/counts; class text is intentionally not compared because the source does not compare it. Full runtime completion remains open. [Evidence](research/RUST_ENTITY_HASH.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1587 |
|
| 1588 |
|
| 1589 |
RE-855: Rust matches 80 original class-hash search cases, including inactive/null class filtering, collisions, nonzero signed active values and cursors beyond the scan count. Bounded safe entity slices reject invalid cursors/counts; class text is intentionally not compared because the source does not compare it. Full runtime completion remains open. [Evidence](research/RUST_ENTITY_HASH.md).
|
| 1590 |
+
|
| 1591 |
+
|
| 1592 |
+
RE-856: 150 original 276505 searches and 256 actual 69386 comparisons recover cursor/active/null-field filtering, ASCII folding, signed high-byte ordering, embedded NUL, nullable pointer order and zero-count behavior. Source calls the comparator with99999. Safe finite strings only; raw invalid pointers and runtime integration remain open. Full runtime completion remains open. [Evidence](research/QVM_ENTITY_FIELD.md).
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -1957,3 +1957,8 @@ Batch RE-844–853 boundary: the single `cargo xtask test-full --since 15d7fcac`
|
|
| 1957 |
## 2026-10-27 — RE-855 Rust entity class-hash search
|
| 1958 |
|
| 1959 |
Rust matches 80 original class-hash search cases, including inactive/null class filtering, collisions, nonzero signed active values and cursors beyond the scan count. Bounded safe entity slices reject invalid cursors/counts; class text is intentionally not compared because the source does not compare it. Focused `cargo xtask test-group rust-entity-hash` passes (9 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1957 |
## 2026-10-27 — RE-855 Rust entity class-hash search
|
| 1958 |
|
| 1959 |
Rust matches 80 original class-hash search cases, including inactive/null class filtering, collisions, nonzero signed active values and cursors beyond the scan count. Bounded safe entity slices reject invalid cursors/counts; class text is intentionally not compared because the source does not compare it. Focused `cargo xtask test-group rust-entity-hash` passes (9 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.
|
| 1960 |
+
|
| 1961 |
+
|
| 1962 |
+
## 2026-10-27 — RE-856 Original field-string entity search with actual comparator
|
| 1963 |
+
|
| 1964 |
+
150 original 276505 searches and 256 actual 69386 comparisons recover cursor/active/null-field filtering, ASCII folding, signed high-byte ordering, embedded NUL, nullable pointer order and zero-count behavior. Source calls the comparator with99999. Safe finite strings only; raw invalid pointers and runtime integration remain open. Focused `cargo xtask test-group entity-field` passes (5 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
|
@@ -1624,3 +1624,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1624 |
|
| 1625 |
|
| 1626 |
- [x] RE-855 Rust entity class-hash search ([evidence](research/RUST_ENTITY_HASH.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 1624 |
|
| 1625 |
|
| 1626 |
- [x] RE-855 Rust entity class-hash search ([evidence](research/RUST_ENTITY_HASH.md)).
|
| 1627 |
+
|
| 1628 |
+
|
| 1629 |
+
- [x] RE-856 Original field-string entity search with actual comparator ([evidence](research/QVM_ENTITY_FIELD.md)).
|
docs/research/QVM_ENTITY_FIELD.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Original field-string entity search with actual comparator
|
| 2 |
+
|
| 3 |
+
RE-856. Reproduce with `python3 scripts/analyze_qvm_entity_field.py`; focused validation: `cargo xtask test-group entity-field`. [Machine report](qvm-entity-field.json).
|
| 4 |
+
|
| 5 |
+
150 original 276505 searches and 256 actual 69386 comparisons recover cursor/active/null-field filtering, ASCII folding, signed high-byte ordering, embedded NUL, nullable pointer order and zero-count behavior. Source calls the comparator with99999. Safe finite strings only; raw invalid pointers and runtime integration remain open.
|
| 6 |
+
|
| 7 |
+
Original executable/native runtime and complete Linux/macOS Rust/Bevy/Solari acceptance remain unverified.
|
docs/research/README.md
CHANGED
|
@@ -1161,3 +1161,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 1161 |
|
| 1162 |
|
| 1163 |
[RE-855: Rust entity class-hash search](RUST_ENTITY_HASH.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1161 |
|
| 1162 |
|
| 1163 |
[RE-855: Rust entity class-hash search](RUST_ENTITY_HASH.md).
|
| 1164 |
+
|
| 1165 |
+
|
| 1166 |
+
[RE-856: Original field-string entity search with actual comparator](QVM_ENTITY_FIELD.md).
|
docs/research/qvm-entity-field.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_entity_field.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
import itertools
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from qvm_research_support import source
|
| 5 |
+
from qvm_camera_world_support import casecmp,find_field,string,POOL,S
|
| 6 |
+
from analyze_qvm import write_json
|
| 7 |
+
ENTITIES=[{'active':0,'text':b'node'},{'active':1,'text':None},{'active':1,'text':b'Node'},{'active':2,'text':b'noDE'},{'active':-1,'text':b'\xff'},{'active':1,'text':b'other'},{'active':1,'text':b'node\0suffix'},{'active':1,'text':b''}]
|
| 8 |
+
TEXTS=[None,b'',b'a',b'A',b'ab',b'aB\0x',b'\xff',b'\x80A']
|
| 9 |
+
def main():
|
| 10 |
+
q,raw,h,ins=source();rows=[];comparisons=[]
|
| 11 |
+
for count,after,needle,field in itertools.product([0,4,8],[-1,0,2,3,7],[b'NODE',b'other',b'\xff',b'',None],[608,700]):
|
| 12 |
+
m={34992508:count};b={}
|
| 13 |
+
for j,e in enumerate(ENTITIES):
|
| 14 |
+
m[POOL+880*j+532]=e['active'];m[POOL+880*j+field]=0 if e['text'] is None else S+j*256
|
| 15 |
+
if e['text'] is not None:string(m,b,S+j*256,e['text'])
|
| 16 |
+
if needle is not None:string(m,b,S+0x2000,needle)
|
| 17 |
+
m,value,p,b=find_field(ins,m,{8:0 if after<0 else POOL+880*after,12:field,16:0 if needle is None else S+0x2000},b);rows.append({'input':dict(count=count,after=after,needle=None if needle is None else needle.hex(),field=field),'result':-1 if value==0 else (value-POOL)//880,**p})
|
| 18 |
+
for left,right,count in itertools.product(TEXTS,TEXTS,[0,1,2,99999]):
|
| 19 |
+
m={};b={}
|
| 20 |
+
if left is not None:string(m,b,S,left)
|
| 21 |
+
if right is not None:string(m,b,S+256,right)
|
| 22 |
+
m,value,p,b=casecmp(ins,m,{8:0 if left is None else S,12:0 if right is None else S+256,16:count},b);comparisons.append({'left':None if left is None else left.hex(),'right':None if right is None else right.hex(),'count':count,'result':value,**p})
|
| 23 |
+
write_json(Path('docs/research/qvm-entity-field.json'),{'source':q['source'],'sha256':q['sha256'],'entities':[{'active':e['active'],'text':None if e['text'] is None else e['text'].hex()} for e in ENTITIES],'probes':rows,'comparisons':comparisons,'limits':'Actual276505 with actual69386 over150 field searches plus256 comparator cases. ASCII case fold and signed-byte ordering, nullable pointers, embedded NUL and zero count are explicit. Logical safe strings only; arbitrary offsets/pointers and runtime integration unverified.'})
|
| 24 |
+
if __name__=='__main__':main()
|
scripts/qvm_camera_world_support.py
CHANGED
|
@@ -14,3 +14,10 @@ def run(ins,m,start,stop,frame,args=None,b=None,handlers=None,base=B):
|
|
| 14 |
def string(m,b,address,data):write_bytes(m,b,{address+j:v for j,v in enumerate(bytes(data)+b'\0')})
|
| 15 |
|
| 16 |
def find_class(ins,m,args,b=None,base=B):return run(ins,m,276433,276503,12,args,b,base=base)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
def string(m,b,address,data):write_bytes(m,b,{address+j:v for j,v in enumerate(bytes(data)+b'\0')})
|
| 15 |
|
| 16 |
def find_class(ins,m,args,b=None,base=B):return run(ins,m,276433,276503,12,args,b,base=base)
|
| 17 |
+
|
| 18 |
+
def casecmp(ins,m,args,b=None,base=B+0x2000):return run(ins,m,69386,69523,40,args,b,base=base)
|
| 19 |
+
def find_field(ins,m,args,b=None,base=B+0x1000):
|
| 20 |
+
comparisons=[]
|
| 21 |
+
def compare(i,m,a,bs):
|
| 22 |
+
m,value,p,b=casecmp(i,m,a,bs);comparisons.append({'arguments':a,'result':value,'trace_sha256':p['execution']['trace_sha256']});return m,value,{'actual_source_child':69386}
|
| 23 |
+
m,value,p,b=run(ins,m,276505,276584,28,args,b,{69386:compare},base=base);p['comparisons']=comparisons;return m,value,p,b
|
scripts/test_qvm_entity_field.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
|
| 4 |
+
def compare(left,right,count=99999):
|
| 5 |
+
if left is None:return 0 if right is None else -1
|
| 6 |
+
if right is None:return 1
|
| 7 |
+
for j in range(min(count,max(len(left),len(right))+1)):
|
| 8 |
+
a=left[j] if j<len(left) else 0;b=right[j] if j<len(right) else 0;a=a-32 if 97<=a<=122 else a;b=b-32 if 97<=b<=122 else b;a=a if a<128 else a-256;b=b if b<128 else b-256
|
| 9 |
+
if a!=b:return -1 if a<b else 1
|
| 10 |
+
if a==0:return 0
|
| 11 |
+
return 0
|
| 12 |
+
class FieldTests(unittest.TestCase):
|
| 13 |
+
def test_actual_comparator_nullable_signed_bytes_and_count(self):
|
| 14 |
+
r=json.loads(Path('docs/research/qvm-entity-field.json').read_text());self.assertEqual(len(r['comparisons']),256)
|
| 15 |
+
for p in r['comparisons']:self.assertEqual(p['result'],compare(None if p['left'] is None else bytes.fromhex(p['left']),None if p['right'] is None else bytes.fromhex(p['right']),p['count']));self.assertEqual(p['changes'],[])
|
| 16 |
+
def test_first_eligible_field_match_and_read_only_world(self):
|
| 17 |
+
r=json.loads(Path('docs/research/qvm-entity-field.json').read_text());self.assertEqual(len(r['probes']),150)
|
| 18 |
+
for p in r['probes']:
|
| 19 |
+
a=p['input'];needle=None if a['needle'] is None else bytes.fromhex(a['needle']);ids=[j for j,e in enumerate(r['entities'][:a['count']]) if j>a['after'] and e['active'] and e['text'] is not None and compare(bytes.fromhex(e['text']),needle)==0];self.assertEqual(p['result'],ids[0] if ids else -1);self.assertEqual(p['changes'],[])
|
| 20 |
+
for c in p['comparisons']:self.assertEqual(c['arguments']['16'],99999)
|
| 21 |
+
if __name__=='__main__':unittest.main()
|
xtask/checks.tsv
CHANGED
|
@@ -2353,3 +2353,7 @@ edge docs/research/rust-entity-hash.json scripts/test_rust_entity_hash.py
|
|
| 2353 |
group rust-entity-hash scripts/analyze_rust_entity_hash.py
|
| 2354 |
edge scripts/analyze_rust_entity_hash.py scripts/analyze_qvm_resumer_audit.py
|
| 2355 |
edge scripts/rust_camera_world_support.py scripts/analyze_qvm_resumer_audit.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2353 |
group rust-entity-hash scripts/analyze_rust_entity_hash.py
|
| 2354 |
edge scripts/analyze_rust_entity_hash.py scripts/analyze_qvm_resumer_audit.py
|
| 2355 |
edge scripts/rust_camera_world_support.py scripts/analyze_qvm_resumer_audit.py
|
| 2356 |
+
report scripts/analyze_qvm_entity_field.py docs/research/qvm-entity-field.json
|
| 2357 |
+
edge docs/research/qvm-entity-field.json scripts/test_qvm_entity_field.py
|
| 2358 |
+
group entity-field scripts/analyze_qvm_entity_field.py
|
| 2359 |
+
edge scripts/analyze_qvm_entity_field.py scripts/analyze_qvm_resumer_audit.py
|