Verify
spec/plan·코드를 runtime-neutral 방식으로 교차검증. skill은 신뢰 영역(진입점 + 보안 책임 + 판사), runner는 실행 주체, reviewer는 순수 검증 provider. 검증 대상의 prompt injection으로 reviewer가 조종될 수 있다는 전제로, 보안 결정권은 skill만 보유.
Usage
/review:verify → 현재 git diff (staged/unstaged) 검증
/review:verify <path> → 지정 파일/디렉토리 검증
/review:verify docs/specs/xxx.md → spec/plan 문서 검증 (항상 2-Way)
/review:verify <path> --runner codex → Codex에서 실행 가능한 경로로 검증
/review:verify <path> --runner agy → Antigravity에서 실행 가능한 경로로 검증
/review:verify <path> --runner codex --reviewers agy
→ Codex 사용 중 필수 agy CLI 검증
/review:verify <path> --runner codex --reviewers agy,aperture
→ Codex 사용 중 agy 필수 + Aperture qwen3.8-max 검증
/review:verify <path> --runner agy --reviewers codex
→ Antigravity 사용 중 필수 Codex 검증
/review:verify <path> --runner agy --reviewers codex,aperture
→ Antigravity 사용 중 Codex 필수 + Aperture qwen3.8-max 검증
/review:verify <path> --reviewers codex,aperture
→ Aperture에서 qwen3.8-max 독립 검증
자동 트리거: 사용자 명시적 입력에서 "검증", "verify", "리뷰해줘" + 검증 대상 감지 시 호출.
제외 필터 (무한 루프 방지): 아래 상태에서는 자동 트리거 금지.
- 이미
/review:verify실행 중 - 직전 Verification Report 출력 중
- 세션 opt-out 플래그 활성
- 자기 자신의 검증 결과를 다시 "검증" 대상으로 감지
아키텍처 (v4)
graph TD
U[사용자 - zzizily verify 또는 자동 트리거] --> SK[skill - 메인 세션 신뢰 영역]
SK -->|1 대상 snapshot 결정적 생성| S1[git diff-파일목록 staged-untracked-rename]
SK -->|2 secret redaction-민감파일 배제| S2[gitleaks-sops 스캔 정제]
SK -->|3 격리 tmp dir 정제 복사본 생성| S3[격리 snapshot]
SK -->|4 원본 무결성 기록| S4[전 workspace hash-git status-mtime-perm]
SK -->|5 runner 선택| RN[Runner Adapter]
RN -->|Claude Code| CC[verify subagent]
RN -->|Codex| CX[codex exec 또는 Codex MCP]
RN -->|Antigravity| AG[agy -p]
RN -->|reviewer fanout| RV[Reviewer Providers]
RV --> CXR[Codex reviewer]
RV --> AGR[Antigravity reviewer]
RV --> AQW[Aperture reviewer - qwen3.8-max]
CXR -->|독립 결과| RN
AGR -->|독립 결과| RN
AQW -->|독립 결과| RN
RN -->|B-R-A-T 반환| SK
SK -->|6 모든 child process 종료 확인| W[TOCTOU 방지 대기]
W -->|7 원본 무결성 사후 광범위 검증| S5[변경 탐지 시 TAMPER]
S5 -->|8 취합-표시-권고| U
| 컴포넌트 | 역할 | 위치 |
|---|---|---|
skill verify |
진입점 + 보안 책임(snapshot/redaction/무결성 감시) + 판사(취합). runtime-neutral 계약 정의 | skills/verify/SKILL.md |
| runner adapter | Claude Code/Codex/Antigravity 중 현재 실행 환경에 맞춰 reviewer fanout 수행 | skill 본문 계약 |
subagent verify |
Claude Code runner adapter. 격리 snapshot에서 순수 검증만 수행. 보안 결정권 없음 | agents/verify.md |
| reviewer provider | Codex, Antigravity, Tailscale Aperture 등 독립 검증 결과 생산 | CLI/MCP/OpenAI-compatible API |
실행 주체와 reviewer 분리
| 축 | 값 | 의미 |
|---|---|---|
runner |
auto | claude | codex | agy |
snapshot 이후 fanout을 실제로 실행하는 주체. 기본 auto |
reviewers |
codex, agy, aperture 조합 |
독립 검증 결과를 내는 provider. aperture는 qwen3.8-max 단일 모델로 독립 검증 |
model_profile |
provider별 모델 지정 | codex:gpt-6-astra, codex:gpt-5.6-sol, codex:gpt-5.6-terra, codex:gpt-5.6-luna, agy:gemini-3.8-flash; Aperture는 고정 qwen3.8-max |
runner는 orchestration 위치만 바꾼다. 보안 책임(snapshot/redaction/integrity)은 항상 skill이 먼저 수행하고, reviewer는 격리 복사본만 본다.
Runner 선택
| runner | 사용 조건 | 실행 방식 |
|---|---|---|
auto |
기본값 | 현재 host가 제공하는 가장 안전한 runner 선택. Claude Code면 subagent, Codex면 local fanout, agy면 agy -p |
claude |
Claude Code plugin/subagent 사용 가능 | Agent(subagent_type: "verify")로 fanout. 필수 reviewer는 codex,agy, aperture 선택 |
codex |
Codex 세션 또는 codex exec 사용 가능 |
Codex가 runner가 되고 agy CLI를 필수 reviewer로 호출. aperture 선택 |
agy |
Antigravity CLI 사용 가능 | Antigravity가 runner가 되고 codex reviewer를 필수 호출. Codex 검증은 MCP 우선, CLI 차선. aperture 선택 |
Claude Runner 정책
사용자가 Claude Code를 사용 중이면 runner=claude로 간주한다. 이때 검증은 항상 아래처럼 수행한다.
| 구분 | reviewer | 실행 경로 | 정책 |
|---|---|---|---|
| 필수 | codex |
Codex MCP 우선, 실패 시 codex exec --sandbox read-only fallback |
생략 불가 |
| 필수 | agy |
agy -p CLI |
생략 불가 |
| 선택 | aperture |
OpenAI-compatible /v1/chat/completions |
--reviewers ... ,aperture 지정 시 qwen3.8-max 추가 |
Claude runner에서 사용자가 --reviewers codex처럼 일부만 지정해도 agy를 자동 보강해 codex,agy로 실행한다. Claude Code에서 Codex 검증은 MCP 우선, codex exec CLI 차선이다. aperture는 명시적으로 요청된 경우에만 추가한다.
Codex Runner 정책
사용자가 Codex를 사용 중이면 runner=codex로 간주한다. 이때 검증은 자기검증만으로 끝내지 않고 외부 reviewer를 반드시 붙인다.
| 구분 | reviewer | 실행 경로 | 정책 |
|---|---|---|---|
| 필수 | agy |
agy -p CLI |
생략 불가 |
| 선택 | aperture |
OpenAI-compatible /v1/chat/completions |
--reviewers ... ,aperture 지정 시 qwen3.8-max 추가 |
Codex runner에서 사용자가 --reviewers codex만 지정해도 agy를 자동 보강한다. 단, Codex 사용 중 최소 검증 경로는 agy CLI 필수 + aperture 선택이다. aperture는 명시적으로 요청된 경우에만 추가한다.
Antigravity Runner 정책
사용자가 Antigravity CLI를 사용 중이면 runner=agy로 간주한다. 이때 검증은 Antigravity 자기검증만으로 끝내지 않고 Codex reviewer를 반드시 붙인다.
| 구분 | reviewer | 실행 경로 | 정책 |
|---|---|---|---|
| 필수 | codex |
Codex MCP 우선, 실패 시 codex exec --sandbox read-only fallback |
생략 불가 |
| 선택 | aperture |
OpenAI-compatible /v1/chat/completions |
--reviewers ... ,aperture 지정 시 qwen3.8-max 추가 |
Antigravity runner에서 사용자가 --reviewers agy만 지정해도 codex를 자동 보강한다. 최소 검증 경로는 codex 필수 + aperture 선택이고, Codex 검증은 MCP 우선, codex exec CLI 차선이다.
Reviewer Provider
| reviewer | 기본 호출 | 모델 선택 |
|---|---|---|
codex |
Codex MCP 우선, 실패 시 codex exec |
provider_config.codex_model |
agy |
agy -p |
provider_config.agy_model |
aperture |
curl + OpenAI-compatible Chat Completions API |
provider_config.aperture_models 고정값 qwen3.8-max; base URL은 APERTURE_BASE_URL 환경변수 |
Codex 모델 선택
| 모델 | 선택 상황 | 피할 상황 |
|---|---|---|
gpt-6-astra |
기본값. high-risk code review, architecture, 보안/권한 경계, 충돌 resolution, 최종 verdict처럼 reasoning 품질이 중요한 검증 | 단순 typo/doc 변경, 빠른 존재 확인 |
gpt-5.6-sol |
레거시 플래그싱 fallback. gpt-6-astra 사용 불가 시 | gpt-6-astra 사용 가능 시 |
gpt-5.6-terra |
공식 docs/reference 확인, dependency/API 동작 검증, 외부 근거 기반 비교처럼 research 성격이 강한 검증 | 순수 local diff patch review만 필요한 경우 |
gpt-5.6-luna |
빠른 triage, small diff sanity check, 파일/심볼 mapping, 저위험 문서 변경 검증 | security/auth/data migration, 복잡한 cross-file reasoning |
기본 선택:
- 불확실하면
codex:gpt-6-astra. - gpt-6-astra 실패 시 레거시
codex:gpt-5.6-sol로 fallback한다. - 외부 문서·API·dependency 근거가 핵심이면
codex:gpt-5.6-terra. - 빠른 저위험 확인이면
codex:gpt-5.6-luna. - blocker 여부나 reviewer 간 충돌 판단은
gpt-6-astra로 승격한다.
Antigravity 모델 선택
| 모델 | 선택 상황 | 피할 상황 |
|---|---|---|
gemini-3.8-flash |
기본 fast lane. low/medium-risk diff, 실행 계획 sanity check, agent workflow 빠른 검토, Codex runner의 필수 외부검증을 낮은 latency로 붙일 때 | high-risk security/auth/data migration, 복잡한 architecture verdict |
gemini-3.1-pro |
high-risk design/code review, multi-file consistency, 긴 계획 검증, Flash 결과가 애매하거나 Codex와 충돌할 때 | 단순 small diff 검증 |
기본 선택:
- Codex runner의 필수
agyreviewer는 기본agy:gemini-3.8-flash. - 보안/권한/데이터/배포 영향이 있거나 reviewer 충돌이 있으면
agy:gemini-3.1-pro로 승격한다. - latency가 더 중요하고 변경이 저위험이면
gemini-3.8-flash를 유지한다.
aperture는 Tailscale Aperture의 OpenAI-compatible API에 직접 연결한다. APERTURE_BASE_URL은 /v1까지 포함한 API base URL로 환경변수에서만 읽고 출력·저장하지 않는다. client API key는 전송하지 않으며 Aperture가 tailnet identity로 인증하고 upstream credential을 주입한다.
Aperture 모델 선택
| 모델 | 검증 관점 | 피할 상황 |
|---|---|---|
qwen3.8-max |
coding, research, architecture·대안 검토, Codex/Antigravity와 독립적인 제3자 관점 | 단독 결과로 최종 판정 |
기본 선택:
aperturereviewer를 선택하면qwen3.8-max단일 모델을 실행한다.- 다른 reviewer 결과를 보지 않고 동일한 정제 prompt와 snapshot을 받는다.
- 모델 호출 실패 시 Verdict는
INCOMPLETE다. - Codex/Antigravity와 충돌하면 근거를 reviewer별로 보존하고 보수적 판정을 적용한다.
Aperture OpenAI-compatible 호출
검증 prompt를 1회 전송한다. PROMPT_FILE은 skill이 격리 dir 안에 생성하며 target kind, acceptance criteria, 상대경로와 정제된 파일 내용, B/R/A/T 출력 계약만 포함한다. APERTURE_BASE_URL 미설정, HTTP 오류, 빈 응답, JSON schema 불일치는 reviewer 실패로 처리한다. endpoint와 response body 전체를 로그에 출력하지 않는다.
command -v curl >/dev/null || { echo "INCOMPLETE: curl 미설치"; exit 1; }
command -v jq >/dev/null || { echo "INCOMPLETE: jq 미설치"; exit 1; }
: "${APERTURE_BASE_URL:?INCOMPLETE: APERTURE_BASE_URL 미설정}"
run_aperture() (
MODEL="$1"
RESULT_FILE="$2"
REQUEST_FILE=$(mktemp /tmp/verify-aperture-request-XXXXXX.json)
RESPONSE_FILE=$(mktemp /tmp/verify-aperture-response-XXXXXX.json)
trap 'rm -f "$REQUEST_FILE" "$RESPONSE_FILE"' EXIT
jq -n --arg model "$MODEL" --rawfile prompt "$PROMPT_FILE" '{
model: $model,
messages: [
{
role: "system",
content: "격리 snapshot만 검증하라. 다른 reviewer 결과를 추측하지 말라. markdown fence 없이 JSON object만 반환하라. schema: {verdict: PASS|FAIL|INCOMPLETE, summary: string, blockers: [{message,evidence}], risks: [{message,evidence}], assumptions: [{message,evidence}], tests: [{message,evidence}]}"
},
{role: "user", content: $prompt}
]
}' > "$REQUEST_FILE" || exit 1
curl --fail --silent \
--connect-timeout 10 --max-time 300 \
-H 'Content-Type: application/json' \
--data-binary "@$REQUEST_FILE" \
"${APERTURE_BASE_URL%/}/chat/completions" \
> "$RESPONSE_FILE" || exit 1
jq -er '
.choices[0].message.content
| select(type == "string" and length > 0)
| fromjson
| select(.verdict as $v | ["PASS", "FAIL", "INCOMPLETE"] | index($v))
| select(.summary | type == "string" and length > 0)
| select([.blockers, .risks, .assumptions, .tests] | all(type == "array"))
| select([.blockers[], .risks[], .assumptions[], .tests[]] | all(
(.message | type == "string" and length > 0) and
(.evidence | type == "string" and length > 0)
))
' "$RESPONSE_FILE" > "$RESULT_FILE"
)
QWEN_RESULT=$(mktemp /tmp/verify-aperture-qwen-XXXXXX.json)
if run_aperture qwen3.8-max "$QWEN_RESULT"; then
APERTURE_STATUS=success
else
APERTURE_STATUS=failed # runner는 INCOMPLETE로 취합한 뒤 임시 파일 정리
fi
QWEN_RESULT를 출처로 취합한 직후 모든 임시 파일을 삭제한다. curl -v, --show-error, set -x, endpoint echo는 금지한다.
외부 전송 동의
최초 1회 외부 provider(Codex/Antigravity/Tailscale Aperture gateway) 전송 동의 필요.
| 방식 | 설명 |
|---|---|
| Project-level 사전 동의 | .omc/ 또는 프로젝트 설정에 동의 기록 시 재확인 없이 진행 |
| 첫 호출 확인 | 미동의 상태에서 첫 호출 시 사용자에게 1회 확인. 동의 시 세션 내 재사용 |
미동의 시: 외부 provider 전송 금지 → 수동 검증 안내 후 종료. 검증 결과의 Integrity는 항상 Consent: DENIED로 표기.
보안 책임 (v3 핵심)
skill(메인 세션, 신뢰 영역)이 모든 보안 결정을 담당. dogfood 2라운드에서 확인된 핵심: subagent가 보안 검증을 자체 수행하면 검증 대상의 prompt injection에 조종되어 무력화됨.
1. 대상 snapshot 결정적 생성
# 검증 대상 파일 목록 (staged + unstaged + untracked + rename/delete/binary)
git diff --name-status HEAD # tracked 변경 (staged + unstaged)
git ls-files --others --exclude-standard # untracked (신규)
git diff --find-renames --name-only # rename 감지
git diff --diff-filter=D --name-only # delete 감지
git diff --numstat # binary/대용량 감지 (- - 형태)
| 케이스 | 처리 |
|---|---|
| staged + unstaged 혼합 | 양쪽 모두 포함 (작업 중인 전체 변경) |
| untracked 신규 파일 | git add -N --intent-to-add 후 diff에 포함 |
| rename | --find-renames로 감지, 신·구 모두 스캔 |
| delete | 삭제된 파일의 마지막 커밋 내용을 diff에 포함 |
| binary | --numstat으로 - 표기 감지, text 취급 불가 → 별도 표기 |
| 대용량 (1MB+) | diff 잘림 방지를 파일 단위 전달 |
대상 외 파일(변경 없는 파일)은 snapshot에서 제외. 단, 무결성 기록은 전 workspace 대상 (아래 참조).
2. Secret redaction (fail-closed)
# gitleaks 스캔 (설치 확인)
command -v gitleaks || { echo "FAIL-CLOSED: gitleaks 미설치"; exit 1; }
# 검증 대상 파일 대상 secret 스캔
gitleaks detect --source "$TARGET" --no-banner --redact --report-format json --report-path "$(mktemp /tmp/gitleaks-XXXXXX.json)"
# sops 암호화 파일 감지 (이미 암호화된 secret은 추가 처리 불필요)
find "$TARGET" -name '*.sops' -o -name '.sops.yaml' 2>/dev/null
# 매칭 시 [REDACTED] 치환
# binary/base64/분할 secret/encrypted 패턴도 동일하게 스캔
| 조건 | 처리 |
|---|---|
| gitleaks 매칭 | 매칭 라인 [REDACTED] 치환 후 snapshot 포함 |
| sops 암호화 파일 | 이미 암호화되어 있으므로 그대로 포함 (평문 아님) |
| scanner 실패/미설치 | fail-closed: 검증 중단. INCOMPLETE 리포트 |
3. 민감 파일 배제
snapshot 생성 시 아래 패턴은 원천 제외.
# 배제 패턴 (rsync --exclude 또는 find 필터)
EXCLUDE_PATTERNS=(
'.env*' # 환경변수 (평문 secret 가능)
'*.key' # 개인키
'*.pem' # 인증서/키
'.sops' # sops 메타데이터
'.gitleaks.toml' # gitleaks 설정 (allowlist로 secret 우회 가능)
'.codex/' # Codex config (API key 등)
'.config/**' # 사용자 config (토큰 가능)
'.aws/' # AWS credential
'.ssh/' # SSH 키
'.gnupg/' # GPG 키링
)
4. 격리 tmp directory 정제 복사본 생성
# 프로세스별 고유 격리 dir
ISOLATED_DIR=$(mktemp -d /tmp/verify-isolated-XXXXXX)
# 정제 복사본 생성 (배제 패턴 + redaction 적용된 파일만)
# 대상 snapshot 파일만 복사 (전 workspace 아님)
# EXCLUDE_PATTERNS 전체를 rsync --exclude로 전달 (secret exfiltration 방지)
rsync -av --files-from <(echo "$TARGET_FILES") \
--exclude '.env*' --exclude '*.key' --exclude '*.pem' \
--exclude '.sops' --exclude '.gitleaks.toml' \
--exclude '.codex/' --exclude '.config/**' \
--exclude '.aws/' --exclude '.ssh/' --exclude '.gnupg/' \
"$WORKSPACE/" "$ISOLATED_DIR/"
# 확인: 격리 dir에 민감 파일이 없어야 함 (EXCLUDE_PATTERNS 전체 검사)
find "$ISOLATED_DIR" \( \
-name '.env*' -o -name '*.key' -o -name '*.pem' \
-o -name '.sops' -o -name '.gitleaks.toml' \
-o -name '.codex' -o -path '*/.config/*' \
-o -name '.aws' -o -name '.ssh' -o -name '.gnupg' \
\) -print | grep -q . && {
echo "FAIL-CLOSED: 격리 snapshot에 민감 파일 잔류"; exit 1; }
원본 workspace 접근 차단: runner/reviewer의 cwd를 격리 dir로 강제. 원본 workspace 경로는 전달하지 않음.
5. 원본 무결성 기록 (검증 전)
전 workspace 상태를 기록. 대상 파일뿐 아니라 대상 외·metadata까지 사후 검증 범위.
# tracked 파일 hash
INTEGRITY_TRACKED_PRE=$(mktemp /tmp/verify-integrity-tracked-XXXXXX.txt)
git ls-files | xargs shasum -a 256 > "$INTEGRITY_TRACKED_PRE"
# untracked 파일 hash (무결성 감시 대상)
INTEGRITY_UNTRACKED_PRE=$(mktemp /tmp/verify-integrity-untracked-XXXXXX.txt)
git ls-files --others --exclude-standard | sort | xargs -r shasum -a 256 > "$INTEGRITY_UNTRACKED_PRE"
# git status 스냅샷
INTEGRITY_STATUS_PRE=$(mktemp /tmp/verify-integrity-status-XXXXXX.txt)
git status --porcelain=v1 --branch > "$INTEGRITY_STATUS_PRE"
# 파일 metadata (mtime, permission)
INTEGRITY_META_PRE=$(mktemp /tmp/verify-integrity-meta-XXXXXX.txt)
find . -type f \( ! -path './.git/*' \) -exec stat -f '%m %Sp %N' {} \; > "$INTEGRITY_META_PRE"
dispatch 실행 계약
도구: Agent(Claude runner) 또는 codex/agy CLI runner
subagent: verify (namespace review:verify, Claude runner에서만 사용)
입력(자연어 지시에 포함):
- isolated_cwd: 격리 tmp directory 절대경로
- target_kind: spec-plan | code
- target_files: 격리 복사본 내 상대경로 목록
- tier: light | standard | high (코드만)
- acceptance_criteria: 선택
- runner: auto | claude | codex | agy
- reviewers: codex,agy,aperture 중 1개 이상. runner=claude에서는 codex,agy 필수 + aperture 선택. runner=codex에서는 agy 필수 + aperture 선택. runner=agy에서는 codex 필수 + aperture 선택
- provider_config: Codex model/sandbox, Antigravity 모델, Aperture base URL 환경변수명과 고정 model(qwen3.8-max)
반환: runner 최종 메시지 = Verification Report
미발견 처리: Claude subagent discovery 실패 시 runner를 codex 또는 agy로 fallback. fallback 불가 시 에러 리포트 출력 후 종료
Claude runner 호출 예시
Agent(
subagent_type: "verify",
description: "교차검증 (격리 snapshot)",
prompt: """
isolated_cwd: /tmp/verify-isolated-aB3xY
target_kind: spec-plan
target_files:
- docs/specs/2026-07-15-feature.md
- plans/implementation-plan.md
tier: (spec-plan은 무시)
acceptance_criteria: (선택) "모든 섹션이 구현 가능한 단위로 분할되어 있을 것"
runner: claude
reviewers: codex,agy,aperture
provider_config:
codex_model: gpt-6-astra
codex_sandbox: read-only
agy_model: gemini-3.8-flash
aperture_base_url_env: APERTURE_BASE_URL
aperture_models:
- qwen3.8-max
격리 복사본으로 reviewer fanout 검증 후 Verification Report 반환.
"""
)
Codex runner 예시
isolated_cwd: /tmp/verify-isolated-aB3xY
target_kind: spec-plan
target_files:
- docs/spec.md
runner: codex
reviewers: agy,aperture
provider_config:
agy_model: gemini-3.8-flash
aperture_base_url_env: APERTURE_BASE_URL
aperture_models:
- qwen3.8-max
현재 Codex 세션이 runner로서 agy와 Aperture/qwen3.8-max를 한 fanout batch에서 독립 호출하고 join 후 Verification Report를 반환한다.
Antigravity runner 예시
agy -p "<검증 프롬프트>" <격리dir>
Discovery 실패 처리
Claude runner에서 subagent verify가 발견되지 않으면 runner=codex 또는 runner=agy fallback을 시도한다. fallback 불가 시 에러 리포트 출력 후 종료한다.
[ERROR] verify subagent discovery 실패
확인 사항:
1. plugin 설치 상태 (claude plugin list | grep zzizily)
2. agents/verify.md 존재 확인 (플러그인 루트 자동 발견, plugin.json 필드 불필요)
3. /reload-plugins 실행 후 재시도
무결성 사후 검증 (TOCTOU 방지)
runner 반환 후, 모든 child process 종료를 확인한 뒤 원본 무결성을 광범위하게 재측정·비교. timeout으로 잔존한 process가 검증 후 원본을 변경하는 TOCTOU(Time-of-Check-to-Time-of-Use) 공격 방지.
# 1. child process 종료 게이트
# 주 게이트: runner dispatch는 동기식 — runner 및 하위 reviewer 호출이 완전히 종료된 후에만 반환.
# 아래 폴링은 timeout으로 잔존할 수 있는 고아 프로세스 정리 대기 (벨트 서스펜더스)
for i in $(seq 1 60); do
pgrep -f 'codex exec|agy -p|curl.*v1/chat/completions' >/dev/null 2>&1 || break
sleep 1
done
# 잔존 시 경고 후에도 무결성 검증 진행 (잔존 = timeout 프로세스)
pgrep -f 'codex exec|agy -p|curl.*v1/chat/completions' >/dev/null 2>&1 && echo "WARNING: 외부 검증 프로세스 잔존 가능"
# 2. 전 workspace 무결성 재측정 (검증 전과 동일 항목)
INTEGRITY_TRACKED_POST=$(mktemp /tmp/verify-integrity-tracked-post-XXXXXX.txt)
git ls-files | xargs shasum -a 256 > "$INTEGRITY_TRACKED_POST"
INTEGRITY_UNTRACKED_POST=$(mktemp /tmp/verify-integrity-untracked-post-XXXXXX.txt)
git ls-files --others --exclude-standard | sort | xargs -r shasum -a 256 > "$INTEGRITY_UNTRACKED_POST"
INTEGRITY_STATUS_POST=$(mktemp /tmp/verify-integrity-status-post-XXXXXX.txt)
git status --porcelain=v1 --branch > "$INTEGRITY_STATUS_POST"
INTEGRITY_META_POST=$(mktemp /tmp/verify-integrity-meta-post-XXXXXX.txt)
find . -type f \( ! -path './.git/*' \) -exec stat -f '%m %Sp %N' {} \; > "$INTEGRITY_META_POST"
# 3. 비교 (tracked/untracked/metadata/대상 외/write→restore 모두)
diff "$INTEGRITY_TRACKED_PRE" "$INTEGRITY_TRACKED_POST"
diff "$INTEGRITY_UNTRACKED_PRE" "$INTEGRITY_UNTRACKED_POST"
diff "$INTEGRITY_STATUS_PRE" "$INTEGRITY_STATUS_POST"
diff "$INTEGRITY_META_PRE" "$INTEGRITY_META_POST"
| 결과 | 처리 |
|---|---|
| 차이 없음 | Integrity: VERIFIED. runner 결과 신뢰 |
| 차이 감지 | Integrity: TAMPER-DETECTED. 검증 무효 → Verdict INCOMPLETE |
| tracked 파일 변경 | runner/reviewer가 원본 수정 시도 (격리 우회 시도) |
| untracked 파일 생성 | runner/reviewer가 workspace에 파일 생성 |
| 대상 외 파일 변경 | runner/reviewer가 검증 대상 외 파일 조작 (prompt injection 의심) |
| metadata/permission 변경 | 권한 상승 또는 mtime 조작 |
| write → restore | 내용은 동일하나 mtime 변경 (숨겨진 수정 시도) |
취합 · 표시
runner의 Verification Report + skill의 Integrity 보고를 통합 표시.
## Verification Result
### Verdict (runner)
**Status**: PASS | FAIL | INCOMPLETE
**Target**: spec-plan | code
**Tier**: light | standard | high
**Runner**: auto | claude | codex | agy
**Routes used**: Codex(MCP | Bash-fallback | failed), Antigravity(agy | failed), Aperture(qwen3.8-max: success | failed)
### Integrity (skill)
**Consent**: GRANTED | DENIED
**Redaction**: OK | FAIL-CLOSED(scanner 실패)
**Integrity**: VERIFIED | TAMPER-DETECTED
### Findings (runner, 출처 표기)
- [Blocker] 즉시 수정 필요 — 근거(file:line/인용) — 출처: Codex | Antigravity | Aperture/qwen3.8-max | multiple
- [Risk] 수정 권장 — 근거 — 출처
- [Assumption] 검증된 가정 — 출처
- [Test] 제안 테스트 — 출처
### Cross-Check (2-Way 이상)
| 항목 | Codex | Antigravity | Aperture/qwen3.8-max | 일치여부 | 충돌해결 |
| :--- | :--- | :--- | :--- | :--- | :--- |
### Recommendation
APPROVE | REQUEST_CHANGES | NEEDS_MORE_EVIDENCE
[한 줄 근거]
blocker 존재 시: 수정 권고 구체적으로 제시 (file:line 기준). Integrity TAMPER 시: 검증 결과 무효, 원인 조사 권고.
격리 tmp dir 정리
# 결과 표시 완료 후 격리 dir 정리 (민감 정보 잔류 방지)
rm -rf "$ISOLATED_DIR"
# 무결성 측정 파일도 정리
rm -f /tmp/integrity-*-*.txt /tmp/verify-aperture-*.json /tmp/verify-isolated-* 2>/dev/null
데이터 흐름
- 사용자
/review:verify [대상]또는 자동 트리거 (rules 최소 규칙 + 제외 필터) - skill: 외부 전송 동의 확인 (최초 1회). 미동의 시 수동 안내 종료
- skill: 대상 snapshot 결정적 생성 (staged/unstaged/untracked/rename/delete/binary/대용량/혼합 우선순위)
- skill: secret redaction + 민감 파일 배제 → 정제. scanner 실패 시 fail-closed
- skill: 격리 tmp directory에 정제 복사본 생성
- skill: 원본 무결성 기록 (전 workspace: tracked/untracked hash, git status, mtime, permission)
- skill: runner 선택 후 dispatch (격리 cwd + 복사본 + config)
- runner: 격리 복사본으로 reviewer fanout 검증. B/R/A/T 반환
- skill: 모든 child process 종료 확인 (TOCTOU 방지 대기)
- skill: 원본 무결성 사후 광범위 검증. 변경 시 TAMPER-DETECTED → INCOMPLETE
- skill: 결과 취합·표시. blocker 있으면 수정 권고. 격리 tmp dir 정리
라우팅 매핑
| 대상 | 조건 | 라우팅 | 종료 조건 |
|---|---|---|---|
| spec/plan | (항상) | 기본 codex,agy 2-Way. Claude runner는 codex,agy 필수, Codex runner는 agy 필수, Antigravity runner는 codex 필수. aperture 선택 시 qwen3.8-max 추가 |
요구 reviewer blocker 0, 충돌 해결 |
| 코드 | 경량 | Claude runner는 codex,agy 필수. Codex runner는 agy 필수. Antigravity runner는 codex 필수. 그 외 runner는 티어 기본값 적용 |
blocker 0 |
| 코드 | 표준 | Claude runner는 codex,agy 필수. Codex runner는 agy 필수. Antigravity runner는 codex 필수. 그 외 runner는 티어 기본값 적용 |
blocker 0, non-blocker 확인 |
| 코드 | 고위험 | 기본 codex,agy 2-Way. Codex runner는 agy 필수, Antigravity runner는 codex 필수. aperture 선택 시 qwen3.8-max 추가 |
요구 reviewer blocker 0, 충돌 해결 |
티어 판정: 고위험 승격조건 최우선 (인증/권한/비밀값/네트워크 경계 변경, 데이터 모델/마이그레이션, 배포 파이프라인, public API 호환성, 대규모 삭제/리팩토링 100줄+, 롤백 어려운 변경). 설정/minor도 보안·호환성 영향 시 고위험.
Key Rules
- 보안 책임 skill 전담: redaction, 민감 파일 배제, 무결성 감시는 skill(신뢰 영역)만 수행. runner/reviewer는 보안 결정권 없음 (검증 대상 prompt injection 조종 가능성 전제)
- 격리 snapshot 필수: runner/reviewer
cwd=격리 tmp directory. 원본 workspace·.env·Codex config 접근 차단. 정제 복사본만 전달 - secret redaction fail-closed: gitleaks/sops scanner 실패 또는 미설치 시 검증 중단 (INCOMPLETE). 매칭 시
[REDACTED]치환 - 민감 파일 원천 배제:
.env*,*.key,*.pem,.sops,~/.codex/,~/.config/**등은 snapshot에서 제외 - 무결성 전 workspace 감시: 검증 전후로 tracked/untracked/hash/git status/mtime/permission 전 항목 비교. 대상 외 변경도 TAMPER
- TOCTOU 방지: 모든 child process 종료 확인 후 무결성 사후 검증. timeout 잔존 process의 사후 쓰기 차단
- Codex workspace-write 금지: 모든 Codex 경로
--sandbox read-only,cwd=격리 dir. MCP-first, 실패 시codex execfallback (workspace-write 절대 금지) - Codex reviewer 우선순위: Claude Code와 Antigravity CLI에서 Codex를 reviewer로 호출할 때는 MCP를 우선 사용하고, 실패/미발견/불완전 응답 시에만
codex execCLI로 fallback - Claude runner 필수 2-Way: Claude Code 사용 중에는
codex(MCP)+agy CLI검증을 반드시 수행.aperture는 선택 reviewer - Codex runner 필수 외부검증: Codex 사용 중에는
agy CLI검증을 반드시 수행.aperture는 선택 reviewer - Antigravity runner 필수 외부검증: Antigravity CLI 사용 중에는
codex검증을 반드시 수행. Codex 경로는 MCP 우선, CLI 차선.aperture는 선택 reviewer - Aperture 직접 호출: OpenAI-compatible
/v1/chat/completions를 호출 - Aperture secret 금지: endpoint/API key는 평문 출력·저장 금지. endpoint는
APERTURE_BASE_URL환경변수로만 참조 - Aperture 단일 모델:
aperture선택 시qwen3.8-max호출 성공이 required reviewer 성공 조건 - fail-closed 판정: APPROVE는 (요구된 reviewer 성공) + blocker 0 + Integrity VERIFIED + Consent OK. timeout/빈 응답/요구 reviewer 실패/무결성 변경 → INCOMPLETE (CI/merge에서 FAIL 동급 차단)
- spec/plan 항상 2-Way: 티어 무관 최소 2개 reviewer로 검증. 기본은
codex,agy - 외부 전송 동의 최초 1회: 미동의 시 수동 검증 안내. 동의는 세션 또는 project-level
- 무한 루프 방지: 자기 출력/실행 중 재트리거 금지 (제외 필터). rules 트리거는 최소 규칙만 잔류
- 격리 dir 정리: 결과 표시 후 격리 tmp directory 및 무결성 측정 파일 삭제 (민감 정보 잔류 방지)
- 한국어 리포트: 결과는 항상 한국어로 출력. finding은 provider/model 출처(Codex | Antigravity | Aperture/qwen3.8-max | multiple) 표기