pdf-quiz-generator/backend/tests
Daniel 7cd2fa5cf4
Some checks failed
Tests / backend (push) Failing after 4s
Tests / frontend (push) Successful in 26s
Tests / e2e (push) Failing after 28s
feat: AI Mode gives the same answer twice, and a typo no longer empties the library
Measured first, by the ped-ai session, fifteen runs of five prompts with
the gateway cache bypassed. Retrieval was already deterministic:
identical shortlist and identical scores every time, and the citation
checker stripped none of the 45 markers written — invented citations are
not the problem here. Generation was the whole variance. At temperature
0.3 the same sources and the same prompt gave answers differing by
15-70% of their text; one differential swung between a 35-word uncited
paraphrase and a 180-word cited list.

So temperature 0 and a seed. Temperature 0 alone was not enough — three
runs still differed — and temperature 0 with a fixed seed came back
byte-identical. The seed is derived from the question, normalised for
case and spacing, so two people asking the same thing get the same
answer and a different question is not pinned to the same sample.

An empty reply is asked once more before it becomes a 502. One in
fifteen came back empty from a healthy model in 4.9 seconds — not a
refusal, not an error, just nothing.

A short query that finds almost nothing is retried against the nearest
article title. "kawasaki criteria" finds fourteen sources; "kawasaki
critera" found none — the lexical ranker cannot match a token that is in
no index, and the embedding of a misspelling is not near the embedding
of the word. Trigrams do not care: that typo scores 0.36 against
"Kawasaki disease" with the next article at 0.11, and the gap is what
makes it safe to act on. pg_trgm is created at startup beside vector,
with a migration for the record.

And an answer drawn from the library must cite it. Not a hallucination
guard — nothing was stripped in fifteen runs — but one answer used the
sources and cited none of them, which leaves the learner an assertion
and nowhere to check it.

Also, article drafts are weighted towards mechanism, in the wording the
ped-ai rewriter is using, so the two lanes read alike: why the body does
what it does, with features and management explained through it rather
than listed. Figure lines and cross-references survive a refine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
2026-09-13 16:24:48 +02:00
..
__init__.py Initial commit: PDF Quiz Generator app 2026-03-30 20:04:53 +00:00
api-contract.json feat: cards come from articles, and Nextcloud is gone 2026-09-13 16:03:04 +02:00
test_access.py fix: a role is not set here while the provider holds it 2026-09-13 14:04:16 +02:00
test_ai_mode.py feat: AI Mode gives the same answer twice, and a typo no longer empties the library 2026-09-13 16:24:48 +02:00
test_ai_mode_matching.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_ai_practice.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_api_contract.py feat: a versioned API, refresh tokens, and an end-to-end stack that found four bugs 2026-09-13 01:23:38 +02:00
test_article_ai.py feat: half the bedside, half the mechanism 2026-09-13 16:05:57 +02:00
test_article_notes.py feat: question folders, per-section notes, and two feedback paths 2026-09-12 18:37:43 +02:00
test_article_search_index.py feat: three answers, chosen by a number rather than by the model 2026-09-12 16:15:05 +02:00
test_articles_cards.py feat: an article follows a topic, rather than copying it once 2026-09-12 19:57:06 +02:00
test_articles_migration.py feat: linked topic articles and card associations 2026-09-07 15:16:48 +02:00
test_bank_cleanup.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_blueprint_plans.py feat: study plans built to the board's content outline 2026-09-11 21:40:17 +02:00
test_captcha.py feat: Cap replaces hCaptcha, self-hosted beside the app 2026-09-12 06:14:14 +02:00
test_category_grants.py fix: the answer side of a question needs an attempt, or the job of writing it 2026-09-13 00:13:43 +02:00
test_category_migration.py feat: retire the tags, and stop settings from hiding from the page that 2026-09-12 05:06:58 +02:00
test_collections.py refactor: remove per-question sharing 2026-09-12 08:42:51 +02:00
test_contact_privacy.py fix: the contact form's messages were readable by anyone 2026-09-12 22:37:28 +02:00
test_draft_questions.py fix: the other registration form, our own transcriber first, and a rail 2026-09-12 04:41:27 +02:00
test_exam_admin.py feat: exams are a group you can build, with the board's own blueprint 2026-09-11 20:27:48 +02:00
test_exam_blueprint.py feat: adaptive weighs the paper as well as the learner, and Session 2026-09-12 05:54:09 +02:00
test_exam_scoped_tags.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_exams.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_feedback.py feat: question folders, per-section notes, and two feedback paths 2026-09-12 18:37:43 +02:00
test_file_intake.py fix: an upload is what its bytes say, not what its name claims 2026-09-12 19:05:12 +02:00
test_global_search.py refactor: remove per-question sharing 2026-09-12 08:42:51 +02:00
test_hybrid_search.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_media_library.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_multi_category.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_option_explanations.py feat: key points smart links, difficulty tags, adaptive sessions, educator-only question management 2026-09-09 02:26:45 +02:00
test_prepared_session.py feat: a session prepared for you, and a model that can see when the one on the job cannot 2026-09-12 15:46:04 +02:00
test_question_detail_access.py fix: the figures route handed out the answer side to anybody signed in 2026-09-13 15:29:29 +02:00
test_question_figures.py fix: a schema promising an owner where the column now says NULL 2026-09-13 14:17:55 +02:00
test_question_folders.py feat: question folders, per-section notes, and two feedback paths 2026-09-12 18:37:43 +02:00
test_question_trash.py feat: questions are soft-deleted, and the trash holds them 2026-09-11 20:12:58 +02:00
test_question_versions.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_quiz_builder.py refactor: the app is a PWA, so the native wrapper goes 2026-09-13 00:26:35 +02:00
test_quiz_sessions.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_refresh_tokens.py feat: a versioned API, refresh tokens, and an end-to-end stack that found four bugs 2026-09-13 01:23:38 +02:00
test_related_privacy.py feat: the bank belongs to a role, not to a person 2026-09-13 13:26:25 +02:00
test_rerank.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_session_lifecycle.py refactor: remove per-question sharing 2026-09-12 08:42:51 +02:00
test_share_public.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_shared_category.py feat: ground AI drafts in the library and PubMed, and mend the card system 2026-09-13 02:44:42 +02:00
test_sso_hardening.py feat: no passwords here — sign-in belongs to the provider 2026-09-13 15:50:38 +02:00
test_sso_roles.py fix: a role is not set here while the provider holds it 2026-09-13 14:04:16 +02:00
test_study_plan_editing.py feat: study plans you can open, work through, and edit 2026-09-10 12:10:39 +02:00
test_study_plan_sessions.py feat: study-plan blocks as modules, sessions that know their block 2026-09-11 04:31:21 +02:00
test_study_tools.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_study_tools_migration.py fix: preserve saved quiz progress across resume failures 2026-09-07 03:34:55 +02:00
test_tag_hierarchy.py refactor: remove the LMS 2026-09-12 23:27:51 +02:00
test_thumbnails.py feat: thumbnails for uploaded images, at two widths and no others 2026-09-12 08:49:20 +02:00
test_tts_voices.py fix: a speech model is added with its voices, and Orpheus is sent where it works 2026-09-13 05:04:37 +02:00
test_vision_fallback.py fix: the answer side of a question needs an attempt, or the job of writing it 2026-09-13 00:13:43 +02:00