Files
VianoBugAnalysis/tests/ui_dashboard_server.py

115 lines
7.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Synthetic, disposable UI fixture; never uses model or database providers."""
import json
import os
import tempfile
from pathlib import Path
import uvicorn
from viano_bug_analysis.api import APIConfig, Client, Project
from viano_bug_analysis.api.app import create_app
from viano_bug_analysis.lifecycle import Workspace, CheckpointStore
from viano_bug_analysis.lifecycle.job import timestamp
from viano_bug_analysis.lifecycle.storage import atomic_json, json_bytes
from viano_bug_analysis.package.factory import PackageFactory
from viano_bug_analysis.case import CaseBuilder
import viano_bug_analysis.api.dashboard as dashboard
import viano_bug_analysis.api.operations as operations
TOKEN = 'ui_fixture_' + 'x' * 40
def seed(root, case_id, title, completed=False):
workspace = Workspace(root)
store = CheckpointStore(workspace)
now = timestamp()
manifest = {'format':'viano-bug-case-package','format_version':1,'case_id':case_id,
'package_id':'preview-'+case_id,'package_generation':0,'analysis_revision':0,
'project':{'id':'viano-core','type':'wow','profile':'vcore'},'created_at':now,'updated_at':now,
'state':'NEW','routing':{'destination':'inbox','reason':None,'retry_count':0,'retry_not_before':None},
'artifacts':{'case':None,'diagnosis':None,'change_request':None,'case_inputs':'inputs.json'},
'history':{'analysis_revisions':0,'reproductions':0,'evidence':0,'handoffs':0,'feedback':0,'events_ref':None},'integrity':{}}
contents={'inputs.json':json_bytes({'format':'viano-case-inputs','format_version':1,'reports':['report.json']}),
'report.json':json_bytes({'format':'viano-bug-report','format_version':1,'title':title,
'observations':[{'text':'Synthetic UI fixture observation'}]})}
path=workspace.inbox/(case_id+'.zip');PackageFactory().create(path,manifest,contents)
store.intake(path);path.unlink()
identity=case_id,manifest['package_id'];CaseBuilder(store).build(*identity)
for state,pointer in [('INTERPRETING_CASE','case_interpretation'),('GENERATING_HYPOTHESES','hypotheses')]:
ref=pointer+'.json';store.advance(*identity,state,step_id=state,
artifacts={pointer:ref},additions={ref:json_bytes({'analysis_revision':1})})
store.advance(*identity,'INVESTIGATING_HYPOTHESES',step_id='investigate')
hypothesis={'id':'H1','proposal':{'title':'Synthetische Arbeitshypothese','mechanism':'Die erwartete Aktion bleibt aus.'},
'confidence':'supported','disposition':'open','iterations':2,'evidence_refs':['E000001'],'working_brief_ref':'brief.json'}
store.advance(*identity,'INVESTIGATING_HYPOTHESES',step_id='fixture-state',
artifacts={'investigation_state':'state.json'},details={'operation':'investigation-state','state_ref':'state.json'},
additions={'state.json':json_bytes({'analysis_revision':1,'hypotheses':{'H1':hypothesis}}),
'brief.json':json_bytes({'analysis_revision':1,'hypothesis_id':'H1','brief':{'findings':[
{'direction':'support','text':'Die Beobachtung passt zur Hypothese.','evidence_refs':['E000001']},
{'direction':'against','text':'Der vorhandene Handler spricht dagegen.','evidence_refs':['E000002']}],
'uncertainties':['Die Laufzeitkonfiguration ist noch ungeklärt.']}})})
measured = [
('BUILDING_CASE','entity_resolution_plan_v4','regular',2500,500),
('INTERPRETING_CASE','case_interpretation_v1','regular',2000,500),
('GENERATING_HYPOTHESES','hypotheses_v4','regular',1500,500),
('INVESTIGATING_HYPOTHESES','investigation_lean_v21','regular',4000,1000),
]
if completed:
measured += [
('BUILDING_DIAGNOSIS','diagnosis_v8','regular',1500,500),
('BUILDING_DIAGNOSIS','change_request_v9','regular',500,0),
]
measured.append(('INVESTIGATING_HYPOTHESES','investigation_format_repair_v1','correction',3000,900))
for i,(phase,prompt,category,inp,out) in enumerate(measured):
ref=f'call{i}.json';request=f'request{i}.json'
call={'rounds':1,'phase':phase,'request_ref':request,'outcome':{
'usage_classification':category,'metadata':{'input_tokens':inp,'output_tokens':out,
'reasoning_tokens':out//2,'cached_input_tokens':1000}}}
store.advance(*identity,'INVESTIGATING_HYPOTHESES',step_id=f'call{i}',
details={'operation':'llm-round','result_ref':ref},
additions={ref:json_bytes(call),request:json_bytes({'prompt_version':prompt})})
if completed:
store.advance(*identity,'BUILDING_DIAGNOSIS',step_id='diagnosis')
documents={
'diagnosis.json':{'analysis_revision':1,'diagnosis':{'status':'confirmed','root_cause':'Synthetische Diagnose für die Oberflächenprüfung','confidence':'strongly_supported'}},
'coding.json':{'analysis_revision':1,'assignment':'assigned','human_dev_assigned':True,
'request':{'required_change':'SQL-Vorlage mit Platzhaltern erstellen.','placeholders':['Passende Koordinaten ergänzen.']}},
'decision.json':{'human_dev':{'status':'assigned','summary':'Passende Spawndaten ermitteln und prüfen.'}},
}
store.advance(*identity,'BUILDING_DIAGNOSIS',step_id='diagnosis-document',
details={'operation':'diagnosis-complete','diagnosis_ref':'diagnosis.json'},
artifacts={'diagnosis':'diagnosis.json'},additions={ref:json_bytes(doc) for ref,doc in documents.items()})
store.advance(*identity,'BUILDING_DIAGNOSIS',step_id='handoff-document',
details={'operation':'change-request-complete','change_request_ref':'coding.json','decision_ref':'decision.json'},
artifacts={'change_request':'coding.json'})
store.advance(*identity,'OUTPUT_READY',step_id='done')
return identity
if __name__ == '__main__':
with tempfile.TemporaryDirectory(prefix='vba-dashboard-', dir=os.environ.get('VBA_UI_TEST_WORKSPACE')) as temporary:
root=Path(temporary)
identity=seed(root,'BUG-000020','Wolpertinger fehlen in Dun Morogh')
seed(root,'BUG-000017','Leuchtbrille – Kontrolllauf',completed=True)
# Display-only test request fixture; real feedback/budget binding is tested
# independently through the actual coordinator in test_human_web.py.
store=CheckpointStore(Workspace(root));ref='ui-test-request.json'
request={'case_id':identity[0],'package_id':identity[1],'analysis_revision':1,'request_id':'ui-test',
'executor':'human','hypothesis_id':'H1','question':'Ist die Kreatur nach Questannahme sichtbar?',
'environment':'Lokaler Testserver','prerequisites':['Quest noch nicht angenommen'],
'steps':['Quest annehmen','Umgebung beobachten'],'requested_observations':['Sichtbarkeit und Build notieren'],
'deadline':'2099-01-01T00:00:00Z'}
store.advance(*identity,'BLOCKED',step_id='ui-test-wait',reason='AWAITING_TEST_FEEDBACK',
retry_not_before=request['deadline'],artifacts={'async_test_request':ref},
details={'operation':'async-test-wait','request_ref':ref},additions={ref:json_bytes(request)})
config=APIConfig(root,(Project('viano-core','wow','vcore'),),
(Client('preview','VBA_UI_TEST_TOKEN',('viano-core',),operator=True),))
from viano_bug_analysis.api.users import Users
Users(root/'auth/users.sqlite3').manage('create_user','preview','ui-fixture-password')
os.environ['VBA_UI_TEST_TOKEN']=TOKEN
dashboard.read_status=lambda _: {'observer':'LIVE','service_id':'fixture-worker'}
operations.read_status=dashboard.read_status
folder=root/'runtime/worker';folder.mkdir(exist_ok=True)
atomic_json(folder/'status.json',{'status':'ANALYZING','service_id':'fixture-worker','updated_at':timestamp(),
'case':{'case_id':identity[0],'package_id':identity[1]}})
uvicorn.run(create_app(config),host='127.0.0.1',port=int(os.environ.get('VBA_UI_TEST_PORT','8765')),access_log=False)