fix(question-types): realign registry ids with the question_type table
The registry hardcoded numeric ids that drifted from the database `question_type` table: MATCHING and HOTSPOT were inserted mid-list (ids 9 and 11) but never seeded, shifting ORDERING/LINK/WORD_BANK/ STAR/VIDEO_RECORDING one or two ids past their real rows. Every id emitter inherited the wrong values — the exercise editor, the AI question generator, and the grading/scoring gate — so e.g. an ORDERING question was stored as id 10 (LINK in the DB), came back as a manual type, and never auto-graded. - Move MATCHING/HOTSPOT to the end (ids 14/15) and flag them `disabled`, restoring the append-only id convention and realigning ORDERING=9, LINK=10, WORD_BANK=11, STAR=12, VIDEO_RECORDING=13 with the DB. - Add a registry test asserting every enabled type's id matches the canonical `question_type` rows and disabled types stay past the live range, so ids can't silently drift again. - Constrain the agent tool schema to enabled, DB-backed ids so the model can't emit a disabled id with no row. - Drop disabled types from the teacher prompt's type list and guidance. - Centralize the dashboard question-type picker on the `disabled` flag. This also fixes video-recording detection, which compared against the stale id 15 instead of the real 13.
This commit is contained in:
@@ -5,11 +5,22 @@ import {
|
||||
LANDING_PAGE_METADATA_DESCRIPTION_SECTION_HINT,
|
||||
LANDING_PAGE_SECTION_HTML_AGENT_HINT
|
||||
} from '@cio/ai-assistant/tools';
|
||||
import { QUESTION_TYPE_REGISTRY } from '@cio/question-types';
|
||||
import { ENABLED_QUESTION_TYPE_REGISTRY } from '@cio/question-types';
|
||||
import { ZExerciseSectionAfterBehavior } from '@cio/utils/validation/exercise';
|
||||
import { ZCourseLandingPageUpdate, ZCourseLandingPageMetadataUpdateFields } from '@cio/utils/validation/course';
|
||||
|
||||
// courseId is NOT a parameter — it's injected from the authenticated request context.
|
||||
|
||||
// Only question types backed by a `question_type` DB row may be generated.
|
||||
// Disabled types (e.g. MATCHING/HOTSPOT) have no row and would fail the FK, so
|
||||
// the model is constrained to the enabled ids rather than the whole registry.
|
||||
const ENABLED_QUESTION_TYPE_IDS = ENABLED_QUESTION_TYPE_REGISTRY.map((type) => type.id);
|
||||
const zEnabledQuestionTypeId = z
|
||||
.number()
|
||||
.int()
|
||||
.refine((id) => ENABLED_QUESTION_TYPE_IDS.includes(id), {
|
||||
message: `questionTypeId must be one of: ${ENABLED_QUESTION_TYPE_IDS.join(', ')}`
|
||||
});
|
||||
// This prevents prompt injection from tricking the LLM into targeting another course.
|
||||
|
||||
export const emptyParam = z.object({});
|
||||
@@ -63,14 +74,9 @@ export const updateContentParam = z.object({
|
||||
|
||||
export const questionSchema = z.object({
|
||||
question: z.string().min(1),
|
||||
questionTypeId: z
|
||||
.number()
|
||||
.int()
|
||||
.min(1)
|
||||
.max(QUESTION_TYPE_REGISTRY.length)
|
||||
.describe(
|
||||
'Required. Use the numeric question type IDs from the teacher system prompt (Question Types). Omitting this field is invalid — set an explicit type on every question and vary types within each exercise.'
|
||||
),
|
||||
questionTypeId: zEnabledQuestionTypeId.describe(
|
||||
'Required. Use the numeric question type IDs from the teacher system prompt (Question Types). Omitting this field is invalid — set an explicit type on every question and vary types within each exercise.'
|
||||
),
|
||||
points: z.number().min(0).default(1),
|
||||
order: z.number().int().min(0),
|
||||
options: z.array(z.object({ label: z.string().min(1), isCorrect: z.boolean() }))
|
||||
@@ -193,7 +199,7 @@ export const updateQuestionPatchSchema = z
|
||||
.object({
|
||||
id: z.number().int(),
|
||||
question: z.string().min(1).optional(),
|
||||
questionTypeId: z.number().int().min(1).max(QUESTION_TYPE_REGISTRY.length).optional(),
|
||||
questionTypeId: zEnabledQuestionTypeId.optional(),
|
||||
points: z.number().min(0).optional(),
|
||||
order: z.number().int().min(0).optional(),
|
||||
exerciseSectionId: z
|
||||
|
||||
Reference in New Issue
Block a user