pipeline: make tech-log-tree.json the one decomposition contract and enforce it
리뷰 두 건을 반영했다. 계약 - tech-log-tree.json 하나가 분해 계약이자 색인이다. 사람이 읽는 트리·Node Specification· 후보 대장은 없어졌고, 문서에 남아 있던 그 개념을 걷어냈다 - candidateScope — 후보를 찾는 SSOT 범위. 접어 넣은 제2부·제3부는 근거이지 후보가 아니다 - sourceRepository — 분석한 저장소의 경로·리비전·판단 근거. 리비전을 모르면 null 로 두고 지어내지 않는다. 갈래가 여럿이면 revisions - 검사기: 계약 미채택·PENDING·PROMOTE↔글감 양방향·candidateScope·sourceRepository 를 error/warn 으로 센다. 옛 스키마도 검사를 피하지 못한다. 테스트 22 → 31 기록 쓰기 - 템플릿 5종에 source·sourceRevision·topicName, Question 에 닫는 조건, 본문 없는 종류에서 assets 제거. 고정 절 개수 삭제 - check_evidence.mjs — 인용한 코드가 SSOT 에 있는지, 앵커가 SSOT 를 가리키는지, 제목이 계약과 같은지, 리비전이 저장소에 있는지. 게시된 기록에서 SSOT 와 다른 URL 을 잡았다 문체 - 문체 규칙의 정본을 ai-tells.md 로. explaining.md 의 질문체 제목·절 끝 대조 반복·그림 예고 규칙을 삭제해 충돌을 없앴다. 첫 절 「설명 뒤에 평가를 붙이지 않는다」에 지우는 사례 네 유형 - voice 스킬의 「독자 쪽을 본다」를 자료에 오독 기록이 있을 때로 좁히고, 평가만 더한 예시를 교체 - check_prose: 안내 문장을 요구하던 경고 제거, 문장이 끝나지 않은 채 문단이 끝나는 조각 검사 추가 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
73026cada6
commit
9d2a3725c5
@@ -3,6 +3,95 @@
|
||||
문장 하나하나는 멀쩡한데 문서군 전체가 같은 리듬으로 굴러갈 때 티가 난다. 개별 문장을 일부러
|
||||
어눌하게 만드는 방향은 역효과다. 아래는 실제 리뷰에서 지적된 것들이다.
|
||||
|
||||
**이 문서가 문체 규칙의 정본이다.** `explaining.md` 는 무엇을 더 설명할지를 다루고, 둘이 어긋나면
|
||||
이쪽을 따른다.
|
||||
|
||||
## 설명 뒤에 평가를 붙이지 않는다
|
||||
|
||||
가장 많이 지적된 형태다. 기술 설명은 이미 끝났는데 그 뒤에 **그 설명을 평가하거나, 다음을 예고하거나,
|
||||
독자가 오해할 것이라고 가정하거나, 어떻게 읽고 써야 하는지 지시하는 문장**이 하나 더 붙는다.
|
||||
|
||||
문장마다 무엇을 주는지 본다 — 동작, 정의, 근거, 판단에 영향을 주는 조건 가운데 하나여야 한다.
|
||||
그 넷 중 어느 것도 주지 않고 판정만 하는 문장은 지운다. 특정 단어를 금지하는 방식은 쓰지 않는다.
|
||||
「중요하다」가 나쁜 것이 아니라 그 문장이 아무것도 더하지 않는 것이 문제다.
|
||||
|
||||
**고치는 순서는 내용이 먼저다.** 필요 없는 문장을 남긴 채 표현만 자연스럽게 바꾸면 어색한 문장의
|
||||
표현만 달라진다. 평가·예고·되풀이를 걷어낸 뒤에 문장을 다듬는다.
|
||||
|
||||
네 가지가 반복된다. 전부 「다른 표현으로 고치는 사례」가 아니라 **「통째로 지우는 사례」**다.
|
||||
|
||||
### 설명한 것의 중요성을 다시 평가한다
|
||||
|
||||
```text
|
||||
✗ 다른 하나는 앞 단계가 어긋났는데도 나머지를 계속 돌려 마지막에 전체 통과를 남기는 일이다.
|
||||
그렇게 만든 기록은 경계가 지켜졌다는 근거가 되지 않는다.
|
||||
○ 다른 하나는 앞 단계가 어긋났는데도 나머지를 계속 돌려 마지막에 전체 통과를 남기는 일이다.
|
||||
|
||||
✗ 발행된 SQL에 Limit 노드가 없다는 것 자체가 DB가 페이징을 하지 않았다는 증거다.
|
||||
○ 발행된 SQL에는 Limit 노드가 없었다.
|
||||
```
|
||||
|
||||
「증거다」「핵심이다」「너무 넓다」「서로를 대신하지 않는다」로 끝나는 꼬리 문장이 이 형태다.
|
||||
앞 문장이 사실을 말했으면 거기서 끝낸다.
|
||||
|
||||
### 독자가 오해할 것이라고 먼저 가정한다
|
||||
|
||||
```text
|
||||
✗ 훑은 행만 보면 keyset이 결과까지 줄인 것으로 짐작하기 쉽다. 커서로 넘긴 두 번째 페이지는
|
||||
OFFSET의 두 번째 페이지와 같은 20개 식별자를 같은 순서로 반환했다.
|
||||
○ 커서로 넘긴 두 번째 페이지는 OFFSET의 두 번째 페이지와 같은 20개 식별자를 같은 순서로 반환했다.
|
||||
|
||||
✗ Web Storage에 토큰을 쓰지 않으니 JavaScript에서도 토큰이 사라진다고 읽기 쉽다. 그렇지 않다.
|
||||
액세스·리프레시·ID 토큰은 실행 중 메모리에 있다.
|
||||
○ 액세스·리프레시·ID 토큰은 실행 중 메모리에 있다.
|
||||
```
|
||||
|
||||
「~로 읽기 쉽다」「~라고 생각하면 안 된다」「~로 보기 쉽다」. 자료에 누군가 실제로 그렇게 읽었다는
|
||||
기록(버그·정정·문의)이 없으면 독자를 지어낸 것이다. 관측부터 적으면 오해는 생기지 않는다.
|
||||
|
||||
### 어떻게 읽고 어떻게 써야 하는지 지시한다
|
||||
|
||||
```text
|
||||
✗ AP2와 AP3의 쿠키는 서버 쪽 상태를 찾는 열쇠이고, AP4의 쿠키는 최소 상태를 담은 값이다.
|
||||
두 쿠키를 같은 문장으로 설명하면 서버 저장소가 있는 쪽과 없는 쪽이 구분되지 않는다.
|
||||
○ AP2와 AP3의 쿠키는 서버 쪽 상태를 찾는 열쇠이고, AP4의 쿠키는 최소 상태를 담은 값이다.
|
||||
|
||||
✗ 이 두 낱말만 알면 따라올 수 있고, 나머지는 처음 나오는 곳에서 푼다.
|
||||
✗ 먼저 브라우저가 들고 있는 값부터 보고, 그 값이 Bearer 요청이 되기까지를 따라간다.
|
||||
✗ native로 내려갔다는 것과 그 범위를 함께 적는다.
|
||||
```
|
||||
|
||||
「~라고 설명하면 ~가 구분되지 않는다」「~를 함께 적는다」「먼저 ~를 보고 다음에 ~를 본다」. 독자에게
|
||||
필요한 것은 각 쿠키가 무엇을 보관하는지이지 그것을 어떻게 설명해야 하는지가 아니다. 이런 문장은
|
||||
작성자의 검토 메모다. 차례 예고도 같다 — 다음 절이 바로 시작하면 된다.
|
||||
|
||||
### 이미 설명한 것을 다시 말한다
|
||||
|
||||
```text
|
||||
✗ 배치는 SQL 왕복 횟수를 줄이고 프로젝션은 적재할 대상을 줄인다. 두 효과는 서로를 대신하지 않는다.
|
||||
○ 배치는 SQL 왕복 횟수를 줄이고 프로젝션은 적재할 대상을 줄인다.
|
||||
|
||||
✗ 반복이 사라진 것이 아니라 스트림 뒤로 숨었다.
|
||||
○ 현재 매핑에서는 각 아이템의 getHighlights()에 접근하면서 지연 로딩이 실행된다.
|
||||
```
|
||||
|
||||
같은 대조를 추상어로 한 번 더 하거나, 동작 설명 뒤에 인상적인 문장으로 닫는 것. 동작을 그대로
|
||||
적으면 독자가 비유를 코드 동작으로 다시 번역하지 않아도 된다.
|
||||
|
||||
### SSOT 에 같은 문장이 있어도 옮기지 않는다
|
||||
|
||||
`final/document.md` 는 사실과 근거의 기준이지 문장의 기준이 아니다. 원문에 「너무 넓은 성공 기준입니다」가
|
||||
있어도 기록에 옮길 이유는 없다. 옮기는 것은 수치·조건·동작·판단이고, 평가는 옮기지 않는다.
|
||||
|
||||
### 무엇을 남기나
|
||||
|
||||
- 코드가 그렇게 동작하는 이유, 측정 조건, 결과를 읽는 데 필요한 예외
|
||||
- 실제 선택을 바꾼 판단 — 「200 이어도 정상인 이유는 세션이 유효하기 때문이다」처럼 판정에 영향을 주는 것
|
||||
- 요약·결론·본문 사이의 반복 — Studio 칸 구조상 필요하다. 걷어낼 것은 **한 칸 안에서** 설명 직후에 붙은 문장이다
|
||||
|
||||
어미 수·절 수·안내 문장 수 같은 수치는 참고 정보다. `style_profile.mjs` 가 「벗어남」을 내도 그것을
|
||||
맞추려고 문장을 넣지 않는다. 위 첫 예시는 문장 검사를 error 0 으로 통과한 채로 지적됐다.
|
||||
|
||||
## 억지 구어체를 만들지 않는다
|
||||
|
||||
AI 티를 지우려고 넣은 질문체와 청유형이 오히려 「AI 문장을 억지로 인간화한 것」으로 읽힌다.
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
가장 자주 나오는 지적은 **설명이 짧다**는 것이다. 사실은 맞는데 독자가 따라오지 못한다.
|
||||
|
||||
그 반대도 같은 무게로 지적된다 — 설명이 끝난 뒤에 그 설명을 평가하거나, 다음 절을 예고하거나,
|
||||
독자가 오해할 것이라고 가정하는 문장이 붙는 것. 이 문서는 **무엇을 더 설명하는가**를 다루고,
|
||||
무엇을 빼는가는 `ai-tells.md` 첫 절이 다룬다. **문체 규칙의 정본은 `ai-tells.md` 다.** 두 문서가
|
||||
어긋나면 그쪽을 따른다. 여기 규칙은 전부 「그 설명이 없으면 독자가 막히는 자리」에서만 쓴다.
|
||||
이미 설명된 문단에 더하지 않는다.
|
||||
|
||||
## 이름을 댔으면 왜 있는지도 댄다
|
||||
|
||||
낯선 클래스·기법·설정 이름을 적고 다음 문장으로 넘어가지 않는다. **왜 그것이 존재하는지**를 한
|
||||
@@ -13,13 +19,13 @@ XorCsrfTokenRequestAttributeHandler가 token을 XOR와 Base64로 가린다.
|
||||
|
||||
쓴다
|
||||
XorCsrfTokenRequestAttributeHandler가 token을 XOR와 Base64로 가린다.
|
||||
BREACH 공격을 줄이기 위해서다. 여기서 깊게 다루지는 않는다 — HTTP 응답 압축 크기의
|
||||
차이로 응답 안의 비밀값을 조금씩 추측하는 공격이고, 그래서 응답에 실리는 값을 매번
|
||||
다르게 만든다.
|
||||
BREACH 공격을 줄이기 위해서다. HTTP 응답 압축 크기의 차이로 응답 안의 비밀값을 조금씩
|
||||
추측하는 공격이고, 그래서 응답에 실리는 값을 매번 다르게 만든다.
|
||||
```
|
||||
|
||||
깊게 안 갈 것이면 **안 간다고 밝히고 한 문장 요약을 준다.** 이름만 던지고 넘어가면 독자는 그
|
||||
자리에서 검색하러 나간다.
|
||||
깊게 안 갈 것이면 **한 문장 요약만 준다.** 「여기서 깊게 다루지는 않는다」 같은 예고는 붙이지 않는다 —
|
||||
요약이 있으면 그것으로 충분하고, 없으면 독자는 그 자리에서 검색하러 나간다. 이 규칙은 **처음
|
||||
나오는 낯선 이름**에만 걸린다. 이미 설명한 이름이나 문맥에서 분명한 이름에는 붙이지 않는다.
|
||||
|
||||
## 「역할이 다르다」로 끝내지 않는다
|
||||
|
||||
@@ -87,27 +93,6 @@ sessionStorage에도 accessToken과 refreshToken이 없었다.
|
||||
쓴다 identity-header-trust
|
||||
```
|
||||
|
||||
## 제목은 묻고 본문은 답한다
|
||||
|
||||
절 제목에 `~해보자` `~하지?` `~일까?`를 쓴다. 그리고 **첫 문장에서 그 질문을 다시 던지고**
|
||||
답한다.
|
||||
|
||||
| 쓰지 않는다 | 쓴다 |
|
||||
|---|---|
|
||||
| 브라우저에 남은 것 | 브라우저에 관리 대상 |
|
||||
| 위조 요청은 어떻게 생겼나 | 위조 요청은 어떻게 생겼을까? |
|
||||
| 세 겹으로 나눠서 막는다 | 세 겹으로 나눠서 막아보자 |
|
||||
| 무엇이 서버로 넘어왔나 | 무엇이 서버로 책임이 넘어왔지? |
|
||||
| upstream이 JWT를 받지 않는다는 뜻 | upstream이 JWT를 받지 않는다? |
|
||||
|
||||
```text
|
||||
## 브라우저에 관리 대상
|
||||
|
||||
브라우저에 관리 대상은 그럼 어떤 게 될까?
|
||||
|
||||
| 무엇 | 브라우저에 있나..? | JavaScript가 읽나..? |
|
||||
```
|
||||
|
||||
## 굵게를 걷어낸다
|
||||
|
||||
`**굵게**`는 거의 쓰지 않는다. 한 절에 하나를 넘기면 강조가 아니라 얼룩이 된다. 강조는
|
||||
@@ -155,9 +140,6 @@ authorization code와 함께 redirect되고, 그 code를 mediator가 token으로
|
||||
이 구조에서는 token 관리와 교환의 위치가 브라우저에서 Spring backend로 옮겨지게 된다.
|
||||
```
|
||||
|
||||
같은 대조를 절 끝에서 한 번 더 쓴다 — 「앞선 구조에서는 브라우저가 OIDC client였다면 이
|
||||
구조에서는 mediator가 OIDC client가 된다」처럼.
|
||||
|
||||
## 결론은 문장 끝에 붙인다
|
||||
|
||||
한 줄짜리 단정문을 따로 떼어 강조하지 않는다. 앞 문장에서 `그래서` · `그렇기 때문에`로
|
||||
@@ -205,11 +187,6 @@ access token이 필요하고, 그것을 응답 본문으로 받게 된다. 그
|
||||
|
||||
Reference의 규칙 제목과 Decision의 결정문도 `~한다`로 끊는다. 그 자리는 기준이다.
|
||||
|
||||
## 그림은 한 줄로 예고한다
|
||||
|
||||
`전체적인 구조를 보면 다음과 같다` 같은 한 줄을 두고 그림을 넣는다. 문단 사이에 말없이
|
||||
끼우지 않는다.
|
||||
|
||||
## 번역투를 걷어낸다
|
||||
|
||||
가장 자주 나오는 지적 두 번째다. 어미는 한국어인데 **문장 구조가 영어**여서 읽기 힘들다.
|
||||
@@ -409,5 +386,4 @@ Reference의 규칙 제목과 Decision의 결정문도 `~한다`로 끊는다.
|
||||
- **`~하면 된다`를 쓰지 않는다.** 조언하는 말투이지 기록하는 말투가 아니다.
|
||||
`정하면 된다` → `정한다`, `적으면 된다` → `적는다`, `두면 된다` → `둔다`
|
||||
- `A는 B다`보다 `A는 B라는 점이 문제가 된다` — 무엇이 걸리는지까지 말한다
|
||||
- 무엇을 하자고 이끌 때는 `~해 보자`를 쓴다. 절 제목과 여는 문장에만 쓰고 규칙에는 쓰지 않는다
|
||||
- 명령조를 줄인다. 검사 항목이 아니라 같이 읽는 사람의 말로 쓴다
|
||||
|
||||
@@ -1,8 +1,40 @@
|
||||
# SSOT에서 글감을 뽑는 기준
|
||||
|
||||
`final/`의 긴 글 하나가 정본(SSOT)이다. 거기서 Studio에 올릴 기록을 뽑아낸다. 이 문서는 **무엇을
|
||||
몇 건으로 나눌지**를 정하는 기준이다. 나눈 결과는 `tech-log-tree.json`에 제목만 먼저 적고, 글은
|
||||
그다음에 쓴다.
|
||||
`final/document.md` 하나가 정본(SSOT)이다. 거기서 Studio에 올릴 기록을 뽑아낸다. 이 문서는
|
||||
**무엇을 몇 건으로 나눌지**를 정하는 기준이다. 나눈 결과는 `tech-log-tree.json` 하나에 적는다 —
|
||||
분해 계약과 색인이 같은 파일이라 둘이 어긋날 자리가 없다.
|
||||
|
||||
## 어느 파일에서 뽑나
|
||||
|
||||
| 층 | 하는 일 |
|
||||
|---|---|
|
||||
| 코드·설정·실행 증거 | 사실의 근거 |
|
||||
| `final/document.md` | **글감 범위의 SSOT** — 후보를 발견하는 유일한 입력 |
|
||||
| `analysis/**/*.md` | final이 이미 채택한 주장을 상세히 확인하는 보조 근거 |
|
||||
| `tech-log-tree.json` | 사람이 고른 글감. 분해 계약이자 색인이고 이 파일이 정본이다 |
|
||||
|
||||
**`analysis/**`를 글감을 찾으려고 열지 않는다.** 이미 final에 있는 주장의 세부를 확인할 때만
|
||||
연다. 분석에만 있고 final에는 없는 자료를 발견하면 트리에 바로 넣지 말고 `final/document.md`를
|
||||
먼저 보강한다. 그러지 않으면 모듈 문서 61편이 각각 정본 노릇을 하고, 트리는 그 절 수의 합만큼
|
||||
자란다.
|
||||
|
||||
## 후보를 찾는 범위
|
||||
|
||||
접어 넣은 `final/document.md`가 전부 후보 자리는 아니다. **제1부(통합 분석)가 후보를 찾는
|
||||
범위**이고, 제2부(모듈 분석 전문)와 제3부(분석 재료)는 근거다. 제2부의 절 제목을 후보로 읽으면
|
||||
모듈 분석 편수만큼 글감이 늘어난다 — 접어 넣기 전에 있던 문제가 그대로 돌아온다.
|
||||
|
||||
범위는 기억하지 말고 계약에 적는다.
|
||||
|
||||
```json
|
||||
"candidateScope": {
|
||||
"document": "final/document.md",
|
||||
"sections": ["§3", "§4", "§5", "§6", "§7", "§8", "§9", "§10", "§11"],
|
||||
"excluded": ["제2부 — 모듈 분석 전문", "제3부 — 분석 재료"]
|
||||
}
|
||||
```
|
||||
|
||||
범위 밖의 앵커는 후보가 아니라 근거다. 제1부에서 나온 글감의 `source`로 건다.
|
||||
|
||||
## 왜 먼저 나누는가
|
||||
|
||||
@@ -10,6 +42,22 @@
|
||||
Reference의 칸도 반쯤만 맞는 기록이 나온다. 종류를 먼저 정하고 그 종류가 요구하는 것이 SSOT에
|
||||
있는지 확인해야 한다.
|
||||
|
||||
## 고르는 것이지 남김없이 내는 것이 아니다
|
||||
|
||||
분석에 빠진 것이 없는지 볼 때는 recall 100%가 맞다. 공개할 글을 정할 때는 아니다. 「분석에서
|
||||
보존할 가치」와 「독립된 글로 읽을 가치」는 다른 물음이고, 둘을 한 축으로 재면 분석 부산물이
|
||||
전부 글이 된다.
|
||||
|
||||
물음은 하나다.
|
||||
|
||||
> **이 기록을 없애고 관련 Case나 Concept의 한 절로 넣어도 이해·결정·재사용성이 그대로라면
|
||||
> 독립 기록으로 만들지 않는다.**
|
||||
|
||||
후보마다 처분을 적는다 — `PROMOTE` · `MERGE_INTO` · `KEEP_IN_SSOT` · `NEEDS_EVIDENCE` ·
|
||||
`NEEDS_DECISION` · `BLOCKED`. `KEEP_IN_SSOT`은 버린 것이 아니라 분석에 남기고 글로 만들지
|
||||
않기로 한 것이고, 그것도 정상적인 결과다. 자세한 것은
|
||||
`.agents/skills/deriving-tech-log-root-tree/references/candidate-disposition.md`.
|
||||
|
||||
## 한 건으로 자르는 단위
|
||||
|
||||
**절이 아니라 주장이다.** SSOT의 `##` 하나가 기록 하나가 아니다. 다음 넷 중 하나가 한 건이다.
|
||||
@@ -46,12 +94,20 @@ Reference 하나로 나누고 `관계`로 잇는다.
|
||||
**같은 관측을 두 건으로 쪼개지 않는다.** 「N+1이 났다」와 「그래서 몇 개가 나갔다」는 한 건이다.
|
||||
쪼개면 둘 다 반쪽이 된다.
|
||||
|
||||
**주제를 먼저 정한다.** Studio는 주제 아래에 다섯 종류를 나눠 보여 준다. 주제가 다르면 같은
|
||||
프로젝트여도 폴더가 갈린다. 주제 slug는 Studio의 것을 그대로 쓴다.
|
||||
**Concept은 거꾸로 뽑는다.** Case·Reference·Decision·Question을 먼저 고르고, 그것을 읽는 사람이
|
||||
미리 알아야 하는 구조가 있을 때만 Concept을 만든다. 메커니즘처럼 보이는 절을 훑어 채우면 어느
|
||||
기록도 필요로 하지 않는 개념이 쌓인다.
|
||||
|
||||
**주제 하나에 독자 질문 하나.** Studio는 주제 아래에 다섯 종류를 나눠 보여 준다. 그 주제의
|
||||
기록들이 함께 답하는 물음을 한 줄로 적고, 그 물음에 답하지 않는 글감은 다른 주제로 옮긴다.
|
||||
주제 slug는 Studio의 것을 그대로 쓴다.
|
||||
|
||||
## `tech-log-tree.json`
|
||||
|
||||
주제 → 종류 → 글감 순서로 담는다. 아직 쓰지 않은 글감은 `file` 없이 제목만 둔다.
|
||||
**주제·글감·`readiness`·`source`·`classification`·`relations`는 사람이 적는다.** 스크립트가
|
||||
채우는 것은 기록 파일에서 읽을 수 있는 넷뿐이다 — `file`·`publication`·`status`·`studioId`.
|
||||
주제 → 종류 → 글감 순서로 담고, 아직 쓰지 않은 글감은 `file` 없이 남는다. `readiness`는 증거가
|
||||
갖춰진 정도이고 `publication`은 Studio에 올렸는지다 — 둘은 다른 것이라 섞지 않는다.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -75,18 +131,23 @@ Reference 하나로 나누고 `관계`로 잇는다.
|
||||
}
|
||||
```
|
||||
|
||||
기록을 쓰거나 지운 뒤에는 다시 만든다. 스크립트는 기록 파일에서 값을 읽어 채우고, `file`이 없는
|
||||
글감은 지우지 않는다.
|
||||
기록을 쓰거나 지운 뒤에는 파생 칸을 다시 채운다. 사람이 적은 칸은 그대로 남는다. 디렉터리를
|
||||
훑어 주제를 만들지 않으므로, 계약에서 뺀 주제의 폴더가 남아 있어도 되살아나지 않고 `unlisted`에
|
||||
적힌다.
|
||||
|
||||
```bash
|
||||
python3 scripts/build-tech-log-tree.py [프로젝트]
|
||||
python3 scripts/verify-tech-log-tree.py [프로젝트] # error 0 이어야 한다
|
||||
```
|
||||
|
||||
## 순서
|
||||
|
||||
1. SSOT를 끝까지 읽는다. 절 제목만 훑지 않는다 — 수치와 근거가 어디 있는지 알아야 종류를 정한다
|
||||
2. 위 물음으로 글감을 나누고 주제를 정한다
|
||||
3. `tech-log-tree.json`에 제목만 적는다. 이때 글은 쓰지 않는다
|
||||
4. 글감 하나를 골라 `<주제>/<종류>/`에 기록을 쓴다. 형식은 `writing-each-kind.md`
|
||||
5. 트리를 다시 만든다
|
||||
6. Studio에 넣고 저장한다
|
||||
2. §3~§8에서 Case, §9에서 Reference, §10에서 Decision, §11에서 Question을 고른다
|
||||
3. 그 넷을 이해하는 데 필요한 Concept만 거꾸로 더한다
|
||||
4. 후보마다 처분을 적고, 사람이 다시 읽은 것만 `dispositionReview: CONFIRMED`로 둔다.
|
||||
`PROMOTE`이면서 `CONFIRMED`인 것만 글감이 된다
|
||||
5. 주제를 묶고 주제마다 독자 질문을 한 줄 적는다
|
||||
6. 글감 하나를 골라 `<주제>/<종류>/`에 기록을 쓴다. 형식은 `writing-each-kind.md`
|
||||
7. 색인을 다시 만들고 검사기를 돌린다
|
||||
8. Studio에 넣고 저장한다
|
||||
|
||||
@@ -67,6 +67,10 @@ evidence:
|
||||
- ../../../final/evidence/explain/highlights-child-plan-A.txt
|
||||
```
|
||||
|
||||
**`assets` 는 본문이 있는 Case 와 Concept 에만 둔다.** 나머지 세 종류는 칸이 평문으로
|
||||
렌더링돼 그림을 표시할 자리가 없다. 그림이 필요한 내용은 Case 나 Concept 에 담고 `관계`로
|
||||
가리킨다.
|
||||
|
||||
`assets` 는 Studio 에 올릴 파일이다. 아직 안 올렸으면 key 가 파일 이름과 같고, 올린 뒤에는
|
||||
서버가 준 `<이름>-<해시8>` 로 바뀐다. **Studio 에 넣을 때 이 목록을 보고 Asset 을 올리고,
|
||||
본문의 `:::evidence key` 를 서버가 준 키로 바꾼다.**
|
||||
@@ -145,6 +149,26 @@ subrequest 가 실어 보내는 것` 같은 것이 여기 온다.
|
||||
Case 와 헷갈리면 **내가 무엇을 했는지**를 묻는다. 내가 돌려 보고 수치를 얻었으면 Case, 남의 문서와
|
||||
코드를 읽고 동작을 정리했으면 Concept 이다.
|
||||
|
||||
### Concept 이 아닌 것
|
||||
|
||||
Concept 은 **어떤 Case 를 이해하려면 먼저 알아야 하는 구조**다. 그 Case 가 없으면 Concept 도
|
||||
없다. 분석하면서 알게 된 사실을 종류가 마땅치 않아 여기 넣지 않는다.
|
||||
|
||||
| 이런 제목 | 실제로는 |
|
||||
|---|---|
|
||||
| 호출자가 없다 · 프로덕션에서 실행되지 않는다 | 부재는 Case 의 관측이다 |
|
||||
| 구현 클래스 51개를 전부 읽었다 · 재현에 쓴 레인 | 분석 범위·방법. SSOT 의 coverage 원장에 남는다 |
|
||||
| 보류한 항목과 보류한 이유 | 분석 진행 기록. 같은 곳에 남는다 |
|
||||
| `grep refs=0` 은 시작점이지 결론이 아니다 | 분석 방법론. Reference 로 쓸 수 있으면 Reference 다 |
|
||||
| (8.4) 문서/구현 드리프트 — … · Confirmed — … | 분석 문서의 절 제목을 그대로 옮긴 것 |
|
||||
|
||||
한두 문장으로 Case 안에서 설명되는 것도 Concept 이 아니다. **없애고 Case 의 한 절로 넣어도
|
||||
이해가 그대로면 독립 기록으로 만들지 않는다.**
|
||||
|
||||
Concept 이 되는 것은 이런 것들이다 — `Spring 조립의 세 경로`, `@ConditionalOnBean 의 평가
|
||||
시점`, `커밋 증거 상태 전이`, `fenced lease 와 CAS`, `gRPC flow control 과 backpressure`.
|
||||
여러 Case 가 같은 선수 지식을 요구할 때 그것을 한 번만 설명하려고 만드는 자리다.
|
||||
|
||||
## Reference — 반복 적용할 기준
|
||||
|
||||
| 칸 | 필드 | 비고 |
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
- [ ] 종류가 내용과 맞는다 (`record-kinds.md`의 판단 흐름)
|
||||
- [ ] Question의 사실과 가정이 섞이지 않았다
|
||||
- [ ] Question이 `OPEN`이면 미지수가 있다
|
||||
- [ ] Question에 닫는 조건이 있다. 「더 알아본다」로 끝나지 않았다
|
||||
- [ ] Decision에 근거 기록이 1개 이상 연결됐다
|
||||
- [ ] Decision의 영향에 감수한 비용이 있다
|
||||
- [ ] Reference의 예시가 문장이다. 코드를 밀어 넣지 않았다
|
||||
@@ -53,6 +54,9 @@
|
||||
- [ ] `여지가 생긴다`·`소지가 있다` 대신 무엇이 어디로 가는지 썼다
|
||||
- [ ] 읽는 법을 지시하는 문장이 없다. `봐야 한다`·`여기까지다`·`먼저 본다`·`읽으면 안 된다`
|
||||
- [ ] 빼도 남은 뜻이 그대로인 문장이 없다
|
||||
- [ ] 설명 직후에 그 설명의 중요성을 평가하는 문장이 없다 (「~증거다」「~핵심이다」「서로를 대신하지 않는다」)
|
||||
- [ ] 독자가 오해할 것이라고 가정하는 문장이 없다 (「~로 읽기 쉽다」「~라고 생각하면 안 된다」)
|
||||
- [ ] 다음 절을 예고하거나 「~를 함께 적는다」처럼 작성 방법을 말하는 문장이 없다
|
||||
- [ ] 규칙 제목이 말한 것을 본문 끝에서 다시 지시하지 않았다
|
||||
- [ ] `싣는다`·`낸다`·`친다`·`짠다`를 실제 동작으로 풀어 썼다
|
||||
- [ ] 동사마다 목적어가 있다. `교환이 끝난다`처럼 무엇인지 빠지지 않았다
|
||||
@@ -74,6 +78,7 @@
|
||||
- [ ] Reference가 Case를 문장만 바꿔 옮기지 않았다
|
||||
- [ ] 현재 확인한 것과 운영에서 추가로 필요한 것을 나눴다
|
||||
- [ ] 테스트를 말할 때 무엇을 단정하는지 적었다
|
||||
- [ ] 어미·절·안내 문장의 수치는 참고만 했다. 맞추려고 문장을 넣지 않았다
|
||||
|
||||
## 본문 (Case)
|
||||
|
||||
@@ -101,6 +106,8 @@
|
||||
- [ ] Project가 필요하면 지정됐고, 그 Project에 slug가 있다
|
||||
- [ ] 관계의 대상이 실제로 있는 공개 기록이다
|
||||
- [ ] 코드·표·그림이 필요한 내용을 Reference나 Question에 밀어 넣지 않았다
|
||||
- [ ] 본문이 없는 세 종류에 `assets`를 선언하지 않았다
|
||||
- [ ] 이 글감의 후보가 `PROMOTE`이고 `dispositionReview`가 `CONFIRMED`다
|
||||
|
||||
## 마지막
|
||||
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
# Root Tree Contract
|
||||
|
||||
The root tree is the explicit boundary between deep project analysis and Tech Log record generation.
|
||||
|
||||
## Required document header
|
||||
|
||||
A root tree records:
|
||||
|
||||
- `schemaVersion`
|
||||
- `project`
|
||||
- `sourceDocument`
|
||||
- `sourceDocumentSha256`
|
||||
- `sourceRevision`
|
||||
- `generatedAt`
|
||||
|
||||
The hash/revision prevents a scheduled generator from treating a tree derived from old code as current.
|
||||
|
||||
## Required human-readable tree
|
||||
|
||||
Each Topic has a title, slug, and four branches:
|
||||
|
||||
```text
|
||||
PROJECT
|
||||
<project>
|
||||
|
||||
TOPIC
|
||||
<Topic title>
|
||||
<topic-slug>
|
||||
|
||||
├── CASE
|
||||
├── REFERENCE
|
||||
├── OPEN QUESTION
|
||||
└── DECISION
|
||||
```
|
||||
|
||||
Empty branches are allowed. Do not manufacture nodes to fill all four kinds.
|
||||
|
||||
## Node source contract
|
||||
|
||||
Every candidate includes a specification after the human-readable tree.
|
||||
|
||||
### Case
|
||||
|
||||
Required:
|
||||
|
||||
- `slug`
|
||||
- `readiness`
|
||||
- one or more `source` anchors
|
||||
- `classification` explaining the concrete incident/experiment/diagnosis
|
||||
- relevant code/evidence when the conclusion depends on them
|
||||
- `missing-verification`
|
||||
- `relations`
|
||||
|
||||
A Case with `NEEDS_EVIDENCE`, `BLOCKED`, or `REJECTED` is not generated.
|
||||
|
||||
### Reference
|
||||
|
||||
Required:
|
||||
|
||||
- `slug`
|
||||
- `readiness`
|
||||
- `source`
|
||||
- `classification` explaining the reusable criterion
|
||||
- `scope`
|
||||
- `exceptions`
|
||||
- `relations`
|
||||
|
||||
A Reference must be useful beyond retelling one Case. If removing the originating project's names leaves no rule, it is probably still a Case.
|
||||
|
||||
### Open Question
|
||||
|
||||
Required:
|
||||
|
||||
- `slug`
|
||||
- `readiness: OPEN`
|
||||
- `source`
|
||||
- `known`
|
||||
- `unknown`
|
||||
- `next-verification`
|
||||
- `decision-criterion`
|
||||
- `relations`
|
||||
|
||||
Do not generate a Question when the detailed analysis already contains a verified answer. Move the material to Case/Reference/Decision as appropriate and update the tree first.
|
||||
|
||||
### Decision
|
||||
|
||||
Required:
|
||||
|
||||
- `slug`
|
||||
- `readiness`
|
||||
- `decision-status`
|
||||
- `source`
|
||||
- `decision-evidence`
|
||||
- `grounds`
|
||||
- `classification`
|
||||
- `relations`
|
||||
|
||||
`decision-status` is one of `PROPOSED`, `ADOPTED`, `SUPERSEDED`, `NOT_DECIDED`. A `NOT_DECIDED` candidate uses `NEEDS_DECISION` and is not generated as a Decision.
|
||||
|
||||
## Readiness semantics
|
||||
|
||||
| readiness | meaning | generation |
|
||||
|---|---|---|
|
||||
| `READY` | grounded enough for the kind | allowed |
|
||||
| `NEEDS_EVIDENCE` | material assertion still lacks verification | blocked |
|
||||
| `NEEDS_DECISION` | direction sounds plausible but project has not decided | blocked |
|
||||
| `OPEN` | legitimate unresolved Question | allowed as Open Question |
|
||||
| `BLOCKED` | sources are incomplete or contradictory | blocked |
|
||||
| `REJECTED` | should not become a record | blocked |
|
||||
|
||||
## Derivation rules
|
||||
|
||||
1. Start from sections and evidence already present in detailed analysis; do not begin by brainstorming titles.
|
||||
2. Prefer several narrowly grounded Cases over one broad Case that combines unrelated incidents.
|
||||
3. Extract References only after identifying the invariant/selection criterion that survives outside the incident.
|
||||
4. Extract Questions from explicit uncertainty, missing verification, operational unknowns, or conflicting constraints.
|
||||
5. Extract Decisions only from explicit project choice evidence: ADR, commit/history, configuration plus recorded rationale, issue/PR decision, or user-supplied decision record.
|
||||
6. A node may relate to several siblings, but each record has one primary purpose.
|
||||
7. If new runtime evidence changes the answer, update detailed analysis and regenerate/review the tree before editing downstream records.
|
||||
@@ -0,0 +1,172 @@
|
||||
# Tech Log Tree Contract
|
||||
|
||||
`tech-log-tree.json` is the explicit boundary between deep project analysis and Tech Log
|
||||
record generation. **It is the decomposition contract and the index at once, and it is the
|
||||
source of truth.** There is one file, so nothing can disagree with it.
|
||||
|
||||
A finished `tech-log-studio/` holds `tech-log-tree.json` and the record folders. Nothing
|
||||
else.
|
||||
|
||||
A project whose index predates this contract fails verification with one error until it is
|
||||
migrated. The per-field checks stay off for such a project — "not written yet" must not read
|
||||
as "written wrong" — but non-adoption itself is counted, because a warning lets an old index
|
||||
avoid every check indefinitely.
|
||||
|
||||
## Required top level
|
||||
|
||||
- `schemaVersion`
|
||||
- `project`
|
||||
- `ssot` and `ssotSha256` — the hash prevents treating a tree derived from old material
|
||||
as current
|
||||
- `sourceRevision`
|
||||
- `generatedAt`
|
||||
- `sourceRepository` — `path`, `revision`, and `verified`: which checkout the analysis read,
|
||||
which commit the document describes, and how that was confirmed. Leave `revision` null rather
|
||||
than inventing one; the verifier warns instead of accepting a made-up label. When the work
|
||||
is spread over branches rather than one line of commits, use `revisions` — a label to commit
|
||||
map — and pin every tip the document describes
|
||||
- `candidateScope` — which part of the SSOT candidates may come from
|
||||
- `contract` — the decomposition rules, `readinessValues`, `dispositionValues`
|
||||
- `topics`, `candidates`, `counts`, `unlisted`
|
||||
|
||||
## Candidate scope
|
||||
|
||||
A folded `final/document.md` carries the integrated analysis, the module analyses, and the
|
||||
analysis material in one file. Only the first is candidate material.
|
||||
|
||||
```json
|
||||
"candidateScope": {
|
||||
"document": "final/document.md",
|
||||
"sections": ["§3", "§4", "§5", "§6", "§7", "§8", "§9", "§10", "§11"],
|
||||
"excluded": ["제2부 — 모듈 분석 전문", "제3부 — 분석 재료"]
|
||||
}
|
||||
```
|
||||
|
||||
`document` names the SSOT and must match `ssot`. `sections` names the candidate scope, and
|
||||
`excluded` names the parts that are evidence rather than candidates. A node may cite an
|
||||
anchor from an excluded part in `source`; it may not exist because of one.
|
||||
|
||||
## Topics
|
||||
|
||||
Each Topic has `topic` (its key), `title`, **`readerQuestion`**, and `kinds` with the five
|
||||
record kinds.
|
||||
|
||||
```json
|
||||
"oauth-oidc-auth-boundary": {
|
||||
"topic": "oauth-oidc-auth-boundary",
|
||||
"title": "OAuth 자격증명과 세션의 보관 경계",
|
||||
"readerQuestion": "자격증명과 세션을 누가 보관하고, 누가 API 요청을 만들며, 보호 자원은 무엇을 신뢰하는가?",
|
||||
"kinds": { "case": [], "concept": [], "reference": [], "question": [], "decision": [] }
|
||||
}
|
||||
```
|
||||
|
||||
Every node in the Topic must help answer the reader question. Two Topics do not share a
|
||||
question; one Topic does not need two. Empty kinds are allowed — do not manufacture nodes
|
||||
to fill all five.
|
||||
|
||||
## Candidates
|
||||
|
||||
Everything the analysis found lives in `candidates` with its disposition —
|
||||
`.agents/skills/deriving-tech-log-root-tree/references/candidate-disposition.md`. Only
|
||||
`PROMOTE` candidates become nodes under `topics`, and the relation runs both ways: a
|
||||
`PROMOTE` candidate whose target is not a node, and a node no `PROMOTE` candidate points
|
||||
at, are both contract errors.
|
||||
|
||||
`dispositionReview` records whether a person re-read the candidate under the independence
|
||||
test. `PENDING` means it reached the tree by recall alone, and a `PENDING` candidate is an
|
||||
error, not a warning — a record written over an unreviewed tree inherits the
|
||||
over-classification the disposition step exists to catch. Write records only for nodes
|
||||
whose candidate is `PROMOTE` and `CONFIRMED`.
|
||||
|
||||
## Written by hand, refreshed by script
|
||||
|
||||
`readiness` · `source` · `code` · `evidence` · `classification` · `relations` and the rest
|
||||
of each kind's fields are written by a person. `build-tech-log-tree.py` never touches them.
|
||||
It refreshes only what it can read from the record files — `file`, `publication`, `status`,
|
||||
`studioId`, `assets`, `evidenceFiles` — and lists records that have no node in `unlisted`.
|
||||
|
||||
### Case
|
||||
|
||||
`slug` · `readiness` · `source` · `classification` · `missing-verification` · `relations`,
|
||||
plus `code`/`evidence` when the conclusion depends on them.
|
||||
|
||||
One problem, an observation or reproduction, a diagnosis, a conclusion that closes. Several
|
||||
observations that answer the same question with the same conclusion are one Case with a
|
||||
table or sub-sections, not several partial Cases.
|
||||
|
||||
### Concept
|
||||
|
||||
`slug` · `readiness` · `source` · `basis-version` · `classification` · `relations`.
|
||||
|
||||
`basis-version` names what the explanation was written against — `Keycloak 26.7.0 identity
|
||||
brokering`, `Spring Boot 3.3 auto-configuration`. A Concept without it cannot be known to
|
||||
be stale.
|
||||
|
||||
A Concept exists because a Case, Decision, or Question needs it to be understood. Absence,
|
||||
call-counts, unwired subsystems, analysis scope, and coverage ledgers are not Concepts.
|
||||
|
||||
### Reference
|
||||
|
||||
`slug` · `readiness` · `source` · `classification` · `scope` · `exceptions` · `relations`.
|
||||
|
||||
A Reference must be useful beyond retelling one Case. If removing the originating
|
||||
project's names leaves no rule, it is still a Case.
|
||||
|
||||
### Open Question
|
||||
|
||||
`slug` · `readiness: OPEN` · `source` · `known` · `unknown` · `next-verification` ·
|
||||
`decision-criterion` · `relations`.
|
||||
|
||||
Do not create a Question when the analysis already contains a verified answer. Move the
|
||||
material to Case/Reference/Decision and update the tree first.
|
||||
|
||||
### Decision
|
||||
|
||||
`slug` · `readiness` · `decision-status` · `source` · `decision-evidence` · `grounds` ·
|
||||
`classification` · `relations`.
|
||||
|
||||
`decision-status` is `PROPOSED`, `ADOPTED`, `SUPERSEDED`, or `NOT_DECIDED`. A
|
||||
`NOT_DECIDED` candidate uses `NEEDS_DECISION` and is not written as a Decision.
|
||||
|
||||
## Readiness semantics
|
||||
|
||||
**`readiness` is about evidence, not about publication.** Whether a record has been
|
||||
written, and whether it has been saved into Studio, are separate facts that the generated
|
||||
index carries as `file` and `publication`. A published record with thin evidence is still
|
||||
`NEEDS_EVIDENCE`.
|
||||
|
||||
| readiness | meaning | generation |
|
||||
|---|---|---|
|
||||
| `READY` | grounded enough for the kind | allowed |
|
||||
| `OPEN` | legitimate unresolved Question | allowed as Open Question |
|
||||
| `NEEDS_EVIDENCE` | material assertion still lacks verification | blocked |
|
||||
| `NEEDS_DECISION` | direction sounds plausible but the project has not decided | blocked |
|
||||
| `BLOCKED` | sources are incomplete or contradictory | blocked |
|
||||
|
||||
`REJECTED` is not a readiness. Whether a candidate becomes a record at all is a
|
||||
disposition, and it lives in `candidates`, not on the node.
|
||||
|
||||
## Derivation rules
|
||||
|
||||
1. Discover candidates from `final/document.md` only. It is the whole analysis, folded in —
|
||||
there is no `analysis/` folder to search in a finished project.
|
||||
2. Give every candidate a disposition before writing any node. `KEEP_IN_SSOT` is a normal
|
||||
outcome, and a decomposition that excludes nothing has not selected anything.
|
||||
3. Apply the independence test: if folding the record into a related Case or Concept as
|
||||
one section changes nothing, it is not an independent record.
|
||||
4. Take Cases, References, Decisions, and Questions first; add Concepts backwards from
|
||||
what those four require.
|
||||
5. Prefer several narrowly grounded Cases over one broad Case combining unrelated
|
||||
incidents — but merge observations that share a question and a conclusion.
|
||||
6. Extract Decisions only from explicit choice evidence: ADR, commit/history, configuration
|
||||
plus recorded rationale, issue/PR decision, or a user-supplied decision record.
|
||||
7. A node may relate to several siblings, but each record has one primary purpose.
|
||||
8. If new runtime evidence changes the answer, update the analysis and revise the tree
|
||||
before editing downstream records.
|
||||
|
||||
## Generation and verification
|
||||
|
||||
```bash
|
||||
python3 scripts/build-tech-log-tree.py <project> # 파생 칸을 다시 채운다
|
||||
python3 scripts/verify-tech-log-tree.py <project> # error 0 이어야 한다
|
||||
```
|
||||
@@ -7,16 +7,18 @@
|
||||
Question 4·Decision 2), n+1liner 24건(Case 5·Reference 7·Question 5·Decision 7).
|
||||
「대개 이렇게 쓴다」는 말은 그 47건이 그렇게 돼 있다는 뜻이다.
|
||||
|
||||
`clean-architecture-backend-template` 의 949건은 다른 절 이름으로 쓰여 있었고 이 기준에 맞춰
|
||||
고쳤다. 올라간 적 없는 초안이 아니라 **올라간 것**이 기준이다.
|
||||
`clean-architecture-backend-template` 의 949건은 다른 절 이름으로 쓰여 있었고, 지금 이 기준으로
|
||||
다시 판정하는 중이다. 아직 기준을 만족한 상태가 아니므로 그 949건을 본보기로 삼지 않는다. 올라간
|
||||
적 없는 초안이 아니라 **올라간 것**이 기준이다.
|
||||
|
||||
## 파일 뼈대 — 다섯 종류가 같다
|
||||
|
||||
```markdown
|
||||
---
|
||||
id · kind · slug · title · topic · project · status · studio
|
||||
id · kind · slug · title · topic · topicName · project · status · studio
|
||||
source · sourceRevision
|
||||
(종류별) basisVersion · decisionStatus · questionStatus · lastVerifiedOn
|
||||
(있으면) assets · evidence
|
||||
(있으면) evidence · assets — assets 는 Case 와 Concept 만
|
||||
---
|
||||
|
||||
# 제목
|
||||
@@ -41,10 +43,13 @@ frontmatter 는 메타데이터, `##` 는 Studio 의 칸, 제목 아래 첫 문
|
||||
|
||||
```yaml
|
||||
source:
|
||||
- analysis/05-adapter-outbound-persistence-jpa.md#L354
|
||||
module: adapter-inbound-graphql
|
||||
- final/document.md#a05-adapter-outbound-persistence-jpa#L354
|
||||
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
||||
```
|
||||
|
||||
`source` 는 SSOT 의 앵커다. 분석을 접어 넣은 프로젝트에는 `analysis/` 가 없으므로 그 경로를 적으면
|
||||
가리키는 파일이 없다.
|
||||
|
||||
**관계 항목은 굵은 제목 한 줄 + 이유 한 줄**이다.
|
||||
|
||||
```markdown
|
||||
@@ -63,7 +68,9 @@ module: adapter-inbound-graphql
|
||||
| 검증 환경 | 런타임·버전·DB·측정 도구. `이름 : 값`으로 줄을 나눈다 |
|
||||
| 재현 조건 | 다른 사람이 같은 값을 얻는 순서. 번호를 매긴다 |
|
||||
|
||||
**본문은 5~12절, 대개 6절이다.**
|
||||
본문의 절은 하나의 주장과 그 근거가 이어지는 단위로 나눈다. 47건에서는 대개 여섯 절 안팎이었지만
|
||||
**절 수는 작성 조건이 아니다.** 숫자를 맞추려고 절을 쪼개거나 붙이면 문서마다 같은 모양이 된다.
|
||||
아래는 그 47건에서 실제로 반복된 순서다.
|
||||
|
||||
- **첫 절은 무대를 세운다.** 잰 코드나 구조를 먼저 보여 준다 — 「측정한 loadFeed 구현」,
|
||||
「무대 — 페이징 한 줄만 추가」, 「가시성을 얹기 전 — 인덱스로 커서 이후만」,
|
||||
@@ -75,7 +82,8 @@ module: adapter-inbound-graphql
|
||||
|
||||
그 마지막 절은 **본문 안**이다. 칸으로 빼면 Studio 에 그런 칸이 없어 사라진다.
|
||||
|
||||
코드블록에는 무엇을 보라는 한 줄을 붙인다. 표 앞이나 뒤에 그 표를 어떻게 읽는지 적는다. 예시는
|
||||
코드블록에는 라벨로 무엇인지 적는다. 표는 머리글이 무엇을 묻는지 말하게 하고, 그 표를 어떻게 읽는지
|
||||
설명하는 문장(「이렇게 갈린다」「함께 읽어야 한다」)은 두지 않는다. 예시는
|
||||
한 규모로 고정한다 — 표가 전체 계열을 이미 보여 준다.
|
||||
|
||||
## Concept — 6건
|
||||
@@ -90,7 +98,8 @@ basisVersion: Keycloak 26.7.0 · oidc-client-ts 3.3.0
|
||||
basisVersion: oauth2-proxy 7.15.2 · Nginx auth_request
|
||||
```
|
||||
|
||||
**본문은 5~8절, 대개 6절이다.**
|
||||
절의 개수를 정해 두지 않는다. 설명해야 할 참여자와 단계가 몇 개인지가 정한다. 47건에서 반복된
|
||||
순서는 이렇다.
|
||||
|
||||
- 첫 절은 무엇이 무엇을 주고받는지다 — 「두 개의 OAuth 왕복이 이어진다」,
|
||||
「Resource Server가 받는 입력」, 「요청 하나가 두 번 평가된다」
|
||||
@@ -128,6 +137,18 @@ basisVersion: oauth2-proxy 7.15.2 · Nginx auth_request
|
||||
`다음 검증`은 실행할 수 있는 문장으로 적는다. 「더 알아본다」로는 닫히지 않는다 —
|
||||
「seed(1000) 뒤 `ANALYZE highlights` 를 돌리고 Plan B 를 다시 잰다」처럼 적는다.
|
||||
|
||||
**그 아래 닫는 조건을 한 줄 붙인다.** 어떤 결과가 나오면 이 질문을 닫거나 Decision 으로 넘기는지
|
||||
적지 않으면 검증을 마쳐도 질문이 그대로 열려 있다. 계약의 `decision-criterion` 이 이 줄이다.
|
||||
|
||||
```markdown
|
||||
## 다음 검증
|
||||
|
||||
1. seed(1000) 뒤 `ANALYZE highlights` 를 돌리고 Plan B 를 다시 잰다
|
||||
|
||||
닫는 조건 : Plan B 의 실제 행 수가 추정치의 2배 안에 들어오면 닫고, 벗어나면 통계 갱신 주기를
|
||||
정하는 Decision 으로 넘긴다
|
||||
```
|
||||
|
||||
## Decision — 9건
|
||||
|
||||
칸은 **`근거`** · `결정문` · `판단 이유` · `영향`. **다른 넷과 달리 관계 절 이름이 「근거」다.**
|
||||
@@ -147,11 +168,13 @@ basisVersion: oauth2-proxy 7.15.2 · Nginx auth_request
|
||||
- 그림은 `technical-visualizer` 로 만든다. 손으로 SVG 를 그리지 않는다
|
||||
- 그림 안에는 이름만 넣는다. 문장은 `<desc>` 와 옆 문단에 둔다
|
||||
- 그림과 증거는 frontmatter 의 `assets` · `evidence` 로 잇는다. 같은 파일을 기록 옆에 복사하지 않는다
|
||||
- `assets` 는 본문이 있는 두 종류만 갖는다. Reference·Question·Decision 은 그림을 렌더링할 자리가
|
||||
없어서 선언해도 화면에 나오지 않는다
|
||||
- 본문은 `<!-- body:start -->` 와 `<!-- body:end -->` 사이다. 그 밖은 Studio 로 가지 않는다
|
||||
|
||||
## 관계를 어디서 가져오나
|
||||
|
||||
관계는 **다른 기록을 가리키는 링크**다. 지어내지 않는다. 분해 계약(`root-tree.md`)이 노드마다
|
||||
관계는 **다른 기록을 가리키는 링크**다. 지어내지 않는다. 분해 계약(`tech-log-tree.json`)이 노드마다
|
||||
`relations` 를 적어 두면 그것을 그대로 옮긴다.
|
||||
|
||||
계약이 관계를 적지 않은 노드는 한 가지 규칙만 쓸 수 있다 — **Reference 의 근거 사건은 같은
|
||||
|
||||
Reference in New Issue
Block a user