84 lines
5.3 KiB
Python
84 lines
5.3 KiB
Python
"""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'
|