"""Aggregate actual evidence without treating startup checks as a resolved crash root cause."""
import collections
import datetime
import hashlib
import json
import os
from pathlib import Path

root=Path('artifacts/crash-analysis-20261021')
def read(name):return json.loads((root/name).read_text(encoding='utf-8-sig'))
package=json.loads(Path('XFEEDToolBox/PluginPackage/package.json').read_text(encoding='utf-8-sig'))
labels=['hardened-final-01','hardened-final-02','hardened-final-after-force']
runs=[read('startup-'+label+'.json') for label in labels]
for run in runs:
    assert run['survived'] and run['secondsRequested']==60
    assert next(f['sha256'] for f in run['files'] if f['name']=='dinput8.dll')==package['sha256']
idle=read('final-idle-prologues.json')
second_idle=read('final-second-idle-prologues.json')
assert all(e['original'] for e in idle['entries']+second_idle['entries'])
assert not read('final-idle-status.json')['observationStarted']
observing=read('final-observing-prologues.json')
assert all(not e['original'] for e in observing['entries'])
observation=read('explicit-observation-survival.json')
assert observation['survived'] and observation['secondsAfterExplicitStart']>=60 and observation['initialized'] and not observation['ready']
native=read('native-memory-final-regression.json')
assert native['passed']
tests=read('tests/test-results.json')
counts=collections.Counter(item['outcome'] for item in tests['results'])
assert counts=={0:151,2:4},counts
cleanup=read('cleanup.json')
assert cleanup['gameProcesses']==0 and cleanup['developmentLoaderRemoved'] and cleanup['installationRecordRemoved']
assert all(f['unchanged'] for f in cleanup['gameAndTranslationFiles'])
quit_rows=[json.loads(line) for line in (root/'native-quit-mainmenu.jsonl').read_text(encoding='utf-8').splitlines()]
assert sum(row.get('kind')=='original-native-quit' for row in quit_rows)==1
quit_journal=Path.home()/'Saved Games/Frontier Developments/Elite Dangerous/Journal.2026-10-21T084446.01.log'
quit_events=[json.loads(line) for line in quit_journal.read_text(encoding='utf-8-sig').splitlines() if line.strip()]
assert any(row.get('event')=='Shutdown' and row.get('timestamp')=='2026-10-21T00:52:40Z' for row in quit_events)
assert read('forced-stop-02.json')['forcedStop'] and read('forced-stop-02.json')['exited']
dump_root=Path(os.environ['LOCALAPPDATA'])/'Temp/Frontier Developments/EliteDangerous/CrashDumps'
dumps=sorted(p.name for p in dump_root.rglob('*.dmp'))
assert dumps==['20261021_081336_MiniDump.dmp','20261021_081544_MiniDump.dmp'],dumps
files=read('final-build-files.json')
for entry in files:
    assert hashlib.sha256(Path(entry['path']).read_bytes()).hexdigest()==entry['sha256'],entry['path']
report={
    'schema':1,'generatedAt':datetime.datetime.now(datetime.timezone.utc).isoformat(),
    'scope':'Crash analysis and plugin startup/lifecycle hardening; no automatic flight acceptance',
    'originalFaultConfirmed':'Invalid free-list node access in the game allocator, RVA 551FC0, exception C0000005',
    'corruptingWriteIdentified':False,'originalCrashReliablyReproduced':False,'originalCrashRootCauseResolved':False,
    'pluginVersion':package['version'],'pluginSha256':package['sha256'],
    'startupAndProtocolRegressionPassed':True,
    'coreTests':{'total':155,'passed':151,'failed':0,'skipped':4},
    'nativeOwnMemoryTests':native,
    'finalStartupRuns':[{'label':r['label'],'processId':r['processId'],'seconds':r['secondsRequested'],'survived':r['survived']} for r in runs],
    'statusQueriesPreserveNativeEntries':True,'explicitObservation':observation,
    'nativeMainMenuQuitObserved':True,'nativeQuitEvidence':'native-quit-mainmenu.jsonl; Journal Shutdown at 2026-10-21T00:52:40Z',
    'forceStopAndRestartObserved':True,'newGameCrashDumps':0,
    'appBuild':{'passed':True,'warnings':0,'errors':0,'evidence':'app-build.log'},
    'flightInputsSent':0,'screenUse':False,'completeAutomaticNavigationAccepted':False,
    'productionReleasePublished':False,'cleanup':cleanup,'captureRenewal':read('capture-renewal.json'),
    'buildFiles':files}
(root/'acceptance.json').write_text(json.dumps(report,ensure_ascii=False,indent=2),encoding='utf-8')
print(json.dumps({k:report[k] for k in ['startupAndProtocolRegressionPassed','originalCrashRootCauseResolved','completeAutomaticNavigationAccepted','pluginVersion','coreTests','newGameCrashDumps','productionReleasePublished']}))
