qvm: no target statistic bookkeeping
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_NO_TARGET_STATS.md +7 -0
- docs/research/README.md +3 -0
- docs/research/qvm-no-target-stats.json +0 -0
- scripts/analyze_qvm_no_target_stats.py +42 -0
- scripts/test_qvm_no_target_stats.py +25 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -613,3 +613,6 @@ Research progress: RE-643 [report](research/QVM_REWOUND_TRACE.md); remaining nat
|
|
| 613 |
|
| 614 |
|
| 615 |
Research progress: RE-644 [report](research/QVM_TWENTY_PELLETS.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 613 |
|
| 614 |
|
| 615 |
Research progress: RE-644 [report](research/QVM_TWENTY_PELLETS.md); remaining native/content/runtime/platform scope stays open.
|
| 616 |
+
|
| 617 |
+
|
| 618 |
+
Research progress: RE-645 [report](research/QVM_NO_TARGET_STATS.md); remaining native/content/runtime/platform scope stays open.
|
docs/FINDINGS.md
CHANGED
|
@@ -962,3 +962,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
|
|
| 962 |
|
| 963 |
|
| 964 |
**RE-644 — Twenty pellet source loop signed seed carry and no-target handoff:** 295018 now executes all20 pellet iterations with actual rotation, signed seed carry and recovered trace return0, then reaches no-target bookkeeping. [Evidence](research/QVM_TWENTY_PELLETS.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 962 |
|
| 963 |
|
| 964 |
**RE-644 — Twenty pellet source loop signed seed carry and no-target handoff:** 295018 now executes all20 pellet iterations with actual rotation, signed seed carry and recovered trace return0, then reaches no-target bookkeeping. [Evidence](research/QVM_TWENTY_PELLETS.md).
|
| 965 |
+
|
| 966 |
+
|
| 967 |
+
**RE-645 — Statistic category maps and complete no-target bookkeeping:** 279820 maps weapon/location categories, increments attempts/misses for no-target IDs, and recomputes percentage; zero total after wrap resets percentage without division. [Evidence](research/QVM_NO_TARGET_STATS.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -933,3 +933,6 @@ Research progress: RE-643 [report](research/QVM_REWOUND_TRACE.md); remaining nat
|
|
| 933 |
|
| 934 |
|
| 935 |
Research progress: RE-644 [report](research/QVM_TWENTY_PELLETS.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 933 |
|
| 934 |
|
| 935 |
Research progress: RE-644 [report](research/QVM_TWENTY_PELLETS.md); remaining native/content/runtime/platform scope stays open.
|
| 936 |
+
|
| 937 |
+
|
| 938 |
+
Research progress: RE-645 [report](research/QVM_NO_TARGET_STATS.md); remaining native/content/runtime/platform scope stays open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -892,3 +892,8 @@ Whole291641 now executes recovered rewind/configured/restore children before and
|
|
| 892 |
## 2026-10-20 — RE-644 Twenty pellet source loop signed seed carry and no-target handoff (separate task commit)
|
| 893 |
|
| 894 |
295018 now executes all20 pellet iterations with actual rotation, signed seed carry and recovered trace return0, then reaches no-target bookkeeping. Four20-pellet compositions plus a zero-direction boundary check every endpoint, signed seed, indexed rotation geometry, trace count and pending bookkeeping ABI. Full suite: 1051 tests pass. Report regenerates byte-identically (1035109 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 892 |
## 2026-10-20 — RE-644 Twenty pellet source loop signed seed carry and no-target handoff (separate task commit)
|
| 893 |
|
| 894 |
295018 now executes all20 pellet iterations with actual rotation, signed seed carry and recovered trace return0, then reaches no-target bookkeeping. Four20-pellet compositions plus a zero-direction boundary check every endpoint, signed seed, indexed rotation geometry, trace count and pending bookkeeping ABI. Full suite: 1051 tests pass. Report regenerates byte-identically (1035109 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
| 895 |
+
|
| 896 |
+
|
| 897 |
+
## 2026-10-20 — RE-645 Statistic category maps and complete no-target bookkeeping (separate task commit)
|
| 898 |
+
|
| 899 |
+
279820 maps weapon/location categories, increments attempts/misses for no-target IDs, and recomputes percentage; zero total after wrap resets percentage without division. 49 category probes and28 no-target/counter/invalid-attacker cases independently check table-derived categories, all20 stats rows, call order and overflow handling. Full suite: 1055 tests pass. Report regenerates byte-identically (520179 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
|
@@ -976,3 +976,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 976 |
|
| 977 |
|
| 978 |
- [x] RE-644 Twenty pellet source loop signed seed carry and no-target handoff ([report](research/QVM_TWENTY_PELLETS.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 976 |
|
| 977 |
|
| 978 |
- [x] RE-644 Twenty pellet source loop signed seed carry and no-target handoff ([report](research/QVM_TWENTY_PELLETS.md)).
|
| 979 |
+
|
| 980 |
+
|
| 981 |
+
- [x] RE-645 Statistic category maps and complete no-target bookkeeping ([report](research/QVM_NO_TARGET_STATS.md)).
|
docs/research/QVM_NO_TARGET_STATS.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Statistic category maps and complete no-target bookkeeping
|
| 2 |
+
|
| 3 |
+
RE-645. Reproduce with `python3 scripts/analyze_qvm_no_target_stats.py`; check with `python3 scripts/test_qvm_no_target_stats.py`. The [machine report](qvm-no-target-stats.json) retains source identity and bounded fixtures.
|
| 4 |
+
|
| 5 |
+
Actual278587/278692 use file-backed jump tables to map weapon and location IDs, returning−1 outside supported categories. Actual279820 no-target paths accept target−1 or≥64, force location category−1, increment category row offsets0/4 and set row56 to100−misses/attempts×100 in source f32 order. A total wrapping to0 resets row56 to0. Attacker−1 bypasses work; invalid weapon category exits after both actual map calls. All20×76-byte rows are independently compared, including preserved canaries. Victim/team/hit branch33715 and damage semantics remain unrecovered; explicit counter fixtures are not legal-runtime claims.
|
| 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
|
@@ -534,3 +534,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 534 |
|
| 535 |
|
| 536 |
[RE-644: Twenty pellet source loop signed seed carry and no-target handoff](QVM_TWENTY_PELLETS.md). Reproduce with `python3 scripts/analyze_qvm_twenty_pellets.py`; check with `python3 scripts/test_qvm_twenty_pellets.py`.
|
|
|
|
|
|
|
|
|
|
|
|
| 534 |
|
| 535 |
|
| 536 |
[RE-644: Twenty pellet source loop signed seed carry and no-target handoff](QVM_TWENTY_PELLETS.md). Reproduce with `python3 scripts/analyze_qvm_twenty_pellets.py`; check with `python3 scripts/test_qvm_twenty_pellets.py`.
|
| 537 |
+
|
| 538 |
+
|
| 539 |
+
[RE-645: Statistic category maps and complete no-target bookkeeping](QVM_NO_TARGET_STATS.md). Reproduce with `python3 scripts/analyze_qvm_no_target_stats.py`; check with `python3 scripts/test_qvm_no_target_stats.py`.
|
docs/research/qvm-no-target-stats.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_no_target_stats.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Source statistic category maps and complete279820 no-target bookkeeping."""
|
| 3 |
+
import itertools
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from qvm_research_support import source,execute,constants
|
| 6 |
+
from qvm_server_fire_support import seed,ENTITY
|
| 7 |
+
from analyze_qvm_entity_init import POOL,STRIDE
|
| 8 |
+
from analyze_qvm_acceleration import PS,word
|
| 9 |
+
from analyze_qvm import write_json
|
| 10 |
+
LOCAL=0x79f10000
|
| 11 |
+
MAP_LOCAL=0x79f00000
|
| 12 |
+
|
| 13 |
+
def category(ins,m,target,value):
|
| 14 |
+
base=MAP_LOCAL+(0x1000 if target==278692 else 0);m=dict(m);m[base+20]=value;start,stop=(278588,278690) if target==278587 else (278693,278731);m,_,e=execute(ins,start,stop,m,(0,0,0),base);return m,{'target':target,'input':value,'result':e['return'],'execution':e}
|
| 15 |
+
|
| 16 |
+
def stats_state(m,client=PS):return {str(j):{str(o):m[client+856+76*j+o]&0xffffffff for o in range(0,76,4)} for j in range(20)}
|
| 17 |
+
|
| 18 |
+
def prepare(raw,h,m=None):
|
| 19 |
+
m=seed(raw,h,4) if m is None else dict(m);m.update(constants(raw,h,range(31236,31404,4)))
|
| 20 |
+
for o in range(0,880,4):m[POOL+7*STRIDE+o]=m[ENTITY+o]
|
| 21 |
+
return m
|
| 22 |
+
|
| 23 |
+
def no_target_stats(ins,m,args):
|
| 24 |
+
m=dict(m);before=stats_state(m)
|
| 25 |
+
for o,v in args.items():m[LOCAL+80+o]=v
|
| 26 |
+
def mapper(target):
|
| 27 |
+
def call(i,m,a,c):m,e=category(i,m,target,a[8]);return m,c,e['result'],e
|
| 28 |
+
return call
|
| 29 |
+
m,_,e=execute(ins,279821,280296,m,(0,0,0),LOCAL,{278587:mapper(278587),278692:mapper(278692)})
|
| 30 |
+
return m,{'arguments':args,'initial':before,'final':stats_state(m),'weapon_category':m.get(LOCAL+12),'execution':e,'status':'void-epilogue'}
|
| 31 |
+
|
| 32 |
+
def main():
|
| 33 |
+
q,raw,h,ins=source();m=prepare(raw,h);maps=[category(ins,m,target,value)[1] for target,values in [(278587,range(-1,30)),(278692,range(-1,17))] for value in values];rows=[]
|
| 34 |
+
cases=list(itertools.product([4,27,1],[-1,64,1023],[0,10,0xffffffff]))
|
| 35 |
+
for ident,target,count in cases+[(4,1023,0)]:
|
| 36 |
+
m=prepare(raw,h)
|
| 37 |
+
for j in range(20):
|
| 38 |
+
for o in range(0,76,4):m[PS+856+76*j+o]=0
|
| 39 |
+
m[PS+856+76*j]=count;m[PS+856+76*j+4]=min(count,7);m[PS+856+76*j+56]=word(9.5)
|
| 40 |
+
args={8:-1 if len(rows)==len(cases) else 7,12:ident,16:1,20:target,24:word(73.5)};rows.append(no_target_stats(ins,m,args)[1])
|
| 41 |
+
write_json(Path('docs/research/qvm-no-target-stats.json'),{'source':q['source'],'sha256':q['sha256'],'jump_words':{str(a):v for a,v in constants(raw,h,range(31236,31404,4)).items()},'category_probes':maps,'probes':rows,'limits':'Actual category278587/278692 and complete279820 for attacker−1 or no-target IDs−1/≥64. No victim/team/hit33715 branch or damage; explicit counter wrap fixtures do not establish legal runtime statistics domains.'})
|
| 42 |
+
if __name__=='__main__':main()
|
scripts/test_qvm_no_target_stats.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,copy,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from test_qvm_ground import word,f
|
| 4 |
+
class NoTargetStatsTests(unittest.TestCase):
|
| 5 |
+
@classmethod
|
| 6 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-no-target-stats.json').read_text());cls.maps={(p['target'],p['input']):p['result'] for p in cls.r['category_probes']}
|
| 7 |
+
def test_independent_file_jump_table_category_results(self):
|
| 8 |
+
for p in self.r['category_probes']:
|
| 9 |
+
value=p['input'];target=p['target'];valid=2<=value<=27 if target==278587 else 1<=value<=14;expected=-1
|
| 10 |
+
if valid:
|
| 11 |
+
address=(31236 if target==278587 else 31344)+4*value;destination=self.r['jump_words'][str(address)];expected=(destination-278608)//4 if target==278587 and destination!=278688 else ((destination-278713)//4 if target==278692 and destination!=278729 else -1)
|
| 12 |
+
self.assertEqual(p['result'],expected);self.assertEqual(p['execution']['calls'],[])
|
| 13 |
+
def test_independent_entire_stats_rows(self):
|
| 14 |
+
for p in self.r['probes']:
|
| 15 |
+
expected=copy.deepcopy(p['initial']);a=p['arguments'];category=self.maps.get((278587,a['12']),-1)
|
| 16 |
+
if a['8']!=-1 and category!=-1:
|
| 17 |
+
row=expected[str(category)];row['0']=(row['0']+1)&0xffffffff;row['4']=(row['4']+1)&0xffffffff;row['56']=word(f(100-f(f(float(row['4'])/float(row['0']))*100))) if row['0'] else 0
|
| 18 |
+
self.assertEqual(p['final'],expected)
|
| 19 |
+
def test_only_actual_category_children_on_no_target_paths(self):
|
| 20 |
+
for p in self.r['probes']:self.assertEqual([c['target'] for c in p['execution']['calls']],[] if p['arguments']['8']==-1 else [278587,278692])
|
| 21 |
+
def test_overflow_zero_total_avoids_division_and_resets_percentage(self):
|
| 22 |
+
for p in self.r['probes']:
|
| 23 |
+
c=self.maps[(278587,p['arguments']['12'])]
|
| 24 |
+
if c!=-1 and p['initial'][str(c)]['0']==0xffffffff:self.assertEqual(p['final'][str(c)]['0'],0);self.assertEqual(p['final'][str(c)]['56'],0)
|
| 25 |
+
if __name__=='__main__':unittest.main()
|