ruleguard — 규칙 2회 위반 강제 훅(메타 장치) (handoff)
발단 = [페페] 26.9.10(목) 지시: 「앞으로 rules 건너뛰고 2번 작업하는 경우 훅 생성을 훅으로 강제한다.」 배경 = Lauren Tan 강의 교훈(사람이 반복 지적하는 규칙은 문서가 아니라 CI·린트로 강제) →
projects/ideas/ideas.md26.9.10 항목에서 채택. 26.9.2 페페 지시(「두 번 잡힌 함정은 rules 에 기억」)를 「두 번이면 훅」 으로 격상한 것.
🆕 26.10.1 — web-designer-required 가 서브에이전트 안의 web-designer 상담을 못 본다 [오탐 의심 · 미조치]
- [코디] 총괄 세션이 맡긴 worker(opus·xhigh, poin-agent 게시글 정리)가 web-designer 상담을 2회 마치고(최종 「OK」)
C:\dev\devplan\poin-agent-hub.html에 기록 문단을 넣으려다 2회 차단 → 위반 카운트 37·38 로 증가(같은 파일 타일 문구 수정 1건은 통과). worker 보고 기준 · 원인은 추정 = 상담 판정이 «그 세션 transcript» 만 보고 중첩 서브에이전트의 상담은 못 찾는다. - 영향 = 26.9.29 「총괄은 직접 안 고치고 worker 에 맡긴다」 구조에서 UI 편집이 막히고 카운트가 오탐으로 오염된다.
- ⏳고칠 곳(추정) = 상담 판정 범위에 부모 세션 폴더의
subagents\agent-*.jsonl포함. 가드 폴더라 [페페] 「해제」 승인이 먼저다. 막힌 문단은 안 넣었다(타일 문구로 devplan 갱신 의무는 충족).
🆕 26.9.23~24 — Stop 훅 차단 시 «답변 2번» [규율로 확정 · 코드는 보류]
- [코디] ✅26.9.24 코디 규율로 확정([페페] 「중복 답변 코디 규율 수정만 먼저 한다」) —
C:\dev\CLAUDE.md「⛔ 답변 보내기 직전」 머리글에 2줄 추가: ①6개 체크리스트를 «답변 텍스트를 쓰기 전에» 끝낸다 ②막혔으면 답변 전문을 다시 쓰지 말고 «바뀐 줄»만 짧게 적어 마친다. - 🔑원인 = 순서다. 훅이 막는 시점엔 방금 쓴 답변이 이미 페페 화면에 떠 있다 — 조치 후 전문을 다시 쓰면 같은 답변이 두 벌 남는다. 26.9.24 한 세션에 3건(
notify-missing2회 ·report-tail-missing2회 ·relative-path-in-report2회). - ⏳보류 =
ruleguard.pyblock_reason()에 같은 문구 1줄(차단 안내문에 박아 넣기). 가드가 자기 폴더를 잠가 페페 텔레그램 「해제」 승인이 필요해서 이번엔 안 건드렸다. 수정안 원문 =projects/ponytail-local/handoff.md「남은 것」. - [페페] 26.9.23 판단 = 「더 지켜본다」 → 26.9.24 재발 3건으로 규율 확정.
🆕 탐지기 추가 (26.9.15)
- [코디] ✅
devplan-page-missing신설(페페 지시 26.9.15 「신규 프로젝트 작업시 devplan 페이지 신설, 관련 작업 이어갈시 매번 갱신. 훅으로 만들어라」) — Stop · deny · mtime 기준(네트워크 0 · 서브프로세스 0). 로직 = ①seedchain/projects/<P>/*.md중 최근 2시간 내 수정 = 이번 세션 작업 ②대응 devplan 카드가 없으면 신설 필요 ③있는데 카드sourcemtime 이 2시간 밖이면 갱신 안 함. 자체검사 14항목 · 전체 65항목 실패 0. - 매칭 =
devplan/projects.json의ub필드(= seedchain 슬러그, 이번에 신설) 우선 → 이름 일치/접두 → 첫 토큰 접두(danggeun-ai-study→danggeun-*). 새 카드엔ub를 넣는다(없으면 느슨 매칭이라 오탐 여지). - 🔴mtime 단독 판정은 오탐이 난다 —
mine()으로 한 번 더 좁힌다(26.9.15 실측). 첫 구현을 실제로 돌려 보니 후보 6개 중 4개가 오탐이었다(pfs82분 전 ·remote-access66분 전 — 내가 안 건드렸는데 자동 스케줄러·다른 세션이 파일을 만져 mtime 이 올라갔다). ⛒처방 = mtime 후보를 뽑은 뒤ctx.session_has(r"projects[\\/]+<슬러그>")로 이 세션 transcript 에 그 경로가 나온 것만 남긴다(공개 API · 오프셋 증분 + 패턴별 캐시라 싸다). 스캔은 패턴마다 1회라 후보를 최근 순 6개로 끊는다(MAX_CANDIDATES). ⚠session_has는 Read/Bash 입력만 본다(Write/Edit 는 안 본다) — 실무상 프로젝트를 만지면ls·grep·cat·python으로 경로가 거의 반드시 등장해서 충분하지만, Write 로만 파일을 만들고 한 번도 안 읽은 프로젝트는 빠질 수 있다(놓침 쪽이라 차단 오탐보다 안전한 실패 방향). - ⛒면제 = 「갱신 안 함」만 답변에
devplan: 갱신 없음(사유)한 줄로 갈음(리포 정리처럼 화면에 비출 게 없는 작업이 실제로 있다 — 26.9.15 ax-biz·danggeun-ai-study 가 그 경우였다). 「카드 자체가 없음」은 면제 불가. 면제 정규식 =devplan\s*[::](report-tail-missing의시드:패턴과 같은 방식). - 면제 대상 프로젝트 =
SKIP(seedchain·ideas·guide) — 카드 개념이 없는 메타. 늘면 여기 추가. - ⚠부산물로 확인 = devplan 카드 등록은 3단계다(
projects.json+project_state.json+build_hub.py). 상태 항목을 빠뜨리면 빌드가 FAIL 로 멈추는데(1:1 검증 게이트),project_state.py set은 기존 항목 전용이라 신규는 JSON 직접 추가해야 한다(CLI 에 생성 경로 없음).
상태 (26.9.10)
- [코디] 그릴링 결정 9개와 합의 확인 완료. 계획 확정 =
design.md(Fable 5 + 코덱스 병합). - [코디] ✅ devplan
C:\dev\devplan\ruleguard-plan.html+ 허브 카드(최근 보드 ①·최근 작업 ② 노출 확인) · 세션문서session-2026-09-10-ruleguard-design.md등록. - [코디] ✅26.9.11 00시대 설치(기록 모드) —
C:\dev\tools\ruleguard\ruleguard.py(1,670줄) + 탐지기 7개 +ledger.json(규칙 12개). 자체검사 61/61 · 재생검증 17/17 · 116MB transcript 기준 PreToolUse 최대 73ms / Stop 최대 105ms. settings.json 에 PreToolUse(Bash|Edit|Write|MultiEdit|NotebookEdit)·UserPromptSubmit·Stop 1항목씩 병합(백업C:\Users\delix\.claude\settings.json.bak_ruleguard_2026-09-11). - [코디] ⏰차단 전환 =
2026-09-12T00:07:33+09:00자동(enforce_from=guard_from). 보고 = 예약작업\Cody\ruleguard-report26.9.11(금) 22:07 KST →report_notify.vbs→report --notify. 로그C:\dev\tools\ruleguard\logs\report_task.log. - [코디] 설계와 달라진 점: ①selftest 미통과(detector_ok 없음) 탐지기는 편집 허용 ②판단형 「페페 확인」 유도는 enforce 이후 ③헤드리스 판별 = 프롬프트 줄
origin유무(entrypoint 는 부모 env 상속이라 실측상 못 씀). - [코디] 📌다음 세션 확인 3가지: ①
ruleguard.py report에서repo-md-multi-registercount=1(26.9.11 최종 답변의[규칙위반]태그를 Stop 훅이 기록했는지 = 자기신고 경로 실전 검증) ②report --health에 PreToolUse·UserPromptSubmit·Stop 3종 실행 시각이 다 찍혔는지 ③9/11 22:07 보고가 텔레그램에 왔는지(logs\report_task.log). - [코디] 알려진 한계: 사용자 중단 직후 Stop 이 오면 partial 답변으로 꼬리줄 위반이 기록될 수 있다(dismiss CLI 없음 — 필요하면 추가). 엔진 1,670줄은 계획 추정(450~500줄)의 3배 → 기능 명세 전부 포함 결과, 축소는 후순위.
- [코디] 🔴자기신고 대기 1건(26.9.11 00시대):
rules\repo.md35행 「새 노트 여러 개면 register_doc 이 서로를 막는다」가 이미 적혀 있었는데 안 읽고 밟았다(세션문서·sessions.md 연속 등록 → 롤백 → 임시 이동으로 복구f21a4fe). 구현 완료 후ruleguard.py add-rule로 seed 1 등록할 것(id 후보repo-md-multi-register, doc =rules/repo.md#빌드·검증). - 롤아웃 = 26.9.10 기록 모드로 켠다 → 26.9.11(금) 자동으로 차단 전환(규칙 목록의
block_from시각). 전환 전에 하루 동안 잡힌 건을 텔레그램으로 보고하고, 페페가 거부할 수 있다.
확정 결정 (26.9.10 그릴링 — 전부 [페페] 결정)
- PYTHONUTF8 = 훅 대신 env 이중화(사용자 환경변수 setx +
~/.claude/settings.jsonenv) + 규칙 완화. ✅적용·실측 완료(부모 env를 지운 헤드리스 claude에서도 Bash에 값이 들어옴). 이 장치의 대상이 아니다. - 세는 단위 = 같은 규칙 누적 2회(세션 무관). 같은 턴 안의 재시도는 1건으로 센다(코덱스 권고).
- 범위 = 규칙 문서 전부 —
C:\dev\CLAUDE.md+C:\dev\seedchain\rules\*.md+C:\dev\seedchain\projects\*\rules.md+ 각 리포 CLAUDE.md. - 검출 = 기계 판정 규칙은 훅이 자동 기록 + 판단형 규칙은 페페 지적·코디 자기신고로 기록.
- 과거 이력 반영 = 문서에 날짜와 함께 2회 이상 적힌 위반은 2회로 시작.
- 기계 판정 규칙 = 자동 승격 — 탐지기가 1회차엔 기록만, 2회째부터 스스로 차단.
- 탐지기 없는 규칙이 2회 = 매 턴 경고(UserPromptSubmit) + 턴 종료 1회 차단(Stop) → 코디가 훅을 만든다. 자체 테스트를 통과해야 해제.
- 판단형 규칙이 2회 = 가장 가까운 기계 신호로 대체 훅. 불가능하면 그 상황 진입 시 체크리스트 주입. 이걸로 닫을지는 페페 확인.
- 강제 훅 끄기 = 페페 텔레그램 승인으로만. 코디는 직접 못 끈다.
- 훅 오류·타임아웃 = 통과(fail-open) — 작업이 통째로 멈추는 사고를 막는다.
- 롤아웃 = 하루 기록 모드 후 차단(페페 선택. 코디 추천은 「과거 transcript 재생 검증 후 즉시 차단」이었다).
초기 장부 (26.9.10 Explore 조사 · 문서에 적힌 기록만)
| 규칙 | 기록된 위반 | 판정 방식 | 시작 횟수 |
|---|---|---|---|
| 텔레그램 알림 누락 | 8/2 · 8/6 | 기계(Stop: 작업 턴인데 notify.py 호출 없음) | 2 |
| heredoc으로 파일 쓰기 | 7/14 ~ 9/9 10회 이상 | 기계(PreToolUse Bash) | 2 |
pfs git add -A·디렉터리 add |
7/13 · 9/3 | 기계(PreToolUse Bash, cwd=pfs) | 2 |
| broker 500/400에 재시도 | 9/5 · 9/8(3회) | 기계(직전 오류 뒤 같은 호출) | 2 |
| Bash로 GUI 띄움(Session 0)·가상데스크톱 미이동 | 8/31 · 9/2 | 판단형 → 대체 훅 | 2 |
| rules 사전읽기 누락 | 9/10 | 기계(코드 Write·Edit 전에 tooling.md Read 여부) | 1 |
| 세션릴레이 누락(8/3) · 상대경로 보고(9/1) · broker 임시 deny(8/18) · 폰 실기 검증을 웹 모바일뷰로 대체(9/4) | 각 1회 | 혼합 | 1 |
- 출처(Explore 보고) =
C:\dev\CLAUDE.md(§2·하단 체크리스트) ·C:\dev\seedchain\rules\tooling.md·C:\dev\seedchain\rules\notify.md·C:\dev\seedchain\projects\pfs\rules.md· 메모리frequent-tool-mistakes·pfs-git-add-all-danger·remote-real-chrome-gui-cdp·bash-heredoc-backslash-double-decode. - PYTHONUTF8 누락은 날짜 기록이 없고 env로 해결돼서 장부에서 뺐다.
코덱스 의견 (26.9.10)
- 무한루프 = Stop 재진입 플래그 + (규칙, 턴)당 1회만 차단 + 타임아웃이면 통과.
- 오탐 승격 = 같은 턴·재시도 중복 집계 금지, 증거가 남은 서로 다른 위반 2건만 승격. 수동 해제·예외 규칙 필수.
- 성능·상태 = 변경 입력만 검사, 200~500ms 안, 원자적 저장, 경로·UTF-8 정규화. 최소 구조 = 규칙 목록 + 상태 파일 + 공용 탐지기 러너 + 얇은 훅 래퍼. 규칙 목록은 YAML 대신 JSON(표준 라이브러리만).
다음
- [ ] Fable 계획과 코덱스 의견 병합 → devplan 계획페이지·허브 카드
- [ ] 구현(기록 모드) → 탐지기 자체검사 + 합성 입력 파이프 테스트 → settings.json 훅 병합(기존 배열 유지)
- [ ] 26.9.11(금) 차단 전환 전 하루치 기록 보고