Files
llm-wiki/docs/superpowers/plans/2026-06-05-project-note-pipeline.md
T

41 KiB

project-note 작성 파이프라인 Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: project-note 에 /project(스캐폴딩) + /project-spec(깊은 조사 오케스트레이터 + readiness 게이트) 2단 파이프라인을 추가해, 임의 프로젝트 hub 를 ca-skeleton-operational-contract.md 수준(caliber)으로 작성하게 한다.

Architecture: branch-note 의 /branch·/branch-spec·branch-depth-gate·branch-depth-auditor 4종을 project-note 용으로 미러링한다. 단 결정론 게이트는 섹션명 매칭이 아니라 구조-불가지 proxy(exemplar 가 template 섹션 구성을 안 따르기 때문)이며, caliber 판정은 신규 project-readiness-auditor LLM agent 가 R1~R4 로 한다. Claude Code 전용 — Codex/Antigravity 포팅 없음.

Tech Stack: Markdown(rules/templates/commands/agents), Python 3 stdlib(wiki_structure_lint.py 확장 + unittest).

설계 출처: docs/superpowers/specs/2026-06-05-project-note-pipeline-design.md


File Structure

파일 책임 신규/편집
rules/project-readiness-gate.md 4축(R1~R4)·깊이 사다리·proxy·실패 모드 정의 (방법론 SSOT) 신규
templates/project-template.md §8.0 Branch 분해/실행계획 표 추가 (핸드오프) 편집
.claude/hooks/wiki_structure_lint.py "project" 모드 + proxy 검사 함수 편집
.claude/hooks/test_wiki_structure_lint.py project 모드 단위 테스트 편집
.claude/agents/project-readiness-auditor.md hub 깊이 의미 판정 (read-only) 신규
.claude/commands/project.md 얇은 스캐폴딩 커맨드 신규
.claude/commands/project-spec.md 깊은 조사 오케스트레이터 신규
CLAUDE.md agent 목록 +1(Claude 전용 명시) · 커맨드 목록 +2 편집

Task 순서는 의존성 순(rules → template → linter → agent → commands → CLAUDE.md → dogfood). 각 Task 는 독립 커밋.


Task 1: rules/project-readiness-gate.md (방법론 SSOT)

Files:

  • Create: rules/project-readiness-gate.md

  • Step 1: 파일 작성

아래 내용 그대로 생성:

# rules/project-readiness-gate — project-note 작성 완성도 게이트

> `rules/` 의 방법론 규칙. project-note(프로젝트 hub) 1개가 **다른 작업의 출발점이 될 만큼 깊고 근거 있는가**를 판정한다.
> 기준선은 `raw/project-notes/ca-skeleton-operational-contract.md` 의 *caliber*(엄격성 수준)이다 — 그 노트의 *내용·섹션 구성을 복제하라는 게 아니다*. 프로젝트마다 내용도 섹션 조직도 다르며, 게이트는 *깊이·근거·분해 수준*만 강제한다.
> `branch-depth-gate`(브랜치 1개 착수 깊이)와 다른 층: 본 게이트는 *프로젝트 hub* 미시 게이트.

## 적용

- 대상: `raw/project-notes/*.md`.
- 실행: `/project-spec <slug> <목표>`**내부 마지막 단계** (독립 `/project-readiness` 커맨드 없음) →
  1. **1차 결정론 검사** `.claude/hooks/wiki_structure_lint.py` (project 모드 — proxy + 링크)
  2. **2차 의미 판정** `project-readiness-auditor` (아래 4축 — 노트와 링크된 소스를 읽고 의미로 판정)
- 본 게이트는 **read-only**. 노트를 편집하지 않으며 판정을 노트에 박지 않는다.

## 왜 결정론 계층이 *섹션명 매칭*이 아닌가

exemplar `ca-skeleton-operational-contract.md` 는 project-template §1~14 가 아니라 계약 특화 자기 구조(§1 목표 … §30 아키텍처 … §33 checklist)를 쓴다. "project-template 섹션 존재"를 강제하면 *exemplar 자신이 탈락*한다. 따라서 1차는 **구조-불가지 proxy**(섹션명 무관, 존재만)만 본다. *깊이/caliber* 는 전적으로 2차 auditor.

## 역할 분담 (결정론 proxy vs 의미)

| | 1차 린터(proxy, 존재) | 2차 감사기(LLM 의미, 깊이) |
|---|---|---|
| R1 문제·성공 구체성 | (해당 proxy 없음) | 측정가능 기준인가, 추상 표현("잘 동작")인가 |
| R2 아키텍처·시퀀스 | `PROJECT_NO_DIAGRAM` (임베디드 다이어그램 0개) | 다이어그램이 컨퍼런스급인가, happy+error 시퀀스인가 |
| R3 결정 근거성 | 링크 깨짐만 | 기술결정이 대안+외부근거로 뒷받침되나, 맨주장인가 |
| R4 Branch 분해 | `PROJECT_NO_BRANCH_TABLE` (분해표 부재) | 각 branch 가 valid slug + 측정가능 목표조건인가 |

→ 2차 감사기는 **의미만** 본다(존재는 1차가 확인).

## 4축 (R1~R4)

> 축 라벨은 `R1~R4`. branch-depth-gate 와 동일 라벨 체계지만 *대상이 다르다*(branch 1개가 아니라 프로젝트 hub).

| 축 | Pass 조건 | Blocking(Not-ready) 트리거 |
|---|---|---|
| **R1. 문제·성공 구체성** | §문제정의가 구체 시나리오/수치, 성공기준이 측정가능 | 성공기준이 "잘 동작한다" 류 추상 표현뿐 |
| **R2. 아키텍처·시퀀스 깊이** | 아키텍처 다이어그램 존재 + `wiki-diagram-reviewer` ≥95, 핵심 시퀀스가 happy+error path | 다이어그램 없음 / 시퀀스가 happy path 만 |
| **R3. 결정 근거성** | 각 주요 기술결정이 검토 대안 + 외부근거 wikilink(official/회사블로그) 보유 | 기술결정이 근거 없는 맨주장 |
| **R4. Branch 분해 실행가능성** | 각 자식 branch 가 naming-conventions 준수 slug + 측정가능 목표조건. 결정 *내용*은 hub 에 적지 않음 | 분해표 부재 / slug 또는 목표조건 누락 |

