/cc-spec:verify — Jev 에게 판정받고 잠그기
Seed spec 을 기계 검사(M-01~M-10)한 뒤 Jev(판정 전용 모델)에 한 번 보내 모호성 점수(5차원)와 3관점 패널 판정을 보정 확률로 받고 `docs/spec-evaluation-{slug}.md` 를 남깁니다 — PASS 면 `--lock` 으로 DRAFT→LOCKED. API 키가 없으면 UNVERIFIED 로 멈추고 절대 통과로...
| 항목 | 내용 |
|---|---|
| 실행 명령 | /cc-spec:verify |
| 분류 | 스펙 명확화 |
| 난이도 | ●●● 높음 |
한마디로#
작성한 핵심 명세(Seed spec)가 개발을 시작해도 될 만큼 또렷한지를, 그 명세를 쓴 AI 가 아니라 별도의 "판정 전용 모델(Jev)" 에게 묻고, 합격이면 도장(잠금)을 찍는 단계입니다. 시험을 본 학생이 자기 답안을 채점하지 않고 채점관에게 넘기는 것과 같아요. Jev 는 글을 쓰지 않고 확률·선택·점수만 돌려주는 모델이라, "대충 괜찮아 보인다"는 말로 넘어갈 수 없습니다.
누가·언제 쓰나요#
/cc-spec:seed로 초안을 만든 뒤, 이대로 확정해도 되는지 판정받고 싶을 때- 명세를 고친 뒤 다시 판정받고 싶을 때 (판정은 파일 내용 지문에 묶여 있어, 고치면 다시 받아야 합니다)
- 판정을 통과한 명세를 더 못 바꾸게 잠가두고(LOCKED) 다음 단계로 넘어가고 싶을 때
👉 먼저 필요한 것: 환경변수 TYPESAFE_API_KEY. 없으면 이 명령은 "판정 불가(UNVERIFIED)"로 멈춥니다 — 통과가 아니며 잠글 수 없습니다.
무엇을 해주나요#
- 1단계 — 기계 검사(무료, 즉시): 꼭 들어가야 할 10개 항목(M-01~M-10)이 채워졌는지 스크립트가 셉니다. 하나라도 빠지면 여기서 멈추고 보완 안내를 냅니다.
-
2단계 — Jev 판정(한 번의 요청): 인수 기준·제약·엔티티 한 줄마다 좁은 질문을 붙여 한꺼번에 보냅니다(보통 20~40문항).
- 모호성 5차원 — "이 줄에 모호한 말이 있나", "무엇이 계기이고 무엇이 관찰되나", "이 제약과 이 기준은 모순되나"를 줄마다 묻고, 걸린 줄을 코드가 세어 0~4 단계로 매깁니다 → 가중 평균이 0.2 이하이고 걸린 Must 줄·모순·빠진 엔티티·실패 사례 누락이 없으면 통과
- 3관점 패널 — 분석가·PM·아키텍트 좌석을 역할극이 아니라 좁은 판정(관찰 가능한가·범위 안인가·타입을 정의할 수 있나)으로 코드가 계산 → 막는 좌석이 0개면 통과. 애매한 답은 찬성으로 세지 않습니다.
-
리포트 —
docs/spec-evaluation-{이름}.md에 판정·확률·보완 안내를 남기고, 명세 파일의 메타데이터에 점수와 판정 도장(모델·날짜·지문)을 기록합니다. - 잠금 — 합격이고
--lock을 붙였거나 확인하면DRAFT → LOCKED.
판정 결과는 합격(PASS) / 조건부(CONDITIONAL) / 불합격(FAIL) / 판정 불가(UNVERIFIED) 넷 중 하나입니다.
어떻게 쓰나요#
/cc-spec:verify # 가장 최근 docs/seed-spec-*.md 를 판정
/cc-spec:verify --file {path} # 특정 파일
/cc-spec:verify --lock # 합격 시 바로 잠금
/cc-spec:verify --dry-run # Jev 에 보낼 요청만 보여 주고 호출하지 않음 (판정 없음)
안에서 무슨 일이 벌어지나요#
- 대상·지문 채취 — 파일을 읽어 버전(vX.Y.Z)과 내용 지문(hash)을 적어 둡니다.
- 기계 검사 — 10항목을 셉니다. 못 읽는 표가 있으면 "통과"가 아니라 "판정 불가"로 막습니다.
- Jev 호출 — 명세를 JSON 으로 직렬화해(표는 배열로) 한 번 보냅니다. 인수 기준·제약·엔티티 한 줄마다 좁은 질문을 붙이므로 보통 20~40문항입니다.
- 판정 집계 — 걸린 줄을 코드가 세어 모호성 점수와 패널 세 좌석을 계산합니다. Must 줄이 하나라도 걸리면 점수가 낮아도 "고치고 다시"입니다. 답이 하나라도 빠지면 판정 불가.
- 리포트·메타데이터 — Jev 는 이유를 쓰지 않지만 어느 줄이 걸렸는지는 나옵니다. 그 줄과 채점 기준을 근거로 에이전트가 보완 안내를 씁니다. 판정 자체는 바꾸지 않습니다.
- 잠금 — 합격 + (
--lock또는 확인) 이면 상태를 LOCKED 로 바꾸고 변경 이력에 남깁니다.
⚠️ 한국어 보정은 결론을 아는 fixture 5건으로 확인했습니다(config/thresholds.yaml jev.calibration). 답한 모델 버전이 보정한 버전과 다르면 리포트에 경고가 붙고, 확률이 0.25~0.75 로 애매했던 줄(uncertain_rows)은 사람이 한 번 더 읽습니다.
⚙️ 상세 옵션·실행 명세 (개발자 / AI 에이전트용)
Usage#
/cc-spec:verify # latest docs/seed-spec-*.md
/cc-spec:verify --file {path}
/cc-spec:verify --lock # lock on PASS without a second confirmation
/cc-spec:verify --dry-run # print the Jev request; no call; no verdictParameters#
| Parameter | Description | Default |
|---|---|---|
--file | Seed spec path | latest docs/seed-spec-*.md |
--lock | Lock on PASS | false (ask) |
--dry-run | Build and print the request only | false |
Prerequisites#
TYPESAFE_API_KEYexported — orCLOUDFLARE_API_TOKEN+CLOUDFLARE_ACCOUNT_IDfor the Workers AI route (seeskills/jev-gate/SKILL.md→ 준비; runjev_judge.py pingonce first). Neither → UNVERIFIED, exit 3.- Python 3.10+ (
jev_judge.pyis stdlib-only).
Execution Flow#
Normative declaration. The step subsections and Next Steps below are derived views
(plugins/cc-dev/rules/orchestration-graph.md §6) — where they disagree, this block wins.
references/EVALUATION_PROTOCOL.md is the SoT for item criteria, skills/jev-gate/questions/*.json
for the question texts and assertions, config/thresholds.yaml for the numbers.
V0 ACT 대상 스펙 결정 (--file | 최신) reads:docs/seed-spec-*.md
V0.1 ACT specVersion + specHash 스탬프 채취 (jev_judge parse) reads:docs/seed-spec-*.md
V1 GATE Stage 1 기계 검사 (jev_judge check, M-01..M-10) verdict:mechanical==="pass" undet:fail fail:Vfix
V2 ACT Jev 요청 1회 — 줄 단위 ambiguity + panel 좌석 (jev_judge judge) reads:skills/jev-gate/questions/ambiguity.json,skills/jev-gate/questions/panel.json
V2.g GATE Jev 게이트 (judge verdict === PASS — 걸린 줄·모순·누락 없음) verdict:jev==="pass" undet:fail fail:Vfix
V3 ACT 리포트 발행 + 메타데이터(점수·Gate 스탬프) 기록 writes:docs/spec-evaluation-{slug}.md,docs/seed-spec-{slug}.md own:lead
V4 GATE 잠금 요청 (--lock || 사용자 확인) verdict:lockRequested===true undet:fail fail:VEND
V5 ACT DRAFT → LOCKED (Locked 날짜 + S6 "locked" 행) writes:docs/seed-spec-{slug}.md own:lead
VEND ACT 보고만 하고 종료 (잠금 없음)
Vfix LOOP 지적 반영 ↺ 재판정 (CONDITIONAL / FAIL) contract:L-spec.verify-fix-rejudge
V0 --> V0.1 --> V1 --> V2 --> V2.g --> V3 --> V4 --> V5
V4 --> VEND
Vfix --> V0.1
V1 ==> Vfix on:mechanical!=="pass" bound:2 invalidates:V1
V2.g ==> Vfix on:jev!=="pass" bound:2 invalidates:V1,V2,V2.g읽는 법: 두 스테이지는 직렬이고 팬아웃이 없다 — V2 는 HTTP 요청 하나이지 에이전트 스폰이 아니므로
tier: 가 없다. 모든 되돌림은 Vfix 로 착지하고 Vfix --> V0.1 로 나가므로, 수정 라운드는 언제나
새 스탬프를 채취하고 Stage 1 부터 다시 시작한다. undet:fail 은 UNVERIFIED(키 부재 · API 오류 ·
답변 누락 · 파싱 불가)를 뜻하며, 이는 Vfix 가 아니라 환경을 고친 뒤 재실행할 일이다 — 스펙을
고쳐도 해결되지 않는다.
Step 1 — Target + stamp#
JJ="${CLAUDE_PLUGIN_ROOT}/skills/jev-gate/scripts/jev_judge.py"
python3 "$JJ" parse docs/seed-spec-{slug}.md # → version, status, spec_hash- Status must be DRAFT or LOCKED. On LOCKED, verify re-judges but never re-locks silently; say so.
Step 2 — Stage 1: mechanical#
python3 "$JJ" check docs/seed-spec-{slug}.md # exit 0 PASS / 2 FAIL- exit 2 → render the
checkstable (✅/❌/⚠️), write remediation per faileddetail, stop atVfix. - ⚠️ UNVERIFIED (unparseable section) blocks like FAIL (eval G1).
Step 3 — Stage 2: one Jev request#
python3 "$JJ" judge --set ambiguity,panel --spec docs/seed-spec-{slug}.md > /tmp/jev-verify.json
# exit 0 PASS · 2 FAIL or CONDITIONAL · 3 UNVERIFIED--dry-runprintsrequestand stops. A dry run has noverdictfield — never report it as one.- The JSON carries
set_results.ambiguity(ambiguity_score,grade,dimensions,findings,flagged_must_rows,uncertain_rows),set_results.panel(blocking,panel[seat].counted_as,panel[seat].basis),results(raw per-question),spec_hash,usage,warnings,caveats. - A state over 32,000 chars or more than 200 constraint × criterion pairs is not sent (UNVERIFIED) — split the spec by domain.
Step 4 — Verdict#
Worst wins: UNVERIFIED > FAIL > CONDITIONAL > PASS (references/EVALUATION_PROTOCOL.md → Integrated Verdict).
The agent may not alter a Jev verdict. It may disagree in the report's commentary and it may fix the spec.
Step 5 — Report + metadata#
- Write
docs/spec-evaluation-{slug}.mdin the protocol's report format. Every table row carries the stamp. - Remediation prose comes from the agent: for each flagged row (
findings,flagged_must_rows) and each non-APPROVE seat (basis), cite the row id, the Seed section and the rubric level text (references/AMBIGUITY_RUBRIC.md) that explains the gap. - Update the Seed metadata:
- Ambiguity Score: {score}·- Gate: {verdict} ({model_reported} · {YYYY-MM-DD} · {spec_hash_short})(this edit changes the file hash — the stamp inGate:refers to the hash that was judged, by design). - If
warningssays the answering model differs from the calibrated one, the report's Summary starts with that caveat, and borderline rows (uncertain_rows) are read by a person before locking.
Step 6 — Lock#
Conditions, all required: Stage 1 PASS · Jev PASS (not CONDITIONAL) · --lock or explicit user confirmation.
Status: DRAFT → LOCKED,- Locked: {YYYY-MM-DD}, append S6 row| {version} | {date} | locked (Gate PASS {spec_hash_short}) | verification | {approver} |.
Loop Contract#
L-spec.verify-fix-rejudge
inv: 라운드 진입 시 새 specHash 를 채취한다(Vfix --> V0.1). 이전 라운드의 모든 지적(실패한 M 항목 ·
level ≥ 1 차원 · non-APPROVE 좌석)이 disposition 을 갖는다: fixed(스펙 위치 인용) | accepted(사유) |
escalated(이슈 id)
prog: open = disposition 이 없는 지적 수, 라운드마다 강한 감소. 같은 지적이 disposition 없이 두 번
제기되면 진행 없음 — 남은 라운드를 같은 수정에 쓰지 않고 /cc-dev:unstuck 으로 올린다
term: mechanical==="pass" && jev==="pass"
budget: outer 2 라운드 (config/thresholds.yaml verify.max_fix_rounds; 각 ==> 의 bound:2). 3회째는 문구가
아니라 문제 정의를 다시 잡을 신호다 — /cc-spec:seed 로 돌아간다
exhaust: FAIL 확정 + 미해소 지적·마지막 disposition·스탬프를 리포트 라운드 표에 남기고 사람에게
에스컬레이트. "경고 후 통과" 금지. UNVERIFIED 는 라운드를 소모하지 않는다(환경 문제)
resume: docs/spec-evaluation-{slug}.md 의 라운드 표(라운드 · 스탬프 · Stage 1 · 2a · 2b · disposition)가
위치 기록이다. 대화 카운터는 /clear 를 넘지 못하므로 예산이 아니다
log: 라운드당 한 줄 "round 2/2: open 3→1, fixed AC-03, stamp v1.0.1/9f3ac1, ambiguity 0.27→0.18"Output#
| File | Path |
|---|---|
| Evaluation report | docs/spec-evaluation-{slug}.md |
| Seed spec (metadata; Status on lock) | docs/seed-spec-{slug}.md |
Next Steps#
- PASS + locked →
/cc-product:plan(Planning stage) ·/cc-spec:status --against …for drift checks - CONDITIONAL → fix the flagged dimensions / seat, re-run (≤ 2 rounds)
- FAIL → fix the relevant stage and re-run; after round 2, go back to
/cc-spec:seedor a human - UNVERIFIED → set
TYPESAFE_API_KEY/ fix the parse error, re-run. Do not lock.
Related Commands#
/cc-spec:seed— author the Seed spec/cc-spec:status— read-only Jev drift report against the LOCKED seed/cc-spec:evolve— evolve a LOCKED seed
References#
references/EVALUATION_PROTOCOL.md— item criteria + verdict rules (SoT)skills/jev-gate/SKILL.md—jev_judge.py, question sets, fail-closed rules, calibration checkskills/jev-gate/questions/ambiguity.json,panel.json— the questions actually sentconfig/thresholds.yaml— numbersplugins/cc-dev/rules/orchestration-graph.md— flow notation (§1), loop contract (§2), gate tri-state (§3)