Commit Graph
5 Commits
Author SHA1 Message Date
DongHyeonkaandClaude Opus 5 d23a18f659 fix: ProblemDetails를 전송 계층이 실제로 만드는 모양 하나로 합친다
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>
2026-08-18 22:13:33 +09:00
DongHyeonkaandClaude Opus 5 e2a0e695dd fix: normalize uncharacterized read failures in the mock Studio gateway
`idempotent()` was fixed to wrap anything `work()` throws, with a documented
rationale: this port's contract is `StudioGatewayError` only, so nothing else
may cross it. Its `read()` sibling was left unwrapped, so an uncharacterized
internal failure on any of the seven read operations escaped as a raw `Error`
and reached UI code written to catch `StudioGatewayError`.

`read()` now applies the same `failureOf` classification. It has no
idempotency ledger, so only the problem half is used. `boundary()` stays
outside the wrap so an aborted request still surfaces as `AbortError`,
exactly as `idempotent()` arranges it -- asserted by the new test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 09:09:36 +09:00
DongHyeonkaandClaude Opus 5 1d01a522de feat: implement the TechLog Studio HTTP gateway
Adds createHttpStudioGateway, the adapter the Studio UI calls in
production. It drives every mutation through mutationIntent()
(defineMutationIntent/defineIdempotencyKey, not
createBrowserMutationIntentFactory, so the caller-supplied idempotency
key is preserved rather than regenerated) and leaves header
construction to the executor/credential collaborator entirely - the
gateway never sees or sets Idempotency-Key or x-csrf-token itself.

Also moves stable-stringify.ts out of adapters/mock/ so the mock and
http adapters share one pure function without production code
depending on the mock directory, and fixes the resulting import in
cursor.ts, mock-studio-gateway.ts, and mock-studio-gateway.test.ts.

Adds MSW handlers (tests/mocks/handlers/tech-log-studio.ts) that wrap
the reference mock-studio-gateway implementation, and a contract test
suite that drives the gateway through a thin fetch-based executor
built from the contract's own projectRequest, proving canonical
path/body/header construction without assembling the full platform
transport.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 01:30:24 +09:00
DongHyeonkaandClaude Opus 5 a0e0be6522 test: cover dashboard needsValidation and detail() nextAction regression risk
Round 3 of the TechLog contract task added two pieces of genuinely new
logic with no assertion on their output: the totals.needsValidation
count in getDashboard(), and the detail() rewrite that avoids a
self-reference when computing WorkingCopyDetail.nextAction. Both would
have passed every existing test if they regressed.

- needsValidation is checked against an independent count derived from
  listDocuments()'s per-document nextAction, with sanity bounds so a
  filter that always returns 0 or the full count can't pass silently.
- detail()'s nextAction is asserted on two fixtures whose expected
  value is justified by the asserted preconditions alongside it
  (published-at-current-version -> NONE; INVALID-but-current-validation
  -> FIX_VALIDATION). Verified locally that hardcoding nextAction to a
  constant in detail() makes the second assertion fail, and that
  zeroing needsValidation's count makes the dashboard assertion fail.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 00:38:03 +09:00
DongHyeonka 27dda3e0e3 feat: compose TechLog static and mock adapters 2026-08-15 19:36:46 +09:00