57 lines
2.8 KiB
Python
57 lines
2.8 KiB
Python
"""Cumulative model findings, distinct from observations and controller state."""
|
|
import copy
|
|
|
|
from .investigation_config import InvestigationError
|
|
|
|
VERSION = 'investigation_project_v13'
|
|
|
|
|
|
def validate_brief(update, previous, evidence):
|
|
brief = update['working_brief']
|
|
findings = brief['findings']
|
|
ids = [f['id'] for f in findings]
|
|
changes = brief['changes']
|
|
if len(ids) != len(set(ids)) or len({c['id'] for c in changes}) != len(changes):
|
|
raise InvestigationError('INVESTIGATION_BRIEF_ID')
|
|
for item in findings + changes:
|
|
if set(item['evidence_refs']) - set(evidence):
|
|
raise InvestigationError('INVESTIGATION_BRIEF_REFERENCE')
|
|
if any(set(f['evidence_refs']) - set(update['evidence_refs']) for f in findings):
|
|
raise InvestigationError('INVESTIGATION_BRIEF_REFERENCE')
|
|
old = {f['id']:f for f in previous['findings']} if previous else {}
|
|
current = {f['id']:f for f in findings}
|
|
changed = {fid for fid, finding in old.items() if current.get(fid) != finding}
|
|
if {c['id'] for c in changes} != changed:
|
|
raise InvestigationError('INVESTIGATION_BRIEF_CHANGE')
|
|
# A high confidence review must use the same cumulative evidence balance.
|
|
for direction, side in (('support','support'), ('against','against')):
|
|
refs = {ref for f in findings if f['direction'] == direction for ref in f['evidence_refs']}
|
|
if refs != set(update['causal_review'][side]):
|
|
raise InvestigationError('INVESTIGATION_BRIEF_BALANCE')
|
|
|
|
|
|
def model_view(context, *, aliases_out=None):
|
|
from .investigation_focus import full_history_view
|
|
view = full_history_view(context, aliases_out=aliases_out)
|
|
selected = view['selected_hypothesis']
|
|
saved = view.pop('working_brief', None)
|
|
view['working_brief'] = copy.deepcopy(saved['brief']) if saved else None
|
|
view['working_brief_status'] = 'model_assessment_not_independent_evidence' if saved else 'not_yet_established'
|
|
for hid, hypothesis in view['hypotheses'].items():
|
|
for key in ('working_brief_ref', 'working_brief_sha256', 'last_record_ref',
|
|
'invalid_responses', 'iterations'):
|
|
hypothesis.pop(key, None)
|
|
if hid != selected:
|
|
view['hypotheses'][hid] = {k:hypothesis[k] for k in ('proposal','confidence','disposition')}
|
|
elif saved:
|
|
# Legacy notes stay until the first cumulative brief is established.
|
|
hypothesis.pop('notes', None)
|
|
for entry in view['evidence'].values():
|
|
entry.pop('record_ref', None)
|
|
for key in ('format','format_version','id','case_id','package_id',
|
|
'analysis_revision','content_ref','content_sha256','novelty_score',
|
|
'action_id','origin'):
|
|
entry['record'].pop(key, None)
|
|
view['budget'] = {'selected_account': view['budget']['accounts'][selected]}
|
|
return view
|