마지막 업데이트 2026-09-03
2026-09-03 · 프로젝트 스킬 .claude/skills/consensus-loop/SKILL.md · Herdr 안에서 실행
PPI web의 커밋·PR 작업이 에이전트 중심으로 진행되면서 개발자가 코드에 직접 관여하지 않게 됐습니다. 그 결과 운영 이슈가 나면 "어느 지점의 어떤 변경이 문제인지"를 추정할 출발점이 없다는 문제가 생겼습니다.
세 갈래로 접근했고, 이 문서는 세 번째의 산출물입니다.
consensus-loopround-N.*.md)와 Herdr가 실제로 읽은 화면(*.terminal.log)을 둘 다 남겨 대조할 수 있게 합니다.
사용자 지시
→ [R1] implementer: 구현 + 근거(round-1.impl.md)
→ [R1] reviewer: VERDICT APPROVE | REVISE(F-번호 findings) (round-1.review.md)
→ 체크포인트: 계속 / 멈춤 / 지시 수정
→ [R2] implementer: finding별 수용(수정) 또는 기각(이유) 명시 후 수정
→ [R2] reviewer: 재판정
→ … 최대 MAX_ROUNDS(기본 4)
→ 합의(APPROVE + open·disputed 0) 또는 에스컬레이션(사람 판정)
tail -f trace.md · 라운드 타임라인 실시간 표시파라미터: TICKET(필수, 브랜치명에서 추출 가능) · MAX_ROUNDS=4 · GATE=confirm|auto · IMPL_KIND=claude · REVIEW_KIND=codex · MODE=impl|analysis
test "${HERDR_ENV:-}" = 1 || exit 1 # Herdr 밖이면 중단
herdr pane split --current --direction right --cwd "$PWD" --no-focus # → IMPL_PANE
herdr pane split --pane "$IMPL_PANE" --direction down --cwd "$PWD" --no-focus # → REVIEW_PANE
herdr pane split --current --direction down --ratio 0.3 --cwd "$PWD" --no-focus # → TRACE_PANE
herdr pane run "$TRACE_PANE" "tail -f .omc/trace/$TICKET/trace.md"
herdr agent start ppi-1267-impl --kind claude --pane "$IMPL_PANE"
herdr agent start ppi-1267-review --kind codex --pane "$REVIEW_PANE"
.result.pane.pane_id에서 읽습니다. 예시나 사이드바 순서로 추정하지 않습니다.agent prompt를 이어 보내 컨텍스트를 유지합니다.| 역할 | 매 라운드 반드시 지킬 것 |
|---|---|
| implementer | commit/push 금지 · 새 분기마다 고유 문자열 리터럴 로그 이벤트명 1개(템플릿 조합 금지) · 비직관적 가드에 // PPI-xxxx … 한 줄 앵커 · 2라운드부터 F-번호별 수용(수정 내용) 또는 기각(이유), 침묵 불가 · 리뷰에 없는 추가 변경 금지 · 결과에 변경 지점 지도 표 필수 |
| reviewer | 첫 줄 VERDICT: APPROVE|REVISE · finding은 F-번호 연속, 파일:줄·심각도(P0~P3)·재현 조건 · 3라운드부터 새 P2·P3 금지(P0·P1은 항상 허용) · 구현자의 기각에 동의하면 resolved(기각 수용), 아니면 disputed+이유 |
| 오케스트레이터 | findings.md 원장 갱신 → 종료 조건 검사 → STATE·trace.md 갱신 → 게이트 |
VERDICT: APPROVE 이고 open·disputed finding 0 → consensus형식 위반(첫 줄 VERDICT 누락, finding 침묵)은 라운드 카운트를 올리지 않고 형식만 다시 요구합니다.
| 하고 싶은 것 | 방법 |
|---|---|
| 보기 | trace pane의 tail -f로 라운드 진행을 본다. 어느 pane이든 focus해 실제 화면을 볼 수 있다. |
| 멈추기 | GATE=confirm이면 라운드 경계에서 "멈춤" 선택. 어느 pane에서든 touch .omc/trace/<TICKET>/PAUSE를 만들면 GATE=auto여도 다음 라운드를 시작하지 않는다. |
| 턴 끊기 | herdr agent send-keys ppi-1267-impl esc. 오케스트레이터가 trace.md에 "사용자 중단"으로 기록. |
| 직접 말하기 | implementer/reviewer pane에 직접 타이핑. 오케스트레이터는 다음 라운드 전 agent read로 개입 여부를 확인해 기록. |
| 지시 수정 | 게이트에서 "지시 수정: …" 입력 → 그 문장이 다음 implementer 프롬프트에 그대로 삽입. |
| 재개 | rm .omc/trace/<TICKET>/PAUSE 후 오케스트레이터 pane에 "계속". |
MODE=analysis)지시가 "원인 분석·조사·왜 이런지"이면 워킹트리를 수정하지 않는 모드로 돕니다. 합의 기준은 "근거로 뒷받침되고 사실/추정이 구분된 원인 1개"입니다.
| 항목 | 구현 모드 | 분석 모드 |
|---|---|---|
| implementer 역할 | 코드 수정 | analyst: 가설 + 근거(로그·파일:줄) + 인과 다이어그램 |
| reviewer 역할 | 결함 지적 | challenger: 반증 시도, 대안 가설, 근거 부족 지점(C-번호) |
| 판정 | APPROVE / REVISE | AGREE / CHALLENGE |
| 합의 조건 | open finding 0 | open challenge 0 + 사실/추정 구분 표기 |
| 수정 | commit 금지 | 워킹트리 수정 자체 금지, 개선점은 제안으로만 |
| 최종 산출물 | 변경 지점 지도 + 결정 기록 5필드 | analysis-final.md: 결론 1줄 → 인과 체인 → 근거 → 기각된 대안과 이유 → 미확인 → 개선 제안 |
challenger는 3라운드부터 새 대안 가설을 내지 않고 기존 가설의 근거 검증만 합니다.
/consensus-loop TICKET=PPI-1267 GATE=confirm
수업 예정시각+1시간이 지난 게스트의 JOIN_ROOM 재입장을 거부하고 GUEST_FORCE_KICKED로
클라이언트를 terminal 상태로 만들어, 방치된 게스트 탭이 socket.io 자동 재접속으로
좀비 세션을 반복하는 문제를 막아. 대상은 apps/socket connection-handlers의 JOIN_ROOM과
apps/web api/v2/lesson-sessions/validate-owner. 두 파일 각각 테스트 추가.
실제 PPI-1267에서 코드리뷰가 JOIN_ROOM 안의 두 번째 소유권 재검증 지점 누락을 잡아냈습니다. 이 루프에서는 그것이 R1 reviewer의 F-1(P1)로 나와 R2에서 수용·수정되는 형태로 기록됩니다.
/consensus-loop MODE=analysis GATE=confirm TICKET=PPI-1270
증상: 9/2 김OO 3회기, 진행자 모니터에서 아동 소리만 안 들림(전사는 정상).
roomId는 세션 로그에서 찾아. LogRocket(아동·진행자)과 Loki ppi-socket 미디어 로그 교차 조사.
코드는 수정하지 마. 기존 판별법 문서 먼저 대조.
[trace pane]
15:02 impl(analyst) R1 시작
15:09 impl(analyst) R1 완료 round-1.analysis.md
결론: iPad WebKit mic clone 송신측 무음(outbound energy=0)
15:14 review(challenger) R1 완료 VERDICT: CHALLENGE
C-1 energy=0 로그가 kick 이후 구간만 확인됨, 이전 구간 근거 없음
C-2 대안: 진행자 측 consumer pause 상태 미확인
15:14 체크포인트 → 사용자: "지시 수정: C-2는 진행자 LogRocket consumer 이벤트로 확인해"
15:16 impl(analyst) R2 C-1 수용(kick 이전 구간 동일 패턴 확인, 사실)
C-2 반박(진행자 consumer resume 정상, 파일:줄)
15:22 review(challenger) R2 VERDICT: AGREE, open 0
15:22 STATE=consensus → analysis-final.md
.omc/trace/<TICKET>/, 커밋 대상 아님)| 파일 | 작성자 | 내용 |
|---|---|---|
trace.md | 오케스트레이터 | 시각·pane·상태·지시 요약·산출물 경로 한 줄씩 append |
round-N.impl.md / .analysis.md | implementer | 변경 지점 지도 또는 가설·근거, finding/challenge별 수용·기각 |
round-N.review.md | reviewer | 첫 줄 VERDICT, 번호 붙은 findings/challenges |
findings.md | 오케스트레이터 | 원장: F-N · 라운드 · 심각도 · 상태(open/resolved/rejected/disputed) · 파일:줄 |
round-N.*.terminal.log | 오케스트레이터 | herdr agent read --source recent-unwrapped 원문. 자기 보고와 대조용 |
STATE | 오케스트레이터 | running / paused / consensus / escalated |
종료 보고에는 결정 기록 5필드가 들어갑니다: 가설 / 기각한 대안과 이유 / 변경 지점(파일:줄) / 검증 근거 / 미검증 항목. 이 5필드가 나중에 "어느 스킬·프롬프트 조합이 결함을 적게 내는가"를 집계하는 LLMOps 데이터가 됩니다. 커밋은 하지 않고 "로컬에 적용함, 확인 후 커밋"으로 끝냅니다.
tail -f pane 표시, 라운드 간 agent prompt 연속 전송은 Herdr 세션에서 한 번 돌려 확인이 필요합니다.terminal.log에 안 남을 수 있어, 그때는 파일 출력 요구로 폴백합니다.