fix: a question slide's options are lettered once, and a bare-letter answer names its option
DeepSeek flash wrote 'A. Start IVIG' into option text the renderer already letters, so the slide read 'A A. Start IVIG'; and an answer of just 'A' sat alone on the answer card, sending the room back a slide to see what A was. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016fZGJNyDvERbMgS2Uc2msP
This commit is contained in:
parent
aac02ec0df
commit
381483dcf3
2 changed files with 32 additions and 2 deletions
|
|
@ -97,6 +97,20 @@ function text(value, max) {
|
||||||
.slice(0, max || 400).trim();
|
.slice(0, max || 400).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var OPTION_LETTER = /^\(?([A-Ha-h])[.):]\s+/;
|
||||||
|
|
||||||
|
function unletter(option) {
|
||||||
|
return option.replace(OPTION_LETTER, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function answerWithOption(answer, options) {
|
||||||
|
var letter = /^\(?([A-Ha-h])[.):]?$/.exec(answer.trim());
|
||||||
|
if (!letter) return answer;
|
||||||
|
var at = 'ABCDEFGH'.indexOf(letter[1].toUpperCase());
|
||||||
|
if (at < 0 || !options[at]) return letter[1].toUpperCase();
|
||||||
|
return letter[1].toUpperCase() + ' — ' + options[at];
|
||||||
|
}
|
||||||
|
|
||||||
function bullets(list) {
|
function bullets(list) {
|
||||||
if (!Array.isArray(list)) return [];
|
if (!Array.isArray(list)) return [];
|
||||||
return list.slice(0, 14).map(function (item) {
|
return list.slice(0, 14).map(function (item) {
|
||||||
|
|
@ -167,9 +181,13 @@ function normalise(raw, gaps) {
|
||||||
if (!out.text) return;
|
if (!out.text) return;
|
||||||
} else if (type === 'question') {
|
} else if (type === 'question') {
|
||||||
out.question = text(slide.question || slide.text, 400);
|
out.question = text(slide.question || slide.text, 400);
|
||||||
|
// The renderer letters the options itself, so a letter the model wrote
|
||||||
|
// into the text ("A. Start IVIG") would be drawn twice.
|
||||||
out.options = (Array.isArray(slide.options) ? slide.options : []).slice(0, 6)
|
out.options = (Array.isArray(slide.options) ? slide.options : []).slice(0, 6)
|
||||||
.map(function (o) { return text(typeof o === 'string' ? o : (o && o.text), 160); }).filter(Boolean);
|
.map(function (o) { return unletter(text(typeof o === 'string' ? o : (o && o.text), 160)); }).filter(Boolean);
|
||||||
out.answer = text(slide.answer, 300);
|
// An answer given as a bare letter is shown with the option it names: a
|
||||||
|
// card reading "A" alone made the room look back at the previous slide.
|
||||||
|
out.answer = answerWithOption(text(slide.answer, 300), out.options);
|
||||||
out.explanation = text(slide.explanation, 500);
|
out.explanation = text(slide.explanation, 500);
|
||||||
if (!out.question) return;
|
if (!out.question) return;
|
||||||
} else if (type === 'title') {
|
} else if (type === 'title') {
|
||||||
|
|
|
||||||
|
|
@ -68,3 +68,15 @@ test('the picker is told what a format is for, never the recipe itself', () => {
|
||||||
assert.deepEqual(Object.keys(entry).sort(), ['audience', 'description', 'id', 'length', 'name']);
|
assert.deepEqual(Object.keys(entry).sort(), ['audience', 'description', 'id', 'length', 'name']);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('a question slide never letters its options twice, and a bare-letter answer names its option', () => {
|
||||||
|
const deck = deckSchema.normalise({ slides: [{ type: 'question', heading: 'Case 1', question: 'Next step?',
|
||||||
|
options: ['A. Start IVIG plus aspirin', 'B) Antibiotics', '(C) Observe', 'Give NSAIDs'], answer: 'A', explanation: 'x' }] });
|
||||||
|
const q = deck.slides[0];
|
||||||
|
assert.deepEqual(q.options, ['Start IVIG plus aspirin', 'Antibiotics', 'Observe', 'Give NSAIDs']);
|
||||||
|
assert.equal(q.answer, 'A — Start IVIG plus aspirin');
|
||||||
|
const prose = deckSchema.normalise({ slides: [{ type: 'question', question: 'q', options: ['x', 'y'], answer: 'Start IVIG' }] });
|
||||||
|
assert.equal(prose.slides[0].answer, 'Start IVIG', 'a written-out answer is left alone');
|
||||||
|
const stray = deckSchema.normalise({ slides: [{ type: 'question', question: 'q', options: ['x'], answer: 'D.' }] });
|
||||||
|
assert.equal(stray.slides[0].answer, 'D', 'a letter with no such option is shown as the letter');
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue