검증 증거 문서 보강

This commit is contained in:
Yun Chan 2026-07-01 12:48:26 +09:00
parent 69fece56bf
commit 7c41c3ce79
5 changed files with 57 additions and 18 deletions

View file

@ -61,6 +61,14 @@ interface LiveCoachEvent {
suggestion: {
title: string;
message: string;
sources?: Array<{
source_id: string;
title: string;
locator?: string | null;
kb_kind?: string | null;
version?: string | null;
citation?: string | null;
}>;
};
}
@ -619,30 +627,59 @@ test.describe("session persistence", () => {
const coachResponse = await coachResponsePromise;
await expectResponseOk(coachResponse);
const coachSuggestion = (await coachResponse.json()) as LiveCoachEvent["suggestion"];
const workbookSource = coachSuggestion.sources?.find(
(source) => source.source_id === "workbook_0615_case_conceptualization",
);
expect(workbookSource, "live coach response should include the licensed workbook source pack").toBeTruthy();
expect(workbookSource?.version).toBe("2026-06-15");
expect(workbookSource?.citation ?? "").toContain("0615");
await expect(page.locator(".sx-coach-card").getByText(coachSuggestion.title)).toBeVisible({
timeout: 30_000,
});
await page.locator(".sx-coach-card").getByRole("button", { name: "근거 보기" }).click();
const evidenceDialog = page.locator(".sx-coach-modal [role='dialog']");
await expect(evidenceDialog).toBeVisible({ timeout: 15_000 });
await expect(evidenceDialog).toContainText(workbookSource!.title);
await expect(evidenceDialog).toContainText("2026-06-15");
await expect(evidenceDialog).toContainText("0615");
await evidenceDialog.getByRole("button", { name: "닫기" }).click();
await expect(evidenceDialog).toHaveCount(0);
const historyResponse = await page.request.get(`/api/sessions/${sessionId}/live-coach`);
await expectResponseOk(historyResponse);
const history = (await historyResponse.json()) as LiveCoachHistoryResponse;
expect(history.source).toBe("database");
expect(
history.events.some(
const persistedCoachEvent = history.events.find(
(event) =>
event.turn_seq === 1 &&
event.learner_text_excerpt?.includes("가장 버거운 감정") &&
event.suggestion.title === coachSuggestion.title,
);
expect(persistedCoachEvent, "DB-backed live coach history should include the delivered coaching event").toBeTruthy();
expect(
persistedCoachEvent?.suggestion.sources?.some(
(source) =>
source.source_id === workbookSource!.source_id &&
source.version === workbookSource!.version &&
(source.citation ?? "").includes("0615"),
),
"DB-backed live coach history should preserve source pack metadata",
).toBe(true);
await page.goto(`/learn/session/${sessionId}`);
await expect(page.locator(".sx-utt.is-learner").filter({ hasText: learnerText })).toBeVisible({
timeout: 15_000,
});
await expect(page.locator(".sx-utt.is-learner .sx-utt__coach-mark")).toBeVisible({
const coachMark = page.locator(".sx-utt.is-learner .sx-utt__coach-mark");
await expect(coachMark).toBeVisible({
timeout: 15_000,
});
await coachMark.click();
const historyDialog = page.locator(".sx-coach-history [role='dialog']");
await expect(historyDialog).toBeVisible({ timeout: 15_000 });
await expect(historyDialog).toContainText(workbookSource!.title);
await expect(historyDialog).toContainText("2026-06-15");
await expect(historyDialog).toContainText("0615");
});
test("persists voice nonverbal metadata into DB-backed review @single-run", async ({ page }) => {