qvm: audit counter and clear reentry
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_COUNTER_REENTRY.md +7 -0
- docs/research/README.md +3 -0
- docs/research/qvm-counter-reentry.json +0 -0
- docs/research/qvm-resumer-audit.json +4 -4
- scripts/analyze_qvm_counter_reentry.py +23 -0
- scripts/qvm_record_clear_support.py +1 -1
- scripts/qvm_stat_update_support.py +1 -1
- scripts/qvm_team_counter_support.py +1 -1
- scripts/test_qvm_counter_reentry.py +23 -0
- xtask/checks.tsv +10 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -1009,3 +1009,6 @@ Research progress: RE-784 [report](research/QVM_NOTIFICATION_REENTRY.md); origin
|
|
| 1009 |
|
| 1010 |
|
| 1011 |
Research progress: RE-785 [report](research/QVM_AWARD_REENTRY.md); original assets unchanged.
|
|
|
|
|
|
|
|
|
|
|
|
| 1009 |
|
| 1010 |
|
| 1011 |
Research progress: RE-785 [report](research/QVM_AWARD_REENTRY.md); original assets unchanged.
|
| 1012 |
+
|
| 1013 |
+
|
| 1014 |
+
Research progress: RE-786 [report](research/QVM_COUNTER_REENTRY.md); original assets unchanged.
|
docs/FINDINGS.md
CHANGED
|
@@ -1355,3 +1355,6 @@ RE-725–734 batch: [health, contact and Rust impulse findings](research/QVM_HEA
|
|
| 1355 |
|
| 1356 |
|
| 1357 |
**RE-785 — Audited dense recent-award scans timestamps and index64 alias:** 285227 uses corrected reentry;32 dense65-record fixtures preserve source scan order, signed timestamp/count gates and index64 award/count aliasing. [Evidence](research/QVM_AWARD_REENTRY.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1355 |
|
| 1356 |
|
| 1357 |
**RE-785 — Audited dense recent-award scans timestamps and index64 alias:** 285227 uses corrected reentry;32 dense65-record fixtures preserve source scan order, signed timestamp/count gates and index64 award/count aliasing. [Evidence](research/QVM_AWARD_REENTRY.md).
|
| 1358 |
+
|
| 1359 |
+
|
| 1360 |
+
**RE-786 — Audited method counters team pairs and dense record clearing:** 278834,279720 and285486 now use corrected reentry; independent counter/alias/address oracles and full legacy tuple comparisons cover160 expanded fixtures. [Evidence](research/QVM_COUNTER_REENTRY.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1356,3 +1356,6 @@ Research progress: RE-784 [report](research/QVM_NOTIFICATION_REENTRY.md); full n
|
|
| 1356 |
|
| 1357 |
|
| 1358 |
Research progress: RE-785 [report](research/QVM_AWARD_REENTRY.md); full native/platform/game scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
| 1356 |
|
| 1357 |
|
| 1358 |
Research progress: RE-785 [report](research/QVM_AWARD_REENTRY.md); full native/platform/game scope remains open.
|
| 1359 |
+
|
| 1360 |
+
|
| 1361 |
+
Research progress: RE-786 [report](research/QVM_COUNTER_REENTRY.md); full native/platform/game scope remains open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -1587,3 +1587,8 @@ The movement resumer also loses non-command STORE1 writes across calls in legacy
|
|
| 1587 |
## 2026-10-21 — RE-785 Audited dense recent-award scans timestamps and index64 alias
|
| 1588 |
|
| 1589 |
285227 uses corrected reentry;32 dense65-record fixtures preserve source scan order, signed timestamp/count gates and index64 award/count aliasing. Focused `cargo xtask test-group award-reentry` passes (10 Python tests); selected reports regenerate twice byte-identically, with storage, links and whitespace guards. New report: 659031 bytes. Full-suite validation is deferred to the tenth batch commit. Recent-award source resumption migrated. Existing Rust parity and source consumers remain bounded numeric contracts.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1587 |
## 2026-10-21 — RE-785 Audited dense recent-award scans timestamps and index64 alias
|
| 1588 |
|
| 1589 |
285227 uses corrected reentry;32 dense65-record fixtures preserve source scan order, signed timestamp/count gates and index64 award/count aliasing. Focused `cargo xtask test-group award-reentry` passes (10 Python tests); selected reports regenerate twice byte-identically, with storage, links and whitespace guards. New report: 659031 bytes. Full-suite validation is deferred to the tenth batch commit. Recent-award source resumption migrated. Existing Rust parity and source consumers remain bounded numeric contracts.
|
| 1590 |
+
|
| 1591 |
+
|
| 1592 |
+
## 2026-10-21 — RE-786 Audited method counters team pairs and dense record clearing
|
| 1593 |
+
|
| 1594 |
+
278834,279720 and285486 now use corrected reentry; independent counter/alias/address oracles and full legacy tuple comparisons cover160 expanded fixtures. Focused `cargo xtask test-group counter-reentry` passes (34 Python tests); selected reports regenerate twice byte-identically, with storage, links and whitespace guards. New report: 200891 bytes. Full-suite validation is deferred to the tenth batch commit. Three bounded source helpers migrated; independent numeric/address expectations and existing source/Rust regressions check their contracts.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -1405,3 +1405,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1405 |
|
| 1406 |
|
| 1407 |
- [x] RE-785 Audited dense recent-award scans timestamps and index64 alias ([report](research/QVM_AWARD_REENTRY.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 1405 |
|
| 1406 |
|
| 1407 |
- [x] RE-785 Audited dense recent-award scans timestamps and index64 alias ([report](research/QVM_AWARD_REENTRY.md)).
|
| 1408 |
+
|
| 1409 |
+
|
| 1410 |
+
- [x] RE-786 Audited method counters team pairs and dense record clearing ([report](research/QVM_COUNTER_REENTRY.md)).
|
docs/research/QVM_COUNTER_REENTRY.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Audited method counters team pairs and dense record clearing
|
| 2 |
+
|
| 3 |
+
RE-786. Reproduce with `python3 scripts/analyze_qvm_counter_reentry.py`; validate with `cargo xtask test-group counter-reentry`. See the [machine report](qvm-counter-reentry.json).
|
| 4 |
+
|
| 5 |
+
The audit includes48 method updates with self-aliasing and unsigned wrap,64 team-pair gates, and48 record clears across sparse and fully populated64-client pools. Accepted index64 and rejected indices-minus-one/65 are checked against exact changed addresses and initialized neighbor values. Existing full method-domain, null/team gates and Rust parity reports are selected transitively. Stat update children remain captured; no claim of full stat lifecycle execution is added.
|
| 6 |
+
|
| 7 |
+
No original executable/full VM/native world collision or rendering runs. Supplied callback/native responses and fixture domains remain explicit; complete macOS/Linux Rust/Bevy/Solari gameplay remains open.
|
docs/research/README.md
CHANGED
|
@@ -945,3 +945,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 945 |
|
| 946 |
|
| 947 |
[RE-785: Audited dense recent-award scans timestamps and index64 alias](QVM_AWARD_REENTRY.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 945 |
|
| 946 |
|
| 947 |
[RE-785: Audited dense recent-award scans timestamps and index64 alias](QVM_AWARD_REENTRY.md).
|
| 948 |
+
|
| 949 |
+
|
| 950 |
+
[RE-786: Audited method counters team pairs and dense record clearing](QVM_COUNTER_REENTRY.md).
|
docs/research/qvm-counter-reentry.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
docs/research/qvm-resumer-audit.json
CHANGED
|
@@ -8628,7 +8628,7 @@
|
|
| 8628 |
285578
|
| 8629 |
],
|
| 8630 |
"path": "scripts/qvm_record_clear_support.py",
|
| 8631 |
-
"repeated_calls_opt_in":
|
| 8632 |
},
|
| 8633 |
{
|
| 8634 |
"backward_conditional_branches": [],
|
|
@@ -8856,7 +8856,7 @@
|
|
| 8856 |
279584
|
| 8857 |
],
|
| 8858 |
"path": "scripts/qvm_stat_update_support.py",
|
| 8859 |
-
"repeated_calls_opt_in":
|
| 8860 |
},
|
| 8861 |
{
|
| 8862 |
"backward_conditional_branches": [],
|
|
@@ -8877,7 +8877,7 @@
|
|
| 8877 |
279818
|
| 8878 |
],
|
| 8879 |
"path": "scripts/qvm_team_counter_support.py",
|
| 8880 |
-
"repeated_calls_opt_in":
|
| 8881 |
}
|
| 8882 |
],
|
| 8883 |
"limits": "Static direct-import calls only, including local aliases. Computed ranges, indirect/module calls and reachability need manual/dynamic review. Backward branches and dynamic stores are review markers, not proven failures; fixture compatibility is not semantic proof.",
|
|
@@ -8920,7 +8920,7 @@
|
|
| 8920 |
"summary": {
|
| 8921 |
"call_expressions": 179,
|
| 8922 |
"files": 140,
|
| 8923 |
-
"legacy_expressions":
|
| 8924 |
"nonliteral_ranges": 20
|
| 8925 |
}
|
| 8926 |
}
|
|
|
|
| 8628 |
285578
|
| 8629 |
],
|
| 8630 |
"path": "scripts/qvm_record_clear_support.py",
|
| 8631 |
+
"repeated_calls_opt_in": true
|
| 8632 |
},
|
| 8633 |
{
|
| 8634 |
"backward_conditional_branches": [],
|
|
|
|
| 8856 |
279584
|
| 8857 |
],
|
| 8858 |
"path": "scripts/qvm_stat_update_support.py",
|
| 8859 |
+
"repeated_calls_opt_in": true
|
| 8860 |
},
|
| 8861 |
{
|
| 8862 |
"backward_conditional_branches": [],
|
|
|
|
| 8877 |
279818
|
| 8878 |
],
|
| 8879 |
"path": "scripts/qvm_team_counter_support.py",
|
| 8880 |
+
"repeated_calls_opt_in": true
|
| 8881 |
}
|
| 8882 |
],
|
| 8883 |
"limits": "Static direct-import calls only, including local aliases. Computed ranges, indirect/module calls and reachability need manual/dynamic review. Backward branches and dynamic stores are review markers, not proven failures; fixture compatibility is not semantic proof.",
|
|
|
|
| 8920 |
"summary": {
|
| 8921 |
"call_expressions": 179,
|
| 8922 |
"files": 140,
|
| 8923 |
+
"legacy_expressions": 166,
|
| 8924 |
"nonliteral_ranges": 20
|
| 8925 |
}
|
| 8926 |
}
|
scripts/analyze_qvm_counter_reentry.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Differential migration of counters, aliases and sparse/dense pair clearing."""
|
| 3 |
+
import itertools
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
import qvm_stat_update_support as stats
|
| 6 |
+
import qvm_record_clear_support as records
|
| 7 |
+
import qvm_team_counter_support as teams
|
| 8 |
+
from qvm_resumer_diff_support import compare
|
| 9 |
+
from qvm_research_support import source
|
| 10 |
+
from analyze_qvm import write_json
|
| 11 |
+
|
| 12 |
+
def main():
|
| 13 |
+
q,raw,h,ins=source();updates=[];clears=[];pairs=[]
|
| 14 |
+
for method,self_hit,initial in itertools.product([-1,0,6,12,20,22,25,34,37,47,48,49],[False,True],[0,0xffffffff]):
|
| 15 |
+
a={'method':method,'self':self_hit,'initial':initial}
|
| 16 |
+
old,new,equal=compare(stats,lambda:stats.update(ins,stats.seed(raw,h,**a),{8:1,12:method,16:1 if self_hit else 2}))
|
| 17 |
+
updates.append({'input':a,'legacy_equal':equal,'changes':new[2]['changes'],'requests':new[2]['requests']})
|
| 18 |
+
for mode,index,dense in itertools.product([3,9,10,11],[-1,0,1,63,64,65],[False,True]):
|
| 19 |
+
a={'mode':mode,'index':index,'dense':dense};old,new,equal=compare(records,lambda:records.clear(ins,records.seed(**a),{8:index}));clears.append({'input':a,'legacy_equal':equal,'changes':new[2]['changes'],'stop':new[2]['execution']['stop']})
|
| 20 |
+
for mode,same,self_hit,initial,actor_client in itertools.product([3,9,10,11],[False,True],[False,True],[0,0xffffffff],[False,True]):
|
| 21 |
+
a={'mode':mode,'same':same,'self':self_hit,'initial':initial,'actor_client':actor_client};old,new,equal=compare(teams,lambda:teams.aggregate(ins,teams.seed(raw,h,**a),{8:teams.ATTACKER,12:teams.ATTACKER if self_hit else teams.TARGET}));pairs.append({'input':a,'legacy_equal':equal,'initial':new[2]['initial'],'final':new[2]['final']})
|
| 22 |
+
write_json(Path('docs/research/qvm-counter-reentry.json'),{'source':q['source'],'sha256':q['sha256'],'updates':updates,'clears':clears,'pairs':pairs,'limits':'Corrected278834/285486/279720;48 stat,48 clear and64 team fixtures. Full legacy/corrected tuple comparisons; complete tracked clear changes across64 dense clients and65 indices. Stat reporting/aggregate/award children remain captured in update; lifecycle/native ownership remains open.'})
|
| 23 |
+
if __name__=='__main__':main()
|
scripts/qvm_record_clear_support.py
CHANGED
|
@@ -16,6 +16,6 @@ def seed(**a):
|
|
| 16 |
|
| 17 |
def clear(ins,m,args):
|
| 18 |
m[R+40]=args[8];addresses=sorted({c+2520+8*j+4*k for slot in range(64) for c in [m[POOL+880*slot+520]] if c for j in range(65) for k in [0,1]});before={a:m[a]&0xffffffff for a in addresses}
|
| 19 |
-
m,e=resume(ins,285487,285578,m,R,handlers={33715:predicate})
|
| 20 |
changes=[{'address':a,'before':v,'after':m[a]&0xffffffff} for a,v in before.items() if v!=(m[a]&0xffffffff)]
|
| 21 |
return m,0,{'arguments':args,'changes':changes,'execution':e}
|
|
|
|
| 16 |
|
| 17 |
def clear(ins,m,args):
|
| 18 |
m[R+40]=args[8];addresses=sorted({c+2520+8*j+4*k for slot in range(64) for c in [m[POOL+880*slot+520]] if c for j in range(65) for k in [0,1]});before={a:m[a]&0xffffffff for a in addresses}
|
| 19 |
+
m,e=resume(ins,285487,285578,m,R,handlers={33715:predicate},repeated_calls=True)
|
| 20 |
changes=[{'address':a,'before':v,'after':m[a]&0xffffffff} for a,v in before.items() if v!=(m[a]&0xffffffff)]
|
| 21 |
return m,0,{'arguments':args,'changes':changes,'execution':e}
|
scripts/qvm_stat_update_support.py
CHANGED
|
@@ -17,6 +17,6 @@ def update(ins,m,args):
|
|
| 17 |
for o,v in args.items():m[T+52+o]=v
|
| 18 |
addresses=sorted({c+o for c in [CLIENT,A_CLIENT] for o in OFFSETS});before={a:m[a]&0xffffffff for a in addresses};requests=[]
|
| 19 |
hs={c:captured(c,requests) for c in [279720,279586,285227,283622]};hs[278733]=classify
|
| 20 |
-
m,e=resume(ins,278835,279584,m,T,handlers=hs)
|
| 21 |
changes=[{'client':'actor' if a>=A_CLIENT and a<A_CLIENT+7000 else 'victim','offset':a-(A_CLIENT if a>=A_CLIENT and a<A_CLIENT+7000 else CLIENT),'before':before[a],'after':m[a]&0xffffffff} for a in addresses if before[a]!=(m[a]&0xffffffff)]
|
| 22 |
return m,0,{'arguments':args,'changes':changes,'requests':requests,'execution':e}
|
|
|
|
| 17 |
for o,v in args.items():m[T+52+o]=v
|
| 18 |
addresses=sorted({c+o for c in [CLIENT,A_CLIENT] for o in OFFSETS});before={a:m[a]&0xffffffff for a in addresses};requests=[]
|
| 19 |
hs={c:captured(c,requests) for c in [279720,279586,285227,283622]};hs[278733]=classify
|
| 20 |
+
m,e=resume(ins,278835,279584,m,T,handlers=hs,repeated_calls=True)
|
| 21 |
changes=[{'client':'actor' if a>=A_CLIENT and a<A_CLIENT+7000 else 'victim','offset':a-(A_CLIENT if a>=A_CLIENT and a<A_CLIENT+7000 else CLIENT),'before':before[a],'after':m[a]&0xffffffff} for a in addresses if before[a]!=(m[a]&0xffffffff)]
|
| 22 |
return m,0,{'arguments':args,'changes':changes,'requests':requests,'execution':e}
|
scripts/qvm_team_counter_support.py
CHANGED
|
@@ -14,5 +14,5 @@ def snapshot(m):return {name:[m[c+o]&0xffffffff for o in [2444,2516]] for name,c
|
|
| 14 |
|
| 15 |
def aggregate(ins,m,args):
|
| 16 |
for o,v in args.items():m[P+32+o]=v
|
| 17 |
-
before=snapshot(m);m,e=resume(ins,279721,279818,m,P,handlers={33715:predicate})
|
| 18 |
return m,0,{'arguments':args,'initial':before,'final':snapshot(m),'execution':e}
|
|
|
|
| 14 |
|
| 15 |
def aggregate(ins,m,args):
|
| 16 |
for o,v in args.items():m[P+32+o]=v
|
| 17 |
+
before=snapshot(m);m,e=resume(ins,279721,279818,m,P,handlers={33715:predicate},repeated_calls=True)
|
| 18 |
return m,0,{'arguments':args,'initial':before,'final':snapshot(m),'execution':e}
|
scripts/test_qvm_counter_reentry.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from test_qvm_method_stat_updates import expected
|
| 4 |
+
from qvm_record_clear_support import RPOOL
|
| 5 |
+
class CounterReentryTests(unittest.TestCase):
|
| 6 |
+
@classmethod
|
| 7 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-counter-reentry.json').read_text())
|
| 8 |
+
def test_stat_changes_and_callback_order(self):
|
| 9 |
+
self.assertEqual(len(self.r['updates']),48)
|
| 10 |
+
for p in self.r['updates']:
|
| 11 |
+
changes,calls=expected(p['input']);self.assertEqual(p['changes'],changes);self.assertEqual([r['target'] for r in p['requests']],calls);self.assertTrue(p['legacy_equal'])
|
| 12 |
+
def test_dense_clear_exact_addresses_and_preserved_neighbors(self):
|
| 13 |
+
self.assertEqual(len(self.r['clears']),48)
|
| 14 |
+
for p in self.r['clears']:
|
| 15 |
+
a=p['input'];slots=range(64) if a['dense'] else [0,3,63];valid=a['mode'] in [3,10] and 0<=a['index']<=64;expected_changes=[{'address':RPOOL+j*6336+2520+8*a['index']+4*k,'before':10000+j*256+2*a['index']+k,'after':0} for j in slots for k in [0,1]] if valid else []
|
| 16 |
+
self.assertEqual(p['changes'],expected_changes,a);self.assertEqual(p['stop'],285578);self.assertTrue(p['legacy_equal'],a)
|
| 17 |
+
def test_team_pair_gate_alias_and_wrapping(self):
|
| 18 |
+
self.assertEqual(len(self.r['pairs']),64)
|
| 19 |
+
for p in self.r['pairs']:
|
| 20 |
+
a=p['input'];v=a['initial'];out={'actor':[v,v],'victim':[v,v]}
|
| 21 |
+
if a['mode'] in [3,10] and a['same'] and not a['self'] and a['actor_client']:out['actor'][0]=(v+1)&0xffffffff;out['victim'][1]=(v+1)&0xffffffff
|
| 22 |
+
self.assertEqual(p['final'],out,a);self.assertTrue(p['legacy_equal'])
|
| 23 |
+
if __name__=='__main__':unittest.main()
|
xtask/checks.tsv
CHANGED
|
@@ -1741,3 +1741,13 @@ report scripts/analyze_qvm_award_reentry.py docs/research/qvm-award-reentry.json
|
|
| 1741 |
edge docs/research/qvm-award-reentry.json scripts/test_qvm_award_reentry.py
|
| 1742 |
edge scripts/analyze_qvm_award_reentry.py scripts/analyze_qvm_resumer_audit.py
|
| 1743 |
group award-reentry scripts/analyze_qvm_award_reentry.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1741 |
edge docs/research/qvm-award-reentry.json scripts/test_qvm_award_reentry.py
|
| 1742 |
edge scripts/analyze_qvm_award_reentry.py scripts/analyze_qvm_resumer_audit.py
|
| 1743 |
group award-reentry scripts/analyze_qvm_award_reentry.py
|
| 1744 |
+
|
| 1745 |
+
group counter-reentry scripts/qvm_stat_update_support.py
|
| 1746 |
+
|
| 1747 |
+
group counter-reentry scripts/qvm_record_clear_support.py
|
| 1748 |
+
|
| 1749 |
+
group counter-reentry scripts/qvm_team_counter_support.py
|
| 1750 |
+
report scripts/analyze_qvm_counter_reentry.py docs/research/qvm-counter-reentry.json
|
| 1751 |
+
edge docs/research/qvm-counter-reentry.json scripts/test_qvm_counter_reentry.py
|
| 1752 |
+
edge scripts/analyze_qvm_counter_reentry.py scripts/analyze_qvm_resumer_audit.py
|
| 1753 |
+
group counter-reentry scripts/analyze_qvm_counter_reentry.py
|