Use compact investigation working sets with durable local evidence recall
This commit is contained in:
1 parent
e8d0602ed3
commit
d81f2f67f3
21 files changed
+1614
-29
No files matched your search
@@ -0,0 +1,283 @@
|
||||
import asyncio
|
||||
import copy
|
||||
import json
|
||||
from dataclasses import asdict,replace
|
||||
import pytest
|
||||
from jsonschema import Draft202012Validator
|
||||
from viano_bug_analysis.analysis.investigation_compact import model_view,source_aliases,_content,validate_tool_shape
|
||||
from viano_bug_analysis.analysis.investigation_prompt import build_prompt,output_schema
|
||||
from viano_bug_analysis.analysis.investigation_config import InvestigationConfig,InvestigationError
|
||||
from viano_bug_analysis.analysis.investigation_decision import normalize
|
||||
from viano_bug_analysis.analysis import Investigator,DiagnosisBuilder
|
||||
from viano_bug_analysis.budget import BudgetManager
|
||||
from viano_bug_analysis.package import PackageReader,PackageValidator
|
||||
from viano_bug_analysis.lifecycle import CheckpointStore,Workspace
|
||||
from viano_bug_analysis.llm.gemini import GeminiProvider
|
||||
from viano_bug_analysis.llm.stable_context import split_document,restore_document
|
||||
from viano_bug_analysis.tools import InvestigationToolRouter
|
||||
from test_investigation_tools import tool_case
|
||||
from test_case_builder import case_setup
|
||||
from test_case_interpreter import gateway
|
||||
from test_investigator import LoopAdapter,CASE,run,state
|
||||
from test_working_brief import service_for,brief
|
||||
from test_project_research import rows
|
||||
|
||||
|
||||
def entry(number,kind='source.read'):
|
||||
query={'kind':kind,'path':'code.cpp','start_line':1,'end_line':2}
|
||||
items=[{'path':'code.cpp','line':1,'text':'important-'+str(number)+'x'*1000},
|
||||
{'path':'code.cpp','line':2,'text':'next line'}]
|
||||
if kind=='database.schema':
|
||||
query={'kind':kind,'table':'creature'}
|
||||
items=[{'table':'creature','columns':[{'COLUMN_NAME':'id','COLUMN_TYPE':'int'},
|
||||
{'COLUMN_NAME':'guid','COLUMN_TYPE':'int'}]}]
|
||||
return {'record':{'id':f'E{number:06d}','hypothesis_id':'H1','action_id':str(number)},
|
||||
'content':{'coverage':'schema_only' if kind=='database.schema' else 'selected_lines',
|
||||
'items':[{'query':query,'origin':{'commit':'a'*40},'result':{'coverage':'schema_only' if kind=='database.schema' else 'selected_lines',
|
||||
'truncated':False,'items':items}}]}}
|
||||
|
||||
|
||||
def context():
|
||||
h={'proposal':{'title':'Missing hook','mechanism':'Required hook is absent.',
|
||||
'expected_evidence':['Missing registration'],'falsifying_evidence':['Hook exists']},
|
||||
'confidence':'plausible','disposition':'active','questions':[], 'notes':[]}
|
||||
evidence={f'E{i:06d}':entry(i) for i in range(1,21)}
|
||||
c={'prompt_version':'investigation_project_v15','case':{'case':{'case_id':'c','package_id':'p','analysis_revision':1},
|
||||
'source_context':{'refs':[{'path':'original/code.cpp'}]},'database_context':{'refs':[]}},
|
||||
'interpretation':{'observed_behavior':[{'text':'Interaction fails','source_ids':['O0001']}],
|
||||
'confirmed_technical_facts':[{'text':'Captured quest giver differs from affected subject.','source_ids':['F0001']}]},
|
||||
'hypotheses':{'H1':h,'H2':copy.deepcopy(h)},'selected_hypothesis':'H1','evidence':evidence,
|
||||
'previous_result':evidence['E000020'],'working_brief':{'brief':brief()},
|
||||
'other_working_briefs':{'H2':{'brief':brief()}},
|
||||
'budget':{'accounts':{'H1':{'remaining':90,'status':'investigating','actions':{}},'H2':{'remaining':90,'status':'investigating','actions':{}}}},
|
||||
'budget_policy':{'default_action_cost':10,'action_costs':{}},'policy':asdict(InvestigationConfig()),
|
||||
'tool_schema':{'x-project-bindings':{'source':{'commit':'a'*40},'database':{'snapshot_id':'snap'},
|
||||
'max_rows':50,'max_lines':80}},'recalled_evidence':[]}
|
||||
return c
|
||||
|
||||
|
||||
def test_working_memory_replaces_payload_history_without_hiding_counterfindings():
|
||||
c=context();original=copy.deepcopy(c);v=model_view(c)
|
||||
assert c==original
|
||||
assert set(v['evidence'])=={'E000020'}
|
||||
assert v['working_brief']['findings'][0]['direction']=='against'
|
||||
assert v['other_working_briefs']['H2']['findings'][0]['evidence_refs']==['E000001']
|
||||
assert 'E000001' in {r['id'] for r in v['evidence_catalog']}
|
||||
assert next(r for r in v['evidence_catalog'] if r['id']=='E000001')['queries'][0]['origin']=={'commit':'a'*40}
|
||||
assert 'E000002' in v['archive_ids']
|
||||
assert len(json.dumps(v)) < len(json.dumps(c))/2
|
||||
|
||||
|
||||
def test_fresh_pending_recalled_and_schema_results_stay_available():
|
||||
c=context();c['recalled_evidence']=['E000002']
|
||||
c['budget']['accounts']['H1']['actions']['3']={'status':'recorded'}
|
||||
c['evidence']['E000004']=entry(4,'database.schema')
|
||||
v=model_view(c)
|
||||
assert {'E000002','E000003','E000020'}<=set(v['evidence'])
|
||||
assert 'E000004' in v['known_schemas']
|
||||
assert v['known_schemas']['E000004']['captures'][0]['coverage']=='schema_only'
|
||||
assert v['known_schemas']['E000004']['captures'][0]['tables'][0]['columns']==[['id','int'],['guid','int']]
|
||||
c['policy']['prompt_target_characters']=1
|
||||
c['evidence']['E000020']['content']['items'][0]['result']['items'][0]['text']='CRITICAL'*20000
|
||||
v=model_view(c)
|
||||
assert 'CRITICAL'*20000 in json.dumps(v)
|
||||
assert v['evidence_policy']['character_target']==1
|
||||
|
||||
|
||||
def test_memoryless_migration_bootstraps_all_evidence_once():
|
||||
c=context();c.pop('working_brief');v=model_view(c)
|
||||
assert set(v['evidence'])==set(c['evidence'])
|
||||
assert v['working_brief_status']=='bootstrap_complete_history'
|
||||
|
||||
|
||||
def test_row_table_preserves_literal_scalar_types_and_duplicates():
|
||||
rows=[{'id':1,'map':0,'null':None,'literal':{'encoding':'result_records_v1','rows':[]}},
|
||||
{'id':2,'map':0,'null':None,'literal':{'encoding':'result_records_v1','rows':[]}}]*10
|
||||
raw={'items':[{'query':{'kind':'database.rows'},'result':{'items':[{'table':'creature','row':r} for r in rows],
|
||||
'truncated':True,'next_offset':20,'coverage':'page'}}]}
|
||||
encoded=_content(raw)['items'][0]['result'];table=encoded['items']['records']
|
||||
restored=[{**table['common'],**dict(zip(table['fields'],r))} for r in table['rows']]
|
||||
assert restored==rows
|
||||
assert encoded['truncated'] is True and encoded['next_offset']==20
|
||||
|
||||
|
||||
def test_stable_cache_partition_survives_new_findings_and_hypothesis_switch():
|
||||
c=context();first=build_prompt(c);doc=json.loads(first['messages'][1]['content'])
|
||||
stable,live=split_document(doc,'investigation_project_v15')
|
||||
assert restore_document(stable,live)==doc
|
||||
c['selected_hypothesis']='H2';c['previous_result']=None;c['evidence']['E000021']=entry(21)
|
||||
updated=json.loads(build_prompt(c)['messages'][1]['content']);stable2,_=split_document(updated,'investigation_project_v15')
|
||||
assert stable2==stable
|
||||
|
||||
|
||||
def test_wire_contract_keeps_finish_reject_early_review_test_and_recall():
|
||||
c=context();wire=output_schema(c)
|
||||
for action in [{'kind':'finish','reason':'Done'},{'kind':'reject','reason':'Refuted'},
|
||||
{'kind':'defer','reason':'Await review'},
|
||||
{'kind':'request_diagnosis','reason':'Cause supported','countercheck_refs':['E000001']},
|
||||
{'kind':'recall','evidence_refs':['E000002']}]:
|
||||
assert Draft202012Validator(wire['properties']['next']).is_valid(action)
|
||||
assert 'working_brief' not in output_schema(dict(c,prompt_version='investigation_project_v12'))['properties']['update']['properties']
|
||||
|
||||
|
||||
def test_loose_wire_does_not_relax_controller_argument_or_brief_validation():
|
||||
from test_lean_investigation_decision import reply
|
||||
c=context();r=reply();r['next']={'kind':'tool','operation':'project.query','arguments':{'kind':'database.rows','table':'creature'}}
|
||||
assert Draft202012Validator(output_schema(c)).is_valid(r)
|
||||
with pytest.raises(InvestigationError,match='INVESTIGATION_OUTPUT'):validate_tool_shape(c,r)
|
||||
r['next']={'kind':'finish','reason':'Done'};r['update']['working_brief']['findings'][0]['text']='x'*301
|
||||
with pytest.raises(InvestigationError):validate_tool_shape(c,r)
|
||||
|
||||
|
||||
def test_packaged_source_alias_roundtrip_and_no_mutation():
|
||||
c=context();before=copy.deepcopy(c);sources,aliases=source_aliases(c)
|
||||
alias=next(iter(sources));assert alias.startswith('PS') and aliases[alias]=='original/code.cpp'
|
||||
assert sources[alias]=='code.cpp' and c==before
|
||||
|
||||
|
||||
def test_recalled_evidence_stays_pinned_without_extra_queries_and_portable_replay(tool_case,tmp_path):
|
||||
store=tool_case[0];service=service_for(tool_case);calls={};seen=[]
|
||||
def change(reply,c):
|
||||
hid=c['selected_hypothesis'];calls[hid]=calls.get(hid,0)+1;n=calls[hid]
|
||||
if hid=='H1' and n in (1,2):reply['next']={'kind':'tool','operation':'project.query','arguments':rows()}
|
||||
elif hid=='H1' and n==3:reply['next']={'kind':'recall','evidence_refs':['E000001']}
|
||||
elif hid=='H1' and n==4:
|
||||
assert 'E000001' in c['evidence'];seen.append(c)
|
||||
reply['next']={'kind':'finish','reason':'Scoped investigation complete'}
|
||||
adapter=LoopAdapter(change)
|
||||
loop=Investigator(store,gateway(adapter),router=InvestigationToolRouter(project_research=service))
|
||||
result=run(loop)
|
||||
assert result.status=='COMPLETED' and seen
|
||||
saved=state(result);assert saved['recalled_evidence']['H1']==['E000001']
|
||||
assert len(BudgetManager(store).snapshot(*CASE).state['accounts']['H1']['actions'])==2
|
||||
portable=CheckpointStore(Workspace(tmp_path/'portable'));portable.intake(result.package)
|
||||
resumed=run(Investigator(portable,gateway(adapter),router=InvestigationToolRouter(project_research=service)))
|
||||
assert resumed.status=='COMPLETED'
|
||||
assert PackageValidator().validate(result.package).valid
|
||||
|
||||
|
||||
def test_v15_small_prefix_attempts_cache_instead_of_failing_local_character_heuristic(monkeypatch):
|
||||
from test_llm_caching import config,scripted,CACHE,native
|
||||
from test_llm_gateway import request
|
||||
req=request();req['prompt_version']='investigation_project_v15'
|
||||
adapter=GeminiProvider();cfg=replace(config(),cache_min_prefix_chars=100000,cache_required=True)
|
||||
seen=scripted(adapter,monkeypatch,[CACHE,native()])
|
||||
result=asyncio.run(adapter.generate(cfg,req,max_response_bytes=10000))
|
||||
assert result.diagnostics['cache_status']=='created' and len(seen)==2
|
||||
|
||||
|
||||
def test_unseen_archive_ids_are_not_newly_citable_before_local_read():
|
||||
from test_lean_investigation_decision import reply
|
||||
c=context();r=reply();r['update']['working_brief']['findings'][0]['evidence_refs']=['E000002']
|
||||
with pytest.raises(InvestigationError,match='EVIDENCE_NOT_READ'):validate_tool_shape(c,r)
|
||||
c['recalled_evidence']=['E000002']
|
||||
validate_tool_shape(c,r)
|
||||
|
||||
|
||||
def test_other_pending_payload_has_inventory_and_is_full_on_its_own_turn():
|
||||
c=context();e=c['evidence']['E000003'];e['record']['hypothesis_id']='H2'
|
||||
c['budget']['accounts']['H2']['actions']['3']={'status':'recorded'}
|
||||
v=model_view(c)
|
||||
assert 'E000003' not in v['evidence'] and 'E000003' in v['evidence_policy']['pending_other_ids']
|
||||
assert any(r['id']=='E000003' for r in v['evidence_catalog'])
|
||||
c['selected_hypothesis']='H2';c['previous_result']=e
|
||||
assert 'E000003' in model_view(c)['evidence']
|
||||
|
||||
|
||||
@pytest.mark.parametrize('action',[{'kind':'finish'},{'kind':'tool','operation':'project.query','arguments':{'kind':'database.rows','table':'creature'}}])
|
||||
def test_invalid_compact_wire_has_no_tool_or_budget_side_effect(tool_case,action):
|
||||
store=tool_case[0];service=service_for(tool_case)
|
||||
adapter=LoopAdapter(lambda r,c:r.update(next=action))
|
||||
result=asyncio.run(Investigator(store,gateway(adapter),router=InvestigationToolRouter(project_research=service)).step(*CASE))
|
||||
assert result.status=='REJECTED' and result.code=='INVESTIGATION_OUTPUT'
|
||||
assert not service._captures
|
||||
assert all(not a['actions'] for a in BudgetManager(store).snapshot(*CASE).state['accounts'].values())
|
||||
|
||||
|
||||
def test_already_visible_local_read_is_rejected_before_external_work(tool_case):
|
||||
store=tool_case[0];service=service_for(tool_case)
|
||||
def change(r,c):
|
||||
if c['previous_result']:r['next']={'kind':'recall','evidence_refs':[c['previous_result']['evidence_id']]}
|
||||
else:r['next']={'kind':'tool','operation':'project.query','arguments':rows()}
|
||||
adapter=LoopAdapter(change)
|
||||
loop=Investigator(store,gateway(adapter),router=InvestigationToolRouter(project_research=service))
|
||||
for _ in range(4):result=asyncio.run(loop.step(*CASE))
|
||||
assert result.status=='REJECTED' and result.code=='INVESTIGATION_RECALL_VISIBLE'
|
||||
snapshot=BudgetManager(store).snapshot(*CASE).state
|
||||
assert len(snapshot['accounts']['H1']['actions'])==1
|
||||
|
||||
|
||||
def test_frozen_v14_active_request_remains_replayable(tool_case):
|
||||
store=tool_case[0];service=service_for(tool_case);adapter=LoopAdapter()
|
||||
loop=Investigator(store,gateway(adapter),router=InvestigationToolRouter(project_research=service))
|
||||
original=loop._context
|
||||
def old_context(*args):
|
||||
value=original(*args);value['prompt_version']='investigation_project_v14'
|
||||
value.pop('other_working_briefs',None);value.pop('recalled_evidence',None)
|
||||
return value
|
||||
loop._context=old_context
|
||||
execute=loop._execute_plan
|
||||
def stop_before_execution(state,budget):raise RuntimeError('simulated crash before execution')
|
||||
loop._execute_plan=stop_before_execution
|
||||
with pytest.raises(InvestigationError,match='INVESTIGATION_INPUT'):run(loop,steps=1)
|
||||
resumed=run(Investigator(store,gateway(adapter),router=InvestigationToolRouter(project_research=service)),steps=1)
|
||||
assert resumed.status=='YIELDED' and len(adapter.contexts)==1
|
||||
|
||||
|
||||
def test_v15_early_completion_reads_local_countercheck_then_independent_review(tool_case):
|
||||
from test_diagnosis_builder import FinalAdapter,build
|
||||
store=tool_case[0];service=service_for(tool_case);local_reads=[]
|
||||
def change(reply,c):
|
||||
early=c['early_review']['request']
|
||||
if early and early['status']=='preparing':
|
||||
reply['next']={'kind':'defer','reason':'Settle pending evidence.'};return
|
||||
own=[e for e,v in c['evidence'].items() if v['record']['hypothesis_id']=='H1']
|
||||
if c['selected_hypothesis']=='H1' and own:
|
||||
eid=own[0]
|
||||
reply['update'].update(confidence='strongly_supported',causal_review={
|
||||
'effect':'supports','support':[eid],'against':[],'reason':'Fixture scoped causal defect.'})
|
||||
other=[e for e,v in c['evidence'].items() if v['record']['hypothesis_id']=='H2']
|
||||
if not other:
|
||||
local_reads.append(1)
|
||||
ref=next(r['id'] for r in c['evidence_catalog'] if r['collector']=='H2')
|
||||
reply['next']={'kind':'recall','evidence_refs':[ref]}
|
||||
else:reply['next']={'kind':'request_diagnosis','reason':'Scoped cause and observed alternative check.','countercheck_refs':[other[0]]}
|
||||
else:reply['next']={'kind':'tool','operation':'project.query','arguments':rows()}
|
||||
adapter=LoopAdapter(change)
|
||||
done=run(Investigator(store,gateway(adapter),router=InvestigationToolRouter(project_research=service)),steps=12)
|
||||
assert done.status=='COMPLETED' and state(done)['early_stop']['status']=='requested'
|
||||
assert len(local_reads)==1
|
||||
before=BudgetManager(store).snapshot(*CASE).state
|
||||
assert all(a['remaining']>0 for a in before['accounts'].values())
|
||||
final=build(DiagnosisBuilder(store,gateway(FinalAdapter(True,lambda p,c:p.update(confidence='strongly_supported')))))
|
||||
assert final.status=='COMPLETED' and BudgetManager(store).snapshot(*CASE).state==before
|
||||
|
||||
|
||||
def test_v15_counterevidence_still_weakens_a_strong_model_claim():
|
||||
from test_lean_investigation_decision import reply
|
||||
from viano_bug_analysis.analysis.confidence_review import effective_confidence
|
||||
c=context();decision=normalize(c,reply())
|
||||
assert decision['update']['causal_review']['effect']=='contradicts'
|
||||
assert effective_confidence(decision['update'])=='weakened'
|
||||
|
||||
|
||||
def test_recall_turn_cannot_publish_unread_finding_before_reading_it():
|
||||
from test_lean_investigation_decision import reply
|
||||
c=context();r=reply()
|
||||
r['update']['working_brief']['findings'][0]['evidence_refs']=['E000002']
|
||||
r['next']={'kind':'recall','evidence_refs':['E000002']}
|
||||
with pytest.raises(InvestigationError) as caught:validate_tool_shape(c,r)
|
||||
assert caught.value.feedback['requirement']=='preserve_existing_brief_omit_new_unread_citations_and_use_recall_first'
|
||||
r['update']['working_brief']['findings'][0]['evidence_refs']=['E000001']
|
||||
validate_tool_shape(c,r)
|
||||
|
||||
|
||||
def test_lossless_table_never_collapses_boolean_integer_or_float_cells():
|
||||
from viano_bug_analysis.analysis.investigation_compact import _table
|
||||
values=[True,1,1.0,False,0,0.0,None,'1']*4
|
||||
rows=[{'value':v,'long_common':'unchanged metadata '*30} for v in values]
|
||||
table=_table(rows)
|
||||
assert isinstance(table,dict) and 'value' not in table['common']
|
||||
decoded=[{**table['common'],**dict(zip(table['fields'],r))} for r in table['rows']]
|
||||
assert [type(r['value']) for r in decoded]==[type(v) for v in values]
|
||||
assert decoded==rows
|
||||
@@ -126,6 +126,8 @@ def test_early_diagnosis_cannot_bypass_calibrated_counterevidence(tool_case):
|
||||
reply['next']={'kind':'request_diagnosis','reason':'Incorrect strong claim','countercheck_refs':[other]}
|
||||
else:reply['next']={'kind':'tool','operation':'project.query','arguments':rows()}
|
||||
loop=Investigator(store,gateway(LoopAdapter(change)),router=InvestigationToolRouter(project_research=service))
|
||||
original=loop._context
|
||||
loop._context=lambda *args:dict(original(*args),prompt_version='investigation_project_v14')
|
||||
run(loop,steps=3)
|
||||
before=BudgetManager(store).snapshot(*CASE).state
|
||||
result=asyncio.run(loop.step(*CASE))
|
||||
|
||||
@@ -45,10 +45,10 @@ class LoopAdapter:
|
||||
result["next"]={"kind":"test","executor":"human","question":"What occurs after interaction?","steps":["Interact once"],
|
||||
"prerequisites":["Use the specified build"],"requested_observations":["Record the observed state"],"environment":"build-A"}
|
||||
if self.change:self.change(result,context)
|
||||
if request['prompt_version'] in {'investigation_project_v12','investigation_project_v13','investigation_project_v14'}:
|
||||
if request['prompt_version'] in {'investigation_project_v12','investigation_project_v13','investigation_project_v14','investigation_project_v15'}:
|
||||
result['update'].setdefault('causal_review',{'effect':'neutral','support':[],'against':[],
|
||||
'reason':'This fixture gathers context without establishing a causal defect.'})
|
||||
if request['prompt_version'] in {'investigation_project_v13','investigation_project_v14'}:
|
||||
if request['prompt_version'] in {'investigation_project_v13','investigation_project_v14','investigation_project_v15'}:
|
||||
existing=context.get('working_brief')
|
||||
review=result['update']['causal_review']
|
||||
findings=[]
|
||||
@@ -62,7 +62,7 @@ class LoopAdapter:
|
||||
'uncertainties':['Causal defect not established.'],'next_question':'Check the selected mechanism.',
|
||||
'changes':[{'id':fid,'reason':'Fixture revises the finding.',
|
||||
'evidence_refs':result['update']['evidence_refs']} for fid,f in old.items() if new.get(fid)!=f]})
|
||||
if request['prompt_version']=='investigation_project_v14':
|
||||
if request['prompt_version'] in {'investigation_project_v14','investigation_project_v15'}:
|
||||
b=result['update']['working_brief']
|
||||
if b['format_version']==1:
|
||||
reasons={v['id']:v['reason'] for v in b.pop('changes')}
|
||||
|
||||
@@ -202,6 +202,8 @@ def test_v14_positive_early_review_reaches_independent_diagnosis_with_rest_budge
|
||||
reply['next']={'kind':'request_diagnosis','reason':'Scoped defect with countercheck.','countercheck_refs':[other]}
|
||||
else:reply['next']={'kind':'tool','operation':'project.query','arguments':rows()}
|
||||
loop=Investigator(tool_case[0],gateway(LoopAdapter(change)),router=InvestigationToolRouter(project_research=service))
|
||||
original=loop._context
|
||||
loop._context=lambda *args:dict(original(*args),prompt_version='investigation_project_v14')
|
||||
done=run(loop,steps=10)
|
||||
assert done.status=='COMPLETED' and state(done)['early_stop']['status']=='requested'
|
||||
budget=BudgetManager(tool_case[0]).snapshot(*CASE).state
|
||||
|
||||
@@ -204,7 +204,7 @@ def test_model_loop_uses_project_tools_and_compact_previous_result(tool_case, re
|
||||
if previous:
|
||||
assert context["evidence"][eid]["content"]["items"]
|
||||
assert "inputs" not in context["case"]
|
||||
assert request["prompt_version"] in ({"investigation_project_v9","investigation_project_v14"} if recall == "upgrade" else {"investigation_project_v9" if recall else "investigation_project_v14"})
|
||||
assert request["prompt_version"] in ({"investigation_project_v9","investigation_project_v15"} if recall == "upgrade" else {"investigation_project_v9" if recall else "investigation_project_v15"})
|
||||
reply={"assessment":{"semantic_score":50,"reason":"Scoped fact","evidence_refs":[eid]} if previous else None,
|
||||
"update":{"confidence":"plausible","evidence_refs":[eid] if previous else [],"resolve_questions":[],"add_questions":[],"note":"Query typed identity"},
|
||||
"next":{"kind":"finish","reason":"Check complete"} if previous else {"kind":"tool","operation":"project.query","arguments":rows()}}
|
||||
@@ -216,13 +216,13 @@ def test_model_loop_uses_project_tools_and_compact_previous_result(tool_case, re
|
||||
assert context['evidence'][recalled]['content']['items']
|
||||
reply['update']['evidence_refs'] = [recalled]
|
||||
reply['next'] = {'kind':'finish','reason':'Recalled exact evidence; uncertainty remains'}
|
||||
if request['prompt_version']=='investigation_project_v14':
|
||||
if request['prompt_version']=='investigation_project_v15':
|
||||
reply['update']['causal_review']={'effect':'neutral','support':[],'against':[],
|
||||
'reason':'Scoped observations are not independent evidence of a defect.'}
|
||||
if request['prompt_version']=='investigation_project_v14':
|
||||
if request['prompt_version']=='investigation_project_v15':
|
||||
reply['update']['working_brief']={'format_version':1,'findings':[],
|
||||
'uncertainties':['Scoped observations only.'],'next_question':'Check remaining uncertainty.','changes':[]}
|
||||
if request['prompt_version']=='investigation_project_v14':
|
||||
if request['prompt_version']=='investigation_project_v15':
|
||||
b=reply['update']['working_brief'];b['format_version']=2;b.pop('changes');b['retired']=[]
|
||||
for k in ('evidence_refs','causal_review','note'):reply['update'].pop(k,None)
|
||||
if reply['assessment']:reply['assessment'].pop('evidence_refs',None)
|
||||
|
||||
Reference in new issue
Block a user