quad/.claude/session/2026-08-16-02-audit-tooling-verification-and-first-real-run.md
qwreey d23d46f746
docs: 감사 루프 4라운드에서 중단(사용자 결정) + 다음 세션 핸드오버 정리
수렴 조건(무발견 2연속)은 못 채웠으나 사용자 결정으로 중단. 발견 추이
6→5→2→2이고 3·4라운드분은 이 세션 변경의 stale이 아니라 코퍼스에 오래
있던 일반 부채(개수 하드코딩, 날짜 없는 시한부 주장)라, 계속 돌리면 수렴이
아니라 옛 부채를 끝없이 캐는 쪽이 된다는 판단. 이 세션 변경분 자체는
안정적(4라운드 설계 코퍼스 각도에서 확실 발견 0건).

todos.md 7번에 중단 사유와 "이번 미수렴 때문에 이어서 돌릴 필요 없음"을
명시하고, 세션 로그에 다음 세션 핸드오버 절(§18) 추가.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 04:05:05 +09:00

491 lines
32 KiB
Markdown

# 2026-08-16 두 번째 세션 — 감사 툴링 재시작 검증 + 핸드오버 감사 첫 실동
전 세션(`2026-08-16-01-subagent-audit-and-claudemd-split.md`)이 남긴
"재시작해야만 확인 가능한 것 3개"를 닫고, `quad-handover-audit` 워크플로를
처음으로 **실제로 감사가 도는 상태**에서 돌린 세션.
## 1. 재시작 검증 3건 — 전부 확인
| 항목 | 결과 | 근거 |
|---|---|---|
| `@import` 3개 로드 | ✅ | `conventions.md`/`project-context.md`/`todos.md` 내용이 실제 컨텍스트에 들어옴 |
| `quad-doc-auditor` 등록 | ✅ | 에이전트 목록에 잡힘. 전 세션 전멸(`agentType not found`)은 `.claude/agents/`가 세션 도중 생긴 디렉토리였던 탓 |
| frontmatter `model: sonnet` 반영 | ✅ | 서브에이전트 트랜스크립트에 `"model":"claude-sonnet-5"` 기록. 워크플로에 `opts.model` 명시 불필요 |
모델 확인은 처음에 "네 모델과 도구를 보고해라"는 프로브 에이전트로 시도했다가
**에이전트가 프롬프트 인젝션으로 판단해 거부**했다(원래 과업인 감사를 버리고
시스템 프롬프트를 덤프하라는 지시였으니 정당한 거부). 자기 보고 대신
트랜스크립트 파일을 직접 grep하는 쪽이 1차 증거라 더 낫다.
## 2. 워크플로는 `name`으로 부르면 스냅샷, `scriptPath`로 부르면 실시간
> **[읽는 순서 주의] 이 절의 "에이전트 정의" 관련 결론은 뒤에서 두 번
> 정정됐다** — 최신 상태는 이 문서 끝쪽(§10, §12)과
> `.claude/agents/quad-doc-auditor.md` 상단 배너를 볼 것. 여기 구체적인
> 결론을 다시 적지 않는 건, 그 결론이 이미 두 번 뒤집혔기 때문이다.
> **워크플로 쪽(`name` vs `scriptPath`) 관측은 그대로 유효하다.**
전 세션 감사 라운드들이 "캐시냐 frontmatter 무시냐"로 길게 갈라놨던 것을
좁히는 증거가 나왔다. 처음엔 이걸 "정의 파일은 세션 시작 스냅샷으로
고정된다(에이전트·워크플로 공통)"로 일반화해서 적었는데, **그건 증거보다
센 주장이었다** — `scriptPath` 경로를 테스트한 적이 없었다. 실제로 갈렸다.
- **`Workflow({name})` = 세션 시작 시점 스냅샷.** 이 세션에서
`.claude/workflows/quad-handover-audit.js`를 편집한 뒤 이름으로 돌렸는데,
런타임이 실제로 실행한 스크립트가 **세션 시작 시점 상태(= 당시 HEAD,
작업트리가 깨끗했음)와 바이트 단위로 동일**했다. 편집은 하나도 안 실렸다.
- **`Workflow({scriptPath})` = 디스크에서 실시간.** 세션 시작 후 **새로
만든** 프로브 스크립트(에이전트 0개)가 정상 실행됐고 — 스냅샷이라면
존재할 수 없다 — 그 파일을 고쳐 다시 부르니 고친 값이 그대로 돌아왔다.
**실무 규칙: 워크플로 정의를 고쳤으면 재시작하지 말고 `scriptPath`
호출할 것.** 이름으로 부르면 옛 정의로 돌면서 새 정의로 돈 것처럼 보인다 —
감사 도구에선 이게 조용한 거짓 초록불이다.
에이전트 정의 쪽은 **같은 등급의 증거가 없다** — 감사 에이전트들이 "받은
지시문에 그 세션에 추가된 배너가 없었다"고 보고했을 뿐이고 그건 자기
보고다(아래 Grep/Glob과 같은 등급). 에이전트엔 `scriptPath` 같은 우회가
없으니 확인 전까지는 보수적으로 **고쳤으면 재시작 뒤에 감사**를 따른다.
미해소로 남은 건 **읽기 전용인데 Write/Edit이 주어지는 원인** 하나.
`memory: project`를 뺐지만 그 뒤 재시작 없이 관찰한 것뿐이라 진단 미확정.
전 세션 감사가 남긴 **"Grep/Glob이 안 주어졌다"는 서술은 두 소스가 어긋나는
미해결 불일치**다 — 호출 세션이 보는 에이전트 등록 목록엔 Grep/Glob이
포함돼 있는데, 실행된 에이전트는 자기 도구를 Read/Bash/Write/Edit으로
보고했다. (처음엔 "자기 보고라 근거가 약하다"고 깎으려 했으나, 에이전트는
자기 함수 목록을 직접 볼 수 있으므로 그건 과한 판단이었다.) 어느 쪽도
확정하지 말고 Write/Edit 원인과 함께 재시작 직후 실행에서 볼 것.
## 3. "존재하지 않는 원칙 인용" 3건 — 재분류 결과 2건은 인용 오류였음
전 세션은 셋 다 같은 성격(가짜 원칙)으로 넘겼는데, 코퍼스 grep +
`git log -S`로 다시 보니 갈렸다.
- **`research/v1-compat-plan.md:50`** — 원칙 자체는 실재. 실제 소스는
`base/component-composition-plan.md` §1(자동 store 생성/자동 흡수 매직
폐기, 사용자 확정)과 `base/store-plan.md` "Store 값 설정 문법" 절
(`__newindex` 자동 위임 폐기). → 재조준.
- **`research/pre-implementation-audit.md:434`** — 역시 실재. 실제 소스는
루트 `ROADMAP.md`의 quad-debug 백로그 항목 + `question.md`. 다만
`research/debug-tooling-plan.md` 쪽은 더 약한 표현("존재 가능성만
인지")이라 그 온도차도 같이 적었다. → 재조준.
- **`base/modifier-plan.md:536`** — 이것만 **진짜로 출처가 없다.** 코퍼스
전체에도, `git log -S`로 본 `CLAUDE.md` 전 히스토리에도 그런 서술이
존재한 적 없다. 임의로 정하지 않고 날짜 붙인 대기 배너 + `question.md`
3번 항목(선택지 (a) `conventions.md`에 명문화 / (b) 지역 논거로만 유지)로
올려 **사용자 판단 대기**.
## 4. `quad-handover-audit` 첫 실동 — 6라운드, **수렴 실패**
에이전트 67개 / 라운드별 새 발견 **28 → 15 → 16 → 7 → 11 → 6**. 최대
라운드(6)를 소진할 때까지 새 발견이 마르지 않아 `converged:false`로 끝났다.
과거 수동 감사가 4~6라운드에 수렴했던 것과 다른 양상.
- 라운드 5에서 발견이 7→11로 **다시 늘었다** — 감사가 코퍼스를 훑는 순서/
관점이 라운드마다 달라서 생기는 것으로 보이고, 단조 감소를 전제한
`MAX_ROUNDS=6`이 이 코퍼스엔 부족하다는 신호.
- 이번 실행은 **위 2번 때문에 옛 스크립트로 돌았다**(이름으로 호출) — 즉 이
결과 자체가 그 함정의 사례다. 다음 실동은 `scriptPath`로.
- **마지막 라운드(6)의 새 발견 6건은 반영만 되고 재감사되지 않았다.**
수렴 조건을 못 채우고 최대 라운드로 끊겼기 때문이다. 그 6건을 포함한
diff 전체를 이 세션이 손으로 검토하고 핵심 주장(절 제목·archive 파일
존재·spikes 실제 개수)은 1차 근거로 확인했지만, **dry 라운드 하나가
주는 확인과 같지는 않다** — 다음 실동의 첫 임무가 이걸 재확인하는 것.
수정 품질 자체는 높았다. 실제로 잡힌 것 중 값진 것:
- `base/slot-plan.md:218`의 정정 배너가 "폐기로 정정됨"에서 멈춰 있었는데,
그 "폐기"가 2026-08-13에 **다시 뒤집혀** 지금 정본은 `retract`=언마운트다.
배너만 보고 지나가면 구현자가 옛 결론을 믿을 자리였다.
- `spikes 44개`류 하드코딩 개수가 여러 문서에 흩어져 있었는데 실제로는
48개(`00`~`43` + `21b`~`21e`)였다. 전부 "폴더가 소스"로 바꿈 —
`conventions.md`의 "개수·목록·상태는 소스를 하나만" 규칙 적용.
- `tools/doc-check.py` docstring이 1·2번 검사 심각도를 **실제 코드와 다르게**
적어놨던 것(둘 다 ERROR라 했지만 코드는 그렇게 동작한 적 없음). 검사
로직은 안 건드리고 서술만 정정.
## 5. 워크플로 스크립트 개선(다음 실행부터 적용됨)
- **반환값에 `findings` 배열 추가.** 기존엔 `roundLog`에 파일명·개수만 있어
커밋 전 diff 리뷰 때 "이 수정이 왜 들어갔는지"를 알 방법이
`journal.jsonl` 고고학뿐이었다.
- `totalFindingsFixed``findingsSentToFix`로 개명. "의심"으로 표시돼
반영 에이전트가 확인 후 건드리지 않은 것도 "고쳐짐"으로 세던 과대계상.
- 반영 에이전트에 `model: 'sonnet'` 명시(감사 패스는 frontmatter로 이미
sonnet, 반영 쪽만 메인 모델을 상속하고 있었음).
## 남은 것
- **`MAX_ROUNDS` 재검토 + 미재감사분 확인** — 수렴 실패가 재현되는지
`scriptPath` 호출로 재실동. 단조 감소 전제가 안 맞으니 "연속 dry 2회"
조건 자체도 같이 볼 것. 라운드 6의 미재감사 6건도 이때 걸러진다.
- **(d) Write/Edit 원인** — 다음 세션 시작 직후 확인.
- **`.claude/agent-memory/`** — 감사 에이전트가 스스로 쓰는 영속 메모리가
생겼고 지금 untracked. 커밋할지 `.gitignore`로 뺄지는 사용자 판단.
- **`modifier-plan.md:536` 원칙** — `question.md` 3번, 사용자 판단 대기.
## 6. [사용자 결정] 감사 루프 재설계 — 워크플로 폐기, 메인 일괄 처리
첫 실동 결과(에이전트 67개 / 4.6M 토큰 / 수렴 실패)를 보고 사용자가 구조
자체를 바꾸기로 함. **사용자 논거 그대로**:
> "토큰이 미친듯이 갈린다는거야. 차라리 감사 두개, 끝나면 한명이 일괄처리
> (보니까, 지금은 처리를 전부 분리해서 함. 이로 인해서 또 다시 부정확
> 문서가 생성될 수도 있고, 파일 겹침을 막기 위해서 너무 많은 처리를
> 수행함). 가 맞다고 생각해. 정확히는, 문제 사항을 처음 편집을 했던 최상위
> 에이전트가 받고, 검토 한 다음 처리하고 다시 2개 정도의 감사 에이전트를
> 돌리고, 마치 code-review 처럼 되는게 맞는듯."
>
> "이런 구조로 인해서 만일 유저의 판단이 필요해보이더라도, 에이전트들이
> 유저에게 입력 요구하기가 까다로움. 메인 에이전트다 하면 뭔가 애매하다
> 싶으면 바로 유저에게 보고하게 하는게 맞아보임"
정리하면 폐기 근거 셋 — (1) 토큰 과다, (2) 파일별 픽스 에이전트가 **또
부정확한 서술을 새로 생산**하고 파일 충돌 회피에만 처리를 낭비, (3)
서브에이전트는 사용자에게 못 물어서 판단이 필요한 항목이 임의 처리됨.
메커니즘은 사용자가 **Agent 직접 호출**을 골랐다(워크플로 유지안과 비교
제시 → "기계가 가장 적고 name/scriptPath 스냅샷 함정이 아예 사라짐" 쪽).
그래서 `.claude/workflows/quad-handover-audit.js`는 **삭제**됐고 절차는
`conventions.md` "작업 방식"이 소스가 됐다:
1. `quad-doc-auditor` 2개를 한 메시지에 병렬 호출
2. 메인이 두 리포트를 합쳐 검토하고 **수정도 메인이 일괄로** 수행
3. 애매하면 임의 처리 말고 **즉시 사용자에게 보고**
4. 새 발견 없는 라운드 2연속까지 반복, **수렴 못 하면 사용자에게 보고하고 멈춤**
5. `doc-check.py` ERROR 0 확인 후 커밋
감사 에이전트 정의에도 출력 형식에 **`사용자 판단`** 등급을 추가했다 —
`의심`에 묻지 말고 따로 빼라는 것(메인이 사용자에게 물을 수 있다는 게 이
구조의 핵심인데, 감사자가 애매한 걸 "이렇게 고치면 됨"으로 넘기면 그
강점이 죽는다).
## 7. [사용자 결정] 출처 없던 원칙 — (a) 명문화 + 새 인용 관례
`modifier-plan.md:536`이 인용해온 "드문 오용/가상 미래 요구까지
방어/최적화하려고 구조를 복잡하게 만들지 않는다"는 **선택지 (a) 채택**으로
`conventions.md`에 "설계 원칙" 절을 신설해 명문화했다.
**사용자 논거**: "(a) 하면 될것 같아. 그리고 추측하건데, 내가 세션 중
했던 말을 옮겨적지 않은 경우로 보이기도 함." — 즉 원칙 자체는 사용자가
실제로 세웠는데 문서화가 누락됐다는 판단.
여기서 파생된 요구로 **새 관례**를 `conventions.md`에 추가: 사용자 발언을
근거로 인용할 때 결론("사용자 확정")만 적지 말고 **무슨 논거로 그렇게
말했는지**까지 남길 것. 논거 원문은 `session/`에, 라이브 문서엔 결론 +
짧은 논거 + 세션 파일 포인터. 본보기는
`base/component-composition-plan.md` §1의 `**사용자 확정**("마법 안쓴다
그것도 동의함")` 패턴. 원칙·규칙을 세우는 발언이면 **그 자리에서**
명문화할 것 — 안 그러면 이번처럼 출처 없는 원칙을 후속 문서들이 인용하게
된다.
## 8. [실측] "감사자가 opus로 돈다"는 관찰 — 감사자가 아니라 픽스 에이전트였음
사용자가 "quad-doc-auditor가 opus로 돌고 있더라"고 지적해서 폐기된 워크플로
실행의 트랜스크립트를 전수 집계함(각 턴을 실제로 생성한 모델 = 최상위
`message.model` 기준):
| 에이전트 종류 | 모델 | 어시스턴트 턴 수 |
|---|---|---|
| `quad-doc-auditor` | `claude-sonnet-5` | 1550 |
| `general-purpose`(픽스) | `claude-opus-5` | 797 |
**감사자는 한 턴도 opus로 돈 적이 없다** — frontmatter `model: sonnet`
정상 반영된다. opus로 돈 건 **픽스 에이전트 49개**였고, 그게 4.6M 토큰의
주범이다. 픽스 쪽에 `model: 'sonnet'`을 명시하는 편집을 해뒀었지만 그
편집이 실린 스크립트가 실행되지 않았다 — 이름 호출 스냅샷 문제(§2)를
그대로 밟은 것. 지금은 픽스 에이전트 자체가 없어져 이 경로가 사라졌다.
**단, 감사자 트랜스크립트에도 `claude-opus-5` 문자열이 실제로 섞여 있다**
위치가 `message.usage.iterations[].model`이고 감사자 18개 중 14개에 각각
딱 한 번씩만 나온다(그 메시지의 최상위 `message.model`은 전부 sonnet).
사용량 회계 필드지 생성 모델이 아니다. **모델을 확인할 때 문자열 grep만
하면 여기서 오독한다** — 반드시 `message.model`로 집계할 것. 이 세션도
처음엔 `grep -o '"model":"..."'`로 확인했었고, 그 방법이 이 함정에
그대로 노출돼 있었다.
## 9. [사용자 결정] 감사 패스 수와 감사자 모델
- **패스 수**: "최소 2에, 변경 사항이 많아진다면 batch 수가 늘어나는게
맞다고 봄" — 고정 2가 아니라 변경 규모에 따라 스케일. 사용자 논거는
구조 설명 쪽이었음: "애초에 빠르게 전체를 훑는거고, 의견에 대한
사실검증은 상위자가 하니까. 빠르게 여러패스가 훑어지는게 유리한 구조임."
- **감사자 모델**: "haiku 는 쓰지 않는편이 나아보임" — sonnet 유지.
사용자가 별도 논거를 붙이지는 않았음(추측해 적지 않는다). 이 세션이
관측한 방증만 덧붙이면, 이번 감사가 잡아온 발견들은 문맥 추론이 꽤
들어간 것들이었다.
둘 다 `conventions.md`의 감사 루프 절차에 반영됨.
## 10. [재정정] §2의 "세션 시작 스냅샷"은 틀렸다 — *커밋된 HEAD*가 맞다
새 절차의 첫 감사 라운드에서 한 패스가 **자기가 받은 지시문이 blob
`92b9484`, 즉 그 시점 HEAD 커밋의 버전과 바이트 단위로 같다**고 보고했고,
메인 세션이 `git rev-parse HEAD:.claude/agents/quad-doc-auditor.md`로 독립
확인했다. 그 HEAD는 **세션 도중에 만든 커밋**(`1343796`)이지 세션 시작
시점(`8aeec76`)이 아니다. 따라서:
- 정의 파일은 **커밋될 때마다 갱신되고, 커밋 안 된 워킹트리 편집만 안
보인다.** §2가 관측한 워크플로 사례도 그때 HEAD가 곧 세션 시작 상태였을
뿐이라 이 설명과 모순되지 않는다(그 관측이 틀린 게 아니라 일반화가 틀렸음).
- 실무 규칙이 **"재시작"에서 "커밋"으로 싸졌다.** 워크플로엔 `scriptPath`
우회가 따로 있지만, 지금은 워크플로 자체를 안 쓰므로 규칙은 하나다 —
**정의를 고쳤으면 커밋한 뒤 감사를 돌린다.**
**이 정정이 (d)도 같이 풀었다.** "`memory: project`를 뺐는데도 Write/Edit이
그대로 주어진다"며 미확정으로 남겨뒀던 건, **그 제거가 아직 커밋 안 돼서
반영이 안 됐던 것**이다. 실제로 옵션이 빠진 정의가 커밋된 뒤 돈 감사자는
Write/Edit이 없었고 `.claude/agent-memory/`에 쓰기도 없었다(파일 mtime이
전부 그 이전 시각). 진단은 처음 것이 맞았다.
**남은 미해결은 `tools:` 필드**다 — frontmatter에 적힌 Grep/Glob이 실제로는
안 주어지고, 적지 않은 `advisor`가 주어진 라운드가 있었다. 그래서 감사자의
읽기 전용은 계속 **행동 규약**으로 지킨다.
교훈 하나: 이 정정은 감사자의 *자기 보고*에서 출발했다. 앞서 이 세션은
자기 보고를 "근거가 약하다"고 깎았다가 다시 "미해결 불일치"로 올렸는데,
이번엔 그 자기 보고가 **검증 가능한 형태**(blob 해시)로 왔기 때문에
메인이 1차 근거로 승격시킬 수 있었다. 자기 보고 자체가 약한 게 아니라
**대조 가능한 형태로 오는가**가 갈림점이다.
## 11. [사용자 결정] `.claude/agent-memory/`는 커밋해서 추적한다
**사용자 논거 원문**:
> "agent-memory 는 커밋해도 될것 같음. 실 기록이고 디펜던시도 아니고,
> 어차피 SAFETY.md 에 따라 구현 시점에는 컨테이너에서 개발되며 다른
> 프라이빗 git 에 올라가고 검토 후 머징되는거라, 문제되는 메모리 있으면
> 사람이 감사처리 마지막으로 함.(환경 노출 등?) 결국 프로젝트 사이드
> 기록이고 같이 올려지는게 맞는게, 개발 환경이 다수라서 필요해보임."
요지 세 가지 — (1) **개발 환경이 여러 개**라 에이전트 메모리가 레포를
따라다녀야 함, (2) 실 기록이고 빌드 디펜던시가 아니라 커밋 비용이 낮음,
(3) 환경 노출 같은 위험은 `SAFETY.md`가 규정한 파이프라인(컨테이너 개발 →
프라이빗 git → 사람 검토 후 머징)의 **마지막 사람 감사**가 최종 방어선.
메인 세션이 커밋 전에 절대경로/이메일/키/토큰 패턴을 스캔했고 노출 소지는
없었다(히트는 전부 frontmatter `name:`과 마크다운 링크). 커밋 전에 그 안의
낡은 결론 하나도 고쳤다 — `project_agent_prompt_caching_bug_reproduced.md`
아직 "캐시 가설"로 서술돼 있었는데 §10에서 이미 뒤집힌 것이라, 커밋된 HEAD
모델로 다시 쓰고 `MEMORY.md` 색인 줄도 같이 갱신(파일 이름은 그대로 두되
frontmatter `name`/`description`을 바꿈). 이 대응 자체가 README가 경고하던
"에이전트가 자기 메모리에 stale한 결론을 남긴다"의 실사례다.
## 12. [재재정정] §10의 "커밋된 HEAD"도 틀렸다 — 지금은 "모른다"가 정답
새 절차의 2라운드에서 감사자 **둘 다 독립적으로** 같은 반증을 가져왔다.
그들이 받은 정의 지시문은 **어느 커밋과도 일치하지 않는 하이브리드**였다:
상단 배너는 구버전(`1343796` 계열)인데 "출력 형식"의 `사용자 판단` 문단은
신버전(`07c77e5`에만 있음)이었다. 메인 세션이 독립 확인:
- `git log --all -S'당시 있던' -- .claude/agents/quad-doc-auditor.md`**커밋 없음**
- `07c77e5`에는 `사용자 판단` 있고 `당시 있던` 없음 / `1343796`에는 둘 다 없음
그들이 받은 텍스트는 메인 세션이 이 파일을 **여러 번에 나눠 편집하던 중간의
워킹트리 상태**(출력 형식 추가는 했고 배너 재작성은 아직 안 한 시점)와
일치하고, 그 상태는 **커밋된 적이 없다**.
| 실행 | 실제로 받은 정의 |
|---|---|
| 폐기된 워크플로 | 세션 시작 시점 상태 |
| 감사 1라운드 | 그 시점 HEAD 커밋(`1343796`)과 바이트 동일 |
| 감사 2라운드 | 어느 커밋과도 불일치 — 커밋된 적 없는 중간 워킹트리 상태 |
**즉 이 세션은 같은 문제에 세 번 결론을 냈고 앞의 둘이 다 틀렸다**(§2
"세션 시작 스냅샷", §10 "커밋된 HEAD"). 세 번째 가설을 세우지 않는다.
남기는 건 관측표와 실무 규칙 하나뿐: **정의를 고쳐도 반영됐다고 가정하지
말고, 중요하면 마커 문구를 넣어 감사자에게 물어 확인할 것** — 이 반증이
정확히 그 방법으로 나왔다(2라운드 프롬프트에 "출력 형식에 `사용자 판단`
문단이 있나"를 끼워 물었고, 그 답이 하이브리드를 드러냈다).
**교훈**: §10에 "자기 보고도 대조 가능한 형태면 1차 근거로 승격된다"고
적었는데, 이번엔 그 승격된 근거로 세운 결론이 또 틀렸다. 대조 가능한
자기 보고 하나는 **그 실행이 무엇을 받았는지**를 말해줄 뿐 **메커니즘이
무엇인지**를 말해주지 않는다 — 관측 하나에서 규칙을 일반화한 게 두 번
연속 실패의 공통 원인이다.
**(d) 결론은 살아남는다.** `memory: project` → Write/Edit 상관관계는
제거 이후의 후보 텍스트가 전부 그 옵션을 안 가지므로, 어느 텍스트가
실렸든 영향을 안 받는다(제거 이후 세 라운드 전부 Write/Edit 없음 +
메모리 주입 없음). 미해결로 남는 건 `tools:` 필드 미반영뿐.
## 13. [실측 재확인] 감사자 모델 — 다섯 실행 전부 sonnet
사용자가 "여전히 opus로 돈다"고 재지적해 2라운드 감사자 둘을 같은 방법으로
다시 집계했다. 최상위 `message.model` 기준:
| 실행 | sonnet 턴 | opus 턴 |
|---|---|---|
| 워크플로 시절 감사자 18개 | 1550 | 0 |
| 2라운드 A | 80 | 0 |
| 2라운드 B | 58 | 0 |
**감사자 턴은 전부 sonnet이다.** 다만 감사자 실행마다
`message.usage.iterations[]` 안에 `claude-opus-5` 항목이 **정확히 1개씩**
붙는다(그 메시지 자신의 `message.model`은 sonnet, 그 턴의 도구는 Bash).
감사자가 `advisor`를 부른 것도 아니다 — 도구 사용은 Bash/Read뿐이었다.
이게 정확히 무엇인지는 모른다(회계 항목으로 보임). **모델을 표시하거나
집계할 때 이 항목을 세면 "감사자가 opus"로 보인다.**
캐싱으로는 설명이 안 된다 — `model: sonnet`은 이 파일 **최초 커밋(`a1c0e44`)
부터** 있었으므로, 아무리 낡은 버전이 실려도 sonnet이다.
## 14. [해소] "감사자가 opus로 돈다"는 관측은 **뷰잉 이슈**였다
사용자가 서브에이전트 뷰에서 위로 스크롤하면 모델명이 opus로 보인다고
두 번 지적했고, 트랜스크립트 실측(다섯 실행 전부 sonnet)과 계속 어긋났다.
사용자가 직접 그 화면을 확인해 원인을 특정함 — **맨 위에 보이는 건
Claude Code 세션 헤더**다:
```
▐▛███▜▌ Claude Code v2.1.233
▝▜█████▛▘ Opus 5 · Claude Max
▘▘ ▝▝ ~/Desktop/quad
```
이건 **메인 세션의 모델**이지 서브에이전트의 모델이 아니다. 서브에이전트
뷰에서도 최상단엔 같은 세션 헤더가 나오므로, 위로 스크롤하면 무조건
상위 모델이 보인다. 사용자 표현대로 "이건 상위 네 모델을 의미".
이제 세 소스가 전부 일치한다 — 트랜스크립트 `message.model`(sonnet),
결과 출력 필드(sonnet), 세션 헤더(메인 모델, 서브에이전트와 무관).
**frontmatter `model: sonnet`은 정상 동작하며, 감사자는 sonnet으로 돈다.**
**교훈 — 이 조사에서 모델을 잘못 읽을 자리가 세 군데였다**:
1. `"model"` 문자열 grep → `message.usage.iterations[]`의 opus 항목에 낚임
(감사자 실행마다 1개씩 붙음, 그 메시지 자신은 sonnet, 정체는 미상)
2. 화면 최상단 배너 → 세션 헤더(메인 모델)라 서브에이전트와 무관
3. 폐기된 워크플로의 `general-purpose` 픽스 에이전트 49개는 **진짜로
opus**였음 — 같은 실행 안에 opus/sonnet이 섞여 있어 "어떤 건 sonnet으로
나온다"는 관측과 헷갈리기 쉬움
**신뢰할 소스는 하나**: 트랜스크립트의 최상위 `message.model`(원하면
`attributionAgent`로 어느 에이전트 몫인지까지 확인).
## 15. 감사 3라운드 — `agent-memory`가 정확히 사각지대였음
두 감사자가 **독립적으로 같은 확실 발견**을 가져왔다: `agent-memory/`
`project_agent_prompt_caching_bug_reproduced.md`가 "커밋된 HEAD에서 읽힌다"를
여전히 **확정 사실로** 서술하고 있었다. §12에서 그 결론을 반증해놓고,
그 정정을 담은 커밋(`1935dd4`)이 `agent-memory/` 아래를 **하나도 안 건드린**
것이다(`git show --stat`으로 감사자가 확인).
이건 이 감사 체계가 설계상 노리던 사각지대의 교과서적 사례다 —
`conventions.md`가 말하는 "변경한 세션 자신은 자기가 뭘 안 건드렸는지
모른다". 게다가 이 파일은 **같은 세션에 두 번 연속으로** stale이 됐다:
캐시 가설로 썼다가 → "커밋된 HEAD"로 고쳤는데 → 바로 다음 커밋이 그걸
뒤집었는데 또 안 따라옴. `agent-memory/`가 2026-08-16에 막 추적 대상이
돼서 아직 "이것도 코퍼스"라는 습관이 안 잡힌 탓이다.
고치면서 그 메모리가 **결론을 복제하지 않고 배너를 가리키게만** 바꿨다 —
같은 사실이 두 곳에 적혀 있으니 두 번 갈라진 것이라, 근본 원인을 없애는
쪽으로. 3라운드 A는 그 외에 `todos.md`의 매달린 포인터도 잡았다("아래 부수
확정 참고"인데 그 헤딩이 직전 라운드에 "미해결 1/2"로 개명됨).
**마커 확인 결과 — 관측표에 새 행**: 3라운드 감사자 **둘 다** 배너의
"재재정정" 낱말과 관측표를 받았고 디스크 현재 내용과 바이트 동일이라고
보고했다. 즉 **일관되게 낡은 게 아니다** — 어떤 실행은 최신을 받고 어떤
실행은 안 받는다. "모른다"를 유지할 근거가 하나 더 늘었고, 동시에
**마커 확인 방식이 실제로 작동한다**는 것도 재확인됐다.
부수적으로 둘 다 자기 모델을 "You are powered by the model named Sonnet 5.
The exact model ID is claude-sonnet-5."로 보고 — §13/§14의 트랜스크립트
실측과 일치.
## 16. 감사 4라운드 — 코퍼스는 깨끗, 대신 주입 경로 실측이 나옴
한 패스는 툴링, 다른 패스는 **설계 코퍼스**(`base/`/`research/`/`ROADMAP.md`)를
맡겼다. 이 세션이 툴링만 만졌으니 설계 쪽은 오래 안 훑인 영역이었다.
**설계 코퍼스 각도(B)** — 이 세션과 무관한 기존 항목 2건:
- `todos.md`가 "Handler 작성 체크리스트 **8개**", "우선순위1 **11개** 전원
완료"로 개수를 두 번째 장소에 하드코딩. 이 프로젝트 자신의 "개수는 소스
하나만" 규칙 위반이라 개수를 빼고 소스를 가리키게 함.
- `base/architecture.md``const` 미채택 사유에 날짜 없음 —
`doc-check.py`의 TEMPORAL 정규식이 못 잡는 자연어 변형("지금은 ~ 못해서").
감사 절차 7번이 노리는 유형이 실제로 걸린 사례. → 아래 §17.
감사가 확인만 하고 넘어간 것도 값졌다: `doc-check.py`
`dispatch-core-plan.md` 인용 WARN 클러스터 11곳을 직접 파본 결과 **전부 본문에
굵은 글씨 인라인으로 실존**했다(헤딩이 아니라 스크립트가 못 찾을 뿐).
그 문서가 최근 분리된 파일이라 "분리 후 인용자 안 따라옴" 패턴이 의심됐던
자리인데 콘텐츠 유실이 없음이 확인됐다.
**툴링 각도(A)** — 코퍼스 확실 발견 0건. 대신 주입 경로 관측 둘:
- 이번 라운드가 받은 **에이전트 정의**는 HEAD보다 정확히 1커밋 전이었다
(2라운드 같은 하이브리드는 아니었음). 관측표 4번째 행.
- **`CLAUDE.md` `@import` 컨텍스트는 세션 시작 시점에 고정된다** —
감사자가 받은 `conventions.md`/`todos.md`/`project-context.md`가 세션 시작
커밋(`8aeec76`)과 정확히 일치했고 그 사이 7커밋이 있었다. 감사자가
"메인 세션 컨텍스트도 그런지 확인해달라"고 요청해 메인이 자기 컨텍스트를
직접 확인 — **그렇다.** 이 세션의 메인은 삭제된 워크플로를 "먼저 돌릴 것"
이라 지시하는 옛 `conventions.md`와, 항목 6에서 끝나는 옛 `todos.md`
컨텍스트에 들고 작업해왔다(실제로는 파일을 직접 읽고 고치며 새 절차를
따랐으므로 행동에는 영향이 없었다).
이건 에이전트 정의 쪽의 "모르는 현상"과 달리 **경로가 다르고 동작이
명확한 것**이라 `conventions.md`에 규칙으로 적었다: **`@import` 파일을
고친 세션은 자기가 방금 쓴 규칙을 컨텍스트에서 못 보므로, 기억에
의존하지 말고 파일을 직접 `Read`해서 따를 것.**
## 17. [사용자 결정] `const` 미채택 재검토 — 에이전트가 정할 문제가 아니었음
감사가 "날짜만 붙일지, 구체적 트리거를 명시할지"를 사용자 판단으로 올렸는데,
사용자가 **전제 자체를 정정**했다.
**사용자 논거 원문**:
> "const 건은 생각보다 더 컴플랙스함. 예를 들어 pesde 의 타입추출화 해서
> d.ts 같이 types emit 하는 류가 있음. 아직 툴링이 미성숙한 상태라 const 를
> 제공 못하는 상황이고, 언제 다시 사용가능해지는지 명확치가 않음. 따라서
> 이는 사용자가 확인된 정보로 제공하는게 맞다고 보고 있음. 필요한 경우
> Human todo 에 해당 부분의 사용 가능해지는 시점을 파악하거나, 사용
> 가능해질 때 에이전트에 알려야할 필요를 명시해둬"
즉 "구체적 트리거"를 에이전트가 적어둘 수 없는 종류다 — pesde의 types emit
같은 툴링 체인의 지원 시점은 외부 사정이고 에이전트에 관측 수단이 없다.
그래서 `question.md`에서 닫고(→ `archive/question-resolved.md`)
**`HUMAN_TODO.md` 8번**으로 옮겼다: 사용자가 시점을 파악하거나, 사용
가능해질 때 에이전트에 알린다. **알려주기 전까지 에이전트는 스스로 판단하지
않고 "일단 `local`로" 원칙을 유지한다.**
## 18. 다음 세션에 넘기는 것
**감사 루프는 4라운드에서 사용자 결정으로 중단**(수렴 미달). 발견 추이
6→5→2→2, 3·4라운드분은 이 세션 변경의 stale이 아니라 코퍼스의 오래된
일반 부채였음. **이번 미수렴 때문에 이어서 돌릴 필요 없음** — 다음 세션이
중대 변경을 하면 그때 평소 절차대로.
**먼저 읽을 것**: `.claude/conventions.md`(이번에 크게 바뀜 — "설계 원칙"
절 신설, 감사 루프 절차 전면 재설계, "사용자 발언 인용 시 논거까지" 관례
신설, `@import` 신선도 주의) → `.claude/todos.md` 7번 → 필요하면 이 문서.
**M0 게이트는 여전히 없음** — 이 세션은 툴링만 만졌고 설계 결정은 안
건드렸다. 착수 전 필독은 그대로 `base/typing-limits.md`
`base/dispatch-core-plan.md`.
**사용자 대기 항목**:
- `HUMAN_TODO.md` 8번 — `const` 툴링 지원 시점(사용자가 알려줄 때까지
에이전트는 판단하지 말 것)
- `question.md` — 용어 정리 잔여, `Operator` 이름 등 기존 항목. 이번 세션이
새로 연 질문은 없음(연 것 둘 다 같은 날 닫힘)
**열린 툴링 미스터리 둘**(M0와 무관, 급하지 않음):
1. 서브에이전트 정의가 언제 반영되는지 모름 — 관측표는
`agents/quad-doc-auditor.md` 상단 배너. **세 번째 가설을 세우지 말 것**,
필요하면 마커로 확인.
2. `tools:` 필드 미반영(적힌 Grep/Glob 안 주어지고, 안 적은 `advisor`
주어짐).
**착수하지 말 것**: `session-summary.md` 자동생성 마이그레이션 — 사용자가
직접 다듬기로 한 항목(`research/doc-include-plan.md`).