📝 한줄 요약
메시지 라우팅을 관찰하는 Hermes hook을 만들 때 가장 위험한 실수는 “관찰만 한다”는 설명을 믿고 곧바로 운영 프로필에 꽂는 것이다. 이번 작업에서는 credential도 gateway도 없는 별도 프로필에 pre_gateway_dispatch observer를 넣고, callback이 언제나 None만 반환하는지, 본문과 식별자를 남기지 않는지, 원래 메시지가 그대로 agent dispatch에 도달하는지부터 검증했다. 발행 전 재실행에서 observer 테스트 14개와 동결 산출물 12개 해시가 모두 통과했지만, Slack adapter에서 먼저 탈락한 메시지는 이 hook이 볼 수 없다는 한계 때문에 판정은 CANARY PASS / PRODUCTION HOLD로 남겼다.
바쁘시면 이것만 읽어도 됩니다.
hook은 기능보다 먼저 행동 불가 계약을 만들었다: callback return은
None, routing directive는 0개다.메시지·답글·raw payload 본문과 사용자·채널·스레드·메시지 식별자는 receipt에 넣지 않았다.
로그는 명시한 절대 로컬 경로가 있을 때만 쓰고,
0600, bounded append, symlink 거부, fail-open을 적용했다.canary profile은 credential·model·PID·LaunchAgent 없이 gateway가 정지된 상태다.
발행 전 fresh test는 14/14, gateway passthrough는 PASS, 동결 산출물은 12/12 bytes·SHA-256 일치였다.
원래 검증 시점의 Slack routing baseline 77개와 Hermes core hook contract 2개도 통과했다.
그러나
pre_gateway_dispatch는 Slack adapter가 받아들인 이벤트만 본다. adapter에서 먼저 탈락한 메시지는 관찰하지 못한다.활성 작업 디렉터리의
.env가 fixture env를 덮는 문제를 합성 sentinel로 재현했고, clean cwd에서 fixture가 보존되는 것도 확인했다. Hermes core test 수정은 이번 사례 발행 작업에서 수행하지 않았다.따라서 이 결과를 “운영 라우팅 완성”으로 승격하지 않고 production HOLD로 유지했다.
🎯 이런 분들께 도움됩니다
메시징 gateway에 hook·plugin·middleware를 추가하려는 운영자
“read-only”, “observer-only”라는 이름만으로는 안전을 신뢰하기 어려운 팀
AI 에이전트 로그에서 본문·사용자 ID·채널 ID를 남기지 않는 계측 경계를 설계하려는 사람
여러 봇이 한 Slack workspace를 공유해 mention·channel-owner precedence를 검증해야 하는 팀
테스트가 실제 사용자 홈의
.env나 활성 profile에 오염되는 문제를 겪는 개발자PASS와 production 승격을 서로 다른 Gate로 운영하려는 조직
😫 문제 상황 — “관찰 hook이면 안전하지 않을까?”
처음 요구는 단순했다.
Hermes hook으로 Slack 라우팅 결정을 관찰해 보자.
다만 기존 동작과 개인정보는 건드리지 말자.
그런데 메시징 경로에서 “관찰”은 생각보다 넓은 권한을 가질 수 있다.
callback이 잘못된 값을 반환하면 메시지를 skip하거나 rewrite할 수 있다.
receipt에 원문을 넣으면 사실상 별도의 대화 로그가 생긴다.
channel·thread·user ID를 그대로 저장하면 메시지가 없어도 개인과 대화 위치를 추적할 수 있다.
실행 중인 profile에 plugin을 바로 켜면 test와 production 경계가 사라진다.
hook이 pipeline 뒤쪽에 있으면 앞에서 탈락한 사건을 전혀 보지 못하면서도 “전체를 관찰했다”고 착각할 수 있다.
가장 중요한 질문은 “hook이 작동하는가?”보다 다음 세 가지였다.
무엇을 볼 수 있는가?
무엇을 절대로 남기지 않는가?
어떤 결과도 바꾸지 않는다는 것을 어떻게 증명할 것인가?
🌱 첫 번째 전환점 — 기능 목록보다 ‘행동 불가 계약’을 먼저 썼다
구현 전에 다음 계약을 동결했다.
경계
계약
등록
pre_gateway_dispatch hook 하나만 등록
반환
모든 정상·예외 경로에서 None
라우팅
skip, rewrite, allow, context·tool·command directive 0개
기본 쓰기
로그 경로가 없으면 파일 생성 0개
공개 receipt
본문·reply·raw payload·이름·원시 ID·attachment 경로 금지
상관관계
명시한 key가 있을 때만 짧은 keyed HMAC, key가 없으면 필드 자체 생략
파일 보호
절대경로, 기존 parent, mode 0600, append-only, final symlink 거부
용량
상한을 넘으면 기존 증거를 자르지 않고 append 중단
오류
관찰·I/O 오류는 fail-open, 원래 dispatch 유지
활성화
credential 없는 별도 profile, gateway 시작 금지
이 구조에서 “observer-only”는 설명 문구가 아니라 검증 가능한 불변식이 되었다.