qvm: entity reuse policy
Browse files- 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/QVM_ENTITY_REUSE.md +7 -0
- docs/research/README.md +3 -0
- docs/research/qvm-entity-reuse.json +0 -0
- scripts/analyze_qvm_entity_reuse.py +33 -0
- scripts/test_qvm_entity_reuse.py +16 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -493,3 +493,6 @@ Research progress: RE-602 [report](research/QVM_SERVER_FIRE_CHAIN.md); remaining
|
|
| 493 |
|
| 494 |
|
| 495 |
Research progress: RE-604 [report](research/QVM_ENTITY_INIT.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 493 |
|
| 494 |
|
| 495 |
Research progress: RE-604 [report](research/QVM_ENTITY_INIT.md); remaining native/content/runtime/platform scope stays open.
|
| 496 |
+
|
| 497 |
+
|
| 498 |
+
Research progress: RE-605 [report](research/QVM_ENTITY_REUSE.md); remaining native/content/runtime/platform scope stays open.
|
docs/FINDINGS.md
CHANGED
|
@@ -851,3 +851,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
|
|
| 851 |
|
| 852 |
|
| 853 |
**RE-604 — Entity initializer and preserved record fields:** 277125 writes only identity, in-use, noclass pointer/tag and owner sentinel; all other 215 words survive. [Evidence](research/QVM_ENTITY_INIT.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 851 |
|
| 852 |
|
| 853 |
**RE-604 — Entity initializer and preserved record fields:** 277125 writes only identity, in-use, noclass pointer/tag and owner sentinel; all other 215 words survive. [Evidence](research/QVM_ENTITY_INIT.md).
|
| 854 |
+
|
| 855 |
+
|
| 856 |
+
**RE-605 — Entity allocator reuse and recent-free guard:** The allocator scans from slot64, skips in-use records and delays recent frees only when freeTime>start+2000 and now−freeTime<1000. [Evidence](research/QVM_ENTITY_REUSE.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -813,3 +813,6 @@ Research progress: RE-602 [report](research/QVM_SERVER_FIRE_CHAIN.md); remaining
|
|
| 813 |
|
| 814 |
|
| 815 |
Research progress: RE-604 [report](research/QVM_ENTITY_INIT.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 813 |
|
| 814 |
|
| 815 |
Research progress: RE-604 [report](research/QVM_ENTITY_INIT.md); remaining native/content/runtime/platform scope stays open.
|
| 816 |
+
|
| 817 |
+
|
| 818 |
+
Research progress: RE-605 [report](research/QVM_ENTITY_REUSE.md); remaining native/content/runtime/platform scope stays open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -707,3 +707,8 @@ RE-602 additional regression:19 related reports from RE-582–591 and RE-593–6
|
|
| 707 |
## 2026-10-20 — RE-604 Entity initializer and preserved record fields (separate task commit)
|
| 708 |
|
| 709 |
277125 writes only identity, in-use, noclass pointer/tag and owner sentinel; all other 215 words survive. Independent full-record oracles cover 18 slot/canary combinations. Full suite: 922 tests pass. Report regenerates byte-identically (194019 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 707 |
## 2026-10-20 — RE-604 Entity initializer and preserved record fields (separate task commit)
|
| 708 |
|
| 709 |
277125 writes only identity, in-use, noclass pointer/tag and owner sentinel; all other 215 words survive. Independent full-record oracles cover 18 slot/canary combinations. Full suite: 922 tests pass. Report regenerates byte-identically (194019 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
| 710 |
+
|
| 711 |
+
|
| 712 |
+
## 2026-10-20 — RE-605 Entity allocator reuse and recent-free guard (separate task commit)
|
| 713 |
+
|
| 714 |
+
The allocator scans from slot64, skips in-use records and delays recent frees only when freeTime>start+2000 and now−freeTime<1000. Nineteen fixtures independently check first-fit order, strict timing boundaries, retained canaries and actual initializer calls. Full suite: 925 tests pass. Report regenerates byte-identically (574361 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -856,3 +856,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 856 |
|
| 857 |
|
| 858 |
- [x] RE-604 Entity initializer and preserved record fields ([report](research/QVM_ENTITY_INIT.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 856 |
|
| 857 |
|
| 858 |
- [x] RE-604 Entity initializer and preserved record fields ([report](research/QVM_ENTITY_INIT.md)).
|
| 859 |
+
|
| 860 |
+
|
| 861 |
+
- [x] RE-605 Entity allocator reuse and recent-free guard ([report](research/QVM_ENTITY_REUSE.md)).
|
docs/research/QVM_ENTITY_REUSE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Entity allocator reuse and recent-free guard
|
| 2 |
+
|
| 3 |
+
RE-605. Reproduce with `python3 scripts/analyze_qvm_entity_reuse.py`; check with `python3 scripts/test_qvm_entity_reuse.py`. The [machine report](qvm-entity-reuse.json) retains source identity and bounded fixtures.
|
| 4 |
+
|
| 5 |
+
The actual first pass of277165 scans fixed pool34091368 in880-byte strides from slot64 to count34992508. A nonzero record532 always skips. On pass0 a free record is delayed only when record564>global34992544+2000 AND global34992532−record564<1000. Equality at either threshold permits reuse. Actual277125 initializes the selected record and the numeric pointer returns; count remains unchanged. The report stops at277262 if the scan exhausts its supplied small pool, leaving extension/retry policy for RE-606. Record contents are retained except the five initializer words; tests retain client-pointer canaries. The finite time fixtures avoid signed-overflow ambiguity; engine lifetime and clearing remain unresolved.
|
| 6 |
+
|
| 7 |
+
No original executable/full QVM/native collision/physics/rendering executes. Native responses and legal input domains are supplied or unverified where stated; full runtime/macOS/Linux Rust/Bevy/Solari gameplay remains open.
|
docs/research/README.md
CHANGED
|
@@ -414,3 +414,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 414 |
|
| 415 |
|
| 416 |
[RE-604: Entity initializer and preserved record fields](QVM_ENTITY_INIT.md). Reproduce with `python3 scripts/analyze_qvm_entity_init.py`; check with `python3 scripts/test_qvm_entity_init.py`.
|
|
|
|
|
|
|
|
|
|
|
|
| 414 |
|
| 415 |
|
| 416 |
[RE-604: Entity initializer and preserved record fields](QVM_ENTITY_INIT.md). Reproduce with `python3 scripts/analyze_qvm_entity_init.py`; check with `python3 scripts/test_qvm_entity_init.py`.
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
[RE-605: Entity allocator reuse and recent-free guard](QVM_ENTITY_REUSE.md). Reproduce with `python3 scripts/analyze_qvm_entity_reuse.py`; check with `python3 scripts/test_qvm_entity_reuse.py`.
|
docs/research/qvm-entity-reuse.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_entity_reuse.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Actual first-pass allocator scan, stopping before extension/retry policy."""
|
| 3 |
+
import itertools
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from qvm_research_support import source,execute
|
| 6 |
+
from analyze_qvm_entity_init import initialize,POOL,STRIDE
|
| 7 |
+
from analyze_qvm_temp_event import record
|
| 8 |
+
from analyze_qvm import write_json
|
| 9 |
+
LOCAL=0x79100000
|
| 10 |
+
|
| 11 |
+
def fixture(count=66,now=5000,start=0,slots=()):
|
| 12 |
+
m={34992508:count,34992532:now,34992544:start,34992500:POOL,34992496:0x10000}
|
| 13 |
+
for index in range(64,max(count,65)):
|
| 14 |
+
p=POOL+index*STRIDE
|
| 15 |
+
for o in range(0,STRIDE,4):m[p+o]=0x12345678
|
| 16 |
+
m[p+532]=1;m[p+564]=0
|
| 17 |
+
for index,used,freed in slots:m[POOL+index*STRIDE+532]=used;m[POOL+index*STRIDE+564]=freed&0xffffffff
|
| 18 |
+
return m
|
| 19 |
+
|
| 20 |
+
def reuse(ins,m):
|
| 21 |
+
m=dict(m);initial={'count':m[34992508],'time':m[34992532],'start':m[34992544],'slots':[{'index':i,'used':m[POOL+i*STRIDE+532],'freed':m[POOL+i*STRIDE+564]} for i in range(64,m[34992508])]};children=[]
|
| 22 |
+
def init(i,m,a,c):m,r=initialize(i,m,a[8]);children.append(r);return m,c,0,r
|
| 23 |
+
m,_,r=execute(ins,277166,277262,m,(0,0,0),LOCAL,{277125:init})
|
| 24 |
+
return m,{'initial':initial,'execution':r,'selected':r['return'],'scan_index':m[LOCAL+32],'retry':m[LOCAL+36],'count':m[34992508],'record':record(m,r['return']) if r['return'] is not None else None,'initializers':children,'boundary':'returned' if r['return'] is not None else 'extension-or-retry-pending'}
|
| 25 |
+
|
| 26 |
+
def main():
|
| 27 |
+
q,raw,h,ins=source();rows=[]
|
| 28 |
+
for freed,now,start in itertools.product([0,2000,2001,4000,4001,4999,5000],[5000],[0,2500]):
|
| 29 |
+
rows.append(reuse(ins,fixture(slots=[(64,0,freed),(65,0,0)],now=now,start=start))[1])
|
| 30 |
+
for slots in [[],[(64,1,0),(65,0,0)],[(64,0,0),(65,0,0)],[(64,0,4999),(65,1,0)]]:rows.append(reuse(ins,fixture(slots=slots))[1])
|
| 31 |
+
rows.append(reuse(ins,fixture(count=64))[1])
|
| 32 |
+
write_json(Path('docs/research/qvm-entity-reuse.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'limits':'Actual277165 first pass with actual277125 child. No native effects. Stops277262 before count extension; full capacity retry is separate.'})
|
| 33 |
+
if __name__=='__main__':main()
|
scripts/test_qvm_entity_reuse.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
class EntityReuseTests(unittest.TestCase):
|
| 4 |
+
@classmethod
|
| 5 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-entity-reuse.json').read_text())
|
| 6 |
+
def test_independent_scan_policy(self):
|
| 7 |
+
for p in self.r['probes']:
|
| 8 |
+
a=p['initial'];eligible=[s['index'] for s in a['slots'] if s['used']==0 and (s['freed']<=a['start']+2000 or a['time']-s['freed']>=1000)];index=eligible[0] if eligible else a['count'];self.assertEqual(p['selected'],34091368+880*index if eligible else None);self.assertEqual(p['scan_index'],index);self.assertEqual(p['count'],a['count']);self.assertEqual(p['retry'],0)
|
| 9 |
+
def test_recent_free_strict_boundaries(self):
|
| 10 |
+
samples={ (p['initial']['slots'][0]['freed'],p['initial']['start']):p for p in self.r['probes'][:14] }
|
| 11 |
+
self.assertEqual(samples[(4000,0)]['scan_index'],64);self.assertEqual(samples[(4001,0)]['scan_index'],65);self.assertEqual(samples[(4001,2500)]['scan_index'],64)
|
| 12 |
+
def test_no_clear_and_actual_child(self):
|
| 13 |
+
for p in self.r['probes']:
|
| 14 |
+
self.assertEqual([c['target'] for c in p['execution']['calls']],[277125] if p['selected'] else [])
|
| 15 |
+
if p['record']:self.assertEqual(p['record']['520'],0x12345678);self.assertEqual(p['record']['532'],1)
|
| 16 |
+
if __name__=='__main__':unittest.main()
|