Task 3 리뷰 finding(Important): contract.ts의 손수 유지되는 ProblemDetails가 tech-log-studio-contract-contribution.ts의 envelopeError()가 실제로 반환하는 모양과 별도로 정의돼 있었다. envelopeError()는 ApiError의 type/title/status/detail/code/retryable/category/details만 채우므로 ProblemDetails가 갖고 있던 옛 평면 필드(instance/traceId/fieldErrors/ latestDocument/latestPublication/conflictingFields)는 production에서 항상 undefined였다 — mock만 채워서 mock이 아무것도 검증하지 못하는 상태였다. - contract.ts: ProblemDetails에서 옛 평면 필드를 제거하고 details를 wire와 같은 union 타입(ValidationErrorDetails | VersionConflictDetails | PublicationConflictDetails | null)으로 정확히 준다. 세 타입을 이제 개별 export한다. - tech-log-studio-contract-contribution.ts: envelopeError()가 contract.ts의 ProblemDetails를 그대로 반환 타입으로 쓴다(로컬 StudioProblemShape 제거) — 이제 한 곳에만 정의가 있다. - mock-studio-gateway.ts / cursor.ts: fieldErrors/latestDocument/ conflictingFields/latestPublication을 wire와 같은 자리(details 안)로 옮긴다. - mock-studio-gateway.test.ts: 위 이동에 맞춰 details를 캐스트로 좁혀 읽도록 갱신. retryable은 optional로 유지했다 — 여러 테스트가 생략하고 만들며, 이번 finding과 무관해 required로 좁히면 관련 없는 파일들이 깨진다. 리뷰가 보류한 2건(asset-upload-transport.ts의 CODES.has 중복 검사, apiErrorSchema.category가 enum이 아닌 것)은 손대지 않았다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
77 lines
4.1 KiB
TypeScript
77 lines
4.1 KiB
TypeScript
import type { components } from "./generated.ts";
|
|
|
|
type Schemas = components["schemas"];
|
|
export type RecordKind = Schemas["RecordKind"];
|
|
export type WorkingCopy = Schemas["WorkingCopy"];
|
|
export type WorkingCopyInput = Schemas["WorkingCopyInput"];
|
|
export type WorkingCopyDetail = Schemas["WorkingCopyDetail"];
|
|
export type StudioDashboard = Schemas["StudioDashboard"];
|
|
export type DocumentPage = Schemas["DocumentPage"];
|
|
export type CreateDocumentInput = Schemas["CreateDocumentInput"];
|
|
export type SaveDocumentCommand = Schemas["SaveDocumentCommand"];
|
|
export type ValidateDocumentCommand = Schemas["ValidateDocumentCommand"];
|
|
export type ValidationReport = Schemas["ValidationReport"];
|
|
export type CreatePreviewCommand = Schemas["CreatePreviewCommand"];
|
|
export type PublicPreview = Schemas["PublicPreview"];
|
|
export type PreviewDetail = Schemas["PreviewDetail"];
|
|
export type PublishDocumentCommand = Schemas["PublishDocumentCommand"];
|
|
export type PublishResult = Schemas["PublishResult"];
|
|
export type UnpublishCommand = Schemas["UnpublishCommand"];
|
|
export type PublicationAggregate = Schemas["PublicationAggregate"];
|
|
export type PublicationEvent = Schemas["PublicationEvent"];
|
|
export type PublicationListItem = Schemas["PublicationListItem"];
|
|
export type PublicationPage = Schemas["PublicationPage"];
|
|
export type PublicationSnapshot = Schemas["PublicationSnapshot"];
|
|
export type CatalogPage = Schemas["CatalogPage"];
|
|
/**
|
|
* ADR-006으로 canonical 계약의 오류가 봉투(`ErrorEnvelope`/`ApiError`)로
|
|
* 바뀌면서 `ProblemDetails` 스키마 자체는 canonical에서 삭제됐다. 더 이상
|
|
* 생성된 스키마에서 뽑지 않고 여기서 손으로 유지하되, 이 모양은 전송 경계
|
|
* (`tech-log-studio-contract-contribution.ts`의 `envelopeError`)가 실제로
|
|
* 만드는 모양과 **동일해야 한다** — 그게 이 값이 production에서 채워지는
|
|
* 유일한 경로다. `ApiError`가 옮겨주는 필드(`type/title/status/detail/code/
|
|
* category/retryable/details`)만 갖는다.
|
|
*
|
|
* (Task 3 fix round 1) 이전에는 ADR-006 이전 평면 wire 모양에서 넘어온
|
|
* `instance`/`traceId`/`fieldErrors`/`latestDocument`/`latestPublication`/
|
|
* `conflictingFields`를 최상위 필드로 따로 두고 있었다. `envelopeError`는
|
|
* 그 필드들을 채우지 않으므로(옮길 대상이 없음) production 값에서는 항상
|
|
* `undefined`였고, mock 게이트웨이만 채웠다 — 타입은 있는데 mock에 대고
|
|
* 짜면 통과하고 실제 HTTP 경로에서는 조용히 비는, 봉투 검증 설계가 막으려던
|
|
* 함정이었다. 그 데이터는 이제 wire와 동일하게 `details` 안에 둔다 — mock도
|
|
* 여기 채운다(`mock-studio-gateway.ts`, `cursor.ts`).
|
|
*/
|
|
export type ValidationErrorDetails = Schemas["ValidationErrorDetails"];
|
|
export type VersionConflictDetails = Schemas["VersionConflictDetails"];
|
|
export type PublicationConflictDetails = Schemas["PublicationConflictDetails"];
|
|
export type ProblemDetailsPayload =
|
|
| ValidationErrorDetails
|
|
| VersionConflictDetails
|
|
| PublicationConflictDetails
|
|
| null;
|
|
|
|
export type ProblemDetails = Readonly<{
|
|
/** Format: uri-reference */
|
|
type: string;
|
|
title: string;
|
|
status: number;
|
|
detail: string;
|
|
code: Schemas["ApiError"]["code"];
|
|
category?: Schemas["ApiError"]["category"];
|
|
// optional 유지: 기존 호출부(테스트의 `new StudioGatewayError({...})` 리터럴
|
|
// 다수, `synthetic()`의 일부 경로)가 `retryable`을 생략한다. 이번 fix
|
|
// round의 finding은 `details`/평면 필드 문제이지 이 필드의 필수 여부가
|
|
// 아니다 — required로 좁히면 무관한 파일들이 깨진다.
|
|
retryable?: boolean;
|
|
details?: ProblemDetailsPayload;
|
|
}>;
|
|
export type PublicRenderModel = Schemas["PublicRenderModel"];
|
|
export type Asset = Schemas["Asset"];
|
|
export type AssetDetail = Schemas["AssetDetail"];
|
|
export type AssetPage = Schemas["AssetPage"];
|
|
export type AssetUsage = Schemas["AssetUsage"];
|
|
export type AssetKind = Schemas["AssetKind"];
|
|
export type AssetManagementStatus = Schemas["AssetManagementStatus"];
|
|
export type UpdateAssetCommand = Schemas["UpdateAssetCommand"];
|
|
export type StudioSession = Schemas["StudioSession"];
|