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:
Rotimi Best
2026-06-29 01:07:02 +01:00
parent eb4cd22ac5
commit 55abf982ed
6 changed files with 131 additions and 72 deletions
@@ -23,18 +23,13 @@ const QUESTION_TYPE_LABEL_KEYS: Partial<Record<QuestionTypeKey, string>> = {
'course.navItem.lessons.exercises.all_exercises.edit_mode.question_types.video_recording'
};
// Temp hidden: MATCHING, HOTSPOT
const HIDDEN_QUESTION_TYPE_KEYS = new Set<QuestionTypeKey>([QUESTION_TYPE_KEY.MATCHING, QUESTION_TYPE_KEY.HOTSPOT]);
export const QUESTION_TYPES = QUESTION_TYPE_REGISTRY.filter((qt) => !HIDDEN_QUESTION_TYPE_KEYS.has(qt.key)).map(
(questionType) => ({
id: questionType.id,
key: questionType.key,
label: questionType.label,
labelKey: QUESTION_TYPE_LABEL_KEYS[questionType.key],
autoGradable: questionType.autoGradable
})
);
export const QUESTION_TYPES = QUESTION_TYPE_REGISTRY.filter((qt) => !qt.disabled).map((questionType) => ({
id: questionType.id,
key: questionType.key,
label: questionType.label,
labelKey: QUESTION_TYPE_LABEL_KEYS[questionType.key],
autoGradable: questionType.autoGradable
}));
export const DEFAULT_QUESTION_TYPE = QUESTION_TYPES.find(
(questionType) => questionType.key === QUESTION_TYPE_KEY.RADIO