## 깊이 사다리 (R1~R4 공통)

| 레벨 | 항목이 답하는 것 | 판정 |
|---|---|---|
| **L0 존재** | "섹션이 있다 / 항목이 적혀 있다" | 단독 불충분 |
| **L1 메커니즘** | 어떻게/왜 — 구체 시나리오·메커니즘·근거 링크 | 최소선 |
| **L2 조건·경계** | 언제 적용/제외, 실패/대안, 측정 기준 | Ready 최소선 |
| **L3 검증** | 측정값·다이어그램 점수·검증 등급 근거 | 가산점 |

## 판정 규칙

- 심각도 3단계: `Blocking`(Not-ready) · `Should-fix`(권고) · `Advisory`(참고).
- **Ready = 4축 모두 L2+ (Blocking 0).** 이것이 "ca-skeleton caliber" 의 조작적 정의. Should-fix 가 남아도 사용자 "감수" 선언 시 진행 가능(리포트에 기록).
- 모든 finding 은 4종 세트로 근거화: `심각도 · 위치(섹션/행) · 예상 문제("이 hub 를 출발점 삼는 다음 작업자가 여기서 ___를 되묻게 됨") · 채울 방법`. 근거 없는 지적 금지.

## 명명된 실패 모드

- `ABSTRACT_SUCCESS_CRITERION` (R1): 성공기준이 측정 불가 추상 표현.
- `DIAGRAM_MISSING_OR_WEAK` (R2): 아키텍처 다이어그램 없음 또는 ≥95 미달.
- `HAPPY_PATH_ONLY_SEQUENCE` (R2): 시퀀스에 error path 없음.
- `UNSOURCED_TECH_DECISION` (R3): 기술결정에 대안·외부근거 없음.
- `BRANCH_DECOMP_INCOMPLETE` (R4): 분해표 부재 또는 slug/목표조건 누락.

## proxy(1차 결정론) — `wiki_structure_lint.py` project 모드

