Fix durable lean investigation repair feedback and context validation

This commit is contained in:
Nico committed 2026-10-18 16:25:06 +02:00
1 parent ca14271f20
commit dd666026d3
6 files changed
+89 -2

No files matched your search

+55
View File
@@ -183,3 +183,58 @@ def test_replay_after_tool_publication_does_not_repeat_model_or_budget(tool_case
assert result.status=='PROGRESSED' and len(adapter.calls)==1
assert len(state(result)['hypotheses']['H1']['lean_session']['turns'])==1
assert len(BudgetManager(tool_case[0]).snapshot(*CASE).state['accounts']['H1']['actions'])==1
def test_bad_consolidation_finding_id_repairs_without_corrupting_context(tool_case,tmp_path):
from viano_bug_analysis.case.contracts import validate
class BadIdOnce(LeanAdapter):
failed=False
async def generate(self,config,request,*,max_response_bytes):
response=await super().generate(config,request,max_response_bytes=max_response_bytes)
c=self.calls[-1]['input']
if self.calls[-1]['task']=='consolidate_investigation_session' and not self.failed:
self.failed=True
eid=next(iter(c['evidence']))
response.document['update']['working_brief']['findings']=[{'id':'F01','direction':'neutral',
'text':'Schema available.','scope':'Captured schema.','evidence_refs':[eid]}]
return response
adapter=BadIdOnce();router=InvestigationToolRouter(project_research=service_for(tool_case))
loop=Investigator(tool_case[0],gateway(adapter),InvestigationConfig(lean_loop=True),router=router)
first=run(loop,steps=1)
before=BudgetManager(tool_case[0]).snapshot(*CASE).state
rejected=asyncio.run(loop.step(*CASE))
assert rejected.status=='REJECTED'
assert BudgetManager(tool_case[0]).snapshot(*CASE).state==before
with PackageReader(rejected.package) as reader:
c=json.loads(reader.read_bytes(state(rejected)['active']['context_ref']))
validate(c,'investigation-context')
detail=c['previous_rejection_details']
assert 'validation_keyword' not in detail
assert 'B0001' in detail['requirement']
# The original released version persisted this extra keyword. Its
# immutable context must remain loadable without a package rewrite.
c['previous_rejection_details']={'validation_path':'/update/working_brief/findings/0/id',
'validation_fields':[],'validation_keyword':'pattern'}
validate(c,'investigation-context')
prompt=build_prompt(c)
assert 'B0001' in json.loads(prompt['messages'][1]['content'])['input']['previous_rejection_details']['requirement']
portable=CheckpointStore(Workspace(tmp_path/'portable'));portable.intake(rejected.package)
final=run(Investigator(portable,gateway(adapter),router=router))
assert final.status=='COMPLETED' and PackageValidator().validate(final.package).valid
def test_invalid_context_is_not_published(tool_case):
from viano_bug_analysis.case.errors import CaseBuildError
adapter=LeanAdapter();loop=Investigator(tool_case[0],gateway(adapter),InvestigationConfig(lean_loop=True),
router=InvestigationToolRouter(project_research=service_for(tool_case)))
result=run(loop,steps=1);saved=state(result)
# A new prompt context is validated before a checkpoint can reference it.
saved['active']={'hypothesis_id':'H1','iteration':2,'attempt':0,'phase':'prompt',
'context_ref':'analysis/investigation/0001/contexts/invalid.json','context_sha256':'0'*64,
'decision':None,'llm_ref':None,'test_request':None,'test_deadline':None,'retry_token':'initial'}
before=tool_case[0].latest(*CASE)
with pytest.raises(CaseBuildError) as caught:loop._save(saved,context={'unexpected':'invalid'})
assert caught.value.code=='INPUT_SCHEMA'
assert tool_case[0].latest(*CASE)==before