fix: deduplicate distractors against each other, guard thin distractor pool
This commit is contained in:
parent
a02f3b139d
commit
a02d3b3335
4 changed files with 68 additions and 370 deletions
|
|
@ -42,4 +42,21 @@ describe("InMemoryGameSessionStore", () => {
|
|||
const result = await store.get("session-1");
|
||||
expect(result).not.toBeNull();
|
||||
});
|
||||
|
||||
it("update persists modified session data", async () => {
|
||||
const data = {
|
||||
answers: new Map([
|
||||
["q1", 2],
|
||||
["q2", 1],
|
||||
]),
|
||||
userId: "user-1",
|
||||
};
|
||||
await store.create("session-1", data, 60_000);
|
||||
|
||||
const updated = { answers: new Map([["q2", 1]]), userId: "user-1" };
|
||||
await store.update("session-1", updated);
|
||||
|
||||
const result = await store.get("session-1");
|
||||
expect(result).toEqual(updated);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -32,7 +32,14 @@ const fakeTerms = [
|
|||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockGetGameTerms.mockResolvedValue(fakeTerms);
|
||||
mockGetDistractors.mockResolvedValue(["wrong1", "wrong2", "wrong3"]);
|
||||
mockGetDistractors.mockResolvedValue([
|
||||
"wrong1",
|
||||
"wrong2",
|
||||
"wrong3",
|
||||
"wrong4",
|
||||
"wrong5",
|
||||
"wrong6",
|
||||
]);
|
||||
});
|
||||
|
||||
describe("createGameSession", () => {
|
||||
|
|
@ -151,6 +158,39 @@ describe("createGameSession", () => {
|
|||
createGameSession(validRequest, store, "user-1"),
|
||||
).rejects.toThrow("db timeout");
|
||||
});
|
||||
|
||||
it("throws when fewer than 3 unique distractors remain after deduplication", async () => {
|
||||
mockGetDistractors.mockResolvedValueOnce([
|
||||
"cane",
|
||||
"cane",
|
||||
"cane",
|
||||
"cane",
|
||||
"cane",
|
||||
"cane",
|
||||
]);
|
||||
|
||||
await expect(
|
||||
createGameSession(validRequest, store, "user-1"),
|
||||
).rejects.toThrow("Not enough unique distractors");
|
||||
});
|
||||
|
||||
it("duplicate distractors are deduplicated against each other", async () => {
|
||||
mockGetDistractors.mockResolvedValueOnce([
|
||||
"wrong1",
|
||||
"wrong1",
|
||||
"wrong1",
|
||||
"wrong2",
|
||||
"wrong3",
|
||||
"wrong4",
|
||||
]);
|
||||
|
||||
const session = await createGameSession(validRequest, store, "user-1");
|
||||
const question = session.questions[0]!;
|
||||
const optionTexts = question.options.map((o) => o.text);
|
||||
|
||||
expect(new Set(optionTexts).size).toBe(4);
|
||||
expect(question.options).toHaveLength(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe("evaluateAnswer", () => {
|
||||
|
|
|
|||
|
|
@ -42,9 +42,16 @@ export const createGameSession = async (
|
|||
6,
|
||||
);
|
||||
|
||||
const uniqueDistractors = distractorTexts.filter(
|
||||
(t) => t !== term.targetText,
|
||||
);
|
||||
const uniqueDistractors = [
|
||||
...new Set(distractorTexts.filter((t) => t !== term.targetText)),
|
||||
];
|
||||
|
||||
if (uniqueDistractors.length < 3) {
|
||||
throw new Error(
|
||||
`Not enough unique distractors for term: ${term.targetText}`,
|
||||
);
|
||||
}
|
||||
|
||||
const optionTexts = [term.targetText, ...uniqueDistractors.slice(0, 3)];
|
||||
const shuffledTexts = shuffleArray(optionTexts);
|
||||
const correctOptionId = shuffledTexts.indexOf(term.targetText);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue