AGENT SKILL

design

에이전트 팀을 활용한 기능 설계 토론 진행

适用职业设计师
使用场景视觉设计
License 许可
MIT
所属仓库
Nharu/cc-cmds
最近更新
2026-11-13
Stars
★ 3
Forks
1

01 前言 Front Matter

name
design
usage
/cc-cmds:design <task>
options
[ { "kind": "positional", "name": "<task>", "summary": "설계 토론을 진행할 작업 주제 (자유형 한국어/영문 텍스트).", "required": true } ]
description
에이전트 팀을 활용한 기능 설계 토론 진행
when_to_use
사용자가 새 기능 설계/아키텍처 결정/다관점 검토가 필요한 설계 논의를 요청할 때
disable-model-invocation
true

03 SKILL.md 正文

Conduct a design discussion using an agent team for the given task. All team discussions and inter-agent communication should be in English to optimize token usage. User-facing communication (interviews, final presentation) and saved documentation should be in Korean.

Control-Flow Invariants

These phase-transition rules govern turn-yielding and MUST stay near the top of this file. Post-compaction reattaches only the first ~5K tokens with priority; a summarized-away transition rule causes silent mis-transition — waiting for the user where the skill must auto-advance, or prompting where it must yield.

CFI-1a — Leg dispatch is a turn-ending act

After the user approves the Step 2 composition, the seat (this conversation) writes the interview brief, launches the discussion leg — the sibling skill design-discuss-unattended, which runs Step 3 and Step 4 through the save in its own session — records the pending leg in leg.json, and then YIELDS the turn. Nothing downstream of Step 4 runs at dispatch time. The dispatch form is part of this invariant: it is a harness-tracked background call, never a detached form (nohup, a bare &) and never a foreground call — only the tracked form wakes the seat, and a foreground call the harness later moves to the background dies with the seat. Yielding is safe here and fatal in a print-mode shard: a conversational seat survives its own yield and receives the next wake-up, whereas a print-mode process (autopilot-router-shift and its kind) ends at the yield — so do not rewrite this yield as a hold.

CFI-1b — The leg's completion wake-up is not a turn-ending act

The wake-up is a hint, never the channel: push completion signals drop, duplicate, mis-route, and after a seat restart the background handle is an orphan nobody re-arms. The pull-check that is the first act of every turn (Step 2, Leg pull-check) is by construction the only channel. The check is active exactly while $STATE/leg.json exists and its state is pending or parked — this sentence is the one definition of that condition, and every other mention points here. done is written by the seat alone, when it consumes a completion artifact, so a consumed completion switches the check off instead of being read a second time. What completes depends on the marker's phase. On discuss, when the check finds the leg's artifact predicate true — the design document exists, its ledger parses, every non-aborted roster row is done, and presentation.md exists with a matching header version (an exit code is not part of the predicate) — the seat renders the three presentation.md blocks verbatim, moves the file aside, and continues in the same turn into Step 5 (Unresolved Issue Walkthrough), without yielding and without any user prompt. Rendering the results is NOT a turn-ending action. On resume, completion is coherence.md with a matching header, and it returns the seat to Step 7 — never to Step 5, which CFI-3c forbids once Step 7 has begun. When the predicate is false the seat goes to recovery and does not enter Step 5.

CFI-2 — Step 6 entry: automatic arrival, then notice-and-yield

(a) ARRIVAL (transition): reaching Step 6 (Plan Refinement) is automatic — Step 5 → Step 6 needs no user prompt. Do not stop on the way in. (b) FIRST ACTION: once at Step 6, the lead emits ONE short Korean notice that refinement is starting (inviting the user's input), then YIELDS the turn and waits for the user to speak first. At Step 6 ENTRY do NOT call AskUserQuestion to open the discussion or manufacture a refinement question — no question tool, no options menu, no "무엇을 다듬을까요?" prompt; Step 6 opens as a plain yield. (c) SCOPE: this prohibition is the ENTRY moment ONLY; it does NOT restrict AskUserQuestion elsewhere — the Step 6 state-check's slug-ambiguity prompt (fires before the entry notice, during pre-entry cleanup) and Step 6's later "propose a new team" approval path remain valid, as do all Step 4/Step 5 AskUserQuestion uses.

CFI-3 — Step 6 exit → Step 7 is automatic; the Class C pass is single-pass and terminal

(a) EXIT (transition): Step 6 ends when the user signals the plan is satisfactory (lead judgment on the reply, no regex — the same class of read as Step 5's abort detection). That signal enters Step 7 (Class C Coherence Pass & Freeze) in the SAME turn: no prompt, no AskUserQuestion, no turn-ending "완료했습니다". Ending the turn on the satisfaction signal is a mis-transition — Step 7 would never run and an un-cohered document would reach the downstream audit. (b) NON-RECURSION: Step 7 runs the coherence pass EXACTLY ONCE over the final text. Its own corrections are never re-submitted for another pass. Re-running it, or looping it until "clean", reproduces inside design the unbounded review loop this pipeline removed. (c) FREEZE / TERMINAL: when Step 7 completes the document is FROZEN — design makes no further edits to it, and there is no path back to Step 5 or Step 6. Further refinement is a new /cc-cmds:design invocation, which runs its own Step 7 before freezing again. Every post-freeze edit re-opens the induced- defect rate that the downstream Class S audit's guarantee rests on. (d) NOT A ROUND CAP: this invariant fixes the freeze and the non-recursion discipline. It carries no numeric round budget — do not add one here.

CFI-4 — A seat whose next duty another SESSION owns may only wait or recover

While leg.json names a leg that has neither completed (artifact predicate false) nor parked (no park.md), the seat's only lawful actions are to wait or to run the recovery ladder of the pull-check. It never re-dispatches (two legs on one ledger) and never enters Step 5. The owner is a session, not a process: the leg parks and exits, so no process existing while the duty stands is the normal state.

Workflow

Step 1: Requirements Interview & Codebase Exploration (Korean)

  • Do NOT create a team yet. First, interview the user to understand requirements. Read ${CLAUDE_SKILL_DIR}/../_common/requirements-interview.md and follow it for the whole interview — the depth, the discipline, issue-originated design, reproduction-first, verification-first and the closing read-back all live there. The bullets below are this skill's own wiring of that interview into the steps that follow.
  • Reproduction hand-off. When the lead judges that reproduction should not be done inline, it is delegated to a Step 3 reproduction agent — proposed as the reproduction agent role in Step 2, which drives Step 3's Round 0.
  • Reproduction data points feed Step 4. The four reproduction data points carry the same labels as the ## 재현·근본원인 section schema in Step 4, so Step 4 can fill that section verbatim.
  • Tier-2 feeds Step 4. Tier-2 of the reproduction fallback (and only Tier-2) triggers the lead to create an unresolved-issue pointer during Step 4 synthesis (see Step 4).
  • Delivery shape (five questions only the user can answer). Ask these during the interview whenever the work could land as more than one pull request or touch more than one repository: which repositories the change lands in (remote slug, not a path — paths differ per machine and per worktree); how many slices it should land as; where an apply happens, if anywhere; who runs that apply — the pipeline or a person; and what parks if an apply fails (the blast radius, which defaults to the whole repository and may only be narrowed). These five are knowledge the user holds and nothing in the codebase does, and this interview is the only place a human is present to give them. Their answers become the ## 구현 슬라이싱 section of Step 4's document, which downstream orchestration parses mechanically rather than inferring — so an unanswered question here is not a gap that gets filled later, it is a section that never exists and a plan that silently falls back to being re-derived by a model.
  • Base design suggestion. When the interview shows the request splitting into pieces that each still need their own design judgment — the same criterion the autopilot entry judgment uses for a base run — show one Korean note proposing /cc-cmds:design-base (a base design: the contracts between the pieces and a ticket split, each ticket designed later on its own) and let the person choose: AskUserQuestion with 이대로 단일 설계 계속 ← 추천 · 중단 — /cc-cmds:design-base 로 다시 시작 (등급 2 — the scope of the work is the person's to decide). Nothing switches or calls automatically; on the second option end the workflow with that command line.
  • Base linkage. When the argument or the interview points at a ticket of a base design (<문서>.md#T<n>, or a tracker reference the registry knows), read ${CLAUDE_SKILL_DIR}/../_common/base-linkage.md and resolve it as it says — asking the person where it resolves to 「찾지 못함」 or 「재앵커링 불가」 or the hash disagrees. A resolved ticket puts a ## 베이스 제약 section into the Step 4 document, before ## 합의된 아키텍처, with the ticket block and its contract blocks copied verbatim, and puts as the first line of ## 합의된 아키텍처 the fixed sentence 「이 문서의 ## 베이스 제약 절에 옮긴 티켓 블록과 계약 블록은 이 절의 결정과 똑같이 구현을 구속한다.」 — that is what binds the section for the attended implement, whose binding tier is named by section and does not list it; the design never changes that section. Step 4 runs in the leg, which writes that section only when the brief names the ticket, so a resolved ticket goes into the brief as three lines (dispatch item 1 below).
  • Verification profile feeds Step 2. A verifiable claim that cannot be settled during the interview is kept for residual encoding at Step 4 synthesis. If Step 1 reveals a verification-heavy profile (multiple (c) external facts, expected (d)/(e) experiments, feasibility questions already visible), flag it so Step 2 can seed a dedicated verification agent.
  • The read-back and the issue merge feed the brief. The confirmed closing read-back and any issue-merge decision are what the brief's ## 요구사항 block carries to the discussion leg (dispatch item 1 below).

Step 2: Team Composition Proposal (Korean)

  • Based on interview results and codebase exploration, propose a team composition to the user.
  • How many roles: bounded by _common/agent-team-protocol.md's ### Team size budget. Read the ceiling and its coordinator-class carve-out there — this step deliberately states no number of its own, so the budget cannot drift into two values.
  • Specify each teammate's role, exploration scope, and model (use short aliases: "opus", "sonnet", "haiku"). Propose sonnet for every teammate by default. Propose opus only when the work that teammate takes on needs it, and write that reason on the teammate's own line of the Korean proposal, so the approval is given with the reason in view. The reason is about the work; the size or importance of the task is not a reason. The person may change any model when approving, and a second opinion on promotion stays with /cc-cmds:design-upgrade.
  • Reproduction agent role (optional, issue/bug tasks): if the reproduction-first filter test (Step 1) is YES and the lead judges a dedicated reproducer is better than reproducing inline, propose a reproduction agent as one of the roles. Its scope is: reproduce the symptom, emit the same four data points + 근거 등급 as Step 1, and — as a precondition of broadcasting — clean up and verify the tree (revert instrumentation, delete out-of-tree artifacts, confirm git status --porcelain == baseline) before findings leave it. This agent drives Step 3's Round 0 (below).
  • Verification agent role (default on, parallel to the reproduction agent): propose a verification agent as one of the roles by default, not only when Step 1 anticipated a verification-heavy profile. The seat is not a domain perspective — it is the seat that settles claims against reality. On the small row selected by the gate below it replaces the second domain seat (domain 1 + verification 1); on larger rows it is an addition. It is counted, not carved out — the carve-out in _common/agent-team-protocol.md is for orchestration roles, and this seat's job is measurement. So the seat occupies a roster row like any other, and the largest row is three domain seats plus the verification seat — four rows, not five. When three domain perspectives are genuinely not enough, do not fold a domain into the verification seat (it would do both jobs worse); take the scope back to the user, as the budget rule does above its own ceiling. Its scope is: settle assigned verifiable claims per _common/verification.md, pre-register each claim's 주장 + 기대 결과 before running, and — as a precondition of broadcasting a verdict — clean up and verify the tree (the two-command boundary gate; for (e), git worktree remove --force + git worktree prune + the record check of _common/verification.md §6.2 — every recorded path gone and no entry carrying this team's owner token) before the verdict leaves it. The Quality Gate can hold a gated proposal and route its claims to this agent. Same cleanup-before-findings-leave precondition + worktree-teardown duty as the reproduction agent.
  • Disclose the leg's permission posture in the proposal, so the approval covers it. The leg runs under --permission-mode bypassPermissions — a human decision already taken for this skill, not a per-run question — but the seat is granting that posture to a child process nobody watches, so the proposal carries one Korean line naming the posture and its blast radius, verbatim: "승인하시면 설계 토론(Step 3·4)은 별도 헤드리스 세션에서 권한 확인 없이(bypassPermissions) 실행됩니다 — 그 세션과 팀원은 이 계정이 쓸 수 있는 모든 경로에 쓰고 Bash·의존성 설치·웹 조회·에이전트 생성을 확인 없이 실행하며, 파이프라인 게이트는 걸리지 않고 코드 무수정 규칙은 지시문으로만 지켜집니다." An approval of a proposal that lacked this line is not an approval of the posture, and the dispatch below does not proceed on it. The approval time is recorded in leg.json (item 3 of the dispatch block).
  • Only create the team after the user approves the composition. On the normal path the seat does not create the team itself — it hands the approved composition to the discussion leg below, and the leg spawns the team inside its own session.

Leg dispatch (after approval — the seat launches the discussion leg)

Step 3 and Step 4 through the save run in a separate headless session, the leg, because the Step 3 rounds and the Step 4 fidelity pass dispatch into the same ledger rows and a same-key resume of a live member (a send-back, a nudge, Case 1 or Case 3) is addressable only from the session that dispatched it, so Step 3 and the pass must share one session, and the seat's own context is what the split keeps below the compaction threshold. The seat hands the leg everything Step 1 and Step 2 produced that is on disk nowhere else, then yields (CFI-1a).

  1. Write the interview brief. Read ${CLAUDE_SKILL_DIR}/../_common/sidecar.md ## 1 and write <base>/docs/design-brief/{slug}.md, where {slug} is the folded document key of §1.1 for the document this workflow will save (docs/{topic-slug}.md → docs-{topic-slug}; the document need not exist yet — the key is derived from the path) and <base> is the main worktree root. Line 1 is an H1; line 2 is the machine header, verbatim: <!-- cc-design-brief v1; writer=design; reader=design-discuss-unattended; owner-doc=<document key>; NOT a design doc; mechanism-local, never staged by a skill -->. Then exactly these eight blocks, in this order, each a ## heading: ## 요구사항 (the interview's requirements and any issue-merge decision; when Step 1's base linkage resolved a ticket, also three field lines — **베이스 문서**: <base document path>, **티켓**: T<n>, **베이스 sha256**: <whole-file sha256 of the base document, measured at resolution> — which are what the leg re-measures before it spawns and what makes it write ## 베이스 제약; without them the section is not written and nothing warns) · ## 제약 · ## 배포 형상 (the five delivery-shape answers as five field lines — **레포**, **슬라이스 수**, **적용 위치**, **적용 주체**, **실패 시 파킹** — writing 없음 where an answer does not apply; an omitted line and a negative answer are different facts, so no line is omitted) · ## 탐색 결과 (codebase exploration findings) · ## 재현 (the four reproduction data points and 근거 등급, or 없음) · ## 팀 구성 (the approved roster: role, scope, model per member) · ## 기준선 (the pre-workflow git status --porcelain -z output, verbatim — assertion 1 of the two-command boundary gate compares against this and the leg cannot re-derive it once the tree has moved) · ## 대상 (five field lines: **topic-slug**, **문서 키**, **접힌 슬러그**, **docs 대상 디렉터리**, **검증 편중 프로필**). The file's last non-empty line is the terminator <!-- cc-design-brief: end -->. Write it with the atomic form of sidecar.md §1.3 (same-directory mktemp, whole-file mv). Never stage it — the brief stays out of the index by this skill's discipline, not by a .gitignore edit.

  2. Prepare the state root. STATE="${XDG_STATE_HOME:-$HOME/.local/state}/cc-cmds/design/{slug}"; mkdir -p "$STATE". If $STATE/leg.json already exists, compare its brief_sha256 with the sha256 of the brief just written: different means a stale marker from an earlier workflow — move it aside to $STATE/leg.stale.<ISO8601>.json and continue (CFI-4 does not apply to a stale marker); identical means a leg for this very brief is already pending — do not dispatch, go to the pull-check below (CFI-4).

  3. Mint the session id and write leg.json first. LEG_SID=$(uuidgen | tr 'A-Z' 'a-z'), then write $STATE/leg.json (atomic form) before launching: { "slug", "session_id", "phase": "discuss", "state": "pending", "dispatched_at", "heartbeat_at", "redispatch_count": 0, "brief_sha256", "leg_out": "$STATE/leg.<session_id>.out", "leg_err": "$STATE/leg.<session_id>.err", "prior_session_ids": [], "transcript_bytes": 0, "leg_json_mtime_at_dispatch", "permission_posture": "bypassPermissions", "posture_approved_at" }. permission_posture and posture_approved_at (the time of the Step 2 approval whose proposal carried the posture line) record that the posture was approved rather than assumed; a marker lacking either names a leg dispatched without that decision. The progress baseline (transcript size 0, this file's own mtime) is written in the same write so the first pull-check has something to compare against. Spelling rule: a harness-owned identifier keeps the harness spelling (session_id, as the -p result object names it); fields this design coined are snake_case. No pid is recorded — the liveness oracle below carries it.

  4. The launch line. Every preflight line is a hard stop, because every failure it catches otherwise presents as exit 0 · subtype success · no artifact — the one shape nobody can debug afterwards. Fill nothing in by hand except what the seat computes above; the block carries no placeholders.

    mkdir -p "$STATE"          # leg.json is written here first, so this comes first
    : "${CLAUDE_CONFIG_DIR:?CLAUDE_CONFIG_DIR is unset - refusing to launch the leg}"
    CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=14400000
    CLI=$(type -P claude)      # absolute path: a bare `claude` is intercepted by this machine's shell guard
    PLUGIN_DIR="${CLAUDE_PLUGIN_ROOT:-$(cd "${CLAUDE_SKILL_DIR}/../.." && pwd)}"
    [ -x "$CLI" ]        || { echo "leg: CLI not executable: $CLI" >&2; exit 2; }
    [ -d "$PLUGIN_DIR" ] || { echo "leg: plugin dir missing: $PLUGIN_DIR" >&2; exit 2; }
    [ -n "$LEG_SID" ]    || { echo "leg: no session id minted" >&2; exit 2; }
    [ -n "$CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS" ] \
                         || { echo "leg: wait ceiling unset - the team would be killed at 600s" >&2; exit 2; }
    
    CLAUDE_CONFIG_DIR="$CLAUDE_CONFIG_DIR" \
    CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS="$CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS" \
    "$CLI" \
      --plugin-dir "$PLUGIN_DIR" \
      --session-id "$LEG_SID" \
      --model opus \
      --effort high \
      --permission-mode bypassPermissions \
      --dangerously-skip-permissions \
      --output-format json \
      --strict-mcp-config \
      -p "/cc-cmds:design-discuss-unattended docs/design-brief/{slug}.md" \
      >> "$STATE/leg.$LEG_SID.out" 2>> "$STATE/leg.$LEG_SID.err" < /dev/null
    

    Why each element is there:

    element failure without it
    $CLI absolute path this machine's shell guard intercepts a bare claude, exits 1 and creates no session at all — the only non-zero phenotype
    CLAUDE_CONFIG_DIR:? an empty value lands in an account-less config dir, and the liveness oracle below can only see legs launched under the same config dir
    the wait ceiling print-mode wind-down kills the team at the default 600 s ceiling and exits 0
    --plugin-dir the slash command resolves to nothing: exit 0 · subtype success · num_turns 0 · Unknown command:
    a fresh --session-id per dispatch the transcript is the progress oracle and must be findable; a reused id is refused
    --output-format json the only source of permission_denials, subagent_stats.killed.system, num_turns
    --strict-mcp-config the leg needs no MCP server; loading them costs startup time and context
    both streams into $STATE, per-attempt file names the ceiling marker is on stderr, every other marker on stdout; after a seat restart these two files are the only evidence, and appending attempts into one file makes every attribution predicate match the previous attempt's bytes

    Flags that must not appear: --setting-sources "" (silently cuts the settings chain) · --settings <file> (-p silently ignores a settings file that fails validation) · --restricted (removes Bash, which the two-command boundary gate uses) · --continue / -c (inherits the seat's conversation) · --fork-session (mints a new id on resume and destroys the handle leg.json holds) · --bg (no push wake-up, so CFI-1b does not hold). The permission posture is a human decision already taken, and checkably so — disclosed with its blast radius in the Step 2 proposal the user approved, and recorded in leg.json as permission_posture and posture_approved_at (item 3). Without a posture the leg fails its first docs/{slug}.md write and reports success — exit 0, subtype success, is_error false, a file never written.

  5. Dispatch as a harness-tracked background Bash call (run_in_background: true) — never detached, never foreground (CFI-1a). Immediately after dispatch emit one Korean notice — "설계 토론을 별도 프로세스로 파견했습니다. 진행은 매 턴 시작 시 확인합니다." — and yield the turn.

  6. The resume line is the same environment, the same flags and the same stream redirections with --session-id "$LEG_SID" replaced by -r "$LEG_SID" and the -p prompt replaced by the message. "Same flags" includes the two redirections — without them a resumed leg writes to neither file and the attribution step has no input. The message is never inlined on the command line. Every message the seat resumes with carries backticks — the park answer template names its site in them, and the Step 7 notes are Markdown — and inside a double-quoted argument the shell runs each backtick span and $( ) as a command, so the message would arrive silently rewritten while the leg still exits 0. The seat therefore writes the message with the Write tool to a same-directory temporary file and mvs it to $STATE/resume.<ISO8601>.txt (the atomic form of sidecar.md §1.3), sets RESUME_MSG to that path, guards it with [ -s "$RESUME_MSG" ], and passes it as -p "$(cat "$RESUME_MSG")" — the output of a command substitution is not expanded again, so the bytes arrive as written. The file stays in $STATE as the record of what was sent. A resume keeps the session id and therefore keeps the team; a re-dispatch mints a new id and loses it. Resume whenever the session is usable.

Leg pull-check (the first act of every turn while the check is active — CFI-1b)

The seat reads $STATE/leg.json before anything else, every turn, for as long as the check is active (CFI-1b defines when). The user's next message is the guaranteed wake-up; there is no watcher process and no push channel (CFI-1b).

  • 0 — Park. If $STATE/park.md exists and its header line matches <!-- cc-design-park v1; exactly, the leg is parked: render the record's 질문 문면, its 선택지 labels and descriptions verbatim to AskUserQuestion — 등급 2 — composing nothing (the seat holds none of the discussion, so it cannot author options; the _common/askuserquestion.md conformance check is the seat's, as the tool's caller). In the same turn as the question, consume the record: move it to $STATE/park.answered.<ISO8601>.md and set leg.json state back to pending (never delete it — the verbatim question must survive for tests and later readers). Without this consumption a parked leg never finishes: the predicate is file existence, so the same question would go out again next turn. When the answer arrives, write the neutral operational message to a resume file and resume the leg through the resume line (dispatch item 6 — never inlined) "park 질문 <자리 id> 에 대한 사용자의 답은 다음과 같다: …" — neutral wording, because a "remember this secret"-shaped prompt is refused as injection while still exiting 0 — and classify the resumed turn as an artifact turn, not a terminal state.
  • 1 — Complete, branched on leg.json phase. discuss — if the artifact predicate holds (CFI-1b; the header the predicate matches is <!-- cc-design-presentation v1; writer=design-discuss-unattended; reader=design; slug=<slug> -->), render the three blocks of $STATE/presentation.md — ## 고지, ## 검증 집계, ## 결과 — verbatim, consume the record the way step 0 consumes park.md — move it to $STATE/presentation.rendered.<ISO8601>.md, never delete it — set state: done, and continue into Step 5 in the same turn. resume — complete when $STATE/coherence.md exists and its first line is <!-- cc-design-coherence v1; writer=design-discuss-unattended; reader=design; slug=<slug> -->; set state: done and continue Step 7 at its triage step (6) in the same turn. On this phase presentation.md is never consulted: it belongs to the discuss phase, and completing on it would re-enter Step 5 after Step 7 has begun, which CFI-3c forbids. This step alone separates real completion from a permission refusal or an injection refusal, which are indistinguishable from success in every machine-readable field.
  • Three readings, none a substitute for another. ⓐ Artifact (steps 0–1) decides success and is positive-only. ⓑ Progress — the leg transcript's size (${CLAUDE_CONFIG_DIR}/projects/*/<session_id>.jsonl, globbed by session id; never re-derive the project key) plus leg.json's mtime — decides whether anything is happening. ⓒ Liveness — claude agents --json queried by sessionId only (never by kind: a -p leg is listed as "interactive", so a kind == "background" filter silently misses every leg), under the same CLAUDE_CONFIG_DIR; absence is not a death verdict. Liveness answers identity, not progress, so its duty is to withhold writes, never to suppress an alarm.
  • 2 — Progress reading. Compare transcript size and leg.json mtime with the previous turn's record. 2a either grew → record the new reading and do nothing this turn. 2b both still, fewer than two consecutive turns → record and stop. 2c both still for two or more consecutive turns → query the liveness oracle first: an entry means a process is alive in that session — neither resume nor attribute; no entry means the leg exited — go to attribution. 2d still and alive for four or more turns → AskUserQuestion — 등급 2 — with exactly two options, 더 기다림 and 포기 (on 포기 the pid comes from the oracle entry just read — the design records none); this is not a park, because a park exists only where the questioner has no question tool.
  • Attribution, 3–8 (launch-line defect vs. death). The exit code carries one bit (zero / non-zero) and nothing more; inside exit 0 never branch on the exit code or on subtype. In order: 3 ceiling kill — leg.err matches Background tasks still running after, or subagent_stats.killed.system > 0 → raise the ceiling and --resume the same session (nothing is lost) · 4 unresolved slash — result contains Unknown command: → fix --plugin-dir, launch with a new session_id · 5 permission starvation — the transcript (session-id glob) carries Claude requested permissions to … but you haven't granted it yet; a non-empty permission_denials in leg.out is the same fact and, under the fixed posture, a canary that the posture did not take → fix the posture, new id · 6 the leg spent turns and declined — num_turns > 0, result present, none of the signals above, and result states a refusal or abort reason in words (the known class is injection refusal) → fix the prompt wording, new id; a result that states no reason, or a reason outside that class, is step 8, not step 6 · 7 no session at all — exit 1, the shell-guard line → call the absolute path · 8 death — no result object, or is_error: true, or the process vanished without a terminal state → read the transcript tail by session-id glob; a rate_limit / 429 tail sets a wait before repair and changes nothing else. Accounting: 3–7 are launch-line defects, and re-entering after one does not increment redispatch_count; only step 8 descends the ladder. Mint a new id only after attribution is finished (a fresh id written first makes the session-id glob resolve to an empty session), and keep the previous id in prior_session_ids.
  • The ladder (entered from step 8 only). Rung 1 — the session is usable → claude -r <session_id> (team preserved, counter unchanged). Rung 1r — on phase: discuss only — the transcript is missing or unusable → re-dispatch with a new session_id, the team is lost, the roster is rebuilt from the durable witness corpus ($STATE/witness/) — INDEX.md's lead/sweep row and SWEEP.md are not member roles and stay off it — redispatch_count += 1. The leg this launches finds the dead dispatch's early ledger stub, and that skill's target-document guard passes a stub while parking a saved document — which is what leaves this rung reachable in the states its purpose needs, since the corpus fills only as rows flip to done and rows exist only once a spawn has already written that stub. On phase: resume rung 1r is forbidden. By then docs/{topic-slug}.md carries Step 5's walkthrough decisions and Step 6's refinements; a re-dispatched leg runs Step 1 through Step 4 from the start and saves over them, and the leg's boundary gate cannot catch it, because that skill's Step 2 exempts this exact path — an accidental re-save and a legitimate first save look identical to every assertion it makes. The new leg also knows no phase, so it writes presentation.md while the resume branch of step 1 above waits for coherence.md: the seat waits on an artifact nobody will write, and the bytes it was waiting to protect are already gone. Take Step 7's fallback (3') instead — the Step 3 roles respawned fresh at a new epoch from the durable witness corpus, the brief and the final document by path, with no save and no new leg; Step 7's precondition step names this as its second trigger. The brief_sha256 identical guard of dispatch item 2 does not reach this ladder. It governs the Step 2 dispatch preparation, and nothing here re-runs item 2, so a rung-1r re-dispatch proceeds on an unchanged brief rather than being blocked by it. What keeps a re-dispatch away from a saved document is neither the phase guard alone nor the leg's guard alone. The phase guard forbids rung 1r on phase: resume, where a saved document exists by construction and no file need be consulted; on phase: discuss the leg's target-document guard is the one that looks at the file, and it parks on a saved document while passing an early stub. Neither stands in for the other — the phase guard reads no file, and the leg's guard reads no phase. And a re-dispatch prompt is not the first dispatch's prompt. Item 4's no placeholders fixes the first dispatch's block; a rung-1r prompt additionally names the corpus path ($STATE/witness/) and the recovery context — the prior session_ids and the incremented redispatch_count — because a leg told none of this rebuilds nothing and composes a fresh roster in place of the approved one. Rung 2 — the floor. At most one re-dispatch per design; a second rung-1r failure is not a question to the user but a demotion: the seat runs Step 3 and Step 4 itself, at today's cost from a worse starting point (Step 1, Step 2, N pull-check turns and at least one attribution already spent). The demoted seat's execution text is Step 3 and Step 4 of this file, read as the interactive procedure they are.

Small-work gate (evaluated once on entering this step)

A single-surface change with no contract change does not need a full design team. Evaluate this before composing, from the Step 1 interview product — this skill receives no entry-plan (the kickoff hands over a command string, nothing more), so the three inputs are read from what the interview settled: the surface count and any contract/schema change from the requirements and constraints, and the target-repository count from the delivery-shape answers. The inputs are defined the same way as the kickoff's tier judgment, so the tier and the roster cannot disagree on what they measure; when the user invokes this skill directly without a kickoff, the gate fires on the same inputs.

Risk indicators outrank the size row. If any indicator fires — a public contract or shared schema change, a public API surface, a DB schema, auth/authorization, an external service integration, async/concurrency — compose for that risk no matter how small the surface is, and this gate does not narrow the team.

When it fires: no risk indicator fired and the work is a single surface in a single target repository. Compose from the small row — one domain seat plus the verification seat (two roster rows, the same roster design-lite runs; the budget counts one domain perspective here, and the budget has no floor) — instead of a larger default row, and state the narrowing in one line of the Korean proposal so the user sees it rather than discovering a thinner team.

Floor. This gate selects among composed rows that each carry at least two roster rows — one domain seat and the verification seat — so it cannot yield an empty roster; an empty roster is not a saving but a hard stop, because the ledger stub is created at spawn time and every resume path fail-closes on a missing or unparseable ledger. The floor belongs to the roster contract in _common/agent-team-protocol.md alongside the team-size ceiling; do not write a second floor rule here.

The kickoff's design tier is solo or team-4. A team-4 plan whose design_path is discuss-audit is dispatched with this roster as design-discuss-unattended, and one whose design_path is solo-audit goes to design-solo-unattended, with no roster; solo is not a row of it — it is design-solo-unattended, a headless lead with no team, and it is only named here so that nobody builds it as a zero-member team.

Step 3: Design Discussion (English, internal only)

Executed by the leg, not the seat, on the normal path. After the dispatch block above the seat yields (CFI-1a); Steps 3 and 4 through the save run inside design-discuss-unattended, which Reads these two steps from this file and applies its own park substitution. The seat runs them itself only at the recovery ladder's floor.

Before assigning any team work, Read ${CLAUDE_SKILL_DIR}/../_common/agent-team-protocol.md. Apply the completion-signal instruction and facilitator rules from that file throughout this step. When you dispatch or resume each member, embed the task-assignment header from _common/agent-team-protocol.md verbatim at the top of each dispatch/resume prompt. Every new round/phase key — each discussion round, the Step 4 fidelity pass, the Step 7 coherence pass — is a fresh background Agent dispatch carrying what the protocol's ## Multi-round lists for a boundary dispatch; only a re-request inside one key resumes the same agentId.

Re-entry notes. This skill opts in to the protocol's ### Parameter — re-entry notes (opt-in); append this clause verbatim after the task-assignment header in every member prompt:

Re-entry notes (MUST): directly above your peer-read: lines (directly above your sentinel when you have none), put a section that starts with the heading ## Re-entry notes, at most 20 lines and 2,000 bytes, one entry per line — path:line — why for a place you would open first if you came back to this work, or one command you would re-run. No findings and no verdicts in it. The next dispatch of your role reads it as the starting point of its re-exploration.

  • Spawn each approved member as a nameless background task — Agent({ subagent_type: "claude", run_in_background: true, prompt: <self-contained assignment> }) — and record each returned agentId in the ledger immediately. Stamp epoch (max(disk epoch, 0)+1, re-derived from the on-disk ledger — never an in-context counter; this Step-3 discussion team is the first team → epoch 1) and the round-1 witnessNonce on every one of its rows in the same at-spawn recording window as agentId/scratchDir, per the protocol Spawn section. The {topic-slug} is no longer a harness team name, but it remains the output doc filename (docs/{topic-slug}.md) and the ledger key (e.g., auth-flow, payment-system).
  • Early ledger stub (at spawn time): create the output doc docs/{topic-slug}.md as an early stub — an H1 title plus the ledger HTML-comment block <!-- cc-design-ledger v3 … --> placed right after the H1 and before the first ##. Each ledger entry is behavior-bearing. Entry schema — the column list, the state domain, the per-row transient set and its terminal-strip rule (including the epoch exemption) — is defined once in _common/agent-team-protocol.md's Role↔agentId ledger v3 and is not restated here. scratchDir is the member's out-of-tree witness directory, recorded at spawn with the same immediacy as agentId. Update it on every state change. This uses the same docs/{topic-slug}.md path as the Step 4 save (the two-command worktree gate already exempts that path — no baseline re-capture needed). On entering any later phase (synthesis fidelity pass, Step 5, Step 6, Step 7 coherence pass), re-read the ledger from disk — do not trust in-context copies; a missing or unparseable block is fail-closed via AskUserQuestion. The ledger block is off-limits to synthesis and fidelity-pass content Edits (whose targets are the enumerated canonical SOTs — 근거 등급 / 검증 기록 관측 결과 / ## 재현·근본원인 관측된 증상 — never the comment block); only ledger-state mutations (running→done/aborted, round, thinReturns) write to it.
  • Witness scratch dir (parameters for _common/agent-team-protocol.md): before the first spawn, run the protocol's ## Spawn command — <plugin root>/orchestrator/cc-team-witness-init.sh {topic-slug} (no bash in front — see the protocol's note) — and record the printed path, literally (not $WITNESS_DIR) as each member's scratchDir in the ledger at spawn time. Each member publishes its round product as ${scratchDir}/{role-slug}.{round/phase}.md per the protocol's write discipline (atomic mv -n + sentinel/nonce). Witnessed surfaces — explicitly: every Step-3 discussion round ({role-slug}.round-N.md), the Step-4 synthesis fidelity pass ({role-slug}.fidelity.md), the Step-7 Class C coherence pass ({role-slug}.coherence.md), and each Step-5 walkthrough / Step-6 refinement fresh team (each fresh team gets its own directory from a fresh run of the ## Spawn command above — never a hand-written mktemp -d, which the protocol forbids — recorded in its rows' scratchDir). Entirely lead-local phases (lead-only doc Edits, the pre-save sweep) are exempt; the sweep leaves no witness, and the lead writes only SWEEP.md into the corpus itself (Step 4 **Pre-save sweep**).
  • All inter-agent discussion and reasoning should be conducted in English.
  • NO code modifications allowed. Design discussion only.
    • (observation & verification carve-out: running the unmodified app/tests, and out-of-tree / isolated-worktree experiments, are not modifications — see ## Constraints → "Observation & verification carve-out".)
  • The lead acts as a facilitator, actively driving multi-round discussion. Do NOT passively wait for results and move on.

Discussion Protocol (rounds per the shared Round budget)

  1. Round 0 — Reproduction grounding pass (only when a reproduction agent is on the team): the reproduction agent reproduces the symptom (with artifacts present), captures the observation in its report text, then reverts/deletes the artifacts → verifies git status is pristine → and only then broadcasts the grounding report to the whole team. Cleanup-and-verify is a precondition of the broadcast (findings must be clean before they leave the producer). Round 0 is a grounding pass and does NOT count against the shared ### Round budget (_common/agent-team-protocol.md). The reproduction agent stays active through Cross-Review, challenging whether each proposal actually addresses the reproduced cause, and converges by returning like any member.
    • Round 0 failure path: if the reproduction agent fails to reproduce, it broadcasts a 가설(추측) grounding report with 재현 차단요인 filled. Tier-1/Tier-2 escalation is owned by the lead (the agent cannot call AskUserQuestion — it only surfaces the blocker; the lead decides whether to ask the user for help and, on Tier-2, creates the Step 4 unresolved-issue pointer). The Quality Gate's "hypothesis + blocker → proceed" branch (below) is exactly this failure-acceptance path.
  2. Round 1 — Initial Proposals: Spawn each member with their design scope. Confirm each member's round-1 witness via witness_present, then read the witness (never the return), before proceeding — a member's proposal is delivered by its witness, not its return text.
  3. Quality Gate: Before proceeding to cross-review, verify each proposal meets minimum depth:
    • References specific files, modules, or patterns from the actual codebase (not generic advice)
    • Includes concrete design decisions with rationale (not just listing options)
    • If a proposal is too shallow or generic, send it back with specific questions asking for deeper analysis
    • Reproduction addendum (when a reproduction agent is present): Round 1 proceeds only after the Round 0 grounding report carries a 근거 등급 (either 확인됨(재현·관측) with observed evidence, OR 가설(추측) with 재현 차단요인) and the tree is pristine-verified. Reject a grounding report that is a code-reading guess with no attempt-to-run, or one that left artifacts in the tree.
    • Verification addendum (sister to the Reproduction addendum; applies on Round 1 and every Round 2+ revision forward). Reject (send back) on ANY of: (1) a load-bearing claim passes the filter test but carries no 검증 등급 tag (a tripwire-phrase hit counts); (2) a 미검증-tagged claim reaching cross-review (disposition: send back "verify or re-justify the reclassification", or hold + route to the verification agent); (3) a 검증됨(통과)/반증됨(실패) tag with no recipe + observed value — a verification claim without evidence (isomorphic to the existing "code-reading guess with no attempt-to-run" rejection); (4) a clearly-filter-passing claim tagged 구현 시 검증 — the misclassification escape hatch (audit: 잔여 사유 token present + 차단 사유 specificity ("ran out of time" inadmissible) + on 구현 필요, re-apply the filter test).
  4. Cross-Review: Dispatch each teammate afresh for the cross-review round with its own past witnesses and its peers' proposal witnesses named by path (_common/agent-team-protocol.md ## Multi-round — the member Reads each whole; the lead does not restate them). Explicitly ask them to identify gaps, risks, contradictions, and alternative approaches. Each cross-review witness ({role-slug}.round-2.md) ends, above its sentinel, with exactly one round-3 declaration line on a line of its own: round-3: none, or round-3: measure — <one measurement not yet run, and the disputed claim it would settle>. That line is where a member names a measurement — the first entry to round 3 in the shared ### Round budget. Ask each member, in the same dispatch, to revise its own proposal — its round-1 witness is among the own past witnesses the dispatch names — in the light of what it found and to state its final position in that witness: this one dispatch is both the cross-review and the convergence dispatch.
    • The shared convergence dispatch is folded into Round 2. _common/agent-team-protocol.md ## Convergence sends a separate convergence dispatch after cross-review; this procedure folds it into the Round 2 dispatch above, so the design team's convergence round/phase token is round-2 and no separate convergence dispatch is sent. The folded dispatch carries no current-consensus or open-conflicts text, because the lead holds no consensus after Round 1: the peers' Round 1 witnesses named by path stand in that place.
    • A sweep refutation does not open Round 3 in this procedure. The second entry path of the shared ### Round budget (the lead's pre-save sweep refuting a claim) is carried out here as the author-only re-convergence of Step 4 **Pre-save sweep** (a focused exchange with the one affected author, once per claim), and the same holds in a team whose Round 3 a named measurement has already opened.
  5. Round 3 (conditional): Confirm each member's cross-review witness via witness_present and read it (never the return). Before deciding whether Round 3 opens, once every cross-review witness is in, check each one's declaration: its last line that is exactly round-3: none or starts round-3: measure — , chosen across both forms. A witness with neither is a Case 3 non-conforming witness (_common/agent-team-protocol.md): re-instruct that member and take its round-2-rev<k> revision before going on. This check runs whether Round 3 opens or not. Then open Round 3 only when at least one Round 2 witness's declaration has the round-3: measure — form. When it opens, dispatch every member's role once afresh for round-3 with its own past witnesses and its peers' Round 2 witnesses named by path — together every Round 2 witness — (_common/agent-team-protocol.md ## Multi-round), and ask each to run the measurements named and state its final position. How many rounds a team may drive follows the shared ### Round budget and is not restated here. A sweep refutation reaches the second entry path through Step 4 **Pre-save sweep** instead: the sweep runs after synthesis and the fidelity pass, when Step 3 is already behind, and a new transition that re-dispatches the whole team would add back, at another point, the dispatch cost this procedure removes. That re-convergence stays as it is, and the corpus file SWEEP.md and the 스윕 반박 field of the 토론 패스 ledger row count it on an axis apart from Round 3.
  6. Convergence Check: Proceed to Step 4 when every member's last-round witness — Round 2 when Round 3 stayed closed, Round 3 when it opened — is witness_present. The declaration check and its Case 3 re-assignment already ran before the opening decision in item 4.

Evidence-grade label (근거 등급): for reproducible issue/bug tasks, the root cause carries a binary evidence grade — 확인됨(재현·관측) (the recipe was actually run and the symptom observed) or 가설(추측) (anything unrun/unattempted/blocked). The field key is 근거 등급, deliberately distinct from 상태 (the walkthrough's state field). The single source of truth is the 근거 등급 field of the saved doc's ## 재현·근본원인 section, computed once at the reproduction discovery point (Step 1 lead-driven OR Round 0 agent-driven — whichever path reproduced); every other location only references it. When a teammate's proposal builds on the reproduced cause, it carries a [근거 등급: …] prefix — this is label-only (it travels with the proposal as context), NOT a hard gate: a 가설(추측) proposal is still discussable.

Verification discipline (검증 등급): parallel to the evidence grade, applied to any load-bearing claim the design rests on (the contract is _common/verification.md). The authoring teammate runs the severity pre-filter, then the single filter test, on each dependent assertion and attaches an inline [검증 등급: …] tag (same pattern as [근거 등급: …]; inter-agent messages only — saved-document marking uses the token-free anchor-reference convention (§검증 기록 V<n>)). A verifiable claim must reach 검증됨(통과)/반증됨(실패), backed by a re-runnable recipe + an observed value, before it is carried into synthesis; a genuinely implementation-time-only claim is encoded as a residual item (잔여 사유: 구현 필요). Linguistic tripwire: a hedge on a decidable fact ("should exist", "presumably", "구현 시 확인/검증 필요") is a confessed-unverified claim. Routing (lead's delegated judgment, not a fence): the author verifies cheap one-command (a)/(b) at proposal time; the Step 2 verification agent takes (c)-heavy / expected (d)/(e) / feasibility questions; all failing verifications and expensive (c)/(d)/(e) go back through re-convergence, never lead-solo (a refutation changes the design after convergence). Claims discovered mid-experiment are recorded only (tagged 미검증 in discussion, routed at the next Quality Gate) — never auto-verified inline; the lead may allow one in-session re-entry per discovered claim, and a claim discovered while verifying a re-entered claim is residual-only (잔여 사유: 검증 차단, blocked reason "recursion depth").

Step 4: Result Synthesis & Documentation (Korean)

  • The lead synthesizes all discussion results into a structured Korean document:
    • 재현·근본원인 (이슈·버그 수정 과제에 한해 최상단에 포함; 기능 설계 과제에서는 생략)
    • 합의된 아키텍처
    • 주요 결정사항과 근거
    • 검증 기록 (세션 내 검증을 수행한 경우에 한해 포함; 수행이 없으면 생략)
    • 미해결 이슈 / 트레이드오프
    • 구현 시 검증 항목 (잔여 검증 클레임이 있는 경우에 한해 포함; 없으면 생략)
    • 테스트 설계 (대상 프로젝트에 테스트 환경과 기존 테스트 파일이 있는 경우 필수 포함; 둘 중 하나라도 없으면 생략)
    • 구현 슬라이싱 (Step 1의 배포 형상 답변이 있는 경우에 한해 포함; 없으면 생략) — 이 표제를 쓰면 권장 구현 순서는 쓰지 않는다
    • 권장 구현 순서 (구현 슬라이싱을 쓰지 않는 경우)
  • Open entries carry **구현 처분**. Every entry synthesis writes into ## 미해결 이슈 / 트레이드오프 carries **구현 처분** and its companion field, chosen and written by ${CLAUDE_SKILL_DIR}/../_common/unresolved-closure.md (## 값 고르는 기준, ## 작성자 꼴); an entry the implementation would otherwise decide by itself is 구현 전 결정.
  • Runtime classification default. If a runtime point in the product being designed maps unstructured input to a closed set of outcomes, Read ${CLAUDE_SKILL_DIR}/../_common/runtime-classification.md and apply it before finishing this step — it fixes the predicate, the two exits, and where the decision, the UR entry, and the R-item land. The predicate excludes judgment this same session makes about its own pipeline or design work (topology test, not this-repository test) — see the file.
  • ## 재현·근본원인 section (issue/bug tasks only — omitted for feature-design tasks). The section records the reproduction findings produced in Step 1 or Round 0 so the design rests on an observed cause, not a guess.
    • Placement & heading: at the very top of the document, before 합의된 아키텍처 (for a bug fix the root cause is upstream of architecture and decisions). The heading is exactly ## 재현·근본원인 with no leading section number — ## 0. / ## 1. etc. is forbidden because the fixed anchor §재현·근본원인 (used by the Tier-2 pointer below) would dangle.
    • Fields: 재현 절차 (a re-runnable recipe — literal commands or an inline fenced script, no /tmp paths since those are deleted, plus a tracked-source 무변경 확인 note; if the observation depended on an out-of-tree driver/instrumentation, write that logic inline as a fenced script so the recorded recipe is self-contained and re-runnable) / 관측된 증상 ("미관측" when only hypothesized) / 근본 원인 (grade-neutral field name — whether it is confirmed lives in 근거 등급, not here) / 근거 등급 / 재현 차단요인 (only when the hypothesis is due to a reproduction failure; carries 차단 사유 + 필요한 것).
    • Grade acquisition: 확인됨(재현·관측) is earned ONLY when the recipe was actually run and 관측된 증상 observed; unrun/unattempted/blocked is 가설(추측).
    • Multi-claim & mixed tasks: if one section holds more than one reproduction claim, repeat each claim as a self-contained ### sub-block (each with its own 재현 절차/관측된 증상/근본 원인/근거 등급 — the source of truth is per-claim), and a Tier-2 pointer targets that claim's sub-block anchor. A mixed task (bug fix + new feature) includes the section per-reproducible-claim: if any part of the task is a reproducible existing-misbehavior claim, the section is included (scoped to that part).
    • Grade propagation (one-way): the reproduction discovery point is the origin; Step 3 proposals carry a [근거 등급: …] prefix (label-only); 주요 결정사항과 근거 points at the grade by referencing §재현·근본원인 (do NOT restate the literal grade token — no stored copy, prevents divergence); the grade is written once, in ## 재현·근본원인.
  • Tier-2 → unresolved-issue pointer: only when reproduction hit Tier-2 (proceeding on a 가설(추측) root cause) does the lead create an unresolved-issue pointer in the ## 미해결 이슈 / 트레이드오프 section during this synthesis (the synthesis-terminal rule permits lead-driven Edits). Encode it to match that section's existing form (mixed-form prohibited; fresh-section default = sub-section). Sub-section example: ### N.x 재현 미확인 — 가설 근본원인 채택 여부 + **상태**: 대기 + **Category**: UR + **Surfaced-at**: Step 4 synthesis + a body line referencing the §재현·근본원인 anchor. The pointer holds its own 상태 (default 대기) and the anchor, but does NOT hold 근거 등급 (that lives only in the canonical section, to avoid duplication/divergence). This makes Step 5's walkthrough consciously ask the user whether to accept the hypothesized cause.
  • ## 검증 기록 section (verification ledger; unnumbered heading) — placed after ## 주요 결정사항과 근거, before ## 미해결 이슈 / 트레이드오프. Holds ### V<n>. sub-blocks per the V-ledger schema in _common/verification.md (the SOT — do NOT restate the field list here). The ledger accepts only performed verifications (검증됨(통과)/반증됨(실패), every entry carrying an observation). If no verification was performed, omit the whole section (the pre-save sweep makes the absence meaningful). Body claims reference an entry by the token-free anchor (§검증 기록 V<n>); the ledger is the single SOT and 주요 결정사항과 근거 does not restate tokens. Field-line rendering: copy the CANON rendering example in _common/verification.md §4 byte-for-byte (bold key **…**:, no leading bullet - , one ASCII space after the colon) — do not choose your own bullet/bold style.
  • ## 구현 시 검증 항목 section (residual items; unnumbered heading) — placed after ## 미해결 이슈 / 트레이드오프, before ## 권장 구현 순서. The two new sections straddle the unresolved-issues section without touching its parse region; neither new heading contains 미해결/이슈, so neither can match the walkthrough parse regex. Holds ### R<n>. sub-blocks per the Residual-item contract in _common/verification.md. The lead performs the transformation move (that file) to convert each in-session-unsettleable claim into an R-item; a residual item is born by exactly the three paths of the contract (filter NO → 구현 필요; verification-attempt exit → 검증 차단; audit-reconciliation deferral → 검증 차단). 0 items → omit the section. Field-line rendering: copy the CANON rendering example in _common/verification.md §5 byte-for-byte (bold key **…**:, no leading bullet - , one ASCII space after the colon) — do not choose your own bullet/bold style.
  • ## 구현 슬라이싱 section (workflow declaration; unnumbered heading) — placed after ## 구현 시 검증 항목, and it replaces ## 권장 구현 순서 rather than joining it: the two say the same thing at different grades, and a document carrying both invites them to diverge. Write it when Step 1's delivery-shape answers exist; omit it otherwise (a single-repo, single-PR change needs no declaration and the omission is meaningful, not lazy). The heading is matched as a whole line, exactly — ^## 구현 슬라이싱$, no leading space and no trailing text; a heading with a parenthetical tail is read as not a declaration at all and the document falls back to model-derived grouping.
    • Blocks and fields: one ### 슬라이스 <id> per slice (<id> is [A-Za-z0-9]+; the convention is ### 슬라이스 A, ### 슬라이스 B, and a trailing — <제목> after the id is fine). Field lines follow the same CANON rendering as everything else (**키**: 값, bold key, no leading bullet, one ASCII space after the colon); a list value is separated by comma + space. Required in every block: **스킬** (one of design·design-audit·implement·review·apply — the stage this slice enters), **레포** (the remote slug <owner>/<name>, never a path — paths differ per machine and per worktree, and the slug is what the driver passes to gh -R), **선언 파일** (repo-relative paths in backticks; slices may overlap here — that is the point, and sequencing is what makes it safe), **선행** (a 슬라이스 <id> list, or the literal 없음 — 없음 is a positive statement of independence and an omitted line is not the same thing; it means implementation precedence: this slice's branch is cut from a base on which every slice it names has already landed), **절단점** (a cutpoint token verbatim). Then, only when the slice has an apply: **적용 명령** (a one-line backticked literal — the presence of this field is the declaration that an apply exists, and it, not the cutpoint, decides whether the next two fields are required), **적용 주체** (파이프라인 or 사람; 사람 means the pipeline stops at merge and the command is copied verbatim into the morning report as an opaque string for the person to run), and — only when the actor is 파이프라인 — **폭발 반경** (what parks if the apply fails: 레포, 런, or a 슬라이스 <id> list; the default is 레포 and it may only be narrowed).

    • **머지 순서** is the second kind of ordering, and every block you write carries it — a 슬라이스 <id> list, or the literal 없음. It means merge order: the slice is planned, implemented and reviewed concurrently with the slices it names, cut from the current base, and only its merge waits until each of them has landed. The parser reads an absent line as 없음, which is what keeps frozen documents meaning what they meant; a new block still writes the line, 없음 included. A 머지 순서 token names only a slice declared earlier in the section (선행 carries no such rule, and adding one would park frozen documents that point at a later slice), and one token never sits in both lists of the same block. A slice joined to others only by merge order still writes **선행**: 없음 — the gate refuses a missing 선행 in a repository with two or more segments, and that floor does not count 머지 순서.

    • **선행 사유** and **머지 순서 사유** say why each kind was chosen. Each is one line of prose and neither enters the declaration digest. A block that carries a **머지 순서** line is a new-grammar block, and in it every list that is not 없음 requires its own reason field: **선행 사유** for a non-empty 선행, **머지 순서 사유** for a non-empty 머지 순서. A block without the line is old grammar and owes no reason, so frozen documents stay valid.

    • Choosing the kind is the design's judgment, and the reason field records it. Choose implementation precedence when the successor needs the predecessor's content in its own tree — it builds on it, calls it, tests against it, or a file overlaps within the closure below. Choose merge order when only the landing order matters and the closure is disjoint — the producer must land last, the slice is a release slice, or an intermediate state must not spread to the installed copy. Disjoint declared files do not by themselves prove the code independent, which is why the choice is a judgment and not a mechanical lowering.

    • Closure disjointness. For a slice S, let M(S) be every slice reachable from S along 선행 ∪ 머지 순서 edges, and P(S) every slice reachable along a path whose first hop is a 선행 edge. S's declared files must be prefix-disjoint from every slice in M(S) \ P(S): a slice in P(S) has landed before S is cut and is already in S's base, while a slice in M(S) \ P(S) lands after S is cut and before S merges, so S never saw its change. README.md, plugin.json and CHANGELOG.md are not exempt — two bases' hunks in a generated index can conflict, or merge cleanly into something the generator would not produce. A violation is a defect owned by that slice, and it parks only that slice and the slices bound to it by either kind.

    • The writer and the reader ship in one release. A parser older than this field ignores the **머지 순서** line and reads that edge as no edge at all, so a document using it must not run on a tree whose gate, shift and driver have not learned it.

    • **잔여 항목** is optional — the verbatim headings of the ## 구현 시 검증 항목 items this implement slice owns, each wrapped in 「」 and separated by , (**잔여 항목**: 「### R4. …」, 「### R5. …」), or the single word 없음 for a slice that owns none — the same spelling **선행** uses for an empty list. Every element is a ### R<n>. heading that the residual section carries verbatim; any other value refuses the whole segment plan. It is what the driver reads as this slice's residual share when it checks that an implement stage's last turn left a result line on each owned item: with one implement slice the share is every item and the field is not needed; with two or more, a slice that omits it owns none.

    • **화면** is optional, and it says which approved screens the slice waits for — the literal 없음, or a list of screen ids ([a-z0-9-]+ each, separated by , ) naming ### 화면 <id> entries of the document's visual sidecar. A slice whose **화면** field is 없음 waits for no screen and is dispatched the night it is planned; a slice that lists screen ids covers those screens only. An omitted field is not 없음: when the run plan has a visual stage or the document has a visual sidecar, a slice without the line waits for every screen of the document. Both checkers (the driver's and the gate's slicing check) read only the shape — a value that is neither 없음 nor such a list refuses the whole segment plan — and never whether an id exists; the dispatch site and visual-unattended look up the ids. Write the field on every slice when the interview record's ## 시각 방향 is not 없음, so that a slice touching no screen says so rather than waiting the night out. The two shapes, verbatim:

      **화면**: 없음
      **화면**: order-list, order-detail
      
    • **크기 사유** and **권한 혼합 사유** are optional, and each names the one coupling that a split would break — one line of prose apiece, written only when rule (f) or (g) of the Step 7 slicing self-check asks for it: **크기 사유** on a block over the size baseline that stays whole, **권한 혼합 사유** on an implement block whose permission profiles mix and stay mixed. A sentence that names no coupling ("it is large") is not a reason. When the person gave the 슬라이스 수 answer, the reason quotes that answer instead of a coupling, because then the answer is what holds the block together. Neither enters the declaration digest, and neither the driver nor the gate reads whether it is present. The two shapes, verbatim:

      **크기 사유**: 생성기와 그 픽스처가 한 형식을 함께 바꿔, 나누면 중간 커밋의 생성기 검사가 깨진다
      **권한 혼합 사유**: 배포 설정 한 줄의 쓰기가 API 계약 변경과 같은 커밋에 있어야 둘이 어긋난 배포가 생기지 않는다
      
    • **리뷰 정책** is optional and its default is 선리뷰후머지 (values: 선리뷰후머지 | 선머지후리뷰 | 리뷰없음). It exists because the cutpoint says how far a slice may go and cannot say when review happens — a slice may be authorized to merge and still owe its review afterwards, and those are two axes rather than two readings of one. 선머지후리뷰 does not remove the obligation, it defers it: the gate leaves a review-obligation row and the run cannot terminate while one is unfulfilled. 리뷰없음 is expressible only when that target's 리뷰 정책 상한 in the run manifest is itself 리뷰없음, which is what stops a stage from choosing it for itself. The ceiling is the whole predicate: a slice may declare no looser than the target it runs against, and the ceiling was frozen at kickoff while a person was present. One real cost belongs with the field rather than in a footnote: post-merge review is by definition review against a base that has already moved, so the review anchor is the merge commit rather than a PR head — and what closes the obligation is a review covering that obligation's merge commit, not merely some later review of that segment. A review of the segment that does not contain the commit that was merged leaves the merge unreviewed while looking as though it did not.

    • **라벨 인정** is optional and an absent line reads as 없음 — the names of the checks this slice expects to fail and to have answered by a label, separated by , and each written exactly as the PR's check list prints it, or the single word 없음. Write it only when the slice deliberately changes the surface such a check guards and the run manifest carries a 라벨 인정 row for that check under the slice's target — the target whose 원격 슬러그 is the slice's 레포. Without both, leave it out: a person decided at kickoff which checks a label may answer, and this field only binds that decision to the slice that needs it. Every name it gives must equal the 체크 of one of those rows; a name no row carries, an empty element, whitespace around an element, a |, or 없음 beside a name parks this slice alone, not the whole plan. A value other than 없음 enters the declaration digest; an absent line or 없음 adds nothing, so documents without the field keep their digests.

    • A section-level **슬라이스 수**: <N> is a checksum, not an input — it must equal the number of blocks whose cutpoint is PR or later (so 커밋/브랜치 slices are not counted). A mismatch means the declaration was truncated or misnumbered, and it is worth stopping for.

    • Two slices are declared as one by default, and only when the person left the count to the design. The default applies only when the delivery-shape 슬라이스 수 answer — the brief's ## 배포 형상 line, or the autopilot interview record's — is 없음 or delegated to design (설계에 위임, with or without its — 문 <n> tail). A count or a chain the person gave binds the declaration: it is itself a positive reason to keep apart the slices it separates, and this rule never folds them. Where the default applies, merge two slices into a single block when all five hold:

      1. they are joined by a 선행 edge that fans out on neither side — the predecessor has no other successor and the successor has no other predecessor. Only 선행 edges count here: a pair joined only by 머지 순서 does not meet this condition and is never merged. Both blocks' 머지 순서 must also be 없음 — a merged block has no rule for folding the two lists into one, so a pair either side of which carries a merge-order edge stays apart and that edge stays where the checks read it;
      2. their 선언 파일 sets still overlap after setting aside the files every change touches regardless of content — generated indexes, version and release files, the repository-wide test runner or build manifest;
      3. 레포, 스킬, 절단점 and 리뷰 정책 are equal, an omitted 리뷰 정책 reading as its default 선리뷰후머지;
      4. neither declares 적용 명령 — a block holds one 적용 주체 and one 폭발 반경, so two applies cannot share one, and a merge that dropped either would switch off the park it declared without any check noticing;
      5. the merged block passes rules (f) and (g) of the Step 7 slicing self-check without a reason field — its declared file count is at or below the size baseline, and it holds one permission profile. A **크기 사유** or **권한 혼합 사유** line either block still carries is not moved into the merged block; it is deleted.

      Keep them apart only when the block prose gives a positive reason: a 슬라이스 수 answer the person gave, a baseline that must be measured on the tree before the other part lands, a release slice, or a conflict surface with in-flight work that the other part does not share. File order alone is not a reason. The rule governs new declarations only; a repair segment is not a declared slice and this rule does not fold it. Merging removes a boundary, not a review — the merged slice is reviewed under the same 리뷰 정책, tier table and P0/P1 gate.

      A merge is finished only when all five of these hold. The driver reads every 선행 token and the checksum at kickoff and stops on a stale one, but it records a 폭발 반경 id without checking that the id exists and parks by exact match, so a radius that still names a retired slice parks nothing. It also runs the blocks once in section order without sorting them and parks a block whose 선행 has not finished, so where the merged block stands decides whether it runs:

      1. the predecessor's <id> survives and the successor's is retired; the merged block's 선언 파일 is the union of both;
      2. every other block's 선행, 머지 순서 and 폭발 반경 that names the retired id names the surviving one instead, listed once;
      3. the merged block's 선행 is the predecessor's 선행, its 머지 순서 is 없음, and its 선행 사유 is the predecessor's — condition 1 leaves the successor no other 선행 edge and neither block a 머지 순서 edge;
      4. the section's **슬라이스 수** drops by one when the shared cutpoint is PR or later, and is unchanged when it is 커밋 or 브랜치, which the checksum does not count;
      5. the merged block takes the successor's position in the section, after every block its 선행 names — left at the predecessor's position it runs ahead of the blocks that stood between the two, and a block among them whose 폭발 반경 named the successor then parks nothing if its apply fails, because the merged block has already run.

      Keep every prose line here and in a slice block from beginning with a bold field key followed by a colon: the slicing parser reads the first such line in a block as that field.

    • There is no 적용 순서 field. Apply order is derived from 선행 ∪ 머지 순서 restricted to the apply-declaring slices; two orderings that cannot be written separately cannot disagree.

  • ## 테스트 설계 section (unnumbered heading) — placed after ## 구현 시 검증 항목, before ## 구현 슬라이싱. Required whenever the target project has a test environment (jest, vitest, pytest, go test, …) and existing test files (*.spec.ts, *.test.tsx, *_test.go, …); omit it when the project lacks either one. It holds the test design for the module/feature being designed — unit-test scenarios and E2E test cases — so implementation inherits a test surface instead of inventing one. This is a section of the design document itself, not a follow-up task.
  • UR escalation pointer (lead's delegated judgment, Tier-2 isomorphic): if a residual claim is load-bearing enough that the user should consciously accept building on it, the lead creates a UR pointer in ## 미해결 이슈 / 트레이드오프 — 상태/Category/Surfaced-at + a §구현 시 검증 항목 R<n> body reference only; it never includes the 검증 등급 key, token, or recipe (predicate check). Per-item mandatory pointers are rejected (the dual backstop already validated the deferral; N pointers = N friction prompts).
  • Synthesis write economy (lead-local, inside the synthesis-terminal window). What synthesis costs is mostly how many responses it is spread across, each one re-reading the lead's whole history (_common/agent-team-protocol.md ## Turn economy). So the lead writes the document in as few responses as its content allows; the author, the inputs and every check of this step stay as they are.
    • Marks. At three points the lead appends one line <event> <UTC time> <stage id> to $STATE/synthesis-marks.txt with the file-edit tool, creating the file when absent: enter as the first act after the last convergence witness is recorded, draft once the whole draft is in the document and before the fidelity pass begins, and save at the synthesis terminal, after the last document write. The time is the output of date -u +%Y-%m-%dT%H:%M:%SZ, issued in the same response as other independent calls (inside a gated run through gate.sh exec … --surface 읽기); the stage id is CC_PIPELINE_STAGE_ID read by name, or - when it is unset. A mark that comes again after a re-attachment is appended, never rewritten. The marks are measurement, not a gate: a missing mark leaves the window unmeasured and changes nothing else.
    • Compose whole, insert once. Compose the whole draft, in this step's section order, before writing any of it. Insert it with one Edit whose old_string is the ledger block's closing line — with the line before it when the closing line alone is not unique in the stub — and whose new_string is those same bytes followed by a blank line and the draft. When one response cannot carry the whole draft, split only at ## boundaries and anchor each continuation the same way as the first insertion: the last line of the previous insertion, together with as many lines before it as make the string unique in the document — section endings repeat (every verification entry ends on the same hygiene line), so the last line alone is often not unique. Never write the draft section by section or field by field, and never Write the whole file over the stub: the ledger block changes only by its own single-row Edits. After the last insertion, confirm with one read that the last ## heading of the planned order is in the document.
    • Inserting is not saving. The draft in the document before the fidelity pass is not the save of Synthesis terminal: the save is this step's last document write, after the pre-save sweep, and the save mark follows it. Fidelity-pass dispatches and re-convergence messages before that write stay inside the window that rule leaves open before the first save.
    • Batch fixes by source. Once every finding of one source is in hand — every fidelity witness read, every sweep check run — apply all fixes that do not depend on one another as several Edits in one response, each anchored on text unique in the document. Only a fix whose anchor another fix rewrites waits for the next response.
    • Batch the sweep's reads. The sweep's checks and the two boundary-gate commands do not depend on one another; issue them in one response (inside a gated run, within ## Turn economy's digest-sharing bound).
    • Not a CFI, on the same basis as the pre-save sweep: skipping it brings back today's cost, not a mis-transition.
  • Synthesis fidelity pass (team-driven, inside the synthesis-terminal window, after the full draft is synthesized and immediately before the pre-save sweep): before the lead's solo pre-save sweep, the Step 3 team's roles (dispatched afresh for the fidelity phase into their ledger rows) check draft↔discussion fidelity — the lossy-synthesis class of defect that only an original-context holder can catch, and that any fresh, context-free reader — which re-reads only the saved doc and holds none of the discussion — can never reach. Emit once, inline at entry (one-way notice, not a question): "팀이 설계 초안의 충실도를 점검하고 있습니다." Ordering rationale: before the sweep, so the sweep also covers the fidelity Edits. Not a CFI (same basis as the pre-save sweep — it rides the existing "clarify before the first save" window, adds no new turn-yield semantics; a skipped pass degrades to a quality loss, not a mis-transition; nothing is added above the ## Control-Flow Invariants heading).
    • Subject & input: reuse the existing Step 3 team's roles — dispatch each role afresh into its ledger row for the fidelity phase (reproduction/verification specialists included — they check their own output sections, the high-trust grade/verdict data implement consumes verbatim). The dispatch names the member's own round witnesses by path, so what the member contributed is read from disk rather than from a retained context — the pass's sensitivity is bounded by what those witnesses recorded. Hand each member the whole draft by path — the dispatch names the document's path, the line number of its first ## heading and the draft's last ## heading, and the member Reads from that line to the end of the file, in consecutive offset/limit ranges whenever one Read cannot return the rest (not a section slice — whole-cloth omissions have no home section and surface only against the full draft). The member's witness quotes the last ## heading it read as a receipt. A witness without that receipt, or with a different heading, did not cover the whole draft: the lead treats it as a Case 3 non-conforming witness and re-assigns that member once with the whole draft quoted in the resume, the one case in which the lead emits the draft. Otherwise the lead's dispatch text never carries the draft itself. The ledger block above the first heading is not part of the draft, so the member does not read it. Scope: each teammate checks only their own contribution — this pass asks "did synthesis distort or drop what I said?", which only the contributor can answer. Document-wide coherence and completeness are not delegated away: they are the subject of the Step 7 Class C coherence pass, which dispatches this same team's roles afresh against the final text.
    • Two fidelity classes:
      • Interpretive (root-cause framing, recipe prose, recommendations, concerns): fidelity = accounted-for — adopted (meaning preserved; paraphrase passes) OR rejected with rationale recorded in the doc. A point rejected-with-rationale passes (not re-litigation). Vanished without a trace = fail.
      • Transcription (observation tokens: 근거 등급, each 검증 등급 verdict + its backing observation field): byte-identical or flag. Grades/verdicts are recorded once at discovery and propagate one-way; synthesis only transcribes (the lead is read-only to them). No rationale justifies recording an observed 확인됨(재현·관측) as 가설(추측), or a performed verdict as weaker. Any divergence MUST be flagged by the specialist.
    • Completion contract: each member publishes its fidelity check as its witness ${scratchDir}/{role-slug}.fidelity.md (sentinel/nonce-terminated per _common/agent-team-protocol.md; the return text is only an early-wake hint, and the lead reconciles the witness — never the return). The witness body is either Fidelity confirmed — all my contributions accounted for. (clean) or one discrepancy block per finding:
      - type: omission | distortion | grade-distortion | decision-reopen
      - contribution: <원래 논점 / 토큰, 1줄>
      - location: <초안 섹션/anchor, 또는 "absent">
      - evidence:
          omission        → 어디에도 없음
          distortion      → 초안은 X, 나는 Y (의미 변경; paraphrase는 finding 아님)
          grade-distortion→ draft token=X | my broadcast value=Y (BYTE 비교; 의미 latitude 없음; 그대로 복원, 판정 금지)
          decision-reopen → 기록된 rationale 자체가 틀렸거나 unsafe한 이유
      
      Either form ends, above its sentinel, with one line of its own findings: <n> — the number of discrepancy blocks, findings: 0 beside the clean sentence. A fidelity witness without that line is a Case 3 non-conforming witness (_common/agent-team-protocol.md): re-instruct the member and take its fidelity-rev<k> revision. The count is the line's value; it is not checked against the blocks. A published witness is the completed check — "check done," not "no issues"; a discrepancy report is a completed check. The "collect all witnesses" gate (witness_present for each member, then read the witness) is satisfied by either form. A thin or empty witness (no fidelity verdict) is a Case-1 thin/empty witness, not a completed check (see No-response below).
    • Triage (lead authority): the type is the teammate's read; the lead routes by one test — "does fixing this contradict a converged decision?"
      • NO → lead Edits immediately: re-reflect the omission / correct the distortion / restore the byte-true grade/observation to its canonical SOT (the 근거 등급 field, the 검증 기록 V-entry's 관측 결과, or ## 재현·근본원인's 관측된 증상 — never a downstream token-free (§…) reference). No team cycle.
      • YES → decision-reopen → reuse the pre-save sweep's 1-cycle re-convergence (author SendMessage → focused exchange → mini cross-review if cross-cutting → update draft → re-check → 2nd failure → AskUserQuestion). In the decision-reopen context the three options are re-read as "adopt the lead's recorded rejection rationale over the teammate's objection / defer the reopened decision to Step 6 redesign / abort" (a challenge to a converged decision, not a verification claim). The 1-cycle counter binds to the reopened decision (not a grade token), per failing item; it is an orthogonal axis to the Case-1 thin-return counter below and they never co-increment.
      • Restore, never re-grade: a grade-distortion fix may restore only the value already present in the specialist's Step-3 broadcast. A third value Z differing from both draft and broadcast is a new observation, not a fidelity discrepancy — this read-only pass cannot physically earn a new grade (no recipe run, no tree change), so it is inadmissible and bounces to re-convergence (the specialist must actually re-run and re-broadcast). Two locks make this unsmugglable: transcript reference-equality + the pass's read-only nature.
    • No-response — Case 1 / Case 2 handling (per _common/agent-team-protocol.md escalation): a thin/empty fidelity witness and a never-returning member are the two failure phenotypes.
      • Case 1 — thin/empty witness (counter): a member publishes a witness with no fidelity verdict (empty or substanceless). 1st → re-scope + resume once (hard prompt: "no empty witness — deliver your fidelity verdict or name a concrete blocker in one line"); 2nd consecutive thin/empty witness → AskUserQuestion. The fidelity-scope prompt variant: (a) "save contributor X's already-reflected contribution without a fidelity check" (→ the emit-only coverage-gap path below — the contribution is already in the draft, only the self-check is missing), (b) re-scope once more, (c) abort save/workflow. On option (a), land on the emit-only path (do NOT apply document-metadata convergence-exclusion marking — see Exclusion is emit-only below).
      • Case 2 — never-returns (binary, not a counter): a fidelity-pass dispatch never returns (runaway/wedge) and the protocol's reconcile-ladder death verdict fires. The recovery is TaskStop + a same-round respawn with the same fidelity assignment (new agentId, with the ledger row's agentId / outputFile updated and its stallMark reset per the protocol). If the respawn also dies → AskUserQuestion (same fidelity-scope variant as Case 1).
      • The decision-reopen re-convergence 1-cycle counter (Triage above) is an orthogonal axis to the Case-1 thin-return counter and they never co-increment.
      • No implicit-confirm — a missing witness is never read as "no objection."
    • Exclusion is emit-only: when a Case-1 option-(a) user decision excludes a teammate, do not apply the escalation's document-metadata convergence-exclusion marking — the teammate already converged in Step 3 (substantive input is in the doc, only self-verification is missing), there is nothing to stamp, and stamping would violate the no-trace invariant. Instead, at save time, emit once per excluded contributor (Korean, mandatory — "no silent caps"): "기여자 X의 기여 내용은 충실도 점검 없이 저장됩니다." ATP's Case-1 option-(a) document-metadata marking — and the state=aborted ledger routing that a genuine Case-1 drop applies to remove a member from the dispatch-completeness roster — are both restricted to genuine Step-3 synthesis-convergence exclusion. This fidelity scoped skip drops only the member's current self-check, not the member: it stays in the state ≠ aborted roster and is not set to aborted, so a later decision-reopen re-convergence correctly re-dispatches it (desired participation, not resurrection).
    • Visibility — 3 emit points: (1) on entry — "팀이 설계 초안의 충실도를 점검하고 있습니다." once (one-way notice, placed inline above; not re-emitted in re-convergence, which is silent by its own spec); (2) clean termination — no emit (a clean pass emits nothing beyond the on-entry notice and the existing save notice — fixes are indistinguishable from ordinary synthesis); (3) exclusion — "기여자 X의 기여 내용은 충실도 점검 없이 저장됩니다." once per contributor at save time. All three are one-way progress-class notices, not ATP "surface" events, and touch no escalation gate. All *"..."* italic Korean, matching the existing Step 4 emit convention.
    • No-trace invariant: a clean pass leaves no mark in either the document or the user channel (beyond the on-entry notice) — fixes appear only as the corrected body itself. The coverage-gap emit is the sole exception, and even it is an ephemeral user notice, not a document write (the saved-document no-trace invariant is preserved).
  • Pre-save sweep (lead backstop, inside the synthesis-terminal window, before the first save — so re-convergence is always still possible): scope is the entire synthesis draft, decisively including assertions the lead introduced during synthesis (the only class that never passed the Quality Gate — the sweep's unique coverage). Pass conditions: the four conditions of _common/verification.md §10 (the shared sweep predicate) — do NOT restate them here; that section is the single definition and this skill cites it. Late finds: cheap (a)/(b) → the lead verifies immediately and records it in the ledger; expensive/failing → re-convergence (SendMessage the affected author → focused verify/fix exchange → mini cross-review if cross-cutting → update draft → re-sweep the changed part → save). Sweep record: for every refutation that opens such a re-convergence, append one line round-3: sweep — <the refuted claim, one line> to the durable corpus file $STATE/witness/SWEEP.md with the file-edit tool, the way INDEX.md is written; when a sweep refutes nothing, still create the file (empty) as the sweep ends, so "no refutation" and "no record" stay apart. Each time a sweep ends (a re-sweep of the changed part included), rewrite INDEX.md's lead row — role-slug lead, round/phase sweep — with SWEEP.md's byte count and sha256 at that moment. This re-convergence does not open round 3; it stays the author-only cycle above, and a fidelity decision-reopen that borrows it is not written to this file. This rides on the existing "clarify before the first save" sentence — no new turn-yield semantics, not a CFI (a missed sweep degrades to today's quality baseline, not a mis-transition). Re-convergence limit: at most 1 cycle per failing claim; a second failure of the same claim → AskUserQuestion (accept residual with refutation evidence / route to Step 6 redesign / abort) rather than a silent round. Visibility tripwire: at ~5 in-session worktree experiments the lead emits a status note (visibility, not a gate).
  • Synthesis terminal: All teammate clarifications must be completed before saving the design document. Once the file is saved, the synthesis phase is over — no further teammate messages are permitted. Do NOT save a partial document, send a teammate message, then save again; clarify before the first save. The sequence save → cleanup → presentation is atomic. Step 5 (walkthrough) and Step 6 (refinement) are new editing phases governed by their own state-check + cleanup rules. The synthesis-terminal rule bars further Step 3 team messages but does NOT bar lead-driven Edits to the saved doc.
  • Save the design document to the project's docs/ directory. File naming convention: use docs/{topic-slug}.md where {topic-slug} matches the Step 3 team's topic slug exactly (e.g., Step 3 team design-auth-flow → saved doc docs/auth-flow.md). This filename-to-slug binding is the local state used by Step 5's entry state-check to recover the slug without relying on lead memory. Interrupted-save case: if the save itself was interrupted (partial write, permission error, etc.), the state-check cannot recover the slug from the filename. In this case the lead must either (a) recover the slug from the original task input or interview output that started the workflow (from in-session conversation history, including slash-command $ARGUMENTS if invoked that way), or (b) treat the workflow as ambiguous and prompt the user via AskUserQuestion before any cleanup action.
  • Document location, plan derivation, and post-implementation update — the three duties that outlive this step.
    • Location: the spec / design document is saved under the project root's docs/ directory. In a workspace that nests several repositories under one root, it is docs/<repo>/ — the repository the design targets, not the workspace. This is a different layer from the filename rule above — that rule fixes the file name, this one fixes the directory — so whether the directory is docs/ or docs/<repo>/, the file is still named {topic-slug}.md and the filename-to-slug binding above holds unchanged.
    • Plan derivation: the implementation plan is written from the saved document, never from in-context memory of the discussion. The document is the input to planning, not a record of it.
    • Post-implementation update: once implementation is finished, the document MUST be updated to match what was actually built. Leaving a design document unrevised after its implementation diverged makes it a wrong document, not a historical one.
  • On the normal path the three user-facing lines below are rendered by the seat from presentation.md (CFI-1b), verbatim; the leg composes them and never emits them.
  • Notify the user in Korean: "설계 문서 저장을 완료했습니다. 팀을 정리한 뒤 결과를 공유드리겠습니다."
  • Before presenting results to the user, Read ${CLAUDE_SKILL_DIR}/../_common/team-cleanup.md and apply it — normal completion is a no-op (returned tasks already self-terminated), abort is TaskStop on any state=running agentId, plus ledger hygiene.
  • Verification aggregate line: if the ## 구현 시 검증 항목 section is non-empty, include in the Step 4 presentation one Korean line — "구현 시 검증 항목 N건이 기록되었습니다 — /implement 시작 시 우선 검증됩니다." (queue impact 0).
  • Present the results to the user in Korean. Do NOT yield the turn here — the presentation and Step 5's entry are one continuous turn. Immediately continue into Step 5 below in this SAME turn, with no stop, no wait, and no user prompt. (CFI-1b)

Step 5: Unresolved Issue Walkthrough

This step runs automatically right after Step 4 (CFI-1b). Its purpose is to drive every unresolved issue in the saved design document to a decision without waiting for an unprompted user request, scoped strictly to issues that cannot be resolved without user input. Mechanical gaps, false positives, and auto-decidable items are NOT this step's responsibility — the Surface Depth router below gives each of them a named destination: the Step 7 Class C coherence pass, a post-implementation /cc-cmds:review carrying a design-conformance tag, or an explicit recorded drop. User-facing communication in this step is Korean; the normative prose below is English.

"Walkthrough-spawned teams (Step 5) and refinement teams (Step 6) are both just fresh nameless-task spawns recorded in the ledger — there is no shared team namespace or monotonic counter — but they still differ in scope and lifetime: a walkthrough-spawned team is bounded to a single unresolved issue's decision debate (user-initiated when auto-investigation findings alone don't yield a clear decision) and its members self-terminate at that issue's resolution; a refinement team handles a user-initiated multi-turn refinement and its roles live (one fresh dispatch per round) until the user is satisfied. They are not competing entry points — they are the same entry point (user-confirmed spawn of nameless background tasks for a single bounded scope) invoked at two different lifecycle moments. The lead never extends a walkthrough-spawned team into a refinement team or vice versa — the self-terminate → next spawn contract is enforced unchanged."

Terminology: throughout this skill use "walkthrough-spawned team" (not "walkthrough investigation team"). "Investigation" refers strictly to the lead-only, read-only activity defined below.

Trigger & Queue Initialization

  • Parse the saved doc's ## 미해결 이슈 / 트레이드오프 section to initialize the issue queue. Parse contract: match the heading with the regex ^##\s+(?:[0-9]+\.\s+)?미해결\s+이슈(?:\s*/\s*트레이드오프)?\s*$ — an optional leading section number (6. , 10. , any digit count) and an optional / 트레이드오프 suffix are both allowed. On multi-match, use the LAST match (synthesis is written top-down, so the deepest occurrence is canonical).
  • 등급 1 On 0-match, surface via AskUserQuestion with three options: (a) add the section and proceed — the lead creates a ## 미해결 이슈 heading via doc Edit (sub-section form by default, per the encoding rules below), re-parses the doc to rebuild the queue; entries the user pre-added are processed as-is, and 0 entries cascade naturally into the 0-issue path; (b) skip the walkthrough and proceed to Step 6; (c) abort — the entire design workflow terminates and Step 6 is NOT entered.
  • 0 issues: emit the Korean notice "미해결 이슈가 없어 곧바로 플랜 리파인먼트 단계로 이동합니다." and proceed directly to Step 6. (CFI-2)
  • 1+ issues: emit "설계 문서에 미해결 이슈 N건이 확인되었습니다. 하나씩 검토하며 정리하겠습니다." and enter the walkthrough proper.
  • Depth-2 promotion on queue init: any entry carrying both 상태: 보류 and a (깊이: 2) marker is auto-promoted to depth-1 — the lead Edits the doc to change 상태: 보류 → 상태: 대기 and (깊이: 2) → (깊이: 1) together (the Parent field is preserved as historical metadata), then appends it to the queue. Plain 상태: 보류 entries (no depth marker, or (깊이: 1)) are NOT promoted — those are deliberate user deferrals.
  • Drop-uncertain promotion on queue init: any 상태: 보류 entry whose 사유: text contains the substring drop 미확정 (produced by the abort-during-drop-prompt path below) is also promoted — change to 상태: 대기, clear the 사유 field, append to the queue. This applies regardless of any depth marker, and re-surfaces issues whose drop confirmation was never completed.
  • Queue order: doc-order, top-to-bottom. Depth-1 items that surface mid-pass are appended to the end of the queue (not inserted right after the current issue) and are reached only after all pre-existing items are processed. No per-category priority ordering.
  • After the walkthrough finishes, emit "미해결 이슈 워크스루를 종료했습니다. 이어서 플랜 리파인먼트를 시작하겠습니다." and enter Step 6 automatically. (CFI-2)
  • If the user aborts mid-walkthrough, batch-mark the remaining items 상태: 보류 (see Abort Semantics below) and move to Step 6. (CFI-2)

Issue Sources & Categories

The issue queue has two sources:

  1. The saved doc's ## 미해결 이슈 / 트레이드오프 section (the Step 4 output).
  2. Items the lead surfaces while re-reviewing the doc — but these must be doc-first: record the item in that section via Edit before appending it to the in-memory queue (idempotency). Items found during the bulk re-review at walkthrough entry are queued as (깊이: 1); items found incidentally during a depth-1 issue's auto-investigation or team discussion are recorded doc-only as (깊이: 2) and do NOT enter the queue (see Depth Management below).

Each issue is classified into one of four categories:

Category Code Definition Auto-investigation default
Decision-needed UD A value/choice the synthesis left undecided or set to a default None — user value judgment
Clarification-needed UC Whether an assumption the synthesis adopted matches user intent grep the codebase convention first
Alternative-to-evaluate UA The doc presents multiple paths and the user must pick Read each option's affected files + cost estimate
Risk-acknowledgment UR A deliberate tradeoff the user must consciously accept None — surface the tradeoff framing only

Surface Depth (3-arm router)

While re-reviewing the doc, the lead routes each candidate issue to exactly one of four destinations. The walkthrough surfaces only what the user must decide; everything else gets a named owner or is dropped on the record. Nothing is left unrouted.

Arm 0 — surface here (this step's own scope). "Does resolving this require user input — a value judgment, an intent confirmation, a choice among alternatives, or a conscious risk acceptance?" YES → the walkthrough surfaces it now, per the per-category flow below. NO → route to arm 1, 2, or 3.

Arm 1 — coherence / completeness → QUEUE it for the Step 7 Class C pass. Cross-section field or contract mismatch, a decision contradicting another section, spelling and formatting, any internal inconsistency the document itself can settle.

Arm 2 — an item the design deliberately left to implementation → /cc-cmds:review carrying a design-conformance tag. Missing standard error handling, an unimplemented item, anything whose real question is "did the code end up matching the design?" That question is unanswerable before code exists, so its destination is post-implementation review rather than this step.

Arm 3 — everything else → EXPLICIT DROP. A false positive already resolved in the doc body, a hypothetical unrelated to real risk, an item outside the design scope, an item the lead's own auto-investigation alone resolves. Dropping is a decision, so it is recorded rather than silent — the pre-queue filter below is its mechanism.

Arm 1's timing is load-bearing — do NOT run anything there. The walkthrough is Step 5; the Class C pass runs after Step 6. Arm 1 is therefore queue-loading for the terminal window, not execution: the lead records the item as a one-line doc-body note tagged [Step 7 정합 점검 대상] and moves on. Reading this arm as "run the enlarged pass now" means editing the document before the freeze, and the downstream audit's whole guarantee rests on nothing changing between the freeze and the reads. Arm 2 fires after implementation and arm 3 is immediate and final, so neither has a timing hazard.

Mapping of the previously-non-surfaced classes to their arms:

Class Arm
spelling, formatting, cross-section field/contract mismatch 1
missing standard error handling 2
items already resolved in the doc body (false positives) 3
hypothetical items unrelated to real risk 3
items outside the design scope 3
items the lead's own auto-investigation alone can resolve 3

Pre-queue filter (arm 3's mechanism): this happens before queue initialization — while the lead re-reviews the doc, any candidate it judges a false positive gets only a short lead note in the doc body (e.g., "lead 자동 조사 결과: 코드베이스 컨벤션 X와 일치 — false positive") and does NOT enter the queue. No state-machine transition occurs, so this is unrelated to the state machine; it is triage, not a decision, and does not conflict with the user-confirmation rule for decisions. It applies to all four categories.

State Machine (5 + 1, doc-anchored)

Each issue follows this state machine (5 non-terminal + 1 transient-remove):

pending → investigating → awaiting-decision → resolved
                                           ↘ deferred
                                           ↘ dropped

UD/UR shortcut: pending → awaiting-decision (skips investigating)
  • investigating / awaiting-decision are ephemeral by default (lead memory). If a transition is mid-flight when a turn ends, checkpoint-write it to the doc so the next session can recover. The checkpoint format is the encoding convention below — sub-section form prepends a **상태**: 조사중 or **상태**: 결정대기 line; table form updates the 상태 column value.
  • Per-category transition shortcut: UD (user value judgment) and UR (tradeoff acknowledgment) have no auto-investigation, so they go pending → awaiting-decision, skipping investigating. UC/UA follow the full transition.
  • Checkpoint recovery: when a new walkthrough invocation parses the doc and finds a 상태: 조사중 or 상태: 결정대기 entry, the prior session's transient memory is lost, so the lead (i) Edits the doc to overwrite the marker with 상태: 대기, then (ii) appends it to the in-memory queue as 대기 so it is re-investigated in natural doc-order. The doc marker and queue state must always agree, so an in-memory reset alone is not sufficient. The checkpoint only guards against doc-state loss; it does not recover in-memory investigation findings.
  • resolved / deferred are terminal — written to the doc immediately.
  • dropped is terminal-remove — right after user confirmation the entry itself is deleted from the doc (the doc reflection is an entry removal, not an annotation write; see the dropped branch below).

Doc Encoding (tolerate both forms + 상태 marker)

Existing design docs use two encodings: table form (columns 항목 | 내용 | 우선순위 | 비고) and sub-section form (### N.x <항목명> headings + prose body). The walkthrough tolerates both and adds an inline 상태 marker.

  • Table form: append a 상태 column to the right of the existing columns. Additional fields (Category, Reason, 자동조사 요약, Surfaced-at, Parent) attach as extra columns. Field definitions: Surfaced-at = the walkthrough invocation that surfaced the entry (format walkthrough pass <N>, or Step 4 synthesis meaning an original design output item). N counter: a monotonic walkthrough-invocation counter starting at 1, +1 each invocation; not stored separately but derived as max(existing Surfaced-at entries) + 1 (the same doc-anchored, no-lead-memory doctrine as file-system enumeration); if the doc has no entries on the first call, N=1. Parent = a depth-2 entry's parent depth-1 issue (format "issue title (§anchor)"). The other fields are defined elsewhere in this step. Last-row removal edge case: if a dropped removal leaves the table with 0 data rows (only header + alignment), the lead removes the entire table and replaces it with the one-line note "이번 walkthrough에서 모든 미해결 이슈가 해소되었습니다." The ## 미해결 이슈 heading itself is kept (needed by the parse contract and future walkthrough invocations).
  • Sub-section form: prepend **상태**: <value> to the first line of each sub-section body. Additional fields are added as prose lines: **Category**: <value>, **Surfaced-at**: walkthrough pass <N>, **Parent**: <issue title> (§<anchor>), **Reason**: <text>, **자동조사 요약**: <text>. Field definitions are form-agnostic: the table-form definitions above (N counter derived as max+1, etc.) apply identically — the forms differ only in notation, the field semantics are single. Last-entry removal edge case: if a dropped removal deletes the last ### N.x sub-section, leaving 0 entries under ## 미해결 이슈, the lead inserts the one-line note "이번 walkthrough에서 모든 미해결 이슈가 해소되었습니다." as prose right after the heading. The heading itself is kept.

상태 values (5+1 states → 6-value Korean vocabulary):

Internal state Korean value Meaning
pending 대기 discovered, unprocessed
investigating 조사중 auto-investigation in progress (ephemeral)
awaiting-decision 결정대기 investigation done, awaiting user input (ephemeral)
resolved 해결 decision applied, reflected in the doc body
deferred 보류 deferred via per-issue defer or abort
dropped 제외 judged a non-issue by auto-investigation — transient classification only (the 제외 judgment exists in lead memory only; right after user confirmation the entry is deleted from the doc, and no 상태: 제외 annotation remains)

Additional invariants:

  • Mixed-form prohibition: within a single doc's ## 미해결 이슈 section, do not mix table form and sub-section form. The doc keeps whatever form Step 4 chose; the walkthrough never converts forms. This binds this skill only when it writes the section anew: an audit or a re-convergence adds an entry carrying **구현 처분** below a table in sub-section form, by ${CLAUDE_SKILL_DIR}/../_common/unresolved-closure.md (## 작성자 꼴).
  • Entries left open carry **구현 처분**: before the freeze, every entry left at a 상태 other than 해결 — 보류 above all — carries **구현 처분** and its companion field, chosen and written by ${CLAUDE_SKILL_DIR}/../_common/unresolved-closure.md (## 값 고르는 기준, ## 작성자 꼴).
  • Fresh section default: if the Step 4 output has no ## 미해결 이슈 section (synthesis judged 0 issues), the walkthrough uses sub-section form by default when creating the section (avoids table layout overhead at 0 rows).
  • Marker absence → 상태: 대기: if an entry exists but has no 상태 marker, the walkthrough interprets it implicitly as 상태: 대기. A marker is written to the doc only at the moment of a user decision; there is no retroactive bulk-write. This is the migration policy for pre-existing docs written without markers.

Depth Management (single section + inline marker)

Re-review and auto-investigation can surface new issues. Depth markers prevent infinite recursion:

  • (깊이: 1) — an item the lead surfaced independently during walkthrough re-review. doc-first Edit → queue-append → handled in the current walkthrough pass.
  • (깊이: 2) — an item surfaced during a depth-1 issue's auto-investigation or team discussion. doc-first Edit (default 상태: 보류 + 사유: depth-2 follow-up (parent <issue title> §<anchor>) + a Parent: <issue title> (§<anchor>) field — 사유 is the short citation, Parent is the structured follow-up field; both render the parent as "issue title + §anchor") → NOT queue-appended → re-enters as (깊이: 1) on the next walkthrough invocation.
  • (깊이: 3) and beyond is structurally impossible — a (깊이: 2) item never enters the current queue, so nothing can surface during its investigation.
  • Marker conversion on re-entry: when a depth-2 item enters as depth-1 on the next walkthrough invocation, the doc's (깊이: 2) marker becomes (깊이: 1) and 상태: 보류 becomes 상태: 대기 together (keeping doc state and queue state in agreement). The Parent field is preserved as historical metadata so a later user can trace the discovery context. Original Step 4 output items (no depth marker) are treated as implicit depth-1 — no marker need be attached.

Do not create a separate sub-section (## 워크스루 후속 항목). All items stay integrated in the existing ## 미해결 이슈 / 트레이드오프 section as a single source of truth; downstream tools parse just that one section.

Announce timing: right after a parent depth-1 issue enters a terminal state (resolved/deferred/dropped), announce in Korean — in one combined message — all depth-2 items identified while processing that issue (both lead auto-investigation and team discussion sources). Example form: ? parent <issue title> 처리 중 depth-2 N건 식별 — 다음 walkthrough에서 자동 표면화: [<title>, <title>, ...]. depth-2 items are default-deferred, so no user decision input is required (announce only). If there are 0 depth-2 items, skip the announce.

Per-issue Processing Flow (hybrid)

One issue per question (invariant): every question in this step carries exactly one issue — one question of a mcp__cc-cmds__question_form form, or one AskUserQuestion call on the fallback path. On the form path a round's form carries every issue now in awaiting-decision, one question each, with that issue's full per-category menu; the form has no option cap, so Cap-handling below does not fire there. On the AUQ fallback path each call still carries exactly one issue, the up-to-4-questions capacity is never used to bundle issues, and the 4-option cap and Cap-handling apply unchanged. The per-issue mechanisms — auto-investigation, the ← 추천 recommendation, the UC 더 논의 follow-up loop, the dropped-confirm prompt and mid-flight reclassification — are per question: investigation finishes before the form opens; a non-terminal answer (더 논의, 그래도 유지, an approved 팀 토론 진행's composition question, 미답) carries its issue to the next round's form; team spawns stay one issue at a time.

Old heading (for re-deriving citations): "One issue per surface (invariant)" - one form carries many questions, so the unit of the invariant is the question

For each issue:

  1. Auto-investigation (lead-only, read-only + reproducible):
    • UD: Read doc context only.
    • UC: grep for the assumed convention in the project's primary source tree (e.g. src/**, plugins/**, app/** — the lead adapts to the project's convention); optional make test.
    • UA: Read each option's affected files + cost estimate (line-count delta, etc.).
    • UR: Read the tradeoff framing only. Reproduction pointer (Surfaced-at: Step 4 synthesis, body references §재현·근본원인): when surfacing it, the Why-it-matters / framing text must quote the canonical section's 근거 등급: 가설(추측) value (read-only reference, not a stored copy) so the user sees the hypothesis grade at decision time without manually following the anchor.
    • Hard limits: stop as inconclusive if grep returns >50 hits; stop if make test exceeds 2 min. If the result is inconclusive, surface it as "조사 inconclusive — 사용자 판단 필요".
  2. 등급 2 Surface as that issue's question in the round's form (one AskUserQuestion call on the fallback path), Korean with: a one-line Title; a Category tag (UD/UC/UA/UR — fits the 12-char header chip limit); Why-it-matters (1-2 lines); the auto-investigation summary (the findings, or "조사 불필요"); Options (the per-category menu below — also apply the recommendation rendering check from the Lead recommendation policy paragraph: when auto-investigation is confident, move the recommended option to position 1 with ← 추천 and place the rationale in its description); and a Doc reference (§ anchor).
  3. Apply the user's decision:
    • Direct resolution → mark 상태: 해결 + reflect the decision in the doc body. A UC "다르게 수정" response also maps here (the lead Edits the doc body per the user's correction + 상태: 해결).
    • Defer → 상태: 보류 + record a reason (format 사유: 사용자 결정 보류 (<date YYYY-MM-DD>)).
    • Drop (the dropped branch, UC only) → after user confirmation the entry is REMOVED from the doc. Trigger condition: branches only in the UC category when the lead's auto-investigation finds the issue is a false positive (already resolved in the doc body / codebase convention matches the assumption). User-confirmation mechanism: surface the false-positive finding as that issue's question, which carries the dropped-confirm menu instead of the UC menu (a separate AskUserQuestion on the fallback path) — body "이 항목은 §X에서 이미 다뤄지고 있어 미해결 이슈에서 제거하려 합니다.", options "확인 / 그래도 유지 / 보류" (each option carries a 1-line description per the Description requirements subsection below — 확인 uses the hybrid <static semantics> — 근거: <false-positive evidence> (<path:line>) form, 그래도 유지 and 보류 use static descriptions). On user confirm, Edit the doc to delete the entry — removed immediately, no 상태: 제외 annotation. On "그래도 유지", enter the normal UC menu (맞음 / 다르게 수정 / 더 논의 / 팀 토론 진행). UD/UA/UR have no dropped branch — they require user value judgment, so a false-positive verdict is impossible.
    • Redesign (a UR option) → 상태: 보류 + 사유: 재설계 필요 — Step 6 refinement에서 처리. The walkthrough does not redesign directly; it defers.
    • Discuss further (a UC option) → the issue returns in the next round's form with the lead's reply in detail and the person's in the note (an AskUserQuestion follow-up on the fallback path); the lead continues the dialogue until the user picks one terminal option among "맞음" / "다르게 수정" / "보류" / "팀 토론 진행". It has no terminal state of its own.
    • Run a team discussion → the spawn flow below.
    • No answer (미답, form path) → the issue rides in the next round's form unchanged. When the same issue comes back 미답 twice in a row → 상태: 보류 + 사유: 사용자 미답 (<date YYYY-MM-DD>).

Per-category Option Menu + Team Spawn

Every option in a per-category menu carries a 1-line description field. For options recommended via ← 추천, the description follows the format <semantics> — 추천 근거: <evidence> with citation tokens per the Lead recommendation policy paragraph; otherwise it is the per-label static text tabulated in the Description requirements subsection.

Each category's user-facing options (Korean). Default ordering: direct-resolution options first, then 보류, then 팀 토론 진행 (escalation gradient). Recommendation override: when the auto-investigation is confident, the recommended option moves to position 1 with ← 추천 appended; the remaining options preserve their relative ordering. Conditional inclusion exception: for UD/UA menus with K_pick ≥ 3, structural-slot visibility (보류·팀 토론 진행) follows the branch (a)/(b) layout in the Lead recommendation policy paragraph — both may be pinned (branch a) or hidden from the visible options array (branch b), with hidden items reachable via the AskUserQuestion Other channel. Default ordering applies only when conditional inclusion does not fire (UC/UR menus, or UD/UA with K_pick ≤ 2). Note the structural slots appear where present, in the order 보류 → 팀 토론 진행 — not every in-scope menu has both: the UC initial menu (맞음 / 다르게 수정 / 더 논의 / 팀 토론 진행) has no 보류 slot and places 더 논의 before 팀 토론 진행; the UR menu (수용 / 재설계 / 보류 / 팀 토론 진행) and UC sub-loop (맞음 / 다르게 수정 / 보류 / 팀 토론 진행) have both. The UC dropped-confirm confirmation dialog (확인 / 그래도 유지 / 보류, no 팀 토론 진행) is not an escalation-gradient menu — it follows its own carve-out ordering and is excluded from this default-ordering rule. See the Lead recommendation policy paragraph below for the confidence criterion + cap-handling rules.

Category Options
UD (1-4 issue-specific concrete picks) + "보류" + "팀 토론 진행". A single concrete pick (binary confirm-only scenario) is also allowed — present the lone option as "이대로 적용 / 보류 / 팀 토론 진행". Picking a concrete pick maps to the "direct resolution" branch above.
UA (option A / option B / ...) + "보류" + "팀 토론 진행". The user's option choice maps to "direct resolution"; the lead records an alternatives-considered note when Editing the doc.
UC "맞음 / 다르게 수정 / 더 논의 / 팀 토론 진행" (initial). Mapping: "맞음" → the "direct resolution" branch (the user confirms the lead's assumption interpretation; mark 상태: 해결 — the bare value, never with a note on the same line (${CLAUDE_SKILL_DIR}/../_common/unresolved-closure.md, ## 작성자 꼴) — but do NOT add a 사유 field — 사유 is reserved for the 보류 state in this spec; instead add the inline note "사용자 confirm: 가정 정확." at the end of the doc entry, with the body unchanged). "다르게 수정" → the same "direct resolution" branch. UC's initial menu deliberately omits "보류" — to prevent the user from skipping the issue without reviewing the auto-investigation summary; "보류" is reachable only inside the sub-loop after the user explicitly enters dialogue via "더 논의". On "더 논의" the sub-loop is entered, and its terminal option set is "맞음 / 다르게 수정 / 보류 / 팀 토론 진행" — "더 논의" is replaced by "보류" to prevent infinite dialogue.
UR "수용 / 재설계 / 보류 / 팀 토론 진행". Picking "수용" maps to the "direct resolution" branch (상태: 해결 + a tradeoff-acceptance note in the doc body — 사용자 acknowledged tradeoff: <original tradeoff framing>).

See the Description requirements subsection below for per-option description format (recommended-option rationale form + per-label static descriptions).

Lead recommendation policy: when the auto-investigation meets the per-category confident criterion — UC: grep returns 3–50 hits with ≥80% alignment to one verdict and no canonical-surface counter-example; UA (ANY of): cost delta ≥2× on line-count with affected-file count not inverted, OR one option has a hard blocker the other lacks, OR one option touches a doc-marked frozen/no-touch path the other doesn't; UD (ALL of): a parallel decision already committed elsewhere in this saved doc anchors the pick (cited as §<anchor>) AND one of the offered options aligns with that committed pattern AND the doc records no "this case is different" rationale — never on lead taste; UR: blast radius scoped to ≤1 module with no concrete lower-cost alternative cited (→ 수용), or ((blast radius ≥2 modules) OR (critical path: auth/payment/data integrity/persistence schema/public API contract)) AND (a concrete cited alternative without prior rejection rationale) (→ 재설계), or the tradeoff explicitly references cross-team coupling / out-of-scope expertise AND ≥2 distinct expert roles would weigh in differently (→ 팀 토론 진행), or the issue is downstream of a depth-1 parent currently in 상태: 대기 or 상태: 결정대기 (→ 보류); NONE-good case: when the lead is confident no listed option fits because of a doc-cited gap (§<anchor> constraint that all options miss, or a blocker absent in <evidence path> that all options require), force 팀 토론 진행 ← 추천 with the gap citation in the rationale — without a specific gap citation this case degrades to inconclusive.

Recommendation contract: the lead applies the documented AskUserQuestion recommendation convention — append ← 추천 to the recommended option's label, force it to position 1, and place the rationale in that option's description field. The description follows the format <semantics> — 추천 근거: <evidence> where <semantics> is a brief (≤10 Korean syllable) action/result summary (긴 UD/UA pick label로 인해 ≤10 음절을 약간 초과해야 의미 보존이 가능한 경우 soft over-flow 허용 — semantic clarity가 우선) and <evidence> carries the rationale. The description MUST be ≤2 sentences, ≤140 chars, and <evidence> MUST carry at least one citation token (code path :line, §<anchor>, a quantitative measurement such as affected files: 4 / ~4× / 12/12 hits, or a blocker fact requires X, absent in <evidence path>). Opinion phrases (cleaner, simpler, idiomatic, common practice, I think, feels like) are forbidden unless paired with a citation token in the same sentence; this citation/denylist rule applies only to descriptions of options carrying ← 추천 — static descriptions on non-recommended options are display-only and exempt. All four options are eligible candidates — including 팀 토론 진행 and 보류 — provided their confidence criterion is met. When the criterion fails (grep results split outside 80/20, cost delta within 1.5×, no parallel anchor for UD, mixed UR impact, NONE-good without a gap citation, any auto-investigation hard limit tripped), the lead refuses to recommend: Why-it-matters surfaces "조사 inconclusive — 사용자 판단 필요" and the menu renders in default order with no ← 추천 suffix. Why-it-matters never duplicates the rationale (that lives only in the recommended option's description); when confident it is framed as "결정만 내리면 적용 가능".

UC sub-loop interaction: the prior recommendation is suppressed by default on first sub-loop entry — re-computation is permitted only if (a) a new auto-investigation pass with materially different inputs still meets the confident criterion, or (b) the dialogue surfaces a previously-unrecorded fact that flips the alignment ratio; in both cases the description must cite the new evidence. "Previously-unrecorded" means the fact is absent from the original AskUserQuestion surface's auto-investigation summary text — the lead's in-session memory of earlier turns does NOT qualify.

Dropped-confirm prompt carve-out: the UC false-positive prompt (body: "이 항목은 §X에서 이미 다뤄지고 있어…") is structurally a confirmation dialog (binary accept / override / punt), not a pick-one-among-equals menu — ← 추천 is NOT applied to its 확인 option (the prompt body already asserts the lead's verdict; adding the suffix would double-signal and friction 그래도 유지). Its 확인 option uses a hybrid description form <static semantics> — 근거: <false-positive evidence> (<path:line>) (with 근거: prefix, NOT 추천 근거: — the segment is a fact statement, not a recommendation rationale); the citation/denylist rules of this paragraph do NOT apply to that hybrid form. The hybrid form still respects the recommended-option ≤140 chars / ≤2 sentences hard limits.

Cap-handling — conditional inclusion (category-agnostic): when concrete picks plus structural slots 보류/팀 토론 진행 would exceed AskUserQuestion's 4-option cap (i.e., K_pick ≥ 3 in UD/UA), the menu undergoes conditional inclusion rather than blanket collapse. Branch (a) — when the recommended option is 보류 or 팀 토론 진행: both structural slots are pinned (recommended at position 1; the non-recommended structural is placed at the position it would occupy in the canonical order [picks..., 보류, 팀 토론 진행] after removing the recommended item and shifting remaining items up — typically position 4 since 팀 토론 진행 is canonical-last, and 보류 lands at position 4 when 팀 토론 진행 is recommended), and the K_pick − 2 lowest-priority concrete picks are dropped per a worst-cascade rule (hard blocker → deprecated-path overlap → frozen-path overlap → largest line-count delta ≥1.5× → doc-order LAST tiebreaker; continue-on-tie within tied subset). The 2 surviving picks fill the visible pick slots in canonical relative order. Branch (b) — when the recommended option is a concrete pick OR the result is inconclusive: both structural slots are hidden from the options array but remain reachable via the AskUserQuestion Other channel — the user types 보류 or 팀 토론 진행 (NFC-normalized + whitespace-normalized including U+3000 → U+0020, exact-match against canonical Korean tokens) and the lead processes the input identically to a menu selection. Hide ≠ collapse: the decision path remains open via Other, so the "보류/팀 토론 진행 never collapse" commitment is preserved; only the visible slot is reassigned under cap pressure when no recommendation endorses them. K_pick ≤ 2 (option count ≤ 4) skips conditional inclusion entirely — both structural slots are always shown. Disclosure: when conditional inclusion fires, the Why-it-matters companion text discloses the dropped picks (branch a, format 옵션 캡(4)으로 <K_pick>개 픽 중 <X>건 생략 — 생략 픽: <label1>, <label2>, ...) or the Other-channel reachability of 보류/팀 토론 진행 (branch b, format 보류·팀 토론 진행은 Other 채널에 '보류' 또는 '팀 토론 진행' 입력 시 동일 처리.) so the user audits the option-set difference. Branch (b) carries the Other-channel disclosure whenever conditional inclusion fires (K_pick ≥ 3), and additionally appends the dropped-picks disclosure when K_pick > 4. Multi-session consistency: the cascade is stateless — re-computed from scratch on each AskUserQuestion call, no drop-state persistence in the doc.

Mid-flight reclassification: if auto-investigation reveals a category change (UC→UD/UR, UA→UD), the lead Edits the doc's Category field, surfaces with the new menu, and re-applies the new category's confident criterion. Investigation-time only: once AskUserQuestion has entered awaiting-decision, the prompt is immutable; if reclassification surfaces late, the lead applies one of two fallbacks. (i) Apply-then-defer (when the user response is 보류 only): apply the user's 보류 as the resolution, Editing Category field first, then 상태: 보류 + 사유 where 사유 is always lead-generated in the canonical defer-branch form 사유: 사용자 결정 보류 (<date YYYY-MM-DD>) (재분류됨: <old-cat> → <new-cat>) (no user-reason-collection branch — there is no free-text input channel on the AskUserQuestion fallback path, and on the form path the note is the user-reason channel; the <date> stamp + 사용자 결정 보류 prefix are mandatory per the cross-issue defer convention). (ii) Immediate-defer (default for any other response, including 팀 토론 진행): 상태: 보류 + 사유: 재분류 필요 — 다음 walkthrough에서 처리; the user's response is discarded because original-category interpretation can be invalid under the new category (team-spawn flow especially is category-coupled and would synthesize under wrong category if (i) were used). The lead's text response discloses the reclassification to avoid silent doc mutation, with distinct messages per case — case (i): "방금 보류 결정을 적용했습니다. 참고로 이 이슈의 Category가 <old> → <new>로 재분류되었습니다."; case (ii) (the consequential one — a discarded user selection must be explained): "재분류(<old> → <new>)이 발견되어 이 이슈는 다음 walkthrough에서 새 카테고리로 다시 surface됩니다. 방금 선택하신 응답은 새 카테고리의 메뉴 의미가 다를 수 있어 적용하지 않았습니다."

Team-spawn coupling: recommending 팀 토론 진행 does NOT preload the team composition into this AskUserQuestion prompt — the role/scope/model proposal remains the separate downstream step described in the Team Spawn Flow below, preserving the two-layer approval (entry into the team flow vs. composition approval). Display-layer fence: the entire recommendation mechanism is a display-layer concern on awaiting-decision: no new states, no doc markers, no transition edges, no checkpoint format changes.

Description requirements

Every option in a per-category AskUserQuestion menu carries a 1-line description. For the recommended option (when present), the description follows the format <semantics> — 추천 근거: <evidence with ≥1 citation token> and must satisfy the citation-token allowlist + denylist rule defined in the Lead recommendation policy paragraph above. For all other options (non-recommended in a recommended menu, and all options in an inconclusive menu), the description is a static 1-line semantics text fixed per label as tabulated below. This table is the single source of truth for static option semantics — when the per-category option menu's decision branches (the menu table preceding this subsection) are amended, the static description for the affected label MUST be updated atomically in the same edit.

Label Static description
수용 현재 트레이드오프를 인정하고 해결됨으로 표시합니다.
재설계 보류 처리 후 Step 6 refinement에서 재설계합니다.
보류 지금 결정을 미루고 나중에 처리합니다.
팀 토론 진행 전문 팀을 구성해 이 이슈를 심층 논의합니다.
맞음 가정이 정확합니다. 해결됨으로 표시합니다.
다르게 수정 가정 내용을 직접 수정합니다.
더 논의 리드와 추가 대화를 진행한 뒤 결정합니다.
확인 이 항목을 문서에서 즉시 삭제합니다.
그래도 유지 이 항목을 유지하고 정상 UC 메뉴로 진행합니다.
UD concrete picks <해당 값>으로 확정합니다. (dynamic — <해당 값>은 이슈가 surface한 개별 pick 라벨)
UA option picks <option name>으로 구현합니다. (dynamic — <option name>은 이슈가 surface한 개별 alternative 라벨)

Dynamic pick recommendation form (UD/UA concrete pick이 추천 옵션일 때): 위 dynamic static template (...합니다.)을 그대로 description에 쓰지 않고, <semantics> slot에 verb-stem 형태 (trailing 합니다. 제거) 로 변환한 뒤 recommended-option format 적용한다. UD 예: <해당 값>으로 확정 — 추천 근거: <evidence>. UA 예: <option name>으로 구현 — 추천 근거: <evidence>. trailing 마침표 제거는 em-dash separator의 명확성을 보존하기 위함이며, <semantics> slot의 ≤10 음절 budget 적용 (긴 <해당 값> / <option name> 라벨의 경우 ≤10 약간 초과 가능; 의미 명확성 우선).

Dropped-confirm prompt exception (third description type): the UC false-positive prompt's 확인 option uses a hybrid format — <static semantics> — 근거: <false-positive evidence> (<path:line>) — with the 근거: prefix (not 추천 근거:) signaling fact statement rather than recommendation. The citation/denylist rules of the Lead recommendation policy paragraph do NOT apply (the 확인 label has no ← 추천 suffix per the dropped-confirm carve-out); the evidence segment is descriptive rather than rationale. The hybrid form inherits the recommended-option ≤140 chars / ≤2 sentences hard limits; if the evidence path exceeds budget, prefer a shorter §<anchor> citation or relative path over the absolute path.

Team spawn flow (when the user picks "팀 토론 진행"):

  1. The lead proposes a role/scope/model composition for that issue in Korean → user approval. If the user rejects or asks to revise the composition, the lead either (i) re-proposes a revised composition (repeatable), or (ii) if the user withdraws "팀 토론 진행", returns to that category's normal terminal option menu (direct resolution / defer / (UC only) drop branch / (UR only) redesign / (UC only) discuss-further, per category). UC exposes "보류" directly in this fallback: the user already engaged the issue actively via the team-spawn proposal, so UC's initial-menu gate (forcing auto-investigation review) no longer applies — the fallback's "보류" is deliberately directly reachable.
  2. Spawn the approved members as fresh nameless background tasks (Agent, subagent_type: "claude", run_in_background: true, no name) and record each agentId in the ledger. Stamp epoch (max(disk epoch, 0)+1, re-derived from the on-disk ledger — never an in-context counter; this fresh walkthrough team → epoch 2 in the normal sequence) and the round-1 witnessNonce on every one of its rows in the same at-spawn recording window as agentId/scratchDir, per the protocol Spawn section. Create this fresh team's own witness dir with a fresh run of the protocol's ## Spawn command — <plugin root>/orchestrator/cc-team-witness-init.sh {issue-slug} (no bash in front — see the protocol's note) — and record the printed path, literally (not $WITNESS_DIR) as each member's scratchDir; the issue-discussion rounds are witnessed per _common/agent-team-protocol.md.
  3. English discussion → synthesis → the lead Edits the doc to reflect the decision. Team result → state mapping: (a) team agrees on a single resolution → 상태: 해결 + decision reflected in the doc body; (b) team agrees on "recommend deferral" → 상태: 보류 + reason 팀 토론 결과 추가 검토 필요; (c) team finds depth-2 items → the doc-first handling above (recorded as separate entries + accumulated in the parent's announce); (d) team agrees a UC issue is a false positive → route to the dropped-confirm prompt above (entry REMOVED after user confirmation). In all cases the doc Edit completes before the team-cleanup in step 4.
  4. Before entering the next issue or ending the walkthrough: Read ${CLAUDE_SKILL_DIR}/../_common/team-cleanup.md and apply it (returned tasks already self-terminated — no-op; TaskStop any state=running agentId; ledger hygiene).
  5. Proceed to the next queue item.

Abort Semantics

  • Abort is detected by lead judgment (no regex matching). Examples:
    • Full abort: "그만", "중단", "이만 됐어", "리파인먼트로 넘어가자", "skip rest".
    • Single-issue skip: "이건 패스", "다음 이슈", "이건 나중에". On a skip, mark only the current issue 상태: 보류 + 사유: 사용자 per-issue skip, <skip date YYYY-MM-DD> (distinguishable from the full-abort reason) and proceed to the next queue item. Active team handling: if a walkthrough-spawned team is active at skip time, apply _common/team-cleanup.md (TaskStop any state=running agentId + ledger hygiene) before entering the next queue item — the same cleanup obligation as the full-abort path (cleanup-anchor doctrine).
  • On full abort, in ONE batched Edit mark all remaining 대기 / 조사중 / 결정대기 items 상태: 보류 + 사유: 사용자 조기 종료, <abort date YYYY-MM-DD, runtime-generated>, then enter Step 6. (CFI-2)
  • If a walkthrough-spawned team is active (spawned, cleanup not yet done) at abort time, clean it up via _common/team-cleanup.md (TaskStop any state=running agentId + ledger hygiene) before the batch 보류 Edit. The issue in progress is included in the batch and marked 상태: 보류.
  • If the user is viewing a UC dropped-confirmation prompt at abort time, the drop is auto-cancelled and that issue is kept in the doc, included in the batch as 상태: 보류 + 사유: 사용자 조기 종료 (drop 미확정, 재호출 시 재표면). No item is ever silently deleted without the user's explicit drop confirmation.

Step 6: Plan Refinement with User

State check on entry: Re-read the ledger from disk (re-read — do not trust in-context copies; a missing/unparseable block is fail-closed via AskUserQuestion). If the ledger has any residual state=running row (a Step 3 original-team member, any prior walkthrough-spawned member from Step 5, or any prior Step 6 refinement member still running), notify the user in Korean ("이전 단계의 팀이 아직 살아있어 정리 후 리파인먼트를 시작하겠습니다."), then execute cleanup now (Read ${CLAUDE_SKILL_DIR}/../_common/team-cleanup.md and apply it — TaskStop each state=running agentId, then ledger hygiene) before any Step 6 activity. A residual state=running row is the leftover-detection signal (it replaces the removed teams/ filesystem scan). The <slug> (the ledger key and docs/<slug>.md filename) is recovered from the saved design document filename in docs/ (the filename encodes the topic slug per Step 4's save convention — local file-system state, not memory). Preferred slug recovery: the lead remembers the exact filename it saved in Step 4 (not mere "most recent .md file" — that may be unrelated to the design workflow if the project is actively edited elsewhere). If the lead cannot recall the exact filename, fall back to matching against docs/ modification times within a narrow window after Step 4, and if still ambiguous (multiple candidates), prompt the user via AskUserQuestion to confirm the target document. Never assume the most recently modified docs/*.md is the design doc without validation. Because the ledger lives inside this workflow's own docs/<slug>.md, every ledger row belongs to the current workflow's topic — there is no cross-matching of unrelated prior-session work. Any state=running row is treated as active and requires cleanup. Under normal flow, all prior members have already self-terminated and this step proceeds with the lead only. Worktree gate (in-session verification cleanup): also run the two-command boundary gate (_common/verification.md §6) on entry, in full — assertion 1 and all three of 2a/2b/2c, not the cc-design-exp- count alone; force-remove (git worktree remove --force) + git worktree prune any mechanism-owned worktree that leaked from a prior step before proceeding.

  • On entering Step 6, emit ONE short Korean notice that the design document is ready for refinement and invite the user's input, then YIELD the turn and wait for the user's reply. At Step 6 ENTRY do NOT call AskUserQuestion to open the discussion or manufacture a refinement question (e.g. '무엇을 다듬을까요?'). Once the user replies, discuss the design document with them in Korean and refine the plan together. (CFI-2)
  • Lead-only by default: doc edits, user Q&A, and codebase re-exploration require no team.
  • If the user raises questions requiring deeper investigation that exceed lead-only capacity, verify the ledger shows no residual state=running row (if one remains, notify in Korean: "새 리파인먼트 팀을 만들기 전에 기존 팀을 먼저 정리하겠습니다." and execute cleanup), then propose composing a new team for that specific investigation — mirror Step 2 (role/scope/model proposal → user approval → spawn the members as fresh nameless background tasks recorded in the ledger). A Step 6 investigation team is always a NEW team — never a reused or restarted prior design team. The closed list of prior-team re-convenings that are permitted anywhere in this skill is in ## Constraints → Permitted team resumes; no Step 6 investigation is on it.
  • Only create a new team if the user approves. Otherwise, continue refining in the current session.
  • If a new team is created, spawn its members as fresh nameless background tasks (Agent, subagent_type: "claude", run_in_background: true, no name) recorded in the ledger (stamp epoch = max(disk epoch, 0)+1, re-derived from the on-disk ledger — never an in-context counter; this fresh refinement team → epoch 3 in the normal sequence — and the round-1 witnessNonce on every row in the at-spawn recording window, per the protocol Spawn section) — each fresh refinement team gets its own nested witness dir from a fresh run of the protocol's ## Spawn command, recorded as the rows' scratchDir, and its rounds are witnessed per _common/agent-team-protocol.md. Conduct internal discussion in English. After discussion converges and results are synthesized, update the saved document in docs/. Then notify the user in Korean: "리파인먼트 팀을 정리한 뒤 후속 논의를 이어가겠습니다." Before creating the next refinement team or returning to user discussion, Read ${CLAUDE_SKILL_DIR}/../_common/team-cleanup.md and apply it (returned members self-terminated — no-op; TaskStop any state=running agentId; ledger hygiene). Present the updated results to the user in Korean.
  • Repeat until the user is satisfied with the plan. That satisfaction signal is the ONLY exit from Step 6, and it enters Step 7 automatically in the same turn (CFI-3a).

Step 7: Class C Coherence Pass & Freeze (document-wide, single-pass, non-recursive)

What this pass is. ONE document-wide coherence-and-completeness check of the FINAL text, run by the Step 3 discussion team. It is not the Step 4 fidelity pass repeated — the two answer different questions. Fidelity asks "did synthesis distort or drop what I said?" and is meaningful only immediately after synthesis. This pass asks "is the whole document coherent and complete?" and is meaningful only on the final text, after Step 5's walkthrough decisions and Step 6's refinements have landed. Both passes exist; neither replaces the other. Because it runs on the final text, "single-pass and non-recursive" here means once over what actually ships.

Why the authoring team, and why it cannot be deferred. Context-dependent defects — a Step 5 or Step 6 decision that contradicts a requirement confirmed in the Step 1 interview, an architecture point discussed but never written down — leave no evidence in the artifact. A fresh reader's sensitivity to them is structurally zero, not merely low, because the evidence it would need is not in the document. The authoring team is the only non-zero channel, and its context dies when design ends. So this pass cannot be handed to any later command; a downstream audit covers the complementary class, not this one.

Single-pass and NON-RECURSIVE (hard). Exactly one pass over the final text. The lead does NOT re-submit the pass's own corrections for another round — reviewing its own output would reproduce, inside design, the generator this pipeline removed. (CFI-3b)

Roster scoping (mandatory, before any dispatch). The Step 3 team is epoch 1, but Step 5 and Step 6 may have spawned fresh teams at epoch 2, 3, … — and Step 6 loops, so the maximum is not statically knowable. Apply the protocol's re-convened prior team — epoch re-stamp (_common/agent-team-protocol.md, Spawn): re-derive epoch := max(disk epoch, 0) + 1 from the on-disk ledger and write it onto every Step-3 row, one single-row Edit per row, all in one contiguous window, before the first coherence dispatch and alongside each row's coherence witnessNonce. Never hard-code the value. After the re-stamp the roster's max(epoch) over non-aborted rows resolves to exactly the Step 3 team; without it the roster resolves to the last fresh team and self-heal would consume a foreign-role member's output as this pass's product. The re-stamp is written by the leg, in the leg's session, because the leg is the session that dispatches into those rows and owns any same-key resume of the members it dispatches.

Procedure

  1. Re-read the ledger from disk (never in-context copies; missing or unparseable is fail-closed via AskUserQuestion). If any state=running row survives from Step 5 or Step 6, Read ${CLAUDE_SKILL_DIR}/../_common/team-cleanup.md and apply it first.

  2. Precondition — does the leg's team still exist on disk? stat ${CLAUDE_CONFIG_DIR}/projects/*/<session_id>/subagents/, globbed by the leg's session_id from leg.json (never re-derive the project key). Present → the primary path (3). Absent → that is the transcript loss, and it is one of exactly two triggers of the fallback (3'). The other is the pull-check ladder's step-8 death while phase is resume, where rung 1r is forbidden precisely because a re-dispatched leg would save over this document. There is no third trigger.

  3. Primary path — the resumed leg dispatches its own team's roles afresh. The seat writes phase: resume together with state: pending into leg.json, in one atomic write — the discuss-phase consumption left state: done, and without pending the pull-check that observes coherence.md never runs (CFI-1b). It then writes the coherence message — the final document's path plus every [Step 7 정합 점검 대상] note the Step 5 router queued (there may be none); the document is never embedded — to a resume file $STATE/resume.<ISO8601>.txt and sends it through the resume line of Step 2's dispatch block (item 6), which passes that file as $(cat …) command substitution and never inlines the message on the command line (the notes are backtick-heavy Markdown), and yields as in CFI-1a. Inside the leg: re-stamp the Step-3 rows' epoch per the paragraph above (a precondition of dispatch, not an optimization), write each row's coherence witnessNonce before the dispatch and flip the row (agentId, outputFile, round/phase, state, stallMark) after it, dispatching each Step 3 role afresh at the new epoch — a new key, so a new dispatch under ## Constraints → Permitted team resumes — with phase token coherence (colon-free, per the protocol), the task-assignment header from _common/agent-team-protocol.md embedded verbatim, the member's own past witnesses by path, and the whole final document read by path. This is the same class of input as the fallback (3') — what was written to disk, no retained context — but not the same input: the fallback reads the whole durable corpus and the brief. Serialization clause: from the moment the coherence turn is dispatched until its artifact ($STATE/coherence.md, header <!-- cc-design-coherence v1; writer=design-discuss-unattended; reader=design; slug=<slug> -->) is observed, the seat does not edit the document; the leg writes the ledger block only and never writes prose. Two processes with no lock between them are otherwise concurrent writers of the very document being frozen.

    • 3'. Fallback (only on one of step 2's two triggers). Respawn the Step 3 roles fresh at a new epoch from the durable witness corpus ($STATE/witness/: every round and phase witness, each member's rendered dispatch prompt, and INDEX.md), the brief, and the final document by path. INDEX.md's lead/sweep row and SWEEP.md are not member roles: neither is respawned nor put on the roster. Class C sensitivity here is partial, not zero: what was written anywhere is recovered — a Step 5/6 decision contradicting a Step 1 requirement is more detectable than today, because the brief is the interview's durable record — and what was thought but never witnessed is not.
  4. Emit ONE one-way Korean notice at entry (not a question): "팀이 최종 문서의 전체 정합성을 점검하고 있습니다."

  5. Collect by witness — each member publishes ${scratchDir}/{role-slug}.coherence.md (sentinel/nonce per the protocol; the return text is only an early-wake hint and the collector reconciles the witness, never the return). Case-1 (thin/empty witness) and Case-2 (never-returns) handling is identical to the Step 4 fidelity pass's, with coherence substituted for fidelity. The finding blocks keep a free shape, but each witness ends, above its sentinel, with one line of its own findings: <n> (findings: 0 when it found nothing); a coherence witness without that line is a Case 3 non-conforming witness (_common/agent-team-protocol.md) — re-instruct the member and take its coherence-rev<k> revision. The count is the line's value; it is not checked against the blocks. A missing witness is NEVER read as "no objection". On the primary path the leg collects and returns its findings in coherence.md; the seat's pull-check observes that file.

  6. Triage and apply — ONE time, by the seat, after the leg's turn has ended. The lead applies corrections directly from coherence.md. A finding that contradicts a converged decision does not reuse the fidelity pass's re-convergence cycle. That cycle opens by messaging the affected author, and here nobody can: the authors' coherence dispatches belong to the leg, a same-key resume is addressable only from the session that dispatched the member, and the leg's turn has ended by the time this step runs — so the borrowed procedure's first step has no executor while only its terminus does. The seat raises such a finding to the user itself — 등급 2 — naming the finding, the converged decision it contradicts and what each answer costs, and applies the answer directly. That is the seat's only channel, not an abbreviation of the team cycle; Step 4's fidelity pass keeps its own cycle, which runs inside the leg where the authors are addressable. Do NOT re-dispatch the team over the corrected text. Clear each consumed [Step 7 정합 점검 대상] note as its item is disposed of, so no queue marker survives into the frozen bytes.

  7. Cleanup — Read ${CLAUDE_SKILL_DIR}/../_common/team-cleanup.md and apply it.

  8. Slicing self-check (only when the document has a ## 구현 슬라이싱 section; the lead runs it, no team). Downstream orchestration parses this section mechanically and cannot ask anyone what was meant, so five composition rules and two split rules are checked here — the last moment the authors are still alive — rather than discovered as a broken build hours later. (a) Declared ⊇ actual. For each ### 슬라이스 <id> block, the files it declares must include every file the slice's own description says it edits; a slice that describes an edit it did not declare fails. (b) A SKILL.md frontmatter change implies README.md. A slice that creates a SKILL.md or edits a SKILL.md's frontmatter must also declare README.md, because this repository's README is generated from skill frontmatter and a slice that changes one without the other lands a tree whose generator gate fails. A slice whose description confines its SKILL.md edits to the body leaves README unchanged and need not declare it — the driver no longer refuses that declaration, and a slice that regenerates README after all is parked as an edit outside its declared files. When the description does not say which part it edits, declare README.md. (c) Two or more implement slices declare their residual share. When the section holds two or more blocks whose **스킬** is implement and the document has a ## 구현 시 검증 항목 section, each such block carries **잔여 항목** naming the items it owns, or 없음 when it owns none; without it the driver reads that slice's share as empty and never asks its implement stage for those items' result lines. (d) A new-grammar block gives a reason per kind. A block carrying a **머지 순서** line carries **선행 사유** when its 선행 is not 없음 and **머지 순서 사유** when its 머지 순서 is not 없음; the gate and the driver park a slice that lacks one as a missing required field. (e) Closure disjointness. For each slice S, its declared files are prefix-disjoint from every slice in M(S) \ P(S) as defined under Blocks and fields, with no exemption for README.md, plugin.json or CHANGELOG.md; an overlap is repaired by turning the edge that brings the other slice into M(S) \ P(S) into a 선행, or by moving the file, never by dropping it from the declaration. (f) Slice size. For each block, count its declared files: one element is one file; an element ending in / counts as the number of files git ls-files -- <element> prints in the design-time working tree of the repository the block's **레포** names, and at least 1 (1 when the design stage cannot read that repository's working tree — no checkout on this machine, or none visible where the design runs); README.md, plugin.json, CHANGELOG.md and test files count like any other file. A block over the baseline of 20 declared files is split into smaller blocks or carries **크기 사유**. (g) One permission profile per slice. This rule applies only to blocks whose **스킬** is implement. A work's permission profile is the --reach token the act would honestly carry when declared to the gate, and the designer judges it — the gate derives a token only from an argv being run, never from a slice declaration — and when no single token can be decided at design time it is 미상. The base profile, which every implement slice holds, is the in-worktree reads, writes, commits and tests the gate asks no reach declaration for (derived -), 런로컬 (an act that reaches only this run's directory or the stage's prototype namespace) and 협업 (the push, PR and merge the cutpoint allows); 기기전역, dev, prod, 배포트리거 and 미상 are each a separate elevated profile. A remote-capable tool (docker, playwright, psql and the like) is judged by the token its gate declaration would honestly carry even when it serves a local test, and a command that reaches a checkout outside the worktree (git pull and the like) never carries 런로컬. A block mixes when its implementation work needs the base profile together with an elevated one, or two or more elevated profiles; a declared **적용 명령** counts too — its profile is that command's reach judged the same way, it counts whatever **적용 주체** says, and an elevated one mixes with the block's base profile. Mixing is counted by elevated act unit: one elevated act (an apply command, a machine-global install, an external service write), the declared files that exist only for that act (the script it runs, a deploy config or install list only it reads) and those files' test files; the artifacts the act ships or deploys (source, migrations, screens) and any file other work (build, local run, tests) also uses are outside the unit. A block whose declared files all belong to one unit and that has no elevated act outside it does not mix, whatever the kind of act and whatever **적용 주체** says. A mixed block either splits the unit off into a block of its own or carries **권한 혼합 사유**. The split's 선행 follows the real order: the unit of an apply command names the implementation block it deploys as 선행, and a block that uses the act's result names the unit block as 선행. When several blocks declare the same **적용 명령**, each is a separate elevated act that runs after its own block's merge, so split each block's unit off on its own and never gather the unit blocks into one; a unit file the original block edited moves with that edit into the unit block split from it, and two unit blocks that declare the same unit file are joined by the 선행 repair of (e). A unit block takes no common file (README.md, plugin.json, CHANGELOG.md and the like): when the unit block's work must edit one, when the elevated work must sit in the same commit as work outside the unit, or when the act has no declared file of its own (an apply command such as git pull), do not split, and write **권한 혼합 사유** on the original block. Repair the declaration in place (this is still a document edit, so it happens before the freeze, not after). If a failure cannot be repaired without a decision the authors did not make — the slice's file set is genuinely unknown — AskUserQuestion rather than guess: a wrong declaration is worse than a missing section, because the driver trusts it.

    • The disposition of the two split rules. A reason names the one coupling a split would break, and a sentence that names none is not a reason; when the person gave the 슬라이스 수 answer, nothing is split and the reason field quotes that answer instead.
    • Neither split rule asks or stops. A split the designer can decide is made, and otherwise the reason field is written. A split is a new declaration, so run (a) through (g) again on every block it made and bring the section's **슬라이스 수** checksum back into line.
    • Finish a split in this order. The original block's id is kept by one of the new blocks and every other new block takes a new id. A block whose 선행 named the original id is changed to name the block that holds the work it waited for. The new blocks stand where the original block stood, never appended at the section's end: each one after every block its 선행 or 머지 순서 names, and before every block that now names it in either list — the driver runs the blocks once in section order and parks a block whose 선행 has not finished, and a 머지 순서 token naming a block declared later is a defect of the slice that carries it. The original block's **잔여 항목** and **적용 명령** move to the block that holds the work they cover, and **적용 주체** and **폭발 반경** move with **적용 명령**. The original block's edit description is divided so that each new block describes only the files it declares — an edit description left behind for a moved file fails that block's (a). Files the new blocks declare together (README.md, plugin.json, CHANGELOG.md) follow the repair of (e), a 선행 edge; a unit block split off by (g) takes none of them. Each new block writes the required fields (**스킬**, **레포**, **선언 파일**, **선행**, **절단점**), and when the original block carried a **머지 순서** line every new block writes one too, because without it the block reads as old grammar and loses its reason obligation; the block that received **적용 명령** inherits the original **절단점**, each other block takes the cutpoint its own work calls for, and the remaining fields (**리뷰 정책**, **라벨 인정**, **화면** and the like) are written on each new block to fit its work. Another block's **머지 순서** or **폭발 반경** that names the original id is changed by the same standard as 선행 — a blast radius parks by exact string and never checks that the id exists, so a radius left on the block the apply moved away from parks nothing. A new-grammar block that gains a 선행 from the split writes **선행 사유** ((d)). When the split declaration cannot be made to pass (a) through (e) without a decision, the split is not made and the original block carries the reason field instead, which is why neither split rule reaches the decision this item's last sentence asks for.
    • The item's last sentence, "If a failure cannot be repaired without a decision the authors did not make …", covers rules (a) through (e) only.
  9. FREEZE. Emit in Korean: "설계 문서를 동결했습니다. 이후 이 세션에서는 문서를 수정하지 않습니다." When the document has a ## 구현 슬라이싱 section, add one line to that notice from bash ${CLAUDE_SKILL_DIR}/../../orchestrator/enforcement-surface-screen.sh -- <every slice's declared files>, which prints <path><TAB><class> for each path an unattended run's hook refuses: 강제 표면: 슬라이스 <id> — <경로> (<분류>, <좌석 적용 가능|사람 몫>), …, slices separated by ; — 규칙카탈로그 and 지침파일 read 좌석 적용 가능, the other two 사람 몫 — or 강제 표면: 없음, or 강제 표면: 판정불가 when the screen exits 2. It is a notice: such a path stays declared, and the person learns now that a run implementing it will stop on that edit. From this point design performs no further document edits. This step is terminal — there is no path back to Step 5 or Step 6. (CFI-3c) At the freeze the seat deletes the state root's control plane — leg.json, park.md, presentation.md, coherence.md, leg.*.out, leg.*.err — and keeps $STATE/witness/: the corpus is the only durable copy of the round products, and deleting the whole root would destroy it at the moment of the freeze. A workflow that ends in an abort keeps everything.

  10. Hand off — and the handoff has TWO destinations, so read which one you are in first.

    If this invocation was asked for by an autopilot kickoff, the destination is that kickoff, not the audit. Say so: the document is frozen, here is its path and its whole-file sha256, go back and resume the kickoff. The audit is already a stage in the run's approved step graph, so naming it here sends the person to run by hand a thing the run is about to dispatch — and if they follow it instead of returning, the run is never created at all. That failure leaves nothing behind: no manifest, no grant, no ledger, no report, so a kickoff abandoned at this exact line is indistinguishable from one that was never started. The handoff lands the moment the freeze happens, which is the moment the kickoff is waiting to be resumed, so this is the most conspicuous instruction at precisely the wrong time.

    Otherwise — tell the user in Korean that the next step is /cc-cmds:design-audit docs/{topic-slug}.md, the independent Class S audit over the now-frozen document. State its shape in one line so the freeze reads as purposeful rather than bureaucratic: independent readers · 1 round · non-recursive · one coherence reconciliation, then stop. It is a fixed budget with a mandatory residual disclosure, not a multi-round loop with a cap — the reader count lives in that skill's own control-flow invariants and is not restated here.

Constraints

  • NO code modifications. Design discussion only.

  • Inter-agent communication must be in English.

  • Team members are nameless Agent sub-agents: team members ARE Agent sub-agents — nameless background tasks (subagent_type: "claude", run_in_background: true, no name), one dispatch per (role, round/phase) key and self-terminating on return. What the design discussion requires is NOT a special team primitive but cross-review and convergence through the witnesses on disk (debate, challenge, cross-validation across rounds, lead-mediated per _common/agent-team-protocol.md). Each new round or phase is a fresh dispatch of the role that reads its own past witnesses and its peers' witnesses by path; a re-request inside one key resumes the same agentId.

  • Permitted team resumes (same key only). A resume — SendMessage to a member's agentId — is permitted only inside the key that member was dispatched for: a send-back P-rev<k>, Case 1, Case 3, the re-assignment for a missing peer-read: receipt, and the witness nudge. A new round/phase key is always a fresh dispatch, never a resume. Step 6's ban targets conscripting a team convened for a different purpose. It does NOT target asking a team about the coherence of its own output — that follows from Class C defects (the context-dependent kind, whose evidence never reached the artifact) having non-zero sensitivity only in the authoring team. Exactly two re-convenings of a prior team's roles are permitted in this skill, each a fresh dispatch into that team's rows, and this list is closed: no other re-convening of a prior team is allowed, for any reason, anywhere.

    1. Step 3 → Step 4 synthesis fidelity pass — the Step 3 roles dispatched afresh to check draft↔discussion fidelity. Phase token fidelity. Mandated by Step 4's "Subject & input" — executed inside the leg (design-discuss-unattended), which dispatches into the Step 3 team's rows and owns their same-key resumes.
    2. Step 3 → Step 7 Class C coherence pass — the Step 3 roles dispatched afresh at a new epoch inside the resumed leg: the seat resumes the leg session (claude -r <session_id>, same flags and redirections) with the coherence message, and the leg dispatches its own team's roles. Phase token coherence. Mandated by Step 7. Fallback (only on one of Step 7's two triggers): the Step 3 roles are dispatched fresh at a new epoch by the seat from the durable witness corpus + the brief + the final document by path — the same pass with a different input, not a third re-convening.

    Everything else spawns FRESH as a new team: the Step 5 walkthrough team, every Step 6 refinement team, and any re-composition. A walkthrough-spawned team is never extended into a refinement team or the reverse. A Step 5 or Step 6 fresh team is never re-convened for the Step 7 coherence pass — the Class C channel is the authoring team specifically, and a fresh team's sensitivity to it is structurally zero, so re-convening one would produce a confident answer from the one vantage that cannot see the defect. Every permitted re-convening of a team from an earlier generation carries the protocol's epoch re-stamp duty (_common/agent-team-protocol.md, Spawn).

  • Deferred tool loading: Before using AskUserQuestion, SendMessage, or TaskStop, you MUST first load them via ToolSearch. Run ToolSearch with query "select:AskUserQuestion,mcp__cc-cmds__question_form", "select:SendMessage", and "select:TaskStop" to load each tool. These are deferred tools and will NOT work unless loaded first. (Agent is a built-in primary tool — do NOT load it via ToolSearch. SendMessage to an agentId resumes a running member; TaskStop aborts one.) AskUserQuestion MUST be loaded before Step 1 (user interview). Before calling AskUserQuestion, Read ${CLAUDE_SKILL_DIR}/../_common/askuserquestion.md and apply its hard constraints to every AskUserQuestion call in this skill.

Observation & verification carve-out (running + experimenting ≠ modifying)

The "NO code modifications" rule above and in Step 3 is absolute and unweakened — but "modification" has a precise definition that makes both reproduction (running the unmodified app/test suite) and in-session verification (out-of-tree experiments and isolated-worktree mini-implementations) fully compatible with it. This carve-out is a definition, not an exception: the two literal "NO code modifications" strings stay literally true everywhere. The full operating mechanics live in ${CLAUDE_SKILL_DIR}/../_common/verification.md §6 (Read it); the compression-critical core is restated here.

  • What "modification" means: a change that persists in the session's main working tree. (In git vocabulary an experiment worktree is also a "working tree", so the scope is the main tree specifically.) Running the app/test suite as-is, an out-of-tree driver, or an isolated-worktree experiment that is torn down — none persists a change to the main tree, so none is a modification.
  • FORBIDDEN: editing any tracked source file in the main working tree — even transiently, even "I'll revert it after." There is no in-tree print-logging exception.
  • Two-command boundary gate (scope is per-surface): at every team-discussion boundary run the gate exactly as _common/verification.md §6 defines it — assertion 1 (main tree git status --porcelain == the pre-workflow baseline, within the caller's declared measurement surface — design declares none, and §6.0's default for a caller that declares nothing is the whole tree, so here assertion 1 is whole-tree equality) and the three scoped worktree assertions 2a/2b/2c. The worktree half is a separate gate because porcelain does not see records inside .git/worktrees/ (the F1 blind spot), and it is scoped rather than whole-output because git worktree list is repository-global — a sibling worktree's commit is not a mismatch. Step 4's design-document save (docs/{slug}.md) and the interview brief docs/design-brief/{slug}.md written at leg dispatch are the skill's two sanctioned tracked-file writes and are NOT subject to this gate — the brief is exempted by path filter, never by staging or ignoring it.

Surface 1 — main working tree (reproduction + categories a/b/c/d): today's rules, unweakened.

  • ALLOWED: executing the unmodified app, running the existing test suite, attaching a debugger, raising verbosity via existing flags/log levels, importing project modules from an out-of-tree driver, and (for category (c)) WebFetch / WebSearch / external CLI. All artifacts, drivers, and logging route to a /tmp sink or existing verbosity/CLI flags — strictly outside the working tree.
  • Cleanup boundary — "before findings leave their producer": whoever produces a finding or a verification verdict (the lead, the reproduction agent, or the verification agent) must, before it leaves in any form (whichever comes first: a broadcast, a verdict-citing SendMessage, a task return, or a doc Edit), revert all instrumentation, delete every out-of-tree artifact, and verify the two-command gate == baseline. There is no window in which the tree is dirty while a finding/verdict is visible to another agent. The lead is the backstop: re-verify before the Step 4 save (the pre-save sweep).
  • Environment vs. working tree (lockfile checklist): the gate is scoped to tracked source only. Verification/reproduction may install dependencies and produce build output: (1) gitignored build output (node_modules/dist/.next/build) is out of scope — never appears in porcelain; (2) an install that rewrites a tracked lockfile (package-lock.json/poetry.lock) or tracked codegen path must NOT persist — use a non-rewrite form (npm ci, npm install --no-save, venv) or revert before the boundary; (3) the pass/fail gate at every boundary is the two-command gate == baseline.

Surface 2 — isolated worktree (category (e) only): for a mini-implementation whose observation unavoidably requires changing tracked content and repo-faithful context (the α∧β condition in _common/verification.md). Compression-critical locks (full mechanics in _common/verification.md §6.2):

  • Create with WT=$(mktemp -d "${TMPDIR:-/tmp}/cc-design-exp-<owner-token>-<slug>.XXXXXX") then git worktree add --detach "$WT" HEAD. mktemp + --detach are MUST, and the owner token is the creating member's phase witnessNonce from its ledger row — it is what scopes assertion 2c to this team rather than to every caller of the mechanism on the machine. Append the created path, that token and a timestamp to the team's creation record under the member's scratchDir, in the same Bash call as the git worktree add; assertion 2a reads that record. EnterWorktree is forbidden (its only-if-unchanged auto-cleanup guarantees a leak for a changed worktree); the Agent-tool isolation form is forbidden.

  • In-worktree FORBIDDEN: no commit / branch / push / tag / git config write / hook install / gc·maintenance / stash (refs/stash is a shared namespace — an in-worktree stash survives worktree removal in the main repo's git stash list, a porcelain-invisible leak).

  • Lifetime: from claim pre-registration to that claim's verdict broadcast; no persistence across re-convergence (regenerate from the recipe — deterministic since the main tree is frozen). One experiment = one worktree, never shared across agents.

  • Final-run rule: a verdict is backed only when the recorded recipe's patch, applied on a clean reset (cd "$WT" && git checkout -- . && git clean -fd — the single inseparable line; run from the wrong cwd it destroys the user's main-tree untracked files), is observed to match the recorded 관측 결과.

  • Cleanup: git worktree remove --force "$WT" + git worktree prune + the record check (every path the creation record claims is absent from git worktree list --porcelain, and no entry carries this team's owner token), before the verdict ships. Lead backstop: the pre-save sweep and the Step 6 entry state-check add the two-command gate.

  • CFI impact: none — quality tier (a missed application is quality degradation, not a mis-transition). Nothing is added above the ## Control-Flow Invariants heading.

Task: $ARGUMENTS

04 同仓库更多 Skills