Recover misplaced joint blocks and preserve unchanged entity citations
This commit is contained in:
1 parent
c3a4690a55
commit
3872735c0a
14 files changed
+265
-10
No files matched your search
@@ -292,3 +292,121 @@ def test_added_dependency_prevents_false_independence_after_patch(built_case):
|
||||
assert interpret(store,gw).status=='REJECTED'
|
||||
assert interpret(store,gw).status=='COMPLETED'
|
||||
assert hypotheses(store,gw).code=='HYPOTHESIS_DEPENDENCY_CHANGED'
|
||||
|
||||
|
||||
def nested_corpus():
|
||||
from pathlib import Path
|
||||
root=Path('tests/fixtures/llm_rejections/20261020/joint-nested-envelope')
|
||||
context=json.loads((root/'context.json').read_text(encoding='utf-8'))
|
||||
context['joint_generation']['recovery_version']=2
|
||||
return root,context
|
||||
|
||||
|
||||
def test_nested_joint_blocks_are_recovered_and_replay_without_extra_calls(built_case,tmp_path):
|
||||
def nested(d):d['hypotheses']['interpretation']=d.pop('interpretation')
|
||||
store=built_case[0];adapter=Adapter(nested);gw=gateway(adapter)
|
||||
assert interpret(store,gw).status=='COMPLETED'
|
||||
final=hypotheses(store,gw);assert final.status=='COMPLETED'
|
||||
from viano_bug_analysis.lifecycle import Workspace,CheckpointStore
|
||||
recipient=CheckpointStore(Workspace(tmp_path/'recipient'))
|
||||
recipient.intake(final.package)
|
||||
assert interpret(recipient,gw).reused
|
||||
assert hypotheses(recipient,gw).reused
|
||||
assert len(adapter.requests)==1
|
||||
|
||||
|
||||
def test_real_nested_reply_passes_full_interpretation_and_hypothesis_validation():
|
||||
import hashlib
|
||||
from viano_bug_analysis.analysis.joint_v2 import joint_document,complete_dependencies,validate_premises
|
||||
from viano_bug_analysis.analysis.contracts import validate_interpretation
|
||||
from viano_bug_analysis.analysis.hypothesis_contracts import build_context,validate_proposals
|
||||
from viano_bug_analysis.analysis.hypothesis_config import HypothesisLimits
|
||||
root,context=nested_corpus()
|
||||
for name,digest in json.loads((root/'hashes.json').read_text(encoding='utf-8')).items():
|
||||
assert hashlib.sha256((root/name).read_bytes()).hexdigest()==digest
|
||||
raw=json.loads((root/'case_plan_v2.json').read_text(encoding='utf-8'))['outcome']['document']
|
||||
before=copy.deepcopy(raw)
|
||||
doc=joint_document(raw,context)
|
||||
assert doc['interpretation']==raw['hypotheses']['interpretation']
|
||||
assert doc['hypotheses']['hypotheses']==raw['hypotheses']['hypotheses']
|
||||
validate_interpretation(doc['interpretation'],context)
|
||||
proposals=complete_dependencies(doc['hypotheses'],doc['interpretation'],context)
|
||||
validate_premises(proposals,doc['interpretation'],context)
|
||||
hc=build_context(context,{'interpretation':doc['interpretation']},'accepted.json',context['joint_generation']['policy'],[],HypothesisLimits())
|
||||
mapping={v['interpretation_pointer']:k for k,v in hc['interpretation_sources'].items()}
|
||||
for proposal in proposals['hypotheses']:
|
||||
proposal.pop('premises')
|
||||
proposal['interpretation_ids']=[mapping[p] for p in proposal.pop('interpretation_paths')]
|
||||
validate_proposals(proposals,hc)
|
||||
assert raw==before
|
||||
context['joint_generation']['recovery_version']=1
|
||||
assert joint_document(raw,context)==raw
|
||||
|
||||
|
||||
@pytest.mark.parametrize('extra',[None,{}, {'observed_behavior':[]}])
|
||||
def test_conflicting_nested_interpretations_are_never_selected(extra):
|
||||
from viano_bug_analysis.analysis.joint_v2 import joint_document
|
||||
from viano_bug_analysis.analysis.errors import InterpretationError
|
||||
_,context=nested_corpus()
|
||||
raw={'interpretation':extra,'hypotheses':{'interpretation':{},'hypotheses':[]}}
|
||||
with pytest.raises(InterpretationError,match='INTERPRETATION_SCHEMA'):joint_document(raw,context)
|
||||
|
||||
|
||||
def test_wrapper_repair_does_not_drop_unknown_siblings():
|
||||
from viano_bug_analysis.analysis.joint_v2 import joint_document
|
||||
_,context=nested_corpus()
|
||||
raw={'hypotheses':{'interpretation':{},'hypotheses':[],'surprise':'unrecognized'}}
|
||||
assert joint_document(raw,context)==raw
|
||||
|
||||
|
||||
def test_real_patch_preserves_only_unchanged_identity_citations():
|
||||
from viano_bug_analysis.analysis.joint_v2 import preserve_entity_citations
|
||||
from viano_bug_analysis.analysis.contracts import validate_interpretation
|
||||
from viano_bug_analysis.analysis.errors import InterpretationError
|
||||
root,context=nested_corpus()
|
||||
old=json.loads((root/'case_plan_interpretation_repair_v1.json').read_text(encoding='utf-8'))['outcome']['document']
|
||||
patch=json.loads((root/'case_plan_statement_repair_v2.json').read_text(encoding='utf-8'))['outcome']['document']
|
||||
before=copy.deepcopy(patch)
|
||||
fixed=copy.deepcopy(old)
|
||||
for p in patch['patches']:
|
||||
if p['path']=='/unknowns':fixed['unknowns']=p['replacement']
|
||||
else:fixed['relevant_entities'][4]=preserve_entity_citations(old['relevant_entities'][4],p['replacement'],context)
|
||||
validate_interpretation(fixed,context)
|
||||
assert 'F0029' in fixed['relevant_entities'][4]['source_ids']
|
||||
assert patch==before
|
||||
replacement=patch['patches'][0]['replacement']
|
||||
for field,value in [('reason','Different technical claim'),('entity_id','N0001')]:
|
||||
changed={**replacement,field:value}
|
||||
assert preserve_entity_citations(old['relevant_entities'][4],changed,context)==changed
|
||||
unknown=copy.deepcopy(replacement);unknown['source_ids'].append('F9999')
|
||||
fixed['relevant_entities'][4]=preserve_entity_citations(old['relevant_entities'][4],unknown,context)
|
||||
with pytest.raises(InterpretationError,match='INTERPRETATION_SOURCE_UNKNOWN'):validate_interpretation(fixed,context)
|
||||
|
||||
|
||||
def test_empty_candidate_repair_request_does_not_request_hypothesis_review(monkeypatch):
|
||||
from viano_bug_analysis.analysis import joint_v2
|
||||
from viano_bug_analysis.analysis.json_consolidation import restore
|
||||
root,context=nested_corpus()
|
||||
source=json.loads((root/'case_plan_interpretation_repair_v1.json').read_text(encoding='utf-8'))
|
||||
monkeypatch.setattr(joint_v2,'read_json',lambda *a,**kw:context)
|
||||
request=joint_v2.repair_request({'privacy':'configured'},None,('error',{'context_ref':'context'},source),{})
|
||||
wire=json.loads(request['messages'][1]['content']);body=restore(wire['repair'])
|
||||
assert body['hypotheses'] is None
|
||||
assert body['review_contract']=={'type':'array','maxItems':0}
|
||||
assert 'F0029' in body['preserve_identity_citations']['/relevant_entities/4']
|
||||
assert 'Return reviews=[]' in request['messages'][0]['content']
|
||||
|
||||
|
||||
def test_real_scoped_patch_projection_preserves_existing_provenance(monkeypatch):
|
||||
from viano_bug_analysis.analysis import joint_v2
|
||||
from viano_bug_analysis.analysis.contracts import validate_interpretation
|
||||
root,context=nested_corpus()
|
||||
source=json.loads((root/'case_plan_interpretation_repair_v1.json').read_text(encoding='utf-8'))
|
||||
call=json.loads((root/'case_plan_statement_repair_v2.json').read_text(encoding='utf-8'))
|
||||
original=source['outcome']['document']
|
||||
body={'issues':joint_v2.issues(original,context)}
|
||||
monkeypatch.setattr(joint_v2,'parent',lambda *a,**kw:(source,body))
|
||||
projected=joint_v2.project(None,call,context)
|
||||
validate_interpretation(projected,context)
|
||||
assert projected['relevant_entities'][4]['reason']==original['relevant_entities'][4]['reason']
|
||||
assert 'F0029' in projected['relevant_entities'][4]['source_ids']
|
||||
Reference in new issue
Block a user