import copy import json import pytest from test_diagnosis_reasoning import example from test_handoff_outcomes import minimal from viano_bug_analysis.analysis.diagnosis_builder import build_prompt, validate_evaluation from viano_bug_analysis.analysis.change_request_contracts import ( build_prompt as handoff_prompt, make_document, render_change_request, validate_request, ChangeRequestError, ) @pytest.mark.parametrize('early', [False, True]) def test_qualified_review_uses_same_contract_and_input(early): _, context = example() context['investigation']['early_stop']['status'] = 'requested' if early else 'none' context['case'] = {}; context['interpretation'] = {} kwargs = dict(modern=True, compact=True, consolidated=True, selected=True, lean=True, reduced=True) old = build_prompt(context, **kwargs) new = build_prompt(context, qualified=True, **kwargs) assert new['prompt_version'] == ('diagnosis_early_v8' if early else 'diagnosis_v8') assert new['output_schema'] == old['output_schema'] assert new['messages'][1] == old['messages'][1] system = new['messages'][0]['content'] assert 'Separate observed findings from causal inference' in system assert 'neither exhaustive absence proofs' in system assert 'Do not both declare a causal premise established' in system assert 'QuestAccept' not in system and 'BUG-000017' not in system def qualified_context(): payload, context = minimal() context.update(case_id='case', package_id='package', analysis_revision=1, diagnosis_ref='diagnosis.json', diagnosis_sha256='0'*64, interpretation={'observed_behavior':[], 'expected_behavior':[]}, policy={}, case={}, uncertainty_handoff_version=1) context['evidence']['E000001']['record']['content_sha256'] = '1'*64 diagnosis = context['diagnosis']['diagnosis'] diagnosis['remaining_uncertainty'] = ['The live deployment may differ from the snapshot.'] diagnosis['decision_basis'] = {'scope_limits':['Only the captured records were examined.']} return payload, context @pytest.mark.parametrize('status', ['ready', 'template', 'none']) def test_caveats_are_copied_without_relying_on_model_or_changing_assignment(status): payload, context = qualified_context() payload['status'] = status before = copy.deepcopy(context) doc = make_document(context, payload, 'context.json', 'call.json') assert doc['request']['status'] == status assert doc['assignment'] == ('none' if status == 'none' else 'assigned') assert not doc['human_dev_assigned'] assert doc['diagnostic_caveats'] == { 'remaining_uncertainty':context['diagnosis']['diagnosis']['remaining_uncertainty'], 'scope_limits':context['diagnosis']['diagnosis']['decision_basis']['scope_limits']} assert 'The live deployment may differ' in render_change_request(doc) doc['diagnostic_caveats']['remaining_uncertainty'].clear() assert context == before context.pop('uncertainty_handoff_version') assert 'diagnostic_caveats' not in make_document(context, payload, 'context.json', 'call.json') def test_handoff_prompt_changes_instructions_without_expanding_model_contract(): _, context = qualified_context() old = handoff_prompt(context, compact=True, version='change_request_v8') new = handoff_prompt(context, compact=True, version='change_request_v9') assert old['output_schema'] == new['output_schema'] assert old['messages'][1] == new['messages'][1] system = new['messages'][0]['content'] assert 'support or challenge' in system assert 'uncertainty alone does not require status=none' in system assert 'A successful build alone does not validate' in system def test_open_assumptions_and_negative_findings_still_allow_bounded_confirmation(): payload, context = example() payload['remaining_uncertainty'].append('A runtime activation path remains untested.') validate_evaluation(payload, context) assert payload['status'] == 'confirmed' def test_model_cannot_supply_controller_owned_caveats(): payload, context = qualified_context() payload['diagnostic_caveats'] = {'remaining_uncertainty':[], 'scope_limits':[]} with pytest.raises(ChangeRequestError, match='CHANGE_REQUEST_OUTPUT'): validate_request(payload, context)