update stage-pilot

This commit is contained in:
2026-04-30 13:03:56 +00:00
parent d9363af773
commit 7e9fbc1418
40 changed files with 5349 additions and 0 deletions
+80
View File
@@ -0,0 +1,80 @@
# Copilot Instructions
이 파일은 호스트 프로젝트 고유 규칙과 StagePilot 규칙을 함께 담는다.
## Host Project Rules
호스트 프로젝트 전용 규칙은 이 섹션에 작성한다.
## StagePilot
<!-- STAGEPILOT:BEGIN -->
# SDLC Governance Instructions
이 워크스페이스의 AI 에이전트는 Agile 중심 반복형 SDLC를 따른다.
모든 작업은 3-phase 구조와 그 안의 단위별 게이트를 기준으로 수행하며, 임의 단계 스킵은 허용되지 않는다(긴급 핫픽스 예외는 별도 규칙 적용).
## Lifecycle Phases
1. Requirements
2. Delivery
3. Release & Feedback
## Governing Units
1. Discovery: 문제 정의 단위
2. REQ: 승인 가능한 요구사항 단위
3. Batch: 함께 계획, 설계, 구현, 검증하는 delivery 단위
4. Release: 함께 배포하고 운영 환류를 기록하는 단위
## Bootstrap Baseline Path
- 프로젝트 시작 시 baseline 문서와 active index는 `bootstrap-baseline`으로 먼저 초기화한다.
- `bootstrap-baseline`은 3-phase lifecycle 밖의 bootstrap 단계이며 별도 governance unit가 아니다.
- 첫 real Discovery는 baseline 초기화 이후 실제 제품/서비스 변경 주제로 시작한다.
## Default Flow
1. Bootstrap: `bootstrap-baseline` (baseline 문서와 active index가 비어 있을 때만)
2. Requirements: `new-discovery` -> `confirm-discovery` -> `draft-req` -> `confirm-req` -> `suggest-batch-reqs` -> `draft-batch`
3. Delivery: `draft-batch-planning` -> `draft-batch-design` -> `run-batch-implementation` -> `draft-batch-verification` -> `confirm-batch-verification` -> `confirm-req-implemented`
4. Release & Feedback: `draft-release` -> `confirm-release` -> `capture-release-feedback`
## Lightweight Change Path
- 단일 저위험 `Approved` REQ이고 구조/인터페이스/런타임 흐름 영향이 없으면 `minor-change` fast path를 사용할 수 있다.
- 이 경로는 `suggest-batch-reqs`를 생략하고 `draft-batch`로 바로 `batch-lite` batch를 만든다.
- `batch-lite`는 planning부터 시작하고, design은 필요할 때만 생성한다.
- release는 `docs-only`, `tooling`, `app-service` profile 중 하나를 선택해 검증 강도를 조정한다.
## Change Management Extension
- 기존 REQ 본문을 수정할 때는 `change-req`를 사용해 Change Log 근거를 먼저 남긴다.
- release feedback의 후속 입력은 `Discovery Input`, `REQ Input`, `Change Request Input`으로 분리해 기록한다.
- 다음 반복 후보만 먼저 정리하려면 `suggest-next-discovery`를 사용하고, 실제 문서 생성은 `new-discovery`로 이어 간다.
## Stage Mapping
- Discovery는 Requirements phase 안에서 유지한다.
- Planning, Design, Implementation, Verification은 Batch 내부 stage로 다룬다.
- Release와 Operations는 Release & Feedback phase 내부에서 다룬다.
- `review-*` stage command는 더 이상 active flow에 포함하지 않고 대응 `confirm-*` 절차에 흡수한다.
- prompt 기반 stage command는 active 경로에서 사용하지 않고 `.github/skills/` 아래 skill entrypoint만 사용한다.
## Global Rules
1. 증거 기반: 요구사항, 가정, 리스크, 결정 근거를 문서에 남긴다.
2. 게이트 준수: 각 phase와 단위의 DoR(진입 조건)과 DoD(완료 조건)을 충족해야 다음 단계로 이동한다.
3. 테스트 우선 검증: 구현 결과는 테스트 또는 검증 근거 없이 완료로 간주하지 않는다.
4. 변경 영향도 기록: 코드/문서/운영 영향 범위를 명시한다.
5. 불확실성 우선 해소: 차단 이슈가 있으면 임의 추정 대신 질문 또는 추가 탐색을 수행한다.
6. 운영 환류: 운영 단계 인사이트는 다음 Discovery의 입력으로 반드시 반영한다.
## Hotfix Exception Path
긴급 핫픽스는 Requirements/Delivery 설계를 경량화할 수 있다. 단, 아래는 필수다.
1. 최소 요구사항 정의(증상, 영향, 성공 조건)
2. 최소 검증(재현 테스트 또는 핵심 시나리오 확인)
3. 배포 전 롤백 계획
4. 배포 후 Postmortem 작성 및 다음 스프린트 환류
<!-- STAGEPILOT:END -->
+239
View File
@@ -0,0 +1,239 @@
# 플레이스홀더 가이드
이 파일은 active workspace 기준으로 `.github/templates/`와 `.github/skills/`에서 사용하는 플레이스홀더의 문법과 처리 원칙을 정의한다.
기본 전제는 아래와 같다.
- active SDLC 진입점은 skill-only 체계다.
- baseline 문서와 active index 초기화는 `bootstrap-baseline`이 담당하며, 이 단계는 Discovery unit를 만들지 않는다.
- `.github/prompts/`는 active 기준 문서가 아니다.
- active 산출물 경로는 `docs/discovery/`, `docs/srs/`, `docs/batches/`, `docs/releases/`다.
## 1. 문법 규칙
| 형식 | 의미 | 예시 |
| --- | --- | --- |
| `{{KEY}}` | 단순 치환 대상 | `{{DISCOVERY_ID}}` |
| `{{KEY:hint}}` | 힌트 포함 치환 대상 | `{{CONFIRMED_AT_KST:TBD}}` |
| `{{KEY:opt1\|opt2}}` | 열거형 선택 값 | `{{DOC_STATUS:draft\|confirmed}}` |
규칙:
- 최종 문서에는 `{{...}}` 문법이 남지 않아야 한다.
- 힌트 텍스트는 치환 시 함께 제거한다.
- 사람 승인 없이는 확정할 수 없는 값은 본문에 무리하게 확정하지 말고 Notes 또는 결정 필요 항목으로 남긴다.
## 2. 처리 주체
플레이스홀더는 아래 세 가지 처리 주체 중 하나에 속한다.
### A. 자동 치환
- ID, 생성 시각, 갱신 시각, 상태 기본값처럼 실행 시점에 자동으로 정해지는 값
- 예:
- `{{DISCOVERY_ID}}`
- `{{CONFIRMED_AT_KST}}`
- `{{BAT_ID}}`
- `{{REL_ID}}`
### B. AI 근거 기반 치환
- 현재 저장소 상태, 상위 문서, 이미 확정된 값으로 채울 수 있는 항목
- 예:
- Discovery의 현재 상태 요약
- REQ의 Impacted Area 초안
- Batch planning의 dependency 정리
- Release rollout checklist 초안
### C. 사람 결정 필요
- 정책 선택, 승인자 지정, 우선순위 확정, 외부 환경 정보처럼 사람 판단이 필요한 값
- 이런 항목은 무리하게 확정하지 않는다.
## 3. 경로별 플레이스홀더 원칙
### 3.0 Bootstrap baseline 템플릿
대상 경로:
- `.github/templates/bootstrap/baseline-seed.yaml`
- `.github/templates/project-structure.md`
- `.github/templates/runtime-flows.md`
- `.github/templates/discovery/index.md`
- `.github/templates/srs/index.md`
- `.github/templates/batches/index.md`
- `.github/templates/releases/index.md`
처리 원칙:
- `bootstrap-baseline`은 먼저 `.stagepilot/bootstrap/baseline.yaml` seed를 만들거나 보강한다.
- greenfield 저장소처럼 관찰 가능한 정보가 부족하면 최소 질문 세트로 seed를 채운다.
- `bootstrap-baseline`은 baseline 문서와 index를 초기화하지만 Discovery 문서를 만들지 않는다.
- baseline 문서는 seed를 source of truth로 렌더링하고, 필요하면 저장소 관찰값으로 보강한다.
- index 문서는 빈 register 골격만 준비하고, 실제 unit 행은 이후 skill이 추가한다.
주요 키:
- `{{BASELINE_MODE}}`
- `{{BASELINE_SEED_PATH}}`
- `{{PROJECT_SUMMARY}}`
- `{{PRIMARY_DOMAIN}}`
- `{{TECH_STACK_BULLETS}}`
- `{{PRIMARY_RUNTIME}}`
- `{{PRIMARY_ENTRYPOINT_BULLETS}}`
- `interfaces.contracts[*]`
- `data_model.entities[*]`
### 3.0.1 선택 cross-cutting 템플릿
대상 경로:
- `.github/templates/interface-contract.md`
- `.github/templates/data-model.md`
처리 원칙:
- 이 문서들은 optional cross-cutting reference다.
- active unit의 source of truth를 대체하지 않고, 여러 REQ와 batch에 공통으로 반복되는 계약 정보를 모아 둔다.
- `bootstrap-baseline`은 seed의 `interfaces`와 `data_model` 섹션을 우선 읽고, 값이 없으면 `runtime`, `structure`, `notes`를 바탕으로 기본 초안을 구체적으로 유도한다.
- baseline 수준의 변경이 있을 때만 갱신하고, REQ별 acceptance criteria를 그대로 복사하지 않는다.
주요 키:
- `{{BASELINE_MODE}}`
- `{{BASELINE_SEED_PATH}}`
- `{{PROJECT_SUMMARY}}`
- `{{PRIMARY_DOMAIN}}`
- `{{PRIMARY_RUNTIME}}`
- `{{INTERFACE_NAME_1}}`
- `{{INTERFACE_PURPOSE_1}}`
- `{{INTERFACE_SUMMARY_BULLETS}}`
- `{{INTERFACE_INPUTS_1}}`
- `{{INTERFACE_OUTPUTS_1}}`
- `{{INTERFACE_ERRORS_1}}`
- `{{INTERFACE_COMPATIBILITY_1}}`
- `{{INTERFACE_SHARED_CONSTRAINTS_BULLETS}}`
- `{{INTERFACE_CURRENT_GAPS_BULLETS}}`
- `{{PERSISTENCE_BACKEND}}`
- `{{ENTITY_NAME_1}}`
- `{{ENTITY_PURPOSE_1}}`
- `{{ENTITY_SOURCE_1}}`
- `{{ENTITY_LIFECYCLE_1}}`
- `{{MODEL_SUMMARY_BULLETS}}`
- `{{ENTITY_FIELDS_1}}`
- `{{ENTITY_RELATIONSHIPS_1}}`
- `{{CONSISTENCY_RULE_BULLETS}}`
- `{{PERSISTENCE_NOTES_BULLETS}}`
- `{{MODEL_CURRENT_GAPS_BULLETS}}`
### 3.1 Discovery 템플릿
대상 경로:
- `.github/templates/discovery/discovery.md`
- `docs/discovery/*.md`
주요 키:
- `{{DISCOVERY_ID}}`
- `{{ISSUE_NAME}}`
- `{{CREATED_AT_KST}}`
- `{{UPDATED_AT_KST}}`
- `{{FREEZE_HANDOFF_DECISION}}`
- `{{READY_FOR_REQ_DRAFTING}}`
- `{{CONFIRMED_BY}}`
- `{{CONFIRMED_AT_KST}}`
처리 원칙:
- Discovery는 REQ 초안 작성으로 넘길 수 있을 때만 freeze handoff를 완료한다.
- Discovery 문서의 용어는 `Planning` 직결이 아니라 `REQ Drafting` 기준으로 유지한다.
### 3.2 SRS 템플릿
대상 경로:
- `docs/srs/req-template.md`
- `docs/srs/index.md`
주요 키:
- `REQ-XXX`
- `Status`
- `Type`
- `Priority`
- `Owner`
처리 원칙:
- REQ는 `Proposed -> Approved -> Implemented -> Deprecated` 상태를 따른다.
- `draft-req`는 초안을 만들고, `confirm-req`는 `Proposed -> Approved`, `confirm-req-implemented`는 `Approved -> Implemented` 전환을 담당한다.
### 3.3 Batch 템플릿
대상 경로:
- `.github/templates/batches/*`
- `docs/batches/*`
주요 키:
- `{{BAT_ID}}`
- `Profile`
- Included REQ 목록
- Source Discovery
처리 원칙:
- batch는 Approved REQ만 포함한다.
- batch는 `standard` 또는 `batch-lite` profile을 가진다.
- `batch-lite`는 `minor-change` fast path의 기본 delivery profile이며, 처음에는 `index.md`와 `planning.md`만 만들 수 있다.
- planning, design, implementation, verification 문서는 같은 batch 폴더 아래에서 관리한다. 단, `batch-lite`는 design/implementation/verification을 단계 진입 시점에 생성할 수 있다.
- `confirm-batch-verification` 성공 전에는 `release-candidate`로 올리지 않는다.
### 3.4 Release 템플릿
대상 경로:
- `.github/templates/releases/*`
- `docs/releases/*`
주요 키:
- `{{REL_ID}}`
- `Profile`
- `Change Request Input`
- Included Batch
- Rollout Plan
- Rollback Plan
처리 원칙:
- release는 `release-candidate` batch만 포함한다.
- release는 `docs-only`, `tooling`, `app-service` profile 중 하나를 가진다.
- feedback handoff에는 `Discovery Input`, `REQ Input`, `Change Request Input`을 구분해 기록한다.
- `confirm-release`는 release 승인, `capture-release-feedback`는 운영 환류 기록을 담당한다.
## 4. Active Skill Summary
| 목적 | Skill | 주요 입력 | 주요 출력 |
| --- | --- | --- | --- |
| Bootstrap baseline 초기화 | `.github/skills/bootstrap-baseline/SKILL.md` | 저장소 루트, baseline/index 존재 여부 | baseline 문서와 active index |
| Discovery 초안 생성 | `.github/skills/new-discovery/SKILL.md` | 이슈/요청 요약 | `docs/discovery/*.md` |
| Discovery 확정 | `.github/skills/confirm-discovery/SKILL.md` | `DISCOVERY_ID` | confirmed Discovery |
| REQ 초안 생성 | `.github/skills/draft-req/SKILL.md` | `DISCOVERY_ID` | `docs/srs/<Type>/req-*.md` |
| REQ 확정 | `.github/skills/confirm-req/SKILL.md` | `REQ-ID` | Approved REQ |
| REQ 변경 관리 | `.github/skills/change-req/SKILL.md` | `REQ-ID` | Change Log 기반 REQ 갱신 |
| REQ 구현 완료 전환 | `.github/skills/confirm-req-implemented/SKILL.md` | `REQ-ID` 또는 `BAT-ID` | Implemented REQ |
| Batch 추천 | `.github/skills/suggest-batch-reqs/SKILL.md` | `DISCOVERY_ID` 또는 REQ 목록 | batch 후보안 |
| Batch 생성 | `.github/skills/draft-batch/SKILL.md` | Approved REQ 목록 | `docs/batches/<BAT_ID>/` |
| Delivery 진행 | `.github/skills/draft-batch-planning/SKILL.md`, `.github/skills/draft-batch-design/SKILL.md`, `.github/skills/run-batch-implementation/SKILL.md`, `.github/skills/draft-batch-verification/SKILL.md`, `.github/skills/confirm-batch-verification/SKILL.md` | `BAT-ID` | batch 문서와 상태 |
| Release 진행 | `.github/skills/draft-release/SKILL.md`, `.github/skills/confirm-release/SKILL.md`, `.github/skills/capture-release-feedback/SKILL.md` | `BAT-ID` 또는 `REL-ID` | release 문서와 운영 환류 |
| 다음 Discovery 추천 | `.github/skills/suggest-next-discovery/SKILL.md` | `REL-ID` 또는 없음 | follow-up 후보안 |
| 상위 orchestration | `.github/skills/run-sdlc/SKILL.md` | Discovery/REQ/Batch/Release 식별자 | 다음 skill 라우팅 |
## 5. 금지 사항
- active 설명 문서에서 `.github/prompts/`를 기준 경로로 안내하지 않는다.
- `review-*`를 별도 active 단계로 서술하지 않는다.
- `docs/sdlc/`를 신규 active 산출물 경로로 사용하지 않는다.
@@ -0,0 +1,913 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from pathlib import Path
import re
import sys
try:
from zoneinfo import ZoneInfo
except ImportError: # pragma: no cover
ZoneInfo = None
RUNTIME_CHOICES = (
"cli",
"api-service",
"web-app",
"worker",
"library",
"mixed",
"other",
)
INTERFACE_TYPE_CHOICES = (
"http-api",
"cli",
"event",
"file",
"internal-service",
"other",
)
UPPERCASE_TOKENS = {
"api": "API",
"http": "HTTP",
"cli": "CLI",
"id": "ID",
"io": "I/O",
"json": "JSON",
"sql": "SQL",
"ui": "UI",
"ux": "UX",
"url": "URL",
}
STORAGE_BACKEND_HINTS = (
(("postgresql", "postgres", "psql"), "PostgreSQL"),
(("mysql", "mariadb"), "MySQL"),
(("sqlite",), "SQLite"),
(("mongodb", "mongo"), "MongoDB"),
(("dynamodb",), "DynamoDB"),
(("redis",), "Redis"),
(("s3", "blob storage", "object storage"), "Object Storage"),
)
@dataclass(frozen=True)
class Entrypoint:
name: str
purpose: str
@dataclass(frozen=True)
class TopLevelArea:
path: str
responsibility: str
@dataclass(frozen=True)
class InterfaceContractHint:
name: str
interface_type: str
actors: str
purpose: str
@dataclass(frozen=True)
class EntityHint:
name: str
purpose: str
@dataclass(frozen=True)
class CompatibilityRuleHint:
interface_name: str
rule: str
@dataclass(frozen=True)
class InterfaceDetailHint:
interface_name: str
value: str
@dataclass(frozen=True)
class SeedAnswers:
repository_name: str
display_name: str
summary: str
primary_domain: str
tech_stack: list[str]
primary_runtime: str
primary_entrypoints: list[Entrypoint]
planned_top_level_areas: list[TopLevelArea]
interface_contracts: list[InterfaceContractHint]
interface_inputs: list[InterfaceDetailHint]
interface_outputs: list[InterfaceDetailHint]
interface_errors: list[InterfaceDetailHint]
core_entities: list[EntityHint]
persistence_backend: str
compatibility_rules: list[CompatibilityRuleHint]
known_unknowns: list[str]
capture_mode: str
def fail(message: str) -> int:
print(f"[bootstrap-seed] ERROR: {message}", file=sys.stderr)
return 1
def log(message: str) -> None:
print(f"[bootstrap-seed] {message}")
def default_display_name(repository_name: str) -> str:
words = re.sub(r"[-_]+", " ", repository_name.strip()).split()
if not words:
return "Project"
return " ".join(word.capitalize() for word in words)
def kst_timestamp() -> str:
if ZoneInfo is not None:
current = datetime.now(ZoneInfo("Asia/Seoul"))
else: # pragma: no cover
current = datetime.now(timezone(timedelta(hours=9)))
return current.strftime("%Y-%m-%d %H:%M")
def yaml_scalar(value: str) -> str:
escaped = value.replace("'", "''")
return f"'{escaped}'"
def parse_csv_list(raw_value: str) -> list[str]:
return [item.strip() for item in raw_value.split(",") if item.strip()]
def parse_pair(raw_value: str, label: str) -> tuple[str, str]:
if "::" not in raw_value:
raise ValueError(f"{label} entries must use 'name :: purpose' format: {raw_value}")
left, right = raw_value.split("::", 1)
left = left.strip()
right = right.strip()
if not left or not right:
raise ValueError(f"{label} entries must include values on both sides of '::': {raw_value}")
return left, right
def parse_parts(raw_value: str, label: str, expected_parts: int) -> tuple[str, ...]:
parts = tuple(part.strip() for part in raw_value.split("::"))
if len(parts) != expected_parts or any(not part for part in parts):
raise ValueError(
f"{label} entries must use exactly {expected_parts} parts separated by '::': {raw_value}"
)
return parts
def prompt_value(question: str, *, default: str | None = None, choices: tuple[str, ...] | None = None) -> str:
while True:
choice_hint = f" ({', '.join(choices)})" if choices else ""
default_hint = f" [{default}]" if default else ""
raw_value = input(f"{question}{choice_hint}{default_hint}: ").strip()
if not raw_value and default is not None:
return default
if not raw_value:
print("Value is required.")
continue
if choices and raw_value not in choices:
print(f"Choose one of: {', '.join(choices)}")
continue
return raw_value
def prompt_lines(question: str, *, example: str, required: bool = False, max_items: int | None = None) -> list[str]:
print(question)
print(f"Format: {example}")
print("Press Enter on an empty line to finish.")
values: list[str] = []
while True:
raw_value = input("> ").strip()
if not raw_value:
if required and not values:
print("At least one line is required.")
continue
break
values.append(raw_value)
if max_items is not None and len(values) >= max_items:
break
return values
def title_case_phrase(text: str) -> str:
tokens = [token for token in re.split(r"[\s/_-]+", text.strip()) if token]
formatted: list[str] = []
for token in tokens:
lowered = token.lower()
if lowered in UPPERCASE_TOKENS:
formatted.append(UPPERCASE_TOKENS[lowered])
else:
formatted.append(token.capitalize())
return " ".join(formatted)
def compact_label(text: str, *, max_words: int = 5) -> str:
cleaned = re.sub(r"[^A-Za-z0-9\s/_-]+", " ", text).strip()
label = title_case_phrase(cleaned)
words = label.split()
if len(words) > max_words:
return " ".join(words[:max_words])
return label
def infer_interface_type(primary_runtime: str, entrypoint_name: str, index: int) -> str:
lowered = entrypoint_name.lower()
if primary_runtime in {"api-service", "web-app"} and index == 0:
return "http-api"
if primary_runtime == "library":
return "internal-service"
if primary_runtime in {"cli", "worker"}:
return "cli"
if any(token in lowered for token in ("uvicorn", "gunicorn", ":app")):
return "http-api"
if lowered.startswith(("python ", "python3 ", "node ")) or " -m " in lowered:
return "cli"
return "other"
def default_interface_actors(interface_type: str) -> str:
actor_map = {
"http-api": "clients and downstream services",
"cli": "operators and automation",
"event": "publishers and subscribers",
"file": "file producers and consumers",
"internal-service": "internal services",
"other": "project operators and integrators",
}
return actor_map[interface_type]
def default_interface_stability(interface_type: str, capture_mode: str) -> str:
if interface_type == "cli":
return "internal"
if capture_mode == "declared":
return "experimental"
return "internal"
def derive_interface_name(entrypoint: Entrypoint, interface_type: str, index: int) -> str:
purpose_label = compact_label(entrypoint.purpose)
if interface_type == "http-api":
return "Primary HTTP API" if index == 0 else f"{purpose_label} API"
if interface_type == "cli":
return f"{purpose_label} Command"
if interface_type == "event":
return f"{purpose_label} Event"
if interface_type == "file":
return f"{purpose_label} File Contract"
if interface_type == "internal-service":
return f"{purpose_label} Service"
return f"{purpose_label} Interface"
def build_interface_hints(answers: SeedAnswers) -> list[InterfaceContractHint]:
hints = list(answers.interface_contracts[:2])
for index, entrypoint in enumerate(answers.primary_entrypoints):
if len(hints) >= 2:
break
interface_type = infer_interface_type(answers.primary_runtime, entrypoint.name, index)
hints.append(
InterfaceContractHint(
name=derive_interface_name(entrypoint, interface_type, index),
interface_type=interface_type,
actors=default_interface_actors(interface_type),
purpose=entrypoint.purpose,
)
)
while len(hints) < 2:
index = len(hints)
fallback_type = "http-api" if index == 0 and answers.primary_runtime in {"api-service", "web-app"} else "internal-service"
hints.append(
InterfaceContractHint(
name="Primary HTTP API" if fallback_type == "http-api" else "Internal Service Interface",
interface_type=fallback_type,
actors=default_interface_actors(fallback_type),
purpose=f"support the primary {answers.primary_domain} workflow",
)
)
return hints[:2]
def default_entity_name(primary_domain: str, index: int) -> str:
domain_label = compact_label(primary_domain, max_words=4) or "Domain"
if index == 0:
return f"{domain_label} Record"
return f"{domain_label} Snapshot"
def default_entity_purpose(primary_domain: str, index: int) -> str:
if index == 0:
return f"represent a core business record in the {primary_domain} domain"
return f"represent a derived or supporting artifact in the {primary_domain} domain"
def build_entity_hints(answers: SeedAnswers) -> list[EntityHint]:
hints = list(answers.core_entities[:2])
while len(hints) < 2:
index = len(hints)
hints.append(
EntityHint(
name=default_entity_name(answers.primary_domain, index),
purpose=default_entity_purpose(answers.primary_domain, index),
)
)
return hints[:2]
def detect_storage_backend(tech_stack: list[str]) -> str:
lowered_stack = [item.lower() for item in tech_stack]
for keywords, label in STORAGE_BACKEND_HINTS:
if any(keyword in item for item in lowered_stack for keyword in keywords):
return label
return "application data store"
def normalize_storage_backend(raw_value: str) -> str:
lowered_value = raw_value.strip().lower()
if not lowered_value:
return "application data store"
for keywords, label in STORAGE_BACKEND_HINTS:
if any(keyword in lowered_value for keyword in keywords):
return label
return raw_value.strip()
def derive_interface_inputs(contract: InterfaceContractHint) -> list[str]:
if contract.interface_type == "http-api":
return [f"service request handled by {contract.name} :: {contract.purpose}"]
if contract.interface_type == "cli":
return [f"command invocation :: {contract.purpose}"]
if contract.interface_type == "event":
return [f"event publication or subscription :: {contract.purpose}"]
if contract.interface_type == "file":
return [f"file input or output trigger :: {contract.purpose}"]
return [f"interface invocation :: {contract.purpose}"]
def derive_interface_outputs(contract: InterfaceContractHint) -> list[str]:
if contract.interface_type == "http-api":
return [f"structured service response :: result of {contract.purpose}"]
if contract.interface_type == "cli":
return [f"console output or generated artifact :: result of {contract.purpose}"]
if contract.interface_type == "event":
return [f"published event payload :: result of {contract.purpose}"]
if contract.interface_type == "file":
return [f"generated or updated file artifact :: result of {contract.purpose}"]
return [f"observable interface result :: outcome of {contract.purpose}"]
def derive_interface_errors(contract: InterfaceContractHint) -> list[str]:
if contract.interface_type == "http-api":
return ["4xx/5xx response :: the request could not be completed successfully"]
if contract.interface_type == "cli":
return ["non-zero exit code :: the command failed for operators or automation"]
return ["reported interface failure :: the contract could not be completed successfully"]
def derive_interface_compatibility(contract: InterfaceContractHint) -> list[str]:
if contract.interface_type == "cli":
return ["arguments and exit-code semantics should remain stable for automation callers"]
return ["payload shape and externally visible behavior should remain backward compatible for stable consumers"]
def resolve_interface_compatibility_rules(
answers: SeedAnswers,
contract: InterfaceContractHint,
) -> list[str]:
shared_rules = [
rule.rule for rule in answers.compatibility_rules if rule.interface_name.strip() == "*"
]
named_rules = [
rule.rule
for rule in answers.compatibility_rules
if rule.interface_name.strip().casefold() == contract.name.casefold()
]
if shared_rules or named_rules:
return shared_rules + named_rules
return derive_interface_compatibility(contract)
def resolve_interface_detail_hints(
detail_hints: list[InterfaceDetailHint],
contract: InterfaceContractHint,
) -> list[str]:
return [
hint.value
for hint in detail_hints
if hint.interface_name.strip().casefold() == contract.name.casefold()
]
def derive_interface_shared_constraints(answers: SeedAnswers, contracts: list[InterfaceContractHint]) -> list[str]:
constraints: list[str] = []
if any(contract.interface_type == "http-api" for contract in contracts):
constraints.append("request validation should happen before persistence or response rendering")
if any(contract.interface_type == "cli" for contract in contracts):
constraints.append("automation-facing commands should communicate failure through stable exit semantics")
if not constraints:
constraints.append("externally visible interfaces should document compatibility expectations before release")
return constraints[:2]
def derive_interface_current_gaps(answers: SeedAnswers, contracts: list[InterfaceContractHint]) -> list[str]:
if answers.known_unknowns:
return answers.known_unknowns[:2]
gaps: list[str] = []
if any(contract.interface_type == "http-api" for contract in contracts):
gaps.append("authentication and API versioning strategy are not defined yet")
if any(contract.interface_type == "cli" for contract in contracts):
gaps.append("automation caller expectations are not fully documented yet")
return gaps[:2] or ["consumer-specific compatibility expectations are not defined yet"]
def derive_entity_source(storage_backend: str, index: int) -> str:
if storage_backend == "PostgreSQL":
return "PostgreSQL primary tables" if index == 0 else "PostgreSQL derived tables"
if storage_backend == "MySQL":
return "MySQL primary tables" if index == 0 else "MySQL derived tables"
if storage_backend == "SQLite":
return "SQLite primary tables" if index == 0 else "SQLite derived tables"
if storage_backend == "MongoDB":
return "MongoDB primary collections" if index == 0 else "MongoDB derived collections"
if storage_backend == "Object Storage":
return "object storage manifests" if index == 0 else "object storage derived artifacts"
return "primary application records" if index == 0 else "derived application records"
def derive_entity_lifecycle(index: int) -> str:
if index == 0:
return "created -> updated -> archived"
return "derived -> published -> superseded"
def derive_entity_fields(index: int, entity: EntityHint, source_entity: EntityHint | None = None) -> list[str]:
if index == 0:
return [
"id :: string or uuid :: stable identifier for the entity",
"status :: enum :: current lifecycle state for the entity",
"created_at :: timestamp :: when the entity was first recorded",
]
source_name = source_entity.name if source_entity is not None else "the primary entity"
return [
"id :: string or uuid :: stable identifier for the derived entity",
f"source_id :: string or uuid :: reference to {source_name}",
"updated_at :: timestamp :: when the derived state was last recomputed or refreshed",
]
def derive_entity_relationships(index: int, entity: EntityHint, other_entity: EntityHint) -> list[str]:
if index == 0:
return [f"{other_entity.name} :: derived from or associated with {entity.name}"]
return [f"{other_entity.name} :: source record or upstream entity for {entity.name}"]
def derive_entity_state_rules(index: int, entity: EntityHint, other_entity: EntityHint) -> list[str]:
if index == 0:
return [
"only one current active record should be treated as authoritative per business key",
"archived records should remain available for audit or replay needs when retained",
]
return [
f"{entity.name} should not exist without a corresponding {other_entity.name}",
f"{entity.name} should be refreshed whenever the authoritative {other_entity.name} changes",
]
def derive_consistency_rules(entities: list[EntityHint]) -> list[str]:
return [
"stable identifiers must remain consistent across related entities",
f"derived records must not outlive their source relationship to {entities[0].name}",
]
def derive_persistence_notes(storage_backend: str) -> list[str]:
return [
f"{storage_backend} is expected to store the current cross-cutting records and derived artifacts",
"migration, indexing, and retention strategy should be updated when schema assumptions change",
]
def derive_model_current_gaps(answers: SeedAnswers) -> list[str]:
if answers.known_unknowns:
return answers.known_unknowns[:2]
return [
"exact schema and indexing strategy are not defined yet",
"retention and archival policy are not defined yet",
]
def collect_required_args(args: argparse.Namespace) -> tuple[str, str, list[str], str, list[str]]:
missing: list[str] = []
if not args.project_summary:
missing.append("--project-summary")
if not args.primary_domain:
missing.append("--primary-domain")
if not args.tech_stack:
missing.append("--tech-stack")
if not args.primary_runtime:
missing.append("--primary-runtime")
if not args.primary_entrypoint:
missing.append("--primary-entrypoint")
if missing:
raise ValueError("Missing required arguments for --non-interactive: " + ", ".join(missing))
tech_stack = parse_csv_list(args.tech_stack)
if not tech_stack:
raise ValueError("--tech-stack must include at least one comma-separated item")
return (
args.project_summary,
args.primary_domain,
tech_stack,
args.primary_runtime,
args.primary_entrypoint,
)
def collect_answers(args: argparse.Namespace, host_root: Path) -> SeedAnswers:
repository_name = args.repository_name or host_root.resolve().name or "project"
display_name = args.display_name or default_display_name(repository_name)
if args.non_interactive:
summary, primary_domain, tech_stack, primary_runtime, primary_entrypoints = collect_required_args(args)
top_level_area_values = args.top_level_area
interface_contract_values = args.interface_contract
interface_input_values = args.interface_input
interface_output_values = args.interface_output
interface_error_values = args.interface_error
core_entity_values = args.core_entity
persistence_backend = normalize_storage_backend(args.persistence_backend) if args.persistence_backend else detect_storage_backend(tech_stack)
compatibility_rule_values = args.compatibility_rule
known_unknowns = args.known_unknown
else:
print("[bootstrap-seed] Answer the minimum bootstrap questions for baseline.yaml.")
print(f"[bootstrap-seed] Host root: {host_root}")
display_name = prompt_value("Display name", default=display_name)
summary = args.project_summary or prompt_value("project-summary | 이 프로젝트를 한 문장으로 설명하면 무엇인가?")
primary_domain = args.primary_domain or prompt_value("primary-domain | 이 프로젝트의 주요 도메인은 무엇인가?")
tech_stack = parse_csv_list(args.tech_stack) if args.tech_stack else parse_csv_list(
prompt_value("tech-stack | 계획 중인 주 언어, 프레임워크, 핵심 인프라는 무엇인가? (comma-separated)")
)
primary_runtime = args.primary_runtime or prompt_value(
"primary-runtime | 계획 중인 주 실행 형태는 무엇인가?",
choices=RUNTIME_CHOICES,
)
primary_entrypoints = args.primary_entrypoint or prompt_lines(
"primary-entrypoints | 대표 진입점 1~3개를 적어 달라.",
example="name :: purpose",
required=True,
max_items=3,
)
top_level_area_values = args.top_level_area or prompt_lines(
"planned-top-level-areas | 이미 알고 있는 top-level 경로가 있으면 적어 달라.",
example="path :: responsibility",
)
interface_contract_values = args.interface_contract or prompt_lines(
"interface-contracts | 대표 인터페이스 1~2개가 있으면 적어 달라.",
example="name :: type :: actors :: purpose",
max_items=2,
)
interface_input_values = args.interface_input or prompt_lines(
"interface-inputs | 각 인터페이스의 대표 input을 적어 달라.",
example="interface-name :: input contract or invocation note",
)
interface_output_values = args.interface_output or prompt_lines(
"interface-outputs | 각 인터페이스의 대표 output을 적어 달라.",
example="interface-name :: output contract or artifact",
)
interface_error_values = args.interface_error or prompt_lines(
"interface-errors | 각 인터페이스의 대표 error를 적어 달라.",
example="interface-name :: error code or failure behavior",
)
core_entity_values = args.core_entity or prompt_lines(
"core-entities | 핵심 엔티티 1~2개가 있으면 적어 달라.",
example="name :: purpose",
max_items=2,
)
persistence_backend = normalize_storage_backend(args.persistence_backend) if args.persistence_backend else prompt_value(
"persistence-backend | 주 persistence backend가 있으면 적어 달라.",
default=detect_storage_backend(tech_stack),
)
compatibility_rule_values = args.compatibility_rule or prompt_lines(
"compatibility-rules | 인터페이스 호환성 규칙이 있으면 적어 달라.",
example="interface-name :: rule 또는 * :: rule",
)
known_unknowns = args.known_unknown or prompt_lines(
"known-unknowns | 아직 미정인 핵심 항목이 있으면 적어 달라.",
example="one unresolved item per line",
)
if primary_runtime not in RUNTIME_CHOICES:
raise ValueError(f"primary runtime must be one of: {', '.join(RUNTIME_CHOICES)}")
if not tech_stack:
raise ValueError("tech-stack must include at least one item")
if not primary_entrypoints:
raise ValueError("at least one primary-entrypoint is required")
if len(primary_entrypoints) > 3:
raise ValueError("primary-entrypoint supports at most 3 values")
if len(interface_contract_values) > 2:
raise ValueError("interface-contract supports at most 2 values")
if len(core_entity_values) > 2:
raise ValueError("core-entity supports at most 2 values")
entrypoints = [Entrypoint(*parse_pair(value, "primary-entrypoint")) for value in primary_entrypoints]
top_level_areas = [TopLevelArea(*parse_pair(value, "top-level-area")) for value in top_level_area_values]
interface_contracts = [
InterfaceContractHint(*parse_parts(value, "interface-contract", 4)) for value in interface_contract_values
]
for contract in interface_contracts:
if contract.interface_type not in INTERFACE_TYPE_CHOICES:
raise ValueError(
"interface-contract type must be one of: " + ", ".join(INTERFACE_TYPE_CHOICES)
)
interface_inputs = [InterfaceDetailHint(*parse_pair(value, "interface-input")) for value in interface_input_values]
interface_outputs = [InterfaceDetailHint(*parse_pair(value, "interface-output")) for value in interface_output_values]
interface_errors = [InterfaceDetailHint(*parse_pair(value, "interface-error")) for value in interface_error_values]
core_entities = [EntityHint(*parse_parts(value, "core-entity", 2)) for value in core_entity_values]
compatibility_rules = [
CompatibilityRuleHint(*parse_pair(value, "compatibility-rule")) for value in compatibility_rule_values
]
return SeedAnswers(
repository_name=repository_name,
display_name=display_name,
summary=summary,
primary_domain=primary_domain,
tech_stack=tech_stack,
primary_runtime=primary_runtime,
primary_entrypoints=entrypoints,
planned_top_level_areas=top_level_areas,
interface_contracts=interface_contracts,
interface_inputs=interface_inputs,
interface_outputs=interface_outputs,
interface_errors=interface_errors,
core_entities=core_entities,
persistence_backend=persistence_backend,
compatibility_rules=compatibility_rules,
known_unknowns=known_unknowns,
capture_mode=args.capture_mode or "declared",
)
def render_seed(answers: SeedAnswers) -> str:
updated_from = {
"declared": "user-answer",
"observed": "repo-observation",
"mixed": "mixed",
}[answers.capture_mode]
interface_contracts = build_interface_hints(answers)
entities = build_entity_hints(answers)
storage_backend = answers.persistence_backend
interface_shared_constraints = derive_interface_shared_constraints(answers, interface_contracts)
interface_current_gaps = derive_interface_current_gaps(answers, interface_contracts)
consistency_rules = derive_consistency_rules(entities)
persistence_notes = derive_persistence_notes(storage_backend)
model_current_gaps = derive_model_current_gaps(answers)
lines = [
"schema_version: 1",
f"capture_mode: {answers.capture_mode}",
"",
"project:",
f" repository_name: {yaml_scalar(answers.repository_name)}",
f" display_name: {yaml_scalar(answers.display_name)}",
f" summary: {yaml_scalar(answers.summary)}",
f" primary_domain: {yaml_scalar(answers.primary_domain)}",
"",
"stack:",
" tech_stack:",
]
for item in answers.tech_stack:
lines.append(f" - {yaml_scalar(item)}")
lines.extend(
[
"",
"runtime:",
f" primary_runtime: {answers.primary_runtime}",
" primary_entrypoints:",
]
)
for entrypoint in answers.primary_entrypoints:
lines.append(f" - name: {yaml_scalar(entrypoint.name)}")
lines.append(f" purpose: {yaml_scalar(entrypoint.purpose)}")
lines.extend(["", "interfaces:", " contracts:"])
for contract in interface_contracts:
resolved_inputs = resolve_interface_detail_hints(answers.interface_inputs, contract)
resolved_outputs = resolve_interface_detail_hints(answers.interface_outputs, contract)
resolved_errors = resolve_interface_detail_hints(answers.interface_errors, contract)
lines.append(f" - name: {yaml_scalar(contract.name)}")
lines.append(f" type: {yaml_scalar(contract.interface_type)}")
lines.append(f" actors: {yaml_scalar(contract.actors)}")
lines.append(f" purpose: {yaml_scalar(contract.purpose)}")
lines.append(
f" stability: {yaml_scalar(default_interface_stability(contract.interface_type, answers.capture_mode))}"
)
lines.append(" inputs:")
for item in resolved_inputs or derive_interface_inputs(contract):
lines.append(f" - {yaml_scalar(item)}")
lines.append(" outputs:")
for item in resolved_outputs or derive_interface_outputs(contract):
lines.append(f" - {yaml_scalar(item)}")
lines.append(" errors:")
for item in resolved_errors or derive_interface_errors(contract):
lines.append(f" - {yaml_scalar(item)}")
lines.append(" compatibility_rules:")
for item in resolve_interface_compatibility_rules(answers, contract):
lines.append(f" - {yaml_scalar(item)}")
lines.append(" shared_constraints:")
for item in interface_shared_constraints:
lines.append(f" - {yaml_scalar(item)}")
lines.append(" current_gaps:")
for item in interface_current_gaps:
lines.append(f" - {yaml_scalar(item)}")
lines.extend(["", "structure:"])
if answers.planned_top_level_areas:
lines.append(" planned_top_level_areas:")
for area in answers.planned_top_level_areas:
lines.append(f" - path: {yaml_scalar(area.path)}")
lines.append(f" responsibility: {yaml_scalar(area.responsibility)}")
else:
lines.append(" planned_top_level_areas: []")
lines.extend(["", "data_model:", f" persistence_backend: {yaml_scalar(storage_backend)}", " entities:"])
for index, entity in enumerate(entities):
other_entity = entities[1 - index]
source_entity = entities[0] if index == 1 else None
lines.append(f" - name: {yaml_scalar(entity.name)}")
lines.append(f" purpose: {yaml_scalar(entity.purpose)}")
lines.append(f" source_of_truth: {yaml_scalar(derive_entity_source(storage_backend, index))}")
lines.append(f" lifecycle: {yaml_scalar(derive_entity_lifecycle(index))}")
lines.append(" key_fields:")
for item in derive_entity_fields(index, entity, source_entity):
lines.append(f" - {yaml_scalar(item)}")
lines.append(" relationships:")
for item in derive_entity_relationships(index, entity, other_entity):
lines.append(f" - {yaml_scalar(item)}")
lines.append(" state_rules:")
for item in derive_entity_state_rules(index, entity, other_entity):
lines.append(f" - {yaml_scalar(item)}")
lines.append(" consistency_rules:")
for item in consistency_rules:
lines.append(f" - {yaml_scalar(item)}")
lines.append(" persistence_notes:")
for item in persistence_notes:
lines.append(f" - {yaml_scalar(item)}")
lines.append(" current_gaps:")
for item in model_current_gaps:
lines.append(f" - {yaml_scalar(item)}")
lines.extend(["", "notes:"])
if answers.known_unknowns:
lines.append(" known_unknowns:")
for item in answers.known_unknowns:
lines.append(f" - {yaml_scalar(item)}")
else:
lines.append(" known_unknowns: []")
lines.extend(
[
"",
"metadata:",
f" captured_at_kst: {yaml_scalar(kst_timestamp())}",
" source: stagepilot-bootstrap-seed.py",
f" updated_from: {updated_from}",
"",
]
)
return "\n".join(lines)
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description="Create .stagepilot/bootstrap/baseline.yaml from StagePilot bootstrap answers.",
)
parser.add_argument("host_root", nargs="?", default=".", help="Host repository root. Defaults to the current directory.")
parser.add_argument("--output", help="Explicit output path. Defaults to HOST_ROOT/.stagepilot/bootstrap/baseline.yaml.")
parser.add_argument("--force", action="store_true", help="Overwrite an existing seed file.")
parser.add_argument("--dry-run", action="store_true", help="Print the generated seed to stdout without writing a file.")
parser.add_argument("--non-interactive", action="store_true", help="Require explicit CLI answers instead of interactive prompts.")
parser.add_argument("--capture-mode", choices=("declared", "observed", "mixed"), help="Seed capture mode.")
parser.add_argument("--repository-name", help="Repository name stored in the seed. Defaults to the host root folder name.")
parser.add_argument("--display-name", help="Display name stored in the seed. Defaults to a title-cased repository name.")
parser.add_argument("--project-summary", help="One-sentence project summary.")
parser.add_argument("--primary-domain", help="Primary domain noun phrase.")
parser.add_argument("--tech-stack", help="Comma-separated technology list.")
parser.add_argument("--primary-runtime", choices=RUNTIME_CHOICES, help="Primary runtime type.")
parser.add_argument(
"--primary-entrypoint",
action="append",
default=[],
help="Primary entrypoint line in 'name :: purpose' format. Repeat up to 3 times.",
)
parser.add_argument(
"--top-level-area",
action="append",
default=[],
help="Optional top-level area in 'path :: responsibility' format.",
)
parser.add_argument(
"--interface-contract",
action="append",
default=[],
help="Optional interface contract in 'name :: type :: actors :: purpose' format. Repeat up to 2 times.",
)
parser.add_argument(
"--interface-input",
action="append",
default=[],
help="Optional interface input in 'interface-name :: input contract or invocation note' format.",
)
parser.add_argument(
"--interface-output",
action="append",
default=[],
help="Optional interface output in 'interface-name :: output contract or artifact' format.",
)
parser.add_argument(
"--interface-error",
action="append",
default=[],
help="Optional interface error in 'interface-name :: error code or failure behavior' format.",
)
parser.add_argument(
"--core-entity",
action="append",
default=[],
help="Optional core entity in 'name :: purpose' format. Repeat up to 2 times.",
)
parser.add_argument("--persistence-backend", help="Optional primary persistence backend or storage system.")
parser.add_argument(
"--compatibility-rule",
action="append",
default=[],
help="Optional compatibility rule in 'interface-name :: rule' format. Use '* :: rule' for a shared rule.",
)
parser.add_argument(
"--known-unknown",
action="append",
default=[],
help="Optional unresolved bootstrap note. Repeat for multiple items.",
)
return parser
def main() -> int:
parser = build_parser()
args = parser.parse_args()
host_root = Path(args.host_root).resolve()
if not host_root.exists() or not host_root.is_dir():
return fail(f"host root not found: {host_root}")
output_path = Path(args.output).resolve() if args.output else host_root / ".stagepilot/bootstrap/baseline.yaml"
try:
answers = collect_answers(args, host_root)
content = render_seed(answers)
except ValueError as error:
return fail(str(error))
except EOFError:
return fail("input ended before the questionnaire was completed")
if args.dry_run:
print(content, end="")
return 0
if output_path.exists() and not args.force:
return fail(f"seed file already exists: {output_path}. Use --force to overwrite.")
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_text(content, encoding="utf-8")
log(f"wrote {output_path}")
log("Next: run /bootstrap-baseline in Copilot Chat to render baseline docs from the seed.")
return 0
if __name__ == "__main__":
sys.exit(main())
File diff suppressed because it is too large Load Diff
+182
View File
@@ -0,0 +1,182 @@
---
name: bootstrap-baseline
description: "Use when: initializing StagePilot in a project before the first real Discovery, running /bootstrap-baseline to create baseline documents and active indexes, or backfilling missing docs/project-structure.md, docs/runtime-flows.md, docs/interface-contract.md, and docs/data-model.md without creating a Discovery unit."
argument-hint: "예: 신규 저장소 baseline 초기화, StagePilot init, baseline 문서/인덱스 생성"
user-invocable: true
---
# Purpose
This skill initializes the StagePilot baseline outside the normal Discovery -> REQ -> Batch -> Release flow.
`docs/project-structure.md`, `docs/runtime-flows.md`, `docs/interface-contract.md`, `docs/data-model.md`, 그리고 active index 문서는 첫 real Discovery 전에 준비하는 bootstrap 산출물이다. 이 skill은 baseline과 index를 먼저 만들고, 첫 Discovery가 실제 제품/서비스 변경 주제로 시작되도록 만든다.
greenfield 저장소처럼 읽을 코드나 설정이 아직 없으면, 이 skill은 사용자에게 최소 질문 세트를 묻고 `.stagepilot/bootstrap/baseline.yaml` seed를 만든 뒤 baseline 문서를 렌더링한다.
# When to use
다음 상황에서 사용한다.
- StagePilot을 새 프로젝트에 처음 적용한 직후 baseline 문서와 index를 만들 때
- `/bootstrap-baseline` 또는 유사한 init 요청으로 baseline 초기화를 수행할 때
- `docs/project-structure.md`, `docs/runtime-flows.md`, `docs/interface-contract.md`, `docs/data-model.md`, `docs/discovery/index.md`, `docs/srs/index.md`, `docs/batches/index.md`, `docs/releases/index.md` 중 일부가 없어서 SDLC를 시작하기 전에 뼈대를 복구해야 할 때
- 첫 real Discovery를 기능, 운영 문제, 기술 결정 같은 실제 변경 주제로 시작하고 싶을 때
다음 상황에는 이 skill을 기본 경로로 사용하지 않는다.
- 이미 진행 중인 Discovery/REQ/Batch/Release가 있고, baseline 변경 책임이 특정 active unit에 속하는 경우
- 실제 제품/서비스 변경 주제가 이미 명확하여 Discovery 초안 생성이 우선인 경우
# Inputs
이 skill은 아래 입력을 사용한다.
- 현재 저장소 루트와 디렉터리 구조
- `docs/discovery/`, `docs/srs/`, `docs/batches/`, `docs/releases/` 존재 여부
- `.stagepilot/bootstrap/baseline.yaml` 존재 여부
- `docs/project-structure.md`, `docs/runtime-flows.md`, `docs/interface-contract.md`, `docs/data-model.md` 존재 여부
- 템플릿 파일
- `.github/templates/bootstrap/baseline-seed.yaml`
- `.github/templates/discovery/index.md`
- `.github/templates/srs/index.md`
- `.github/templates/batches/index.md`
- `.github/templates/releases/index.md`
- `.github/templates/project-structure.md`
- `.github/templates/runtime-flows.md`
- `.github/templates/interface-contract.md`
- `.github/templates/data-model.md`
- 현재 시각 (KST)
# Core Rules
## 0. 단위 경계
- `bootstrap-baseline`은 Discovery, REQ, Batch, Release 중 어느 것도 아니다.
- 이 skill은 초기 운영 기준선을 만드는 bootstrap 단계다.
- 이 skill은 Discovery 문서를 생성하지 않는다.
- baseline 초기화가 끝난 뒤 첫 real Discovery는 실제 제품/서비스 변경, 운영 이슈, 기술 결정 같은 주제로 시작한다.
## 1. 생성 대상
- 아래 경로가 없으면 생성한다.
- `.stagepilot/bootstrap/baseline.yaml`
- `docs/discovery/index.md`
- `docs/srs/index.md`
- `docs/batches/index.md`
- `docs/releases/index.md`
- `docs/project-structure.md`
- `docs/runtime-flows.md`
- `docs/interface-contract.md`
- `docs/data-model.md`
- 이미 존재하는 파일은 임의로 덮어쓰지 않는다.
- 일부만 없는 경우에는 누락된 파일만 생성한다.
## 1.5 최소 질문 세트
- 저장소 관찰만으로 baseline 핵심 정보가 부족하면 먼저 질문을 수행한다.
- 질문은 아래 다섯 개를 기본 세트로 사용한다.
- `project-summary`
- 질문: `이 프로젝트를 한 문장으로 설명하면 무엇인가?`
- 답변 형식: 한 문장 자유 텍스트
- `primary-domain`
- 질문: `이 프로젝트의 주요 도메인은 무엇인가?`
- 답변 형식: 짧은 명사구 또는 분야명
- `tech-stack`
- 질문: `계획 중인 주 언어, 프레임워크, 핵심 인프라는 무엇인가?`
- 답변 형식: 쉼표로 구분한 목록
- `primary-runtime`
- 질문: `계획 중인 주 실행 형태는 무엇인가?`
- 답변 형식: `cli` | `api-service` | `web-app` | `worker` | `library` | `mixed` | `other`
- `primary-entrypoints`
- 질문: `대표 진입점 1~3개를 적어 달라.`
- 답변 형식: 줄마다 `name :: purpose`
- 아래 질문은 선택 입력이다.
- `planned-top-level-areas`
- 질문: `이미 알고 있는 top-level 경로가 있으면 적어 달라.`
- 답변 형식: 줄마다 `path :: responsibility`
- `interface-contracts`
- 질문: `대표 인터페이스 1~2개가 있으면 적어 달라.`
- 답변 형식: 줄마다 `name :: type :: actors :: purpose`
- `interface-inputs`
- 질문: `각 인터페이스의 대표 input을 적어 달라.`
- 답변 형식: 줄마다 `interface-name :: input contract or invocation note`
- `interface-outputs`
- 질문: `각 인터페이스의 대표 output을 적어 달라.`
- 답변 형식: 줄마다 `interface-name :: output contract or artifact`
- `interface-errors`
- 질문: `각 인터페이스의 대표 error를 적어 달라.`
- 답변 형식: 줄마다 `interface-name :: error code or failure behavior`
- `core-entities`
- 질문: `핵심 엔티티 1~2개가 있으면 적어 달라.`
- 답변 형식: 줄마다 `name :: purpose`
- `persistence-backend`
- 질문: `주 persistence backend가 있으면 적어 달라.`
- 답변 형식: 짧은 backend 또는 storage 이름
- `compatibility-rules`
- 질문: `인터페이스 호환성 규칙이 있으면 적어 달라.`
- 답변 형식: 줄마다 `interface-name :: rule` 또는 `* :: rule`
- `known-unknowns`
- 질문: `아직 미정인 핵심 항목이 있으면 적어 달라.`
- 답변 형식: 줄마다 항목 하나
- 이미 읽을 수 있는 저장소 증거가 있으면 질문 수를 줄이고, seed의 비어 있는 값만 보충한다.
- `interface-contracts`, `interface-inputs`, `interface-outputs`, `interface-errors`, `core-entities`, `persistence-backend`, `compatibility-rules`가 비어 있더라도 bootstrap은 `runtime`, `primary-entrypoints`, `primary-domain`, `tech-stack`, `planned-top-level-areas`, `known-unknowns`를 바탕으로 기본 초안을 유도해 seed를 보강할 수 있다.
## 1.6 seed 파일 source-of-truth 규칙
- bootstrap 질문 결과와 저장소 관찰 결과의 합성 source of truth는 `.stagepilot/bootstrap/baseline.yaml`이다.
- seed 파일은 active SDLC unit가 아니라 bootstrap 선언 파일이다.
- seed 파일이 있으면 baseline 문서 생성과 갱신 시 이를 우선 읽는다.
- seed 파일이 없고 저장소 증거가 충분하지 않으면 질문 없이 baseline 문서를 추정 생성하지 않는다.
- 저장소 관찰값과 사용자 답변이 함께 있으면 `capture_mode`는 `mixed`다.
- 저장소 관찰값만으로 충분하면 `capture_mode`는 `observed`다.
- 사용자 선언이 중심이고 저장소 관찰값은 보조면 `capture_mode`는 `declared`다.
## 2. baseline 문서 작성 원칙
- `docs/project-structure.md`는 seed의 `project`, `stack`, `runtime`, `structure` 값을 먼저 반영하고, 저장소 관찰 결과가 있으면 보강한다.
- `docs/runtime-flows.md`는 seed의 `runtime`과 `notes` 값을 먼저 반영하고, 저장소 관찰 결과가 있으면 보강한다.
- `docs/interface-contract.md`는 seed의 `interfaces` 섹션을 먼저 반영하고, 값이 부족하면 `runtime`, `primary-entrypoints`, `known-unknowns`를 바탕으로 대표 외부 API, CLI, 이벤트, 파일 I/O 계약의 기본 초안을 구체화한다.
- `docs/data-model.md`는 seed의 `data_model` 섹션을 먼저 반영하고, 값이 부족하면 `primary-domain`, `tech-stack`, `planned-top-level-areas`, `known-unknowns`를 바탕으로 핵심 엔티티, 관계, 상태, persistence 규칙의 기본 초안을 구체화한다.
- 입력만으로 알 수 없는 항목은 의미 있는 플레이스홀더로 남기되, 추론 가능한 구조 정보는 실제 문장으로 채운다.
- baseline 문서의 `Source Discovery / Batch`는 bootstrap 산출물임을 드러내는 값으로 채운다.
- baseline 문서는 `declared`, `observed`, `mixed` 중 어느 모드로 렌더링되었는지와 seed 경로를 드러내야 한다.
## 3. index 작성 원칙
- index 문서는 템플릿을 기반으로 생성한다.
- 초기화 시점에는 register 본문만 만들고 실제 Discovery/REQ/Batch/Release 항목은 비워 둔다.
- index 생성은 active unit 생성으로 간주하지 않는다.
## 4. 진행 중 unit가 있는 경우
- 진행 중인 Discovery/REQ/Batch/Release가 이미 있고 baseline 문서만 일부 비어 있다면, 먼저 현재 active unit가 그 변경을 소유해야 하는지 판정한다.
- 특정 active unit의 요구사항이나 설계/검증 근거로 baseline 변경이 필요한 경우에는 그 unit 안에서 처리한다.
- 단순 bootstrap 누락 복구이고 active unit 책임이 아니라면 `bootstrap-baseline`으로 누락 파일만 보강할 수 있다.
# Execution Procedure
1. 저장소에서 active docs 루트와 baseline 파일 존재 여부를 확인한다.
2. `.stagepilot/bootstrap/baseline.yaml`이 없거나 핵심 필드가 비어 있으면 저장소 관찰로 채울 수 있는 값과 질문이 필요한 값을 분리한다.
3. 저장소 관찰만으로 부족하면 최소 질문 세트를 사용해 사용자 선언 입력을 수집한다.
4. `.github/templates/bootstrap/baseline-seed.yaml`를 기준으로 `.stagepilot/bootstrap/baseline.yaml`을 생성 또는 보강한다.
5. 누락된 디렉터리가 있으면 `docs/discovery`, `docs/srs`, `docs/batches`, `docs/releases`를 먼저 준비한다.
6. 누락된 index 파일을 각 템플릿으로 생성한다.
7. seed 파일과 저장소 상태를 반영해 `docs/project-structure.md`, `docs/runtime-flows.md`, `docs/interface-contract.md`, `docs/data-model.md`를 생성 또는 보강한다.
8. 이미 존재하는 파일은 보존하고, 필요한 경우에만 누락 복구 또는 seed 반영 사실을 결과에 기록한다.
9. 완료 후 다음 단계로 `new-discovery`를 사용해 첫 real Discovery를 시작하도록 안내한다.
# Output Expectations
- 생성 또는 복구한 파일 목록
- seed 파일 상태 (`created` | `preserved` | `updated`)
- baseline 문서 상태 (`created` | `preserved` | `missing-information`)
- index 문서 상태 (`created` | `preserved`)
- 첫 real Discovery에서 다뤄야 할 주제 후보 또는 다음 action
# Validation
- 생성한 파일 경로가 active docs 구조와 일치하는지 확인한다.
- `.stagepilot/bootstrap/baseline.yaml`의 필수 필드가 비어 있지 않은지 확인한다.
- baseline 문서와 index에 남아 있는 플레이스홀더가 정말 사람 결정이 필요한 값인지 점검한다.
- baseline 문서의 `Project Summary`, `Primary Domain`, `Tech Stack`, `Primary Runtime`와 공통 계약 정보가 seed 및 저장소 관찰과 모순되지 않는지 확인한다.
- Discovery 문서를 생성하지 않았는지 확인한다.
@@ -0,0 +1,38 @@
---
name: capture-release-feedback
description: "Use when: recording post-release observations, running /capture-release-feedback with a REL ID, appending feedback and follow-up inputs to docs/releases/rel-XXX_*.md, or marking included batches as released after deployment feedback is captured."
argument-hint: "예: rel-001 또는 docs/releases/rel-001_20260424_scaffold.md"
user-invocable: true
---
# Purpose
This skill records post-release observations, converts them into follow-up Discovery or REQ inputs, and closes the release with captured feedback.
# Inputs
- `REL-ID` 또는 release 경로
- 운영 관찰 결과
- 대상 release 문서
- 포함 batch 목록
- `docs/releases/index.md`
- `docs/batches/index.md`
# Core Rules
- 운영 관찰 결과는 사실과 후속 입력으로 분리해 기록한다.
- 후속 입력은 `Discovery Input`, `REQ Input`, `Change Request Input`으로 구분한다.
- release feedback을 남긴 뒤 release 상태는 `feedback-captured`로 전환할 수 있다.
- 포함 batch 상태는 필요하면 `released`로 갱신한다.
# Execution Procedure
1. release 문서와 포함 batch를 읽는다.
2. 운영 관찰 결과를 release 문서의 Feedback Handoff 섹션에 반영한다.
3. 후속 Discovery 입력, 신규 REQ 입력, 기존 REQ 변경 후보를 분리해 기록한다.
4. release index 상태를 `feedback-captured`로 갱신하고, 포함 batch 상태를 `released`로 조정한다.
# Validation
- release 문서에 운영 관찰 결과와 `Discovery Input`, `REQ Input`, `Change Request Input`이 모두 남았는지 확인한다.
- release index 상태와 batch index 상태가 문서 본문과 일치하는지 확인한다.
+96
View File
@@ -0,0 +1,96 @@
---
name: change-req
description: "Use when: updating an existing requirement after approval or implementation, running /change-req with a REQ ID or file path, recording a change-request entry before overwriting a REQ, analyzing impacted batches/releases, or deciding whether an Implemented REQ must be downgraded and reverified."
argument-hint: "예: req-001 또는 docs/srs/Documentation/req-001_minor-docs.md"
user-invocable: true
---
# Purpose
This skill applies a controlled change to an existing REQ by recording a new change-request entry before editing the requirement body, analyzing downstream delivery impact, and updating status/index state when the prior implementation is no longer valid.
# When to use
- `/change-req req-001`처럼 기존 REQ의 Requirement, Acceptance Criteria, Impacted Area를 수정해야 할 때
- 운영 피드백이나 release feedback에서 기존 REQ 수정 필요가 확인됐을 때
- `Implemented` 또는 `Approved` REQ가 더 이상 현재 구현/검증 증거와 맞지 않는지 판단해야 할 때
- `docs/srs/index.md`의 REQ 상태와 실제 변경 영향 범위를 다시 동기화해야 할 때
# Inputs
- 선택 입력
- `REQ-ID` prefix
- REQ 파일 경로
- 변경 요청 근거
- 사용자 요청
- release feedback
- batch verification 또는 implementation 결과
- 대상 REQ 문서
- `docs/srs/index.md`
- 관련 `docs/batches/index.md`
- 관련 `docs/releases/index.md`
- 영향이 의심되는 batch/release 문서들
# Core Rules
## 1. 입력 해석
- prefix 입력이면 `docs/srs/**/req-001_*.md` 형식으로 찾는다.
- 동일 prefix에 여러 문서가 매칭되면 임의 선택하지 않는다.
- REQ가 `Deprecated`면 기본적으로 새 변경 요청 대상으로 삼지 않는다. 복구가 필요하면 근거를 먼저 명시한다.
## 2. 변경 요청 기록 규칙
- 기존 `Requirement`, `Acceptance Criteria`, `Impacted Area`를 덮어쓰기 전에 새 `Change Log` 항목을 추가한다.
- 새 변경 항목 ID는 `CHG-YYYYMMDD-NN` 형식을 사용하고 같은 날짜 내에서 순차 증가시킨다.
- 새 항목에는 최소한 아래를 모두 기록한다.
- `Change Summary`
- `Intent`
- `Acceptance Criteria Delta`
- `Impacted Area Delta`
- `Delivery Trace Delta`
- `Revalidation Impact`
- `Validation Plan`
- 과거 `Change Log` 항목은 삭제하거나 덮어쓰지 않는다.
## 3. 상태 영향 규칙
- 변경이 기존 구현 또는 verification evidence를 무효화하지 않으면 현재 상태를 유지할 수 있다.
- `Implemented` REQ의 기존 구현/검증 근거가 깨지면 상태를 `Approved`로 되돌린다.
- 변경이 승인 전제 자체를 다시 검토하게 만들면 상태를 `Proposed`로 되돌릴 수 있다.
- 상태를 되돌릴 때는 이유를 `Revalidation Impact`와 `Change Log`에 함께 남긴다.
- 상태가 바뀌면 `docs/srs/index.md`의 Register와 `Recent Change Log Summary`도 함께 갱신한다.
## 4. 영향 분석 규칙
- 관련 batch가 있으면 어떤 batch planning/design/verification이 다시 검토되어야 하는지 기록한다.
- 관련 release가 있으면 release 문서를 직접 덮어쓰지 말고 영향 범위와 후속 action을 REQ의 `Change Log`에 남긴다.
- 사람 판단이 필요한 범위 재정의, 우선순위 변경, 정책 변경은 임의 확정하지 않는다.
# Execution Procedure
1. 입력에서 대상 REQ 경로를 확정한다.
2. REQ 현재 상태와 최근 `Change Log`를 읽는다.
3. `docs/batches/index.md`, `docs/releases/index.md`, 관련 batch/release 문서를 읽어 현재 delivery trace를 요약한다.
4. 변경 요청 근거를 기존 구현/검증 상태와 비교한다.
5. 새 `Change Log` 항목을 먼저 추가하고 delta, trace, revalidation impact를 채운다.
6. 그 다음 REQ 본문(`Requirement`, `Acceptance Criteria`, `Impacted Area`, `Notes`)을 필요한 만큼 수정한다.
7. 상태 유지 또는 상태 되돌림 필요 여부를 결정해 REQ 본문과 `docs/srs/index.md`를 갱신한다.
8. `Recent Change Log Summary`에 최신 변경 항목을 반영한다.
# Output Expectations
- 대상 REQ 경로
- 새 `Change Log` 항목 ID
- 변경 요약
- 영향 받는 batch/release 목록
- 재검증 필요 여부
- 상태 유지 또는 상태 되돌림 결과
- `docs/srs/index.md` 갱신 결과
# Validation
- `Change Log` 새 항목이 REQ 본문 수정보다 앞선 시간순 근거로 남았는지 확인한다.
- `Acceptance Criteria Delta`, `Delivery Trace Delta`, `Revalidation Impact`가 모두 채워졌는지 확인한다.
- 상태 되돌림이 필요한 경우 REQ 문서와 `docs/srs/index.md` 상태가 함께 바뀌었는지 확인한다.
- 관련 batch/release 영향이 `Change Log`에 누락되지 않았는지 확인한다.
@@ -0,0 +1,38 @@
---
name: confirm-batch-verification
description: "Use when: approving a batch verification result, running /confirm-batch-verification with a BAT ID, promoting docs/batches/<BAT_ID> to release-candidate, or updating docs/batches/index.md after verification passes."
argument-hint: "예: bat-001 또는 docs/batches/bat-001_20260424_scaffold"
user-invocable: true
---
# Purpose
This skill checks whether a batch verification document has enough evidence to release the batch and, if so, promotes the batch to `release-candidate`.
# Inputs
- `BAT-ID` 또는 batch 경로
- `docs/batches/<BAT_ID>/verification.md`
- 포함된 REQ 문서들
- `docs/batches/index.md`
# Core Rules
- verification에 미해결 blocker가 있으면 승인하지 않는다.
- 포함된 REQ의 acceptance criteria가 evidence와 연결돼야 한다.
- `batch-lite`는 design 문서 없이도 승인할 수 있지만, planning의 `Design Gate`가 design 불필요를 명시하고 verification이 구조 영향 없음 또는 baseline 영향 없음을 확인해야 한다.
- 승인 성공 시 batch status는 `release-candidate`가 된다.
# Execution Procedure
1. batch와 verification 문서를 읽는다.
2. 필요하면 planning과 design을 함께 읽어 profile과 구조 영향 여부를 확인한다.
3. Acceptance Mapping, Evidence, Blocking Issues를 점검한다.
4. 승인 가능하면 verification 상태와 batch index 상태를 갱신한다.
5. 승인 불가면 상태는 유지하고 blocker를 보고한다.
# Validation
- 승인 성공인 경우 batch index 상태가 `release-candidate`인지 확인한다.
- 승인 보류인 경우 blocker가 명시됐는지 확인한다.
- `batch-lite` 승인 성공인 경우 design 부재가 검증 근거와 모순되지 않는지 확인한다.
+208
View File
@@ -0,0 +1,208 @@
---
name: confirm-discovery
description: "Use when: running /confirm-discovery with dcy-xyz or a Discovery path, re-checking the current repository state against docs/discovery/*.md, filling AI-resolvable placeholders or inconsistencies, and promoting the Discovery to confirmed when it is ready for REQ drafting in the Requirements phase."
argument-hint: "예: dcy-001 또는 docs/discovery/dcy-001_20260424_krx-stock-picker-python-scaffold.md"
user-invocable: true
---
# Purpose
This Skill revalidates an existing Discovery document against the current repository state, fills anything the AI can resolve from local evidence, and promotes the document to `confirmed` only when REQ drafting handoff has no remaining blockers.
이 Skill의 결과는 아래 두 경우로 나뉜다.
- 확인 결과 승인 가능이면 대상 Discovery 문서를 `confirmed`로 전환하고 `docs/discovery/index.md`의 해당 행 상태를 함께 갱신한다.
- 승인까지는 불가하더라도 AI가 근거 있게 채울 수 있는 항목이 있으면 문서를 먼저 보강한다. 단, 이 경우 `confirmed` 전환과 REQ drafting 준비 플래그 변경은 하지 않는다.
# When to use
다음 상황에서 사용한다.
- `/confirm-discovery dcy-xyz` 형태로 기존 Discovery를 최종 확인해야 할 때
- `docs/discovery/` 아래 Discovery 초안 문서를 REQ 초안 작성 가능 상태로 승격해야 할 때
- 현재 저장소 구현 상태를 다시 확인해 Discovery 본문의 사실 관계를 정정하거나 보강해야 할 때
- 문서 안의 플레이스홀더 중 AI가 근거 있게 채울 수 있는 항목을 먼저 정리한 뒤 승인 가능 여부를 판정해야 할 때
- `docs/discovery/index.md`의 상태가 실제 Discovery 상태와 일치하는지 함께 맞춰야 할 때
# Inputs
이 Skill은 아래 입력을 사용한다.
- Discovery 식별자
- `dcy-001` 같은 축약 ID
- `dcy-001_20260424_topic-slug` 같은 전체 Discovery ID
- `docs/discovery/<DISCOVERY_ID>.md` 같은 직접 경로
- Discovery 문서 본문
- `docs/discovery/index.md`
- 현재 저장소 구현 상태
- 관련 소스 파일
- 설정 파일
- 관련 문서
- 현재 시각 (KST)
# Core Rules
## 1. 입력 해석 규칙
- 입력이 `dcy-001`처럼 prefix만 주어지면 `docs/discovery/` 아래에서 해당 prefix로 시작하는 문서를 찾는다.
- 입력이 전체 Discovery ID면 `docs/discovery/<DISCOVERY_ID>.md`를 직접 찾는다.
- 입력이 파일 경로면 해당 경로를 그대로 사용한다.
- 매칭 결과가 0개면 자동 진행하지 않고 사용자에게 입력을 재확인하도록 알린다.
- 같은 prefix에 대해 여러 문서가 매칭되면 임의 선택하지 않고 후보 목록을 보여 준 뒤 사용자 확인을 요청한다.
- `.vendor/` 경로는 탐색 대상에서 제외한다.
## 2. 현재 구현 상태 재확인 규칙
- 현재 구현 상태 확인은 요구사항이 이미 모두 구현되었는지 검사하는 절차가 아니다.
- 이 확인의 목적은 Discovery의 `현재 상태`, `영향 범위`, `성공 기준`, `체크 항목`, `사용자 결정 필요 항목`이 저장소 현실과 맞는지 검증하는 것이다.
- 구현 부재 자체는 차단 사유가 아니다. Discovery가 애초에 신규 작업을 정의하는 문서라면 코드가 없는 상태도 정상일 수 있다.
- 차단이 되는 경우는 아래와 같다.
- 문서가 이미 존재한다고 적은 구현이 실제 저장소에는 없어서 본문 사실 관계가 틀린 경우
- 저장소 현실이 문서의 핵심 범위, 사용자 시나리오, 성공 기준을 다시 써야 할 정도로 바뀐 경우
- 문서의 남은 결정 항목이 여전히 사람 판단을 필요로 하는데 승인 상태로 올리려는 경우
## 3. 승인 전 보강 규칙
승인 판정 전에 먼저 아래 보강 절차를 수행한다.
### 3-1. 일관성 검토
- 용어 혼용, 범위 충돌, 중복 서술, 번호 누락을 확인한다.
- `# 5. 요구사항 목록`, `# 6. 리스크/가정 목록`, `# 7. 초기 성공 기준`, `# 8. REQ로 넘기기 전 확인 체크`, `# 10. 사용자 결정 필요 항목 요약`, `# 11. Discovery Freeze`의 연결 관계를 확인한다.
- 문장만 다르고 같은 의미를 반복하는 부분은 간결하게 정리한다.
- 문법, 오타, 링크 형식, 체크리스트 표현을 함께 정리한다.
### 3-2. 증거 기반 보강
- Discovery 본문에서 이슈명, 핵심 변경 항목, FR/NFR, 범위 경계를 읽고 키워드를 추출한다.
- 키워드를 바탕으로 저장소에서 관련 파일, 설정, 문서를 탐색한다.
- 탐색 결과는 최소한 아래 판단으로 정리한다.
- 이미 존재함
- 일부 존재함
- 아직 없음
- 문서와 모순됨
- AI가 아래 근거로 확정 가능한 항목은 실제 문장으로 치환한다.
- 같은 Discovery 문서 안 다른 섹션에 이미 답이 있는 항목
- 현재 저장소 파일 구조, 설정, 문서에서 직접 확인 가능한 항목
- 승인 행위 시각처럼 현재 실행 시점에 자동 확정 가능한 항목
- 아래 항목은 추론만으로 확정하지 않는다.
- 정책 선택
- 우선순위 승인
- 외부 시스템 또는 외부 데이터 확인 결과
- 승인자 지명처럼 사람 책임을 수반하는 결정
### 3-3. 플레이스홀더 분류 기준
- A. 승인 시점 자동 채움
- 예: `{{DATA_CONFIRMED_AT_KST:...}}`, `{{CONFIRMED_AT_KST:...}}`
- 승인 성공 시 현재 시각으로 채운다.
- B. 증거 기반 해소 가능
- 문서 다른 섹션, 저장소 구조, 이미 확정된 값으로 해소 가능한 플레이스홀더다.
- 승인 성공 여부와 무관하게 먼저 채운다.
- C. 사람 결정 또는 외부 확인 필요
- `{{DECIDE_*}}`, `{{CONFIRM_*}}`, `{{DATA_*}}` 중 아직 문서와 저장소 근거만으로 해소되지 않는 항목이다.
- 승인 차단 대상이다.
- 승인 판정 직전에는 A와 B만 남아 있어야 한다.
- B로 분류한 항목을 채운 뒤에도 `# 1`부터 `# 10` 사이에 C 유형 플레이스홀더가 남아 있으면 승인하지 않는다.
## 4. 최종 승인 게이트
아래 조건을 모두 만족해야 `confirmed`로 전환한다.
- 문서 상태가 아직 `confirmed`가 아니어야 한다.
- B 유형 보강 이후 C 유형 플레이스홀더가 0개여야 한다.
- `# 6. 리스크/가정 목록`의 오픈 질문에 `상태: Open` 항목이 없어야 한다.
- `# 8. REQ로 넘기기 전 확인 체크`에 남아 있는 미완료 항목이 있다면, 그 항목이 REQ 초안 작성을 막지 않는다고 문서에 명시되어 있어야 한다. 그렇지 않으면 차단한다.
- `# 10. 사용자 결정 필요 항목 요약`에 남은 항목이 모두 `없음`이거나, 문서 안에서 이미 답이 반영되어 제거 가능해야 한다.
- `# 11. Discovery Freeze`에 `Confirmed By`가 비어 있지 않아야 한다.
- 현재 저장소 상태가 Discovery의 핵심 범위나 요구사항을 다시 정의해야 할 정도로 모순되지 않아야 한다.
다음 경우는 `confirmed` 전환 대신 보류한다.
- Discovery 초안이 아니라 사실상 새 Discovery 생성 또는 대규모 범위 재정의가 필요한 경우
- 확인 과정에서 FR/NFR, In Scope/Out of Scope, 성공 기준을 실질적으로 다시 써야 하는 경우
- 승인자 또는 필수 결정 사항이 여전히 문서 밖 사람 판단에 의존하는 경우
## 5. 허용되는 수정 범위
이 Skill은 아래 수정만 수행한다.
- AI가 근거 있게 채울 수 있는 플레이스홀더 치환
- 현재 저장소 상태에 맞춘 사실 관계 보정
- 표현, 번호, 체크리스트, 링크의 일관성 정리
- 실제 문서 변경이 있었다면 `마지막 갱신 시각(KST)` 갱신
- 승인 가능 시 아래 상태 전환 수행
- `# 0. 문서 상태`의 `상태`를 `confirmed`로 변경
- `# 11. Discovery Freeze`의 `Handoff Decision`을 `승인`으로 변경
- `# 11. Discovery Freeze`의 `Ready for REQ Drafting`을 `true`로 변경
- `Confirmed At (KST)`를 현재 시각으로 채움
- `docs/discovery/index.md`의 해당 Discovery 행 상태를 `confirmed`로 갱신
아래 상황이면 상태 전환 없이 보강만 하고 종료한다.
- C 유형 플레이스홀더가 남아 있는 경우
- 오픈 질문 또는 사용자 결정 항목이 남아 있는 경우
- 승인 자체보다 먼저 Discovery 내용 재정비가 필요한 경우
# Repository Exploration
현재 구현 상태를 다시 확인할 때는 아래 순서로 저장소를 탐색한다.
1. Discovery 문서에서 이슈명, 핵심 변경 항목, FR/NFR, 범위 경계 키워드를 뽑는다.
2. 키워드 기준으로 관련 소스, 설정, 문서를 찾는다.
3. 아래 항목은 기본적으로 제외한다.
- 테스트 파일
- 의존성 잠금 파일
- `.vendor/` 하위 파일
4. 탐색 결과를 아래 형태로 정리한다.
- 관련 파일 경로 목록
- 이미 구현된 내용
- 일부만 구현된 내용
- 아직 없는 내용
- 문서와 모순되는 내용
5. 탐색 결과는 Discovery 보강과 승인 게이트 판단에만 사용한다.
# Execution Procedure
다음 순서대로 작업한다.
1. 입력에서 Discovery 문서 경로를 확정한다.
2. 대상 Discovery 문서와 `docs/discovery/index.md`를 읽는다.
3. Discovery의 핵심 범위, FR/NFR, 오픈 질문, 체크리스트, 사용자 결정 필요 항목을 추출한다.
4. 위 `Repository Exploration` 규칙에 따라 현재 저장소 상태를 확인한다.
5. 문서 전체를 검토해 일관성 오류와 플레이스홀더를 나열한다.
6. B 유형 플레이스홀더와 명백한 사실 관계 오류를 먼저 수정한다.
7. 문서 내용이 바뀌었다면 `마지막 갱신 시각(KST)`를 현재 시각으로 갱신한다.
8. 다시 한 번 `최종 승인 게이트`를 평가한다.
9. 게이트를 통과하면 A 유형 플레이스홀더를 채우고 문서를 `confirmed`로 전환한다.
10. 게이트를 통과하면 `docs/discovery/index.md`의 해당 행 상태도 `confirmed`로 갱신한다.
11. `docs/discovery/index.md`에 해당 Discovery 행이 없으면 현재 문서 메타데이터를 기준으로 같은 테이블 형식의 행을 추가한다.
12. 게이트를 통과하지 못하면 상태는 유지하고, 보강된 내용과 남은 차단 항목만 보고한다.
# Output Expectations
작업이 끝나면 아래 내용을 보고할 수 있어야 한다.
- 대상 `DISCOVERY_ID`와 문서 경로
- 현재 저장소 상태 재확인 결과 요약
- AI가 자동으로 채운 항목 목록
- 남겨 둔 항목 목록과 남긴 이유
- 최종 판정
- `confirmed 전환 완료`
- `보강만 수행, 승인 보류`
- `문서 변경 없이 승인 보류`
- `docs/discovery/index.md` 갱신 결과
- REQ 초안 작성으로 넘기기 전에 남은 작업 요약
# Validation
완료 전에 아래를 확인한다.
- 대상 경로가 `docs/discovery/<DISCOVERY_ID>.md` 형식을 만족하는지
- 대상 Discovery 문서가 실제로 존재하는지
- 보강 후에도 C 유형 플레이스홀더와 `상태: Open` 오픈 질문이 정확히 식별되었는지
- 승인 완료인 경우 문서 상태와 `docs/discovery/index.md` 상태가 모두 `confirmed`인지
- 승인 보류인 경우 `confirmed`, `승인`, `true` 같은 승인 전환 값이 잘못 들어가지 않았는지
- 문서 본문 보강이 새로운 요구사항 생성이나 범위 재정의로 번지지 않았는지
- 결과 보고에 자동 처리 항목과 차단 항목이 모두 포함되는지
+40
View File
@@ -0,0 +1,40 @@
---
name: confirm-release
description: "Use when: approving a release plan, running /confirm-release with a REL ID or release path, promoting docs/releases/rel-XXX_*.md from draft to confirmed, or validating rollout and rollback readiness before deployment."
argument-hint: "예: rel-001 또는 docs/releases/rel-001_20260424_scaffold.md"
user-invocable: true
---
# Purpose
This skill validates a release document and promotes it to `confirmed` only when rollout, rollback, and verification checks are ready.
# Inputs
- `REL-ID` 또는 release 경로
- 대상 release 문서
- `docs/releases/index.md`
- 포함 batch 문서들
# Core Rules
- Included Batch가 모두 release-candidate여야 한다.
- Rollout Plan, Rollback Plan, Verification Checklist가 비어 있으면 승인하지 않는다.
- release profile에 맞는 검증 항목이 비어 있으면 승인하지 않는다.
- `docs-only`는 링크/렌더링/패키징 검증으로 충분하며 health endpoint를 요구하지 않는다.
- `tooling`은 설치/업데이트/CLI 또는 스크립트 smoke 결과가 있어야 한다.
- `app-service`는 health, 로그, smoke 또는 동등한 운영 확인 근거가 있어야 한다.
- 승인 성공 시 release 상태를 `confirmed`로 바꾸고 index를 갱신한다.
# Execution Procedure
1. release 문서와 포함 batch 상태를 확인한다.
2. rollout, rollback, verification 준비도와 release profile의 필수 검증 항목을 점검한다.
3. 게이트 통과 시 release 상태와 index를 `confirmed`로 갱신한다.
4. 미통과 시 상태는 유지하고 blocker를 보고한다.
# Validation
- 승인 성공인 경우 release 문서와 index 상태가 모두 `confirmed`인지 확인한다.
- 승인 보류인 경우 누락 항목이 명시됐는지 확인한다.
- profile별 검증 항목이 release 문서의 선택된 profile과 모순되지 않는지 확인한다.
@@ -0,0 +1,100 @@
---
name: confirm-req-implemented
description: "Use when: confirming that approved requirements have implementation and verification evidence, running /confirm-req-implemented with a REQ ID, BAT ID, or file path, promoting docs/srs/<Type>/req-XXX_<slug>.md from Approved to Implemented, or updating docs/srs/index.md after batch verification passes."
argument-hint: "예: req-001 또는 bat-001 또는 docs/srs/Interface/req-001_picker-cli-run.md"
user-invocable: true
---
# Purpose
This skill validates that an approved requirement has implementation and verification evidence, then promotes it to `Implemented` only when every acceptance criterion is traceable to delivery evidence.
`Implemented`는 배포 완료 자체를 뜻하지 않는다. 기본 기준은 구현과 검증 증거가 확보된 상태이며, 일반적으로 `release-candidate` 또는 `released` batch의 verification 결과를 근거로 삼는다.
# When to use
- `/confirm-req-implemented req-001`처럼 특정 REQ를 `Implemented`로 전환해야 할 때
- `/confirm-req-implemented bat-001`처럼 batch verification 이후 포함 REQ 상태를 동기화해야 할 때
- `/confirm-req-implemented`처럼 입력 없이 현재 저장소의 `Approved` REQ 중 구현 완료로 승격 가능한 대상을 일괄 점검해야 할 때
- `docs/srs/index.md`의 REQ 상태가 실제 batch verification evidence와 어긋나 있을 때
# Inputs
- 선택 입력
- `REQ-ID` prefix
- REQ 파일 경로
- `BAT-ID` prefix
- batch 경로
- 입력이 없으면 `docs/srs/**/req-*.md` 전체에서 `Status: Approved` REQ를 후보로 찾는다.
- 대상 REQ 문서 또는 대상 batch 문서
- `docs/srs/index.md`
- `docs/batches/index.md`
- 관련 `docs/batches/<BAT_ID>/index.md`
- 관련 `docs/batches/<BAT_ID>/verification.md`
- 필요하면 관련 `docs/batches/<BAT_ID>/implementation.md`
# Core Rules
## 1. 입력 해석
- `req-001` 같은 prefix가 주어지면 `docs/srs/**/req-001_*.md` 형식으로 찾는다.
- `bat-001` 같은 prefix가 주어지면 `docs/batches/` 아래 matching batch를 찾고, 포함 REQ 중 `Approved` 상태만 후보로 삼는다.
- 입력이 없으면 `docs/srs/` 아래에서 `req-template.md`를 제외한 모든 `req-*.md`를 읽고, 그중 `Status: Approved` 문서를 후보로 삼는다.
- 같은 prefix에 여러 문서가 매칭되면 임의 선택하지 않는다.
- 입력이 없는 일괄 모드에서는 여러 후보가 정상이며, 각 후보를 개별 게이트로 평가한다.
## 2. 구현 완료 전환 게이트
- 아래 조건을 모두 만족해야 `Implemented`로 전환한다.
- 대상 REQ의 현재 `Status`가 `Approved`다.
- 연결된 batch가 `release-candidate` 또는 `released` 상태다.
- batch `verification.md`에 해당 REQ의 `Acceptance Mapping`이 존재한다.
- REQ의 모든 `Acceptance Criteria`가 verification evidence와 연결된다.
- batch verification의 `Blocking Issues`가 이 REQ를 미통과 상태로 남기지 않는다.
- release 배포 완료는 필수 조건이 아니다. 구현과 검증 evidence가 충분하면 `release-candidate` 상태에서도 `Implemented` 전환이 가능하다.
- 연결된 batch를 찾지 못하거나 evidence가 부족하면 상태를 바꾸지 않는다.
- 하나의 REQ가 여러 batch에 걸쳐 있고 어떤 batch를 근거로 삼아야 할지 명확하지 않으면 임의로 전환하지 않는다.
## 3. 허용되는 수정
- AI가 근거 있게 정리할 수 있는 오타, 링크, 표현 불일치는 보강할 수 있다.
- 전환 성공 시 아래 변경을 수행한다.
- REQ 문서의 `Status`를 `Implemented`로 변경
- `Change Log`에 구현 완료 전환 기록 추가
- `docs/srs/index.md`의 해당 Register 행 상태를 `Implemented`로 갱신
- 필요하면 `Recent Change Log Summary`를 갱신
- evidence 자체를 새로 만들어 내거나, batch verification의 blocker를 임의 해소하지 않는다.
- 사람 판단이 필요한 범위 변경, acceptance criteria 재정의, batch 재매핑은 임의로 확정하지 않는다.
# Execution Procedure
1. 입력에서 대상 REQ 하나, REQ 목록, 또는 batch 경로를 확정한다.
2. batch 입력인 경우 batch `index.md`에서 Included REQ를 읽고 `Approved` REQ만 후보로 만든다.
3. 입력이 없는 경우 `docs/srs/**/req-*.md`를 스캔해 `Status: Approved` 문서를 후보 목록으로 만든다.
4. 각 후보 REQ에 대해 `docs/batches/index.md`와 batch 문서를 읽어 연결된 batch를 찾는다.
5. 연결된 batch의 `verification.md`에서 REQ acceptance mapping, evidence, blocking issue를 점검한다.
6. 게이트를 통과한 REQ만 `Implemented`로 전환하고 `Change Log`, `docs/srs/index.md`를 갱신한다.
7. 게이트를 통과하지 못한 REQ는 상태를 유지하고 남은 blocker를 수집한다.
8. 입력이 batch 또는 무인자 일괄 모드인 경우, 성공 목록과 보류 목록을 분리해 보고한다.
# Output Expectations
- 단일 입력 모드
- 대상 REQ 또는 batch 경로
- 구현 완료 전환 성공 여부
- 사용한 근거 batch와 verification evidence 요약
- 자동 보강한 항목 목록
- 남은 blocker 또는 미해결 항목
- `docs/srs/index.md` 갱신 결과
- batch/무인자 일괄 모드
- 검토한 REQ 전체 목록
- `Implemented` 전환 성공한 REQ 목록
- 전환 보류한 REQ 목록과 각 blocker
- `docs/srs/index.md` 갱신 결과
# Validation
- 전환 성공인 경우 REQ 문서와 `docs/srs/index.md` 상태가 모두 `Implemented`인지 확인한다.
- 전환 보류인 경우 상태가 잘못 바뀌지 않았는지 확인한다.
- 사용한 verification evidence가 실제 REQ acceptance criteria와 연결되는지 확인한다.
- batch 입력 모드에서는 batch에 포함된 `Approved` REQ만 처리되었는지 확인한다.
+93
View File
@@ -0,0 +1,93 @@
---
name: confirm-req
description: "Use when: reviewing a proposed REQ for approval, running /confirm-req with a REQ ID or file path, running /confirm-req without arguments to review all unapproved REQs, promoting docs/srs/<Type>/req-XXX_<slug>.md from Proposed to Approved, updating docs/srs/index.md after approval, or when the user asks in Korean to '요구 사항 명세를 검토하고 승인해줘', '요구사항 명세를 검토하고 승인해줘', 'REQ를 검토하고 승인해줘', or '승인되지 않은 전체 req를 검토하고 승인해줘'."
argument-hint: "예: req-001 또는 docs/srs/Interface/req-001_picker-cli-run.md 또는 인자 없이 /confirm-req"
user-invocable: true
---
# Purpose
This skill validates a proposed requirement document and promotes it to `Approved` only when it is ready to be used as delivery input.
# When to use
- `/confirm-req req-001`처럼 REQ 승인 게이트를 통과시켜야 할 때
- `/confirm-req`처럼 입력 없이 승인되지 않은 전체 REQ를 일괄 검토하고 승인 가능한 항목만 승격해야 할 때
- REQ 문서의 필수 필드와 Acceptance Criteria 충족 여부를 다시 확인해야 할 때
- `docs/srs/index.md` 상태를 REQ 문서와 맞춰야 할 때
# Inputs
- 선택 입력: REQ 식별자
- `req-001` 같은 prefix
- 전체 REQ 파일 경로
- 입력이 없으면 `docs/srs/**/req-*.md` 전체를 스캔해 승인되지 않은 REQ를 대상으로 삼는다.
- 대상 REQ 문서 또는 대상 REQ 문서 목록
- `docs/srs/index.md`
# Core Rules
## 1. 입력 해석
- prefix 입력이면 `docs/srs/**/req-001_*.md` 형식으로 찾는다.
- 입력이 없으면 `docs/srs/` 아래에서 `req-template.md`를 제외한 모든 `req-*.md`를 찾고, 그중 `Status: Proposed`인 문서를 승인 후보로 삼는다.
- 후보가 0개면 진행하지 않는다.
- 후보가 여러 개면 임의 선택하지 않는다.
- 입력이 없는 일괄 모드에서는 여러 후보가 정상이며, 각 후보를 개별 승인 게이트로 평가한다.
## 2. 승인 게이트
- 아래 항목이 모두 있어야 승인 가능하다.
- `Status`, `Type`, `Priority`, `Owner`
- `Intent`
- `Requirement`
- 구체적인 `Acceptance Criteria`
- `Impacted Area`
- `Change Log`
- 미해결 placeholder, 사람 결정 필요 메모, blocker가 남아 있으면 승인하지 않는다.
- `Status`가 이미 `Approved`, `Implemented`, `Deprecated`이면 중복 승인하지 않는다.
- 일괄 모드에서는 승인 불가한 문서가 있더라도 전체 실행을 중단하지 않는다. 승인 가능한 문서만 승격하고, 나머지는 blocker와 함께 별도 보고한다.
## 3. 허용되는 수정
- AI가 근거 있게 바로 고칠 수 있는 표현, 오타, 누락 제목 정리는 보강할 수 있다.
- 승인 성공 시 아래 변경을 수행한다.
- REQ 문서의 `Status`를 `Approved`로 변경
- `Change Log`에 승인 기록 추가
- `docs/srs/index.md`의 해당 Register 행 상태 갱신
- 필요하면 `Recent Change Log Summary` 갱신
- 사람 판단이 필요한 우선순위, 범위, Owner는 임의로 확정하지 않는다.
- 일괄 모드에서도 허용되는 수정 범위는 동일하며, 승인 불가 문서의 상태는 바꾸지 않는다.
# Execution Procedure
1. 입력에서 대상 REQ 경로 하나 또는 대상 REQ 문서 목록을 확정한다.
2. 입력이 없는 경우 `docs/srs/**/req-*.md`를 스캔해 `Status: Proposed` 문서를 승인 후보 목록으로 만든다.
3. 대상 REQ들와 `docs/srs/index.md`를 읽는다.
4. 각 REQ마다 필수 필드, Acceptance Criteria, Notes의 blocker 여부를 확인한다.
5. AI가 근거 있게 정리할 수 있는 사소한 일관성 문제를 먼저 고친다.
6. 각 REQ에 대해 승인 게이트를 다시 평가한다.
7. 게이트 통과한 REQ만 `Approved`로 전환하고 인덱스를 갱신한다.
8. 게이트 미통과한 REQ는 상태를 유지하고 남은 blocker를 수집한다.
9. 입력이 없는 경우 승인 성공 목록과 승인 불가 목록을 분리해 함께 보고한다.
# Output Expectations
- 단일 입력 모드:
- 대상 REQ 경로
- 승인 성공 여부
- 자동 보강한 항목 목록
- 남은 blocker 또는 미해결 항목
- `docs/srs/index.md` 갱신 결과
- 무인자 일괄 모드:
- 검토한 REQ 전체 목록
- 승인 성공한 REQ 목록
- 승인 불가한 REQ 목록과 각 blocker
- 자동 보강한 항목 목록
- `docs/srs/index.md` 갱신 결과
# Validation
- 승인 성공인 경우 REQ 문서와 index 상태가 모두 `Approved`인지 확인한다.
- 승인 보류인 경우 상태가 잘못 바뀌지 않았는지 확인한다.
- 무인자 일괄 모드에서는 승인 성공한 REQ만 상태가 바뀌고, 승인 불가한 REQ는 기존 상태가 유지되는지 확인한다.
@@ -0,0 +1,54 @@
---
name: draft-batch-design
description: "Use when: drafting the design document for an existing batch, running /draft-batch-design with a BAT ID, filling docs/batches/<BAT_ID>/design.md, recording architecture and interface decisions before implementation, or planning updates to docs/project-structure.md and docs/runtime-flows.md."
argument-hint: "예: bat-001 또는 docs/batches/bat-001_20260424_scaffold"
user-invocable: true
---
# Purpose
This skill writes the design document for a batch by summarizing architecture, changed areas, key decisions, and edge cases from the batch plan and included REQs.
`docs/project-structure.md`와 `docs/runtime-flows.md`가 존재하면, 이 skill은 해당 baseline 문서를 읽고 이번 batch의 구조 영향과 흐름 영향을 비교해야 한다.
# Inputs
- `BAT-ID` 또는 batch 경로
- `docs/batches/<BAT_ID>/planning.md`
- 포함된 REQ 문서들
- `docs/batches/<BAT_ID>/design.md`
- `docs/project-structure.md` (존재하는 경우)
- `docs/runtime-flows.md` (존재하는 경우)
# Core Rules
- planning이 없거나 범위가 비어 있으면 설계를 진행하지 않는다.
- 설계는 구현 전에 결정해야 할 구조와 인터페이스를 중심으로 적는다.
- `batch-lite`이고 planning의 `Design Gate`가 `no`이며 구조/인터페이스/런타임 영향이 없다면 design 단계는 생략할 수 있다.
- REQ 간 공통 설계 전제가 있다면 batch design에 끌어올린다.
- baseline 문서가 있으면 이번 batch 설계는 baseline 대비 변경점과 유지점이 무엇인지 명시해야 한다.
- `design.md`에는 최소한 아래 내용을 포함해야 한다.
- Architecture Summary
- Changed Areas
- Key Decisions
- Edge Cases
- Architecture Impact (`none` | `project-structure` | `runtime-flows` | `both`)
- Reference Doc Update Plan
- 기존 템플릿에 위 섹션이 없으면 설계 문서에 추가해 채운다.
# Execution Procedure
1. batch 경로를 확정한다.
2. planning과 포함 REQ를 읽는다.
3. planning의 `Design Gate`가 `no`이고 batch profile이 `batch-lite`면 design 없이 진행 가능한지 다시 확인하고, 그대로면 design 생략 결정을 유지한다.
4. `docs/project-structure.md`와 `docs/runtime-flows.md`가 있으면 읽고 현재 baseline과 batch 범위를 비교한다.
5. `design.md`에 Architecture Summary, Changed Areas, Key Decisions, Edge Cases를 채운다.
6. Architecture Impact와 Reference Doc Update Plan을 명시한다.
7. 설계상 blocker가 있으면 문서에 명시하고 구현으로 넘기지 않는다.
# Validation
- design 문서에 Architecture Summary, Changed Areas, Key Decisions, Edge Cases가 모두 있는지 확인한다.
- planning에서 정의한 핵심 범위가 design에서 누락되지 않았는지 확인한다.
- 구조 또는 흐름 영향이 있는 batch라면 Architecture Impact와 Reference Doc Update Plan이 채워졌는지 확인한다.
- `batch-lite`에서 design을 생략한 경우 planning의 `Design Gate`와 batch index profile이 그 결정을 설명하는지 확인한다.
@@ -0,0 +1,38 @@
---
name: draft-batch-planning
description: "Use when: drafting the planning document for an existing batch, running /draft-batch-planning with a BAT ID, populating docs/batches/<BAT_ID>/planning.md, or setting batch scope and dependency notes before design."
argument-hint: "예: bat-001 또는 docs/batches/bat-001_20260424_scaffold"
user-invocable: true
---
# Purpose
This skill writes the planning document for a batch by consolidating included REQs, scope, dependencies, milestones, and key risks.
# Inputs
- `BAT-ID` 또는 batch 경로
- `docs/batches/<BAT_ID>/index.md`
- 포함된 REQ 문서들
- `docs/batches/<BAT_ID>/planning.md`
# Core Rules
- planning은 batch 수준 범위, 의존성, 순서를 명확히 해야 한다.
- REQ 문서를 다시 쓰지 말고 delivery 관점의 묶음 계획으로 요약한다.
- planning은 design이 구현 전에 필요한지 여부를 명시해야 한다.
- `batch-lite`라면 planning에 왜 design을 생략할 수 있는지 또는 언제 design이 필요해지는지 남긴다.
- planning 작성 후 batch 상태는 `in-delivery`로 올릴 수 있다.
# Execution Procedure
1. 입력에서 batch 경로를 확정한다.
2. batch index와 포함 REQ를 읽는다.
3. `planning.md`에 scope, out-of-scope, dependency, milestone, risk를 채운다.
4. `planning.md`의 `Design Gate`에 design 필요 여부와 근거를 적는다.
4. 필요하면 batch `index.md`의 Status를 `in-delivery`로 갱신한다.
# Validation
- planning 문서에 Included REQ, Delivery Plan, Dependencies, Design Gate, Milestones, Risks가 모두 존재하는지 확인한다.
- batch index와 planning의 포함 REQ 목록이 일치하는지 확인한다.
@@ -0,0 +1,49 @@
---
name: draft-batch-verification
description: "Use when: drafting verification evidence for a batch, running /draft-batch-verification with a BAT ID, filling docs/batches/<BAT_ID>/verification.md, mapping REQ acceptance criteria to evidence before release approval, or verifying sync with docs/project-structure.md and docs/runtime-flows.md."
argument-hint: "예: bat-001 또는 docs/batches/bat-001_20260424_scaffold"
user-invocable: true
---
# Purpose
This skill drafts the verification document for a batch by mapping included REQ acceptance criteria to available evidence and identifying remaining blockers.
batch design 또는 REQ가 baseline 문서 생성/갱신 또는 구조/흐름 영향이 있음을 나타내면, verification은 `docs/project-structure.md`와 `docs/runtime-flows.md`가 코드와 설계에 맞게 동기화되었는지도 확인해야 한다.
# Inputs
- `BAT-ID` 또는 batch 경로
- 포함된 REQ 문서들
- `docs/batches/<BAT_ID>/design.md` (존재하는 경우)
- `docs/batches/<BAT_ID>/planning.md`
- `docs/batches/<BAT_ID>/implementation.md`
- `docs/batches/<BAT_ID>/verification.md`
- `docs/project-structure.md` (존재하는 경우)
- `docs/runtime-flows.md` (존재하는 경우)
# Core Rules
- verification은 Discovery 성공 기준이 아니라 REQ acceptance criteria에 직접 연결한다.
- evidence가 없는 항목은 통과로 간주하지 않는다.
- 확인되지 않은 항목은 `Blocking Issues`에 명시한다.
- `batch-lite`에서 design 문서가 없다면 planning의 `Design Gate`와 implementation 결과를 기준으로 구조 영향이 실제로 없었는지 확인해야 한다.
- design의 Architecture Impact가 `none`이 아니거나 baseline 문서 생성/갱신이 batch 범위에 있으면, baseline 문서 동기화 evidence를 verification에 포함해야 한다.
- baseline 문서 동기화가 필요한데 evidence가 없으면 release-ready로 간주하지 않는다.
# Execution Procedure
1. batch와 포함 REQ를 확정한다.
2. REQ acceptance criteria를 목록화한다.
3. design 문서가 있으면 Architecture Impact와 Reference Doc Update Plan을 읽고, 없으면 planning의 `Design Gate`를 읽는다.
4. implementation 결과와 테스트 로그를 근거로 evidence를 연결한다.
5. baseline 문서 동기화가 필요하면 `docs/project-structure.md`와 `docs/runtime-flows.md`의 생성/갱신 여부를 evidence에 포함한다.
6. `batch-lite`에서 design이 없었다면 verification에 `no architecture impact confirmed` 여부를 남긴다.
7. `verification.md`의 Acceptance Mapping, Evidence, Result를 채운다.
# Validation
- 포함 REQ마다 acceptance mapping이 존재하는지 확인한다.
- evidence 없는 항목이 있으면 Result에 blocker로 반영했는지 확인한다.
- Architecture Impact가 있는 batch라면 baseline 문서 동기화 evidence 또는 blocker가 명시됐는지 확인한다.
- `batch-lite`에서 design이 없는 경우 planning과 implementation을 기준으로 구조 영향 없음 또는 design 누락 blocker 중 하나가 명시됐는지 확인한다.
+56
View File
@@ -0,0 +1,56 @@
---
name: draft-batch
description: "Use when: creating a new batch from approved REQ IDs, running /draft-batch with one or more req IDs, scaffolding docs/batches/<BAT_ID>/ files, or updating docs/batches/index.md for a new delivery unit."
argument-hint: "예: req-001 req-002 req-003"
user-invocable: true
---
# Purpose
This skill creates a new batch delivery unit from approved requirements, chooses the right delivery profile, scaffolds its folder and documents, and updates the batch register.
# Inputs
- Approved `REQ-ID` 목록
- 선택 입력
- batch profile 힌트 (`standard` | `batch-lite` | `minor-change`)
- `docs/srs/index.md`
- 대상 REQ 문서들
- `docs/batches/index.md`
- `.github/templates/batches/` 아래 템플릿
# Core Rules
- `Approved` 상태가 아닌 REQ는 batch에 포함하지 않는다.
- 새 batch 폴더는 `docs/batches/bat-XXX_YYYYMMDD_scope/` 형식을 사용한다.
- 새 batch는 `standard` 또는 `batch-lite` profile 중 하나를 가진다.
- 입력이 정확히 1개의 `Approved` REQ이고 범위가 국소적이며 구조/인터페이스/런타임 흐름 변경이 없으면 `minor-change` fast path를 사용할 수 있다. 이 경우 결과 batch profile은 `batch-lite`로 기록한다.
- `standard` batch는 생성 시 아래 파일을 함께 만든다.
- `index.md`
- `planning.md`
- `design.md`
- `implementation.md`
- `verification.md`
- `batch-lite`는 생성 시 아래 파일만 먼저 만든다.
- `index.md`
- `planning.md`
- `batch-lite`의 `implementation.md`와 `verification.md`는 해당 단계 진입 시 생성한다.
- `batch-lite`라도 구조/인터페이스/흐름 영향이 생기면 `design.md`를 추가하고 사실상 standard depth로 다룬다.
- `docs/batches/index.md`의 register를 함께 갱신하며, 가능하면 profile도 함께 기록한다.
# Execution Procedure
1. 입력된 REQ 경로와 상태를 확인한다.
2. REQ 수, 영향 범위, 구조/인터페이스/런타임 영향 여부를 기준으로 `standard` 또는 `batch-lite` profile을 결정한다.
3. 배치 제목과 slug를 결정하고 다음 `BAT-ID`를 계산한다.
4. 템플릿 기반으로 batch 폴더와 profile에 맞는 문서를 생성한다.
5. `index.md`에 `Profile`, 포함 REQ, source discovery, 공통 범위를 채운다.
6. `planning.md`에 `Design Gate`를 기록해 design이 즉시 필요한지 여부를 남긴다.
7. `docs/batches/index.md`에 새 register 행을 추가한다.
# Validation
- 포함 REQ가 모두 `Approved`인지 확인한다.
- `standard`면 5개 문서가 모두 생성되었는지 확인한다.
- `batch-lite`면 `index.md`, `planning.md`가 생성되었고 `Profile: batch-lite`가 기록되었는지 확인한다.
- `docs/batches/index.md`에 새 batch 행이 추가되었는지 확인한다.
+43
View File
@@ -0,0 +1,43 @@
---
name: draft-release
description: "Use when: creating a release document from one or more release-candidate batches, running /draft-release with BAT IDs, generating docs/releases/rel-XXX_YYYYMMDD_<slug>.md, or updating docs/releases/index.md before release approval."
argument-hint: "예: bat-001 또는 bat-001 bat-002"
user-invocable: true
---
# Purpose
This skill creates a profile-aware release document from one or more verified batches and registers it in the release index.
# Inputs
- `BAT-ID` 목록
- `docs/batches/index.md`
- 각 batch의 `verification.md`
- `docs/releases/index.md`
- `.github/templates/releases/release.md`
# Core Rules
- `release-candidate`가 아닌 batch는 release에 포함하지 않는다.
- 새 release 경로는 `docs/releases/rel-XXX_YYYYMMDD_<slug>.md` 형식을 사용한다.
- release는 `docs-only`, `tooling`, `app-service` profile 중 하나를 가진다.
- release profile은 포함 batch의 운영 부담 중 가장 무거운 것을 따른다. 기본 우선순위는 `app-service` > `tooling` > `docs-only`다.
- `docs-only`는 문서, 가이드, 템플릿, 정적 산출물 변경에 사용한다.
- `tooling`은 bootstrap, 스크립트, CLI, 자동화, 패키지 동작 검증이 필요한 변경에 사용한다.
- `app-service`는 실제 서비스 배포, runtime health, 로그, 운영 확인이 필요한 변경에 사용한다.
- release 문서 생성 시 Included Batch, Profile, Scope, Rollout Plan, Rollback Plan, Verification Checklist를 채운다.
# Execution Procedure
1. 입력 batch들의 상태와 verification 결과를 확인한다.
2. 포함 batch의 변경 성격과 검증 evidence를 기준으로 release profile을 결정한다.
3. 다음 `REL-ID`를 계산하고 제목/slug를 정한다.
4. 템플릿 기반으로 release 문서를 생성한다.
5. `docs/releases/index.md`에 register 행을 추가한다.
# Validation
- 포함 batch가 모두 `release-candidate`인지 확인한다.
- release 문서에 `Profile`이 있고 profile별 검증 항목이 비어 있지 않은지 확인한다.
- release 문서와 index register 행이 함께 생성됐는지 확인한다.
+126
View File
@@ -0,0 +1,126 @@
---
name: draft-req
description: "Use when: turning a confirmed Discovery into one or more requirement documents under `docs/srs/`, running /draft-req with a dcy-id or Discovery path, creating docs/srs/<Type>/req-XXX_<slug>.md files, updating docs/srs/index.md from FR/NFR input, or carrying forward constraints from docs/project-structure.md and docs/runtime-flows.md."
argument-hint: "예: dcy-001 또는 docs/discovery/dcy-001_20260424_krx-stock-picker-python-scaffold.md"
user-invocable: true
---
# Purpose
This skill converts a Discovery document into one or more requirement documents under `docs/srs/`, updates the SRS register, and writes the generated REQ references back to the source Discovery document.
`docs/project-structure.md`와 `docs/runtime-flows.md`가 존재하면, REQ 작성 시 이 문서들을 공통 baseline 참조 문서로 읽고 필요한 구조 제약만 REQ에 반영한다.
# When to use
- `/draft-req dcy-001`처럼 Discovery를 REQ backlog로 정규화해야 할 때
- Discovery의 FR/NFR을 구현 가능한 requirement 문서로 분리해야 할 때
- `docs/srs/index.md`의 register와 Next Requirement ID를 함께 갱신해야 할 때
- Discovery가 구조 또는 runtime baseline 갱신을 요구할 때 이를 REQ backlog에 반영해야 할 때
# Inputs
- Discovery 식별자
- `dcy-001` 같은 prefix
- 전체 Discovery ID
- `docs/discovery/<DISCOVERY_ID>.md` 경로
- 대상 Discovery 문서 본문
- `docs/project-structure.md` (존재하는 경우)
- `docs/runtime-flows.md` (존재하는 경우)
- `.github/templates/srs/index.md`
- `.github/templates/srs/req-template.md`
# Core Rules
## 0. Baseline architecture reference rules
- `docs/project-structure.md`와 `docs/runtime-flows.md`는 REQ의 상세 본문을 대체하지 않지만, 구조 제약과 흐름 제약을 읽기 위한 공통 baseline 참조 문서로 사용한다.
- REQ에는 baseline 문서의 전체 구조나 전체 흐름을 복제하지 않는다. 구현에 필요한 제약과 acceptance 기준만 남긴다.
- source Discovery가 구조 또는 runtime baseline 갱신을 요구하면, REQ 후보에 baseline 문서 갱신 작업을 포함해야 한다.
- baseline 문서가 없고 source Discovery가 그 갭 보완을 직접 범위에 포함한다면, baseline 문서를 다루는 REQ를 누락하면 안 된다.
- baseline 문서가 없는데 source Discovery가 그 갭을 다루지 않는다면, `bootstrap-baseline` 선행 누락 가능성을 보고한다.
## 1. 입력 해석
- 입력이 prefix면 `docs/discovery/` 아래에서 일치하는 문서를 찾는다.
- 여러 후보가 나오면 임의 선택하지 않고 사용자 확인이 필요하다고 보고한다.
- `.vendor/` 경로는 탐색 대상에서 제외한다.
## 2. REQ 분해 원칙
- FR은 기본적으로 독립 구현과 독립 검증 가능 단위로 REQ 후보를 만든다.
- 하나의 FR이 과도하게 크면 복수 REQ로 분해한다.
- NFR은 독립 측정 가능성, 독립 backlog 가치, 운영 영향도가 충분할 때만 별도 REQ로 승격한다.
- 특정 FR 또는 batch 검증 기준에 흡수하는 편이 적절한 NFR은 별도 REQ를 만들지 말고 Notes에 연결 근거를 남긴다.
- baseline 문서 갱신 요구는 보통 `Documentation`, `Interface`, `Configuration` 중 가장 적절한 Type으로 분류한다.
## 3. Type 및 경로 규칙
- 아래 폴더 중 정확히 하나를 선택한다.
- `Configuration`
- `Data`
- `Deployment`
- `Documentation`
- `Exception`
- `Installation`
- `Integration`
- `Interface`
- `Migration`
- `Non-Functional`
- `Testing`
- 새 REQ 경로는 `docs/srs/<Type>/req-XXX_<slug>.md` 형식을 사용한다.
- `REQ-XXX` 번호는 `docs/srs/index.md`의 `Next Requirement ID`를 source of truth로 사용한다.
## 4. 문서 작성 규칙
- `docs/srs/req-template.md`를 기준으로 문서를 만든다.
- `Status` 기본값은 `Proposed`다.
- `Intent`, `Requirement`, `Acceptance Criteria`, `Impacted Area`, `Notes`를 실제 문장으로 채운다.
- baseline 문서와 충돌하거나 baseline 문서를 갱신해야 하는 구조 제약이 있으면 `Impacted Area` 또는 `Notes`에 명시한다.
- 사람 승인 없이는 확정할 수 없는 항목은 비워 두지 말고 `Notes`에 결정 필요 또는 가정으로 명시한다.
- Change Log는 최초 생성 기록을 남긴다.
## 5. 인덱스 갱신 규칙
- REQ를 하나 이상 생성하면 `docs/srs/index.md`의 아래 항목을 함께 갱신한다.
- `Next Requirement ID`
- `Requirement Register`
- `Recent Change Log Summary`
- Register에는 ID, Title, Type, Status, Priority, Owner, Link를 추가한다.
## 6. Source Discovery 역참조 갱신 규칙
- REQ를 하나 이상 생성하면 source Discovery 문서의 `# 0. 문서 상태`에도 어떤 REQ가 생성됐는지 기록해야 한다.
- Discovery 문서에 `생성된 REQ 참조` 항목이 이미 있으면 생성된 REQ 목록으로 갱신하고, 없으면 `후속 Discovery 참조` 바로 아래에 추가한다.
- `생성된 REQ 참조`는 생성된 REQ 번호 순서대로 유지하고 중복을 허용하지 않는다.
- source Discovery 문서를 갱신했다면 `마지막 갱신 시각(KST)`도 함께 갱신한다.
- 생성된 REQ가 아직 없으면 `생성된 REQ 참조: 없음`을 유지한다.
# Execution Procedure
1. 입력에서 Discovery 경로를 확정한다.
2. Discovery 문서에서 FR/NFR, 범위 경계, 리스크, 성공 기준을 읽는다.
3. `docs/project-structure.md`와 `docs/runtime-flows.md`가 있으면 읽고, REQ에 남겨야 할 구조 제약과 흐름 제약을 추린다.
4. FR/NFR별 REQ 후보 목록을 만든다.
5. baseline 문서 갱신 또는 baseline 갭 보완 요구가 있으면 이를 반영한 REQ 후보를 포함한다.
6. 각 후보에 대해 Type, 제목, slug, Acceptance Criteria를 결정한다.
7. `docs/srs/index.md`의 다음 번호부터 순서대로 REQ 파일을 생성한다.
8. `docs/srs/index.md`를 갱신한다.
9. source Discovery 문서의 `생성된 REQ 참조`와 `마지막 갱신 시각(KST)`를 갱신한다.
10. 생성 결과와 제외한 NFR이 있으면 그 이유를 함께 보고한다.
# Output Expectations
- 생성된 REQ 파일 목록
- 각 REQ의 Type과 핵심 의도
- baseline 문서 참조 또는 생성/갱신 요구를 어떤 REQ에 반영했는지
- `docs/srs/index.md` 갱신 결과
- source Discovery 문서의 `생성된 REQ 참조` 갱신 결과
- 별도 REQ로 승격하지 않은 NFR 목록과 처리 이유
# Validation
- 모든 REQ 경로가 `docs/srs/<Type>/req-XXX_<slug>.md` 형식을 만족하는지 확인한다.
- 생성된 REQ 수와 `Requirement Register` 행 수가 일치하는지 확인한다.
- `Next Requirement ID`가 마지막 생성 번호보다 정확히 1 큰지 확인한다.
- baseline 문서 갱신 또는 baseline 갭 보완이 source Discovery 범위에 있으면, 이를 다루는 REQ가 실제로 생성되었는지 확인한다.
+379
View File
@@ -0,0 +1,379 @@
---
name: new-discovery
description: "Use when: deciding whether to update an existing Discovery document or start a new one, running /new-discovery with or without parameters, drafting docs/discovery/dcy-<id>_<YYYYMMDD>_<topic-slug>.md for a real product/service change, generating Discovery documents, or updating docs/discovery/index.md after baseline initialization is ready."
argument-hint: "예: 사용자 로그인 기능 추가 - OAuth2 소셜 로그인, 세션 관리, 로그아웃 처리"
user-invocable: true
---
# Purpose
This skill decides whether an incoming request should update an existing Discovery document or start a new one, then drafts or updates Discovery documentation based on issues, user requests, meeting notes, or repository state.
입력이 없으면 현재 Discovery/SRS/batch/release 상태와 baseline 문서 상태를 읽어 새 Discovery가 필요한지 판정한다. baseline 초기화가 아직 끝나지 않은 저장소에서는 먼저 `bootstrap-baseline`으로 `docs/project-structure.md`, `docs/runtime-flows.md`, active index를 준비한 뒤 첫 real Discovery를 생성한다.
새 Discovery를 생성하기로 판정된 경우 generated output must follow this structure:
- `docs/discovery/dcy-<id>_<YYYYMMDD>_<topic-slug>.md`
- Update `docs/discovery/index.md`
# When to use
다음 상황에서 사용한다.
- 새로운 SDLC 주기를 시작해야 할 때
- 기존 SDLC의 요구사항, 범위, 성공 기준을 조정해야 하는데 새 주기 생성이 필요한지 먼저 판정해야 할 때
- `/new-discovery ...` 또는 파라미터 없는 `/new-discovery`로 Discovery 초안을 만들어야 할 때
- baseline 초기화가 완료된 뒤 첫 real Discovery를 시작해야 할 때
- 이슈/요청사항을 `docs/discovery/` 아래 표준 Discovery 문서로 전환해야 할 때
- Discovery 문서를 템플릿 기반으로 작성하되, 추론 가능한 내용을 실제 문장으로 채워야 할 때
- `docs/discovery/index.md`에 새 Discovery 링크를 추가해야 할 때
# Inputs
이 skill은 아래 입력을 사용한다.
- 이슈 식별 정보
- GitHub issue link 또는 issue 번호
- 이슈 내용
- 사용자 입력 원문 또는 이슈 본문 전체
- 이슈 제목 또는 요청 요약
- SDLC 문맥
- 기존 `docs/discovery/` 폴더 구조 및 파일 목록
- 기존 `docs/srs/`, `docs/batches/`, `docs/releases/` 상태
- 기존 `docs/discovery/index.md` 내용
- `docs/project-structure.md`, `docs/runtime-flows.md` 존재 여부
- 현재 시각 (KST)
- 저장소 문맥
- 현재 저장소 상태
- 저장소 현황 탐색 결과
- 템플릿 파일
- `.github/templates/discovery/discovery.md`
- `.github/templates/discovery/index.md`
- `.github/templates/project-structure.md`
- `.github/templates/runtime-flows.md`
입력 해석 규칙:
- GitHub issue link 또는 issue 번호가 있으면 해당 이슈의 제목, 본문, 링크를 기준 입력으로 사용한다.
- 사용자 입력 원문과 요청 요약은 이슈 링크가 없거나 보조 설명이 필요할 때 함께 사용한다.
- 파라미터가 없으면 저장소 상태를 먼저 분류한 뒤 추천 Discovery 또는 진행 중인 반복 유지 여부를 판단한다.
- 저장소 현황 탐색 결과는 `# 3. 문제점의 요약` 중 `현재 상태` 작성에 사용한다.
# Core Rules
## 0. Baseline 문서 정책
- `docs/project-structure.md`와 `docs/runtime-flows.md`는 SDLC의 별도 governance unit가 아니라, 이후 Discovery/REQ/Batch/Release에서 공통으로 참조하는 cross-cutting baseline 문서다.
- baseline 초기화는 첫 Discovery와 분리된 `bootstrap-baseline` 경로를 기본값으로 사용한다.
- baseline 문서와 active index가 모두 없는 저장소에서는 `new-discovery`가 Discovery를 생성하기 전에 `bootstrap-baseline`을 우선 추천하고 중단한다.
- baseline 문서가 이미 있고, Discovery가 구조/런타임 변경을 다룰 때만 해당 Discovery 안에 baseline 문서 갱신 요구를 포함한다.
## 1. 파라미터 없는 실행 판정 규칙
- `/new-discovery`가 파라미터 없이 실행되면 먼저 아래 경로를 점검한다.
- `docs/discovery/`
- `docs/srs/`
- `docs/batches/`
- `docs/releases/`
- `docs/project-structure.md`
- `docs/runtime-flows.md`
- 파라미터 없는 실행은 아래 3가지 저장소 상태 중 하나로 판정한다.
- `no-history`: Discovery와 후속 SDLC 문서가 사실상 없고 첫 반복을 시작해야 하는 상태
- `active-cycle`: draft/review Discovery, Proposed REQ, 진행 중 batch, 미정리 release처럼 활성 unit가 존재해 파라미터 없는 실행만으로는 다음 반복 추천이 모호한 상태
- `ready-for-next-iteration`: active unit는 없고 새 반복을 시작할 준비가 된 상태
- `no-history`이고 baseline 문서 또는 active index가 없으면 `bootstrap-baseline`을 우선 추천하고 새 Discovery를 생성하지 않는다.
- `no-history`이지만 baseline 초기화가 끝나 있으면 첫 real Discovery를 생성한다.
- `active-cycle`이면 새 Discovery를 생성하지 않고 중단한다. 대신 현재 반복을 계속 진행하도록 `run-sdlc` 또는 해당 후속 skill을 추천한다.
- `ready-for-next-iteration`이면 이전 Discovery, SRS, 구현 상태, baseline 문서 차이를 읽고 추천 follow-up Discovery를 생성한다.
- `ready-for-next-iteration`에서 후보 ranking만 먼저 필요하면 `suggest-next-discovery`를 사용하고, 실제 문서 생성이 확정되면 `new-discovery`로 이어 간다.
- baseline 문서가 없고 active unit도 없다면, follow-up Discovery보다 `bootstrap-baseline`을 우선한다.
## 2. 기존 Discovery 갱신 vs 새 Discovery 생성 판정 규칙
- 기존 주기 후보 탐색과 비교는 아래 `확인 절차`를 따른다.
- 후보 문서가 있고 아래 조건을 모두 만족하면 기존 Discovery를 갱신한다.
- 변경이 기존 문제 정의와 핵심 사용자 시나리오를 유지한다.
- FR/NFR 변경이 문구 명확화, 측정 가능성 보강, 범위 경계의 미세 조정, 우선순위 재정렬 수준이다.
- 요구사항 삭제 또는 수정이 기존 REQ, batch planning, batch design, implementation 산출물을 사실상 무효화하지 않는다.
- 대상 Discovery가 아직 초기 정리 단계이거나, 후속 단계 문서가 있어도 변경 영향이 국소적이라 동일 문서 안에서 추적 가능하다.
- 아래 조건 중 하나라도 만족하면 새 Discovery를 생성한다.
- FR/NFR 삭제 또는 수정이 범위, 이해관계자, 핵심 사용자 시나리오, 성공 기준을 실질적으로 바꾼다.
- 기존 하위 단계 문서나 구현 결과를 다시 써야 할 정도로 설계/구현 전제가 깨진다.
- 기존 Discovery가 사실상 Freeze 이후 단계로 진행되어 변경 이력을 같은 문서에 계속 누적하면 책임 경계가 흐려진다.
- 운영 환류, 새로운 이슈, 정책 전환 등으로 후속 반복을 독립 주기로 추적하는 편이 명확하다.
- 기존 Discovery를 더 이상 기준으로 쓰지 않더라도 기존 문서를 삭제하지 않는다. 새 문서를 생성하는 경우 기존 문서는 참조 대상으로 유지하고, 대체 또는 후속 관계를 문서에 남긴다.
- 판정 결과는 반드시 아래 둘 중 하나로 명시한다.
- `기존 Discovery 갱신`
- `새 Discovery 생성`
### 확인 절차
- 입력 원문 또는 추천 Discovery 주제에서 아래 식별 정보를 먼저 추출한다.
- GitHub issue 번호 또는 링크
- 이슈 제목의 핵심 명사
- 기능명, 모듈명, 동사, 영향 범위 키워드
- `docs/discovery/` 아래 기존 문서를 탐색할 때는 `.vendor/` 경로를 제외하고 아래 순서로 후보를 찾는다.
- issue 번호 또는 링크의 정확 일치
- 이슈 제목과 파일명 slug의 핵심 키워드 일치
- 기존 Discovery 문서 안의 문제 정의, FR/NFR, 범위 경계 키워드 일치
- 후보 문서가 하나 이상 발견되면 각 후보마다 아래 항목을 비교한다.
- 같은 문제 정의 또는 같은 기능 묶음을 다루는지
- 현재 단계가 Discovery, REQ 정제, batch delivery, release 이후 어디까지 진행됐는지
- 이번 변경이 기존 FR/NFR의 미세 조정인지, 핵심 요구사항 폐기 또는 재정의인지
- 기존 하위 단계 문서와 구현 산출물을 유지 가능한지, 다시 작성해야 하는지
- 후보가 없으면 기본 판정은 `새 Discovery 생성`이다.
- 후보가 하나이고 판정 규칙에 명확히 부합하면 해당 후보를 기준으로 자동 판정한다.
- 후보가 여러 개이거나, 하나의 후보라도 `기존 Discovery 갱신`과 `새 Discovery 생성` 사이에서 명확히 갈리지 않으면 임의로 진행하지 않는다.
- 후보 문서 경로 목록과 각 후보의 비교 근거를 사용자에게 보고한다.
- 사용자 확인 전에는 새 폴더 생성이나 기존 문서 갱신을 하지 않는다.
- 최종 판정 결과에는 선택된 대상 문서 경로 또는 새로 만들 Discovery 생성 사유를 반드시 함께 기록한다.
## 3. Discovery ID 규칙
- `docs/discovery/` 아래 기존 문서 중 `dcy-<3자리>_` 패턴의 최대 번호를 찾는다.
- 다음 번호를 3자리 zero-pad로 계산한다.
- 오늘 날짜를 `YYYYMMDD` 형식으로 구한다.
- 사용자 입력 원문, 추천 Discovery 제목, 이슈 본문 전체, GitHub issue link에서 `topic-slug`를 만든다.
- `topic-slug`는 소문자 kebab-case의 형태로 만든다.
- slug 규칙:
- 영문/숫자 외 문자는 `-`로 치환
- 연속 `-`는 하나로 축약
- 시작/끝 `-` 제거
- 결과가 비면 `untitled` 사용
- 최종 `DISCOVERY_ID`는 `dcy-<id>_<YYYYMMDD>_<topic-slug>` 형식이어야 한다.
## 4. 문서 생성/갱신 규칙
- 판정 결과가 `새 Discovery 생성`이면 새 파일을 `docs/discovery/<DISCOVERY_ID>.md` 경로로 생성한다.
- `새 Discovery 생성`인 경우 Discovery 문서는 `.github/templates/discovery/discovery.md`를 기반으로 생성한다.
- `docs/discovery/index.md`가 없으면 `.github/templates/discovery/index.md`를 기반으로 생성한다.
- Discovery가 구조/런타임 baseline 갭을 직접 다루는 경우, `.github/templates/project-structure.md`와 `.github/templates/runtime-flows.md`를 이후 산출물 템플릿 참조로 취급한다.
- `기존 Discovery 갱신`이면 대상 Discovery 문서를 갱신한다.
- 동일 경로가 이미 있으면 덮어쓰지 말고 다음 ID를 재계산한다.
- 불필요한 파일은 만들지 않는다.
## 5. Discovery 초안 작성 원칙
- 입력 문장이 짧더라도 기능 목적, 예상 사용자, 산출물, 성공 조건을 합리적으로 추론해 초안을 작성한다.
- 입력만으로 추론 가능한 내용은 플레이스홀더로 남기지 말고 실제 문장으로 채운다.
- 사용자 승인, 외부 데이터, 정책 결정, 확정 범위 경계처럼 추론만으로 확정하면 안 되는 항목만 플레이스홀더로 남긴다.
- 공란은 허용하지 않는다.
- 합리적 기본안을 제시할 수 있으면 초안 문장으로 채운다.
- 사용자 확인이 반드시 필요하면 관련 본문에는 최소 플레이스홀더를 남기고 `# 10. 사용자 결정 필요 항목 요약`에 정리한다.
- `기존 Discovery 갱신`인 경우 FR/NFR 변경 또는 삭제 이유, 영향 받는 하위 단계, 기존 문서와의 차이를 문서 안에 명시해 변경 근거를 남긴다.
- Discovery가 구조/런타임 baseline 변경을 직접 다루는 경우 `# 4. 이번에 정의할 변경`, `# 5. 요구사항 목록`, `# 9. 파일 처리 결과`에 `docs/project-structure.md`와 `docs/runtime-flows.md` 갱신 요구를 명시한다.
## 6. 플레이스홀더 유지 규칙
- 사용자 승인 전 확정되면 안 되는 정책/범위/산출물 위치/대상 독자 결정은 본문에도 플레이스홀더를 남긴다.
- `# 10. 사용자 결정 필요 항목 요약`의 항목은 반드시 아래 형식 중 하나를 사용한다.
- `{{DECIDE_*}}`
- `{{CONFIRM_*}}`
- `{{DATA_*}}`
- `TBD` 같은 일반 문자열보다 의미가 드러나는 플레이스홀더를 우선 사용한다.
# Discovery Sections To Fill
다음 섹션은 자동으로 채워야 한다.
## `# 1. 계획 상태 요약`
- `해석` 2줄은 입력 요청 또는 파라미터 없는 실행의 저장소 상태 해석을 바탕으로 직접 작성한다.
## `# 0. 문서 상태`
- `새 Discovery 생성`이면 `대체됨`, `후속 주기 참조` 기본값은 `없음`으로 둔다.
- 기존 Discovery를 대체하거나 이어받는 새 Discovery를 만드는 경우, 이전 Discovery 문서에도 해당 참조 필드를 갱신한다.
- `기존 Discovery 갱신`이면 기존 참조 값을 보존하고, 새 관계가 확정된 경우에만 관련 필드를 갱신한다.
플레이스홀더 치환 규칙:
- `{{DISCOVERY_ID:dcy-<3자리>_<YYYYMMDD>_<topic-slug>}}` -> 계산한 `DISCOVERY_ID`
- `{{SUPERSEDED_BY_DISCOVERY:없음 또는 docs/discovery/<DISCOVERY_ID>.md}}` -> `없음` 또는 대체 Discovery 경로
- `{{FOLLOW_UP_DISCOVERY_REF:없음 또는 docs/discovery/<DISCOVERY_ID>.md}}` -> `없음` 또는 후속 Discovery 경로
## `# 2. 요구사항 판정 결과`
- 기본값은 `신규`로 둔다.
- 입력만으로 명백한 중복/유사라고 판단 가능한 경우에만 다르게 쓴다.
- 근거 2줄도 직접 작성한다.
## `# 3. 문제점의 요약`
- 현재 상태, 기대 상태, 이해관계자, 주요 사용자 시나리오를 입력 기반으로 채운다.
- 특히 `현재 상태`는 저장소 탐색 결과와 baseline 문서 존재 여부를 반영해야 한다.
## `# 4. 이번에 정의할 변경`
- 핵심 변경 항목 1~3개를 직접 작성한다.
- Discovery가 구조 또는 runtime baseline 갭을 다루면 baseline 문서 갱신을 핵심 변경 항목에 포함한다.
- `영향 범위`의 코드/문서/운영 영향도 추론해 채운다.
## `# 5. 요구사항 목록`
- FR 2개 이상, NFR 1개 이상을 직접 작성한다.
- Discovery가 구조 또는 runtime baseline 갭을 다루는 경우, `docs/project-structure.md`와 `docs/runtime-flows.md` 갱신 요구를 FR에 포함한다.
- In Scope/Out of Scope는 초안 수준으로 제안한다.
- 사용자 승인 없이는 확정할 수 없는 범위 경계는 플레이스홀더로 남긴다.
## `# 6. 리스크/가정 목록`
- 리스크 2개 이상, 가정 2개 이상을 직접 작성한다.
- 오픈 질문은 정말 결정이 필요한 경우에만 남긴다.
## `# 7. 초기 성공 기준`
- 성공 기준 2개 이상을 작성한다.
- Discovery가 구조 또는 runtime baseline 변경을 다루는 경우 baseline 문서와 이후 산출물 참조 가능성을 성공 기준에 연결한다.
- 각 성공 기준에 대해 측정 방식과 데이터 출처 초안을 작성한다.
## `# 9. 파일 처리 결과`
- 생성 결과와 최소 참조 문서를 채운다.
- Discovery가 구조 또는 runtime baseline 갭을 다루면 `.github/templates/project-structure.md`와 `.github/templates/runtime-flows.md`를 참조 문서에 포함한다.
- 참조 문서가 없으면 `없음`이라고 쓴다.
## `# 10. 사용자 결정 필요 항목 요약`
- 자동 추론으로 확정할 수 없는 항목만 `DECIDE`, `CONFIRM`, `DATA`에 넣는다.
- 이 섹션 항목은 설명문이 아니라 플레이스홀더 형식으로 남긴다.
## `# 11. Discovery Freeze`
- `Handoff Decision` 기본값은 `보류`다.
- `Handoff Rationale`에는 현재 상태를 짧게 적는다.
- 예: `초기 Discovery 초안 생성 완료, REQ 초안 작성 전 사용자 확인 필요`
# Repository Exploration
Discovery 문서의 `# 3. 문제점의 요약` 중 `현재 상태`를 채우기 위해 저장소 현황 탐색을 수행한다.
1. 이슈 원문 또는 추천 주제에서 핵심 키워드(기능명, 모듈명, 동사)를 추출한다.
2. 키워드를 기반으로 저장소에서 관련 파일, 디렉터리, 함수, 기존 문서를 탐색한다.
3. 탐색 범위는 아래와 같다.
- 소스 파일: `.ts`, `.js`, `.py`, `.go`, `.java` 등
- 설정 파일
- 기존 `docs/` 문서
4. 아래 항목은 제외한다.
- 테스트 파일
- 의존성 잠금 파일 (`package-lock.json`, `.lock`)
5. 탐색 결과에서 아래 내용을 추출한다.
- 관련 파일 경로 목록 (최대 10개)
- 현재 구현 방식 요약 (함수명, 클래스명, 주요 로직 1~3줄)
- 현재 상태에서 이슈 원문이 지적하는 문제가 실제로 존재하는지 여부
- `docs/project-structure.md`, `docs/runtime-flows.md` 존재 여부와 최신성 판단에 필요한 단서
6. 관련 파일을 찾지 못하면 `관련 파일 없음 — 신규 기능으로 추정`으로 기록한다.
7. 탐색 결과는 `# 3. 문제점의 요약`의 `현재 상태` 기술에만 반영한다.
# Execution Procedure
다음 순서대로 작업한다.
1. 입력 원문이 있으면 이슈명을 한 문장으로 정리하고, 없으면 저장소 상태를 먼저 분류한다.
2. 파라미터 없는 실행이면 discovery/srs/batches/releases/baseline 문서 상태를 읽어 `no-history`, `active-cycle`, `ready-for-next-iteration` 중 하나로 판정한다.
<<<<<<< HEAD
3. 입력 원문이 없고 `active-cycle`이면 새 Discovery 자동 생성을 중단하고 현재 반복을 계속 진행해야 하는 이유와 추천 skill을 보고한다.
4. 입력 원문이 없고 `no-history`이면 baseline Discovery를 생성 대상으로 확정한다.
5. 입력 원문이 없고 `ready-for-next-iteration`이면 이전 Discovery, SRS, 구현 상태, baseline 문서 상태를 바탕으로 추천 follow-up Discovery 주제를 정한다.
6. 입력 원문, 이슈 링크, 신규 요구 요약처럼 명시적 신규 입력이 있으면 `active-cycle` 여부와 무관하게 위 `확인 절차`에 따라 issue 번호/링크, 제목 키워드, 기능명, 범위 키워드를 추출하고 기존 후보 주기를 찾는다.
7. 입력 원문이 없고 추천 Discovery 주제가 정해졌으면 위 `확인 절차`에 따라 issue 번호/링크, 제목 키워드, 기능명, 범위 키워드를 추출하고 기존 후보 주기를 찾는다.
8. 후보 비교 결과를 바탕으로 `기존 Discovery 갱신` 또는 `새 Discovery 생성`으로 판정한다.
9. `active-cycle` 상태에서 명시적 신규 입력으로 새 Discovery를 진행하는 경우, 기존 active unit와의 범위 충돌 여부와 병렬 진행 사유를 함께 기록한다.
10. 판정이 애매하면 사용자 확인 전까지 자동 생성 또는 자동 갱신을 중단하고 후보와 근거를 보고한다.
11. 저장소 현황 탐색을 수행한다.
12. 판정 결과가 `새 Discovery 생성`이면 기존 `docs/discovery/` 경로를 다시 스캔해 다음 번호를 계산한다.
13. `새 Discovery 생성`이면 날짜와 slug를 조합해 `DISCOVERY_ID`를 만든다.
14. `새 Discovery 생성`이면 `docs/discovery/<DISCOVERY_ID>.md` 파일을 생성한다.
15. `기존 Discovery 갱신`이면 대상 Discovery 문서를 갱신한다.
16. 아래 플레이스홀더를 우선 치환한다.
=======
3. `active-cycle`이면 새 Discovery 생성을 중단하고 현재 반복을 계속 진행해야 하는 이유와 추천 skill을 보고한다.
4. `no-history`이고 baseline 문서 또는 active index가 비어 있으면 `bootstrap-baseline`을 우선 추천하고 Discovery 생성을 중단한다.
5. `no-history`이지만 baseline 초기화가 끝나 있으면 첫 real Discovery 생성 대상으로 확정한다.
6. `ready-for-next-iteration`이면 이전 Discovery, SRS, 구현 상태, baseline 문서 상태를 바탕으로 추천 follow-up Discovery 주제를 정한다.
7. 입력 원문이 있거나 추천 Discovery 주제가 정해졌으면 위 `확인 절차`에 따라 issue 번호/링크, 제목 키워드, 기능명, 범위 키워드를 추출하고 기존 후보 주기를 찾는다.
8. 후보 비교 결과를 바탕으로 `기존 Discovery 갱신` 또는 `새 Discovery 생성`으로 판정한다.
9. 판정이 애매하면 사용자 확인 전까지 자동 생성 또는 자동 갱신을 중단하고 후보와 근거를 보고한다.
10. 저장소 현황 탐색을 수행한다.
11. 판정 결과가 `새 Discovery 생성`이면 기존 `docs/discovery/` 경로를 다시 스캔해 다음 번호를 계산한다.
12. `새 Discovery 생성`이면 날짜와 slug를 조합해 `DISCOVERY_ID`를 만든다.
13. `새 Discovery 생성`이면 `docs/discovery/<DISCOVERY_ID>.md` 파일을 생성한다.
14. `기존 Discovery 갱신`이면 대상 Discovery 문서를 갱신한다.
15. 아래 플레이스홀더를 우선 치환한다.
>>>>>>> e15c3d2 (feat: introduce lightweight change path, change-req skill, and release feedback loop)
- `{{DOC_STATUS:draft|review|confirmed}}` -> `draft`
- `{{DISCOVERY_ID:dcy-<3자리>_<YYYYMMDD>_<topic-slug>}}` -> 계산한 `DISCOVERY_ID`
- `{{ISSUE_NAME:짧은 한글 또는 영문 이슈명}}` -> 입력 원문 또는 요약 이슈명
- `{{ISSUE_NAME}}` -> 입력 원문 또는 요약 이슈명
- `{{CREATED_AT_KST:TBD}}` -> 현재 시각(KST)
- `{{CREATED_AT_KST}}` -> 현재 시각(KST)
- `{{UPDATED_AT_KST:TBD}}` -> 현재 시각(KST)
- `{{UPDATED_AT_KST}}` -> 현재 시각(KST)
- `{{SUPERSEDED_BY_DISCOVERY:없음 또는 docs/discovery/<DISCOVERY_ID>.md}}` -> `없음` 또는 대체 Discovery 경로
- `{{FOLLOW_UP_DISCOVERY_REF:없음 또는 docs/discovery/<DISCOVERY_ID>.md}}` -> `없음` 또는 후속 Discovery 경로
- `{{OUTPUT_PATH}}` -> 생성 파일 경로
- `{{FILE_RESULT:생성|갱신|미생성}}` -> `생성`
<<<<<<< HEAD
17. baseline Discovery 또는 baseline 문서 보완 Discovery면 `docs/project-structure.md`와 `docs/runtime-flows.md` 생성/갱신 요구를 핵심 변경과 FR에 반영한다.
18. `기존 Discovery 갱신`인 경우 `{{OUTPUT_PATH}}`와 `{{FILE_RESULT}}`는 갱신 대상 파일과 `갱신`으로 해석한다.
19. `새 Discovery 생성`이면서 기존 Discovery를 대체하거나 이어받는 경우, 기존 Discovery 문서에 `대체됨` 또는 `후속 주기 참조` 필드를 새 문서 경로로 갱신한다.
20. Discovery 문서에서는 추론 가능한 플레이스홀더를 적극적으로 실제 내용으로 치환한다.
21. 추론 불가능하거나 사용자 확인이 필요한 항목만 플레이스홀더로 남긴다.
22. `새 Discovery 생성`인 경우에만 `docs/discovery/index.md` 전역 인덱스에 새 행을 추가한다.
23. `기존 Discovery 갱신`인 경우 전역 인덱스에 새 행을 추가하지 않는다.
=======
16. Discovery가 구조 또는 runtime baseline 갭을 직접 다루면 `docs/project-structure.md`와 `docs/runtime-flows.md` 갱신 요구를 핵심 변경과 FR에 반영한다.
17. `기존 Discovery 갱신`인 경우 `{{OUTPUT_PATH}}`와 `{{FILE_RESULT}}`는 갱신 대상 파일과 `갱신`으로 해석한다.
18. `새 Discovery 생성`이면서 기존 Discovery를 대체하거나 이어받는 경우, 기존 Discovery 문서에 `대체됨` 또는 `후속 주기 참조` 필드를 새 문서 경로로 갱신한다.
19. Discovery 문서에서는 추론 가능한 플레이스홀더를 적극적으로 실제 내용으로 치환한다.
20. 추론 불가능하거나 사용자 확인이 필요한 항목만 플레이스홀더로 남긴다.
21. `새 Discovery 생성`인 경우에만 `docs/discovery/index.md` 전역 인덱스에 새 행을 추가한다.
22. `기존 Discovery 갱신`인 경우 전역 인덱스에 새 행을 추가하지 않는다.
>>>>>>> e15c3d2 (feat: introduce lightweight change path, change-req skill, and release feedback loop)
# Global Index Rules
- `docs/discovery/index.md`가 없으면 아래 골격으로 새로 만든다.
- `## Discovery 목록`에는 새 행을 추가한다.
- 형식은 아래와 같다.
`| <DISCOVERY_ID> | <YYYYMMDD> | <ISSUE_NAME> | [Discovery](./<DISCOVERY_ID>.md) | draft |`
- 테이블 구조 자체는 바꾸지 않는다.
- `기존 Discovery 갱신`으로 판정된 경우 `docs/discovery/index.md`에 새 행을 추가하지 않는다.
- 같은 `DISCOVERY_ID`가 이미 있으면 중복 추가하지 않는다.
# Output Expectations
작업이 끝나면 아래 내용을 보고할 수 있어야 한다.
- 판정 결과 (`기존 Discovery 갱신` 또는 `새 Discovery 생성`)
- 파라미터 없는 실행이면 저장소 상태 분류 (`no-history` | `active-cycle` | `ready-for-next-iteration`)
- `active-cycle` 상태였다면 자동 중단 사유 또는 병렬 Discovery 허용 사유
- 대상 `DISCOVERY_ID`
- 확인에 사용한 후보 Discovery 목록과 각 후보의 비교 근거
- 새 Discovery인 경우 생성한 파일 경로
- 기존 Discovery 갱신인 경우 갱신한 파일 경로
- 기존 Discovery와의 대체 또는 후속 참조 갱신 결과
- `docs/discovery/index.md` 갱신 결과 또는 미갱신 사유
- `docs/project-structure.md`, `docs/runtime-flows.md` baseline 상태와 Discovery 반영 결과
- 저장소 현황 탐색 결과
- 자동으로 채운 Discovery 핵심 섹션 요약
- 사용자 확인이 필요해 플레이스홀더로 남긴 항목 요약
# Validation
완료 전에 아래를 확인한다.
- `새 Discovery 생성`이면 생성 경로가 `docs/discovery/<DISCOVERY_ID>.md` 형식을 만족하는지
- `새 Discovery 생성`이면 Discovery 문서가 생성되었는지
- `새 Discovery 생성`이면 `docs/discovery/index.md`가 신규 생성 또는 올바르게 갱신되었는지
- Discovery가 구조 또는 runtime baseline 갭을 다루면 `docs/project-structure.md`, `docs/runtime-flows.md` 갱신 요구가 문서 본문에 포함됐는지
- `기존 Discovery 갱신`이면 대상 Discovery 문서만 갱신되었는지
- `기존 Discovery 갱신`이면 새 `DISCOVERY_ID`와 불필요한 파일이 생성되지 않았는지
- 기존 Discovery 후보 탐색 결과와 판정 근거가 보고 가능한 형태로 정리되었는지
- 파라미터 없는 실행에서 `active-cycle` 상태라면 사용자 확인이나 명시적 신규 입력 없이 새 Discovery를 자동 생성하지 않았는지
- `active-cycle` 상태에서 명시적 신규 입력으로 새 Discovery를 생성한 경우, 기존 active unit와의 범위 충돌 여부와 판정 근거가 함께 정리됐는지
- 판정이 애매한 경우 사용자 확인 없이 새 폴더 생성이나 기존 문서 갱신을 진행하지 않았는지
- `대체됨`, `후속 주기 참조` 필드가 `없음` 또는 유효한 Discovery 경로로 채워졌는지
- 새 Discovery가 기존 Discovery의 대체 또는 후속 반복이라면 기존 Discovery의 참조 필드가 함께 갱신되었는지
- 추론 가능한 섹션은 실제 문장으로 채워졌는지
- 사용자 확인이 필요한 항목만 플레이스홀더로 남았는지
@@ -0,0 +1,38 @@
---
name: run-batch-implementation
description: "Use when: implementing a confirmed batch design, running /run-batch-implementation with a BAT ID, applying code changes for docs/batches/<BAT_ID>, or updating implementation logs and validation evidence for a batch."
argument-hint: "예: bat-001 또는 docs/batches/bat-001_20260424_scaffold"
user-invocable: true
---
# Purpose
This skill executes the implementation work for a batch, updates code, and records the changed files, execution log, validation, and remaining risks in the batch implementation document.
# Inputs
- `BAT-ID` 또는 batch 경로
- `docs/batches/<BAT_ID>/planning.md`
- `docs/batches/<BAT_ID>/design.md`
- `docs/batches/<BAT_ID>/implementation.md`
- 관련 REQ 문서와 실제 코드 경로
# Core Rules
- planning과 design이 없는 batch는 구현하지 않는다.
- 코드 변경 전 `implementation.md`의 Plan Summary와 Changed Files 초안을 먼저 맞춘다.
- 구현 직후 가장 좁은 테스트, lint, typecheck, 또는 동작 검증을 수행한다.
- blocker가 생기면 문서에 남기고 범위를 임의 확장하지 않는다.
# Execution Procedure
1. batch 경로, plan, design, 관련 REQ를 읽는다.
2. 구현 범위와 변경 파일 후보를 요약한다.
3. 실제 코드 변경을 수행한다.
4. `implementation.md`의 Changed Files, Execution Log, Validation, Remaining Risks를 갱신한다.
5. batch index 상태를 필요하면 `in-delivery`로 유지 또는 보정한다.
# Validation
- `implementation.md`에 실제 변경 파일과 검증 기록이 반영됐는지 확인한다.
- 구현 직후 수행한 가장 좁은 검증 명령 또는 결과가 문서에 남았는지 확인한다.
+97
View File
@@ -0,0 +1,97 @@
---
name: run-sdlc
description: "Use when: orchestrating the next SDLC action from the current 3-phase state, running /run-sdlc with a Discovery, REQ, Batch, or Release ID, resuming from the first incomplete unit in docs/discovery, docs/srs, docs/batches, or docs/releases, or routing a no-history repository to bootstrap-baseline before the first real Discovery."
argument-hint: "예: dcy-001, bat-001, rel-001, req-001 req-002"
user-invocable: true
---
# Purpose
This skill inspects the current state of Discovery, REQ, Batch, and Release documents and routes work to the next skill-only step in the 3-phase SDLC model.
`docs/project-structure.md`와 `docs/runtime-flows.md`는 별도 governance unit는 아니지만, 이 skill은 다음 단계를 추천할 때 해당 baseline 문서의 존재 여부와 갱신 필요 여부를 함께 확인한다.
# Inputs
- `DISCOVERY_ID`
- `REQ-ID` 목록
- `BAT-ID`
- `REL-ID`
- 관련 문서 경로
- `docs/project-structure.md` (존재하는 경우)
- `docs/runtime-flows.md` (존재하는 경우)
# Core Rules
- 이 skill은 `docs/discovery/`, `docs/srs/`, `docs/batches/`, `docs/releases/`만 active 경로로 사용한다.
- `docs/project-structure.md`와 `docs/runtime-flows.md`는 active routing 대상은 아니지만, 모든 단계에서 참고할 cross-cutting baseline 문서로 취급한다.
- prompt 기반 stage command는 사용하지 않는다.
- `review-*` 단계는 별도 명령으로 두지 않고 대응 `confirm-*` 절차에 흡수된 상태를 전제로 한다.
- 사람 선택이 필요한 경계에서는 자동으로 넘기지 않고 중단한다. 대표적으로 `suggest-batch-reqs` 결과에서 어떤 후보를 채택할지 결정하는 단계가 그렇다.
- 단, 정확히 1개의 `Approved` REQ가 국소적이고 저위험 변경으로 판단되면 `minor-change` fast path로 `draft-batch`를 바로 제안할 수 있다. 이 경로의 batch profile은 `batch-lite`다.
- active unit가 아직 없고 baseline 문서 또는 active index가 비어 있으면, 첫 real Discovery 전에 `bootstrap-baseline`을 우선 추천한다.
# Execution Procedure
## 1. 입력 해석
- 입력이 `dcy-`로 시작하면 Discovery를 기준으로 현재 상태를 확인한다.
- 입력이 `req-` 목록이면 REQ 상태를 읽고 batch 생성 또는 추천 단계로 보낸다.
- 입력이 `bat-`로 시작하면 batch delivery 상태를 확인한다.
- 입력이 `rel-`로 시작하면 release 상태를 확인한다.
- 입력이 없으면 현재 저장소에서 첫 incomplete step을 판정한다.
- 어떤 입력이든 가능하면 `docs/project-structure.md`와 `docs/runtime-flows.md` 존재 여부를 함께 확인한다.
## 1.5 bootstrap baseline routing
- active unit가 없고 `docs/project-structure.md`, `docs/runtime-flows.md`, active index 중 일부라도 비어 있으면 `bootstrap-baseline`을 다음 skill로 제안한다.
- 이 경우 Discovery를 자동 생성하지 않는다.
- baseline 초기화가 끝난 뒤 `new-discovery`를 다음 real Discovery entrypoint로 안내한다.
## 2. Discovery 기준 routing
- Discovery가 아직 `confirmed`가 아니면 `confirm-discovery`를 우선 실행한다.
- Discovery는 confirmed지만 연결된 REQ가 없으면 `draft-req`를 다음 단계로 사용한다.
- Approved REQ는 있으나 batch가 없으면 `suggest-batch-reqs`를 실행해 후보를 제시하고, 사용자가 후보를 선택한 뒤 `draft-batch`로 이어 가도록 멈춘다.
- baseline 문서 갭이 있으면 상태 요약에 `docs/project-structure.md`와 `docs/runtime-flows.md` 갱신 필요 여부를 함께 기록한다.
## 3. REQ 기준 routing
- `Proposed` REQ면 `confirm-req`를 다음 단계로 사용한다.
- 기존 REQ의 `Requirement`, `Acceptance Criteria`, 구현 전제가 바뀌어 Change Log 기반 변경 관리가 필요하면 `change-req`를 다음 단계로 사용한다.
- `Approved` REQ가 `release-candidate` 또는 `released` batch의 verification evidence와 연결돼 있으면 `confirm-req-implemented`를 다음 단계로 사용한다.
- 단일 `Approved` REQ이고 구조/인터페이스/런타임 영향이 없는 소규모 변경이면 `draft-batch`를 `minor-change -> batch-lite` 경로로 바로 제안한다.
- Approved REQ 묶음이 2개 이상이거나 사람 선택이 필요한 경우 `suggest-batch-reqs` 또는 `draft-batch`로 이어진다.
- baseline 문서 갱신이 REQ에 포함돼 있으면 상태 요약에 이를 반영한다.
## 4. Batch 기준 routing
- `planning.md`가 비어 있거나 draft 수준이면 `draft-batch-planning`
- batch profile이 `standard`이거나 `batch-lite`라도 planning의 `Design Gate`가 `yes`면 `draft-batch-design`
- batch profile이 `batch-lite`이고 `Design Gate`가 `no`면 design 없이 `run-batch-implementation`
- 구현 로그와 코드 변경이 아직 없으면 `run-batch-implementation`
- verification 문서가 없거나 불완전하면 `draft-batch-verification`
- verification evidence가 있지만 release-candidate가 아니면 `confirm-batch-verification`
- batch가 `release-candidate` 또는 `released`이고 포함 REQ 중 `Approved` 상태가 남아 있으면 `confirm-req-implemented`
- batch가 `release-candidate`이고 포함 REQ 구현 상태 동기화까지 끝났으면 `draft-release`
- batch design 또는 verification에 structure/flow 영향이 보이면 baseline 문서 갱신 필요 여부를 상태 요약에 포함한다.
## 5. Release 기준 routing
- release 문서가 draft면 profile(`docs-only` | `tooling` | `app-service`)에 맞는 근거가 채워졌는지 확인한 뒤 `confirm-release`
- `feedback-captured` release에 follow-up 입력이 있으면 `suggest-next-discovery` 또는 `change-req`를 다음 단계 후보로 제안한다.
- release가 confirmed 이후 운영 관찰이 남아 있지 않으면 `capture-release-feedback`
# Output Expectations
- 입력으로 해석한 단위 종류
- 현재 상태 요약
- baseline 문서 상태 (`present` | `missing` | `update-likely-required` | `bootstrap-required`)
- 바로 실행할 다음 skill 1개 또는 추천 후보 목록
- 자동으로 진행하지 않고 멈춘 이유가 있으면 그 사유
# Validation
- 다음 단계가 현재 문서 상태와 모순되지 않는지 확인한다.
- 제안한 다음 skill이 실제 `.github/skills/` 아래 존재하는지 확인한다.
- baseline 문서가 필요한 상황에서 상태 요약 또는 추천 사유에 그 정보가 누락되지 않았는지 확인한다.
@@ -0,0 +1,75 @@
---
name: suggest-batch-reqs
description: "Use when: recommending delivery batch groupings from approved requirements, running /suggest-batch-reqs with a Discovery ID or REQ list, assessing cohesion and delivery risk, or preparing input for /draft-batch without changing repository state."
argument-hint: "예: dcy-001 또는 req-001 req-002 req-003"
user-invocable: true
---
# Purpose
This skill recommends one or more candidate batch groupings from approved requirements and reports rationale, exclusions, risk, and confidence without modifying any files. 입력이 없으면 현재 저장소에서 아직 delivery 입력으로 소모되지 않은 Approved REQ를 찾아 이번 batch 후보를 추천한다.
# When to use
- Approved REQ가 여러 개 쌓여 어떤 묶음으로 delivery를 시작할지 추천이 필요할 때
- `/suggest-batch-reqs dcy-001` 또는 `/suggest-batch-reqs req-001 req-002`처럼 batch 후보안을 받아야 할 때
- `/suggest-batch-reqs`처럼 인자 없이 현재 저장소의 Approved REQ 중 아직 구현 완료 또는 기존 batch 편성이 끝나지 않은 후보만 추려 이번 batch 권장안을 보고 싶을 때
- `draft-batch` 실행 전에 포함/제외 REQ 근거를 미리 보고 싶을 때
# Inputs
- 선택 입력
- `DISCOVERY_ID` 또는 Approved `REQ-ID` 목록
- 입력이 없으면 `docs/srs/**/req-*.md`와 `docs/srs/index.md`를 읽어 Approved REQ를 찾는다.
- 입력이 없으면 `docs/batches/index.md`도 함께 읽어 이미 batch에 편성된 REQ를 제외한다.
- 선택 입력
- batch 최대 크기
- Type, Priority, Owner 필터
- 제외할 REQ 목록
- 강제로 함께 고려할 REQ 목록
# Core Rules
- 이 skill은 추천만 수행하고 저장소 상태를 바꾸지 않는다.
- `Approved`가 아닌 REQ는 후보에서 제외한다.
- 입력이 없는 경우 `Implemented` 상태 REQ는 후보에서 제외한다.
- 입력이 없는 경우 `docs/batches/index.md` 기준으로 `draft`, `in-delivery`, `release-candidate`, `released` batch에 이미 포함된 REQ는 중복 추천하지 않는다.
- 아래 조건을 많이 만족할수록 같은 batch 후보로 묶는다.
- 같은 사용자 가치 또는 기능 흐름
- 같은 모듈, 인터페이스, 런타임 경로
- 같은 설계 전제와 환경 가정
- 같은 iteration 안에서 구현과 검증 가능
- acceptance criteria를 함께 검증하는 것이 효율적임
- release 시 함께 배포해도 위험이 과도하지 않음
- 아래 조건이 있으면 같은 batch로 묶지 않는다.
- 핵심 설계 전제 충돌
- 완전히 다른 verification 흐름 필요
- 독립 배포가 필요한 고위험 변경
- 미해결 정책 결정이나 외부 의존성으로 planning이 불안정함
# Execution Procedure
1. 입력이 Discovery면 연결된 REQ 후보를 찾고, 입력이 REQ 목록이면 각 REQ 문서를 읽는다.
2. 입력이 없으면 `docs/srs/**/req-*.md`, `docs/srs/index.md`, `docs/batches/index.md`를 읽어 Approved REQ 전체를 찾고, `Implemented` 상태 또는 기존 batch에 이미 포함된 REQ를 제외해 현재 후보군을 만든다.
3. 각 REQ의 상태, Type, Impacted Area, Acceptance Criteria를 요약한다.
4. 후보군에서 Approved REQ만 추린 뒤 응집도와 delivery risk 기준으로 후보안을 1개 이상 만든다.
5. 각 후보에 대해 포함 REQ, 제외 REQ와 제외 이유, 추천 근거, 위험도, 신뢰도를 정리한다.
6. 바로 사용할 수 있는 `/draft-batch ...` 입력 예시를 제시한다.
# Output Expectations
- 후보 `BAT-CANDIDATE-N` 목록
- 입력이 없는 경우 스캔한 Approved REQ 목록
- 후보별 포함 REQ
- 후보별 제외 REQ와 제외 이유
- 후보별 추천 근거
- 후보별 위험도 (`Low|Medium|High`)
- 후보별 신뢰도 (`High|Medium|Low`)
- `draft-batch` 추천 명령 예시
# Validation
- 출력에 `Approved`가 아닌 REQ가 포함되지 않았는지 확인한다.
- 입력이 없는 경우 `Implemented` 상태 REQ와 기존 batch에 이미 포함된 REQ가 후보에 남아 있지 않은지 확인한다.
- 추천안이 2개 이상일 때는 최소 1개는 작은 묶음 또는 보수적 대안을 포함한다.
- 적절한 묶음이 없으면 `단일 REQ batch 권장`을 명시한다.
@@ -0,0 +1,63 @@
---
name: suggest-next-discovery
description: "Use when: recommending the next Discovery candidate from release feedback, pending requirements, baseline gaps, or recent doctor reports, running /suggest-next-discovery with or without a REL ID, or deciding whether feedback should become a new Discovery or a change-req instead."
argument-hint: "예: rel-001 또는 인자 없이 /suggest-next-discovery"
user-invocable: true
---
# Purpose
This skill analyzes release feedback, pending REQs, baseline gaps, and recent delivery signals to recommend the next improvement loop. It reports ranked candidates and tells the user whether to start a new Discovery or route work into `change-req` instead.
# When to use
- `/suggest-next-discovery`처럼 다음 반복 주제를 추천받고 싶을 때
- `feedback-captured` release 이후 어떤 후속 Discovery를 열지 정해야 할 때
- release feedback에 기존 REQ 수정과 신규 Discovery 후보가 섞여 있어 triage가 필요할 때
- `stagepilot-doctor --report ...` 결과와 release feedback를 함께 보고 다음 개선 루프를 정하고 싶을 때
# Inputs
- 선택 입력
- `REL-ID` prefix 또는 release 경로
- 입력이 없으면 `docs/releases/*.md`, `docs/srs/index.md`, `docs/project-structure.md`, `docs/runtime-flows.md`를 읽어 후보를 찾는다.
- 선택 입력
- `stagepilot-doctor` Markdown report 경로
- 관련 release 문서의 `Feedback Handoff`
- `docs/srs/index.md`와 미구현/변경 대기 REQ 상태
- `docs/project-structure.md`, `docs/runtime-flows.md` (존재하는 경우)
# Core Rules
- 이 skill은 추천만 수행하고 저장소 상태를 바꾸지 않는다.
- release feedback의 후보는 아래 셋 중 하나로 분류한다.
- `new-discovery`
- `change-req`
- `no-action`
- 기존 REQ의 수정으로 닫히는 항목은 새 Discovery보다 `change-req`를 우선 추천한다.
- 서로 다른 가치 흐름이나 이해관계자를 가지는 후보는 별도 Discovery로 분리한다.
- 추천에는 가치, 위험, 노력의 상대 평가를 포함한다.
# Execution Procedure
1. 입력 release가 있으면 해당 문서를, 없으면 최근 release 문서들을 읽는다.
2. `Feedback Handoff`에서 Discovery Input, REQ Input, Change Request Input을 추린다.
3. `docs/srs/index.md`와 관련 REQ 상태를 읽어 기존 REQ 수정으로 해결 가능한지 판정한다.
4. baseline 문서 gap, 미구현 REQ, doctor report의 경고/오류가 후속 반복 후보인지 함께 판단한다.
5. 후보를 `new-discovery` 또는 `change-req`로 분류하고 가치/위험/노력 점수를 매긴다.
6. 우선순위 순으로 추천 목록과 바로 실행할 명령 예시를 제시한다.
# Output Expectations
- 후보 목록 (`CANDIDATE-1`, `CANDIDATE-2`, ...)
- 각 후보의 분류 (`new-discovery` | `change-req` | `no-action`)
- 근거 release 또는 REQ
- 가치/위험/노력 (`High|Medium|Low`)
- 추천 이유
- 다음 명령 예시 (`/new-discovery ...` 또는 `/change-req ...`)
# Validation
- 동일 후보를 `new-discovery`와 `change-req`에 중복 배치하지 않았는지 확인한다.
- release feedback 근거가 없는 임의 후보를 만들지 않았는지 확인한다.
- 기존 REQ 수정으로 닫히는 항목을 새 Discovery로 과도하게 승격하지 않았는지 확인한다.
+25
View File
@@ -0,0 +1,25 @@
# {{BAT_ID}}: <배치 제목>
- Status: draft | in-delivery | release-candidate | released | archived
- Profile: standard | batch-lite
- Source Discovery: <dcy-id 또는 없음>
- Included REQ: <REQ-ID 목록>
- Excluded REQ: <REQ-ID 목록 또는 없음>
## Summary
- <이 batch를 왜 묶었는지>
## Scope
- In Scope:
- <포함 범위>
- Out of Scope:
- <제외 범위>
## Documents
- Planning: [planning.md](./planning.md)
- Design: <`[design.md](./design.md)` 또는 `none (batch-lite with no architecture impact)`>
- Implementation: <`[implementation.md](./implementation.md)` 또는 `create at implementation stage`>
- Verification: <`[verification.md](./verification.md)` 또는 `create at verification stage`>
## Notes
- <공통 리스크, 공통 결정 사항>
+26
View File
@@ -0,0 +1,26 @@
# {{BAT_ID}} Design
- Status: draft | confirmed
- Batch: {{BAT_ID}}
## Architecture Summary
- <배치 수준 설계 요약>
## Changed Areas
- Docs: <문서 경로>
- Modules: <모듈/컴포넌트>
- Interfaces: <인터페이스>
## Key Decisions
1. <결정 1>
2. <결정 2>
## Edge Cases
- <예외 처리 및 설계 경계>
## Architecture Impact
- <none | project-structure | runtime-flows | both>
## Reference Doc Update Plan
- project-structure.md: <갱신 계획 또는 none>
- runtime-flows.md: <갱신 계획 또는 none>
@@ -0,0 +1,20 @@
# {{BAT_ID}} Implementation
- Status: draft | in-progress | completed
- Batch: {{BAT_ID}}
## Plan Summary
- <이번 구현에서 실제 변경할 범위>
## Changed Files
- <파일 목록>
## Execution Log
1. <실행 항목>
2. <실행 항목>
## Validation
- <실행한 테스트, lint, typecheck, 수동 점검>
## Remaining Risks
- <잔여 이슈>
+10
View File
@@ -0,0 +1,10 @@
# Batch Index
## 목적
- 이 문서는 batch delivery 단위의 전역 인덱스다.
- 각 batch는 `docs/batches/<BAT_ID>/` 아래에서 profile(`standard` | `batch-lite`)에 맞는 산출물을 관리한다.
## Batch Register
| BAT ID | Profile | Status | Included REQ | Discovery | Folder |
| --- | --- | --- | --- | --- | --- |
+28
View File
@@ -0,0 +1,28 @@
# {{BAT_ID}} Planning
- Status: draft | confirmed
- Batch: {{BAT_ID}}
- Profile: standard | batch-lite
## Included REQ
- <REQ-ID 목록>
## Delivery Plan
- <구현 범위, 순서, 선행 조건>
## Dependencies
- Internal:
- <내부 의존성>
- External:
- <외부 의존성>
## Design Gate
- Design Required Before Implementation: yes | no
- Reason: <왜 즉시 design이 필요한지 또는 왜 생략 가능한지>
## Milestones
1. <마일스톤>
2. <마일스톤>
## Risks
- <리스크와 대응>
+21
View File
@@ -0,0 +1,21 @@
# {{BAT_ID}} Verification
- Status: draft | confirmed
- Batch: {{BAT_ID}}
## Acceptance Mapping
- <REQ-ID>:
- <AC와 evidence 연결>
## Evidence
- Test:
- <테스트 결과>
- Manual:
- <수동 검증 결과>
- Logs:
- <로그 또는 스크린샷 경로>
## Result
- Ready for Release: false
- Blocking Issues:
- <차단 이슈 또는 없음>
@@ -0,0 +1,95 @@
schema_version: 1
capture_mode: declared # declared | observed | mixed
project:
repository_name: {{REPOSITORY_NAME:repo-folder-name}}
display_name: {{PROJECT_NAME:display name or repo name}}
summary: {{PROJECT_SUMMARY:one-sentence project summary}}
primary_domain: {{PRIMARY_DOMAIN:short domain phrase or undecided}}
stack:
tech_stack:
- {{TECH_STACK_ITEM_1:primary language or framework}}
runtime:
primary_runtime: {{PRIMARY_RUNTIME:cli|api-service|web-app|worker|library|mixed|other}}
primary_entrypoints:
- name: {{ENTRYPOINT_NAME_1:command or interface name}}
purpose: {{ENTRYPOINT_PURPOSE_1:brief purpose}}
interfaces:
contracts:
- name: {{INTERFACE_NAME_1:primary interface name}}
type: {{INTERFACE_TYPE_1:http-api|cli|event|file|internal-service|other}}
actors: {{INTERFACE_ACTORS_1:who calls or receives it}}
purpose: {{INTERFACE_PURPOSE_1:what this interface exists to do}}
stability: {{INTERFACE_STABILITY_1:experimental|internal|stable}}
inputs:
- {{INTERFACE_INPUT_1_1:input contract or invocation note}}
outputs:
- {{INTERFACE_OUTPUT_1_1:output contract or artifact}}
errors:
- {{INTERFACE_ERROR_1_1:error code or failure behavior}}
compatibility_rules:
- {{INTERFACE_COMPATIBILITY_1_1:compatibility or versioning rule}}
- name: {{INTERFACE_NAME_2:secondary interface name}}
type: {{INTERFACE_TYPE_2:http-api|cli|event|file|internal-service|other}}
actors: {{INTERFACE_ACTORS_2:who calls or receives it}}
purpose: {{INTERFACE_PURPOSE_2:what this interface exists to do}}
stability: {{INTERFACE_STABILITY_2:experimental|internal|stable}}
inputs:
- {{INTERFACE_INPUT_2_1:input contract or invocation note}}
outputs:
- {{INTERFACE_OUTPUT_2_1:output contract or artifact}}
errors:
- {{INTERFACE_ERROR_2_1:error code or failure behavior}}
compatibility_rules:
- {{INTERFACE_COMPATIBILITY_2_1:compatibility or versioning rule}}
shared_constraints:
- {{INTERFACE_SHARED_CONSTRAINT_1:cross-cutting interface constraint}}
current_gaps:
- {{INTERFACE_GAP_1:known contract gap or planned change}}
structure:
planned_top_level_areas:
- path: {{TOP_LEVEL_PATH_1:path such as src/ or app/}}
responsibility: {{TOP_LEVEL_RESPONSIBILITY_1:brief responsibility}}
data_model:
persistence_backend: {{PERSISTENCE_BACKEND:primary persistence backend or storage system}}
entities:
- name: {{ENTITY_NAME_1:primary entity}}
purpose: {{ENTITY_PURPOSE_1:what this entity represents}}
source_of_truth: {{ENTITY_SOURCE_1:table, collection, file, or service}}
lifecycle: {{ENTITY_LIFECYCLE_1:created -> updated -> archived}}
key_fields:
- {{ENTITY_FIELD_1_1:field :: type :: meaning}}
relationships:
- {{ENTITY_RELATIONSHIP_1_1:related entity :: relationship meaning}}
state_rules:
- {{ENTITY_STATE_RULE_1_1:state or invariant rule}}
- name: {{ENTITY_NAME_2:secondary entity}}
purpose: {{ENTITY_PURPOSE_2:what this entity represents}}
source_of_truth: {{ENTITY_SOURCE_2:table, collection, file, or service}}
lifecycle: {{ENTITY_LIFECYCLE_2:created -> updated -> archived}}
key_fields:
- {{ENTITY_FIELD_2_1:field :: type :: meaning}}
relationships:
- {{ENTITY_RELATIONSHIP_2_1:related entity :: relationship meaning}}
state_rules:
- {{ENTITY_STATE_RULE_2_1:state or invariant rule}}
consistency_rules:
- {{CONSISTENCY_RULE_1:consistency or referential rule}}
persistence_notes:
- {{PERSISTENCE_NOTE_1:mapping, storage, or migration note}}
current_gaps:
- {{MODEL_GAP_1:known model gap or planned schema change}}
notes:
known_unknowns:
- {{KNOWN_UNKNOWN_1:optional unresolved bootstrap item or none}}
metadata:
captured_at_kst: {{CAPTURED_AT_KST:YYYY-MM-DD HH:MM}}
source: bootstrap-baseline-questionnaire
updated_from: {{UPDATED_FROM:user-answer|repo-observation|mixed}}
+88
View File
@@ -0,0 +1,88 @@
# {{PROJECT_NAME}} Data Model
- Baseline Mode: {{BASELINE_MODE:declared|observed|mixed}}
- Baseline Seed: {{BASELINE_SEED_PATH:.stagepilot/bootstrap/baseline.yaml}}
- Status: draft | confirmed
- Owner: {{OWNER_OR_TEAM}}
- Last Updated (KST): {{UPDATED_AT_KST}}
- Source Discovery / Batch: {{SOURCE_REF}}
## Project Summary
- {{PROJECT_SUMMARY:one-sentence summary of the project}}
## Primary Domain
- {{PRIMARY_DOMAIN:short domain phrase or undecided}}
## Primary Persistence Backend
- {{PERSISTENCE_BACKEND:primary persistence backend or storage system}}
## Purpose
- This document captures the approved cross-cutting data model baseline for the project.
- It is a shared reference for REQ drafting, batch design, implementation, verification, migration planning, and handoff.
## Scope
- Covers core entities, relationships, states, persistence mappings, and shared consistency rules.
- Does not duplicate full functional acceptance criteria already owned by REQ documents.
- Does not replace ORM definitions, migration files, or generated schema artifacts.
## Model Summary
{{MODEL_SUMMARY_BULLETS:- - <entity name> :: <role in the system>}}
## Entity: `{{ENTITY_NAME_1:primary entity}}`
- Purpose: {{ENTITY_PURPOSE_1:what this entity represents}}
- Source of Truth: {{ENTITY_SOURCE_1:table, collection, file, or service}}
- Lifecycle: {{ENTITY_LIFECYCLE_1:created -> updated -> archived}}
### Key Fields
{{ENTITY_FIELDS_1:- <field name> :: <type or shape> :: <meaning>}}
### Relationships
{{ENTITY_RELATIONSHIPS_1:- <related entity> :: <relationship meaning>}}
### State Rules
{{ENTITY_STATE_RULES_1:- <state or invariant rule>}}
## Entity: `{{ENTITY_NAME_2:secondary entity}}`
- Purpose: {{ENTITY_PURPOSE_2:what this entity represents}}
- Source of Truth: {{ENTITY_SOURCE_2:table, collection, file, or service}}
- Lifecycle: {{ENTITY_LIFECYCLE_2:created -> updated -> archived}}
### Key Fields
{{ENTITY_FIELDS_2:- <field name> :: <type or shape> :: <meaning>}}
### Relationships
{{ENTITY_RELATIONSHIPS_2:- <related entity> :: <relationship meaning>}}
### State Rules
{{ENTITY_STATE_RULES_2:- <state or invariant rule>}}
## Shared Consistency Rules
{{CONSISTENCY_RULE_BULLETS:- - <uniqueness, referential, or retention rule>}}
## Persistence / Integration Notes
{{PERSISTENCE_NOTES_BULLETS:- - <mapping, indexing, migration, or synchronization note>}}
## Current Gaps / Planned Changes
{{MODEL_CURRENT_GAPS_BULLETS:- - <known model gap or planned schema change>}}
## Update Triggers
- Update this document when a core entity, key field, or relationship changes.
- Update this document when lifecycle or persistence behavior changes.
- Update this document when a batch introduces a migration, backfill, or breaking data assumption.
## Change Log
{{CHANGE_LOG_BULLETS:- - <change log entry>}}
+224
View File
@@ -0,0 +1,224 @@
# 0. 문서 상태
이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다.
- 상태: {{DOC_STATUS:draft|review|confirmed}}
- 문서 ID: {{DISCOVERY_ID:dcy-<3자리>_<YYYYMMDD>_<topic-slug>}}
- 이슈명: {{ISSUE_NAME:짧은 한글 또는 영문 이슈명}}
- 작성 시각(KST): {{CREATED_AT_KST:TBD}}
- 마지막 갱신 시각(KST): {{UPDATED_AT_KST:TBD}}
- 대체됨: {{SUPERSEDED_BY_DISCOVERY:없음 또는 docs/discovery/<DISCOVERY_ID>.md}}
- 후속 Discovery 참조: {{FOLLOW_UP_DISCOVERY_REF:없음 또는 docs/discovery/<DISCOVERY_ID>.md}}
- 생성된 REQ 참조: 없음
# 1. 계획 상태 요약
현재 Discovery가 어떤 배경에서 작성되고 있는지, 연계 문서가 있는지, 지금 시점의 해석이 무엇인지 짧게 요약한다.
- 연계 문서 현황:
- 관련 점수 파일: {{RELATED_SCORE_FILE:미생성 또는 경로}}
- 관련 TODO/메모: {{TODO_FILE:경로 또는 없음}}
- 해석:
- {{SUMMARY_LINE_1:현재 검토/작성 배경 요약}}
- {{SUMMARY_LINE_2:이번 Discovery에서 판단해야 할 핵심 요약}}
# 2. 요구사항 판정 결과
이번 요청이 기존 요구사항과 비교해 신규인지, 유사한지, 중복인지 판단하고 그 근거를 남긴다.
- 판정: {{REQUIREMENT_CLASSIFICATION:완전 중복|유사|신규}}
- 근거
- {{CLASSIFICATION_REASON_1}}
- {{CLASSIFICATION_REASON_2}}
> **판정이 `완전 중복`인 경우**: 이하 섹션 작성을 중단하고 `# 9. 파일 처리 결과`에 중복 판정 사유와 참조 문서 경로를 기록한 뒤 문서를 닫는다. REQ 초안 작성으로 넘기지 않는다.
# 3. 문제점의 요약
문제의 현재 상태, 기대 상태, 관련 이해관계자, 제약사항을 정리한다. Discovery의 핵심 맥락을 가장 먼저 이해할 수 있어야 한다.
- 현재 상태
- {{CURRENT_STATE_1}}
- {{CURRENT_STATE_2}}
- 기대 상태
- {{TARGET_STATE_1}}
- {{TARGET_STATE_2}}
- 이해관계자
- {{STAKEHOLDER_1:예. 문서 작성자(AI agent)}}
- {{STAKEHOLDER_2:예. 리뷰어/승인자}}
- {{STAKEHOLDER_3:예. 운영 담당자}}
- 제약사항
- {{CONSTRAINT_1}}
- {{CONSTRAINT_2}}
## 주요 사용자 시나리오
사용자 또는 운영자가 실제로 어떤 상황에서 이 변경을 필요로 하는지 대표 시나리오를 적는다.
- {{USER_SCENARIO_1}}
- {{USER_SCENARIO_2}}
- {{USER_SCENARIO_3}}
# 4. 이번에 정의할 변경
이번 Discovery에서 다루는 핵심 변경 항목을 목록으로 적는다. 기능, 구조, 규칙 변경을 함께 포함해도 된다.
- {{CHANGE_ITEM_1}}
- {{CHANGE_ITEM_2:필요 없으면 삭제}}
- {{CHANGE_ITEM_3:필요 없으면 삭제}}
## 영향 범위
변경이 미칠 코드/문서/운영 범위를 명시해 REQ 정제와 batch planning에서 추정 누락을 줄인다.
- 코드 영향:
- {{CODE_IMPACT_1:예. docs/discovery/index.md 갱신 로직}}
- {{CODE_IMPACT_2:필요 없으면 삭제}}
- 문서 영향:
- {{DOC_IMPACT_1}}
- {{DOC_IMPACT_2:필요 없으면 삭제}}
- 운영 영향:
- {{OPS_IMPACT_1:예. 배포/운영 절차 변경 없음}}
- {{OPS_IMPACT_2:필요 없으면 삭제}}
# 5. 요구사항 목록
실제로 구현과 검증으로 이어질 요구사항을 기능/비기능으로 나누어 정리하고, 범위 경계를 명확히 적는다.
## 기능 요구사항
- FR-1: {{FR_1}}
- FR-2: {{FR_2}}
- FR-3: {{FR_3:필요 없으면 삭제}}
- FR-4: {{FR_4:필요 없으면 삭제}}
## 비기능 요구사항
성능, 운영성, 일관성, 자동화 안정성 등 기능 외 요구사항을 적는다.
- NFR-1: {{NFR_1}}
- NFR-2: {{NFR_2}}
- NFR-3: {{NFR_3:필요 없으면 삭제}}
## 범위 경계
이번 반복에서 반드시 포함할 범위와 명시적으로 제외할 범위를 구분한다.
- In Scope
- {{IN_SCOPE_1}}
- {{IN_SCOPE_2}}
- Out of Scope
- {{OUT_OF_SCOPE_1}}
- {{OUT_OF_SCOPE_2}}
# 6. 리스크/가정 목록
불확실성과 전제 조건을 분리해서 적는다. 리스크는 영향과 완화 방안을, 가정은 현재 판단의 전제를 기록한다.
## 리스크
- R-1 ({{RISK_LEVEL_1:High|Medium|Low}}): {{RISK_1}}
- 완화 방안: {{MITIGATION_1}}
- R-2 ({{RISK_LEVEL_2:High|Medium|Low}}): {{RISK_2}}
- 완화 방안: {{MITIGATION_2}}
- R-3 ({{RISK_LEVEL_3:High|Medium|Low}}): {{RISK_3:필요 없으면 삭제}}
- 완화 방안: {{MITIGATION_3:필요 없으면 삭제}}
## 가정
아직 확정되지 않았지만 현재 문서 작성의 기반이 되는 전제를 적는다.
- A-1: {{ASSUMPTION_1}}
- A-2: {{ASSUMPTION_2}}
- A-3: {{ASSUMPTION_3:필요 없으면 삭제}}
## 오픈 질문
답을 아직 모르는 항목을 적는다. 추정으로 덮지 말고 REQ 초안 작성 이전에 확인할 질문으로 남긴다.
- OQ-1: {{OPEN_QUESTION_1}}
- 상태: {{OPEN_QUESTION_STATUS_1:Open|Answered|Deferred|Dropped}}
- 처리 방안: {{OPEN_QUESTION_ACTION_1:누가 어떤 방식으로 결정/확인할지}}
- 종료 조건: {{OPEN_QUESTION_EXIT_1:언제 이 질문을 Answered/Deferred/Dropped로 처리할지}}
- OQ-2: {{OPEN_QUESTION_2}}
- 상태: {{OPEN_QUESTION_STATUS_2:Open|Answered|Deferred|Dropped}}
- 처리 방안: {{OPEN_QUESTION_ACTION_2:누가 어떤 방식으로 결정/확인할지}}
- 종료 조건: {{OPEN_QUESTION_EXIT_2:언제 이 질문을 Answered/Deferred/Dropped로 처리할지}}
- OQ-3: {{OPEN_QUESTION_3:필요 없으면 삭제}}
- 상태: {{OPEN_QUESTION_STATUS_3:Open|Answered|Deferred|Dropped}}
- 처리 방안: {{OPEN_QUESTION_ACTION_3:누가 어떤 방식으로 결정/확인할지}}
- 종료 조건: {{OPEN_QUESTION_EXIT_3:언제 이 질문을 Answered/Deferred/Dropped로 처리할지}}
### 오픈 질문 처리 기준
- `Open`: 아직 답이 없고 다음 단계 진행에 영향이 있는 상태다. 문서에 유지한다.
- `Answered`: 답이 확정된 상태다. 관련 본문/요구사항에 반영한 뒤 오픈 질문 목록에서는 제거하거나 resolved 기록으로 이동한다.
- `Deferred`: 지금 단계에서 결정하지 않고 다음 단계 또는 후속 이슈로 넘기는 상태다. 넘길 대상과 이유를 반드시 적는다.
- `Dropped`: 더 이상 유효하지 않은 질문이다. 삭제 사유를 짧게 남기고 목록에서 제거한다.
- 처리 원칙 1: 질문만 남기지 말고 반드시 `상태`, `처리 방안`, `종료 조건`을 함께 적는다.
- 처리 원칙 2: 답이 나온 질문은 본문 반영 없이 단순 삭제하지 않는다. 반영 위치를 먼저 갱신한다.
- 처리 원칙 3: High 영향 질문은 `Deferred` 처리 후 처리 방안에 REQ 인계 추적 방식을 명시한다.
# 7. 초기 성공 기준
이 변경이 성공했다고 판단할 기준을 측정 가능하게 정의한다. 가능하면 데이터 출처까지 연결한다.
- S-1: {{SUCCESS_METRIC_1}}
- S-2: {{SUCCESS_METRIC_2}}
- S-3: {{SUCCESS_METRIC_3:필요 없으면 삭제}}
## 측정 방식 및 데이터 출처
각 성공 기준을 어떻게 측정할지와 어떤 데이터나 문서를 근거로 쓸지 적는다.
- S-1 측정 방식: {{MEASURE_METHOD_1}} / 데이터 출처: {{MEASURE_SOURCE_1}}
- S-2 측정 방식: {{MEASURE_METHOD_2}} / 데이터 출처: {{MEASURE_SOURCE_2}}
- S-3 측정 방식: {{MEASURE_METHOD_3:필요 없으면 삭제}} / 데이터 출처: {{MEASURE_SOURCE_3:필요 없으면 삭제}}
# 8. REQ로 넘기기 전 확인 체크
REQ 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. 미완료 항목은 후속 결정이 필요함을 뜻한다.
- [ ] 범위(In Scope/Out of Scope) 확정
- 기준: {{CHECK_SCOPE_CRITERIA}}
- [ ] 성공 지표의 측정 방식/데이터 출처 확정
- 기준: {{CHECK_METRICS_CRITERIA}}
- [ ] High 영향 리스크 우선순위 및 해소 책임자 지정
- 기준: {{CHECK_RISK_OWNER_CRITERIA}}
- [ ] 모든 오픈 질문(OQ) `Open` 상태 없음 확인
- 기준: OQ 목록에 `Open` 상태 항목이 0개이거나, 잔여 항목 전부 `Deferred` 처리 완료
- [ ] Freeze 확정 담당자(CONFIRMED_BY) 지정
- 기준: {{CHECK_CONFIRMEDBY_CRITERIA}}
# 9. 파일 처리 결과
이 Discovery 문서 생성/갱신 결과와 참조 문서를 기록한다. 이후 추적과 리뷰 시 근거로 사용한다.
- 처리 결과: {{FILE_RESULT:생성|갱신|미생성}}
- 생성 경로: {{OUTPUT_PATH}}
- 참조 문서:
- {{REFERENCE_1}}
- {{REFERENCE_2}}
- {{REFERENCE_3:필요 없으면 삭제}}
# 10. 사용자 결정 필요 항목 요약
사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. 결정, 확인, 데이터 요청을 구분해서 적는다.
## DECIDE
- {{DECIDE_ITEM_1}}
- {{DECIDE_ITEM_2:필요 없으면 삭제}}
## CONFIRM
- {{CONFIRM_ITEM_1}}
- {{CONFIRM_ITEM_2:필요 없으면 삭제}}
## DATA
- {{DATA_ITEM_1}}
- {{DATA_ITEM_2:필요 없으면 삭제}}
# 11. Discovery Freeze
REQ 초안 작성 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다.
## 섹션 참조
- 범위: [# 5. 요구사항 목록 > 범위 경계](#5-요구사항-목록)
- 리스크/오픈 질문: [# 6. 리스크/가정 목록](#6-리스크가정-목록)
- 성공 기준: [# 7. 초기 성공 기준](#7-초기-성공-기준)
- 인계 전 확인: [# 8. REQ로 넘기기 전 확인 체크](#8-req로-넘기기-전-확인-체크)
- 사용자 결정 필요: [# 10. 사용자 결정 필요 항목 요약](#10-사용자-결정-필요-항목-요약)
## Freeze 플래그
- Handoff Decision: {{FREEZE_HANDOFF_DECISION:REQ Drafting 진행 가능|보류}}
- Handoff Rationale: {{FREEZE_HANDOFF_RATIONALE:진행 가능 또는 보류 판단 근거 1-2줄}}
- Ready for REQ Drafting: {{READY_FOR_REQ_DRAFTING:false}}
- Confirmed By: {{CONFIRMED_BY:TBD}}
- Confirmed At (KST): {{CONFIRMED_AT_KST:TBD}}
# 12. 작성 가이드
템플릿 사용 시의 기본 규칙을 적는다. 실제 문서를 만들 때는 이 가이드를 기준으로 플레이스홀더를 치환한다.
- 이 파일은 템플릿이다. 실제 문서 작성 시 `{{...}}` 플레이스홀더를 구체 값으로 교체한다.
- 필요 없는 항목은 삭제하고, 부족한 항목은 같은 형식으로 추가한다.
- Open Questions는 가정으로 대체하지 말고 그대로 유지한다.
- `대체됨`은 현재 Discovery가 더 이상 기준 문서가 아닐 때 대체 Discovery 경로를 기록하고, 해당 사항이 없으면 `없음`으로 둔다.
- `후속 Discovery 참조`는 범위를 이어받는 별도 Discovery가 생성된 경우 그 Discovery 경로를 기록하고, 없으면 `없음`으로 둔다.
- Discovery Freeze는 문서 하단에 반드시 유지한다.
+8
View File
@@ -0,0 +1,8 @@
# Discovery 전체 인덱스
<!-- 아래 테이블은 /new-discovery 실행 시 자동 갱신된다. 수동 편집 금지. -->
## Discovery 목록
| ID | 날짜 | 이슈명 | 문서 | 상태 |
|---|---|---|---|---|
+92
View File
@@ -0,0 +1,92 @@
# {{PROJECT_NAME}} Interface Contract
- Baseline Mode: {{BASELINE_MODE:declared|observed|mixed}}
- Baseline Seed: {{BASELINE_SEED_PATH:.stagepilot/bootstrap/baseline.yaml}}
- Status: draft | confirmed
- Owner: {{OWNER_OR_TEAM}}
- Last Updated (KST): {{UPDATED_AT_KST}}
- Source Discovery / Batch: {{SOURCE_REF}}
- Primary Runtime: {{PRIMARY_RUNTIME:cli|api-service|web-app|worker|library|mixed|other}}
## Project Summary
- {{PROJECT_SUMMARY:one-sentence summary of the project}}
## Primary Domain
- {{PRIMARY_DOMAIN:short domain phrase or undecided}}
## Purpose
- This document captures the approved external and cross-boundary interface contracts for the project.
- It is a cross-cutting reference for REQ drafting, batch design, implementation, verification, and handoff.
## Scope
- Covers externally visible APIs, CLI surfaces, events, files, or batch I/O contracts.
- Does not duplicate full business requirements already owned by REQ documents.
- Does not replace low-level code references or generated API artifacts.
## Interface Summary
{{INTERFACE_SUMMARY_BULLETS:- - <interface name> :: <purpose>}}
## Interface: `{{INTERFACE_NAME_1:primary interface name}}`
- Type: {{INTERFACE_TYPE_1:http-api|cli|event|file|internal-service|other}}
- Consumers / Producers: {{INTERFACE_ACTORS_1:who calls or receives it}}
- Purpose: {{INTERFACE_PURPOSE_1:what this interface exists to do}}
- Stability: {{INTERFACE_STABILITY_1:experimental|internal|stable}}
### Inputs
{{INTERFACE_INPUTS_1:- <input field or argument> :: <meaning>}}
### Outputs
{{INTERFACE_OUTPUTS_1:- <output field or artifact> :: <meaning>}}
### Error Contract
{{INTERFACE_ERRORS_1:- <error code or condition> :: <behavior>}}
### Compatibility Rules
{{INTERFACE_COMPATIBILITY_1:- <versioning or compatibility rule>}}
## Interface: `{{INTERFACE_NAME_2:secondary interface name}}`
- Type: {{INTERFACE_TYPE_2:http-api|cli|event|file|internal-service|other}}
- Consumers / Producers: {{INTERFACE_ACTORS_2:who calls or receives it}}
- Purpose: {{INTERFACE_PURPOSE_2:what this interface exists to do}}
- Stability: {{INTERFACE_STABILITY_2:experimental|internal|stable}}
### Inputs
{{INTERFACE_INPUTS_2:- <input field or argument> :: <meaning>}}
### Outputs
{{INTERFACE_OUTPUTS_2:- <output field or artifact> :: <meaning>}}
### Error Contract
{{INTERFACE_ERRORS_2:- <error code or condition> :: <behavior>}}
### Compatibility Rules
{{INTERFACE_COMPATIBILITY_2:- <versioning or compatibility rule>}}
## Shared Constraints
{{INTERFACE_SHARED_CONSTRAINTS_BULLETS:- - <authentication, timeout, idempotency, or size constraint>}}
## Current Gaps / Planned Changes
{{INTERFACE_CURRENT_GAPS_BULLETS:- - <known contract gap or planned interface change>}}
## Update Triggers
- Update this document when an externally visible API, event, CLI, or file contract changes.
- Update this document when a batch changes compatibility, validation, or error behavior.
- Update this document when a new external consumer or producer is introduced.
## Change Log
{{CHANGE_LOG_BULLETS:- - <change log entry>}}
+64
View File
@@ -0,0 +1,64 @@
# {{PROJECT_NAME}} Project Structure
- Baseline Mode: {{BASELINE_MODE:declared|observed|mixed}}
- Baseline Seed: {{BASELINE_SEED_PATH:.stagepilot/bootstrap/baseline.yaml}}
- Status: draft | confirmed
- Owner: {{OWNER_OR_TEAM}}
- Last Updated (KST): {{UPDATED_AT_KST}}
- Source Discovery / Batch: {{SOURCE_REF}}
## Project Summary
- {{PROJECT_SUMMARY:one-sentence summary of the project}}
## Primary Domain
- {{PRIMARY_DOMAIN:short domain phrase or undecided}}
## Tech Stack
{{TECH_STACK_BULLETS:- <planned stack item 1>
- <planned stack item 2>}}
## Primary Runtime
- Type: {{PRIMARY_RUNTIME:cli|api-service|web-app|worker|library|mixed|other}}
- Planned Entry Points:
{{PRIMARY_ENTRYPOINT_BULLETS:- <entrypoint> :: <purpose>}}
## Purpose
- This document is the current approved repository and package structure baseline.
- It is a cross-cutting reference document for Discovery, REQ, Batch Design, Batch Verification, and implementation updates.
## Scope
- Covers the top-level repository layout and package/module boundaries.
- Does not duplicate detailed business rules, acceptance criteria, or implementation-only function signatures.
## Top-Level Structure
```text
{{TOP_LEVEL_STRUCTURE_TREE:<text tree baseline>}}
```
## Package / Module Responsibilities
{{MODULE_RESPONSIBILITY_BULLETS:- `<path-or-package-1>`
- <responsibility summary>}}
## Dependency Rules
{{DEPENDENCY_RULE_BULLETS:- <dependency rule 1>}}
## Shared Boundaries
{{SHARED_BOUNDARY_BULLETS:- <shared boundary 1>}}
## Current Gaps / Planned Changes
{{CURRENT_GAPS_BULLETS:- <gap or planned structural change 1>}}
## Update Triggers
- Update this document when package boundaries change.
- Update this document when new top-level runtime or domain modules are added.
- Update this document when a batch changes the approved structure baseline.
## Change Log
{{CHANGE_LOG_BULLETS:- - <change log entry>}}
+10
View File
@@ -0,0 +1,10 @@
# Release Index
## 목적
- 이 문서는 release 단위의 전역 인덱스다.
- 각 release는 하나 이상의 release-candidate batch를 묶고, profile(`docs-only` | `tooling` | `app-service`)에 맞는 배포와 후속 환류를 추적한다.
## Release Register
| REL ID | Profile | Status | Included Batch | Discovery/REQ Input | Link |
| --- | --- | --- | --- | --- | --- |
+92
View File
@@ -0,0 +1,92 @@
# {{REL_ID}}: <릴리즈 제목>
- Status: draft | confirmed | released | feedback-captured
- Profile: docs-only | tooling | app-service
- Included Batch: <BAT-ID 목록>
## Scope
- Included:
- <포함 batch 또는 REQ>
- Excluded:
- <제외 범위>
## Rollout Plan
1. <배포 순서>
2. <배포 순서>
## Rollback Plan
- <롤백 조건과 절차>
## Verification Checklist
- <배포 전 확인>
- <배포 후 확인>
## Release Execution Evidence
- Release Status Transition Target: released
### Deployment Facts
- Executed At:
- <배포 시작 시각>
- Completed At:
- <배포 완료 시각>
- Environment:
- <배포 대상 환경>
- Operator:
- <배포 수행자>
- Revision or Artifact:
- <커밋 SHA 또는 배포 artifact 식별자>
- Commands or Procedure:
- <실행 명령 또는 배포 절차 요약>
### Profile-Specific Checks
- docs-only:
- Published or Packaged Targets:
- <문서 경로, 배포 산출물 또는 none>
- Link or Rendering Check:
- <링크 점검, 렌더링 확인 또는 none>
- Navigation or Consumer Update:
- <목차/가이드/릴리즈 노트 반영 결과 또는 none>
- tooling:
- Install or Upgrade Smoke:
- <설치/업데이트/부트스트랩 결과 또는 none>
- CLI or Script Execution:
- <명령 실행 결과 또는 none>
- Compatibility Note:
- <하위 호환성/운영자 영향 또는 none>
- app-service:
- Health Endpoint:
- <호출 결과와 확인 시각>
- Startup Log Fields:
- <app, event, command, run_id 확인 결과>
- Request Log Fields:
- <request_id 포함 여부와 확인 결과>
- Smoke or Manual Verification:
- <배포 후 재실행한 검증과 결과>
### Rollback Outcome
- Rollback Required:
- <yes 또는 no>
- Rollback Trigger:
- <발생 시 원인, 없으면 none>
- Rollback Action:
- <수행한 조치, 없으면 none>
### Release Decision Evidence
- Released Decision:
- <released 전환 여부>
- Rationale:
- <released 전환 판단 근거>
- Recorded By:
- <기록자>
- Recorded At:
- <기록 시각>
## Feedback Handoff
- Observation Summary:
- <운영 관찰 사실 요약 또는 없음>
- Discovery Input:
- <후속 discovery 후보>
- REQ Input:
- <후속 req 후보>
- Change Request Input:
- <기존 req 변경 후보>
+58
View File
@@ -0,0 +1,58 @@
# {{PROJECT_NAME}} Runtime Flows
- Baseline Mode: {{BASELINE_MODE:declared|observed|mixed}}
- Baseline Seed: {{BASELINE_SEED_PATH:.stagepilot/bootstrap/baseline.yaml}}
- Status: draft | confirmed
- Owner: {{OWNER_OR_TEAM}}
- Last Updated (KST): {{UPDATED_AT_KST}}
- Source Discovery / Batch: {{SOURCE_REF}}
- Primary Runtime: {{PRIMARY_RUNTIME:cli|api-service|web-app|worker|library|mixed|other}}
## Project Summary
- {{PROJECT_SUMMARY:one-sentence summary of the project}}
## Purpose
- This document is the current approved execution-flow baseline for the project.
- It is a cross-cutting reference document for Discovery, REQ, Batch Design, Batch Verification, and implementation updates.
## Scope
- Covers representative command and runtime flows.
- Does not duplicate full acceptance criteria or low-level implementation details.
## Covered Entry Points
{{PRIMARY_ENTRYPOINT_BULLETS:- <entry-point-1> :: <purpose>}}
## Shared Components
{{SHARED_COMPONENT_BULLETS:- <shared component or service 1>}}
## Flow: `{{FLOW_NAME_1:bootstrap or first runtime flow}}`
{{FLOW_STEPS_1:1. <step 1>
2. <step 2>
3. <step 3>}}
## Flow: `{{FLOW_NAME_2:secondary runtime flow or operation}}`
{{FLOW_STEPS_2:1. <step 1>
2. <step 2>
3. <step 3>}}
## Flow Constraints
{{FLOW_CONSTRAINT_BULLETS:- <flow constraint 1>}}
## Current Gaps / Planned Changes
{{CURRENT_GAPS_BULLETS:- <gap or planned flow change 1>}}
## Update Triggers
- Update this document when a command entry point changes.
- Update this document when a runtime orchestration path changes.
- Update this document when a batch changes the approved flow baseline.
## Change Log
{{CHANGE_LOG_BULLETS:- - <change log entry>}}
+87
View File
@@ -0,0 +1,87 @@
# Software Requirement Specification Index
## 목적
- 이 문서는 프로젝트의 SRS 운영 기준과 requirement 목록을 관리하는 entry point이다.
- 개별 requirement의 상세 내용은 타입별 폴더 하위 `req-XXX_*.md` 파일에서 관리한다.
## 사용 방법
1. 새로운 requirement가 필요하면 `Next Requirement ID`를 확인하고 `docs/srs/req-template.md`를 복사해 `docs/srs/<Type>/req-XXX_<slug>.md` 파일을 생성한다.
2. 초안 작성은 `draft-req`, 승인 전환은 `confirm-req`, 변경 대응은 `change-req`, 구현 완료 전환은 `confirm-req-implemented` skill을 기준으로 수행한다.
3. 작성 또는 수정 후 누락과 모호성을 점검한다.
4. requirement 추가 또는 변경 후 `Next Requirement ID`, `Requirement Register`, `Recent Change Log Summary`를 함께 갱신한다.
5. `Proposed` requirement를 승인하려면 승인 준비 상태와 blocker를 점검한다.
6. `Approved` requirement는 구현 이슈나 작업 항목으로 연결한다.
7. 구현과 검증이 끝난 requirement는 `confirm-req-implemented` skill로 완료 전환 가능 여부를 점검한다.
8. requirement 변경 시 `change-req` skill을 기준으로 해당 REQ 파일의 `Change Log`를 먼저 갱신한 뒤 본문을 수정한다.
9. 구현 전에는 관련 REQ 파일과 최근 `Change Log`를 기준으로 변경 범위를 판단한다.
## 상태 정의
- Proposed: 초안 상태이며 구현 기준으로 확정되지 않음
- Approved: 구현 기준으로 승인됨
- Implemented: 구현과 검증이 완료됨
- Deprecated: 더 이상 유지하지 않음
## Status Transition Evidence
### Proposed -> Approved
- `Status`, `Type`, `Priority`, `Owner`, `Intent`, `Requirement`, `Acceptance Criteria`, `Impacted Area`, `Change Log`가 모두 존재해야 한다.
- `Type`은 아래 분류 도표에서 정확하게 하나로 지정되어야 한다.
- `Acceptance Criteria`는 구현 판단에 사용할 수 있을 정도로 구체적이어야 한다.
- 미해결 assumption 또는 open question이 있으면 `Notes`에 명시하고, 승인 blocker 여부를 판단해야 한다.
- 승인 전환 시 해당 REQ 파일의 `Change Log`에 status 변경 사유를 기록해야 한다.
### Approved -> Implemented
- 각 `Acceptance Criteria`에 대해 test, manual verification, 또는 구현 결과 중 최소 1개의 evidence가 있어야 한다.
- evidence는 requirement 문서 자체 또는 연결된 구현/검증 결과에서 추적 가능해야 한다.
- 미충족 `Acceptance Criteria`가 있으면 `Implemented`로 전환하지 않는다.
- 구현 완료 전환 시 잔여 리스크와 미검증 영역이 있으면 `Change Log`에 기록해야 한다.
- 상태 전환은 `confirm-req-implemented` skill을 기준으로 수행한다.
### Requirement Change Handling
- 기존 REQ 본문(`Requirement`, `Acceptance Criteria`, `Impacted Area`)을 수정하기 전에는 새 `Change Log` 항목을 만든다.
- `Change Log`에는 최소한 `Acceptance Criteria Delta`, `Impacted Area Delta`, `Delivery Trace Delta`, `Revalidation Impact`, `Validation Plan`이 포함되어야 한다.
- 변경이 기존 구현 또는 verification evidence를 무효화하면 `Implemented` requirement는 `Approved`로 되돌린다.
- 변경이 승인 전제 자체를 다시 검토하게 만들면 `Approved` 또는 `Implemented` requirement를 `Proposed`로 되돌릴 수 있다.
- 상태 되돌림이 발생하면 `Requirement Register`와 `Recent Change Log Summary`도 함께 갱신한다.
## Requirement 타입 분류 도표
| 타입 | 정의 | 예시 |
|------|------|------|
| **Configuration** | 설정 옵션, 커스터마이징 포인트 | 설정 파라미터, 환경 변수, 옵션 항목 |
| **Data** | 데이터 구조, 저장/로드, 파일 형식, 스키마 | 설정 파일 형식, DB 스키마, API 구조 |
| **Deployment** | 배포 방식, 운영 절차, 배포 환경 | 컨테이너 배포, 스택 관리, 운영 가이드 |
| **Documentation** | 문서 작성, 가이드, 매뉴얼, 안내서 | 사용자 가이드, API 문서, 튜토리얼 |
| **Exception** | 오류 처리, 예외 복구, 재시도 전략 | 오류 복구, 검증 실패 처리, 폴백 전략 |
| **Installation** | 시스템 설치, 환경 구성, 초기화 절차 | Docker 이미지 빌드, DB 마이그레이션, 사전 조건 설정 |
| **Integration** | 외부 시스템 연동, 플러그인, 확장 | 3rd party 연동, 플러그인 인터페이스 |
| **Interface** | 사용자 상호작용 방식 (UI, API, CLI, 제어방식) | CLI 명령어, API 엔드포인트, 웹 UI 기능 |
| **Migration** | 데이터 이전, 버전 업그레이드 | 데이터 마이그레이션, 버전 호환성 |
| **Non-Functional** | 성능, 보안, 확장성, 호환성, 신뢰성 | 성능 목표, 보안 정책, 확장성 |
| **Testing** | 테스트 전략, QA 요구사항, 검증 방식 | 테스트 커버리지, 회귀 테스트, 수락 기준 |
## Requirement 작성 규칙
- 각 requirement는 고유 ID를 가진다. 예: `REQ-001`
- 다음 신규 requirement 번호의 source of truth는 이 문서의 `Next Requirement ID` 섹션이다.
- 새 requirement를 추가하거나 ID 충돌이 발생할 수 있는 변경을 했으면 `Next Requirement ID`를 함께 갱신한다.
- 각 requirement는 `Type`을 명시해야 한다. 위 분류 도표 중 정확하게 하나로 선택하며, `docs/srs/<Type>/` 폴더명도 같은 문자열을 사용한다.
- 각 requirement는 `Intent`, `Requirement`, `Acceptance Criteria`, `Impacted Area`를 반드시 포함한다.
- 모호한 표현("개선한다", "적절히 처리한다") 대신 관찰 가능하고 test 가능한 문장을 사용한다.
- requirement 변경 사항은 해당 REQ 파일의 `Change Log`에 기록한다.
- requirement 변경 시 영향 받는 batch/release와 재검증 필요 여부를 `Change Log`에 남긴다.
- `Recent Change Log Summary`는 최신 5건만 유지한다.
- status 전환은 `Status Transition Evidence` 기준을 따른다.
## Next Requirement ID
- Current: `REQ-001`
- Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다.
## Requirement Register
| ID | Title | Type | Status | Priority | Owner | Link |
| --- | --- | --- | --- | --- | --- | --- |
## Recent Change Log Summary
- 없음
+67
View File
@@ -0,0 +1,67 @@
# req-XXX: <요구사항 제목>
- Status: Proposed | Approved | Implemented | Deprecated
- Type: Configuration | Data | Deployment | Documentation | Exception | Installation | Integration | Interface | Migration | Non-Functional | Testing
- Priority: High | Medium | Low
- Owner: <담당자 또는 팀>
## Intent
- <이 요구사항이 필요한 이유와 달성하려는 목표를 1~3문장으로 작성>
## Requirement
- <시스템이 반드시 수행해야 하는 동작을 단정형 문장으로 작성>
## Acceptance Criteria
1. Given <선행 조건>, When <행동>, Then <기대 결과>
2. Given <선행 조건>, When <행동>, Then <기대 결과>
## Impacted Area
- Docs: <영향 받는 문서 경로>
- Modules: <영향 받는 모듈/컴포넌트>
- Tests: <추가/수정해야 하는 테스트>
## Notes
- <가정, 제약, 미해결 이슈>
## Change Log
### CHG-YYYYMMDD-01
- Date: YYYY-MM-DD
- Author: <작성자>
#### Change Summary
- <무엇이 변경되었는지>
#### Intent
- <왜 변경했는지>
#### Acceptance Criteria Delta
- Added:
- <추가된 기준>
- Updated:
- <변경된 기준>
- Removed:
- <삭제된 기준>
#### Impacted Area Delta
- Docs:
- <문서 영향>
- Modules:
- <코드 영향>
- Tests:
- <테스트 영향>
#### Delivery Trace Delta
- Batches:
- <영향 받는 batch 또는 none>
- Releases:
- <영향 받는 release 또는 none>
#### Revalidation Impact
- Reverification Needed: yes | no
- Existing Implementation Invalidated: yes | no
- Status Recommendation: keep-current | revert-to-approved | revert-to-proposed
- Follow-up Action: <필요한 재검증, 재배치, 후속 작업>
#### Validation Plan
- <검증 방법과 완료 조건>