feat: phase 4 of AI pipeline hardening — quiz & content quality
- 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:
@@ -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 (1–2 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 = {
|
||||
|
||||
Reference in New Issue
Block a user