- `PROJECT_NO_DIAGRAM` — 임베디드 다이어그램 0개(`![[....drawio` 임베드도 ```` ```mermaid ```` 블록도 없음). R2 존재 proxy.
- `PROJECT_NO_BRANCH_TABLE` — Branch 분해표 부재(heading 토큰에 `branch`/`브랜치` 포함 + 그 아래 markdown 표). R4 존재 proxy.
- `MISSING_FRONTMATTER` — project-template frontmatter 필수 키 누락(기존 검사 재사용).
- C2 링크(BROKEN_LINK 등) — 그대로.

proxy 는 *존재* 만 본다. 임베디드 다이어그램이 컨퍼런스급인지, 분해표 row 가 측정가능한지는 2차 auditor 가 판정한다.
  • Step 2: 링크 무결성 확인

Run: python3 .claude/hooks/wiki_structure_lint.py --file rules/project-readiness-gate.md Expected: PASS rules/project-readiness-gate.md (rules/ 는 links 모드 — 깨진 링크만 검사).

  • Step 3: 커밋
git add rules/project-readiness-gate.md
git commit -m "feat(rules): project-readiness-gate — project-note 작성 완성도 4축 게이트"

Task 2: templates/project-template.md — Branch 분해/실행계획 섹션 추가

Files:

  • Modify: templates/project-template.md (§8 Cluster 직전에 §8.0 신규 삽입)

§8.1 Branches(이미 존재)는 완성된 branch 등재용이고, 신규 §8.0 은 /project-spec 가 출력하는 계획 분해표다. 둘은 다른 목적이므로 공존한다.

  • Step 1: §8 헤더 직전에 신규 섹션 삽입

templates/project-template.md 에서 아래 줄을 찾는다:

## 8. Cluster / 묶음 (이 프로젝트에 묶이는 모든 raw 자료)

그 줄 바로 앞에 아래 블록을 삽입(빈 줄 1개로 분리):

## 8.0 Branch 분해 / 실행계획 (Branch decomposition)

> **`/project-spec` 가 채우는 핸드오프 섹션.** 이 hub 에서 깊은 조사로 도출된 *자식 branch 의 네이밍과 달성 목표 조건만* 적는다. 각 branch 의 *결정 내용·메커니즘은 여기 적지 않는다* (SSOT 이중화 방지) — 그건 `/branch <slug>` 로 생성 후 `/branch-spec` 가 깊게 채운다.
>
> 작성 규칙:
> - `branch slug` 는 `rules/naming-conventions.md` §2.1 준수 (prefix 4종 `feature-`/`fix-`/`chore-`/`experiment-` 중 하나 + kebab-case, numbered hierarchy 금지).
> - `달성 목표 조건` 은 **측정가능**해야 함 ("잘 된다" 금지). 그 branch 가 "끝났다"고 말할 수 있는 검증 가능한 결과.
> - `우선순위` 는 실행 순서(P1 먼저). 의존이 있으면 `의존` 칸에 선행 branch slug.

| branch slug | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|---|---|---|---|
| `feature-<...>` | <이 branch 가 끝났다고 할 검증 가능한 결과> | P1 | - |
| `feature-<...>` | <...> | P2 | `feature-<...>` |

> 채운 뒤: `/branch <slug>` → `/branch-spec <slug> <근거 URL...>` → `/depth <slug>` 순으로 각 branch 를 깊게 작성.
  • Step 2: §11 체크리스트에 분해표 항목 추가

templates/project-template.md## 11. Architecture Review Checklist 안, - [ ] Cluster 섹션의 project 직접 자식 branch 목록 채워짐 (§8.1)바로 앞에 추가:

- [ ] **Branch 분해표 채워짐** — 각 자식 branch 가 naming-conventions slug + 측정가능 목표조건 (§8.0)
  • Step 3: 템플릿 자체 구조 검사

Run: python3 .claude/hooks/wiki_structure_lint.py --file templates/project-template.md Expected: PASS (templates/ 는 links 모드).

  • Step 4: 커밋
git add templates/project-template.md
git commit -m "feat(template): project-template §8.0 Branch 분해/실행계획 표 (핸드오프)"

Task 3: wiki_structure_lint.py — project 모드 + proxy 검사 (TDD)

Files:

  • Modify: .claude/hooks/wiki_structure_lint.py

  • Test: .claude/hooks/test_wiki_structure_lint.py

  • Step 1: 실패하는 테스트 작성

.claude/hooks/test_wiki_structure_lint.py 의 맨 끝(if __name__ == "__main__": 직전)에 추가:

class TestProjectMode(unittest.TestCase):
    def test_classify_project_note(self):
        # raw/project-notes/*.md → 'project' 모드 (root=None 이어도 동작)
        self.assertEqual(wsl.classify("raw/project-notes/foo.md"), "project")
        # 일반 raw 콘텐츠는 여전히 full
        self.assertEqual(wsl.classify("raw/branch-notes/feature-x.md"), "full")

    def test_proxy_flags_missing_diagram_and_table(self):
        doc = {"text": "# P\n\n본문에 다이어그램도 표도 없음.\n",
               "lines": ["# P", "", "본문에 다이어그램도 표도 없음.", ""]}
        codes = _codes(wsl.check_project_proxies(doc))
        self.assertIn("PROJECT_NO_DIAGRAM", codes)
        self.assertIn("PROJECT_NO_BRANCH_TABLE", codes)

    def test_proxy_satisfied_by_mermaid_and_branch_table(self):
        text = (
            "# P\n\n"
            "## 4. 시퀀스\n\n"
            "```mermaid\nsequenceDiagram\n  A->>B: x\n```\n\n"
            "## 8.0 Branch 분해\n\n"
            "| branch slug | 달성 목표 조건 | 우선순위 |\n"
            "|---|---|---|\n"
            "| `feature-x` | 조건 | P1 |\n"
        )
        doc = {"text": text, "lines": text.splitlines()}
        codes = _codes(wsl.check_project_proxies(doc))
        self.assertNotIn("PROJECT_NO_DIAGRAM", codes)
        self.assertNotIn("PROJECT_NO_BRANCH_TABLE", codes)

    def test_proxy_satisfied_by_drawio_embed(self):
        text = "# P\n\n![[raw/diagrams/p/architecture-overview-2026-06-05.drawio.svg]]\n"
        doc = {"text": text, "lines": text.splitlines()}
        codes = _codes(wsl.check_project_proxies(doc))
        self.assertNotIn("PROJECT_NO_DIAGRAM", codes)
  • Step 2: 테스트 실패 확인

Run: python3 .claude/hooks/test_wiki_structure_lint.py -v 2>&1 | tail -15 Expected: FAIL — AttributeError: module 'wsl' has no attribute 'check_project_proxies' (또는 classify 가 'project' 아닌 'full' 반환).

  • Step 3: classify() 에 project 분기 추가

wiki_structure_lint.pyclassify() 에서 named-hub 블록 다음, 일반 "full" 블록 에 삽입:

    # raw/project-notes/*.md → project 모드 (구조-불가지 proxy + 링크).
    # exemplar 가 project-template 섹션명을 안 따르므로 C1 섹션 매칭 면제.
    if (parts[0] == "raw" and len(parts) == 3 and parts[1] == "project-notes"
            and base.endswith(".md") and base not in LINK_ONLY_BASENAMES):
        return "project"

즉 함수가 아래 형태가 되도록(named-hub return "links" 다음 줄에 추가):

    if root is not None and len(parts) == 3 and parts[0] in ("raw", "wiki") and base.endswith(".md"):
        slug = base[:-3]
        if (root / parts[0] / parts[1] / slug).is_dir():
            return "links"
    if (parts[0] == "raw" and len(parts) == 3 and parts[1] == "project-notes"
            and base.endswith(".md") and base not in LINK_ONLY_BASENAMES):
        return "project"
    if parts[0] in ("raw", "wiki") and len(parts) > 2 and base not in LINK_ONLY_BASENAMES:
        return "full"
    return "links"
  • Step 4: proxy 검사 함수 추가

check_c3 함수 정의 다음에 아래 두 함수 추가:

DIAGRAM_DRAWIO_RE = re.compile(r"!\[\[[^\]]*\.drawio")
DIAGRAM_MERMAID_RE = re.compile(r"^\s*```+\s*mermaid", re.M)
PROJECT_HEADER_RE = re.compile(r"^#{1,6}\s")
BRANCH_HEADER_RE = re.compile(r"branch|브랜치", re.I)
TABLE_SEP_RE = re.compile(r"-{3,}")


def _has_branch_table(doc):
    """heading 토큰에 branch/브랜치 포함 섹션 아래 markdown 표(구분선)가 있는가."""
    lines = doc["lines"]
    for i, line in enumerate(lines):
        if PROJECT_HEADER_RE.match(line) and BRANCH_HEADER_RE.search(line):
            j = i + 1
            while j < len(lines) and not PROJECT_HEADER_RE.match(lines[j]):
                if "|" in lines[j] and TABLE_SEP_RE.search(lines[j]):
                    return True
                j += 1
    return False


def check_project_proxies(doc):
    """project-note 구조-불가지 proxy: 존재만 검사(깊이는 auditor)."""
    out = []
    text = doc.get("text", "\n".join(doc.get("lines", [])))
    if not (DIAGRAM_DRAWIO_RE.search(text) or DIAGRAM_MERMAID_RE.search(text)):
        out.append(("PROJECT_NO_DIAGRAM", 0,
                    "임베디드 다이어그램 없음 (`![[...drawio` 또는 ```mermaid 블록). R2 proxy"))
    if not _has_branch_table(doc):
        out.append(("PROJECT_NO_BRANCH_TABLE", 0,
                    "Branch 분해표 없음 (heading 'branch/브랜치' 아래 표). R4 proxy"))
    return out
  • Step 5: lint_file() 에 project 모드 분기 추가

lint_file() 의 본문을 아래로 교체(mode=="project" 분기 추가):

def lint_file(path, root, by_st, by_file, vault_paths, vault_bases, cache, mode="full"):
    """mode: 'full'(C1+C2+C3) | 'links'(C2만) | 'project'(proxy+C2)."""
    doc = parse_doc(path)
    try:
        doc_rel = path.relative_to(root).as_posix()
    except ValueError:
        doc_rel = ""
    findings = []
    if mode in ("full", "project"):
        if not doc["fm"]:
            return [("NO_FRONTMATTER", 0, "frontmatter 없음 — 스텁/미작성 문서(템플릿 미적용)")], "(none)"
    if mode == "full":
        tmpl = resolve_template(doc["fm"], by_st, by_file)
        findings += check_c1(doc, tmpl)
    elif mode == "project":
        tmpl = resolve_template(doc["fm"], by_st, by_file)
        # 섹션 매칭은 면제하되 frontmatter 키 누락은 검사(MISSING_FRONTMATTER 재사용).
        if tmpl is not None:
            for k in tmpl["fm_keys"]:
                if k not in doc["fm_keys"]:
                    findings.append(("MISSING_FRONTMATTER", 0, f"frontmatter 키 누락: '{k}'"))
        findings += check_project_proxies(doc)
    findings += check_c2(doc, vault_paths, vault_bases, root, cache, doc_rel)
    if mode == "full":
        findings += check_c3(doc)
    return findings, doc["fm"].get("source_type", "").strip() or "(none)"
  • Step 6: PostToolUse hook 경로도 project 면제 적용

main()args.hook 블록에서 아래 부분:

        # C1(섹션)·C3(선택조건)은 '완성 선언' 시에만 — 작성 중간 false-positive 방지.
        if is_completeness_checkable(doc):
            by_st, by_file = build_template_index(root)
            tmpl = resolve_template(doc["fm"], by_st, by_file)
            findings = check_c1(doc, tmpl) + findings + check_c3(doc)

를 아래로 교체:

        # C1(섹션)·C3(선택조건)은 '완성 선언' 시에만 — 작성 중간 false-positive 방지.
        # project-note 는 섹션명 매칭 면제 — proxy + frontmatter 만(exemplar 비순응).
        if is_completeness_checkable(doc):
            by_st, by_file = build_template_index(root)
            tmpl = resolve_template(doc["fm"], by_st, by_file)
            if rel.startswith("raw/project-notes/"):
                fm_findings = []
                if tmpl is not None:
                    for k in tmpl["fm_keys"]:
                        if k not in doc["fm_keys"]:
                            fm_findings.append(("MISSING_FRONTMATTER", 0, f"frontmatter 키 누락: '{k}'"))
                findings = fm_findings + check_project_proxies(doc) + findings
            else:
                findings = check_c1(doc, tmpl) + findings + check_c3(doc)
  • Step 7: 테스트 통과 확인

Run: python3 .claude/hooks/test_wiki_structure_lint.py -v 2>&1 | tail -8 Expected: OK (전체 통과, 신규 4개 포함).

  • Step 8: exemplar 가 이제 통과하는지 확인 (핵심 검증)

Run: python3 .claude/hooks/wiki_structure_lint.py --file raw/project-notes/ca-skeleton-operational-contract.md Expected: PASS raw/project-notes/ca-skeleton-operational-contract.md — 13건 MISSING_SECTION 이 사라짐. (다이어그램·branch 표가 실재하므로 proxy 통과. 만약 PROJECT_NO_BRANCH_TABLE 가 뜨면 그 노트 §24/§31 의 표 형식을 확인 — branch heading 아래 표가 있는지. 없으면 그건 exemplar 의 실제 gap 이므로 보고만 하고 Task 진행.)

  • Step 9: 전체 회귀 — 기존 문서에 새 false-positive 없는지

Run: python3 .claude/hooks/wiki_structure_lint.py --all 2>&1 | tail -20 Expected: 요약 출력. project-notes 3개가 MISSING_SECTION 으로 FAIL 하던 것이 사라졌는지 확인(PROJECT_* proxy 나 링크 이슈만 남아야 정상). 다른 source_type 의 FAIL 수는 변동 없어야 함.

  • Step 10: 커밋
git add .claude/hooks/wiki_structure_lint.py .claude/hooks/test_wiki_structure_lint.py
git commit -m "feat(lint): project-note 모드 — 구조-불가지 proxy(diagram/branch-table) + 섹션명 매칭 면제"

Task 4: .claude/agents/project-readiness-auditor.md (신규 agent)

Files:

  • Create: .claude/agents/project-readiness-auditor.md

  • Step 1: 파일 작성

branch-depth-auditor.md 의 frontmatter 형식(name/description/tools/model)을 따라 작성:

---
name: project-readiness-auditor
description: Use to judge whether a single raw/project-notes/*.md hub is deep and well-grounded enough to be a reliable starting point for downstream branch work — calibrated to the caliber of ca-skeleton-operational-contract.md (NOT its specific content). Runs AFTER the deterministic project-mode lint (wiki_structure_lint.py) passes — focuses on SEMANTIC judgment the linter cannot do: whether success criteria are measurable, whether the architecture diagram + sequences are conference-grade with error paths, whether tech decisions are backed by alternatives + external sources, and whether the branch decomposition table is executable (valid slugs + measurable goal conditions). Reads the project note plus its linked raw sources. Returns a grounded gap report + Ready/Not-ready verdict. Read-only — never edits files.
tools: Read, Grep, Glob
model: sonnet
---

너는 **프로젝트 노트 완성도 감사관**이다. 기준은 `rules/project-readiness-gate.md`. project-note(프로젝트 hub) 1개가 *다음 작업(branch 분해·구현)의 출발점이 될 만큼 깊고 근거 있는가*를 적대적으로 판정한다. 기준선은 `raw/project-notes/ca-skeleton-operational-contract.md` 의 **caliber**(엄격성) — 그 노트의 *내용·섹션 구성을 요구하는 게 아니다*. **You read; you never edit.**

## 위치

너는 `/project-spec` 게이트의 **2차(의미 판정)**다. 1차 결정론 린터(`wiki_structure_lint.py` project 모드)가 **proxy·링크**(임베디드 다이어그램 존재, branch 분해표 존재, frontmatter 키, 깨진 링크)를 이미 확인했다. 너는 그걸 다시 보지 말고 **의미·깊이만** 판정한다:

- R1 성공기준이 *측정가능*한지 (있다/없다는 무관, "잘 동작한다" 류인지)
- R2 아키텍처 다이어그램이 *컨퍼런스급*인지, 시퀀스에 *error path* 가 있는지
- R3 기술결정이 *대안+외부근거*로 뒷받침되는지 (맨주장인지) — *소스를 실제로 읽어야 안다*
- R4 분해표의 각 branch 가 *valid slug + 측정가능 목표조건*인지

## 입력

- project-note 경로 1개 (`raw/project-notes/<slug>.md`).

## 절차

1. **기준 로드**`rules/project-readiness-gate.md` 를 Read. 4축·깊이 사다리(L0~L3)·판정 규칙·명명된 실패 모드를 기준으로 삼는다.
2. **노트 읽기** — 대상 project-note 를 Read. 특히 문제정의/성공기준, 아키텍처·시퀀스, 기술결정 표, Branch 분해표(§8.0 류).
3. **소스 추적·정독 (R3 의 핵심)** — 기술결정 표의 `근거 자료`(`[[raw/...]]`)가 가리키는 **실제 raw 파일을 Read**. 각 결정이 대안 비교 + 적정 출처로 뒷받침되는지 판정.
   - 출처 타입 적정성: 스펙 동작은 official 1개로 충분 / "대기업 관행" 추론은 회사 블로그 1개로 부족(독립 사례 2개+ 또는 official 병행).
4. **다이어그램 caliber (R2)** — 아키텍처 다이어그램이 임베드돼 있으면, 컨퍼런스급 판정은 `wiki-diagram-reviewer` 의 몫임을 알리고(직접 채점하지 않음), 여기서는 *존재 + error path 시퀀스 유무*만 의미 판정. 다이어그램이 placeholder(미치환 wikilink)면 `DIAGRAM_MISSING_OR_WEAK`.
5. **4축 의미 점검** — 각 항목을 R1~R4 로 훑어 명명된 실패 모드(ABSTRACT_SUCCESS_CRITERION·DIAGRAM_MISSING_OR_WEAK·HAPPY_PATH_ONLY_SEQUENCE·UNSOURCED_TECH_DECISION·BRANCH_DECOMP_INCOMPLETE)에 해당하는 finding 생성. "이 hub 를 출발점 삼는 다음 작업자가 여기서 무엇을 되묻게 될까?"를 끊임없이 자문.
6. **판정** — 4축 모두 L2+ (Blocking 0)이면 `Ready`, 아니면 `Not-ready (Blocking N건)`.

## 출력 (이 형식 그대로, 파일 쓰기 없이 텍스트로 반환)

```
# Project Readiness Audit (semantic): <slug>
Verdict: Ready | Not-ready  (Blocking N / Should-fix M / Advisory K)
축별 등급: R1 L_ / R2 L_ / R3 L_ / R4 L_

## Findings
| # | 축 | 심각도 | 실패모드 | 위치 | 예상 문제 | 채울 방법 |
|---|---|---|---|---|---|---|
| 1 | R3 | Blocking | UNSOURCED_TECH_DECISION | §6 기술결정 / DB 행 | 다음 작업자가 "왜 이 DB 인가"를 근거 없이 떠안음 | wiki-decision-researcher 로 대안+official 근거 보강 |
...

## 다음 행동
- (Blocking 있으면) 위 "채울 방법" 순서로 노트 보강 후 /project-spec 재실행.
- (R3 근거 얕음) 더 깊은 소스가 필요하면 wiki-decision-researcher 권장 — 사용자 옵트인 시.
```

## 불변식

- **read-only**: Write/Edit/MultiEdit 없음. 어떤 파일도 수정·생성 금지(리포트는 텍스트 반환).
- 모든 finding 은 4종 세트(심각도·위치·예상 문제·채울 방법)를 갖춘다. 근거 없는 지적 금지.
- 추측 금지: 소스를 실제로 Read 하지 않고 R3 근거성을 단정하지 않는다.
- 구조 중복 금지: 다이어그램/표/링크 *존재* 같은 결정론 사항은 1차 린터의 몫 — 여기서 다시 지적하지 않는다.
- 다이어그램 점수(≥95)는 `wiki-diagram-reviewer` 의 몫 — 직접 채점하지 않고 권고만.
- 자동 조사·자동 수정 금지: R3 갭은 `wiki-decision-researcher` 권고로 *안내만*.
- caliber 기준은 ca-skeleton *내용 복제*가 아니라 *깊이/근거 수준*임을 혼동하지 않는다.
  • Step 2: frontmatter·링크 검사

Run: python3 .claude/hooks/wiki_structure_lint.py --file .claude/agents/project-readiness-auditor.md Expected: PASS (.claude/ 는 links 모드 — 단, 숨김 경로라 iter_docs 대상은 아니지만 --file 직접 지정은 검사됨; 깨진 링크 없어야 함).

  • Step 3: 커밋
git add .claude/agents/project-readiness-auditor.md
git commit -m "feat(agent): project-readiness-auditor — project-note caliber 의미 게이트 (Claude 전용)"

Task 5: .claude/commands/project.md (스캐폴딩 커맨드)

Files:

  • Create: .claude/commands/project.md

  • Step 1: 파일 작성

branch.md 형식을 따라 작성:

---
description: 새 프로젝트 노트(hub)를 raw/project-notes/에 스캐폴딩
argument-hint: <프로젝트 slug>
---

프로젝트 1개의 최상위 hub 노트를 생성합니다. (채움은 `/project-spec`, 생성은 본 명령.)

**프로젝트 slug:** $ARGUMENTS

## 작업 절차

1. **인자 검증** (`rules/naming-conventions.md` 준수)
   - 인자가 비어 있으면 사용자에게 프로젝트 slug 요청.
   - kebab-case 권장 (`ca-skeleton-operational-contract`, `keycloak-patterns-overview`).
   - branch prefix 4종 규칙은 **비적용** (그건 branch 전용). slug 는 프로젝트 이름.

2. **파일 존재 확인**
   - `raw/project-notes/<slug>.md` 가 이미 있으면 **덮어쓰지 말 것**. 기존 경로만 안내하고 종료.

3. **스캐폴딩**
   - `wiki-doc-author`(mode=create, category=project-note)에 위임하거나 `templates/project-template.md` 를 복사 → `raw/project-notes/<slug>.md`.
   - frontmatter `title`(slug 를 사람이 읽는 형태로), `status: draft`, `status_label: active`, `last_reviewed`(오늘) 치환.
   - 본문 `# {{title}}` 헤더 치환. 나머지 placeholder·섹션(특히 §8.0 Branch 분해표 skeleton)은 **보존** — 추측해서 채우지 말 것.
   - project-note 는 cluster 의 root 이므로 Parent upward link 불요(자기 자신이 hub).

4. **사용자 안내**
   - 파일 경로 출력.
   - "이제 `/project-spec <slug> <프로젝트 목표>` 로 깊은 조사를 채우세요." 안내.

## 규칙

- **스캐폴딩만**. 내용을 추측해서 채우지 말 것 (채움은 `/project-spec`).
- §8.0 Branch 분해표 skeleton 을 삭제하지 말 것 — `/project-spec` 가 핸드오프로 채운다.
- project-note 는 머지/완료 후에도 raw 에 **영구 보관**. verified 사실만 `/ingest``wiki/projects/` 에 추출.
- `wiki/log.md` 는 기록하지 않음 (`/branch` 와 동일 정책).
  • Step 2: 링크 검사

Run: python3 .claude/hooks/wiki_structure_lint.py --file .claude/commands/project.md Expected: PASS.

  • Step 3: 커밋
git add .claude/commands/project.md
git commit -m "feat(command): /project — project-note 스캐폴딩 (Claude 전용)"

Task 6: .claude/commands/project-spec.md (오케스트레이터)

Files:

  • Create: .claude/commands/project-spec.md

  • Step 1: 파일 작성

branch-spec.md 의 구조(참조 섹션 + 작업 절차 + 규칙)를 따르되 project hub 용으로:

---
description: 빈 프로젝트 노트를 깊은 조사로 ca-skeleton 수준까지 채우고 끝에 readiness 게이트로 검증
argument-hint: <프로젝트 slug> <프로젝트 목표 자연어> [근거 URL ...]
---

`/project` 로 만든 빈 project-note(hub)를 **다음 작업의 출발점이 될 만큼 깊게 채우는** 오케스트레이터입니다.
기준선은 `raw/project-notes/ca-skeleton-operational-contract.md`*caliber*(엄격성)이며, 내용·섹션 구성은 프로젝트마다 다릅니다. 목표 prose 에서 문제·아키텍처·기술결정·branch 분해를 도출하고, 근거 없는 결정은 자동조사하되 **사용자 소유 결정(범위/우선순위/목표)은 직접 질문**으로 채우고, 끝에 readiness 게이트로 검증합니다.

**프로젝트 slug + 목표:** $ARGUMENTS

## 참조 (작업 시 정독)

- `rules/project-readiness-gate.md` — 끝에 적용할 4축(R1~R4) + proxy + 실패 모드.
- `rules/naming-conventions.md` §2.1 — Branch 분해표 slug 규칙.
- `rules/diagram-standards.md` — 아키텍처 .drawio / 시퀀스 Mermaid 컨퍼런스급 기준.
- `templates/project-template.md` — 채울 대상 구조(특히 §3 아키텍처, §4 시퀀스, §6 기술결정, §8.0 Branch 분해).
- `CLAUDE.md` §11, §15 — 근거 없는 결정 금지, 파생 규칙.

### 프로젝트 ground truth (필수 — 추측 방지, 읽기 전용)

대상 프로젝트에 코드 레포가 있으면 그 레포가 SSOT. 예: ca-tmpl 류는 `/home/donghyeon/workspace/ca-tmpl``CLAUDE.md`/`AGENTS.md`/`src/<module>`/`docs/registries/*.yaml` 를 읽어 명세를 실제 구현·계약에 정합시킨다(ground-truth repo 기억 참조). `actually-implemented` 주장은 `src/` grep 으로만 확정.

## 작업 절차

1. **전제 확인**
   - 인자 비면 slug+목표 요청(종료). slug 노트가 **없으면** 생성하지 말고 `/project <slug>` 먼저 안내(종료). 채움은 본 명령, 생성은 `/project`.
   - 노트의 §1 개요가 비고 목표 인자도 없으면 `NEEDS_CONTEXT` — 사용자에게 목표 질문.

2. **프로젝트 ground truth 확인 (읽기 전용)** — 대상 repo 코드/기존 raw/관련 노트를 읽어 현황 파악. 코드 미확인 항목은 `documented-only`/`planned` 로 표기. 레포 부재 시 `NO_GROUND_TRUTH` 라벨 + 한계 보고.

3. **문제정의·성공기준 구체화 (R1)**
   - 추상 표현 거부. 구체 시나리오·수치로.
   -**명확화 질문** — 정해야 하는데 근거·기본값이 없는 *사용자 소유 결정*(프로젝트 범위/우선순위/성공기준 임계)은 추측·UNSUPPORTED 라벨 대신 **AskUserQuestion 으로 직접 묻는다**. (branch-spec 과의 차이: hub 는 사용자 in-the-loop.)

4. **아키텍처 + 시퀀스 (R2)**
   - 핵심 user flow 의 Mermaid 시퀀스를 자동 작성(happy + error path, autonumber).
   - 아키텍처 `.drawio` 는 자동생성 불가 → §3.1 에 임베드 placeholder 와 `needs-diagram` 표시를 남기고, 사용자가 작성/요청하도록 안내. 작성되면 `wiki-diagram-reviewer` 로 ≥95 검수(게이트가 확인).

5. **기술결정 대안조사 (R3)**
   - 주요 기술결정마다 `wiki-decision-researcher` dispatch (decision_topic + 프로젝트 + constraints + N). 공식문서 + 대기업 블로그 webfetch 로 대안 비교 + 근거 raw 생성. §6 표의 `근거 자료` 칸에 `[[raw/...]]` 링크.
   - **bound: 회당 최대 6개 결정.** 초과분은 `deferred` 보고(silent 절단 금지).
   - 조사 후에도 근거 없으면 `UNSUPPORTED_DECISION` 라벨 + trade-off 한 줄.

6. **Branch 분해표 (R4 — 핸드오프)**
   - §8.0 표에 {branch slug(naming-conventions) | 측정가능 목표조건 | 우선순위 | 의존}만 채운다. **결정 내용·메커니즘은 적지 않음**(SSOT 이중화 방지). 이 표가 `/branch`·`/branch-spec` 입력.

7. **프로젝트 레벨 고정 결정** — Stack commitment / SSOT owner 등 branch 간 충돌 방지 결정(내용은 프로젝트별). 해당 없으면 명시.

8. **검증등급 + 면접·외부공개 경계** — project-template §9·§10 채움. 코드 확인 기준 등급(actually-implemented/locally-verified/...).

9. **자동 게이트 — readiness (맨 끝, 내부 단계)**
   - **(9a) 1차 결정론** — `python3 .claude/hooks/wiki_structure_lint.py --file raw/project-notes/<slug>.md`. proxy(PROJECT_NO_DIAGRAM/PROJECT_NO_BRANCH_TABLE)·frontmatter·링크 확인.
   - **(9b) 2차 의미** — 통과 시 `project-readiness-auditor` dispatch(노트 경로 전달). R1~R4 판정.
   - **(9c) 루프백** — Not-ready(Blocking)면 → §3~§8 로 되돌아가 *Blocking 축을 보강* → 9a·9b 재실행. 4축 모두 L2+(Blocking 0)까지 반복.

10. **요약 보고 (짧게, 상세는 노트에)**
    - 사람이 5초에 읽을 요약만: `채운 결정 N / UNSUPPORTED K / 조사 M / branch 분해 B / needs-diagram D / readiness: Ready|Not-ready (Blocking 축 인용)`.
    - 통과 못하면 *무엇을 더 채워야 하는지* 한 줄씩(축·finding 인용).

## 규칙

- **추측해서 FACT 로 채우지 않는다.** 근거 없으면 자동조사 → 실패 시 `UNSUPPORTED_*` 라벨. 단 *사용자 소유 결정*은 라벨 대신 **AskUserQuestion**.
- **`actually-implemented``src/` grep 으로만 확정.** note→note 자기보고 전이 금지.
- **기존 사용자 작성 본문 보존** — 채움은 빈 셀/skeleton 에만.
- **자동조사 bounded** — §5 의 6개 한도. 초과는 `deferred` 명시.
- **새 agent 를 만들지 않는다** — 기존 `wiki-source-summarizer`/`wiki-decision-researcher`/`wiki-doc-author`/`wiki-diagram-reviewer`/`project-readiness-auditor` 만 dispatch.
- **검증은 readiness 게이트에 위임** — 본 명령은 *채움*에 집중. 4축 판정 로직을 중복 구현하지 않는다.
- `wiki/log.md` 기록 안 함 (`/branch`·`/depth` 와 동일).
  • Step 2: 링크 검사

Run: python3 .claude/hooks/wiki_structure_lint.py --file .claude/commands/project-spec.md Expected: PASS.

  • Step 3: 커밋
git add .claude/commands/project-spec.md
git commit -m "feat(command): /project-spec — project-note 깊은 조사 오케스트레이터 + readiness 게이트 (Claude 전용)"

Task 7: CLAUDE.md — agent/command 목록 갱신

Files:

  • Modify: CLAUDE.md

  • Step 1: agent 목록에 추가

CLAUDE.md 의 Claude Code 자동화 agent 나열 중 마지막 항목인 .claude/agents/wiki-decision-researcher.md다음에 추가:

  - `.claude/agents/project-readiness-auditor.md` — project-note(hub) 완성도 의미 게이트 (read-only, ca-skeleton caliber 판정). **Claude Code 전용** — Codex/Antigravity 포팅 없음(`/project`·`/project-spec` 파이프라인은 3-플랫폼 패리티 예외).
  • Step 2: 3-플랫폼 서술에 예외 명시

CLAUDE.md 의 Antigravity CLI 자동화 설명 중 동일 9개 agent 표현을 찾아 아래로 교체:

찾기: .claude와 동일 9개 agent 교체: .claude와 동일 9개 agent (단 project-readiness-auditor 는 Claude 전용 — 3-플랫폼 포팅 대상 아님)

  • Step 3: depth.md 기반 §14 변환/품질 명령 설명에 /project 계열 추가

CLAUDE.md §2 디렉터리 역할 표의 .claude/commands/ 행에서 /branch-spec 뒤에 /project·/project-spec 을 캡처 그룹에 추가:

찾기: **캡처**: /daily, /branch, /branch-spec 교체: `**캡처**: `/daily`, `/branch`, `/branch-spec`, `/project`, `/project-spec

  • Step 4: 진행 중 프로젝트 노트 안내 위쪽, 명령 우선순위 §14 캡처 섹션에 한 줄 추가

CLAUDE.md §14 "### 캡처 (raw 입력)" 의 - 새 브랜치 시작 시 → /branch <name>다음에 추가:

- 새 프로젝트 시작 시 → `/project <slug>` (스캐폴딩) → `/project-spec <slug> <목표>` (깊은 조사 + readiness 게이트). project-note hub 를 ca-skeleton 수준으로 채운 뒤, §8.0 Branch 분해표를 `/branch`·`/branch-spec` 로 전개.
  • Step 5: 링크/구조 검사 (CLAUDE.md 는 links 모드)

Run: python3 .claude/hooks/wiki_structure_lint.py --file CLAUDE.md Expected: PASS.

  • Step 6: 커밋
git add CLAUDE.md
git commit -m "docs(CLAUDE): /project·/project-spec 커맨드 + project-readiness-auditor(Claude 전용) 등재"

Task 8: Dogfood 검증 (실제 사용 + 게이트 동작 확인)

Files: (없음 — 검증 + 일회성 산출물)

  • Step 1: 신규 project-note 스캐폴딩 (수동 /project 시뮬레이션)

templates/project-template.md 를 복사해 테스트 노트 생성:

cp templates/project-template.md /tmp/_dogfood-project.md
python3 .claude/hooks/wiki_structure_lint.py --file /tmp/_dogfood-project.md

Expected: --file 은 절대경로라 classify 가 raw/project-notes 로 인식 못 해 'links' 또는 'full'로 처리될 수 있음 — 이 스텝은 템플릿 자체가 proxy 를 만족하는지(§4 시퀀스 mermaid 예시 + §8.0 표)만 육안 확인용. 핵심 검증은 Step 2.

  • Step 2: 실제 경로에서 proxy 동작 확인

빈 스텁(다이어그램·표 없음)과 템플릿 기반(다이어그램·표 있음)을 각각 raw/project-notes/ 경로로 검사:

printf -- '---\ntitle: T\nsource_type: project-note\nstatus: reviewed\nconfidence: low\ntags: [project-note]\nrelated_projects: []\nlast_reviewed: 2026-06-05\ndiagrams: []\narchitecture_review: 2026-06-05\nstatus_label: active\n---\n\n# T\n\n내용 없음.\n' > raw/project-notes/_dogfood-empty.md
python3 .claude/hooks/wiki_structure_lint.py --file raw/project-notes/_dogfood-empty.md

Expected: FAIL with [PROJECT_NO_DIAGRAM][PROJECT_NO_BRANCH_TABLE] (frontmatter 키는 충족하므로 MISSING_FRONTMATTER 없음).

  • Step 3: 정리
rm -f raw/project-notes/_dogfood-empty.md /tmp/_dogfood-project.md
  • Step 4: 전체 테스트 + 린트 최종 확인
python3 .claude/hooks/test_wiki_structure_lint.py 2>&1 | tail -3
python3 .claude/hooks/wiki_structure_lint.py --all 2>&1 | tail -6

Expected: 단위 테스트 OK. --all 요약에서 project-notes 가 MISSING_SECTION 로 FAIL 하지 않음.

  • Step 5: (선택) 실제 auditor dispatch 리허설

실제 project-note(raw/project-notes/keycloak-patterns-overview.md 등) 1개에 대해 project-readiness-auditor 를 dispatch 해 리포트가 형식대로 나오는지 확인(read-only 이므로 안전). Blocking finding 은 보강 백로그로 기록만.

  • Step 6: dogfood 결과 기록 + 커밋(필요 시)

게이트가 의도대로 동작하면 Task 완료. 보강이 필요한 finding 은 docs/superpowers/specs/2026-06-05-project-note-pipeline-design.md §5 "사용하며 보강" 항목으로 issue 화(별도 커밋 불요).


Self-Review

Spec coverage:

  • §2 신규 산출물 6종 → Task 1(rules), 2(template), 3(linter), 4(agent), 5(/project), 6(/project-spec), 7(CLAUDE.md). ✓
  • §4.1 오케스트레이터 흐름 10단계 → Task 6 작업 절차에 1:1 반영. ✓
  • §5.1 4축 + §5.2 proxy + §5.3 auditor → Task 1(rules 정의) + Task 3(proxy 구현) + Task 4(auditor). ✓
  • Claude 전용 / 3-플랫폼 예외 → Task 7 Step 1·2 에 명시. ✓
  • "v1 then iterate" → Task 8 Step 6 보강 백로그. ✓

Placeholder scan: 모든 코드 step 에 실제 코드/명령/expected 포함. rules·agent·command 본문 전체 inline. 템플릿 편집은 찾기/삽입 위치 명시. placeholder 없음. ✓

Type/이름 일관성: finding 코드(PROJECT_NO_DIAGRAM/PROJECT_NO_BRANCH_TABLE/MISSING_FRONTMATTER)가 Task 1(rules)·Task 3(linter)·Task 8(dogfood expected) 전체에서 동일. 함수명 check_project_proxies/_has_branch_table 가 Task 3 구현·테스트에서 동일. agent name project-readiness-auditor 가 Task 4·6·7 에서 동일. ✓

알려진 잔여 리스크:

  • Task 3 Step 8: exemplar 의 branch 표가 markdown 표가 아니라 bullet 이면 PROJECT_NO_BRANCH_TABLE 가 뜰 수 있음 → 그 경우 exemplar 의 실제 gap 이므로 보고만(차단 아님). v1 수용.
  • --file 절대경로 시 classify 가 project 모드를 못 잡을 수 있음 → 게이트는 항상 repo-상대경로(raw/project-notes/<slug>.md)로 호출(Task 6 Step 9a 명시). dogfood Step 2 도 상대경로 사용.