[업무일지] 정정해도 되살아나던 AI 하네스 지침과 철회 목록
모니터링 도구 연결을 확인하는 방법이 틀렸다고 검증해 놓고도, 그 방법이 팀 AI 하네스의 커맨드 문서 세 곳에 2주 넘게 남아 있었습니다. 검증 결과를 제 개인 메모리에만 적어 둔 탓에, 팀원 세션의 에이전트는 계속 옛 지침을 따랐습니다. 반증된 주장을 레포에 목록으로 두고 다시 나타나면 CI 를 실패시키게 했는데, 그 뒤 2주 남짓 사이에 스캔 경계 밖에서 두 번 더 샜습니다.
검증한 결론이 개인 메모리에만 있었다
저희 팀은 장애 분석이나 설계 검토를 AI 에이전트(Claude Code)와 같이 하는 분석 워크스페이스를 레포 하나로 운영합니다. 에이전트가 매번 같은 절차를 밟도록 적어 둔 지침 파일, 커맨드 문서, 검사 스크립트를 묶어 하네스라고 부르고요. 분석 결과는 같은 레포에서 사내 위키로도 발행하고, 커맨드 문서만 스무 개가 넘습니다.
그중 로그 조회 커맨드는 시작하자마자 모니터링 도구가 이 세션에 붙어 있는지부터 확인합니다. 확인 방법은 claude mcp list 를 돌려 ✔ Connected 가 뜨는지 보는 것이었고요.
7월 말에 이 방법이 틀렸다는 걸 확인했습니다. 저희는 MCP 서버를 컨테이너로 띄우는 방식으로 등록해 두는데, 목록 명령은 그 컨테이너를 매번 새로 띄워 handshake 한 결과를 찍습니다. 지금 세션에 그 서버의 도구가 실제로 올라와 있는지와는 별개입니다. 그래서 목록에는 Connected 가 뜨는데 세션에서는 도구를 못 찾는 일이 생기거든요. 세션 기준으로 보려면 에이전트가 그 서버의 도구를 실제로 찾을 수 있는지로 판정해야 합니다.
문제는 이 결론을 적은 자리였습니다. 저는 그걸 Claude Code 의 개인 메모리에 적었습니다. 제 세션은 그 뒤로 맞게 판정했죠. 커맨드 문서는 그대로였고요.
8월 14일에 하네스를 정리하다가 같은 지침이 커맨드 세 곳에 살아 있는 걸 봤습니다. 에러 분석, 로그 조회, 서비스 상태 점검이었습니다. 팀원이 그 커맨드를 돌리면 에이전트는 문서에 적힌 대로 목록 명령을 믿습니다. 틀렸다는 사실은 제 로컬 메모리 파일 안에만 있었으니까요.
같은 주에 비슷한 게 하나 더 나왔습니다. 전날 에이전트가 매 세션 읽는 지침 파일(CLAUDE.md)에서 “작업 레포는 develop 에 머지하니까 PR 본문의 Closes #N 으로 이슈가 자동으로 닫히지 않는다”는 서술을 고쳤습니다. 서비스 코드가 있는 작업 레포들의 기본 브랜치가 develop 이라 자동 close 는 멀쩡히 동작하고 있었습니다. PR 을 머지하고 1초 뒤에 이슈가 닫히는 걸 보고 고친 겁니다. 그런데 주간 점검 스크립트의 헤더 주석에는 그 틀린 전제가 그대로 있었습니다.
두 건은 모양이 같습니다. 한 곳에서 정정했고, 나머지로 퍼지지 않았습니다. 누가 우연히 다시 들여다보지 않으면 계속 남습니다.
메모리는 쓴 사람만 보호한다
AI 도구의 메모리는 개인 것입니다. 제 머신에서 도는 제 세션이 읽고, 팀원 세션은 읽지 않습니다. 팀이 같이 보는 건 레포에 커밋된 하네스뿐이죠.
그러니 교훈을 메모리에 적으면 고쳐지는 건 제 세션 하나입니다. 문서는 틀린 채로 남고, 다른 사람의 에이전트는 그 문서를 따릅니다. 더 곤란한 건 제 쪽에서는 문제가 안 보인다는 점입니다. 제 세션은 맞게 동작하니까, 제가 커맨드를 돌려서는 이 결함을 재현할 수가 없습니다.
정정은 제 메모리 안에만 있고, 팀원 에이전트는 공용 문서의 옛 지침을 따른다
그래서 반증된 주장을 레포 안의 공용 목록으로 옮기기로 했습니다. 코드에서는 RETRACTIONS 라는 배열이고, 이 글에서는 철회 목록이라고 부르겠습니다. 그 주장이 하네스 어딘가에 다시 나타나면 PR 검사를 실패시키고요. 누가 발견해 주기를 기다리지 않겠다는 겁니다.
반증된 주장을 목록으로 두고 CI 에서 실패시킨다
체커는 Node.js 스크립트 하나이고, 이 레포의 PR 검사 워크플로에 단계 하나로 붙였습니다(GitHub Actions, Node 24). 아무것도 고치지 않습니다. 찾아서 보여주고 종료코드로 PR 을 막을 뿐입니다. 철회 목록의 항목 하나는 이렇게 생겼습니다.
1
2
3
4
5
6
7
8
9
10
11
12
// Node 24 · 하네스 정합성 체커의 철회 목록 (2026-08-14 첫 항목, 메시지는 줄여 옮김)
const RETRACTIONS = [
{
id: 'mcp-list-as-session-check',
pattern: /claude mcp list/, // 반증된 주장이 드러나는 표현
scope: /^(CLAUDE\.md|\.claude\/commands\/.*\.md)$/, // 어디서 찾을지
allow: ['.claude/commands/<도구>/setup.md'], // 서버 등록 커맨드에서는 정당한 사용
verified: '2026-07-28 실측 · 2026-08-14 재확인', // 무엇으로 반증했는지
okIf: /아니다|오진|판정하지 않는다|쓰지 않는다|⚠️/, // 인용해서 경고하는 문장은 통과
message: '목록의 Connected 는 세션 도구 등록 상태가 아니다. 세션에서 도구가 잡히는지로 판정할 것.',
},
]
검사 본체는 단순합니다. 대상 파일을 줄 단위로 읽어서, pattern 에 걸렸는데 okIf 에는 안 걸린 줄을 위반으로 냅니다.
1
2
3
4
5
6
7
8
for (const r of RETRACTIONS) {
if (!r.scope.test(file) || r.allow.includes(file)) continue
lines.forEach((line, i) => {
if (!r.pattern.test(line)) return
if (r.okIf && r.okIf.test(line)) return // 같은 줄에 정정 문구가 있으면 통과
found.push({ id: r.id, file, line: i + 1, message: r.message, verified: r.verified })
})
}
설계의 핵심은 okIf 입니다. 반증된 표현을 인용해서 경고하는 문장까지 잡으면 정정문 자체를 쓸 수가 없거든요. 로그 조회 커맨드를 고친 문장이 딱 그렇습니다.
⚠️
claude mcp list의✔ Connected는 세션 도구 등록 상태가 아니라 (…) 오진한다.
이 줄에도 claude mcp list 가 들어 있습니다. 이걸 위반으로 잡으면 체커가 정정문을 지우라고 요구하는 꼴이 됩니다. 다시 들어온 옛 지침에는 이런 부정 표현이 붙지 않으니, 같은 줄의 부정 표현으로 둘을 가를 수 있다고 봤습니다.
verified 는 비워 둘 수 없게 했습니다. 무엇을 어떻게 실측해서 틀렸다고 판단했는지 적는 칸입니다. 근거 없이 “이 표현 금지”만 남아 있으면 다음 사람은 이유를 모르니 되돌리거나 무시할 거라 봤습니다. CI 로그에도 메시지 아래에 이 근거가 같이 찍힙니다.
scope 는 처음에 커맨드 문서만 봤다가 같은 날 CLAUDE.md 를 넣었습니다. CLAUDE.md 는 매 세션 자동으로 로드되니, 틀린 지침이 거기 다시 들어가면 피해가 제일 넓은 자리죠.
일부러 뺀 곳도 있습니다. 작업 이력 아카이브는 스캔하지 않습니다. 그 문서들은 “그때 그렇게 믿었다”는 기록이라, 나중에 반증된 표현이 남아 있는 게 정상입니다. 거기까지 고치라고 하면 이력을 고쳐 쓰게 됩니다. 도메인 레퍼런스 문서도 뺐습니다. 레퍼런스 문서가 실제 코드와 맞는지는 위키 점검 커맨드가 따로 보고 있어서, 검사 둘이 같은 문서에 다른 판정을 내는 상황을 만들고 싶지 않았습니다.
CLAUDE.md 는 지우지 않고 옮겨서 줄였다
같은 작업에서 CLAUDE.md 도 손봤습니다. 33.1k자까지 불어 있었거든요. 매 세션 통째로 읽히는 파일이라 길이가 곧 비용입니다. 그런데 길이를 줄이려고 이유까지 지우면 에이전트가 예외 상황에서 판단을 못 합니다. 그래서 불릿에 박혀 있던 상세를 그 내용을 소유한 커맨드 문서로 옮기고, CLAUDE.md 에는 링크만 남겼습니다. 30.1k자가 됐습니다.
옮긴 상세로 가는 길이 링크 하나뿐이라, 체커에 상대 링크가 실제 파일을 가리키는지 보는 검사를 하나 더 붙였습니다. 이 검사는 첫날 오탐을 두 번 냈습니다. 코드 위치를 파일:줄번호 로 적는 워크스페이스 관례 때문에 멀쩡한 링크를 깨졌다고 잡았고, 커밋하지 않는 클론 디렉터리를 가리키는 링크는 CI 에서만 깨졌습니다. 둘 다 그날 안에 고쳤습니다.
강제를 덜어내자던 지난 글과 막는 대상이 다르다
지난 글에서 강제를 늘리는 것보다 덜어내는 게 어렵다고 썼습니다. 이 체커는 그 반대 방향으로 보일 수 있습니다.
제 기준에서 둘은 막는 대상이 다릅니다. 그 글에서 걷어낸 건 점검 커맨드를 여러 사람이 동시에 못 돌리게 막던 잠금이었습니다. 사람이 커맨드를 언제 돌리는지를 묶는 장치였죠. 이 체커는 사람의 절차를 묶지 않습니다. 에이전트가 지시로 읽는 문서에 틀린 걸로 확인된 문장이 다시 들어오는 것만 막습니다. 누가 어떤 순서로 일하든 상관없고요. 막는 문장도 누군가 실측으로 반증해서 목록에 올린 것뿐이라, 체커가 스스로 규칙을 늘리지는 않습니다.
팀원이 쓰기 시작하자 경계 밖에서 샜다
2주 뒤인 8월 28일에 팀원이 이 목록에 항목을 하나 올렸습니다. 이슈 라벨 두 개가 한 레포에만 있다는 서술이 CLAUDE.md 에 남아 있었는데, 그 라벨은 이미 전 레포에 만들어 둔 상태였습니다. 팀원은 문구만 고치지 않고 철회 목록에 등록했습니다. 커밋 메시지에는 이렇게 적었더군요.
“개인 메모리에 적으면 본인만 보호되고 팀원 하네스에서 되살아난다”
스크립트 헤더에 적어 둔 이유를 팀원이 자기 말로 다시 쓰고 있었습니다.
같은 작업에서 구멍이 하나 드러났습니다. 폐기한 이슈 제목 규칙은 이미 목록에 올라가 있었는데, 온보딩 문서 하나가 그 옛 규칙을 계속 가르치고 있었습니다. 온보딩 문서가 스캔 경계 밖이었거든요. 한 곳만 고쳐지고 다른 곳에 남는 바로 그 일이, 체커가 안 보는 자리에서 난 겁니다.
팀원이 경계를 온보딩 문서까지 넓혔습니다. 새로 온 사람이 규칙을 배우는 곳이라, 거기 폐기된 지침이 남아 있으면 커맨드를 고쳐도 사람 쪽에서 되살아납니다.
사흘 뒤에는 제가 같은 걸 겪었습니다. 작업 기록 저장 절차를 정해 둔 기준 문서(이력 디렉터리의 README)가 저장 커맨드가 커밋과 푸시까지 자동으로 한다고 적고 있었습니다. 커맨드 본문은 처음부터 “자동으로 커밋·푸시하지 않는다”였고요. 커맨드들이 기준으로 가리키는 문서가 스캔 밖에 있어서, 체커는 정반대 서술을 못 봤습니다.
여기서 제가 그은 경계가 틀렸다는 걸 알았습니다. 이력 아카이브를 빼면서 디렉터리째 뺐는데, 같은 디렉터리에 있어도 그 README 는 지금 쓰는 절차의 기준 문서입니다. README 하나만 대상에 넣고, 자동 커밋 서술을 목록에 올렸습니다.
스캔 경계 안의 재등장만 잡혔다. 온보딩 문서와 기준 README 까지 경계를 넓히고, 이력 아카이브는 계속 뺀다
그 뒤로 경계를 넓힐 때 보는 질문은 하나입니다. 에이전트나 사람이 이 문서를 지금의 지침으로 읽는가. 그렇다면 넣고, 특정 시점의 기록이면 뺍니다.
정규식이 못 잡는 재등장은 남아 있다
패턴이 정규식이라 같은 주장을 다른 말로 쓰면 못 잡습니다. 항목마다 자주 나오는 표현을 몇 개 넣어 두긴 했지만, 그걸로 다 막힌다고 보지 않습니다. 정정 문구로 통과시키는 okIf 에도 대가가 있습니다. 넓게 잡을수록 오탐은 줄지만 그만큼 진짜 재등장도 통과할 여지가 생깁니다.
목록은 누군가 올려야 작동합니다. 반증을 확인하고도 메모리에만 적으면 8월 14일 이전과 똑같습니다. 이건 도구로 강제할 수 있는 게 아니라서, 스크립트 헤더에 “틀린 걸 확인하면 메모 말고 여기에”라고 적어 두는 것 말고는 해 둔 게 없습니다. 팀원이 먼저 올린 건 다행이었지만, 그게 매번 일어난다는 보장은 없죠.
경계는 계속 넓어지는 중입니다. 보름 남짓 사이에 두 번 넓혔고, 온보딩 문서를 넣을 때는 멀쩡한 링크가 깨졌다고 잡혀서 그 처리를 같이 넣어야 했습니다. 문서 전체를 한 번에 스캔하는 쪽은 택하지 않았습니다. 이력까지 고쳐 쓰게 만들고 위키 점검 커맨드와 판정이 겹치기 때문입니다. 그 대가로 새 종류의 문서가 생길 때마다 넣을지 말지를 사람이 정해야 하고, 그 판단은 아직 체커 밖에 있습니다.