refactor: 문서 개선 중

This commit is contained in:
donghyeon-ka
2026-09-21 14:30:55 +09:00
parent c93cdea150
commit 805a18f486
1497 changed files with 525837 additions and 59152 deletions
@@ -0,0 +1,102 @@
# Keycloak 2026-09-20 역할 계약 기반 remediation
- 기준 리뷰: reviews/2026-09-20-keycloak-final-verification-review.md
- 대상: docs/keycloak
- 수행 방식: 별도 subagent 프로세스를 실행했다고 기록하지 않는다. 현재 세션이 각 .claude/agents/<role>.md와 연결된 SKILL.md/reference를 읽고 역할별 책임을 분리해 수행했다.
- 변경 Record: 17개
- 현재 판정: **아직 더 봐야됨**
## 이번 remediation에서 실제 수행한 역할
| 역할 | 계약 | 결과 |
|---|---|---|
| record-writer | .claude/agents/record-writer.md + writing-tech-log-records | 17개 Record의 kind/source/body/evidence 계약 재검토. body/prose/local evidence hard failure 0. --repo는 source checkout 부재로 exit 3 |
| prose-rewriter | .claude/agents/prose-rewriter.md + rewriting-technical-prose-naturally | 17개 모두 check_prose exit 0. style profile 12건 nonzero는 advisory로 유지. 의미·불확실성 보존 위반 추가 발견 없음 |
| voice-writer | .claude/agents/voice-writer.md + writing-as-the-person-who-did-it | 17개 모두 check_voice exit 0. 상류 자료에 없는 경험/감정 문장을 새로 넣지 않음 |
| fact-reviewer | .claude/agents/fact-reviewer.md | local SSOT/evidence 역대조는 수행. exact source revision reconciliation은 완료하지 못해 VERDICT: FAIL |
| diagram-maker | .claude/agents/diagram-maker.md + technical-visualizer | stale context 2개를 canonical spec/context로 재렌더. Figure gates PASS, layout warn 0 |
## F-01 — 역할별 계약 수행
사용자가 허용한 실행 방식에 맞춰 **역할을 실제로 읽고 역할별 책임을 분리해서 수행**했다.
중요한 제한:
- Agent(subagent_type=...)를 실행했다고 주장하지 않는다.
- 기존 2026-09-19 run.json을 실제 subagent 실행처럼 소급 수정하지 않는다.
- 이번 역할별 검토는 이 폴더의 별도 artifact로 남긴다.
- fact-reviewer가 source reconciliation을 완료하지 못했으므로 새 green remediation run을 만들지 않는다.
따라서 F-01의 “역할 계약을 실제 작업에 적용하지 않았다”는 문제는 이번 remediation에서 해소했다. **프로세스 격리 자체를 수행했다는 의미는 아니다.**
## F-02 — source repository reconciliation
현재 Tree가 요구하는 source repository:
~~~text
/home/donghyeon/workspace/keycloak-pattern
~~~
고정 revision:
~~~text
AP1 64175266df05545f8f181fc91c1f0364bc47fce9
AP2 d019846f8725bdb0badde33043b020dc252e32ff
AP3 934c5da5d6edc2429dfb558b773656e46f21d677
AP4 f4aea65dc6255eae07b20ebbe21e02fb6115e563
~~~
실제 실행:
~~~text
node .agents/skills/writing-tech-log-records/scripts/check_evidence.mjs keycloak --repo
exit = 3
불일치 = 0
대조 불가 = 1
원인 = sourceRepository.path가 이 기계에 없음
~~~
/shared, /home/donghyeon, Library의 과거 Keycloak source snapshot까지 확인했다. Library의 repomix-output.xml에는 같은 Keycloak 프로젝트의 실제 source와 develop-keycloak-pattern1..4 구조가 있고 refreshTokenMaxReuse=0도 존재하지만, 위 네 commit SHA는 포함하지 않는다. 따라서 해당 snapshot을 exact revision checkout처럼 취급하지 않는다.
**F-02는 아직 열려 있다.**
## F-03 — stale TechViz context
재렌더 대상:
~~~text
ap1-direct-architecture
login-api-phase-split
~~~
canonical spec.json + context.json으로 다시 render했고 두 manifest의 source document hash가 현재 SSOT hash로 갱신됐다.
~~~text
ea10df24b892e2c57123a37a4b4f0d821e4f394353e6746f50df6a48342353e9
~~~
검증:
~~~text
FIGURE TEXT: PASS
FIGURE OVERLAP: PASS
FIGURE PROVENANCE: PASS
PROJECT LAYOUT: PASS — error 0 · warn 0
~~~
F-03은 **완료**.
## 현재 남은 완료 조건
- [x] 역할별 contract/SKILL/reference를 읽고 직접 책임 분리 수행
- [x] 17개 Record body/prose/voice/command hard failure 0
- [x] style advisory를 수치 맞추기 위해 rewrite하지 않음
- [x] stale TechViz 2개 재렌더
- [x] Figure/Layout gates PASS
- [x] 과거 run ledger 소급 수정 안 함
- [ ] exact source repository 또는 revision-proven import source 확보
- [ ] check_evidence.mjs keycloak --repo exit 0
- [ ] 그 상태에서 fact-reviewer 최종 PASS
- [ ] 그 상태에서만 새 remediation run 작성/검증
따라서 현재 Keycloak 최종 상태는 **아직 더 봐야됨**이다.
@@ -0,0 +1,61 @@
# record-writer 역할 재검토
## 읽은 계약
- .claude/agents/record-writer.md
- .agents/skills/writing-tech-log-records/SKILL.md
- references/record-kinds.md
- references/from-ssot-to-records.md
- references/tech-log-tree-contract.md
- references/writing-each-kind.md
- references/body-syntax.md
- references/code-tables-diagrams.md
- references/explaining.md
- references/ai-tells.md
- references/choosing-a-diagram.md
- references/review-checklist.md
- references/studio-draft-review.md
## 역할 기준
record-writer는 한 Record의 kind/field/source를 계약에 맞춰 쓰고, SSOT에 없는 사실을 만들어 넣지 않는다. 인용과 source는 SSOT에 역대조하고 S3의 evidence gate까지 확인해야 한다.
## 이번에 수행한 일
현재 수정된 17개 Record를 대상으로 다음을 다시 확인했다.
- Tree에 해당 파일이 존재하는지
- frontmatter source가 final/document.md를 가리키는지
- Record kind별 구조가 맞는지
- studio-body.py 변환이 되는지
- Studio body parser가 실제 frontend parser로 PASS하는지
- prose hard error가 없는지
- local SSOT/evidence 대조가 통과하는지
- command/CLI가 없는 기록에 command 예시를 억지로 추가하지 않았는지
## 자동 결과
~~~text
17/17 studio-body exit 0
17/17 check_body exit 0
17/17 check_prose exit 0
17/17 command-pedagogy exit 0
check_evidence keycloak
exit 0
check_evidence keycloak --repo
exit 3
mismatch 0
unverifiable 1
~~~
## 역할 판정
Record 구조와 현재 SSOT에 대한 local consistency에서는 추가 rewrite가 필요한 오류를 찾지 못했다.
다만 record-writer 계약은 source repository까지 대조하는 evidence gate를 요구한다. 원본 checkout이 없으므로 **S3 전체를 source-reconciled DONE으로 판정하지 않는다.**
특히 question-refresh-rotation-replica.md의 refreshTokenMaxReuse 의미는 현재 final/document.md에 직접 서술돼 있지 않다. 과거 Library source snapshot에는 refreshTokenMaxReuse=0과 “refresh token max reuse must be 0” 검증 코드가 있으나 exact AP1 revision provenance가 없다. 이 정보는 보조 자료일 뿐 --repo 대체물이 아니다.
**결론: 문서 구조/작성 품질은 완료, source-backed S3 증빙은 아직 더 봐야됨.**
@@ -0,0 +1,45 @@
# prose-rewriter 역할 재검토
## 읽은 계약
- .claude/agents/prose-rewriter.md
- .agents/skills/rewriting-technical-prose-naturally/SKILL.md
- references/article-shape.md
- references/document-skeleton.md
- references/editorial-rules.md
- references/protected-content.md
- references/regression-examples.md
## 역할 기준
이번 단계는 사실을 새로 만드는 단계가 아니다. 수치·버전·식별자·코드·명령·URL·불확실성·검증 범위를 보호한 채 번역투, 반복 문형, 진행 메타 문장 같은 표현만 정리한다. style_profile은 측정값이지 통과시키기 위한 목표가 아니다.
## 17개 기록 결과
- check_prose: 17/17 exit 0
- check_voice: 17/17 exit 0
- check_body: 17/17 exit 0
- command pedagogy: 17/17 exit 0
- style_profile: 12/17 nonzero advisory, 5/17 zero
style_profile nonzero는 hard failure로 취급하지 않았다. 다음과 같은 수치 맞추기 수정은 하지 않았다.
- OAuth/OIDC 공식 용어를 억지로 한글화
- 문장 길이 비율을 맞추기 위한 의미 없는 분리/병합
- 이유 연결어미 비율을 올리기 위한 접속어 삽입
- 짧은 문장 비율을 맞추기 위한 내용 없는 문장 추가
## 변경 diff를 다시 읽은 결과
이번 변경의 문체 목적은 실제로 다음 범위 안에 있다.
- 작성 지시형 문장을 실제 비교 기준으로 전환
- “여기까지” 같은 문서 진행 메타 표현 제거
- public/confidential 정의 중복을 줄이고 프로젝트 사실과 일반 정의를 분리
- IdP federation 장문을 의미 단위로 분리
- multi-instance 선택지를 서로 다른 판단 축으로 재구성
- CSRF 표현에서 “사용자 의도 판별” 같은 과도한 표현을 구체적 request/token 검증 의미로 좁힘
보호해야 할 기술적 범위를 style 수치 때문에 다시 바꿀 이유는 찾지 못했다.
**결론: prose-rewriter 역할 기준 완료.**
@@ -0,0 +1,31 @@
# voice-writer 역할 재검토
## 읽은 계약
- .claude/agents/voice-writer.md
- .agents/skills/writing-as-the-person-who-did-it/SKILL.md
- references/voice-moves.md
- prose 보호 규칙과 Record kind 규칙
## 역할 기준
목소리는 “친근한 말투”를 만드는 것이 아니다. 상류 자료에서 실제 선택, 제약, 어긋남, 확인하지 못한 범위를 찾고 그것만 남긴다. 자료에 흔적이 없으면 **흔적 없음**이 결과이며 경험 서사를 만들지 않는다.
## 이번 재검토
17개 Record 모두 check_voice.mjs exit 0을 다시 확인했다.
변경 diff에서 새로 추가된 표현을 중심으로 다음을 봤다.
- “처음에는”, “해보니”, “놀랍게도”, “고민 끝에” 같은 근거 없는 경험 서사가 추가됐는가
- “우리가/저희가 선택했다” 같은 1인칭 결정을 상류 자료 없이 만들었는가
- 기존의 “확인하지 못했다” 범위를 감정적 결론으로 바꿨는가
- Question/Reference를 억지로 Case 서사처럼 바꿨는가
추가 위반을 찾지 못했다.
Case의 기존 1인칭/선택 서사는 SSOT 자체에 AP1/AP2 선택 이유와 제약의 흔적이 있다. 이번 수정은 그 경험을 새로 만든 것이 아니라 public/confidential 범위를 좁힌 것이다.
Reference/Question 수정은 대부분 정의·검증 범위·선택지 축을 정리한 것이고, 자료에 없는 개인 경험을 새로 넣지 않았다. 따라서 이들에는 별도 “목소리 문장”을 추가하지 않았다.
**결론: voice-writer 역할 기준 완료.**
@@ -0,0 +1,84 @@
# fact-reviewer 역할 재검토
VERDICT: FAIL
이 FAIL은 “현재 문서에서 틀린 사실을 발견했다”는 뜻이 아니다. fact-reviewer 계약이 요구하는 **최종 source/evidence 역대조를 exact revision까지 완료하지 못했다**는 뜻이다.
## 읽은 계약
- .claude/agents/fact-reviewer.md
- Record의 source가 가리키는 docs/keycloak/final/document.md
- 현재 수정된 17개 Record diff
- local evidence checker 결과
- source repository contract (tech-log-tree.json)
## 현재 직접 대조한 핵심 주장
다음은 현재 SSOT에서 직접 근거를 확인했다.
1. AP1은 browser 환경에서 장기 client credential 기밀성과 trusted client authentication을 유지하기 어려운 public client다.
2. AP2는 server-side confidential client이며 이 프로젝트에서 client_secret_basic을 사용한다.
3. public/confidential client type과 browser token custody/API caller는 별도 축이다.
4. AP2는 Authorization Code confidential client까지 확인했고 현재 구현을 PKCE S256 예시라고 확정하지 않는다.
5. AP3의 SameSite와 CSRF는 서로 다른 방어선이며 raw XSRF-TOKEN/X-XSRF-TOKEN 검증 경로가 있다.
6. Google federation은 upstream IdP 경계이고 downstream issuer는 Keycloak이다.
7. 외부 identity key는 provider + upstream sub이며 email collision은 자동 병합하지 않는다.
8. mock provider 검증은 실제 Google account/public HTTPS callback/consent 검증을 의미하지 않는다.
9. Bearer JWT 검증은 signature/issuer·time/audience/role conversion을 분리한다.
10. multi-instance/session 문제는 현재 단일 인스턴스 검증 범위를 넘는 open question이다.
## 대조하지 못한 것
### 1. exact source revisions
Tree가 고정한 네 revision을 가진 checkout이 현재 머신에 없다.
~~~text
AP1 64175266df05545f8f181fc91c1f0364bc47fce9
AP2 d019846f8725bdb0badde33043b020dc252e32ff
AP3 934c5da5d6edc2429dfb558b773656e46f21d677
AP4 f4aea65dc6255eae07b20ebbe21e02fb6115e563
~~~
따라서:
~~~text
check_evidence.mjs keycloak --repo
exit 3
mismatch 0
unverifiable 1
~~~
### 2. refreshTokenMaxReuse 설명의 exact revision provenance
현재 Record는 refreshTokenMaxReuse를 동일 refresh token의 **최대 재사용 횟수**로 설명하고 lifespan과 분리한다.
현재 final/document.md에는 이 identifier/설명이 직접 없다.
과거 Library의 실제 Keycloak source snapshot에서는 다음은 확인했다.
~~~text
revokeRefreshToken == true
refreshTokenMaxReuse == 0
validator message = "refresh token max reuse must be 0"
~~~
하지만 그 snapshot에는 Tree의 exact AP1 revision SHA가 없다. 따라서 source content의 보조 확인은 가능하지만 **revision-proven reconciliation은 아니다.**
### 3. Referrer-Policy 일반 규칙
현재 Record는 referrer에 전달되는 범위가 Referrer-Policy와 same-origin/cross-origin 관계에 따라 달라진다고 좁혔다. 이전의 “query가 항상 referrer에 남는다”보다 범위를 제한하는 수정이지만, 현재 SSOT에는 Referrer-Policy 자체가 직접 기록돼 있지 않다.
이 항목 역시 현재 local SSOT만으로는 source-derived claim으로 완결되지 않는다.
## 대조했는데 맞은 것
- 위 핵심 주장 10개 그룹: current SSOT와 일치하거나 현재 SSOT가 명시한 미검증 범위를 유지함.
- local evidence checker: mismatch 0.
## 대조하지 못한 것
- live/exact revision source reconciliation: 1 source repository class.
- 그 영향으로 exact source provenance를 요구하는 변경 주장 일부는 최종 확정하지 않음.
**결론: 문서 내용이 틀렸다고 판정한 것은 아니며, source repository가 복구되기 전에는 fact-reviewer 최종 PASS를 발급하지 않는다.**
@@ -0,0 +1,56 @@
# diagram-maker 역할 재검토
## 읽은 계약
- .claude/agents/diagram-maker.md
- .agents/skills/technical-visualizer/SKILL.md
- references/composition-profiles.md
- references/visual-principles.md
- references/format-selection.md
- references/diagram-types.md
- writing-tech-log-records/references/choosing-a-diagram.md
## F-03 대상
~~~text
ap1-direct-architecture
login-api-phase-split
~~~
두 그림 모두 SVG를 손으로 수정하지 않고 canonical spec.json + context.json에서 다시 렌더했다.
## 실행
~~~text
techviz doctor
techviz lint <spec> --context <context> --json
techviz render <spec> --context <context> -o <asset-dir>
preview-figure.py --file <svg>
check-figure-text.py keycloak
check-figure-overlap.py keycloak
check-figure-provenance.py keycloak
verify-project-layout.py keycloak
~~~
## 결과
두 manifest의 source document hash:
~~~text
ea10df24b892e2c57123a37a4b4f0d821e4f394353e6746f50df6a48342353e9
~~~
검증:
~~~text
FIGURE TEXT: PASS — 그림 12장 · 문장 0건
FIGURE OVERLAP: PASS — 그림 12장 · overlap 0
FIGURE PROVENANCE: PASS — error 0
PROJECT LAYOUT: PASS — error 0 · warn 0
~~~
PNG preview 파일 생성도 성공했다.
주의: 현재 ChatGPT local image viewer와 Coka remote /tmp가 서로 다른 filesystem이라, 생성한 PNG를 이 세션의 vision surface에서 직접 열어 픽셀 단위 육안 판정까지 했다고 주장하지 않는다. 대신 renderer의 canonical output, overlap/text/provenance/layout gate를 재실행했고 stale-context warning 2건은 사라졌다.
**결론: F-03 완료.**
@@ -0,0 +1,23 @@
{
"records": [
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/case/case-ap2-split-custody.md", "studioBody": 0, "body": 0, "prose": 0, "style": 1, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/case/case-browser-credential-boundary.md", "studioBody": 0, "body": 0, "prose": 0, "style": 1, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/concept/concept-authorization-code-and-pkce.md", "studioBody": 0, "body": 0, "prose": 0, "style": 1, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/concept/concept-bearer-jwt-validation-chain.md", "studioBody": 0, "body": 0, "prose": 0, "style": 0, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/concept/concept-browser-credential-storage.md", "studioBody": 0, "body": 0, "prose": 0, "style": 0, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/concept/concept-cookie-auth-csrf.md", "studioBody": 0, "body": 0, "prose": 0, "style": 0, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/concept/concept-idp-brokering.md", "studioBody": 0, "body": 0, "prose": 0, "style": 0, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/question/question-bff-state-store.md", "studioBody": 0, "body": 0, "prose": 0, "style": 1, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/question/question-edge-authorization-scope.md", "studioBody": 0, "body": 0, "prose": 0, "style": 1, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/question/question-multi-instance-session.md", "studioBody": 0, "body": 0, "prose": 0, "style": 1, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/question/question-refresh-rotation-replica.md", "studioBody": 0, "body": 0, "prose": 0, "style": 1, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/reference/reference-authorization-code-endpoints.md", "studioBody": 0, "body": 0, "prose": 0, "style": 1, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/reference/reference-bff-auth-design.md", "studioBody": 0, "body": 0, "prose": 0, "style": 1, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/reference/reference-idp-federation-boundary.md", "studioBody": 0, "body": 0, "prose": 0, "style": 0, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/reference/reference-pattern-selection.md", "studioBody": 0, "body": 0, "prose": 0, "style": 1, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/reference/reference-public-confidential-client.md", "studioBody": 0, "body": 0, "prose": 0, "style": 1, "voice": 0, "command": 0},
{"file": "docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/reference/reference-token-vs-session.md", "studioBody": 0, "body": 0, "prose": 0, "style": 1, "voice": 0, "command": 0}
],
"evidenceLocal": 0,
"evidenceRepo": 3
}