"""Regressions for request scope; no live model or expected production answer.""" import pytest from tools.answers.question_plan import build_question_plan, MeetingRequest from tools.answers.delivery_contract import mechanical_check, ContractError from tools.knowledge.sources import profile_units from tools.knowledge.academic import answer_academic from tools.knowledge.planned_answers import answer_facets CAT=[{'name':name,'kind':'Person','source_document':'pages/students/2020/'+key+'/README.md'} for name,key in [('Eva Nová','eva'),('Adam Nový','adam')]] def profile(person,content): p=next(p for p in CAT if p['name']==person) return profile_units({'title':person,'path':p['source_document'],'content':content},include_records=True) def test_independent_clauses_do_not_share_work_type_year_or_facets(): q='Na čom pracovala Eva Nová? Čo mal Adam Nový vytvoriť vo svojej diplomovej práci z roku 2021?' p=build_question_plan(q,CAT) assert not p.clarification and p.spec.intent=='facets' assert p.spec.matches_work('Eva Nová','Bakalárska práca 2026','bachelor_thesis',2026) assert not p.spec.matches_work('Adam Nový','Bakalárska práca 2021','bachelor_thesis',2021) assert p.spec.matches_work('Adam Nový','Diplomová práca 2021','diploma_thesis',2021) rows=profile('Eva Nová','# Bakalárska práca 2026\nStav:\n- Implementovaný systém pre otázky.')+profile('Adam Nový','# Diplomová práca 2021\nZadanie:\n- Vytvorte databázu dokumentov.') result=answer_facets(p,{'version':'c','index_version':{'version':'v'},'units':rows},rows,engine='rag',limit=5) assert {r['person'] for r in result['evidence']}=={'Eva Nová','Adam Nový'} assert 'databázu dokumentov' in result['answer'] and 'Implementovaný systém' in result['answer'] @pytest.mark.parametrize('word,count',[('dvoma',2),('troch',3),('4',4)]) def test_latest_meeting_count_is_a_real_constraint(word,count): p=build_question_plan(f'Porovnaj pokrok Evy Novej medzi poslednými {word} stretnutiami.',CAT) assert p.spec.meeting.count==count and p.spec.answer_mode=='comparison' @pytest.mark.parametrize('engine',['rag','graphrag']) def test_meeting_comparison_keeps_both_records_and_rejects_third(engine): rows=profile('Eva Nová','# Diplomový projekt 2026\nStretnutie 1.1.2026\nStav:\n- Starý model funguje.\nStretnutie 2.2.2026\nÚlohy:\n- Vytvorte agenta.\nStretnutie 3.3.2026\nStav:\n- Vytvorený agent.\nÚlohy:\n- Vyhodnoťte systém.') idx={'version':'c','index_version':{'version':'v'},'academic_schema':1,'units':rows} p=build_question_plan('Ako pokročila Eva Nová medzi poslednými dvoma stretnutiami a vyhodnotila systém?',CAT) result=answer_academic(p.spec.question,idx,engine=engine,mode='meeting',plan=p) dates={r.get('date') for r in result['evidence']} assert dates=={'2026-02-02','2026-03-03'} assert 'Vytvorte agenta' in result['answer'] and 'Vyhodnoťte systém' in result['answer'] assert 'nie je v tomto zápise doložený' in result['answer'] mechanical_check(p.spec,result,idx) result['evidence'].append(next(r for r in rows if r.get('record_date')=='2026-01-01' and r['kind']!='meeting')) with pytest.raises(ContractError,match='wrong_work_or_meeting'):mechanical_check(p.spec,result,idx) def test_warning_against_guessing_is_not_a_request_for_prediction(): p=build_question_plan('Čo vieme o ukončení práce alebo štúdia Evy Novej? Rozlíš záznam od toho, čo by sme iba odhadovali podľa roku práce.',CAT) assert p.spec.intent=='completion' and not p.clarification other=build_question_plan('Odhadni, kedy Eva Nová dokončí prácu.',CAT) assert other.clarification def test_unnamed_other_authorship_does_not_become_profile_owner(): from tools.knowledge.evidence import claim_eligible rows=profile('Eva Nová','# Diplomová práca 2027\nStav:\n- Hotová prvá verzia chatbota. Urobil to niekto iný. Chatbot vie odpovedať.') assert not any(claim_eligible(r) for r in rows if 'niekto iný' in r['text']) @pytest.mark.parametrize('second',[ 'Čo mala Eva Nová vytvoriť v diplomovke?', 'Čo mala Eva Nová vytvoriť v diplomovom projekte 2 z roku 2026?', ]) def test_informal_type_and_project_number_stay_in_their_own_clause(second): p=build_question_plan('Na čom pracoval Adam Nový? '+second,CAT) assert not p.clarification assert p.spec.matches_work('Adam Nový','Bakalárska práca 2020','bachelor_thesis',2020) adam=next(w for w in p.spec.works if w.person=='Adam Nový') assert not adam.work_type and not adam.numbers and not adam.years def test_validated_work_interval_reaches_metadata_graph_parameters(): from tools.graphrag import graph_search as gs from tools.graphrag.tests.test_graph_search import FakeSession q='Aké práce má Eva Nová od roku 2019 do roku 2021?' plan=build_question_plan(q,CAT) session=FakeSession({gs.CATALOG_QUERY:[{**CAT[0],'element_id':'p1'}]}) result=gs.search_graph_with_session(session,q,question_plan=plan.spec) assert result.get('reason')!='unsupported_constraint' calls=[params for query,params in session.calls if query in {gs.THESIS_FACTS_QUERY,gs.WORK_FACTS_QUERY}] assert calls and all(p['years']==[2019,2020,2021] for p in calls) # Without a valid shared plan, raw legacy search still refuses the operator. assert gs.search_graph_with_session(session,q)['reason']=='unsupported_constraint'