docs(TechLog): 글감 56개를 기록으로 쓴다
주제 13개 · Case 28 · Concept 5 · Reference 15 · Question 4 · Decision 4. 계약의 노드마다 종류가 요구하는 칸을 채우고, 본문이 있는 두 종류에는 SSOT 가 이미 그려 둔 도식 셋(value-boundaries · decision-path-404 · topic-variant-model)을 tech-log-studio/ 로 옮겨 붙였다. 새로 그린 그림은 없다. 검사 셋 전부 통과한다. check_body.mjs 56 편 중 본문이 있는 33 편 PASS check_prose.mjs 56 편 error 0 check_evidence.mjs --repo 포함 문제 없음 verify-tech-log-tree.py 프로젝트 5 · error 0 · warn 0 인용한 코드블록은 전부 SSOT 에서 찾아 대조했다. check_evidence.mjs 가 본문의 각 줄과 source 앵커와 계약 제목을 다시 확인한다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6955611439
commit
f6c825e858
+91
@@ -0,0 +1,91 @@
|
||||
---
|
||||
kind: CASE
|
||||
slug: a-narrow-implementation-satisfied-a-wide-port
|
||||
title: 구현이 종류를 좁게 적어도 넓은 포트를 만족했다
|
||||
topic: what-the-compiler-lets-through
|
||||
topicName: 타입 검사가 통과시키는 곳
|
||||
project: TechLog
|
||||
status: 게시 전
|
||||
lastVerifiedOn: 2026-09-04
|
||||
sourceRevision: tech-log@2026-09-02
|
||||
source:
|
||||
- final/document.md#§6.1
|
||||
---
|
||||
|
||||
# 구현이 종류를 좁게 적어도 넓은 포트를 만족했다
|
||||
|
||||
개념 삭제가 계속 질문 삭제 경로로 나갔다. 앞선 커밋이 게이트웨이를 고치지 못했는데 타입 검사가 통과해서 반영된 줄 알았다. TypeScript 에서 메서드 매개변수는 bivariant 라, 구현이 종류를 좁게 적어도 넓은 포트 시그니처를 만족한 것으로 통과한다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **TypeScript 가 검사를 놓아 주는 네 곳**
|
||||
bivariance 가 그중 하나다.
|
||||
- **타입에는 보이는데 부를 수 없는 연산이 네 번 나왔다**
|
||||
같은 삭제 경로에서 난 다른 부류의 결함이다.
|
||||
- **한 경계를 고쳤으면 값의 여정 끝에서 확인한다**
|
||||
이 사건이 그 규칙의 근거 하나다.
|
||||
|
||||
## 문제
|
||||
|
||||
포트는 네 종류를 받는다고 선언돼 있는데 구현은 세 종류만 적혀 있었다. 그 상태로 타입 검사가 통과했다.
|
||||
|
||||
CONCEPT 을 넘기면 구현의 삼항 사슬이 마지막 `else` 로 떨어뜨려 질문 삭제 경로를 부른다. 배포된 번들에서 서버 로그에 `DELETE /api/v1/studio/questions/{id} 404` 가 계속 찍혔다.
|
||||
|
||||
## 결론
|
||||
|
||||
TypeScript 에서 메서드 매개변수는 bivariant 다. 구현이 매개변수를 좁게 적어도 넓은 포트 시그니처를 만족한 것으로 통과한다.
|
||||
|
||||
포트 : CASE · REFERENCE · QUESTION · CONCEPT
|
||||
구현 : CASE · REFERENCE · QUESTION
|
||||
타입 검사 : 통과
|
||||
실행 결과 : CONCEPT 이 질문 삭제로 나감
|
||||
|
||||
같은 병이 필터 타입에서도 났다. 포트와 정적 어댑터가 타입을 따로 들고 있어, 포트에 필터가 늘어도 어댑터는 모르는 상태가 됐다. `satisfies` 도 같은 이유로 잡지 못했다. 타입을 하나로 합쳐서 고쳤다.
|
||||
|
||||
## 검증 환경
|
||||
|
||||
tech-log-frontend : 6429aee 이후 · 67a5491 에서 필터 타입 통합
|
||||
TypeScript : 메서드 매개변수 bivariance
|
||||
확인 방식 : 배포본의 서버 로그에서 실제로 나가는 경로를 확인
|
||||
|
||||
## 재현 조건
|
||||
|
||||
1. 포트에 네 값을 받는 메서드를 선언한다
|
||||
2. 구현에서 세 값만 적는다 — 타입 검사가 통과한다
|
||||
3. 네 번째 값을 넘겨 실제로 어떤 경로가 나가는지 본다
|
||||
|
||||
## 본문
|
||||
|
||||
<!-- body:start -->
|
||||
|
||||
## 좁은 구현이 넓은 포트를 만족한다
|
||||
|
||||
```ts
|
||||
// 포트 시그니처
|
||||
deleteDocument(kind: "CASE" | "REFERENCE" | "QUESTION" | "CONCEPT", id: string): Promise<void>;
|
||||
|
||||
// 구현이 이렇게 좁게 적혀 있어도 위 시그니처를 "만족"한다
|
||||
deleteDocument(kind: "CASE" | "REFERENCE" | "QUESTION", id: string) { … }
|
||||
```
|
||||
|
||||
메서드 매개변수가 bivariant 이므로 이 둘은 호환된다고 판정된다. 구현 안의 삼항 사슬은 CONCEPT 을 마지막 `else` 로 떨어뜨린다.
|
||||
|
||||
## 왜 반영된 줄 알았나
|
||||
|
||||
앞선 커밋에서 게이트웨이를 고쳤다고 판단한 근거가 타입 검사 통과였다. 좁게 적힌 구현을 그 커밋이 건드리지 않았고, 검사는 그것을 묻지 않았다.
|
||||
|
||||
배포된 번들에서 서버 로그를 보고서야 알았다. 삭제 요청이 질문 경로로 나가고 있었다.
|
||||
|
||||
## 같은 병이 필터에서도 났다
|
||||
|
||||
포트와 정적 어댑터가 필터 타입을 따로 들고 있었다. 포트에 축 필터를 더해도 어댑터의 타입은 그대로였고, `satisfies` 도 같은 이유로 통과했다.
|
||||
|
||||
타입을 하나로 합쳐서 고쳤다. 포트가 아는 필터와 어댑터가 아는 필터가 같은 타입이면 한쪽만 늘어날 수 없다.
|
||||
|
||||
## 확인한 것과 확인하지 못한 것
|
||||
|
||||
CONCEPT 을 `deleteQuestion` 으로 되돌려 가드가 깨지는 것을 확인했다.
|
||||
|
||||
배포된 번들에 옛 삼항이 남아 있던 것은 서버 로그의 404 로 확인했다. 그 로그 원문은 이 저장소에 없다.
|
||||
|
||||
<!-- body:end -->
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
---
|
||||
kind: CASE
|
||||
slug: the-typecheck-command-checked-no-files
|
||||
title: npx tsc --noEmit 이 한 파일도 검사하지 않고 성공했다
|
||||
topic: what-the-compiler-lets-through
|
||||
topicName: 타입 검사가 통과시키는 곳
|
||||
project: TechLog
|
||||
status: 게시 전
|
||||
lastVerifiedOn: 2026-09-04
|
||||
sourceRevision: tech-log@2026-09-02
|
||||
source:
|
||||
- final/document.md#§6.4
|
||||
---
|
||||
|
||||
# npx tsc --noEmit 이 한 파일도 검사하지 않고 성공했다
|
||||
|
||||
운영에서 릴리즈 목록이 `ReferenceError` 로 비었다. import 하나가 빠져 있었고 다른 변수는 아예 정의된 적이 없었다. `npx tsc --noEmit` 이 통과했기 때문에 그것을 보지 못했다. 루트 tsconfig 는 `"files": []` 에 project references 만 나열하므로 그 명령은 한 파일도 검사하지 않고 성공한다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **TypeScript 가 검사를 놓아 주는 네 곳**
|
||||
검사 대상을 갖지 않은 tsconfig 가 그중 하나다.
|
||||
- **가드는 작동했는데 제가 그것을 돌리지 않아 두 번 새어 나갔다**
|
||||
가드를 넣고 돌리지 않은 다른 사건이다.
|
||||
- **배포 전에 사람이 돌려야 하는 것과 그 함정**
|
||||
이 사건 뒤에 목록으로 굳혔다.
|
||||
|
||||
## 문제
|
||||
|
||||
운영에서 릴리즈 목록 화면이 비었고 콘솔에 `ReferenceError` 가 났다. 링크 컴포넌트 import 가 빠졌고, 이동 함수는 정의된 적이 없었다.
|
||||
|
||||
타입 검사를 돌렸을 때 통과했다. 그래서 이 오류가 배포까지 갔다.
|
||||
|
||||
## 결론
|
||||
|
||||
`npx tsc --noEmit` 은 루트 tsconfig 를 읽는다. 그 파일은 `"files": []` 에 project references 만 나열하므로 검사할 파일이 없고, 없는 채로 성공한다.
|
||||
|
||||
실제 검사는 `npm run check:types` 가 한다. 이 명령이 여섯 개 프로젝트를 돌며 검사한다.
|
||||
|
||||
그 명령으로 돌리자 저장소에 남아 있던 다른 오류도 함께 드러났다.
|
||||
|
||||
CatalogEntry 가 export 되지 않음
|
||||
라우트 파라미터가 unknown
|
||||
메시지 키가 파라미터를 받도록 등록되지 않음
|
||||
ReleaseIndexItem 에 summary 없음
|
||||
|
||||
## 검증 환경
|
||||
|
||||
tech-log-frontend : e9b8661 이후
|
||||
tsconfig : 루트가 project references 만 나열
|
||||
확인 방식 : 두 명령을 같은 작업 트리에서 각각 돌려 결과를 대조
|
||||
|
||||
## 재현 조건
|
||||
|
||||
1. 어느 프로젝트 파일에 정의되지 않은 변수를 하나 넣는다
|
||||
2. `npx tsc --noEmit` 을 돌린다 — 성공한다
|
||||
3. `npm run check:types` 를 돌린다 — 그 파일에서 멈춘다
|
||||
|
||||
## 본문
|
||||
|
||||
<!-- body:start -->
|
||||
|
||||
## 검사할 파일이 없는 tsconfig
|
||||
|
||||
루트 tsconfig 는 이 저장소에서 컴파일 대상을 갖지 않는다. `"files": []` 에 project references 만 나열한다. 각 프로젝트는 자기 tsconfig 를 갖고 있고, 루트는 그들을 가리키기만 한다.
|
||||
|
||||
`npx tsc --noEmit` 은 references 를 따라가지 않는다. 루트가 지목한 파일 집합만 보고, 그 집합이 비어 있으므로 아무것도 검사하지 않은 채 0 으로 끝난다.
|
||||
|
||||
## 통과가 무엇을 뜻했나
|
||||
|
||||
이 명령이 성공했을 때 확인된 것은 「루트 tsconfig 가 유효하다」까지다. 코드가 컴파일되는지는 확인되지 않았다.
|
||||
|
||||
## 올바른 명령으로 돌렸을 때
|
||||
|
||||
`npm run check:types` 는 여섯 프로젝트를 각각 돌린다. 그 명령으로 돌리자 릴리즈 목록의 두 오류에 더해 네 가지가 더 나왔다 — export 되지 않은 타입, `unknown` 인 라우트 파라미터, 파라미터를 받도록 등록되지 않은 메시지 키, 목록 항목에 없는 요약.
|
||||
|
||||
## 남은 것
|
||||
|
||||
루트 tsconfig 는 그대로 뒀다. 누군가 다시 `npx tsc --noEmit` 을 쓰는 것을 막는 검사는 없고, 배포 전에 돌릴 다섯 명령의 목록에 적어 둔 것이 지금의 대책이다.
|
||||
|
||||
<!-- body:end -->
|
||||
Reference in New Issue
Block a user