175 lines
9.6 KiB
Python
175 lines
9.6 KiB
Python
"""Academic joins: roles, record dates and outcomes must belong to one work."""
|
|
import pytest
|
|
|
|
from tools.knowledge.sources import profile_units,advisor_name
|
|
from tools.knowledge.academic import answer_academic,completion_event,academic_intent
|
|
from tools.knowledge.query import answer_from_index,intent
|
|
|
|
|
|
def index(*profiles):
|
|
rows=[]
|
|
for number,(name,text) in enumerate(profiles):
|
|
rows.extend(profile_units({'title':name,'path':f'pages/students/2022/student_{number}/README.md',
|
|
'content':text},include_records=True))
|
|
return {'version':'fixture','index_version':{'version':'fixture'},'academic_schema':1,'units':rows}
|
|
|
|
|
|
@pytest.fixture(params=['rag','graphrag'])
|
|
def engine(request):return request.param
|
|
|
|
|
|
def test_supervisor_and_consultant_are_distinct_and_missing_role_is_not_invented(engine):
|
|
data=index(('Alena Nová','# Bakalárska práca 2026\nkonzultant Matúš Čavojský\n'
|
|
'Predbežný názov:\nOrchestrácia modelov pomocou MCP\n'))
|
|
r=answer_from_index('Kto je vedúci a konzultant bakalárskej práce Aleny Novej?',data,engine=engine)
|
|
assert r['status']=='ok'
|
|
assert 'Konzultant: Matúš Čavojský' in r['answer']
|
|
assert 'Vedúci práce: v dostupných podkladoch nie je uvedený' in r['answer']
|
|
assert 'Orchestrácia modelov' in r['answer'] and r['source_urls']
|
|
|
|
|
|
def test_profile_level_supervisor_is_not_assigned_to_every_work(engine):
|
|
data=index(('Alena Nová','Vedúci: Daniel Hládek\n# Diplomová práca 2024\nNázov: Overené grafy\n'))
|
|
r=answer_academic('Kto je vedúci diplomovej práce Aleny Novej z roku 2024?',data,engine=engine)
|
|
assert 'Vedúci práce: Daniel' not in r['answer']
|
|
assert 'nie je uvedený' in r['answer']
|
|
|
|
|
|
def test_latest_meeting_is_selected_by_date_even_when_profile_order_is_reversed(engine):
|
|
data=index(('Alena Nová','# Diplomová práca 2026\nStretnutie 5.5.2026\nStav:\n'
|
|
'- Implementovaný systém RAG.\nÚlohy:\n- Vyhodnoťte model.\n'
|
|
'Stretnutie 1.2.2026\nStav:\n- Vytvorený prvý návrh systému.\n'))
|
|
r=answer_academic('Kedy mala Alena Nová posledné stretnutie a o čom bolo?',data,engine=engine)
|
|
assert r['status']=='ok' and '2026-05-05' in r['answer']
|
|
assert 'Implementovaný' in r['answer'] and 'Plán:' in r['answer']
|
|
assert 'prvý návrh' not in r['answer']
|
|
assert all(e.get('date')=='2026-05-05' for e in r['evidence'])
|
|
|
|
|
|
def test_empty_latest_meeting_does_not_borrow_older_meeting_contents(engine):
|
|
data=index(('Alena Nová','# Diplomová práca 2026\nStretnutie 1.2.2026\n'
|
|
'Stav:\n- Implementovaný systém RAG.\nStretnutie 5.5.2026\n'))
|
|
r=answer_academic('Kedy mala Alena Nová posledné stretnutie?',data,engine=engine)
|
|
assert '2026-05-05' in r['answer'] and 'Obsah tohto stretnutia nie je' in r['answer']
|
|
assert 'Implementovaný' not in r['answer']
|
|
|
|
|
|
def test_partial_date_does_not_inherit_year_or_establish_absolute_latest_meeting(engine):
|
|
data=index(('Alena Nová','# Diplomová práca 2027\nStretnutie 5.5.2026\nStav:\n'
|
|
'- Implementovaný systém RAG.\nStretnutie 7.11.\nStav:\n- Urobená nová verzia systému.\n'))
|
|
r=answer_academic('Kedy mala Alena Nová posledné stretnutie?',data,engine=engine)
|
|
assert '2026-05-05' in r['answer'] and 'či sú novšie' in r['answer']
|
|
assert '2027-11-07' not in r['answer'] and '2026-11-07' not in r['answer']
|
|
|
|
|
|
def test_premature_work_note_does_not_prove_failed_defense_or_ended_studies(engine):
|
|
data=index(('Samuel Vasiľ','# Bakalárska práca 2026\nUkončil predčasne\n'))
|
|
r=answer_academic('Ukončil Samuel Vasiľ štúdium úspešne alebo predčasne?',data,engine=engine)
|
|
assert 'Ukončil predčasne' in r['answer']
|
|
assert r['reason']=='completion_not_documented'
|
|
assert 'rozsahom' in r['answer'] and 'Nemožno z toho usúdiť, že stále prebieha' in r['answer']
|
|
|
|
|
|
@pytest.mark.parametrize('sentence',[
|
|
'Plán ukončiť štúdium v roku 2024.',
|
|
'Mal by úspešne ukončiť diplomovú prácu v roku 2024.',
|
|
'Dokončil text práce v roku 2024.',
|
|
'Dokončil prácu na experimente v roku 2024.',
|
|
'Implementovaný systém RAG.',
|
|
'Nie je potvrdené, že úspešne obhájil diplomovú prácu.',
|
|
'Kolega úspešne obhájil diplomovú prácu v roku 2024.',
|
|
'Úspešne obhájil diplomovú prácu, ale neukončil štúdium.',
|
|
])
|
|
def test_subtasks_plans_negations_and_other_people_do_not_prove_graduation(sentence):
|
|
row={'text':sentence,'phase':'progress','work_type':'diplomova','work_year':2024}
|
|
assert completion_event(row) is None
|
|
|
|
|
|
def test_work_heading_year_is_not_a_completion_year(engine):
|
|
data=index(('Alena Nová','# Diplomová práca 2024\nVedúci: Daniel Hládek\n'
|
|
'Stretnutie 1.6.2024\nStav:\n- Úspešne obhájila diplomovú prácu.\n'))
|
|
r=answer_academic('Ktorí študenti v roku 2024 úspešne ukončili práce pod vedením Daniela Hladeka?',data,engine=engine)
|
|
assert r['status']=='no_answer' and r['reason']=='academic_conditions_not_documented'
|
|
|
|
|
|
def test_completion_supervisor_and_year_join_to_same_person_and_work(engine):
|
|
data=index(
|
|
('Alena Nová','# Diplomová práca 2024\nVedúci: Daniel Hládek\nNázov: Presné grafy\n'
|
|
'Stav:\n- Úspešne obhájila diplomovú prácu v roku 2024.\n'),
|
|
('Boris Starý','# Diplomová práca 2024\nVedúci: Ján Staš\nStav:\n'
|
|
'- Úspešne obhájil diplomovú prácu v roku 2024.\n'
|
|
'# Bakalárska práca 2022\nVedúci: Daniel Hládek\n'),
|
|
('Cyril Malý','# Diplomová práca 2024\nVedúci: Daniel Hládek\n'
|
|
'Stav:\n- Úspešne obhájil diplomovú prácu v roku 2025.\n'))
|
|
r=answer_academic('Ktorí študenti v roku 2024 úspešne ukončili práce pod vedením Daniela Hladeka?',data,engine=engine)
|
|
assert r['status']=='ok' and 'Alena Nová' in r['answer'] and 'Presné grafy' in r['answer']
|
|
assert 'Boris Starý' not in r['answer'] and 'Cyril Malý' not in r['answer']
|
|
assert {e['person'] for e in r['evidence']}=={'Alena Nová'}
|
|
assert {e['work_label'] for e in r['evidence']}=={'Diplomová práca 2024'}
|
|
|
|
|
|
def test_submission_is_not_summarized_as_success(engine):
|
|
data=index(('Alena Nová','# Diplomová práca 2024\nVedúci: Daniel Hládek\n'
|
|
'Stav:\n- Odovzdala diplomovú prácu v roku 2024.\n'))
|
|
r=answer_academic('Ktorí študenti v roku 2024 úspešne ukončili práce pod vedením Daniela Hladeka?',data,engine=engine)
|
|
assert r['status']=='no_answer'
|
|
|
|
|
|
def test_actual_conflicting_outcomes_are_reported_instead_of_cherry_picking_success(engine):
|
|
data=index(('Alena Nová','# Diplomová práca 2024\nVedúci: Daniel Hládek\nStav:\n'
|
|
'- Úspešne obhájila diplomovú prácu v roku 2024.\n'
|
|
'- Neobhájila diplomovú prácu v roku 2024.\n'))
|
|
r=answer_academic('Ktorí študenti v roku 2024 úspešne ukončili práce pod vedením Daniela Hladeka?',data,engine=engine)
|
|
assert r['status']=='no_answer' and r['reason']=='conflicting_completion_evidence'
|
|
assert 'rozporné záznamy' in r['answer']
|
|
|
|
|
|
def test_exact_completion_date_needs_an_explicit_event_date_not_only_event_year(engine):
|
|
data=index(('Alena Nová','# Diplomová práca 2024\nStav:\n'
|
|
'- Úspešne obhájila diplomovú prácu v roku 2024.\n'))
|
|
r=answer_academic('Obhájila Alena Nová diplomovú prácu 5.6.2024?',data,engine=engine)
|
|
assert r['status']=='no_answer'
|
|
data=index(('Alena Nová','# Diplomová práca 2024\nStav:\n'
|
|
'- Úspešne obhájila diplomovú prácu dňa 5.6.2024.\n'))
|
|
r=answer_academic('Obhájila Alena Nová diplomovú prácu 5.6.2024?',data,engine=engine)
|
|
assert r['status']=='ok' and '5.6.2024' in r['answer']
|
|
|
|
|
|
def test_limit_is_reported_without_claiming_an_exhaustive_list(engine):
|
|
data=index(*[(name,'# Diplomová práca 2024\nVedúci: Daniel Hládek\n'
|
|
'Stav:\n- Úspešne obhájil diplomovú prácu v roku 2024.\n')
|
|
for name in ['Alena Nová','Boris Starý']])
|
|
r=answer_academic('Ktorí študenti v roku 2024 úspešne ukončili práce pod vedením Daniela Hladeka?',data,engine=engine,limit=1)
|
|
assert r['truncated'] and 'obmedzený výber' in r['answer']
|
|
assert len({e['person'] for e in r['evidence']})==1
|
|
|
|
|
|
def test_old_checkpoint_does_not_silently_answer_new_intents(engine):
|
|
data=index(('Alena Nová','# Diplomová práca 2024\nVedúci: Daniel Hládek\n'))
|
|
data.pop('academic_schema')
|
|
r=answer_academic('Kto je vedúci práce Aleny Novej?',data,engine=engine)
|
|
assert r['status']=='error' and r['reason']=='content_index_unavailable'
|
|
|
|
|
|
@pytest.mark.parametrize('question,mode',[
|
|
('Kto je vedúci práce Jána Holpa?','advisors'),
|
|
('Kto vedie diplomovú prácu Jána Holpa?','advisors'),
|
|
('Kedy mal Ján Holp naposledy stretnutie?','meeting'),
|
|
('Ukončil Samuel Vasiľ štúdium úspešne?','completion'),
|
|
])
|
|
def test_academic_intents_use_the_shared_backend(question,mode):
|
|
assert intent(question)==academic_intent(question)==mode
|
|
|
|
|
|
def test_completed_subtasks_are_not_routed_to_degree_completion():
|
|
assert academic_intent('Aké experimenty dokončil Ján Holp?') is None
|
|
assert academic_intent('Ktoré úlohy dokončil Ján Holp?') is None
|
|
|
|
|
|
def test_colloquial_thesis_name_keeps_the_work_type_instead_of_listing_all_works(engine):
|
|
data=index(('Ján Holp','# Diplomová práca 2021\nVedúci: Daniel Hládek\n'
|
|
'# Bakalárska práca 2019\nVedúci: Ján Staš\n'))
|
|
r=answer_academic('Kto vedie diplomovku Jána Holpa?',data,engine=engine)
|
|
assert r['status']=='ok' and 'Vedúci práce: Daniel Hládek' in r['answer']
|
|
assert 'Bakalárska práca' not in r['answer'] and 'Ján Staš' not in r['answer']
|