Simplify investigation replies and derive controller bookkeeping
This commit is contained in:
1 parent
57984e5793
commit
49095ac803
26 files changed
+2072
-207
No files matched your search
@@ -0,0 +1,103 @@
|
||||
"""Offline projection of archived v13 replies onto v14, without new reasoning."""
|
||||
import argparse
|
||||
import copy
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from jsonschema import Draft202012Validator
|
||||
from viano_bug_analysis.analysis.investigation_prompt import build_prompt, output_schema
|
||||
from viano_bug_analysis.analysis.investigation_decision import normalize
|
||||
from viano_bug_analysis.analysis.confidence_review import effective_confidence
|
||||
from viano_bug_analysis.analysis.model_context import model_json
|
||||
from viano_bug_analysis.analysis.investigation_config import InvestigationError
|
||||
from viano_bug_analysis.package import PackageReader
|
||||
from viano_bug_analysis.llm.gemini import GeminiProvider
|
||||
|
||||
|
||||
def signature(messages):
|
||||
return hashlib.sha256(model_json(messages).encode('utf8')).hexdigest()
|
||||
|
||||
|
||||
def project(context, document):
|
||||
"""Copy semantic fields exactly; reuse only already written change reasons."""
|
||||
result=copy.deepcopy(document);update=result['update'];brief=update['working_brief']
|
||||
old={f['id']:f for f in context.get('working_brief',{}).get('brief',{}).get('findings',[])}
|
||||
reasons={c['id']:c['reason'] for c in brief.pop('changes')}
|
||||
brief['format_version']=2
|
||||
for f in brief['findings']:
|
||||
previous=old.get(f['id'])
|
||||
critical=previous and (f['direction']!=previous['direction'] or set(previous['evidence_refs'])-set(f['evidence_refs']))
|
||||
if critical and f['id'] in reasons:f['revision_reason']=reasons[f['id']]
|
||||
present={f['id'] for f in brief['findings']}
|
||||
brief['retired']=[{'id':fid,'reason':reasons[fid]} for fid in old if fid not in present and fid in reasons]
|
||||
for key in ('note','evidence_refs','causal_review'):update.pop(key)
|
||||
if result['assessment'] is not None:result['assessment'].pop('evidence_refs')
|
||||
return result
|
||||
|
||||
|
||||
def measure(path):
|
||||
with PackageReader(path) as reader:
|
||||
contexts={};calls=[]
|
||||
for ref in reader.files:
|
||||
if ref.startswith('analysis/investigation/') and '/contexts/' in ref:
|
||||
c=json.loads(reader.read_bytes(ref))
|
||||
if c.get('prompt_version')=='investigation_project_v13':
|
||||
contexts[signature(build_prompt(c)['messages'])]=c
|
||||
elif ref.startswith('llm/operations/') and '/round-' in ref and ref.endswith('.json'):
|
||||
call=json.loads(reader.read_bytes(ref))
|
||||
if call['phase']=='INVESTIGATING_HYPOTHESES':calls.append((ref,call))
|
||||
state=json.loads(reader.read_bytes(reader.manifest['artifacts']['investigation_state']))
|
||||
rejected={n['llm_ref']:n['code'] for h in state['hypotheses'].values() for n in h['notes'] if n['kind']=='invalid_response'}
|
||||
rows=[];requests=[];unavailable=0
|
||||
for ref,call in calls:
|
||||
request=json.loads(reader.read_bytes(call['request_ref']))
|
||||
original=contexts[signature(request['messages'])]
|
||||
context=dict(original,prompt_version='investigation_project_v14')
|
||||
def request_sizes(req):
|
||||
system,prefix,live=GeminiProvider._messages(req,stable_case_context=True)
|
||||
return {'message_bytes':sum(len(m['content'].encode('utf8')) for m in req['messages']),
|
||||
'prefix_bytes':len(model_json([system,prefix]).encode('utf8')),
|
||||
'live_bytes':len(model_json(live).encode('utf8'))}
|
||||
requests.append({'call_ref':ref,'old':request_sizes(request),
|
||||
'new':request_sizes(build_prompt(context))})
|
||||
document=call.get('outcome',{}).get('document')
|
||||
if document is None:
|
||||
unavailable+=1;continue
|
||||
wire=project(original,document)
|
||||
errors=list(Draft202012Validator(output_schema(context)).iter_errors(wire))
|
||||
code='WIRE_SCHEMA' if errors else None
|
||||
normalized=None
|
||||
if code is None:
|
||||
try:normalized=normalize(context,wire)
|
||||
except InvestigationError as error:code=error.code
|
||||
rows.append({'call_ref':ref,'original_rejection':rejected.get(ref),
|
||||
'projected_rejection':code,'old_document_bytes':len(model_json(document).encode('utf8')),
|
||||
'new_document_bytes':len(model_json(wire).encode('utf8')),
|
||||
'projected_effect':normalized['update']['causal_review']['effect'] if normalized else None,
|
||||
'projected_confidence':effective_confidence(normalized['update']) if normalized else None})
|
||||
return {'case_id':reader.manifest['case_id'],'package_generation':reader.manifest['package_generation'],
|
||||
'calls':len(calls),'unavailable_schema_replies':unavailable,'samples':rows,'requests':requests}
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
parser=argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('packages',nargs='+',type=Path);parser.add_argument('--output',type=Path,required=True)
|
||||
args=parser.parse_args();results=[measure(p) for p in args.packages]
|
||||
rows=[r for result in results for r in result['samples']]
|
||||
old=sum(r['old_document_bytes'] for r in rows);new=sum(r['new_document_bytes'] for r in rows)
|
||||
requests=[r for result in results for r in result['requests']]
|
||||
report={'measurement':'investigation_v14_reply_projection','old_document_bytes':old,'new_document_bytes':new,
|
||||
'visible_json_reduction_percent':round(100*(1-new/old),2),
|
||||
'rejected_v13_structured':sum(bool(r['original_rejection']) for r in rows),
|
||||
'rejected_v14_projection':sum(bool(r['projected_rejection']) for r in rows),
|
||||
'request_totals':{version:{unit:sum(r[version][unit] for r in requests)
|
||||
for unit in ('message_bytes','prefix_bytes','live_bytes')} for version in ('old','new')},
|
||||
'limitations':['Canonical visible JSON bytes only, not provider output/thinking tokens.',
|
||||
'No new model replies; semantic claims copied exactly, no proof of correctness.',
|
||||
'Schema-failing replies without stored documents cannot be projected.',
|
||||
'Projection validates wire and brief normalization, not external tool availability or final diagnosis.'],
|
||||
'packages':results}
|
||||
args.output.parent.mkdir(parents=True,exist_ok=True)
|
||||
args.output.write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n',encoding='utf8')
|
||||
print(json.dumps({k:v for k,v in report.items() if k not in {'packages','limitations'}}))
|
||||
Reference in new issue
Block a user