feat: phase 4 of AI pipeline hardening — quiz & content quality
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 31s
On Pull Request to Main / publish (pull_request) Successful in 1m1s
On Pull Request to Main / deploy-dev (pull_request) Successful in 1m31s

- src/lib/random.js: Fisher–Yates shuffle/sample/pickInt; replace every
  biased .sort(() => 0.5 - Math.random()) site in testService.
- testService: debias correctIndex via prompt + runtime re-roll (up to 2x
  when one position holds >50%); quality gate rejecting <4 distinct
  options, banned filler ("all of the above" etc) and explanations
  shorter than 20 chars; dedup new questions against the existing bank
  via normalised question text.
- Quiz schema/tool/prompt require difficulty ('easy'|'medium'|'hard');
  db.getQuizBank defaults legacy records to 'medium' on read.
- learningService.generateCustomTopic: kebab-case slug ID from the
  polished label with collision suffixes; default learning_relevance
  'standard' when the model omits it.
- Tests for random helpers, dedup/quality-gate behaviour and the
  extended quiz schema.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
RaymondVerhoef
2026-05-20 19:22:10 +02:00
parent c82e4fc3a1
commit 66e0c275da
9 changed files with 407 additions and 74 deletions

View File

@@ -205,6 +205,8 @@ export const EMIT_CUSTOM_TOPIC_TOOL = {
},
};
const QUIZ_DIFFICULTIES = ['easy', 'medium', 'hard'];
const quizQuestionSchema = {
type: 'object',
properties: {
@@ -214,8 +216,9 @@ const quizQuestionSchema = {
options: { type: 'array', items: { type: 'string' }, minItems: 4, maxItems: 4 },
correctIndex: { type: 'integer', minimum: 0, maximum: 3 },
explanation: { type: 'string', description: 'Why the correct answer is correct (12 sentences).' },
difficulty: { type: 'string', enum: QUIZ_DIFFICULTIES, description: 'Per-question difficulty tag.' },
},
required: ['id', 'question', 'topicLabel', 'options', 'correctIndex', 'explanation'],
required: ['id', 'question', 'topicLabel', 'options', 'correctIndex', 'explanation', 'difficulty'],
};
export const EMIT_QUIZ_QUESTIONS_TOOL = {