consensus-loop — 구현·리뷰 합의 루프 스킬 가이드

마지막 업데이트 2026-09-03

2026-09-03 · 프로젝트 스킬 .claude/skills/consensus-loop/SKILL.md · Herdr 안에서 실행

요약. 한 에이전트가 작업을 블랙박스처럼 끝내는 대신, 구현자(implementer)리뷰어(reviewer)를 서로 다른 Herdr pane·서로 다른 모델로 띄워 라운드 단위로 수정↔리뷰를 반복하고 합의(APPROVE + open finding 0)에 도달시키는 오케스트레이션 지침입니다. 모든 라운드는 pane에서 실시간으로 보이고, 라운드 경계마다 사람이 멈추거나 지시를 끼워 넣을 수 있습니다. 코드를 만지지 않는 분석 모드(analyst↔challenger)도 있습니다.

1. 왜 만들었나

PPI web의 커밋·PR 작업이 에이전트 중심으로 진행되면서 개발자가 코드에 직접 관여하지 않게 됐습니다. 그 결과 운영 이슈가 나면 "어느 지점의 어떤 변경이 문제인지"를 추정할 출발점이 없다는 문제가 생겼습니다.

세 갈래로 접근했고, 이 문서는 세 번째의 산출물입니다.

  1. PR·커밋 규약 강화 — 변경 지점 지도(파일:줄 → 왜 → 깨지면 보이는 시그널), 분기마다 고유 로그 이벤트명, 결정 기록 5필드.
  2. LLMOps 도구 검토 — LangChain/LangSmith는 Claude Code 내부 호출을 추적할 수 없고, 핑퐁이 LLM 쪽은 이미 자체 trace가 있어 도입 가치가 낮다고 판단.
  3. 과정 자체를 보이게 하기 — Herdr pane으로 구현·리뷰 왕복을 분리해 사람이 관찰·개입할 수 있는 루프로 만들기. → consensus-loop
에이전트의 "이렇게 조사했다"는 자기 보고는 사후 합리화가 섞이기 쉽습니다. 그래서 이 스킬은 자기 보고(round-N.*.md)와 Herdr가 실제로 읽은 화면(*.terminal.log)을 둘 다 남겨 대조할 수 있게 합니다.

2. 전체 흐름

사용자 지시
  → [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) 또는 에스컬레이션(사람 판정)
오케스트레이터현재 pane · 코드 수정 금지 · 라운드 진행·기록·판정
implementerclaude 기본 · 구현 + 변경 지점 지도
reviewercodex 기본 · 다른 모델로 교차 검토
tracetail -f trace.md · 라운드 타임라인 실시간 표시

파라미터: TICKET(필수, 브랜치명에서 추출 가능) · MAX_ROUNDS=4 · GATE=confirm|auto · IMPL_KIND=claude · REVIEW_KIND=codex · MODE=impl|analysis

3. pane 배치와 에이전트 수명

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"

4. 라운드 규칙

역할매 라운드 반드시 지킬 것
implementercommit/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 갱신 → 게이트

종료 조건 (순서대로 검사)

  1. VERDICT: APPROVE 이고 open·disputed finding 0 → consensus
  2. 같은 finding이 2라운드 연속 disputedescalated (사람이 판정)
  3. N == MAX_ROUNDS → escalated
  4. 그 외 → 다음 라운드

형식 위반(첫 줄 VERDICT 누락, finding 침묵)은 라운드 카운트를 올리지 않고 형식만 다시 요구합니다.

5. 사람이 개입하는 방법

하고 싶은 것방법
보기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에 "계속".

6. 분석 모드 (MODE=analysis)

지시가 "원인 분석·조사·왜 이런지"이면 워킹트리를 수정하지 않는 모드로 돕니다. 합의 기준은 "근거로 뒷받침되고 사실/추정이 구분된 원인 1개"입니다.

항목구현 모드분석 모드
implementer 역할코드 수정analyst: 가설 + 근거(로그·파일:줄) + 인과 다이어그램
reviewer 역할결함 지적challenger: 반증 시도, 대안 가설, 근거 부족 지점(C-번호)
판정APPROVE / REVISEAGREE / CHALLENGE
합의 조건open finding 0open challenge 0 + 사실/추정 구분 표기
수정commit 금지워킹트리 수정 자체 금지, 개선점은 제안으로만
최종 산출물변경 지점 지도 + 결정 기록 5필드analysis-final.md: 결론 1줄 → 인과 체인 → 근거 → 기각된 대안과 이유 → 미확인 → 개선 제안

challenger는 3라운드부터 새 대안 가설을 내지 않고 기존 가설의 근거 검증만 합니다.

7. 사용 예시

7-1. 구현 지시 — PPI-1267 방치된 게스트 탭 무한 재접속 차단

/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에서 수용·수정되는 형태로 기록됩니다.

7-2. 분석 요청 — 진행자 모니터에서 아동 소리만 안 들림

/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

8. 추적 산출물 (.omc/trace/<TICKET>/, 커밋 대상 아님)

파일작성자내용
trace.md오케스트레이터시각·pane·상태·지시 요약·산출물 경로 한 줄씩 append
round-N.impl.md / .analysis.mdimplementer변경 지점 지도 또는 가설·근거, finding/challenge별 수용·기각
round-N.review.mdreviewer첫 줄 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 데이터가 됩니다. 커밋은 하지 않고 "로컬에 적용함, 확인 후 커밋"으로 끝냅니다.

9. 한계와 미검증 항목

관련 문서