import { strict as assert } from "node:assert"; import { test } from "vitest"; import type { components } from "../../../src/features/tech-log/contracts/public/generated.ts"; type ReferenceBody = components["schemas"]["ReferenceDetailResponse"]["reference"]; /* 이 파일은 사고 하나에서 나왔다. 공개 Reference 화면이 통째로 비어 있었다. Studio 에서는 같은 글이 다 보였으므로 "공개 쪽만 안 나온다" 로 드러났다. 원인은 게이트웨이가 읽던 이름이 계약에 없는 것들이었다는 것이다 — `purposeSummary`, `applyWhenMarkdown`, `exceptionsMarkdown`, `examplesMarkdown`. 전부 undefined 로 떨어졌고 타입 검사는 `as string` 단언 때문에 아무 말도 하지 않았다. 그래서 여기서 확인하는 것은 값이 아니라 **이름**이다. 계약이 그 칸을 갖고 있는가, 그리고 화면이 기대하는 모양인가. */ test("the public Reference contract keeps the fields the screen reads", () => { const reference = { title: "", scopeSummary: "", appliesTo: [], excludedScope: [], rules: [{ title: "", body: "" }], examples: [], freshnessStatus: "CURRENT", content: "", contentFormat: "MARKDOWN", contentFormatVersion: 1, tags: [], publishedAt: "", updatedAt: "", } satisfies ReferenceBody; // 화면이 읽는 이름 그대로. 하나라도 계약에서 사라지면 위의 `satisfies` 가 먼저 깨진다. assert.deepEqual(Object.keys(reference).sort(), [ "appliesTo", "content", "contentFormat", "contentFormatVersion", "examples", "excludedScope", "freshnessStatus", "publishedAt", "rules", "scopeSummary", "tags", "title", "updatedAt", ]); }); /* Reference 의 본문은 `content` 마크다운이 아니라 규칙과 예시에 있다. Studio 의 편집기가 제목과 본문을 따로 받고 `body_markdown` 은 비워 두기 때문이다 — 그래서 `content` 를 잘라 규칙을 만들려 하면 언제나 빈 목록이 된다. */ test("a rule carries its own title and body, not a slice of markdown", () => { const rule: NonNullable[number] = { title: "Authorization Endpoint에는 client_secret을 보내지 않는다", body: "이 요청은 브라우저의 full-page navigation으로 나간다.", }; assert.equal(typeof rule.title, "string"); assert.equal(typeof rule.body, "string"); });