diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index ffb529d..00ef918 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -11,22 +11,59 @@ # SDLC Governance Instructions 이 워크스페이스의 AI 에이전트는 Agile 중심 반복형 SDLC를 따른다. -모든 작업은 단계 기반으로 수행하며, 단계 스킵은 허용되지 않는다(긴급 핫픽스 예외는 별도 규칙 적용). +모든 작업은 3-phase 구조와 그 안의 단위별 게이트를 기준으로 수행하며, 임의 단계 스킵은 허용되지 않는다(긴급 핫픽스 예외는 별도 규칙 적용). -## Lifecycle Stages +## Lifecycle Phases -1. Discovery -2. Planning -3. Design -4. Implementation -5. Verification -6. Release -7. Operations +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. 게이트 준수: 각 단계의 DoR(진입 조건)과 DoD(완료 조건)을 충족해야 다음 단계로 이동한다. +2. 게이트 준수: 각 phase와 단위의 DoR(진입 조건)과 DoD(완료 조건)을 충족해야 다음 단계로 이동한다. 3. 테스트 우선 검증: 구현 결과는 테스트 또는 검증 근거 없이 완료로 간주하지 않는다. 4. 변경 영향도 기록: 코드/문서/운영 영향 범위를 명시한다. 5. 불확실성 우선 해소: 차단 이슈가 있으면 임의 추정 대신 질문 또는 추가 탐색을 수행한다. @@ -34,7 +71,7 @@ ## Hotfix Exception Path -긴급 핫픽스는 Discovery/Planning/Design을 경량화할 수 있다. 단, 아래는 필수다. +긴급 핫픽스는 Requirements/Delivery 설계를 경량화할 수 있다. 단, 아래는 필수다. 1. 최소 요구사항 정의(증상, 영향, 성공 조건) 2. 최소 검증(재현 테스트 또는 핵심 시나리오 확인) diff --git a/.github/instructions/placeholder-guide.md b/.github/instructions/placeholder-guide.md index 3332bf5..73f6b82 100644 --- a/.github/instructions/placeholder-guide.md +++ b/.github/instructions/placeholder-guide.md @@ -1,243 +1,239 @@ # 플레이스홀더 가이드 -이 파일은 `.github/templates/` 및 `.github/prompts/`에서 사용하는 `{{...}}` 플레이스홀더의 문법, 처리 주체, 전체 목록을 정의한다. -템플릿을 수정하거나 새 프롬프트를 작성할 때 이 파일을 기준으로 한다. +이 파일은 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}}` | 단순 치환 대상. 힌트 없음. | `{{CYCLE_ID}}` | -| `{{KEY:hint}}` | 힌트 포함. 치환 시 힌트 텍스트도 함께 제거. | `{{CREATED_AT_KST:TBD}}` | -| `{{KEY:opt1\|opt2\|opt3}}` | 열거형. 나열된 값 중 하나를 선택. | `{{DOC_STATUS:draft\|review\|confirmed}}` | -| `{{KEY_N_DECISION:hint}}` | AI agent가 섹션 본문에 임시로 삽입하는 판단 대기 마커. `review-discovery` 등 검토 단계에서 실제 문장으로 치환하거나 `#10`으로 이동. | `{{TARGET_STATE_2_DECISION:...}}` | +| --- | --- | --- | +| `{{KEY}}` | 단순 치환 대상 | `{{DISCOVERY_ID}}` | +| `{{KEY:hint}}` | 힌트 포함 치환 대상 | `{{CONFIRMED_AT_KST:TBD}}` | +| `{{KEY:opt1\|opt2}}` | 열거형 선택 값 | `{{DOC_STATUS:draft\|confirmed}}` | -> **규칙**: 플레이스홀더를 채울 때는 `{{...}}` 전체를 값으로 교체한다. 힌트나 파이프(`|`) 열거는 최종 문서에 남기지 않는다. +규칙: ---- +- 최종 문서에는 `{{...}}` 문법이 남지 않아야 한다. +- 힌트 텍스트는 치환 시 함께 제거한다. +- 사람 승인 없이는 확정할 수 없는 값은 본문에 무리하게 확정하지 말고 Notes 또는 결정 필요 항목으로 남긴다. -## 2. 처리 주체 분류 +## 2. 처리 주체 -플레이스홀더는 **누가 채워야 하는가**에 따라 세 가지로 나뉜다. +플레이스홀더는 아래 세 가지 처리 주체 중 하나에 속한다. -### A. 자동 치환 (Auto — 프롬프트 실행 시 agent가 즉시 채움) +### A. 자동 치환 -| 키 | 치환 값 | 사용 위치 | -|---|---|---| -| `{{DOC_STATUS}}` / `{{DOC_STATUS:draft\|review\|confirmed}}` | `draft` | 모든 SDLC 문서 `#0` | -| `{{CYCLE_ID}}` / `{{CYCLE_ID:sdlc-<3자리>__}}` | 계산된 주기 ID | 모든 SDLC 문서 `#0`, index, summary | -| `{{ISSUE_NAME}}` / `{{ISSUE_NAME:...}}` | 사용자 입력 원문 | 모든 SDLC 문서 `#0`, summary | -| `{{CREATED_AT_KST}}` / `{{CREATED_AT_KST:TBD}}` | 현재 시각 (KST) | 모든 SDLC 문서 `#0`, summary | -| `{{UPDATED_AT_KST}}` / `{{UPDATED_AT_KST:TBD}}` | 현재 시각 (KST) | 모든 SDLC 문서 `#0`, summary | -| `{{OUTPUT_PATH}}` | 생성 파일 경로 | `1_discovery.md` `#9` | -| `{{FILE_RESULT}}` / `{{FILE_RESULT:생성\|갱신\|미생성}}` | `생성` (신규) 또는 `갱신` | `1_discovery.md` `#9` | -| `{{SUMMARY_STATUS}}` / `{{SUMMARY_STATUS:draft\|review\|confirmed}}` | `draft` | `summary.md` | +- ID, 생성 시각, 갱신 시각, 상태 기본값처럼 실행 시점에 자동으로 정해지는 값 +- 예: + - `{{DISCOVERY_ID}}` + - `{{CONFIRMED_AT_KST}}` + - `{{BAT_ID}}` + - `{{REL_ID}}` ---- +### B. AI 근거 기반 치환 -### B. AI 추론 치환 (Infer — agent가 입력 요청과 저장소 맥락을 바탕으로 초안을 채움) +- 현재 저장소 상태, 상위 문서, 이미 확정된 값으로 채울 수 있는 항목 +- 예: + - Discovery의 현재 상태 요약 + - REQ의 Impacted Area 초안 + - Batch planning의 dependency 정리 + - Release rollout checklist 초안 -> 입력만으로 합리적 추론이 가능한 항목은 플레이스홀더로 남기지 않고 자연어 문장으로 채운다. -> 추론이 불확실한 경우에는 `_DECISION` 접미사 형태로 남기고 `review-discovery` 단계에서 처리한다. +### C. 사람 결정 필요 -| 키 | 설명 | 위치 | -|---|---|---| -| `{{PLANNING_SCORE_FILE}}` | Planning 점수 파일 경로 또는 `미생성` | `#1` | -| `{{TODO_FILE}}` | 관련 TODO/메모 경로 또는 `없음` | `#1` | -| `{{SUMMARY_LINE_1}}`, `{{SUMMARY_LINE_2}}` | 현재 검토 배경 및 이번 Discovery 핵심 요약 | `#1` | -| `{{REQUIREMENT_CLASSIFICATION}}` | `신규` / `유사` / `완전 중복` | `#2` | -| `{{CLASSIFICATION_REASON_1}}`, `{{CLASSIFICATION_REASON_2}}` | 판정 근거 2줄 | `#2` | -| `{{CURRENT_STATE_1}}`, `{{CURRENT_STATE_2}}` | 현재 문제 상태 | `#3` | -| `{{TARGET_STATE_1}}`, `{{TARGET_STATE_2}}` | 기대 상태 | `#3` | -| `{{STAKEHOLDER_1~3}}` | 이해관계자 | `#3` | -| `{{CONSTRAINT_1}}`, `{{CONSTRAINT_2}}` | 제약사항 | `#3` | -| `{{USER_SCENARIO_1~3}}` | 주요 사용자 시나리오 | `#3` | -| `{{CHANGE_ITEM_1~3}}` | 핵심 변경 항목 | `#4` | -| `{{CODE_IMPACT_1~2}}`, `{{DOC_IMPACT_1~2}}`, `{{OPS_IMPACT_1~2}}` | 영향 범위 | `#4` | -| `{{FR_1~4}}` | 기능 요구사항 (최소 2개) | `#5` | -| `{{NFR_1~3}}` | 비기능 요구사항 (최소 1개) | `#5` | -| `{{IN_SCOPE_1~2}}`, `{{OUT_OF_SCOPE_1~2}}` | 범위 경계 | `#5` | -| `{{RISK_LEVEL_1~3}}`, `{{RISK_1~3}}`, `{{MITIGATION_1~3}}` | 리스크 항목 (최소 2개) | `#6` | -| `{{ASSUMPTION_1~3}}` | 가정 (최소 2개) | `#6` | -| `{{OPEN_QUESTION_1~3}}`, `{{OPEN_QUESTION_STATUS_1~3}}` | 오픈 질문 | `#6` | -| `{{OPEN_QUESTION_ACTION_1~3}}`, `{{OPEN_QUESTION_EXIT_1~3}}` | 오픈 질문 처리 방안/종료 조건 | `#6` | -| `{{SUCCESS_METRIC_1~3}}` | 성공 기준 (최소 2개) | `#7` | -| `{{MEASURE_METHOD_1~3}}`, `{{MEASURE_SOURCE_1~3}}` | 측정 방식 및 데이터 출처 | `#7` | -| `{{CHECK_SCOPE_CRITERIA}}` | 범위 확정 기준 | `#8` | -| `{{CHECK_METRICS_CRITERIA}}` | 성공 지표 확정 기준 | `#8` | -| `{{CHECK_RISK_OWNER_CRITERIA}}` | 리스크 책임자 지정 기준 | `#8` | -| `{{CHECK_CONFIRMEDBY_CRITERIA}}` | Freeze 담당자 지정 기준 | `#8` | -| `{{REFERENCE_1~3}}` | 참조 문서 목록 | `#9` | -| `{{SUMMARY_POINT_1~2}}` | summary.md 핵심 요약 | `summary.md` | +- 정책 선택, 승인자 지정, 우선순위 확정, 외부 환경 정보처럼 사람 판단이 필요한 값 +- 이런 항목은 무리하게 확정하지 않는다. ---- +## 3. 경로별 플레이스홀더 원칙 -### C. 사용자 결정 필요 (Decide — 자동 추론 불가, 사용자/승인자가 직접 채워야 함) +### 3.0 Bootstrap baseline 템플릿 -> 이 항목들은 `#10 사용자 결정 필요 항목 요약`에 모아서 관리한다. -> 섹션 본문에는 최소 플레이스홀더만 남기거나 맥락 설명 문장으로 대체한다. +대상 경로: -| 키 | 설명 | 위치 | -|---|---|---| -| `{{DECIDE_ITEM_1~2}}` | 정책/구조 결정이 필요한 항목 | `#10 > DECIDE` | -| `{{CONFIRM_ITEM_1~2}}` | 범위나 책임자 확인이 필요한 항목 | `#10 > CONFIRM` | -| `{{DATA_ITEM_1~2}}` | 외부 데이터나 환경 정보가 필요한 항목 | `#10 > DATA` | -| `{{FREEZE_HANDOFF_DECISION}}` | Planning 진행 가능 여부 (`Planning 진행 가능` / `보류`) | `#11` | -| `{{FREEZE_HANDOFF_RATIONALE}}` | Handoff Decision 판단 근거 | `#11` | -| `{{READY_FOR_PLANNING}}` | `true` / `false` | `#11` | -| `{{CONFIRMED_BY}}` | Freeze 확정 담당자 이름 | `#11` | -| `{{CONFIRMED_AT_KST}}` | Freeze 확정 시각 (KST) | `#11` | +- `.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` ---- +처리 원칙: -## 3. `_DECISION` 접미사 패턴 +- `bootstrap-baseline`은 먼저 `.stagepilot/bootstrap/baseline.yaml` seed를 만들거나 보강한다. +- greenfield 저장소처럼 관찰 가능한 정보가 부족하면 최소 질문 세트로 seed를 채운다. +- `bootstrap-baseline`은 baseline 문서와 index를 초기화하지만 Discovery 문서를 만들지 않는다. +- baseline 문서는 seed를 source of truth로 렌더링하고, 필요하면 저장소 관찰값으로 보강한다. +- index 문서는 빈 register 골격만 준비하고, 실제 unit 행은 이후 skill이 추가한다. -섹션 본문에 판단이 필요한 항목이 생겼을 때 AI agent가 임시로 삽입하는 마커이다. +주요 키: -- **형식**: `{{원래키_N_DECISION:판단 내용 또는 질문}}` -- **예시**: `{{TARGET_STATE_2_DECISION:README 확장으로 할지, 별도 파일로 분리할지 결정 필요}}` -- **처리 규칙**: - - `review-discovery` 프롬프트 실행 시 각 항목을 검토하여 아래 중 하나로 처리한다. - - 추론 가능 → 자연어 문장으로 치환 - - 사용자 결정 필요 → `#10`으로 이동하고 본문은 맥락 설명 문장으로 대체 +- `{{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 템플릿 ---- +대상 경로: -## Planning 전용 플레이스홀더 (`2_planning.md`) +- `.github/templates/interface-contract.md` +- `.github/templates/data-model.md` -### A. 자동 치환 (Auto) +처리 원칙: -| 키 | 치환 값 | 사용 위치 | -|---|---|---| -| `{{DISCOVERY_PATH}}` | `docs/sdlc//1_discovery.md` | `#0`, `#9` | +- 이 문서들은 optional cross-cutting reference다. +- active unit의 source of truth를 대체하지 않고, 여러 REQ와 batch에 공통으로 반복되는 계약 정보를 모아 둔다. +- `bootstrap-baseline`은 seed의 `interfaces`와 `data_model` 섹션을 우선 읽고, 값이 없으면 `runtime`, `structure`, `notes`를 바탕으로 기본 초안을 구체적으로 유도한다. +- baseline 수준의 변경이 있을 때만 갱신하고, REQ별 acceptance criteria를 그대로 복사하지 않는다. -### B. AI 추론 치환 (Infer) +주요 키: -| 키 | 설명 | 위치 | -|---|---|---| -| `{{PLANNING_ISSUE_PURPOSE}}` | Discovery 이슈명과 핵심 목적 요약 | `#1` | -| `{{PLANNING_IN_SCOPE_1~2}}` | Discovery `#5`에서 이식한 In Scope | `#1` | -| `{{PLANNING_OUT_OF_SCOPE_1~2}}` | Discovery `#5`에서 이식한 Out of Scope | `#1` | -| `{{PLANNING_FR_1~4}}` | Discovery `#5` FR 요약 | `#1` | -| `{{PLANNING_NFR_1~2}}` | Discovery `#5` NFR 요약 | `#1` | -| `{{DEFERRED_ITEM_1~2}}` | Discovery `#6`에서 Deferred 처리된 오픈 질문 | `#1` | -| `{{TASK_TITLE_N}}` | FR/NFR 기반 태스크 제목 | `#2` | -| `{{TASK_TYPE_N}}` | 태스크 유형 (`개발\|문서\|검토\|설계\|운영`) | `#2` | -| `{{TASK_REF_N}}` | 참조 요구사항 ID (예: `FR-1`) | `#2` | -| `{{TASK_DEP_N}}` | 의존 태스크 ID 또는 `-` | `#2` | -| `{{TASK_DOD_N}}` | 태스크 완료 조건 | `#2` | -| `{{EFFORT_N}}` | 추정 공수 (숫자 또는 범위) | `#3` | -| `{{EFFORT_UNIT}}` | 공수 단위 (`SP\|시간\|일`) | `#3` | -| `{{EFFORT_NOTE_N}}` | 공수 추정 비고 | `#3` | -| `{{TOTAL_EFFORT}}` | 총 추정 공수 | `#3` | -| `{{EFFORT_CONFIDENCE}}` | 추정 신뢰도 (`High\|Medium\|Low`) | `#3` | -| `{{EFFORT_BASIS}}` | 추정 근거 | `#3` | -| `{{MILESTONE_N_NAME}}` | 마일스톤 이름 | `#4` | -| `{{MILESTONE_N_TASKS}}` | 마일스톤 포함 태스크 목록 | `#4` | -| `{{MILESTONE_N_DONE}}` | 마일스톤 완료 조건 | `#4` | -| `{{ITERATION_UNIT}}` | 이터레이션 단위 | `#4` | -| `{{ITERATION_N_TASKS}}` | 이터레이션 N 포함 태스크 | `#4` | -| `{{TASK_DEPENDENCY_N}}` | 태스크 간 의존 관계 설명 | `#5` | -| `{{EXTERNAL_DEP_N}}` | 외부 의존성 항목 | `#5` | -| `{{TECH_CONSTRAINT_N}}` | 기술/환경 제약 | `#5` | -| `{{VERIFY_CRITERIA_N}}` | 검증 대상 성공 기준 (Discovery S-N 요약) | `#6` | -| `{{VERIFY_METHOD_N}}` | 검증 방법 초안 | `#6` | -| `{{PLAN_RISK_LEVEL_N}}` | Planning 리스크 등급 | `#7` | -| `{{PLAN_RISK_N}}` | Planning 리스크 내용 | `#7` | -| `{{PLAN_MITIGATION_N}}` | 리스크 완화 방안 | `#7` | -| `{{PLAN_ASSUMPTION_N}}` | Planning 단계 가정 | `#7` | -| `{{PLAN_OPEN_QUESTION_N}}` | Planning 오픈 질문 | `#7` | -| `{{PLAN_OQ_STATUS_N}}` | 오픈 질문 상태 | `#7` | -| `{{PLAN_OQ_ACTION_N}}` | 오픈 질문 처리 방안 | `#7` | -| `{{PLAN_OQ_EXIT_N}}` | 오픈 질문 종료 조건 | `#7` | -| `{{CHECK_TASKS_CRITERIA}}` | 태스크 확정 기준 | `#8` | -| `{{CHECK_EFFORT_CRITERIA}}` | 공수 추정 확정 기준 | `#8` | -| `{{CHECK_SCHEDULE_CRITERIA}}` | 일정 확정 기준 | `#8` | -| `{{CHECK_DEP_CRITERIA}}` | 외부 의존성 해소 기준 | `#8` | +- `{{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}}` -### C. 사용자 결정 필요 (Decide) +### 3.1 Discovery 템플릿 -| 키 | 설명 | 위치 | -|---|---|---| -| `{{TASK_OWNER_N}}` | 태스크 담당자 | `#2` | -| `{{MILESTONE_N_DATE}}` | 마일스톤 목표 날짜 | `#4` | -| `{{ITERATION_N_PERIOD}}` | 이터레이션 날짜 범위 | `#4` | -| `{{VERIFY_OWNER_N}}` | 검증 담당자 | `#6` | -| `{{FREEZE_HANDOFF_DECISION}}` | Design 진행 가능 여부 | `#11` | -| `{{FREEZE_HANDOFF_RATIONALE}}` | Handoff Decision 판단 근거 | `#11` | -| `{{READY_FOR_DESIGN}}` | `true` / `false` | `#11` | -| `{{CONFIRMED_BY}}` | Freeze 확정 담당자 이름 | `#11` | -| `{{CONFIRMED_AT_KST}}` | Freeze 확정 시각 (KST) | `#11` | +대상 경로: ---- +- `.github/templates/discovery/discovery.md` +- `docs/discovery/*.md` -## Design 전용 플레이스홀더 (`3_design.md`) +주요 키: -### A. 자동 치환 (Auto) +- `{{DISCOVERY_ID}}` +- `{{ISSUE_NAME}}` +- `{{CREATED_AT_KST}}` +- `{{UPDATED_AT_KST}}` +- `{{FREEZE_HANDOFF_DECISION}}` +- `{{READY_FOR_REQ_DRAFTING}}` +- `{{CONFIRMED_BY}}` +- `{{CONFIRMED_AT_KST}}` -| 키 | 치환 값 | 사용 위치 | -|---|---|---| -| `{{PLANNING_PATH}}` | `docs/sdlc//2_planning.md` | `#0`, `#8` | +처리 원칙: -### B. AI 추론 치환 (Infer) +- Discovery는 REQ 초안 작성으로 넘길 수 있을 때만 freeze handoff를 완료한다. +- Discovery 문서의 용어는 `Planning` 직결이 아니라 `REQ Drafting` 기준으로 유지한다. -| 키 | 설명 | 위치 | -|---|---|---| -| `{{DESIGN_ISSUE_PURPOSE}}` | Planning 이슈명과 핵심 목적 요약 | `#1` | -| `{{DESIGN_TASK_TITLE_N}}` | Planning `#2`에서 이식한 태스크 제목 | `#1` | -| `{{DESIGN_TASK_REF_N}}` | Planning `#2`에서 이식한 참조 요구사항 | `#1` | -| `{{DESIGN_DEFERRED_ITEM_N}}` | Planning `#7`에서 Deferred 처리된 오픈 질문 | `#1` | -| `{{ARCH_OVERVIEW}}` | 전체 아키텍처/구조 개요 | `#2` | -| `{{COMPONENT_N_NAME}}` | 주요 컴포넌트 이름 | `#2` | -| `{{COMPONENT_N_ROLE}}` | 컴포넌트 역할 | `#2` | -| `{{COMPONENT_N_SCOPE}}` | 컴포넌트 영향 범위 | `#2` | -| `{{DATA_FLOW_N}}` | 데이터 흐름 단계 | `#2` | -| `{{DESIGN_DETAIL_N}}` | 태스크별 설계 방향 | `#3` | -| `{{DESIGN_TARGET_N}}` | 변경 대상 파일/함수/설정 | `#3` | -| `{{DESIGN_IO_N}}` | 입력/출력 또는 사이드이펙트 | `#3` | -| `{{DESIGN_EDGE_N}}` | 예외/엣지 케이스 | `#3` | -| `{{INTERFACE_N}}` | API/함수 시그니처 | `#4` | -| `{{SCHEMA_N}}` | 데이터 스키마/포맷 | `#4` | -| `{{EVENT_N}}` | 이벤트/메시지 | `#4` | -| `{{SEC_INJECTION}}` ~ `{{SEC_OTHER}}` | 보안 항목 해당 여부 | `#5` | -| `{{SEC_INJECTION_ACTION}}` ~ `{{SEC_OTHER_ACTION}}` | 보안 대응 방안 | `#5` | -| `{{DESIGN_RISK_LEVEL_N}}` | Design 리스크 등급 | `#6` | -| `{{DESIGN_RISK_N}}` | Design 리스크 내용 | `#6` | -| `{{DESIGN_MITIGATION_N}}` | 리스크 완화 방안 | `#6` | -| `{{DESIGN_ASSUMPTION_N}}` | Design 단계 가정 | `#6` | -| `{{DESIGN_OPEN_QUESTION_N}}` | Design 오픈 질문 | `#6` | -| `{{DESIGN_OQ_STATUS_N}}` | 오픈 질문 상태 | `#6` | -| `{{DESIGN_OQ_ACTION_N}}` | 오픈 질문 처리 방안 | `#6` | -| `{{DESIGN_OQ_EXIT_N}}` | 오픈 질문 종료 조건 | `#6` | -| `{{CHECK_DESIGN_COMPLETE}}` | 설계 완성 기준 | `#7` | -| `{{CHECK_INTERFACE}}` | 인터페이스 확정 기준 | `#7` | -| `{{CHECK_SECURITY}}` | 보안 점검 완료 기준 | `#7` | +### 3.2 SRS 템플릿 -### C. 사용자 결정 필요 (Decide) +대상 경로: -| 키 | 설명 | 위치 | -|---|---|---| -| `{{DESIGN_TASK_OWNER_N}}` | 태스크 담당자 | `#1` | -| `{{FREEZE_HANDOFF_DECISION}}` | Implementation 진행 가능 여부 | `#10` | -| `{{FREEZE_HANDOFF_RATIONALE}}` | Handoff Decision 판단 근거 | `#10` | -| `{{READY_FOR_IMPLEMENTATION}}` | `true` / `false` | `#10` | -| `{{CONFIRMED_BY}}` | Freeze 확정 담당자 이름 | `#10` | -| `{{CONFIRMED_AT_KST}}` | Freeze 확정 시각 (KST) | `#10` | +- `docs/srs/req-template.md` +- `docs/srs/index.md` ---- +주요 키: -## 4. 참조 위치 요약 +- `REQ-XXX` +- `Status` +- `Type` +- `Priority` +- `Owner` -| 파일 | 역할 | 관련 플레이스홀더 | -|---|---|---| -| `.github/prompts/new-sdlc.prompt.md` | 주기 생성, 자동/추론 치환 실행 | A, B 전체 | -| `.github/prompts/review-discovery.prompt.md` | 검토, `_DECISION` 처리, 사용자 결정 항목 정리 | B (`_DECISION`), C | -| `.github/prompts/draft-planning.prompt.md` | Planning 초안 생성, Discovery 내용 이식 | A, B 전체 (Planning) | -| `.github/prompts/draft-design.prompt.md` | Design 초안 생성, Planning 내용 이식 | A, B 전체 (Design) | -| `.github/templates/sdlc/1_discovery.md` | Discovery 원본 템플릿 | A, B, C 전체 | -| `.github/templates/sdlc/2_planning.md` | Planning 원본 템플릿 | A, B, C 전체 (Planning) | -| `.github/templates/sdlc/3_design.md` | Design 원본 템플릿 | A, B, C 전체 (Design) | +처리 원칙: + +- 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//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//` | +| 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 산출물 경로로 사용하지 않는다. \ No newline at end of file diff --git a/.github/prompts/confirm-design.prompt.md b/.github/prompts/confirm-design.prompt.md deleted file mode 100644 index 1ac2d0f..0000000 --- a/.github/prompts/confirm-design.prompt.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -name: "confirm-design" -description: "Approve a Design document and mark it as confirmed, ready for Implementation" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/3_design.md" -agent: "agent" ---- -SDLC Design 문서를 최종 승인 처리한다. - -목표: -- `3_design.md`의 상태를 `confirmed`로 변경한다. -- `# 10. Design Freeze`의 `Handoff Decision`을 `승인`으로, `Ready for Implementation`을 `true`로 변경한다. -- `마지막 갱신 시각(KST)`과 승인 시각(`CONFIRMED_AT_KST`)을 현재 시각으로 채운다. -- 승인 불가 조건이 있으면 문서를 변경하지 않고 이유를 보고한다. - ---- - -## 플레이스홀더 분류 기준 - -모든 `{{...}}` 플레이스홀더를 동일하게 차단 조건으로 취급하지 않는다. 아래 세 유형으로 먼저 분류한다. - -### A. 승인 행위 자체로 채워지는 플레이스홀더 (자동 해소) - -승인 명령 실행 시 자동으로 채우며, 이 값이 남아 있어도 차단하지 않는다. - -| 플레이스홀더 패턴 | 자동 채움 값 | -|---|---| -| `{{CONFIRMED_AT_KST...}}` | 현재 시각 (KST, `YYYY-MM-DD HH:MM:SS KST`) | -| `{{CONFIRMED_BY...}}` | 섹션 10의 `Confirmed By:` 줄에서 읽은 값. 해당 줄이 없으면 차단하지 않고 플레이스홀더를 제거한 뒤 빈 값으로 처리 | - -### B. 맥락상 해소된 플레이스홀더 (자동 정리) - -섹션 7(체크리스트) 또는 섹션 9(사용자 결정 요약)에 있는 플레이스홀더는 **해당 결정의 실질 값이 섹션 10에 이미 기입되어 있으면** 해소된 것으로 간주한다. 승인 처리 시 해당 플레이스홀더를 실질 값으로 치환하거나 설명 텍스트로 대체한다. 차단하지 않는다. - -예시: -- 섹션 7의 `{{CONFIRM_CONFIRMEDBY}}` → 섹션 10의 `Confirmed By: Justin` 값이 있으면 → `Justin`으로 치환 또는 체크리스트 기준 텍스트에서 플레이스홀더 제거 -- 섹션 9 CONFIRM 항목의 `{{CONFIRM_CONFIRMEDBY}}` → 동일하게 처리 - -### C. 실질 미해소 플레이스홀더 (차단 대상) - -섹션 1~6(본문 내용)에 남아 있는 `{{...}}` 플레이스홀더로서, 위 A·B 유형에 해당하지 않는 것. 이 플레이스홀더가 하나라도 있으면 승인을 보류한다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 값이 CYCLE_ID(예: `sdlc-001`)이면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `3_design.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로를 사용한다. -- 파일이 존재하지 않으면 경로를 재확인하도록 사용자에게 피드백하고 중단한다. - -### 2. 플레이스홀더 분류 및 사전 해소 - -문서 전체의 `{{...}}` 플레이스홀더를 스캔해 A·B·C 유형으로 분류한다. - -- **A 유형**: 목록만 기록한다. 4단계에서 자동으로 채운다. -- **B 유형**: 섹션 10에서 실질 값을 읽어 치환 가능한지 확인한다. 가능하면 4단계에서 함께 처리한다. -- **C 유형**: 목록을 보고하고 승인을 보류한다. - -### 3. 승인 가능 여부 확인 (사전 게이트 검사) - -아래 조건을 모두 충족해야 승인을 진행한다. - -| 항목 | 확인 기준 | -|------|-----------| -| 문서 상태 | `confirmed`가 아닌 상태(`draft` 또는 `review`)여야 한다. 이미 `confirmed`면 중단한다. | -| 실질 미해소 플레이스홀더 (C 유형) | C 유형 플레이스홀더가 0개여야 한다. | -| 오픈 질문 미해소 | `# 6` 오픈 질문 목록에 `상태: Open`인 항목이 없어야 한다. | -| 필수 섹션 미완성 | `# 2`, `# 3`, `# 5`, `# 7`, `# 9`, `# 10` 섹션이 존재하고 내용이 채워져 있어야 한다. | -| Ready for Implementation 사전 설정 | `Ready for Implementation: false`이거나 아직 갱신 전인 경우만 승인 처리 대상이다. 이미 `true`이면 이미 처리된 문서임을 알린다. | - -> **예외**: C 유형 플레이스홀더 또는 오픈 질문 미해소만 문제인 경우, 사용자가 명시적으로 `--force`를 표현했으면 해당 항목 목록을 보고하되 승인을 진행한다. - -### 4. 문서 업데이트 (승인 가능 시에만 실행) - -아래 항목을 변경한다. 이 목록 외 내용은 절대 수정하지 않는다. - -1. `# 0. 문서 상태`의 `- 상태:` 줄 → `confirmed`로 변경 -2. `# 0. 문서 상태`의 `- 마지막 갱신 시각(KST):` → 현재 시각으로 변경 -3. `# 10. Design Freeze`의 `- Handoff Decision:` → `승인`으로 변경 -4. `# 10. Design Freeze`의 `- Ready for Implementation:` → `true`로 변경 -5. **A 유형 플레이스홀더** → 각 자동 채움 값으로 치환 -6. **B 유형 플레이스홀더** → 섹션 10에서 읽은 실질 값으로 치환 (또는 플레이스홀더 제거) -7. `docs/sdlc//index.md`의 Design 행 `상태` 열 → `` `confirmed` ``로 변경. 행 형식: `| 3. Design | ... | ... |` - -### 5. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **처리 결과**: 승인 완료 또는 승인 불가 -- **자동 처리된 플레이스홀더 목록** (A·B 유형, 승인 완료 시) -- **변경된 필드 목록** (승인 완료 시) -- **미충족 항목 목록** (승인 불가 시): 각 항목에 대한 조치 안내 포함 -- **다음 단계 안내**: 승인 완료 시 Implementation 단계(`/draft-implementation `) 실행 안내 - ---- - -## 중요 규칙 - -- 4단계에서 명시된 항목 외에는 문서 내용을 절대 변경하지 않는다. -- C 유형 미해소 조건이 있으면 문서에 아무 변경도 가하지 않는다. -- 이미 `confirmed` 상태인 문서에는 재처리하지 않는다. -- 현재 시각은 시스템 또는 컨텍스트에서 제공된 날짜/시간을 사용한다. diff --git a/.github/prompts/confirm-discovery.prompt.md b/.github/prompts/confirm-discovery.prompt.md deleted file mode 100644 index 0435919..0000000 --- a/.github/prompts/confirm-discovery.prompt.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -name: "confirm-discovery" -description: "Approve a Discovery document and mark it as confirmed, ready for Planning" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/1_discovery.md" -agent: "agent" ---- -SDLC Discovery 문서를 최종 승인 처리한다. - -목표: -- `1_discovery.md`의 상태를 `confirmed`로 변경한다. -- `# 11. Discovery Freeze`의 `Handoff Decision`을 `승인`으로, `Ready for Planning`을 `true`로 변경한다. -- `마지막 갱신 시각(KST)`과 승인 시각(`CONFIRMED_AT_KST`)을 현재 시각으로 채운다. -- 승인 불가 조건이 있으면 문서를 변경하지 않고 이유를 보고한다. - ---- - -## 플레이스홀더 분류 기준 - -모든 `{{...}}` 플레이스홀더를 동일하게 차단 조건으로 취급하지 않는다. 아래 세 유형으로 먼저 분류한다. - -### A. 승인 행위 자체로 채워지는 플레이스홀더 (자동 해소) - -승인 명령 실행 시 자동으로 채우며, 이 값이 남아 있어도 차단하지 않는다. - -| 플레이스홀더 패턴 | 자동 채움 값 | -|---|---| -| `{{CONFIRMED_AT_KST...}}` | 현재 시각 (KST, `YYYY-MM-DD HH:MM:SS KST`) | -| `{{CONFIRMED_BY...}}` | 섹션 11의 `Confirmed By:` 줄에서 읽은 값. 해당 줄이 없으면 차단하지 않고 플레이스홀더를 제거한 뒤 빈 값으로 처리 | - -### B. 맥락상 해소된 플레이스홀더 (자동 정리) - -섹션 8(체크리스트) 또는 섹션 10(사용자 결정 요약)에 있는 플레이스홀더는 **해당 결정의 실질 값이 섹션 11에 이미 기입되어 있으면** 해소된 것으로 간주한다. 승인 처리 시 해당 플레이스홀더를 실질 값으로 치환하거나 설명 텍스트로 대체한다. 차단하지 않는다. - -예시: -- 섹션 8의 `{{CONFIRM_CONFIRMEDBY}}` → 섹션 11의 `Confirmed By: Justin` 값이 있으면 → `Justin`으로 치환 또는 체크리스트 기준 텍스트에서 플레이스홀더 제거 -- 섹션 10 CONFIRM 항목의 `{{CONFIRM_CONFIRMEDBY}}` → 동일하게 처리 - -### C. 실질 미해소 플레이스홀더 (차단 대상) - -섹션 1~7(본문 내용)에 남아 있는 `{{...}}` 플레이스홀더로서, 위 A·B 유형에 해당하지 않는 것. 이 플레이스홀더가 하나라도 있으면 승인을 보류한다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 값이 CYCLE_ID(예: `sdlc-001`)이면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `1_discovery.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로를 사용한다. -- 파일이 존재하지 않으면 경로를 재확인하도록 사용자에게 피드백하고 중단한다. - -### 2. 플레이스홀더 분류 및 사전 해소 - -문서 전체의 `{{...}}` 플레이스홀더를 스캔해 A·B·C 유형으로 분류한다. - -- **A 유형**: 목록만 기록한다. 3단계에서 자동으로 채운다. -- **B 유형**: 섹션 11에서 실질 값을 읽어 치환 가능한지 확인한다. 가능하면 3단계에서 함께 처리한다. -- **C 유형**: 목록을 보고하고 승인을 보류한다. - -### 3. 승인 가능 여부 확인 (사전 게이트 검사) - -아래 조건을 모두 충족해야 승인을 진행한다. - -| 항목 | 확인 기준 | -|------|-----------| -| 문서 상태 | `confirmed`가 아닌 상태(`draft` 또는 `review`)여야 한다. 이미 `confirmed`면 중단한다. | -| 실질 미해소 플레이스홀더 (C 유형) | C 유형 플레이스홀더가 0개여야 한다. | -| 오픈 질문 미해소 | `# 6` 오픈 질문 목록에 `상태: Open`인 항목이 없어야 한다. | -| 필수 섹션 미완성 | `# 5`, `# 7`, `# 8`, `# 10`, `# 11` 섹션이 존재하고 내용이 채워져 있어야 한다. | -| Ready for Planning 사전 설정 | `Ready for Planning: false`이거나 아직 갱신 전인 경우만 승인 처리 대상이다. 이미 `true`이면 이미 처리된 문서임을 알린다. | - -> **예외**: C 유형 플레이스홀더 또는 오픈 질문 미해소만 문제인 경우, 사용자가 명시적으로 `--force`를 표현했으면 해당 항목 목록을 보고하되 승인을 진행한다. - -### 4. 문서 업데이트 (승인 가능 시에만 실행) - -아래 항목을 변경한다. 이 목록 외 내용은 절대 수정하지 않는다. - -1. `# 0. 문서 상태`의 `- 상태:` 줄 → `confirmed`로 변경 -2. `# 0. 문서 상태`의 `- 마지막 갱신 시각(KST):` → 현재 시각으로 변경 -3. `# 11. Discovery Freeze`의 `- Handoff Decision:` → `승인`으로 변경 -4. `# 11. Discovery Freeze`의 `- Ready for Planning:` → `true`로 변경 -5. **A 유형 플레이스홀더** → 각 자동 채움 값으로 치환 -6. **B 유형 플레이스홀더** → 섹션 11에서 읽은 실질 값으로 치환 (또는 플레이스홀더 제거) -7. `docs/sdlc//index.md`의 Discovery 행 `상태` 열 → `` `confirmed` ``로 변경. 행 형식: `| 1. Discovery | ... | ... |` - -### 5. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **처리 결과**: 승인 완료 또는 승인 불가 -- **자동 처리된 플레이스홀더 목록** (A·B 유형, 승인 완료 시) -- **변경된 필드 목록** (승인 완료 시) -- **미충족 항목 목록** (승인 불가 시): 각 항목에 대한 조치 안내 포함 -- **다음 단계 안내**: 승인 완료 시 Planning 단계(`/planning-draft `) 실행 안내 - ---- - -## 중요 규칙 - -- 4단계에서 명시된 항목 외에는 문서 내용을 절대 변경하지 않는다. -- C 유형 미해소 조건이 있으면 문서에 아무 변경도 가하지 않는다. -- 이미 `confirmed` 상태인 문서에는 재처리하지 않는다. -- 현재 시각은 시스템 또는 컨텍스트에서 제공된 날짜/시간을 사용한다. diff --git a/.github/prompts/confirm-implementation.prompt.md b/.github/prompts/confirm-implementation.prompt.md deleted file mode 100644 index a28624c..0000000 --- a/.github/prompts/confirm-implementation.prompt.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -name: "confirm-implementation" -description: "Approve an Implementation document and mark it as confirmed, ready for Verification" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/4_implementation.md" -agent: "agent" ---- -SDLC Implementation 문서를 최종 승인 처리한다. - -목표: -- `4_implementation.md`의 상태를 `confirmed`로 변경한다. -- `# 8. Implementation Freeze`의 `Handoff Decision`을 `승인`으로, `Ready for Verification`을 `true`로 변경한다. -- `마지막 갱신 시각(KST)`과 승인 시각(`CONFIRMED_AT_KST`)을 현재 시각으로 채운다. -- 승인 불가 조건이 있으면 문서를 변경하지 않고 이유를 보고한다. - ---- - -## 플레이스홀더 분류 기준 - -모든 `{{...}}` 플레이스홀더를 동일하게 차단 조건으로 취급하지 않는다. 아래 세 유형으로 먼저 분류한다. - -### A. 승인 행위 자체로 채워지는 플레이스홀더 (자동 해소) - -승인 명령 실행 시 자동으로 채우며, 이 값이 남아 있어도 차단하지 않는다. - -| 플레이스홀더 패턴 | 자동 채움 값 | -|---|---| -| `{{CONFIRMED_AT_KST...}}` | 현재 시각 (KST, `YYYY-MM-DD HH:MM:SS KST`) | -| `{{CONFIRMED_BY...}}` | 섹션 8의 `Confirmed By:` 줄에서 읽은 값. 해당 줄이 없으면 차단하지 않고 플레이스홀더를 제거한 뒤 빈 값으로 처리 | - -### B. 맥락상 해소된 플레이스홀더 (자동 정리) - -섹션 5(체크리스트) 또는 섹션 7(사용자 결정 요약)에 있는 플레이스홀더는 **해당 결정의 실질 값이 섹션 8에 이미 기입되어 있으면** 해소된 것으로 간주한다. 승인 처리 시 해당 플레이스홀더를 실질 값으로 치환하거나 설명 텍스트로 대체한다. 차단하지 않는다. - -### C. 실질 미해소 플레이스홀더 (차단 대상) - -섹션 1~4(본문 내용)에 남아 있는 `{{...}}` 플레이스홀더로서, 위 A·B 유형에 해당하지 않는 것. 이 플레이스홀더가 하나라도 있으면 승인을 보류한다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 값이 CYCLE_ID(예: `sdlc-001`)이면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `4_implementation.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로를 사용한다. -- 파일이 존재하지 않으면 경로를 재확인하도록 사용자에게 피드백하고 중단한다. - -### 2. 플레이스홀더 분류 및 사전 해소 - -문서 전체의 `{{...}}` 플레이스홀더를 스캔해 A·B·C 유형으로 분류한다. - -- **A 유형**: 목록만 기록한다. 4단계에서 자동으로 채운다. -- **B 유형**: 섹션 8에서 실질 값을 읽어 치환 가능한지 확인한다. 가능하면 4단계에서 함께 처리한다. -- **C 유형**: 목록을 보고하고 승인을 보류한다. - -### 3. 승인 가능 여부 확인 (사전 게이트 검사) - -아래 조건을 모두 충족해야 승인을 진행한다. - -| 항목 | 확인 기준 | -|------|-----------| -| 문서 상태 | `confirmed`가 아닌 상태(`draft` 또는 `review`)여야 한다. 이미 `confirmed`면 중단한다. | -| 실질 미해소 플레이스홀더 (C 유형) | C 유형 플레이스홀더가 0개여야 한다. | -| 오픈 질문 미해소 | `# 4` 오픈 질문 목록에 `상태: Open`인 항목이 없어야 한다. | -| 필수 섹션 미완성 | `# 2`, `# 3`, `# 5`, `# 7`, `# 8` 섹션이 존재하고 내용이 채워져 있어야 한다. | -| Ready for Verification 사전 설정 | `Ready for Verification: false`이거나 아직 갱신 전인 경우만 승인 처리 대상이다. 이미 `true`이면 이미 처리된 문서임을 알린다. | - -> **예외**: C 유형 플레이스홀더 또는 오픈 질문 미해소만 문제인 경우, 사용자가 명시적으로 `--force`를 표현했으면 해당 항목 목록을 보고하되 승인을 진행한다. - -### 4. 문서 업데이트 (승인 가능 시에만 실행) - -아래 항목을 변경한다. 이 목록 외 내용은 절대 수정하지 않는다. - -1. `# 0. 문서 상태`의 `- 상태:` 줄 → `confirmed`로 변경 -2. `# 0. 문서 상태`의 `- 마지막 갱신 시각(KST):` → 현재 시각으로 변경 -3. `# 8. Implementation Freeze`의 `- Handoff Decision:` → `승인`으로 변경 -4. `# 8. Implementation Freeze`의 `- Ready for Verification:` → `true`로 변경 -5. **A 유형 플레이스홀더** → 각 자동 채움 값으로 치환 -6. **B 유형 플레이스홀더** → 섹션 8에서 읽은 실질 값으로 치환 (또는 플레이스홀더 제거) -7. `docs/sdlc//index.md`의 Implementation 행 `상태` 열 → `` `confirmed` ``로 변경. 행 형식: `| 4. Implementation | ... | ... |` - -### 5. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **처리 결과**: 승인 완료 또는 승인 불가 -- **자동 처리된 플레이스홀더 목록** (A·B 유형, 승인 완료 시) -- **변경된 필드 목록** (승인 완료 시) -- **미충족 항목 목록** (승인 불가 시): 각 항목에 대한 조치 안내 포함 -- **다음 단계 안내**: 승인 완료 시 Verification 단계(`/draft-verification `) 실행 안내 - ---- - -## 중요 규칙 - -- 4단계에서 명시된 항목 외에는 문서 내용을 절대 변경하지 않는다. -- C 유형 미해소 조건이 있으면 문서에 아무 변경도 가하지 않는다. -- 이미 `confirmed` 상태인 문서에는 재처리하지 않는다. -- 현재 시각은 시스템 또는 컨텍스트에서 제공된 날짜/시간을 사용한다. diff --git a/.github/prompts/confirm-operation.prompt.md b/.github/prompts/confirm-operation.prompt.md deleted file mode 100644 index 9e30e7f..0000000 --- a/.github/prompts/confirm-operation.prompt.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -name: "confirm-operation" -description: "Approve an Operations document and mark the SDLC cycle as complete" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/7_operation.md" -agent: "agent" ---- -SDLC Operations 문서를 최종 승인 처리하고 SDLC 주기를 완료한다. - -목표: -- `7_operation.md`의 상태를 `confirmed`로 변경한다. -- `# 10. Operations Freeze`의 `Handoff Decision`을 `승인`으로, `SDLC 주기 완료`를 `true`로 변경한다. -- `마지막 갱신 시각(KST)`과 승인 시각(`CONFIRMED_AT_KST`)을 현재 시각으로 채운다. -- 승인 불가 조건이 있으면 문서를 변경하지 않고 이유를 보고한다. - ---- - -## 플레이스홀더 분류 기준 - -모든 `{{...}}` 플레이스홀더를 동일하게 차단 조건으로 취급하지 않는다. 아래 세 유형으로 먼저 분류한다. - -### A. 승인 행위 자체로 채워지는 플레이스홀더 (자동 해소) - -| 플레이스홀더 패턴 | 자동 채움 값 | -|---|---| -| `{{CONFIRMED_AT_KST...}}` | 현재 시각 (KST, `YYYY-MM-DD HH:MM:SS KST`) | -| `{{CONFIRMED_BY...}}` | 섹션 10의 `Confirmed By:` 줄에서 읽은 값. 해당 줄이 없으면 차단하지 않고 플레이스홀더를 제거한 뒤 빈 값으로 처리 | - -### B. 맥락상 해소된 플레이스홀더 (자동 정리) - -섹션 7(체크리스트) 또는 섹션 9(사용자 결정 요약)에 있는 플레이스홀더는 **해당 결정의 실질 값이 섹션 10에 이미 기입되어 있으면** 해소된 것으로 간주한다. 차단하지 않는다. - -### C. 실질 미해소 플레이스홀더 (차단 대상) - -섹션 1~6(본문 내용)에 남아 있는 `{{...}}` 플레이스홀더로서, 위 A·B 유형에 해당하지 않는 것. 이 플레이스홀더가 하나라도 있으면 승인을 보류한다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 값이 CYCLE_ID(예: `sdlc-001`)이면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `7_operation.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로를 사용한다. -- 파일이 존재하지 않으면 경로를 재확인하도록 사용자에게 피드백하고 중단한다. - -### 2. 플레이스홀더 분류 및 사전 해소 - -문서 전체의 `{{...}}` 플레이스홀더를 스캔해 A·B·C 유형으로 분류한다. - -- **A 유형**: 목록만 기록한다. 4단계에서 자동으로 채운다. -- **B 유형**: 섹션 10에서 실질 값을 읽어 치환 가능한지 확인한다. 가능하면 4단계에서 함께 처리한다. -- **C 유형**: 목록을 보고하고 승인을 보류한다. - -### 3. 승인 가능 여부 확인 (사전 게이트 검사) - -아래 조건을 모두 충족해야 승인을 진행한다. - -| 항목 | 확인 기준 | -|------|-----------| -| 문서 상태 | `confirmed`가 아닌 상태(`draft` 또는 `review`)여야 한다. 이미 `confirmed`면 중단한다. | -| 실질 미해소 플레이스홀더 (C 유형) | C 유형 플레이스홀더가 0개여야 한다. | -| 오픈 질문 미해소 | `# 5` 오픈 질문 목록에 `상태: Open`인 항목이 없어야 한다. | -| 필수 섹션 미완성 | `# 2`, `# 3`, `# 7`, `# 9`, `# 10` 섹션이 존재하고 내용이 채워져 있어야 한다. | -| SDLC 주기 완료 사전 설정 | `SDLC 주기 완료: false`이거나 아직 갱신 전인 경우만 승인 처리 대상이다. 이미 `true`이면 이미 처리된 문서임을 알린다. | - -> **예외**: C 유형 플레이스홀더 또는 오픈 질문 미해소만 문제인 경우, 사용자가 명시적으로 `--force`를 표현했으면 해당 항목 목록을 보고하되 승인을 진행한다. - -### 4. 문서 업데이트 (승인 가능 시에만 실행) - -아래 항목을 변경한다. 이 목록 외 내용은 절대 수정하지 않는다. - -1. `# 0. 문서 상태`의 `- 상태:` 줄 → `confirmed`로 변경 -2. `# 0. 문서 상태`의 `- 마지막 갱신 시각(KST):` → 현재 시각으로 변경 -3. `# 10. Operations Freeze`의 `- Handoff Decision:` → `승인`으로 변경 -4. `# 10. Operations Freeze`의 `- SDLC 주기 완료:` → `true`로 변경 -5. **A 유형 플레이스홀더** → 각 자동 채움 값으로 치환 -6. **B 유형 플레이스홀더** → 섹션 10에서 읽은 실질 값으로 치환 (또는 플레이스홀더 제거) -7. `docs/sdlc//index.md`의 Operations 행 `상태` 열 → `` `confirmed` ``로 변경. 행 형식: `| 7. Operations | ... | ... |` - -### 5. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **처리 결과**: 승인 완료 또는 승인 불가 -- **자동 처리된 플레이스홀더 목록** (A·B 유형, 승인 완료 시) -- **변경된 필드 목록** (승인 완료 시) -- **미충족 항목 목록** (승인 불가 시): 각 항목에 대한 조치 안내 포함 -- **SDLC 주기 완료 안내**: 승인 완료 시 이 주기의 `# 6` 다음 Discovery 환류 항목이 다음 SDLC 주기의 입력이 됨을 안내한다. - ---- - -## 중요 규칙 - -- 4단계에서 명시된 항목 외에는 문서 내용을 절대 변경하지 않는다. -- C 유형 미해소 조건이 있으면 문서에 아무 변경도 가하지 않는다. -- 이미 `confirmed` 상태인 문서에는 재처리하지 않는다. -- 현재 시각은 시스템 또는 컨텍스트에서 제공된 날짜/시간을 사용한다. diff --git a/.github/prompts/confirm-planning.prompt.md b/.github/prompts/confirm-planning.prompt.md deleted file mode 100644 index f3c3f99..0000000 --- a/.github/prompts/confirm-planning.prompt.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -name: "confirm-planning" -description: "Approve a Planning document and mark it as confirmed, ready for Design" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/2_planning.md" -agent: "agent" ---- -SDLC Planning 문서를 최종 승인 처리한다. - -목표: -- `2_planning.md`의 상태를 `confirmed`로 변경한다. -- `# 11. Planning Freeze`의 `Handoff Decision`을 `승인`으로, `Ready for Design`을 `true`로 변경한다. -- `마지막 갱신 시각(KST)`과 승인 시각(`CONFIRMED_AT_KST`)을 현재 시각으로 채운다. -- 승인 불가 조건이 있으면 문서를 변경하지 않고 이유를 보고한다. - ---- - -## 플레이스홀더 분류 기준 - -모든 `{{...}}` 플레이스홀더를 동일하게 차단 조건으로 취급하지 않는다. 아래 세 유형으로 먼저 분류한다. - -### A. 승인 행위 자체로 채워지는 플레이스홀더 (자동 해소) - -승인 명령 실행 시 자동으로 채우며, 이 값이 남아 있어도 차단하지 않는다. - -| 플레이스홀더 패턴 | 자동 채움 값 | -|---|---| -| `{{CONFIRMED_AT_KST...}}` | 현재 시각 (KST, `YYYY-MM-DD HH:MM:SS KST`) | -| `{{CONFIRMED_BY...}}` | 섹션 11의 `Confirmed By:` 줄에서 읽은 값. 해당 줄이 없으면 차단하지 않고 플레이스홀더를 제거한 뒤 빈 값으로 처리 | - -### B. 맥락상 해소된 플레이스홀더 (자동 정리) - -섹션 8(체크리스트) 또는 섹션 10(사용자 결정 요약)에 있는 플레이스홀더는 **해당 결정의 실질 값이 섹션 11에 이미 기입되어 있으면** 해소된 것으로 간주한다. 승인 처리 시 해당 플레이스홀더를 실질 값으로 치환하거나 설명 텍스트로 대체한다. 차단하지 않는다. - -예시: -- 섹션 8의 `{{CONFIRM_CONFIRMEDBY}}` → 섹션 11의 `Confirmed By: Justin` 값이 있으면 → `Justin`으로 치환 또는 체크리스트 기준 텍스트에서 플레이스홀더 제거 -- 섹션 10 CONFIRM 항목의 `{{CONFIRM_CONFIRMEDBY}}` → 동일하게 처리 - -### C. 실질 미해소 플레이스홀더 (차단 대상) - -섹션 1~7(본문 내용)에 남아 있는 `{{...}}` 플레이스홀더로서, 위 A·B 유형에 해당하지 않는 것. 이 플레이스홀더가 하나라도 있으면 승인을 보류한다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 값이 CYCLE_ID(예: `sdlc-001`)이면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `2_planning.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로를 사용한다. -- 파일이 존재하지 않으면 경로를 재확인하도록 사용자에게 피드백하고 중단한다. - -### 2. 플레이스홀더 분류 및 사전 해소 - -문서 전체의 `{{...}}` 플레이스홀더를 스캔해 A·B·C 유형으로 분류한다. - -- **A 유형**: 목록만 기록한다. 4단계에서 자동으로 채운다. -- **B 유형**: 섹션 11에서 실질 값을 읽어 치환 가능한지 확인한다. 가능하면 4단계에서 함께 처리한다. -- **C 유형**: 목록을 보고하고 승인을 보류한다. - -### 3. 승인 가능 여부 확인 (사전 게이트 검사) - -아래 조건을 모두 충족해야 승인을 진행한다. - -| 항목 | 확인 기준 | -|------|-----------| -| 문서 상태 | `confirmed`가 아닌 상태(`draft` 또는 `review`)여야 한다. 이미 `confirmed`면 중단한다. | -| 실질 미해소 플레이스홀더 (C 유형) | C 유형 플레이스홀더가 0개여야 한다. | -| 오픈 질문 미해소 | `# 7` 오픈 질문 목록에 `상태: Open`인 항목이 없어야 한다. | -| 필수 섹션 미완성 | `# 2`, `# 3`, `# 6`, `# 8`, `# 10`, `# 11` 섹션이 존재하고 내용이 채워져 있어야 한다. | -| Ready for Design 사전 설정 | `Ready for Design: false`이거나 아직 갱신 전인 경우만 승인 처리 대상이다. 이미 `true`이면 이미 처리된 문서임을 알린다. | - -> **예외**: C 유형 플레이스홀더 또는 오픈 질문 미해소만 문제인 경우, 사용자가 명시적으로 `--force`를 표현했으면 해당 항목 목록을 보고하되 승인을 진행한다. - -### 4. 문서 업데이트 (승인 가능 시에만 실행) - -아래 항목을 변경한다. 이 목록 외 내용은 절대 수정하지 않는다. - -1. `# 0. 문서 상태`의 `- 상태:` 줄 → `confirmed`로 변경 -2. `# 0. 문서 상태`의 `- 마지막 갱신 시각(KST):` → 현재 시각으로 변경 -3. `# 11. Planning Freeze`의 `- Handoff Decision:` → `승인`으로 변경 -4. `# 11. Planning Freeze`의 `- Ready for Design:` → `true`로 변경 -5. **A 유형 플레이스홀더** → 각 자동 채움 값으로 치환 -6. **B 유형 플레이스홀더** → 섹션 11에서 읽은 실질 값으로 치환 (또는 플레이스홀더 제거) -7. `docs/sdlc//index.md`의 Planning 행 `상태` 열 → `` `confirmed` ``로 변경. 행 형식: `| 2. Planning | ... | ... |` - -### 5. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **처리 결과**: 승인 완료 또는 승인 불가 -- **자동 처리된 플레이스홀더 목록** (A·B 유형, 승인 완료 시) -- **변경된 필드 목록** (승인 완료 시) -- **미충족 항목 목록** (승인 불가 시): 각 항목에 대한 조치 안내 포함 -- **다음 단계 안내**: 승인 완료 시 Design 단계(`/draft-design `) 실행 안내 - ---- - -## 중요 규칙 - -- 4단계에서 명시된 항목 외에는 문서 내용을 절대 변경하지 않는다. -- C 유형 미해소 조건이 있으면 문서에 아무 변경도 가하지 않는다. -- 이미 `confirmed` 상태인 문서에는 재처리하지 않는다. -- 현재 시각은 시스템 또는 컨텍스트에서 제공된 날짜/시간을 사용한다. diff --git a/.github/prompts/confirm-release.prompt.md b/.github/prompts/confirm-release.prompt.md deleted file mode 100644 index c661757..0000000 --- a/.github/prompts/confirm-release.prompt.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -name: "confirm-release" -description: "Approve a Release document and mark it as confirmed, ready for Operations" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/6_release.md" -agent: "agent" ---- -SDLC Release 문서를 최종 승인 처리한다. - -목표: -- `6_release.md`의 상태를 `confirmed`로 변경한다. -- `# 9. Release Freeze`의 `Handoff Decision`을 `승인`으로, `Ready for Operations`를 `true`로 변경한다. -- `마지막 갱신 시각(KST)`과 승인 시각(`CONFIRMED_AT_KST`)을 현재 시각으로 채운다. -- 승인 불가 조건이 있으면 문서를 변경하지 않고 이유를 보고한다. - ---- - -## 플레이스홀더 분류 기준 - -모든 `{{...}}` 플레이스홀더를 동일하게 차단 조건으로 취급하지 않는다. 아래 세 유형으로 먼저 분류한다. - -### A. 승인 행위 자체로 채워지는 플레이스홀더 (자동 해소) - -| 플레이스홀더 패턴 | 자동 채움 값 | -|---|---| -| `{{CONFIRMED_AT_KST...}}` | 현재 시각 (KST, `YYYY-MM-DD HH:MM:SS KST`) | -| `{{CONFIRMED_BY...}}` | 섹션 9의 `Confirmed By:` 줄에서 읽은 값. 해당 줄이 없으면 차단하지 않고 플레이스홀더를 제거한 뒤 빈 값으로 처리 | - -### B. 맥락상 해소된 플레이스홀더 (자동 정리) - -섹션 6(체크리스트) 또는 섹션 8(사용자 결정 요약)에 있는 플레이스홀더는 **해당 결정의 실질 값이 섹션 9에 이미 기입되어 있으면** 해소된 것으로 간주한다. 차단하지 않는다. - -### C. 실질 미해소 플레이스홀더 (차단 대상) - -섹션 1~5(본문 내용)에 남아 있는 `{{...}}` 플레이스홀더로서, 위 A·B 유형에 해당하지 않는 것. 이 플레이스홀더가 하나라도 있으면 승인을 보류한다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 값이 CYCLE_ID(예: `sdlc-001`)이면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `6_release.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로를 사용한다. -- 파일이 존재하지 않으면 경로를 재확인하도록 사용자에게 피드백하고 중단한다. - -### 2. 플레이스홀더 분류 및 사전 해소 - -문서 전체의 `{{...}}` 플레이스홀더를 스캔해 A·B·C 유형으로 분류한다. - -- **A 유형**: 목록만 기록한다. 4단계에서 자동으로 채운다. -- **B 유형**: 섹션 9에서 실질 값을 읽어 치환 가능한지 확인한다. 가능하면 4단계에서 함께 처리한다. -- **C 유형**: 목록을 보고하고 승인을 보류한다. - -### 3. 승인 가능 여부 확인 (사전 게이트 검사) - -아래 조건을 모두 충족해야 승인을 진행한다. - -| 항목 | 확인 기준 | -|------|-----------| -| 문서 상태 | `confirmed`가 아닌 상태(`draft` 또는 `review`)여야 한다. 이미 `confirmed`면 중단한다. | -| 실질 미해소 플레이스홀더 (C 유형) | C 유형 플레이스홀더가 0개여야 한다. | -| 오픈 질문 미해소 | `# 5` 오픈 질문 목록에 `상태: Open`인 항목이 없어야 한다. | -| 필수 섹션 미완성 | `# 2`, `# 3`, `# 4`, `# 6`, `# 8`, `# 9` 섹션이 존재하고 내용이 채워져 있어야 한다. | -| Ready for Operations 사전 설정 | `Ready for Operations: false`이거나 아직 갱신 전인 경우만 승인 처리 대상이다. 이미 `true`이면 이미 처리된 문서임을 알린다. | - -> **예외**: C 유형 플레이스홀더 또는 오픈 질문 미해소만 문제인 경우, 사용자가 명시적으로 `--force`를 표현했으면 해당 항목 목록을 보고하되 승인을 진행한다. - -### 4. 문서 업데이트 (승인 가능 시에만 실행) - -아래 항목을 변경한다. 이 목록 외 내용은 절대 수정하지 않는다. - -1. `# 0. 문서 상태`의 `- 상태:` 줄 → `confirmed`로 변경 -2. `# 0. 문서 상태`의 `- 마지막 갱신 시각(KST):` → 현재 시각으로 변경 -3. `# 9. Release Freeze`의 `- Handoff Decision:` → `승인`으로 변경 -4. `# 9. Release Freeze`의 `- Ready for Operations:` → `true`로 변경 -5. **A 유형 플레이스홀더** → 각 자동 채움 값으로 치환 -6. **B 유형 플레이스홀더** → 섹션 9에서 읽은 실질 값으로 치환 (또는 플레이스홀더 제거) -7. `docs/sdlc//index.md`의 Release 행 `상태` 열 → `` `confirmed` ``로 변경. 행 형식: `| 6. Release | ... | ... |` - -### 5. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **처리 결과**: 승인 완료 또는 승인 불가 -- **자동 처리된 플레이스홀더 목록** (A·B 유형, 승인 완료 시) -- **변경된 필드 목록** (승인 완료 시) -- **미충족 항목 목록** (승인 불가 시): 각 항목에 대한 조치 안내 포함 -- **다음 단계 안내**: 승인 완료 시 Operations 단계(`/draft-operation `) 실행 안내 - ---- - -## 중요 규칙 - -- 4단계에서 명시된 항목 외에는 문서 내용을 절대 변경하지 않는다. -- C 유형 미해소 조건이 있으면 문서에 아무 변경도 가하지 않는다. -- 이미 `confirmed` 상태인 문서에는 재처리하지 않는다. -- 현재 시각은 시스템 또는 컨텍스트에서 제공된 날짜/시간을 사용한다. diff --git a/.github/prompts/confirm-verification.prompt.md b/.github/prompts/confirm-verification.prompt.md deleted file mode 100644 index 8668323..0000000 --- a/.github/prompts/confirm-verification.prompt.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -name: "confirm-verification" -description: "Approve a Verification document and mark it as confirmed, ready for Release" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/5_verification.md" -agent: "agent" ---- -SDLC Verification 문서를 최종 승인 처리한다. - -목표: -- `5_verification.md`의 상태를 `confirmed`로 변경한다. -- `# 9. Verification Freeze`의 `Handoff Decision`을 `승인`으로, `Ready for Release`를 `true`로 변경한다. -- `마지막 갱신 시각(KST)`과 승인 시각(`CONFIRMED_AT_KST`)을 현재 시각으로 채운다. -- 승인 불가 조건이 있으면 문서를 변경하지 않고 이유를 보고한다. - ---- - -## 플레이스홀더 분류 기준 - -모든 `{{...}}` 플레이스홀더를 동일하게 차단 조건으로 취급하지 않는다. 아래 세 유형으로 먼저 분류한다. - -### A. 승인 행위 자체로 채워지는 플레이스홀더 (자동 해소) - -| 플레이스홀더 패턴 | 자동 채움 값 | -|---|---| -| `{{CONFIRMED_AT_KST...}}` | 현재 시각 (KST, `YYYY-MM-DD HH:MM:SS KST`) | -| `{{CONFIRMED_BY...}}` | 섹션 9의 `Confirmed By:` 줄에서 읽은 값. 해당 줄이 없으면 차단하지 않고 플레이스홀더를 제거한 뒤 빈 값으로 처리 | - -### B. 맥락상 해소된 플레이스홀더 (자동 정리) - -섹션 6(체크리스트) 또는 섹션 8(사용자 결정 요약)에 있는 플레이스홀더는 **해당 결정의 실질 값이 섹션 9에 이미 기입되어 있으면** 해소된 것으로 간주한다. 차단하지 않는다. - -### C. 실질 미해소 플레이스홀더 (차단 대상) - -섹션 1~5(본문 내용)에 남아 있는 `{{...}}` 플레이스홀더로서, 위 A·B 유형에 해당하지 않는 것. 이 플레이스홀더가 하나라도 있으면 승인을 보류한다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 값이 CYCLE_ID(예: `sdlc-001`)이면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `5_verification.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로를 사용한다. -- 파일이 존재하지 않으면 경로를 재확인하도록 사용자에게 피드백하고 중단한다. - -### 2. 플레이스홀더 분류 및 사전 해소 - -문서 전체의 `{{...}}` 플레이스홀더를 스캔해 A·B·C 유형으로 분류한다. - -- **A 유형**: 목록만 기록한다. 4단계에서 자동으로 채운다. -- **B 유형**: 섹션 9에서 실질 값을 읽어 치환 가능한지 확인한다. 가능하면 4단계에서 함께 처리한다. -- **C 유형**: 목록을 보고하고 승인을 보류한다. - -### 3. 승인 가능 여부 확인 (사전 게이트 검사) - -아래 조건을 모두 충족해야 승인을 진행한다. - -| 항목 | 확인 기준 | -|------|-----------| -| 문서 상태 | `confirmed`가 아닌 상태(`draft` 또는 `review`)여야 한다. 이미 `confirmed`면 중단한다. | -| 실질 미해소 플레이스홀더 (C 유형) | C 유형 플레이스홀더가 0개여야 한다. | -| 검증 항목 미통과 | `# 3` 검증 결과에 `실패` 또는 `블로킹` 상태 항목이 없어야 한다. | -| 결함(BUG) Open 상태 | `# 4` BUG 목록에 `Open` 상태 항목이 없어야 한다. | -| 오픈 질문 미해소 | `# 5` 오픈 질문 목록에 `상태: Open`인 항목이 없어야 한다. | -| 필수 섹션 미완성 | `# 2`, `# 3`, `# 6`, `# 8`, `# 9` 섹션이 존재하고 내용이 채워져 있어야 한다. | -| Ready for Release 사전 설정 | `Ready for Release: false`이거나 아직 갱신 전인 경우만 승인 처리 대상이다. 이미 `true`이면 이미 처리된 문서임을 알린다. | - -> **예외**: C 유형 플레이스홀더 또는 오픈 질문 미해소만 문제인 경우, 사용자가 명시적으로 `--force`를 표현했으면 해당 항목 목록을 보고하되 승인을 진행한다. 단, 검증 실패/블로킹 항목이나 BUG `Open` 항목이 있으면 `--force`로도 승인하지 않는다. - -### 4. 문서 업데이트 (승인 가능 시에만 실행) - -아래 항목을 변경한다. 이 목록 외 내용은 절대 수정하지 않는다. - -1. `# 0. 문서 상태`의 `- 상태:` 줄 → `confirmed`로 변경 -2. `# 0. 문서 상태`의 `- 마지막 갱신 시각(KST):` → 현재 시각으로 변경 -3. `# 9. Verification Freeze`의 `- Handoff Decision:` → `승인`으로 변경 -4. `# 9. Verification Freeze`의 `- Ready for Release:` → `true`로 변경 -5. **A 유형 플레이스홀더** → 각 자동 채움 값으로 치환 -6. **B 유형 플레이스홀더** → 섹션 9에서 읽은 실질 값으로 치환 (또는 플레이스홀더 제거) -7. `docs/sdlc//index.md`의 Verification 행 `상태` 열 → `` `confirmed` ``로 변경. 행 형식: `| 5. Verification | ... | ... |` - -### 5. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **처리 결과**: 승인 완료 또는 승인 불가 -- **자동 처리된 플레이스홀더 목록** (A·B 유형, 승인 완료 시) -- **변경된 필드 목록** (승인 완료 시) -- **미충족 항목 목록** (승인 불가 시): 각 항목에 대한 조치 안내 포함 -- **다음 단계 안내**: 승인 완료 시 Release 단계(`/draft-release `) 실행 안내 - ---- - -## 중요 규칙 - -- 4단계에서 명시된 항목 외에는 문서 내용을 절대 변경하지 않는다. -- C 유형 미해소 조건이 있으면 문서에 아무 변경도 가하지 않는다. -- 이미 `confirmed` 상태인 문서에는 재처리하지 않는다. -- 현재 시각은 시스템 또는 컨텍스트에서 제공된 날짜/시간을 사용한다. diff --git a/.github/prompts/draft-design.prompt.md b/.github/prompts/draft-design.prompt.md deleted file mode 100644 index b10ed56..0000000 --- a/.github/prompts/draft-design.prompt.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -name: "draft-design" -description: "Create a 3_design.md draft from a confirmed Planning document" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/2_planning.md" -agent: "agent" ---- -확정된 Planning 문서를 기반으로 Design 초안(`3_design.md`)을 생성한다. - -목표: -- `docs/sdlc//3_design.md`를 생성한다. -- `2_planning.md`의 확정 내용(태스크, 요구사항, 검증 계획, 리스크)을 Design 초안의 입력으로 사용한다. -- 추론 가능한 항목은 초안 문장으로 채우고, 사용자 결정이 필요한 항목만 플레이스홀더로 남긴다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 CYCLE_ID(예: `sdlc-001`)를 제공했으면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `2_planning.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로의 상위 폴더에서 `2_planning.md`를 찾는다. -- 파일이 없으면 사용자에게 피드백하고 중단한다. - -### 2. Planning 인계 조건 확인 - -`2_planning.md`에서 아래 조건을 확인한다. 미충족 시 중단하고 이유를 보고한다. - -| 항목 | 기준 | -|------|------| -| 문서 상태 | `confirmed`여야 한다 | -| Ready for Design | `true`여야 한다 | -| 3_design.md 존재 여부 | 이미 존재하면 덮어쓰기 의사를 확인하고, 의사 표현이 없으면 중단한다 | - -### 3. Planning 내용 추출 - -`2_planning.md`와 `1_discovery.md`에서 아래 항목을 읽어 Design 초안 작성에 사용한다. - -- 이슈명 (`# 0`의 `이슈명:`) -- 문서 ID / CYCLE_ID -- 태스크 전체 목록 및 담당자 (`# 2`) -- 태스크별 DoD (`# 2`) -- FR/NFR 목록 (`# 1`) -- 검증 계획 개요 (`# 6`) -- 리스크 및 완화 방안 (`# 7`) -- Deferred 처리된 오픈 질문 (`# 7`) -- 외부 의존성 및 기술/환경 제약 (`# 5`) - -### 4. Design 초안 작성 원칙 - -- Planning 태스크 구조와 FR/NFR을 바탕으로 각 태스크의 설계 방향, 변경 대상, 입출력을 초안으로 채운다. -- 저장소 구조, 파일 경로, 기존 코드 패턴을 실제로 확인해 변경 대상(`DESIGN_TARGET_N`)을 구체적으로 명시한다. -- 아래 항목은 추론 불가 또는 사용자 확인 필요이므로 플레이스홀더로 남긴다. - - 외부 시스템 계약이 미확정인 인터페이스 - - Freeze 확정 담당자 (`{{CONFIRMED_BY:TBD}}`) -- 보안 고려사항(`# 5`)은 변경 내용을 기준으로 OWASP Top 10 항목을 점검해 해당/비해당과 근거를 채운다. - -### 5. 자동으로 채워야 하는 항목 - -| 항목 | 채움 방법 | -|------|---------| -| `# 0` 메타데이터 | 현재 시각, CYCLE_ID, 이슈명, Planning 경로를 자동 입력 | -| `# 1` Planning 인계 요약 | Planning `# 2` 태스크 목록 이식, `# 7`의 Deferred 항목 이식 | -| `# 2` 아키텍처/구조 개요 | FR/NFR과 저장소 구조를 기반으로 변경 영향 범위 초안 작성 | -| `# 2` 주요 컴포넌트 | 실제 파일/모듈/디렉터리 구조를 확인해 영향 컴포넌트 나열 | -| `# 3` 상세 설계 | 각 T-N 태스크별 설계 방향, 변경 대상, 입출력 초안 작성 | -| `# 4` 인터페이스 정의 | FR/NFR 기반으로 필요한 API, 함수 시그니처, 스키마 초안 작성 | -| `# 5` 보안 고려사항 | 변경 내용 기준 OWASP 항목 점검, 해당/비해당 및 대응 방안 채움 | -| `# 6` 리스크 | Planning 이월 리스크 중 Design 관련 항목 포함 및 신규 Design 리스크 추가 | -| `# 8` 파일 처리 결과 | 생성 결과와 참조 문서 경로 채움 | -| `# 9` 사용자 결정 필요 | 미확정 인터페이스, 외부 시스템 계약 등 사용자 결정 필요 항목 정리 | -| `# 10` Freeze 플래그 | `Handoff Decision: 보류`, `Ready for Implementation: false` 초기값 입력 | - -### 6. 파일 생성 - -- 경로: `docs/sdlc//3_design.md` -- 기반: `.github/templates/sdlc/3_design.md`를 구조 기준으로 사용하되, 위 작성 원칙에 따라 채운 초안을 생성한다. - -### 7. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **생성 결과**: 파일 경로 -- **채워진 항목 요약**: 자동 추론으로 채운 주요 내용 목록 -- **사용자 결정 필요 항목**: `# 9`에 정리된 항목 요약 -- **다음 단계 안내**: Design 검토 후 `/confirm-design ` 실행 안내 - ---- - -## 중요 규칙 - -- Planning이 `confirmed` 상태가 아니면 초안을 생성하지 않는다. -- 이미 `3_design.md`가 존재하는 경우 사용자 명시 없이 덮어쓰지 않는다. -- 변경 대상 경로/파일명은 저장소를 직접 확인해 실제 존재하는 경로를 사용한다. 추측으로 채우지 않는다. -- 보안 고려사항은 "비해당"이라도 근거를 한 줄 이상 남긴다. -- 현재 시각은 시스템 또는 컨텍스트에서 제공된 날짜/시간을 사용한다. diff --git a/.github/prompts/draft-implementation.prompt.md b/.github/prompts/draft-implementation.prompt.md deleted file mode 100644 index 2c2e87f..0000000 --- a/.github/prompts/draft-implementation.prompt.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -name: "draft-implementation" -description: "Create a 4_implementation.md draft from a confirmed Design document" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/3_design.md" -agent: "agent" ---- -확정된 Design 문서를 기반으로 Implementation 초안(`4_implementation.md`)을 생성한다. - -목표: -- `docs/sdlc//4_implementation.md`를 생성한다. -- `3_design.md`의 확정 내용(태스크, 변경 대상, 인터페이스, 보안)을 Implementation 초안의 입력으로 사용한다. -- 추론 가능한 항목은 초안 문장으로 채우고, 사용자 결정이 필요한 항목만 플레이스홀더로 남긴다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 CYCLE_ID(예: `sdlc-001`)를 제공했으면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `3_design.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로의 상위 폴더에서 `3_design.md`를 찾는다. -- 파일이 없으면 사용자에게 피드백하고 중단한다. - -### 2. Design 인계 조건 확인 - -`3_design.md`에서 아래 조건을 확인한다. 미충족 시 중단하고 이유를 보고한다. - -| 항목 | 기준 | -|------|------| -| 문서 상태 | `confirmed`여야 한다 | -| Ready for Implementation | `true`여야 한다 | -| 4_implementation.md 존재 여부 | 이미 존재하면 덮어쓰기 의사를 확인하고, 의사 표현이 없으면 중단한다 | - -### 3. Design 내용 추출 - -`3_design.md`와 `2_planning.md`에서 아래 항목을 읽어 Implementation 초안 작성에 사용한다. - -- 이슈명 (`# 0`의 `이슈명:`) -- 문서 ID / CYCLE_ID -- 태스크 전체 목록 및 담당자 (`# 1`) -- 태스크별 변경 대상 파일/함수 (`# 3`) -- 태스크별 입출력 및 엣지 케이스 (`# 3`) -- 인터페이스 정의 (`# 4`) -- 보안 고려사항 (`# 5`) -- 리스크 및 완화 방안 (`# 6`) -- Deferred 처리된 오픈 질문 (`# 6`) - -### 4. Implementation 초안 작성 원칙 - -- Design에서 확정된 태스크 구조와 변경 대상을 기반으로 각 태스크의 구현 방법, 변경 파일, 완료 조건을 초안으로 채운다. -- 저장소 구조, 파일 경로, 기존 코드 패턴을 실제로 확인해 변경 파일 목록(`IMP_FILE_N`)을 구체적으로 명시한다. -- 아래 항목은 추론 불가 또는 사용자 확인 필요이므로 플레이스홀더로 남긴다. - - 태스크 담당자 (`{{IMP_TASK_OWNER_N:TBD}}`) - - Freeze 확정 담당자 (`{{CONFIRMED_BY:TBD}}`) - -### 5. 자동으로 채워야 하는 항목 - -| 항목 | 채움 방법 | -|------|---------| -| `# 0` 메타데이터 | 현재 시각, CYCLE_ID, 이슈명, Design 경로를 자동 입력 | -| `# 1` Design 인계 요약 | Design `# 1` 태스크 목록 및 변경 대상 이식, `# 6`의 Deferred 항목 이식 | -| `# 2` 구현 순서 | 태스크 의존 관계를 기반으로 구현 순서 초안 작성 | -| `# 2` 태스크별 구현 방법 | Design `# 3` 상세 설계 내용을 기반으로 구현 접근 방법 초안 작성 | -| `# 3` 변경 파일 목록 | Design `# 3`의 변경 대상 파일/함수를 기반으로 실제 경로 확인 후 목록 작성 | -| `# 4` 리스크 | Design 이월 리스크 중 Implementation 관련 항목 포함 및 신규 리스크 추가 | -| `# 6` 파일 처리 결과 | 생성 결과와 참조 문서 경로 채움 | -| `# 7` 사용자 결정 필요 | 미확정 태스크 담당자, 외부 시스템 호출 확인 필요 항목 정리 | -| `# 8` Freeze 플래그 | `Handoff Decision: 보류`, `Ready for Verification: false` 초기값 입력 | - -### 6. 파일 생성 - -- 경로: `docs/sdlc//4_implementation.md` -- 기반: `.github/templates/sdlc/4_implementation.md`를 구조 기준으로 사용하되, 위 작성 원칙에 따라 채운 초안을 생성한다. - -### 7. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **생성된 파일 경로** -- **자동 채워진 항목 목록** (어떤 값으로 채웠는지) -- **플레이스홀더로 남긴 항목 목록** (사용자 결정 필요 이유 포함) -- **다음 단계 안내**: `/review-implementation ` 실행 안내 diff --git a/.github/prompts/draft-operation.prompt.md b/.github/prompts/draft-operation.prompt.md deleted file mode 100644 index cbd8466..0000000 --- a/.github/prompts/draft-operation.prompt.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -name: "draft-operation" -description: "Create a 7_operation.md draft from a confirmed Release document" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/6_release.md" -agent: "agent" ---- -확정된 Release 문서를 기반으로 Operations 초안(`7_operation.md`)을 생성한다. - -목표: -- `docs/sdlc//7_operation.md`를 생성한다. -- `6_release.md`의 배포 결과와 모니터링 정보를 Operations 초안의 입력으로 사용한다. -- 추론 가능한 운영 항목은 초안으로 채우고, 사용자 결정이 필요한 항목만 플레이스홀더로 남긴다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 CYCLE_ID(예: `sdlc-001`)를 제공했으면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `6_release.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로의 상위 폴더에서 `6_release.md`를 찾는다. -- 파일이 없으면 사용자에게 피드백하고 중단한다. - -### 2. Release 인계 조건 확인 - -`6_release.md`에서 아래 조건을 확인한다. 미충족 시 중단하고 이유를 보고한다. - -| 항목 | 기준 | -|------|------| -| 문서 상태 | `confirmed`여야 한다 | -| Ready for Operations | `true`여야 한다 | -| 7_operation.md 존재 여부 | 이미 존재하면 덮어쓰기 의사를 확인하고, 의사 표현이 없으면 중단한다 | - -### 3. 내용 추출 - -`6_release.md`, `5_verification.md`, `1_discovery.md`에서 아래 항목을 읽어 Operations 초안 작성에 사용한다. - -- 이슈명 (`# 0`의 `이슈명:`) -- 문서 ID / CYCLE_ID -- 배포 환경 및 배포 방식 (`6_release.md` `# 2`) -- 스모크 테스트 항목 (`6_release.md` `# 4`) -- Release 모니터링 확인 항목 (`6_release.md` `# 4`) -- Deferred 처리된 오픈 질문 (`6_release.md` `# 5`) -- 성공 기준(S-N) (`1_discovery.md` `# 7`) - -### 4. Operations 초안 작성 원칙 - -- Release의 스모크 테스트/모니터링 항목을 확장해 지속적인 운영 모니터링 항목을 도출한다. -- 저장소 구조와 배포 방식을 참고해 장애 대응 절차를 구체적으로 초안으로 작성한다. -- `# 6` 다음 Discovery 환류 항목은 초안 생성 시 빈 상태(`없음`)로 두고, 운영 중 갱신하도록 안내한다. -- 아래 항목은 추론 불가 또는 사용자 확인 필요이므로 플레이스홀더로 남긴다. - - 모니터링 담당자 (`{{OPS_MONITOR_OWNER:TBD}}`) - - 에스컬레이션 연락처 (`{{OPS_ESCALATION_1:TBD}}`) - - Freeze 확정 담당자 (`{{CONFIRMED_BY:TBD}}`) - -### 5. 자동으로 채워야 하는 항목 - -| 항목 | 채움 방법 | -|------|---------| -| `# 0` 메타데이터 | 현재 시각, CYCLE_ID, 이슈명, Release 경로를 자동 입력 | -| `# 1` Release 인계 요약 | Release 배포 결과 요약, Deferred 항목 이식 | -| `# 2` 모니터링 항목 | Release 스모크 테스트/모니터링 항목을 기반으로 지속 모니터링 항목 도출, 임계값 초안 작성 | -| `# 3` 런북 — 정상 운영 절차 | Release 배포 방식 기반으로 주기적 확인 절차 초안 작성 | -| `# 3` 런북 — 장애 대응 절차 | 롤백 계획 및 배포 방식 기반으로 장애 초기 대응 절차 초안 작성 | -| `# 5` 리스크 | Release 이월 리스크 중 Operations 관련 항목 포함 | -| `# 6` 다음 Discovery 환류 | `없음`으로 초기화 (운영 중 갱신 안내) | -| `# 8` 파일 처리 결과 | 생성 결과와 참조 문서 경로 채움 | -| `# 9` 사용자 결정 필요 | 모니터링 담당자, 에스컬레이션 담당자 미지정 항목 정리 | -| `# 10` Freeze 플래그 | `Handoff Decision: 보류`, `SDLC 주기 완료: false` 초기값 입력 | - -### 6. 파일 생성 - -- 경로: `docs/sdlc//7_operation.md` -- 기반: `.github/templates/sdlc/7_operation.md`를 구조 기준으로 사용하되, 위 작성 원칙에 따라 채운 초안을 생성한다. - -### 7. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **생성된 파일 경로** -- **자동 채워진 항목 목록** (어떤 값으로 채웠는지) -- **플레이스홀더로 남긴 항목 목록** (사용자 결정 필요 이유 포함) -- **다음 단계 안내**: `/review-operation ` 실행 안내 diff --git a/.github/prompts/draft-planning.prompt.md b/.github/prompts/draft-planning.prompt.md deleted file mode 100644 index 40e9096..0000000 --- a/.github/prompts/draft-planning.prompt.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -name: "draft-planning" -description: "Create a 2_planning.md draft from a confirmed Discovery document" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/1_discovery.md" -agent: "agent" ---- -확정된 Discovery 문서를 기반으로 Planning 초안(`2_planning.md`)을 생성한다. - -목표: -- `docs/sdlc//2_planning.md`를 생성한다. -- `1_discovery.md`의 확정 내용(FR/NFR, 범위, 성공 기준, 리스크)을 Planning 초안의 입력으로 사용한다. -- 추론 가능한 항목은 초안 문장으로 채우고, 사용자 결정이 필요한 항목만 플레이스홀더로 남긴다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 CYCLE_ID(예: `sdlc-001`)를 제공했으면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `1_discovery.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로의 상위 폴더에서 `1_discovery.md`를 찾는다. -- 파일이 없으면 사용자에게 피드백하고 중단한다. - -### 2. Discovery 인계 조건 확인 - -`1_discovery.md`에서 아래 조건을 확인한다. 미충족 시 중단하고 이유를 보고한다. - -| 항목 | 기준 | -|------|------| -| 문서 상태 | `confirmed`여야 한다 | -| Ready for Planning | `true`여야 한다 | -| 2_planning.md 존재 여부 | 이미 존재하면 덮어쓰기 의사를 확인하고, 의사 표현이 없으면 중단한다 | - -### 3. Discovery 내용 추출 - -`1_discovery.md`에서 아래 항목을 읽어 Planning 초안 작성에 사용한다. - -- 이슈명 (`# 0`의 `이슈명:`) -- 문서 ID / CYCLE_ID -- In Scope / Out of Scope (`# 5`) -- FR 전체 목록 (`# 5`) -- NFR 전체 목록 (`# 5`) -- 성공 기준 S-1~S-N (`# 7`) -- 리스크 R-1~R-N 및 완화 방안 (`# 6`) -- Deferred 처리된 오픈 질문 (`# 6`) -- 가정 A-1~A-N (`# 6`) - -### 4. Planning 초안 작성 원칙 - -- 입력 요청과 Discovery 내용을 바탕으로 합리적으로 추론 가능한 항목은 자연어 문장으로 채운다. -- 아래 항목은 추론 불가 또는 사용자 확인 필요이므로 플레이스홀더로 남긴다. - - 태스크 담당자 (`{{TASK_OWNER_N:TBD}}`) - - 마일스톤 목표 날짜 (`{{MILESTONE_N_DATE:TBD}}`) - - 이터레이션 기간 (`{{ITERATION_N_PERIOD:TBD}}`) - - Freeze 확정 담당자 (`{{CONFIRMED_BY:TBD}}`) -- 공수 추정은 유사 작업 기준 또는 태스크 복잡도 기반으로 초안 값을 제안한다. 불확실하면 범위(예: `2-4 SP`)로 표기한다. -- 태스크는 각 FR 1개당 최소 1개를 생성하되, 구현/검토/문서화를 묶거나 분리하는 것이 합리적이면 그렇게 한다. - -### 5. 자동으로 채워야 하는 항목 - -| 항목 | 채움 방법 | -|------|---------| -| `# 0` 메타데이터 | 현재 시각, CYCLE_ID, 이슈명, Discovery 경로를 자동 입력 | -| `# 1` Discovery 인계 요약 | Discovery `# 5` 범위/FR/NFR 내용 요약 이식 | -| `# 1` 이월 오픈 질문 | Discovery `# 6`의 `Deferred` 항목 이식 | -| `# 2` 태스크 분해 | FR/NFR 기반으로 최소 2개 이상의 태스크 생성 | -| `# 2` 태스크 DoD | 각 태스크의 완료 조건을 FR 내용 기반으로 초안 작성 | -| `# 3` 공수 추정 | 각 태스크에 초안 공수값 또는 범위 제안 | -| `# 4` 마일스톤 | 태스크 그룹 기반으로 최소 1개 이상 초안 작성 | -| `# 5` 의존성 | 태스크 간 의존 관계를 분석해 초안 작성 | -| `# 6` 검증 계획 | Discovery 성공 기준(S-N)과 연결해 검증 방법 초안 작성 | -| `# 7` 리스크 | Discovery 이월 리스크 중 Planning 관련 항목 포함 및 신규 Planning 리스크 추가 | -| `# 9` 파일 처리 결과 | 생성 결과와 참조 문서 경로 채움 | -| `# 10` 사용자 결정 필요 | 담당자 지정, 일정 확정, 예산/환경 제약 등 사용자 결정 필요 항목 정리 | -| `# 11` Freeze 플래그 | `Handoff Decision: 보류`, `Ready for Design: false` 초기값 입력 | - -### 6. 파일 생성 - -- 경로: `docs/sdlc//2_planning.md` -- 기반: `.github/templates/sdlc/2_planning.md`를 구조 기준으로 사용하되, 위 작성 원칙에 따라 채운 초안을 생성한다. - -### 7. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **생성 결과**: 파일 경로 -- **채워진 항목 요약**: 자동 추론으로 채운 주요 내용 목록 -- **사용자 결정 필요 항목**: `# 10`에 정리된 항목 요약 -- **다음 단계 안내**: Planning 검토 후 `/confirm-planning ` 실행 안내 - ---- - -## 중요 규칙 - -- Discovery가 `confirmed` 상태가 아니면 초안을 생성하지 않는다. -- 이미 `2_planning.md`가 존재하는 경우 사용자 명시 없이 덮어쓰지 않는다. -- 추론 불가 항목은 `TBD` 대신 의미 있는 플레이스홀더(`{{TASK_OWNER_1:TBD}}` 등)로 남긴다. -- 공수 추정 초안은 반드시 근거(유사 사례, 복잡도 판단 등)와 함께 `# 3`에 명시한다. -- 현재 시각은 시스템 또는 컨텍스트에서 제공된 날짜/시간을 사용한다. diff --git a/.github/prompts/draft-release.prompt.md b/.github/prompts/draft-release.prompt.md deleted file mode 100644 index 51aa19d..0000000 --- a/.github/prompts/draft-release.prompt.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -name: "draft-release" -description: "Create a 6_release.md draft from a confirmed Verification document" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/5_verification.md" -agent: "agent" ---- -확정된 Verification 문서를 기반으로 Release 초안(`6_release.md`)을 생성한다. - -목표: -- `docs/sdlc//6_release.md`를 생성한다. -- `5_verification.md`의 검증 결과와 `4_implementation.md`의 변경 파일 목록을 Release 초안의 입력으로 사용한다. -- 추론 가능한 배포 계획 항목은 초안으로 채우고, 사용자 결정이 필요한 항목만 플레이스홀더로 남긴다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 CYCLE_ID(예: `sdlc-001`)를 제공했으면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `5_verification.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로의 상위 폴더에서 `5_verification.md`를 찾는다. -- 파일이 없으면 사용자에게 피드백하고 중단한다. - -### 2. Verification 인계 조건 확인 - -`5_verification.md`에서 아래 조건을 확인한다. 미충족 시 중단하고 이유를 보고한다. - -| 항목 | 기준 | -|------|------| -| 문서 상태 | `confirmed`여야 한다 | -| Ready for Release | `true`여야 한다 | -| 6_release.md 존재 여부 | 이미 존재하면 덮어쓰기 의사를 확인하고, 의사 표현이 없으면 중단한다 | - -### 3. 내용 추출 - -`5_verification.md`, `4_implementation.md`, `1_discovery.md`에서 아래 항목을 읽어 Release 초안 작성에 사용한다. - -- 이슈명 (`# 0`의 `이슈명:`) -- 문서 ID / CYCLE_ID -- 검증 결과 요약 (`5_verification.md` `# 3`) -- Deferred 처리된 오픈 질문 (`5_verification.md` `# 5`) -- 변경 파일 목록 (`4_implementation.md` `# 3`) -- 저장소 구조 및 배포 관련 설정 파일 - -### 4. Release 초안 작성 원칙 - -- 저장소 구조와 배포 관련 파일(`.github/workflows`, `Makefile`, `bootstrap/` 등)을 실제로 확인해 배포 방식과 도구를 구체적으로 초안으로 채운다. -- 롤백 계획은 변경 파일 목록을 기반으로 현실적인 롤백 절차를 초안으로 작성한다. -- 스모크 테스트 항목은 핵심 기능 FR을 기반으로 도출한다. -- 아래 항목은 추론 불가 또는 사용자 확인 필요이므로 플레이스홀더로 남긴다. - - 롤백 담당자 (`{{REL_ROLLBACK_OWNER:TBD}}`) - - Freeze 확정 담당자 (`{{CONFIRMED_BY:TBD}}`) - -### 5. 자동으로 채워야 하는 항목 - -| 항목 | 채움 방법 | -|------|---------| -| `# 0` 메타데이터 | 현재 시각, CYCLE_ID, 이슈명, Verification 경로를 자동 입력 | -| `# 1` Verification 인계 요약 | Verification 검증 결과 요약, Deferred 항목 이식 | -| `# 2` 배포 환경/방식/도구 | 저장소 구조 기반으로 배포 방식 초안 작성 | -| `# 2` 배포 순서 | 변경 파일 목록 기반으로 의존 관계를 고려한 배포 순서 초안 작성 | -| `# 3` 롤백 계획 | 변경 내용에 대한 현실적인 롤백 조건 및 절차 초안 작성 | -| `# 4` 스모크 테스트 | FR 기반으로 핵심 시나리오 도출 및 확인 방법 초안 작성 | -| `# 5` 리스크 | Verification 이월 리스크 중 Release 관련 항목 포함 | -| `# 7` 파일 처리 결과 | 생성 결과와 참조 문서 경로 채움 | -| `# 8` 사용자 결정 필요 | 배포 담당자, 롤백 담당자 미지정 항목 정리 | -| `# 9` Freeze 플래그 | `Handoff Decision: 보류`, `Ready for Operations: false` 초기값 입력 | - -### 6. 파일 생성 - -- 경로: `docs/sdlc//6_release.md` -- 기반: `.github/templates/sdlc/6_release.md`를 구조 기준으로 사용하되, 위 작성 원칙에 따라 채운 초안을 생성한다. - -### 7. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **생성된 파일 경로** -- **자동 채워진 항목 목록** (어떤 값으로 채웠는지) -- **플레이스홀더로 남긴 항목 목록** (사용자 결정 필요 이유 포함) -- **다음 단계 안내**: `/review-release ` 실행 안내 diff --git a/.github/prompts/draft-verification.prompt.md b/.github/prompts/draft-verification.prompt.md deleted file mode 100644 index 3560dec..0000000 --- a/.github/prompts/draft-verification.prompt.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -name: "draft-verification" -description: "Create a 5_verification.md draft from a confirmed Implementation document" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/4_implementation.md" -agent: "agent" ---- -확정된 Implementation 문서를 기반으로 Verification 초안(`5_verification.md`)을 생성한다. - -목표: -- `docs/sdlc//5_verification.md`를 생성한다. -- `4_implementation.md`의 완료 태스크와 `1_discovery.md`의 성공 기준(S-N)을 Verification 초안의 입력으로 사용한다. -- 추론 가능한 검증 항목은 초안으로 채우고, 사용자 결정이 필요한 항목만 플레이스홀더로 남긴다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 사용자가 CYCLE_ID(예: `sdlc-001`)를 제공했으면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `4_implementation.md` 경로를 확정한다. -- 사용자가 파일 경로를 직접 제공했으면 해당 경로의 상위 폴더에서 `4_implementation.md`를 찾는다. -- 파일이 없으면 사용자에게 피드백하고 중단한다. - -### 2. Implementation 인계 조건 확인 - -`4_implementation.md`에서 아래 조건을 확인한다. 미충족 시 중단하고 이유를 보고한다. - -| 항목 | 기준 | -|------|------| -| 문서 상태 | `confirmed`여야 한다 | -| Ready for Verification | `true`여야 한다 | -| 5_verification.md 존재 여부 | 이미 존재하면 덮어쓰기 의사를 확인하고, 의사 표현이 없으면 중단한다 | - -### 3. 내용 추출 - -`4_implementation.md`, `3_design.md`, `1_discovery.md`에서 아래 항목을 읽어 Verification 초안 작성에 사용한다. - -- 이슈명 (`# 0`의 `이슈명:`) -- 문서 ID / CYCLE_ID -- 구현 완료 태스크 목록 및 변경 파일 (`# 1`, `# 3`) -- 태스크별 완료 조건(DoD) (`# 2`) -- Deferred 처리된 오픈 질문 (`# 4`) -- 성공 기준(S-N) (`1_discovery.md` `# 7`) -- 기능 요구사항(FR) 목록 (`1_discovery.md` `# 5`) -- 검증 계획 개요 (`2_planning.md` `# 6`) - -### 4. Verification 초안 작성 원칙 - -- Discovery 성공 기준(S-N)과 FR 목록을 기반으로 검증 항목(VC-N)을 도출한다. -- 각 VC 항목에 검증 방법(수동/자동/혼합)과 측정 가능한 성공 기준을 초안으로 채운다. -- 검증 결과(`# 3`) 테이블은 모두 `미완료`로 초기화한다. -- 아래 항목은 추론 불가 또는 사용자 확인 필요이므로 플레이스홀더로 남긴다. - - 검증 담당자 (`{{VER_OWNER_N:TBD}}`) - - Freeze 확정 담당자 (`{{CONFIRMED_BY:TBD}}`) - -### 5. 자동으로 채워야 하는 항목 - -| 항목 | 채움 방법 | -|------|---------| -| `# 0` 메타데이터 | 현재 시각, CYCLE_ID, 이슈명, Implementation 경로를 자동 입력 | -| `# 1` Implementation 인계 요약 | Implementation `# 1`/`# 2` 태스크 목록 및 DoD 이식, `# 4`의 Deferred 항목 이식 | -| `# 2` 검증 항목 | Discovery S-N 기준과 FR/NFR을 기반으로 VC-N 항목 도출 및 검증 방법/성공 기준 초안 작성 | -| `# 2` 성공 기준 연결 | S-N과 VC-N의 연결 관계 명시 | -| `# 3` 검증 결과 | 모든 항목 `미완료`로 초기화, 통과/실패 집계 0으로 초기화 | -| `# 5` 리스크 | Implementation 이월 리스크 중 Verification 관련 항목 포함 | -| `# 7` 파일 처리 결과 | 생성 결과와 참조 문서 경로 채움 | -| `# 8` 사용자 결정 필요 | 검증 담당자 미지정 항목 정리 | -| `# 9` Freeze 플래그 | `Handoff Decision: 보류`, `Ready for Release: false` 초기값 입력 | - -### 6. 파일 생성 - -- 경로: `docs/sdlc//5_verification.md` -- 기반: `.github/templates/sdlc/5_verification.md`를 구조 기준으로 사용하되, 위 작성 원칙에 따라 채운 초안을 생성한다. - -### 7. 결과 보고 - -응답에 아래 내용을 포함한다. - -- **생성된 파일 경로** -- **자동 채워진 항목 목록** (어떤 값으로 채웠는지) -- **플레이스홀더로 남긴 항목 목록** (사용자 결정 필요 이유 포함) -- **다음 단계 안내**: `/review-verification ` 실행 안내 diff --git a/.github/prompts/new-sdlc.prompt.md b/.github/prompts/new-sdlc.prompt.md deleted file mode 100644 index e63c1c8..0000000 --- a/.github/prompts/new-sdlc.prompt.md +++ /dev/null @@ -1,173 +0,0 @@ ---- -name: "new-sdlc" -description: "Create next SDLC cycle folder and draft 1_discovery.md from slash-command arguments" -argument-hint: "예: 사용자 로그인 기능 추가 - OAuth2 소셜 로그인, 세션 관리, 로그아웃 처리" -agent: "agent" ---- -/new-sdlc 로 들어온 인자를 기반으로 새 SDLC 주기를 생성한다. - -목표: -- `docs/sdlc/sdlc-__/` 폴더를 생성한다. -- 위 폴더에 `1_discovery.md` draft 문서를 생성한다. -- 위 폴더에 `index.md`, `summary.md` draft 문서를 함께 생성한다. -- `1_discovery.md`는 `.github/templates/sdlc/1_discovery.md`를 기반으로, 입력 문장과 현재 구현 상태를 바탕으로 기본 내용을 가능한 한 채운 초안이어야 한다. - -입력 해석: -- 사용자가 `/new-sdlc ...` 뒤에 입력한 전체 텍스트를 이슈 원문으로 사용한다. -- 이슈명은 원문과 현재 구현 상태를 확인하여 한 문장으로 요약한다. -- `topic-slug`는 이슈 원문을 소문자 kebab-case로 변환해 만든다. -- slug 규칙: - - 영문/숫자 외 문자는 `-`로 치환 - - 연속 `-`는 하나로 축약 - - 시작/끝 `-` 제거 - - 결과가 비면 `untitled` 사용 - -Discovery 초안 작성 원칙: -- 입력 문장이 짧더라도 기능 목적, 예상 사용자, 산출물, 성공 조건을 합리적으로 추론해 초안을 작성한다. -- 이미 입력만으로 추론 가능한 내용은 플레이스홀더로 남기지 말고 자연어 문장으로 채운다. -- 사용자 승인, 외부 데이터, 정책 결정, 확정 범위 경계처럼 추론만으로 확정하면 안 되는 항목만 플레이스홀더로 남긴다. -- 사용자 결정이 필요한 항목은 `결정 필요` 같은 일반 문장으로만 쓰지 말고, 반드시 `{{...}}` 플레이스홀더 형태로 남긴다. -- 모르면 공란으로 두지 말고 아래 둘 중 하나로 처리한다. - - 합리적 기본안 제시 가능: 초안 문장으로 채운다. - - 사용자 확인이 반드시 필요: `# 10. 사용자 결정 필요 항목 요약`에 넣고 관련 본문에는 최소 플레이스홀더를 남긴다. - -자동으로 채워야 하는 Discovery 섹션: -- `# 1. 계획 상태 요약` - - `해석` 2줄은 입력 요청을 바탕으로 직접 작성한다. -- `# 2. 요구사항 판정 결과` - - 기본값은 `신규`로 두되, 입력만으로 명백한 중복/유사라고 판단 가능한 경우에만 다르게 쓴다. - - 근거도 2줄 작성한다. -- `# 3. 문제점의 요약` - - 현재 상태, 기대 상태, 이해관계자, 주요 사용자 시나리오를 입력 기반으로 채운다. -- `# 4. 이번에 정의할 변경` - - 핵심 변경 항목 1~3개를 직접 작성한다. - - `영향 범위`의 코드/문서/운영 영향도 추론해 채운다. -- `# 5. 요구사항 목록` - - FR 2개 이상, NFR 1개 이상을 직접 작성한다. - - In Scope/Out of Scope는 초안 수준으로 제안하되, 사용자 승인 없이는 확정할 수 없는 경계는 플레이스홀더로 남긴다. -- `# 6. 리스크/가정 목록` - - 리스크 2개 이상, 가정 2개 이상을 직접 작성한다. - - 오픈 질문은 정말 결정이 필요한 경우에만 남긴다. -- `# 7. 초기 성공 기준` - - 성공 기준 2개 이상과 측정 방식/데이터 출처 초안을 작성한다. -- `# 9. 파일 처리 결과` - - 생성 결과와 최소 참조 문서를 채운다. 참조 문서가 없으면 `없음`이라고 쓴다. -- `# 10. 사용자 결정 필요 항목 요약` - - 자동 추론으로 확정할 수 없는 항목만 `DECIDE`, `CONFIRM`, `DATA`에 넣는다. - - 이 섹션의 항목은 설명문이 아니라 플레이스홀더 형식으로 남긴다. -- `# 11. Discovery Freeze` - - `Handoff Decision`은 기본 `보류`로 둔다. - - `Handoff Rationale`에는 "초기 Discovery 초안 생성 완료, Planning 인계 전 사용자 확인 필요"와 같이 현재 상태를 적는다. - -플레이스홀더를 유지해도 되는 대표 항목: -- 승인/확정 책임자 -- 외부 문서 경로, 아직 없는 후속 산출물 경로 -- 사용자 확인이 필요한 범위 경계 -- 데이터 출처가 실제로 정해지지 않은 성공 지표 측정값 -- 오픈 질문의 최종 답변 - -플레이스홀더 유지 규칙: -- 사용자 승인 전 확정되면 안 되는 정책/범위/산출물 위치/대상 독자 결정은 본문에도 플레이스홀더를 남긴다. -- `# 10. 사용자 결정 필요 항목 요약`에 들어가는 항목은 반드시 `{{DECIDE_*}}`, `{{CONFIRM_*}}`, `{{DATA_*}}` 형태를 사용한다. -- `TBD` 같은 일반 문자열보다 의미가 드러나는 플레이스홀더를 우선 사용한다. - -실행 절차: -1. `docs/sdlc/` 아래의 기존 폴더 중 `sdlc-<3자리>_` 패턴을 스캔해 최대 번호를 찾는다. -2. 다음 번호를 3자리 zero-pad로 계산한다. 예: `001`, `002`, ... -3. 오늘 날짜를 `YYYYMMDD`로 구한다. -4. `CYCLE_ID = sdlc-__`를 만든다. -5. 저장소 현황 탐색 — `# 3 문제점 요약`의 "현재 상태" 기술 근거를 수집한다. - - 이슈 원문에서 핵심 키워드(기능명, 모듈명, 동사)를 추출한다. - - 키워드를 기반으로 저장소에서 관련 파일·디렉터리·함수를 탐색한다. - - 탐색 범위: 소스 파일(`.ts`, `.js`, `.py`, `.go`, `.java` 등), 설정 파일, 기존 문서(`docs/`). 테스트 파일과 의존성 잠금 파일(`package-lock.json`, `.lock`)은 제외한다. - - 탐색 결과에서 아래 항목을 추출한다. - - 관련 파일 경로 목록 (최대 10개, 관련성 높은 순) - - 현재 구현 방식 요약 (함수명·클래스명·주요 로직 1~3줄) - - 현재 상태에서 이슈 원문이 지적하는 문제가 실제로 존재하는지 여부 - - 관련 파일을 찾지 못한 경우: "관련 파일 없음 — 신규 기능으로 추정"으로 기록하고 계속 진행한다. - - 탐색 결과는 `1_discovery.md` 작성 시 `#3` 현재 상태 기술에만 반영한다. 다른 섹션에는 사용하지 않는다. -6. `docs/sdlc//` 폴더를 생성한다. -7. `.github/templates/sdlc/1_discovery.md`를 기반으로 `docs/sdlc//1_discovery.md`를 생성한다. -7. [`.github/templates/sdlc/index.md`](../../.github/templates/sdlc/index.md)를 기반으로 `docs/sdlc//index.md`를 생성한다. - -8. `.github/templates/sdlc/summary.md`가 있으면 이를 기반으로 `docs/sdlc//summary.md`를 생성한다. 템플릿이 없으면 아래 기본 골격으로 생성한다. - - ```md - # Summary - {{CYCLE_ID}} - - - 이슈명: {{ISSUE_NAME}} - - 상태: {{SUMMARY_STATUS:draft|review|confirmed}} - - 작성 시각(KST): {{CREATED_AT_KST}} - - 마지막 갱신 시각(KST): {{UPDATED_AT_KST}} - - ## 핵심 요약 - - {{SUMMARY_POINT_1}} - - {{SUMMARY_POINT_2:필요 없으면 삭제}} - - ## 단계별 문서 - - [Discovery](./1_discovery.md) - - [Index](./index.md) - ``` - -11. 생성 파일들에서 아래 플레이스홀더를 우선 치환한다. - - `{{DOC_STATUS:draft|review|confirmed}}` -> `draft` - - `{{CYCLE_ID:sdlc-<3자리>__}}` -> 계산한 `CYCLE_ID` - - `{{CYCLE_ID}}` -> 계산한 `CYCLE_ID` - - `{{ISSUE_NAME:짧은 한글 또는 영문 이슈명}}` -> 사용자 입력 원문 - - `{{ISSUE_NAME}}` -> 사용자 입력 원문 - - `{{CREATED_AT_KST:TBD}}` -> 현재 시각(KST) - - `{{CREATED_AT_KST}}` -> 현재 시각(KST) - - `{{UPDATED_AT_KST:TBD}}` -> 현재 시각(KST) - - `{{UPDATED_AT_KST}}` -> 현재 시각(KST) - - `{{OUTPUT_PATH}}` -> 생성 파일 경로 - - `{{FILE_RESULT:생성|갱신|미생성}}` -> `생성` - - `{{SUMMARY_STATUS:draft|review|confirmed}}` -> `draft` -12. `1_discovery.md`에서는 위 규칙에 따라 추론 가능한 플레이스홀더를 적극적으로 실제 내용으로 치환한다. 이때 5단계에서 수집한 저장소 현황 탐색 결과를 `# 3 문제점 요약`의 현재 상태 기술에 반영한다. -13. 추론 불가능하거나 사용자 확인이 필요한 항목만 플레이스홀더로 남긴다. -14. `docs/sdlc/index.md` 전역 인덱스를 갱신한다. - - 파일이 없으면 아래 초기 골격으로 신규 생성한다. - - ```md - # SDLC 전체 주기 인덱스 - - - - ## 주기 목록 - - | ID | 날짜 | 이슈명 | Discovery | 상태 | - |---|---|---|---|---| - - ## 단계별 횡단 조회 - - | 단계 | 문서 목록 | - |---|---| - | Discovery | | - | Planning | | - | Design | | - | Implementation | | - | Verification | | - | Release | | - | Operations | | - ``` - - - 파일이 이미 있으면 다음 규칙으로 갱신한다. - - `## 주기 목록` 테이블에 새 행을 추가한다. 형식: - `| | | | [Discovery](.//1_discovery.md) | draft |` - - `## 단계별 횡단 조회` 테이블에서 `Discovery` 행의 `문서 목록` 셀에 `[](.//1_discovery.md)` 링크를 추가한다. - - 나머지 단계 행은 해당 단계 파일이 실제로 존재할 때만 링크를 추가한다(지금은 Discovery만 추가). - - 테이블 구조 자체는 변경하지 않는다. 행/셀 추가만 한다. - -응답 형식: -- 생성된 `CYCLE_ID` -- 생성한 폴더 경로 -- 생성한 파일 경로 목록 (`1_discovery.md`, `index.md`, `summary.md`) -- `docs/sdlc/index.md` 갱신 결과 (신규 생성 또는 갱신된 행 내용) -- **저장소 현황 탐색 결과**: 발견된 관련 파일 목록과 현재 상태 요약 (또는 "관련 파일 없음 — 신규 기능으로 추정") -- 자동으로 채운 Discovery 핵심 섹션 요약 -- 사용자 확인이 필요해 플레이스홀더로 남긴 항목 요약 - -중요 규칙: -- 질문 없이 바로 생성을 시도한다. (입력이 비어 있어 slug를 만들 수 없는 경우에만 짧게 확인) -- 기존 동일 경로가 있으면 덮어쓰지 말고, 다음 ID를 재계산해 새 주기로 생성한다. -- `docs/sdlc/index.md`에 이미 같은 `CYCLE_ID` 행이 있으면 중복 추가하지 않는다. -- 불필요한 파일은 만들지 않는다. diff --git a/.github/prompts/review-design.prompt.md b/.github/prompts/review-design.prompt.md deleted file mode 100644 index 612a573..0000000 --- a/.github/prompts/review-design.prompt.md +++ /dev/null @@ -1,148 +0,0 @@ ---- -name: "review-design" -description: "Review and validate SDLC Design document for consistency, completeness, and readiness for approval" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/3_design.md" -agent: "agent" ---- -SDLC Design 문서를 체계적으로 검토하고, 승인 가능한 상태인지 판단한다. - -목표: -- `3_design.md` 파일의 일관성 확인 (태스크/아키텍처/인터페이스/보안 간 중복 및 충돌) -- 기술적 오류, 잘못된 표현, 명확하지 않은 문구 식별 -- AI agent에게 할당된 플레이스홀더(`{{...}}`) 중 판단/결정 가능한 항목 처리 -- 플레이스홀더 중 사용자 결정이 정말 필요한 항목만 남겼는지 확인 -- 최종 승인 가능 상태 판단 - ---- - -## 검토 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 문서 경로 또는 CYCLE_ID에서 `3_design.md` 파일 위치를 확정한다. -- 파일이 없으면 입력값을 다시 확인하도록 사용자에게 피드백하고 중단한다. -- `2_planning.md`도 함께 읽어 인계 내용의 정합성 확인에 사용한다. - -### 2. Planning 인계 정합성 검토 - -`# 1. Planning 인계 요약`이 `2_planning.md`의 확정 내용과 일치하는지 확인한다. - -- 태스크 목록(T-N 제목, 참조 요구사항)이 Planning `# 2`와 내용/수량이 일치하는가 -- 이월된 오픈 질문이 Planning `# 7`의 `Deferred` 항목과 대응하는가 -- `# 3` 상세 설계의 T-N 항목이 `# 1` 태스크 목록과 누락 없이 1:1 대응하는가 - -### 3. 저장소 현황 대조 - -`3_design.md`에 기술된 "현재 상태(개선 전)"가 실제 저장소와 일치하는지 확인한다. - -#### 3-1. 변경 대상 파일 존재 여부 - -`# 3 상세 설계`의 각 T-N 섹션에서 "변경 대상" 파일/함수 경로를 추출하고 실제 저장소에서 확인한다. - -| 확인 항목 | 기준 | -|-----------|------| -| 수정 대상으로 명시된 파일 | 실제 저장소에 존재해야 한다. 없으면 경고 — 경로 오류 또는 신규 생성 여부를 명시하도록 요구 | -| 삭제 대상으로 명시된 파일 | 실제 저장소에 존재해야 한다. 없으면 경고 | -| 신규 생성 대상으로 명시된 파일 | 실제 저장소에 **없어야** 한다. 이미 존재하면 경고 — 수정 대상으로 재분류 필요 | - -#### 3-2. "현재 상태" 기술 정확성 - -`# 3 상세 설계` 및 `# 4 인터페이스 정의`에서 "현재 X 방식으로 동작한다", "현재 Y 함수가 Z를 반환한다" 등 현황을 기술한 문장을 찾아 실제 코드와 대조한다. - -- 일치: 별도 표시 없이 통과 -- 불일치: 해당 문장과 실제 코드를 나란히 제시하고 설계 문서 수정을 요구한다. **불일치 항목이 하나라도 있으면 최종 판단을 "보류(Hold)"로 설정한다.** -- 확인 불가(파일이 너무 크거나 탐색 범위 초과): "확인 불가 — 수동 검토 권장" 으로 표시한다. - -#### 3-3. 인터페이스 시그니처 대조 - -`# 4 인터페이스 정의`에 "현재 시그니처"가 명시된 항목에 대해 실제 코드의 함수/메서드 시그니처와 대조한다. - -- 파라미터 이름·타입·반환 타입이 일치하는지 확인한다. -- 불일치 시 실제 시그니처를 제시하고 설계 문서 수정을 요구한다. - -### 5. 일관성 검토 (모든 섹션 대상) - -- **태스크 번호 연속성**: `# 1`, `# 2` 컴포넌트 영향 범위, `# 3` 상세 설계의 T-N 번호가 누락 없이 연속이고 일치하는가 -- **인터페이스 정합성**: `# 3` 상세 설계에서 언급된 API/함수가 `# 4` 인터페이스 정의에 실제로 명시되었는가 -- **보안 연결성**: `# 3`에서 입출력이 정의된 경우 `# 5` 보안 점검의 "입력값 검증(Injection)" 항목이 적절히 점검되었는가 -- **숫자 연속성**: R-N, DA-N, OQ-N 번호가 누락 없이 연속인지 확인 - -### 4. 표현 검토 (모든 텍스트) - -- **문법**: 문장 구조, 주술 호응, 시제 일관성 -- **명확성**: "적절히", "대략", "가능하면" 같은 모호한 표현 식별 -- **작성 수준**: 기술 문서 기준의 형식적 톤 유지. 비공식 표현 제거 -- **오타**: 한글 띄어쓰기, 숫자 오류, 테이블 형식 검증 - -### 6. 플레이스홀더 처리 - -모든 `{{...}}` 플레이스홀더를 나열하고 각 항목의 의도를 파악한다. - -AI agent가 채울 수 있는 항목: -- `{{..._DECISION:...}}` 형태 — 문서 내 다른 섹션이나 Planning/저장소 정보로 추론 가능한지 확인 -- 컴포넌트 역할(`COMPONENT_N_ROLE`), 데이터 흐름(`DATA_FLOW_N`), 엣지 케이스(`DESIGN_EDGE_N`) 등 구조적으로 추론 가능한 항목 - -사용자 결정이 필요한 항목 (플레이스홀더 유지): -- 태스크 담당자(`DESIGN_TASK_OWNER_N`) -- 외부 시스템 계약이 미확정인 인터페이스(`INTERFACE_N`, `SCHEMA_N`) -- Freeze 확정 담당자(`CONFIRMED_BY`) - -각 항목에 대해 아래 중 하나를 판단한다: -- **채울 수 있음**: 문서 내 맥락, Planning 내용, 저장소 구조로 합리적 추론 가능 → 실제 내용으로 치환 -- **판단 불가능**: 사용자/승인자 결정, 외부 시스템 계약, 책임자 지정 필요 → 플레이스홀더 유지하되 명확성 강화 - -처리 결과를 별도 목록으로 보고한다. - -### 7. 섹션별 최소 검수 기준 - -| 섹션 | 최소 기준 | -|------|---------| -| `# 0 문서 상태` | 메타데이터 완성도 확인 (CREATED_AT_KST, PLANNING_PATH 채워졌는가) | -| `# 1 Planning 인계 요약` | 태스크 최소 1개 이상, Planning 태스크와 1:1 대응 여부 | -| `# 2 아키텍처/구조 설계` | 전체 구조 개요 1문단 이상, 주요 컴포넌트 1개 이상 | -| `# 3 상세 설계` | 모든 T-N 태스크에 설계 방향과 변경 대상이 있는가 | -| `# 4 인터페이스 정의` | 해당 없으면 "해당 없음" 명시, 있으면 함수/API 시그니처가 구체적인가 | -| `# 5 보안 고려사항` | 4개 항목(Injection/Auth/Data/Dep) 모두 해당/비해당 판정이 있는가, 해당 항목에 대응 방안이 있는가 | -| `# 6 리스크/가정/오픈 질문` | 리스크 1개 이상, 가정 1개 이상, OQ `Open` 상태가 있으면 종료 조건이 명시되었는가 | -| `# 7 확인 체크` | 체크 항목이 구체적이고 측정 가능한가 | -| `# 9 사용자 결정 필요` | 플레이스홀더가 실제 `{{...}}` 형식인가 (단순 문장 아닌가) | -| `# 10 Freeze` | Handoff Decision과 Rationale이 채워졌는가 | - -### 8. 최종 승인 판단 - -- **승인 가능 (Ready for Implementation)**: - - 모든 T-N 태스크에 설계 방향과 변경 대상이 채워졌는가 - - 인터페이스 계약이 구체적으로 명시되었는가 - - 보안 점검 항목 중 "해당"은 모두 대응 방안이 있는가 - - `# 6` 오픈 질문에 `Open` 상태 항목이 없거나 모두 `Deferred` 처리 완료인가 - - 남은 플레이스홀더는 모두 정당한가 (사용자/승인자 결정이 정말 필요) - - Freeze 플래그가 준비되었는가 (`READY_FOR_IMPLEMENTATION: true`로 변경 가능한가) - - 저장소 현황 대조에서 불일치 항목이 없는가 (3-2, 3-3) -- **조건부 (Pending Minor Changes)**: - - 일부 표현/인터페이스 초안만 수정하면 가능 - - 보안 항목 중 근거가 빈약한 항목 보완 권장 - - 저장소 현황 대조 결과 중 "확인 불가" 항목이 있어 수동 검토 권장 -- **보류 (Hold)**: - - T-N 태스크 설계 방향 누락, 인터페이스 미정의, 보안 "해당" 항목에 대응 방안 없음, OQ `Open` 잔여 등 근본적 재검토 필요 - - 저장소 현황 대조(3-2, 3-3)에서 불일치 항목이 하나라도 있는 경우 - ---- - -## 응답 형식 - -- **검토 결과 요약** - - Planning 인계 정합성 오류 (있으면 나열) - - 저장소 현황 대조 결과 (불일치/확인 불가 항목 나열, 없으면 "이상 없음") - - 발견된 일관성 오류 (있으면 나열) - - 표현/문법 오류 (있으면 나열) - - 섹션별 완성도 (예: `# 3` 상세 설계 — T-2 변경 대상 누락) - -- **플레이스홀더 처리 결과** - - 채워진 항목 (예: `{{COMPONENT_2_ROLE}}` → "Copilot 프롬프트 파일 등록·관리" 로 치환) - - 유지된 항목 (예: `{{DESIGN_TASK_OWNER_1:TBD}}` → 담당자 지정 필요로 유지) - -- **수정 사항 목록** (적용된 변경) - -- **최종 판단** - - 승인 가능 / 조건부 / 보류 - - 근거 및 남은 작업 사항 diff --git a/.github/prompts/review-discovery.prompt.md b/.github/prompts/review-discovery.prompt.md deleted file mode 100644 index baf02fd..0000000 --- a/.github/prompts/review-discovery.prompt.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -name: "review-discovery" -description: "Review and validate SDLC Discovery document for consistency, completeness, and readiness for approval" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/1_discovery.md" -agent: "agent" ---- -SDLC Discovery 문서를 체계적으로 검토하고, 승인 가능한 상태인지 판단한다. - -목표: -- 1_discovery.md 파일의 일관성 확인 (개념/용어/범위 중복 및 충돌) -- 기술적 오류, 잘못된 표현, 명확하지 않은 문구 식별 -- AI agent에게 할당된 플레이스홀더({{...}}) 중 판단/결정 가능한 항목 처리 -- 플레이스홀더 중 사용자 결정이 정말 필요한 항목만 남겼는지 확인 -- 최종 승인 가능 상태 판단 - -검토 절차: - -1. 입력 해석 - - 사용자가 제공한 문서 경로 또는 CYCLE_ID에서 1_discovery.md 파일 위치를 확정한다. - - 파일이 없으면 입력값을 다시 확인하도록 사용자에게 피드백한다. - -2. 일관성 검토 (모든 섹션 대상) - - 용어: 같은 개념이 다른 이름으로 반복되는지 확인. 예: "사용자"와 "최종 사용자", "범위"와 "경계" 혼용. - - 개념 중복: 섹션 간 내용이 동일하거나 매우 유사한 부분 식별. 예: `# 1`의 해석과 `# 10` 요약의 중복. - - 범위 정합성: In Scope/Out of Scope가 명확히 구분되는지, 요구사항 목록과 맞는지 확인. - - 숫자 일관성: 리스크(R-1~3), 가정(A-1~3), 성공 기준(S-1~3) 등 번호가 누락 없이 연속인지 확인. - -3. 표현 검토 (모든 텍스트) - - 문법: 문장 구조, 주술 호응, 시제 일관성 확인. - - 명확성: 주관적이거나 모호한 표현 식별. 예: "적절한", "대략적으로", "대체로". - - 작성 수준: 기술 문서 기준의 형식적 톤 유지. 비공식 표현이나 과도한 가정 제거. - - 오타: 한글 띄어쓰기, 숫자 오류, 링크 형식 검증. - -4. 플레이스홀더 처리 - - 모든 `{{...}}` 플레이스홀더를 나열하고, 각 항목의 의도를 파악한다. - - AI agent 할당 항목 식별: - - `{{ASSUMPTION_1_DECISION:...}}`, `{{TARGET_STATE_2_DECISION:...}}` 같은 `_DECISION` 형태 - - `{{DECIDE_*}}`, `{{CONFIRM_*}}`, `{{DATA_*}}` 형태 - - 각 항목에 대해 아래 중 하나를 판단한다. - - **채울 수 있음**: 문서 내 다른 섹션, 입력 요청, 저장소 구조를 바탕으로 합리적 내용 추론 가능 → 실제 내용으로 치환 - - **판단 불가능**: 사용자/승인자의 정책 결정, 외부 데이터 확인, 승인 책임자 지정 필요 → 플레이스홀더 유지하되 명확성 강화 - - 처리 결과를 별도 목록으로 보고한다. - -5. 섹션별 최소 검수 기준 - - `# 0 문서 상태`: 메타데이터 완성도 확인 (예: CREATED_AT_KST는 현재 시각으로 채워졌는가) - - `# 2 요구사항 판정`: 판정이 신규/유사/중복 중 하나인가, 근거는 2줄 이상인가 - - `# 3 문제점 요약`: 현재 상태와 기대 상태가 명확히 대비되는가 - - `# 5 요구사항 목록`: FR/NFR 각각 최소 개수(FR 2개, NFR 1개) 이상인가, 범위 경계가 명시되었는가 - - `# 6 리스크/가정/오픈질문`: 항목 수가 적절한가(2개 이상), 오픈 질문은 정말 결정 필요인가 - - `# 8 확인 체크`: 체크 항목이 구체적이고 측정 가능한가 - - `# 10 사용자 결정 필요`: 플레이스홀더가 실제 플레이스홀더 형식인가 (단순 문장 아닌가) - - `# 11 Freeze`: Handoff Decision과 Rationale이 채워졌는가 - -6. 최종 승인 판단 - - **승인 가능 (Ready for Planning)**: - - 모든 일관성 오류가 해소되었는가 - - 명확하지 않은 표현이 제거되었는가 - - 남은 플레이스홀더는 모두 정당한가 (사용자/승인자 결정이 정말 필요) - - 모든 요구 섹션이 채워졌는가 - - Freeze 플래그가 준비되었는가 (READY_FOR_PLANNING: true로 변경 가능한가) - - **조건부 (Pending Minor Changes)**: - - 일부 표현만 수정하면 가능 - - 플레이스홀더 중 일부는 명확성을 위해 재작성 권장 - - **보류 (Hold)**: - - 개념적 불일치, 범위 재정의, 승인자 선정 등 근본적 재검토 필요 - -응답 형식: -- **검토 결과 요약** - - 발견된 일관성 오류 (있으면 나열) - - 표현/문법 오류 (있으면 나열) - - 섹션별 완성도 점수 (예: 3/5 = 범위 경계 미명시) - -- **플레이스홀더 처리 결과** - - 채워진 항목 (예: `{{TARGET_STATE_2_DECISION}}` → "GitHub 기반으로 운영"로 치환) - - 유지된 항목 (예: `{{DECIDE_ITEM_1}}` → 사용자 승인 필요로 유지) - -- **수정 사항 목록** (적용된 변경) - -- **최종 판단** - - 승인 가능 / 조건부 / 보류 - - 근거 및 남은 작업 사항 - -중요 규칙: -- 도큐먼트 내용을 변경하는 경우 반드시 명확히 표기한다. -- AI agent 판단으로 치환한 항목은 합리적 근거를 함께 설명한다. -- 의도적으로 플레이스홀더를 유지한 이유도 명시한다. -- 승인 판단은 객관적 기준(섹션 완성도, 형식 준수, 범위 명확성)을 우선으로 한다. diff --git a/.github/prompts/review-implementation.prompt.md b/.github/prompts/review-implementation.prompt.md deleted file mode 100644 index 8876d15..0000000 --- a/.github/prompts/review-implementation.prompt.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -name: "review-implementation" -description: "Review and validate SDLC Implementation document for consistency, completeness, and readiness for approval" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/4_implementation.md" -agent: "agent" ---- -SDLC Implementation 문서를 체계적으로 검토하고, 승인 가능한 상태인지 판단한다. - -목표: -- `4_implementation.md` 파일의 일관성 확인 (태스크/변경 파일/완료 조건 간 중복 및 충돌) -- 기술적 오류, 잘못된 표현, 명확하지 않은 문구 식별 -- AI agent에게 할당된 플레이스홀더(`{{...}}`) 중 판단/결정 가능한 항목 처리 -- 플레이스홀더 중 사용자 결정이 정말 필요한 항목만 남겼는지 확인 -- 최종 승인 가능 상태 판단 - ---- - -## 검토 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 문서 경로 또는 CYCLE_ID에서 `4_implementation.md` 파일 위치를 확정한다. -- 파일이 없으면 입력값을 다시 확인하도록 사용자에게 피드백하고 중단한다. -- `3_design.md`도 함께 읽어 인계 내용의 정합성 확인에 사용한다. - -### 2. Design 인계 정합성 검토 - -`# 1. Design 인계 요약`이 `3_design.md`의 확정 내용과 일치하는지 확인한다. - -- 태스크 목록(T-N 제목, 변경 대상)이 Design `# 1`/`# 3`과 내용/수량이 일치하는가 -- 이월된 오픈 질문이 Design `# 6`의 `Deferred` 항목과 대응하는가 -- `# 2` 태스크별 구현 방법의 변경 대상이 Design `# 3`의 변경 대상과 일치하는가 - -### 3. 일관성 검토 (모든 섹션 대상) - -- **태스크 번호 연속성**: `# 1`, `# 2`, `# 3`의 T-N 번호가 누락 없이 연속이고 일치하는가 -- **변경 파일 정합성**: `# 2` 태스크별 변경 대상이 `# 3` 변경 파일 목록에 빠짐없이 포함되어 있는가 -- **완료 조건 측정 가능성**: `# 2` 각 태스크의 완료 조건(DoD)이 구체적이고 측정 가능한가 ("구현 완료"처럼 모호한 표현 금지) -- **숫자 연속성**: R-N, IA-N, OQ-N 번호가 누락 없이 연속인지 확인 - -### 4. 표현 검토 (모든 텍스트) - -- **문법**: 문장 구조, 주술 호응, 시제 일관성 -- **명확성**: "적절히", "대략", "가능하면" 같은 모호한 표현 식별 -- **작성 수준**: 기술 문서 기준의 형식적 톤 유지. 비공식 표현 제거 -- **오타**: 한글 띄어쓰기, 숫자 오류, 테이블 형식 검증 - -### 5. 플레이스홀더 처리 - -모든 `{{...}}` 플레이스홀더를 나열하고 각 항목의 의도를 파악한다. - -AI agent가 채울 수 있는 항목: -- `{{..._DECISION:...}}` 형태 — 문서 내 다른 섹션이나 Design 내용으로 추론 가능한지 확인 -- 변경 파일 유형(`IMP_FILE_TYPE_N`), 관련 태스크(`IMP_FILE_TASK_N`) 등 구조적으로 추론 가능한 항목 - -사용자 결정이 필요한 항목 (플레이스홀더 유지): -- 태스크 담당자(`IMP_TASK_OWNER_N`) -- Freeze 확정 담당자(`CONFIRMED_BY`) - -각 항목에 대해 아래 중 하나를 판단한다: -- **채울 수 있음**: 문서 내 맥락, Design 내용, 저장소 구조로 합리적 추론 가능 → 실제 내용으로 치환 -- **판단 불가능**: 사용자/승인자 결정, 외부 확인, 책임자 지정 필요 → 플레이스홀더 유지하되 명확성 강화 - -처리 결과를 별도 목록으로 보고한다. - -### 6. 섹션별 최소 검수 기준 - -| 섹션 | 최소 기준 | -|------|---------| -| `# 0 문서 상태` | 메타데이터 완성도 확인 (CREATED_AT_KST, DESIGN_PATH 채워졌는가) | -| `# 1 Design 인계 요약` | 태스크 최소 1개 이상, Design 태스크와 1:1 대응 여부 | -| `# 2 구현 계획` | 모든 T-N 태스크에 구현 방법, 변경 대상, 완료 조건이 있는가 | -| `# 3 변경 파일 목록` | `# 2`에서 언급된 변경 대상이 모두 목록에 포함되었는가, 파일 경로가 실제 경로인가 | -| `# 4 리스크/가정/오픈 질문` | 리스크 1개 이상, 가정 1개 이상, OQ `Open` 상태가 있으면 종료 조건이 명시되었는가 | -| `# 5 확인 체크` | 체크 항목이 구체적이고 측정 가능한가 | -| `# 7 사용자 결정 필요` | 플레이스홀더가 실제 `{{...}}` 형식인가 (단순 문장 아닌가) | -| `# 8 Freeze` | Handoff Decision과 Rationale이 채워졌는가 | - -### 7. 최종 승인 판단 - -- **승인 가능 (Ready for Verification)**: - - 모든 T-N 태스크에 구현 방법, 변경 대상, 완료 조건이 채워졌는가 - - 변경 파일 목록이 실제 파일 경로 기준으로 정확한가 - - `# 4` 오픈 질문에 `Open` 상태 항목이 없거나 모두 `Deferred` 처리 완료인가 - - 남은 플레이스홀더는 모두 정당한가 (사용자/승인자 결정이 정말 필요) - - Freeze 플래그가 준비되었는가 (`READY_FOR_VERIFICATION: true`로 변경 가능한가) -- **조건부 (Pending Minor Changes)**: - - 완료 조건(DoD) 일부가 모호하거나, 변경 파일 경로 확인 필요 - - 플레이스홀더 중 일부는 명확성을 위해 재작성 권장 -- **보류 (Hold)**: - - 태스크 구현 방법 누락, 변경 파일 목록 불완전, OQ `Open` 잔여 등 근본적 재검토 필요 - ---- - -## 응답 형식 - -- **검토 결과 요약** - - Design 인계 정합성 오류 (있으면 나열) - - 발견된 일관성 오류 (있으면 나열) - - 표현/문법 오류 (있으면 나열) - - 섹션별 완성도 (예: `# 2` T-2 완료 조건 모호) - -- **플레이스홀더 처리 결과** - - 채워진 항목 (예: `{{IMP_FILE_TYPE_2}}` → `수정` 로 치환) - - 유지된 항목 (예: `{{IMP_TASK_OWNER_1:TBD}}` → 담당자 지정 필요로 유지) - -- **수정 사항 목록** (적용된 변경) - -- **최종 판단** - - 승인 가능 / 조건부 / 보류 - - 근거 및 남은 작업 사항 diff --git a/.github/prompts/review-operation.prompt.md b/.github/prompts/review-operation.prompt.md deleted file mode 100644 index 809384d..0000000 --- a/.github/prompts/review-operation.prompt.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -name: "review-operation" -description: "Review and validate SDLC Operations document for consistency, completeness, and readiness for approval" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/7_operation.md" -agent: "agent" ---- -SDLC Operations 문서를 체계적으로 검토하고, 승인 가능한 상태인지 판단한다. - -목표: -- `7_operation.md` 파일의 일관성 확인 (모니터링/런북/환류 항목 간 충돌 및 누락) -- 기술적 오류, 잘못된 표현, 명확하지 않은 문구 식별 -- AI agent에게 할당된 플레이스홀더(`{{...}}`) 중 판단/결정 가능한 항목 처리 -- 플레이스홀더 중 사용자 결정이 정말 필요한 항목만 남겼는지 확인 -- 최종 승인 가능 상태 판단 - ---- - -## 검토 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 문서 경로 또는 CYCLE_ID에서 `7_operation.md` 파일 위치를 확정한다. -- 파일이 없으면 입력값을 다시 확인하도록 사용자에게 피드백하고 중단한다. -- `6_release.md`도 함께 읽어 인계 내용 정합성 확인에 사용한다. - -### 2. 인계 정합성 검토 - -- 배포 결과 요약이 Release `# 2`/`# 4`의 내용과 일치하는가 -- 이월된 오픈 질문이 Release `# 5`의 `Deferred` 항목과 대응하는가 -- 런북의 장애 대응 절차가 Release `# 3`의 롤백 계획과 연결되는가 - -### 3. 일관성 검토 (모든 섹션 대상) - -- **모니터링 실현 가능성**: `# 2` 모니터링 항목의 임계값이 수치화되었는가 ("오류가 없어야 한다" 대신 "5xx 오류율 1% 이하" 등) -- **런북 실행 가능성**: `# 3` 절차가 실제 운영자가 따를 수 있을 만큼 구체적인가 -- **에스컬레이션 일관성**: 에스컬레이션 경로가 실제 연락 가능한 대상인가 -- **숫자 연속성**: R-N, OQ-N 번호가 누락 없이 연속인지 확인 - -### 4. 표현 검토 (모든 텍스트) - -- **문법**: 문장 구조, 주술 호응, 시제 일관성 -- **명확성**: "문제가 생기면", "필요할 때" 같은 모호한 표현 식별 -- **작성 수준**: 기술 문서 기준의 형식적 톤 유지 -- **오타**: 한글 띄어쓰기, 숫자 오류, 테이블 형식 검증 - -### 5. 플레이스홀더 처리 - -모든 `{{...}}` 플레이스홀더를 나열하고 각 항목의 의도를 파악한다. - -AI agent가 채울 수 있는 항목: -- `{{..._DECISION:...}}` 형태 — 문서 내 다른 섹션이나 Release 내용으로 추론 가능한지 확인 -- 모니터링 확인 방법(`OPS_MONITOR_METHOD_N`), 장애 대응 첫 단계 등 구조적으로 추론 가능한 항목 - -사용자 결정이 필요한 항목 (플레이스홀더 유지): -- 모니터링 담당자(`OPS_MONITOR_OWNER`) -- 에스컬레이션 연락처(`OPS_ESCALATION_1`) -- Freeze 확정 담당자(`CONFIRMED_BY`) - -각 항목에 대해 아래 중 하나를 판단한다: -- **채울 수 있음**: 문서 내 맥락, Release 내용으로 합리적 추론 가능 → 실제 내용으로 치환 -- **판단 불가능**: 실제 운영 정보, 담당자 지정 필요 → 플레이스홀더 유지하되 명확성 강화 - -처리 결과를 별도 목록으로 보고한다. - -### 6. 섹션별 최소 검수 기준 - -| 섹션 | 최소 기준 | -|------|---------| -| `# 0 문서 상태` | 메타데이터 완성도 확인 (CREATED_AT_KST, REL_PATH 채워졌는가) | -| `# 1 Release 인계 요약` | 배포 환경과 스모크 테스트 결과가 명시되었는가 | -| `# 2 운영 모니터링` | 모니터링 항목 최소 1개 이상, 각 항목에 임계값과 대응 방안이 있는가 | -| `# 3 런북` | 정상 운영 절차 1단계 이상, 장애 대응 절차 1단계 이상, 에스컬레이션 경로가 있는가 | -| `# 5 리스크/오픈 질문` | OQ `Open` 상태가 있으면 종료 조건이 명시되었는가 | -| `# 6 다음 Discovery 환류` | "없음"이거나 구체적인 인사이트/개선 사항이 기록되었는가 | -| `# 7 확인 체크` | 체크 항목이 구체적이고 측정 가능한가 | -| `# 9 사용자 결정 필요` | 플레이스홀더가 실제 `{{...}}` 형식인가 | -| `# 10 Freeze` | Handoff Decision과 Rationale이 채워졌는가 | - -### 7. 최종 승인 판단 - -- **승인 가능 (SDLC 주기 완료)**: - - 모니터링 항목에 임계값과 대응 방안이 모두 명시되었는가 - - 런북(정상 운영/장애 대응/에스컬레이션)이 완비되었는가 - - `# 5` 오픈 질문에 `Open` 상태 항목이 없거나 모두 `Deferred` 처리 완료인가 - - `# 6` 다음 Discovery 환류 항목이 작성되었거나 "없음"으로 명시되었는가 - - Freeze 플래그가 준비되었는가 (`SDLC_CYCLE_COMPLETE: true`로 변경 가능한가) -- **조건부 (Pending Minor Changes)**: - - 일부 모니터링 임계값이 모호하거나, 런북 절차 보완 필요 -- **보류 (Hold)**: - - 모니터링 항목 없음, 장애 대응 절차 없음, 에스컬레이션 경로 없음 등 근본적 재검토 필요 - ---- - -## 응답 형식 - -- **검토 결과 요약** - - Release 인계 정합성 오류 (있으면 나열) - - 발견된 일관성 오류 (있으면 나열) - - 표현/문법 오류 (있으면 나열) - - 섹션별 완성도 (예: `# 2` 모니터링 임계값 미수치화) - -- **플레이스홀더 처리 결과** - - 채워진 항목 (예: `{{OPS_MONITOR_METHOD_1}}` → `GitHub 저장소 오류 로그 확인` 로 치환) - - 유지된 항목 (예: `{{OPS_MONITOR_OWNER:TBD}}` → 담당자 지정 필요로 유지) - -- **수정 사항 목록** (적용된 변경) - -- **최종 판단** - - 승인 가능 / 조건부 / 보류 - - 근거 및 남은 작업 사항 diff --git a/.github/prompts/review-planning.prompt.md b/.github/prompts/review-planning.prompt.md deleted file mode 100644 index ca89bff..0000000 --- a/.github/prompts/review-planning.prompt.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -name: "review-planning" -description: "Review and validate SDLC Planning document for consistency, completeness, and readiness for approval" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/2_planning.md" -agent: "agent" ---- -SDLC Planning 문서를 체계적으로 검토하고, 승인 가능한 상태인지 판단한다. - -목표: -- `2_planning.md` 파일의 일관성 확인 (태스크/요구사항/범위 간 중복 및 충돌) -- 기술적 오류, 잘못된 표현, 명확하지 않은 문구 식별 -- AI agent에게 할당된 플레이스홀더(`{{...}}`) 중 판단/결정 가능한 항목 처리 -- 플레이스홀더 중 사용자 결정이 정말 필요한 항목만 남겼는지 확인 -- 최종 승인 가능 상태 판단 - ---- - -## 검토 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 문서 경로 또는 CYCLE_ID에서 `2_planning.md` 파일 위치를 확정한다. -- 파일이 없으면 입력값을 다시 확인하도록 사용자에게 피드백하고 중단한다. -- `1_discovery.md`도 함께 읽어 인계 내용의 정합성 확인에 사용한다. - -### 2. Discovery 인계 정합성 검토 - -`# 1. Discovery 인계 요약`이 `1_discovery.md`의 확정 내용과 일치하는지 확인한다. - -- FR/NFR 목록이 Discovery `# 5`와 내용/수량이 일치하는가 -- In Scope / Out of Scope 경계가 Discovery와 충돌하지 않는가 -- 이월된 오픈 질문이 Discovery `# 6`의 `Deferred` 항목과 대응하는가 - -### 3. 일관성 검토 (모든 섹션 대상) - -- **용어**: 태스크 제목, 요구사항 ID(FR-N, T-N, M-N), 담당자 표기가 섹션 간 일치하는가 -- **태스크 참조**: `# 2` 태스크 분해 테이블의 T-N 번호가 `# 3` 공수 추정, `# 4` 일정 계획, `# 5` 의존성과 연속·일치하는가 -- **성공 기준 연결**: `# 6` 검증 계획의 기준(S-N)이 Discovery `# 7`과 대응하는가 -- **숫자 연속성**: T-N, M-N, OQ-N, R-N 번호가 누락 없이 연속인지 확인 - -### 4. 표현 검토 (모든 텍스트) - -- **문법**: 문장 구조, 주술 호응, 시제 일관성 -- **명확성**: "적절히", "대략", "가능하면" 같은 모호한 표현 식별 -- **작성 수준**: 기술 문서 기준의 형식적 톤 유지. 비공식 표현 제거 -- **오타**: 한글 띄어쓰기, 숫자 오류, 테이블 형식 검증 - -### 5. 플레이스홀더 처리 - -모든 `{{...}}` 플레이스홀더를 나열하고 각 항목의 의도를 파악한다. - -AI agent가 채울 수 있는 항목: -- `{{..._DECISION:...}}` 형태 — 문서 내 다른 섹션이나 Discovery 내용으로 추론 가능한지 확인 -- 태스크 유형(`TASK_TYPE_N`), 참조 요구사항(`TASK_REF_N`), 의존 관계(`TASK_DEP_N`) 등 구조적으로 추론 가능한 항목 - -사용자 결정이 필요한 항목 (플레이스홀더 유지): -- 태스크 담당자(`TASK_OWNER_N`) -- 마일스톤 목표 날짜(`MILESTONE_N_DATE`) -- 이터레이션 기간(`ITERATION_N_PERIOD`) -- 검증 담당자(`VERIFY_OWNER_N`) -- Freeze 확정 담당자(`CONFIRMED_BY`) - -각 항목에 대해 아래 중 하나를 판단한다: -- **채울 수 있음**: 문서 내 맥락, Discovery 내용, 저장소 구조로 합리적 추론 가능 → 실제 내용으로 치환 -- **판단 불가능**: 사용자/승인자 결정, 외부 데이터, 책임자 지정 필요 → 플레이스홀더 유지하되 명확성 강화 - -처리 결과를 별도 목록으로 보고한다. - -### 6. 섹션별 최소 검수 기준 - -| 섹션 | 최소 기준 | -|------|---------| -| `# 0 문서 상태` | 메타데이터 완성도 확인 (CREATED_AT_KST, DISCOVERY_PATH 채워졌는가) | -| `# 1 Discovery 인계 요약` | FR 2개 이상, NFR 1개 이상, In/Out Scope 명시 여부 | -| `# 2 작업 분해` | 태스크 최소 2개 이상, 각 태스크에 DoD가 있는가 | -| `# 3 공수 추정` | 모든 태스크에 추정 공수와 단위가 있는가, 총 공수와 신뢰도가 명시되었는가 | -| `# 4 일정 계획` | 마일스톤 최소 1개 이상, 이터레이션 단위가 정의되었는가 | -| `# 5 의존성 및 제약` | 태스크 간 의존성이 `# 2`와 일치하는가 | -| `# 6 검증 계획` | Discovery 성공 기준(S-N)과 연결된 검증 방법 초안이 있는가 | -| `# 7 리스크/가정/오픈 질문` | 항목이 적절한가(리스크 1개 이상, 가정 1개 이상), 오픈 질문은 정말 결정 필요인가 | -| `# 8 확인 체크` | 체크 항목이 구체적이고 측정 가능한가 | -| `# 10 사용자 결정 필요` | 플레이스홀더가 실제 `{{...}}` 형식인가 (단순 문장 아닌가) | -| `# 11 Freeze` | Handoff Decision과 Rationale이 채워졌는가 | - -### 7. 최종 승인 판단 - -- **승인 가능 (Ready for Design)**: - - 모든 일관성 오류가 해소되었는가 - - 명확하지 않은 표현이 제거되었는가 - - 남은 플레이스홀더는 모두 정당한가 (사용자/승인자 결정이 정말 필요) - - 모든 요구 섹션이 채워졌는가 - - Freeze 플래그가 준비되었는가 (`READY_FOR_DESIGN: true`로 변경 가능한가) -- **조건부 (Pending Minor Changes)**: - - 일부 표현/수치만 수정하면 가능 - - 플레이스홀더 중 일부는 명확성을 위해 재작성 권장 -- **보류 (Hold)**: - - 태스크-요구사항 연결 누락, 공수 추정 근거 부재, 범위 재정의 등 근본적 재검토 필요 - ---- - -## 응답 형식 - -- **검토 결과 요약** - - Discovery 인계 정합성 오류 (있으면 나열) - - 발견된 일관성 오류 (있으면 나열) - - 표현/문법 오류 (있으면 나열) - - 섹션별 완성도 (예: `# 3` 공수 추정 — T-2 추정값 누락) - -- **플레이스홀더 처리 결과** - - 채워진 항목 (예: `{{TASK_DEP_2}}` → `T-1` 로 치환) - - 유지된 항목 (예: `{{TASK_OWNER_1:TBD}}` → 담당자 지정 필요로 유지) - -- **수정 사항 목록** (적용된 변경) - -- **최종 판단** - - 승인 가능 / 조건부 / 보류 - - 근거 및 남은 작업 사항 - ---- - -## 중요 규칙 - -- 문서 내용을 변경하는 경우 반드시 명확히 표기한다. -- AI agent 판단으로 치환한 항목은 합리적 근거를 함께 설명한다. -- 의도적으로 플레이스홀더를 유지한 이유도 명시한다. -- 승인 판단은 객관적 기준(섹션 완성도, 형식 준수, Discovery 정합성)을 우선으로 한다. -- Discovery와의 정합성 확인은 `1_discovery.md`를 직접 읽어서 수행한다. 기억이나 추론에 의존하지 않는다. diff --git a/.github/prompts/review-release.prompt.md b/.github/prompts/review-release.prompt.md deleted file mode 100644 index 34a15db..0000000 --- a/.github/prompts/review-release.prompt.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -name: "review-release" -description: "Review and validate SDLC Release document for consistency, completeness, and readiness for approval" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/6_release.md" -agent: "agent" ---- -SDLC Release 문서를 체계적으로 검토하고, 승인 가능한 상태인지 판단한다. - -목표: -- `6_release.md` 파일의 일관성 확인 (배포 준비/롤백/스모크 테스트 간 중복 및 충돌) -- 기술적 오류, 잘못된 표현, 명확하지 않은 문구 식별 -- AI agent에게 할당된 플레이스홀더(`{{...}}`) 중 판단/결정 가능한 항목 처리 -- 플레이스홀더 중 사용자 결정이 정말 필요한 항목만 남겼는지 확인 -- 최종 승인 가능 상태 판단 - ---- - -## 검토 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 문서 경로 또는 CYCLE_ID에서 `6_release.md` 파일 위치를 확정한다. -- 파일이 없으면 입력값을 다시 확인하도록 사용자에게 피드백하고 중단한다. -- `5_verification.md`와 `4_implementation.md`도 함께 읽어 인계 내용 정합성 확인에 사용한다. - -### 2. 인계 정합성 검토 - -- 검증 결과 요약이 Verification `# 3` 결과와 일치하는가 -- 이월된 오픈 질문이 Verification `# 5`의 `Deferred` 항목과 대응하는가 -- 스모크 테스트 항목이 핵심 FR과 연결되는가 - -### 3. 일관성 검토 (모든 섹션 대상) - -- **배포 순서 일관성**: `# 2` 배포 순서가 Implementation `# 3` 변경 파일 목록과 연결되는가 -- **롤백 실현 가능성**: `# 3` 롤백 절차가 실제 배포 방식에 맞게 기술되었는가 (git 기반이면 커밋/브랜치/태그 참조, CI/CD 기반이면 파이프라인 롤백 방법 등) -- **스모크 테스트 충족성**: `# 4` 스모크 테스트가 핵심 기능을 최소한 커버하는가 -- **숫자 연속성**: R-N, OQ-N 번호가 누락 없이 연속인지 확인 - -### 4. 표현 검토 (모든 텍스트) - -- **문법**: 문장 구조, 주술 호응, 시제 일관성 -- **명확성**: "필요 시", "대략", "적절히" 같은 모호한 표현 식별 -- **작성 수준**: 기술 문서 기준의 형식적 톤 유지 -- **오타**: 한글 띄어쓰기, 숫자 오류, 테이블 형식 검증 - -### 5. 플레이스홀더 처리 - -모든 `{{...}}` 플레이스홀더를 나열하고 각 항목의 의도를 파악한다. - -AI agent가 채울 수 있는 항목: -- `{{..._DECISION:...}}` 형태 — 문서 내 다른 섹션이나 저장소 구조로 추론 가능한지 확인 -- 배포 방식(`REL_DEPLOY_METHOD`), 스모크 테스트 방법(`REL_SMOKE_METHOD_N`) 등 저장소 구조 기반으로 추론 가능한 항목 - -사용자 결정이 필요한 항목 (플레이스홀더 유지): -- 롤백 담당자(`REL_ROLLBACK_OWNER`) -- 배포 대상 환경(`REL_TARGET_ENV`): 실제 운영 환경 정보 -- Freeze 확정 담당자(`CONFIRMED_BY`) - -각 항목에 대해 아래 중 하나를 판단한다: -- **채울 수 있음**: 저장소 구조, 문서 내 맥락으로 합리적 추론 가능 → 실제 내용으로 치환 -- **판단 불가능**: 실제 환경 정보, 담당자 지정 필요 → 플레이스홀더 유지하되 명확성 강화 - -처리 결과를 별도 목록으로 보고한다. - -### 6. 섹션별 최소 검수 기준 - -| 섹션 | 최소 기준 | -|------|---------| -| `# 0 문서 상태` | 메타데이터 완성도 확인 (CREATED_AT_KST, VER_PATH 채워졌는가) | -| `# 1 Verification 인계 요약` | 검증 결과 요약(통과 수/전체 수)이 있는가 | -| `# 2 배포 준비` | 배포 환경, 방식, 도구가 명시되었는가, 배포 순서가 1단계 이상인가 | -| `# 3 롤백 계획` | 롤백 조건 1개 이상, 롤백 절차 1단계 이상, 롤백 담당자가 있는가 | -| `# 4 배포 후 확인` | 스모크 테스트 항목 1개 이상, 각 항목에 확인 방법과 성공 기준이 있는가 | -| `# 5 리스크/오픈 질문` | OQ `Open` 상태가 있으면 종료 조건이 명시되었는가 | -| `# 6 확인 체크` | 체크 항목이 구체적이고 측정 가능한가 | -| `# 8 사용자 결정 필요` | 플레이스홀더가 실제 `{{...}}` 형식인가 | -| `# 9 Freeze` | Handoff Decision과 Rationale이 채워졌는가 | - -### 7. 최종 승인 판단 - -- **승인 가능 (Ready for Operations)**: - - 배포 준비(환경/방식/순서)가 명확히 정의되었는가 - - 롤백 조건, 절차, 담당자가 모두 명시되었는가 - - 스모크 테스트 항목이 최소 1개 이상이고 성공 기준이 구체적인가 - - `# 5` 오픈 질문에 `Open` 상태 항목이 없거나 모두 `Deferred` 처리 완료인가 - - Freeze 플래그가 준비되었는가 (`READY_FOR_OPERATIONS: true`로 변경 가능한가) -- **조건부 (Pending Minor Changes)**: - - 일부 배포 방식 설명이 모호하거나 스모크 테스트 성공 기준 보완 필요 -- **보류 (Hold)**: - - 롤백 계획 없음, 배포 순서 불명확, 스모크 테스트 항목 누락 등 근본적 재검토 필요 - ---- - -## 응답 형식 - -- **검토 결과 요약** - - Verification 인계 정합성 오류 (있으면 나열) - - 발견된 일관성 오류 (있으면 나열) - - 표현/문법 오류 (있으면 나열) - - 섹션별 완성도 (예: `# 3` 롤백 담당자 미지정) - -- **플레이스홀더 처리 결과** - - 채워진 항목 (예: `{{REL_DEPLOY_METHOD}}` → `git push (자동 배포 없음)` 로 치환) - - 유지된 항목 (예: `{{REL_ROLLBACK_OWNER:TBD}}` → 담당자 지정 필요로 유지) - -- **수정 사항 목록** (적용된 변경) - -- **최종 판단** - - 승인 가능 / 조건부 / 보류 - - 근거 및 남은 작업 사항 diff --git a/.github/prompts/review-verification.prompt.md b/.github/prompts/review-verification.prompt.md deleted file mode 100644 index e74d2be..0000000 --- a/.github/prompts/review-verification.prompt.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -name: "review-verification" -description: "Review and validate SDLC Verification document for consistency, completeness, and readiness for approval" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/5_verification.md" -agent: "agent" ---- -SDLC Verification 문서를 체계적으로 검토하고, 승인 가능한 상태인지 판단한다. - -목표: -- `5_verification.md` 파일의 일관성 확인 (검증 항목/성공 기준/결과 간 중복 및 충돌) -- 기술적 오류, 잘못된 표현, 명확하지 않은 문구 식별 -- AI agent에게 할당된 플레이스홀더(`{{...}}`) 중 판단/결정 가능한 항목 처리 -- 플레이스홀더 중 사용자 결정이 정말 필요한 항목만 남겼는지 확인 -- 최종 승인 가능 상태 판단 - ---- - -## 검토 절차 - -### 1. 입력 해석 - -- 사용자가 제공한 문서 경로 또는 CYCLE_ID에서 `5_verification.md` 파일 위치를 확정한다. -- 파일이 없으면 입력값을 다시 확인하도록 사용자에게 피드백하고 중단한다. -- `4_implementation.md`와 `1_discovery.md`도 함께 읽어 인계 내용 및 성공 기준 정합성 확인에 사용한다. - -### 2. 인계 정합성 검토 - -- 구현 완료 태스크 목록이 Implementation `# 1`/`# 2`와 내용/수량이 일치하는가 -- 검증 항목(VC-N)이 Discovery `# 7` 성공 기준(S-N) 및 FR과 연결되어 있는가 (`# 2` 성공 기준 연결 섹션 확인) -- 이월된 오픈 질문이 Implementation `# 4`의 `Deferred` 항목과 대응하는가 - -### 3. 일관성 검토 (모든 섹션 대상) - -- **VC 번호 연속성**: `# 2` 검증 항목과 `# 3` 검증 결과의 VC-N 번호가 누락 없이 연속이고 일치하는가 -- **성공 기준 측정 가능성**: `# 2` 각 VC 항목의 성공 기준이 구체적이고 측정 가능한가 ("정상 동작"처럼 모호한 표현 금지) -- **검증 결과 정합성**: `# 3` 통과/실패 집계가 실제 결과 테이블과 일치하는가 -- **결함 연결성**: `# 4` BUG 항목이 검증 항목(VC-N)과 연결되는지 확인 -- **숫자 연속성**: R-N, OQ-N, BUG-N 번호가 누락 없이 연속인지 확인 - -### 4. 표현 검토 (모든 텍스트) - -- **문법**: 문장 구조, 주술 호응, 시제 일관성 -- **명확성**: "정상적으로", "충분히", "대략" 같은 모호한 표현 식별 -- **작성 수준**: 기술 문서 기준의 형식적 톤 유지. 비공식 표현 제거 -- **오타**: 한글 띄어쓰기, 숫자 오류, 테이블 형식 검증 - -### 5. 플레이스홀더 처리 - -모든 `{{...}}` 플레이스홀더를 나열하고 각 항목의 의도를 파악한다. - -AI agent가 채울 수 있는 항목: -- `{{..._DECISION:...}}` 형태 — 문서 내 다른 섹션이나 Discovery/Implementation 내용으로 추론 가능한지 확인 -- 검증 방법(`VER_METHOD_N`), 결함 심각도(`BUG_SEVERITY_N`) 등 구조적으로 추론 가능한 항목 - -사용자 결정이 필요한 항목 (플레이스홀더 유지): -- 검증 담당자(`VER_OWNER_N`) -- 결함 재작업 내용(`BUG_FIX_N`): 실제 구현 변경 필요 -- Freeze 확정 담당자(`CONFIRMED_BY`) - -각 항목에 대해 아래 중 하나를 판단한다: -- **채울 수 있음**: 문서 내 맥락, Discovery/Implementation 내용으로 합리적 추론 가능 → 실제 내용으로 치환 -- **판단 불가능**: 사용자/승인자 결정, 실제 검증 수행 필요 → 플레이스홀더 유지하되 명확성 강화 - -처리 결과를 별도 목록으로 보고한다. - -### 6. 섹션별 최소 검수 기준 - -| 섹션 | 최소 기준 | -|------|---------| -| `# 0 문서 상태` | 메타데이터 완성도 확인 (CREATED_AT_KST, IMP_PATH 채워졌는가) | -| `# 1 Implementation 인계 요약` | 태스크 최소 1개 이상, Implementation 태스크와 1:1 대응 여부 | -| `# 2 검증 계획` | VC 최소 2개 이상, 각 VC에 검증 방법과 측정 가능한 성공 기준이 있는가 | -| `# 2 성공 기준 연결` | Discovery S-N이 하나 이상의 VC-N과 연결되었는가 | -| `# 3 검증 결과` | VC-N과 결과 테이블의 행 수가 일치하는가, 집계 숫자가 맞는가 | -| `# 4 결함` | BUG `Open` 상태가 있으면 재작업 내용이 명시되었는가 | -| `# 5 리스크/오픈 질문` | OQ `Open` 상태가 있으면 종료 조건이 명시되었는가 | -| `# 6 확인 체크` | 체크 항목이 구체적이고 측정 가능한가 | -| `# 8 사용자 결정 필요` | 플레이스홀더가 실제 `{{...}}` 형식인가 (단순 문장 아닌가) | -| `# 9 Freeze` | Handoff Decision과 Rationale이 채워졌는가 | - -### 7. 최종 승인 판단 - -- **승인 가능 (Ready for Release)**: - - 모든 VC 항목이 "통과" 상태인가 - - BUG `Open` 상태 항목이 없는가 (Deferred는 근거와 함께 허용) - - Discovery 성공 기준(S-N)이 모두 VC와 연결되어 검증되었는가 - - `# 5` 오픈 질문에 `Open` 상태 항목이 없거나 모두 `Deferred` 처리 완료인가 - - 남은 플레이스홀더는 모두 정당한가 (사용자/승인자 결정이 정말 필요) - - Freeze 플래그가 준비되었는가 (`READY_FOR_RELEASE: true`로 변경 가능한가) -- **조건부 (Pending Minor Changes)**: - - 일부 VC 항목이 아직 "미완료"이나 곧 완료 예정 - - BUG 항목 심각도가 낮고 재작업 계획이 명확한 경우 -- **보류 (Hold)**: - - VC 항목에 "실패" 또는 "블로킹" 상태 존재, BUG `Open` 잔여, S-N 연결 누락 등 근본적 재검토 필요 - ---- - -## 응답 형식 - -- **검토 결과 요약** - - Implementation 인계 정합성 오류 (있으면 나열) - - 발견된 일관성 오류 (있으면 나열) - - 표현/문법 오류 (있으면 나열) - - 섹션별 완성도 (예: `# 2` VC-3 성공 기준 모호) - -- **플레이스홀더 처리 결과** - - 채워진 항목 (예: `{{VER_METHOD_2}}` → `자동` 로 치환) - - 유지된 항목 (예: `{{VER_OWNER_1:TBD}}` → 검증 담당자 지정 필요로 유지) - -- **수정 사항 목록** (적용된 변경) - -- **최종 판단** - - 승인 가능 / 조건부 / 보류 - - 근거 및 남은 작업 사항 diff --git a/.github/prompts/run-implementation.prompt.md b/.github/prompts/run-implementation.prompt.md deleted file mode 100644 index 4c0511b..0000000 --- a/.github/prompts/run-implementation.prompt.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -name: "run-implementation" -description: "Execute implementation tasks from 4_implementation.md and record results" -argument-hint: "예: sdlc-001 또는 docs/sdlc/sdlc-001_20260417_stage-pilot/4_implementation.md" -agent: "agent" ---- -`4_implementation.md`에 정의된 태스크를 순서대로 실제 구현하고, 완료 후 문서의 확인체크(`#5`)와 파일처리결과(`#6`)를 자동으로 채운다. - -목표: -- `#2 구현 계획`에 기술된 순서대로 태스크를 실행한다. -- 각 태스크 완료 후 DoD를 자체 확인하고, 미충족 시 즉시 보고한다. -- 모든 태스크 완료 후 `#3 변경 파일 목록`을 실제 결과로 갱신하고, `#5`와 `#6`을 채운다. -- 문서 상태는 `review`로 변경한다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- CYCLE_ID(예: `sdlc-001`)가 주어지면 `docs/sdlc/` 아래에서 해당 패턴으로 시작하는 폴더를 찾아 `4_implementation.md` 경로를 확정한다. -- 파일 경로가 직접 주어지면 그대로 사용한다. -- 파일이 없으면 사용자에게 경로를 재확인하도록 요청하고 중단한다. - -### 2. 사전 게이트 확인 - -아래 조건을 모두 충족해야 구현을 시작한다. 미충족 시 이유를 보고하고 중단한다. - -| 항목 | 기준 | -|------|------| -| 문서 상태 | `draft` 또는 `review`이어야 한다. `confirmed`이면 이미 완료된 구현임을 알린다. | -| `#2` 구현 계획 존재 | 구현 순서와 T-N 섹션이 모두 채워져 있어야 한다. 플레이스홀더가 남아 있으면 `draft-implementation`을 먼저 완성하도록 안내한다. | -| `#3` 변경 파일 목록 존재 | 최소 1개 이상의 파일 항목이 있어야 한다. | -| Design 인계 조건 | 참조 `3_design.md`가 `confirmed` 상태인지 확인한다. 아니면 경고만 출력하고 계속 진행한다. | - -### 3. 구현 실행 - -`#2 구현 계획`의 `구현 순서` 목록을 기준으로 태스크를 순서대로 실행한다. - -#### 태스크별 실행 규칙 - -각 T-N 태스크에 대해 아래 순서로 진행한다. - -1. **계획 읽기**: 해당 T-N 섹션의 `구현 방법`, `변경 대상`, `완료 조건`, `주의사항`을 읽는다. -2. **현황 파악**: 변경 대상 파일이 이미 존재하는지 확인하고, 존재하면 관련 코드를 읽어 맥락을 파악한다. -3. **구현**: 파일 생성, 수정, 삭제를 수행한다. 기존 코드의 스타일과 패턴을 따른다. -4. **DoD 자체 확인**: `완료 조건`에 기술된 각 항목을 하나씩 점검한다. - - 충족: 다음 태스크로 진행한다. - - 미충족: 보고하고 즉시 재작업한다. 재작업 후에도 미충족이면 태스크를 블로킹으로 표시하고 사용자에게 결정을 요청한다. - -#### 실행 중 주의사항 - -- 각 태스크의 `주의사항`을 반드시 읽고 구현에 반영한다. -- `#4 리스크`에 기록된 리스크 완화 방안을 구현 중에 적용한다. -- `#1 이월된 오픈 질문` 항목이 있으면 구현 중 해당 결정을 내려 기록한다. -- 구현 중 새로 발견된 문제가 `#3 변경 파일 목록`에 없는 파일을 변경해야 하는 경우, 변경 전 그 이유를 간단히 기록한다. - -### 4. 완료 후 문서 갱신 - -모든 태스크 완료 후 아래 항목을 문서에 반영한다. 이 목록 외 내용은 수정하지 않는다. - -#### `#3 변경 파일 목록` 갱신 - -실제로 생성/수정/삭제된 파일을 기준으로 목록을 갱신한다. -- 계획에 있었으나 실제로 변경되지 않은 파일은 `비고`에 `미변경 - <이유>`를 기록하고 유지한다. -- 계획에 없었으나 실제로 변경된 파일은 새 행으로 추가하고 `비고`에 `계획 외 변경`을 기록한다. - -#### `#5 Verification으로 넘기기 전 확인 체크` 갱신 - -각 체크 항목을 실제 결과에 따라 `[x]`(완료) 또는 `[ ]`(미완료)로 업데이트한다. 블로킹 태스크가 있으면 해당 항목을 `[ ]`로 남기고 비고를 추가한다. - -#### `#6 파일 처리 결과` 갱신 - -- `처리 결과`: `갱신` -- `생성 경로`: 경로 확인 후 기입 -- `마지막 갱신 시각(KST)`: 현재 시각으로 기입 - -#### `#0 문서 상태` 변경 - -- `상태`: `review`로 변경 -- `마지막 갱신 시각(KST)`: 현재 시각으로 변경 - -### 5. 결과 보고 - -구현이 끝나면 아래 항목을 포함한 보고서를 출력한다. - -- **실행 완료된 태스크 목록** (T-N, 완료 조건 충족 여부) -- **블로킹 태스크** (있는 경우): 원인 및 필요한 사용자 결정 사항 -- **계획 외 변경 파일** (있는 경우): 파일명과 이유 -- **다음 단계 안내**: 블로킹 없음 → `/review-implementation sdlc-001` 실행 권장 - ---- - -## 중요 규칙 - -- `4_implementation.md`의 `#2`와 `#3`을 구현의 유일한 기준으로 삼는다. 범위 밖 변경은 사용자 확인 없이 수행하지 않는다. -- 기존 코드를 삭제하거나 되돌리기 어려운 파괴적 변경은 수행 전 사용자에게 확인한다. -- DoD가 측정 불가능한 서술로 되어 있으면 가능한 근접한 방식으로 자체 평가하고, 평가 방식을 보고서에 명시한다. -- 구현 실행은 `draft` 또는 `review` 상태에서만 허용한다. diff --git a/.github/prompts/run-sdlc.prompt.md b/.github/prompts/run-sdlc.prompt.md deleted file mode 100644 index 770e282..0000000 --- a/.github/prompts/run-sdlc.prompt.md +++ /dev/null @@ -1,257 +0,0 @@ ---- -name: "run-sdlc" -description: "Run the full SDLC pipeline for a given cycle, automatically resuming from the first incomplete stage" -argument-hint: "예: sdlc-001 Justin" -agent: "agent" ---- -지정된 SDLC 주기의 전체 파이프라인을 순서대로 실행한다. - -인자: -- `sdlc-xyz`: SDLC 주기 ID (예: `sdlc-001`) -- `my-name`: 각 단계 승인자 이름 (예: `Justin`) - -목표: -- 지정된 SDLC 주기의 현재 진행 상태를 파악하고, 미완료 단계부터 순서대로 실행한다. -- 각 단계가 완료(`confirmed`)되면 다음 단계로 자동 진행한다. -- 사용자 판단이 필요한 경우 즉시 중단하고, 어떤 판단이 필요한지 명확하게 안내한다. - ---- - -## 실행 절차 - -### 1. 입력 해석 - -- 첫 번째 인자를 `CYCLE_ID`로 사용한다 (예: `sdlc-001`). -- 두 번째 인자를 `APPROVER_NAME`으로 사용한다 (예: `Justin`). -- `docs/sdlc/` 아래에서 `CYCLE_ID`로 시작하는 폴더를 찾는다. - - 폴더가 없으면 오류를 보고하고 중단한다. - - 폴더가 여러 개이면 가장 최근(날짜 순)을 사용하고 선택한 폴더 경로를 보고한다. -- 이후 단계에서 `SDLC_DIR = docs/sdlc/<일치하는 폴더>`로 참조한다. - -### 2. 현재 상태 파악 - -`SDLC_DIR/index.md`의 단계별 상태 테이블을 읽어 각 단계의 현재 상태를 확인한다. -파일이 없으면 각 문서 파일을 직접 읽어 `# 0. 문서 상태`의 `- 상태:` 줄에서 상태를 확인한다. - -확인 대상 단계와 해당 문서 파일: - -| 단계 | 문서 파일 | confirmed 조건 | -|------|-----------|----------------| -| Discovery | `1_discovery.md` | 상태 = `confirmed` 또는 `Ready for Planning: true` | -| Planning | `2_planning.md` | 상태 = `confirmed` 또는 `Ready for Design: true` | -| Design | `3_design.md` | 상태 = `confirmed` 또는 `Ready for Implementation: true` | -| Implementation | `4_implementation.md` | 상태 = `confirmed` 또는 `Ready for Verification: true` | -| Verification | `5_verification.md` | 상태 = `confirmed` 또는 `Ready for Release: true` | -| Release | `6_release.md` | 상태 = `confirmed` 또는 `Ready for Operations: true` | -| Operations | `7_operation.md` | 상태 = `confirmed` 또는 `SDLC 주기 완료: true` | - -### 3. 실행 시작 지점 결정 - -단계를 아래 순서로 순회하며 `confirmed`가 아닌 첫 번째 단계를 찾는다. - -1. Discovery -2. Planning -3. Design -4. Implementation -5. Verification -6. Release -7. Operations - -모든 단계가 `confirmed`이면 SDLC 주기가 완료되었음을 보고하고 종료한다. - -### 4. 단계별 실행 - -시작 지점부터 각 단계의 서브스텝을 아래 순서로 실행한다. -각 서브스텝 실행 후 결과를 확인하고, 블로킹 조건이 발생하면 즉시 중단한다. - -#### 4-1. Discovery 단계 (`1_discovery.md`) - -`1_discovery.md`의 상태에 따라 아래 서브스텝을 실행한다. - -| 현재 상태 | 실행할 서브스텝 | -|-----------|----------------| -| 파일 없음 | 오류 보고 후 중단 — Discovery 문서는 `/new-sdlc`로 먼저 생성해야 한다 | -| `draft` 또는 `review` | ① `review-discovery` → ② `confirm-discovery` | -| `confirmed` | 스킵 | - -- `review-discovery` 실행 시: 검토 결과가 **보류(Hold)**이면 → [블로킹 처리](#블로킹-처리) -- `confirm-discovery` 실행 시: `APPROVER_NAME`을 `Confirmed By` 값으로 사용한다. - 승인 불가 보고를 받으면 → [블로킹 처리](#블로킹-처리) - -#### 4-2. Planning 단계 (`2_planning.md`) - -`2_planning.md`의 상태에 따라 아래 서브스텝을 실행한다. - -| 현재 상태 | 실행할 서브스텝 | -|-----------|----------------| -| 파일 없음 | ① `draft-planning` → ② `review-planning` → ③ `confirm-planning` | -| `draft` | ① `review-planning` → ② `confirm-planning` | -| `review` | ① `confirm-planning` | -| `confirmed` | 스킵 | - -- `draft-planning` 실행 시: Discovery가 `confirmed` 상태인지 확인한다. 아니면 중단. -- `review-planning` 실행 시: {{TASK_OWNER_N}}는 copilot으로 자동으로 채우고, {{MILESTONE_N_DATE}}, {{ITERATION_N_PERIOD}}는 현재 날짜로 채운다. 검토 결과가 **보류(Hold)**이면 → [블로킹 처리](#블로킹-처리) -- `confirm-planning` 실행 시: `APPROVER_NAME`을 `Confirmed By` 값으로 사용한다. - 승인 불가 보고를 받으면 → [블로킹 처리](#블로킹-처리) - -#### 4-3. Design 단계 (`3_design.md`) - -`3_design.md`의 상태에 따라 아래 서브스텝을 실행한다. - -| 현재 상태 | 실행할 서브스텝 | -|-----------|----------------| -| 파일 없음 | ① `draft-design` → ② `review-design` → ③ `confirm-design` | -| `draft` | ① `review-design` → ② `confirm-design` | -| `review` | ① `confirm-design` | -| `confirmed` | 스킵 | - -- `draft-design` 실행 시: Planning이 `confirmed` 상태인지 확인한다. 아니면 중단. -- `review-design` 실행 시: 검토 결과가 **보류(Hold)**이면 → [블로킹 처리](#블로킹-처리) -- `confirm-design` 실행 시: `APPROVER_NAME`을 `Confirmed By` 값으로 사용한다. - 승인 불가 보고를 받으면 → [블로킹 처리](#블로킹-처리) - -#### 4-4. Implementation 단계 (`4_implementation.md`) - -`4_implementation.md`의 상태에 따라 아래 서브스텝을 실행한다. - -| 현재 상태 | 실행할 서브스텝 | -|-----------|----------------| -| 파일 없음 | ① `draft-implementation` → ② `run-implementation` → ③ `review-implementation` → ④ `confirm-implementation` | -| `draft` | ① `run-implementation` → ② `review-implementation` → ③ `confirm-implementation` | -| `review` | ① `review-implementation` → ② `confirm-implementation` | -| `confirmed` | 스킵 | - -- `draft-implementation` 실행 시: Design이 `confirmed` 상태인지 확인한다. 아니면 중단. -- `run-implementation` 실행 시: 블로킹 태스크가 발생하면 → [블로킹 처리](#블로킹-처리) -- `review-implementation` 실행 시: 검토 결과가 **보류(Hold)**이면 → [블로킹 처리](#블로킹-처리) -- `confirm-implementation` 실행 시: `APPROVER_NAME`을 `Confirmed By` 값으로 사용한다. - 승인 불가 보고를 받으면 → [블로킹 처리](#블로킹-처리) - -#### 4-5. Verification 단계 (`5_verification.md`) - -`5_verification.md`의 상태에 따라 아래 서브스텝을 실행한다. - -| 현재 상태 | 실행할 서브스텝 | -|-----------|----------------| -| 파일 없음 | ① `draft-verification` → ② `review-verification` → ③ `confirm-verification` | -| `draft` | ① `review-verification` → ② `confirm-verification` | -| `review` | ① `confirm-verification` | -| `confirmed` | 스킵 | - -- `draft-verification` 실행 시: Implementation이 `confirmed` 상태인지 확인한다. 아니면 중단. -- `review-verification` 실행 시: 검토 결과가 **보류(Hold)**이면 → [블로킹 처리](#블로킹-처리) -- `confirm-verification` 실행 시: `APPROVER_NAME`을 `Confirmed By` 값으로 사용한다. - 승인 불가 보고를 받으면 → [블로킹 처리](#블로킹-처리) - -#### 4-6. Release 단계 (`6_release.md`) - -`6_release.md`의 상태에 따라 아래 서브스텝을 실행한다. - -| 현재 상태 | 실행할 서브스텝 | -|-----------|----------------| -| 파일 없음 | ① `draft-release` → ② `review-release` → ③ `confirm-release` | -| `draft` | ① `review-release` → ② `confirm-release` | -| `review` | ① `confirm-release` | -| `confirmed` | 스킵 | - -- `draft-release` 실행 시: Verification이 `confirmed` 상태인지 확인한다. 아니면 중단. -- `review-release` 실행 시: 검토 결과가 **보류(Hold)**이면 → [블로킹 처리](#블로킹-처리) -- `confirm-release` 실행 시: `APPROVER_NAME`을 `Confirmed By` 값으로 사용한다. - 승인 불가 보고를 받으면 → [블로킹 처리](#블로킹-처리) - -#### 4-7. Operations 단계 (`7_operation.md`) - -`7_operation.md`의 상태에 따라 아래 서브스텝을 실행한다. - -| 현재 상태 | 실행할 서브스텝 | -|-----------|----------------| -| 파일 없음 | ① `draft-operation` → ② `review-operation` → ③ `confirm-operation` | -| `draft` | ① `review-operation` → ② `confirm-operation` | -| `review` | ① `confirm-operation` | -| `confirmed` | 스킵 | - -- `draft-operation` 실행 시: Release가 `confirmed` 상태인지 확인한다. 아니면 중단. -- `review-operation` 실행 시: 검토 결과가 **보류(Hold)**이면 → [블로킹 처리](#블로킹-처리) -- `confirm-operation` 실행 시: `APPROVER_NAME`을 `Confirmed By` 값으로 사용한다. - 승인 불가 보고를 받으면 → [블로킹 처리](#블로킹-처리) - ---- - -### 블로킹 처리 - -아래 상황 중 하나가 발생하면 즉시 실행을 중단하고 사용자에게 아래 정보를 제공한다. - -1. **review-* 결과가 보류(Hold)인 경우** - - 어느 단계의 review에서 보류가 발생했는지 - - 보류 이유 (review 결과에서 제시된 미충족 항목) - - 해결을 위해 필요한 사용자 조치 - -2. **confirm-* 결과가 승인 불가인 경우** - - 어느 단계의 confirm이 실패했는지 - - C 유형 미해소 플레이스홀더 목록 (해당 시) - - 미해소 오픈 질문 목록 (해당 시) - - 해결 방법 안내 (예: 문서에서 해당 항목을 직접 채운 후 `/run-sdlc ` 재실행) - -3. **run-implementation 실행 중 블로킹 태스크가 발생한 경우** - - 블로킹된 태스크 번호(T-N)와 원인 - - 사용자가 결정해야 할 사항 - - 해결 후 `/run-sdlc ` 재실행 안내 - -4. **Verification 단계가 미완료인 경우** - - Verification 문서의 현재 상태 - - 필요한 조치 안내 - ---- - -### 5. 완료 보고 - -전체 파이프라인이 완료되면(모든 단계 `confirmed`) 아래 내용을 포함한 완료 보고를 출력한다. - -- **완료된 주기**: `CYCLE_ID` -- **각 단계별 최종 상태** (표 형식) -- **이번 실행에서 처리된 단계 목록** -- **다음 Discovery 환류 항목**: Operations `# 6` 섹션의 내용 요약 (있는 경우) -- **다음 SDLC 주기 시작 안내**: `/new-sdlc <다음 이슈 내용>` 명령 안내 - ---- - -## 서브스텝 실행 방식 - -각 서브스텝은 해당 프롬프트 파일의 전체 절차를 그대로 실행한다. - -| 서브스텝 | 참조 프롬프트 | -|----------|--------------| -| `review-discovery` | `.github/prompts/review-discovery.prompt.md` | -| `confirm-discovery` | `.github/prompts/confirm-discovery.prompt.md` | -| `draft-planning` | `.github/prompts/draft-planning.prompt.md` | -| `review-planning` | `.github/prompts/review-planning.prompt.md` | -| `confirm-planning` | `.github/prompts/confirm-planning.prompt.md` | -| `draft-design` | `.github/prompts/draft-design.prompt.md` | -| `review-design` | `.github/prompts/review-design.prompt.md` | -| `confirm-design` | `.github/prompts/confirm-design.prompt.md` | -| `draft-implementation` | `.github/prompts/draft-implementation.prompt.md` | -| `run-implementation` | `.github/prompts/run-implementation.prompt.md` | -| `review-implementation` | `.github/prompts/review-implementation.prompt.md` | -| `confirm-implementation` | `.github/prompts/confirm-implementation.prompt.md` | -| `draft-verification` | `.github/prompts/draft-verification.prompt.md` | -| `review-verification` | `.github/prompts/review-verification.prompt.md` | -| `confirm-verification` | `.github/prompts/confirm-verification.prompt.md` | -| `draft-release` | `.github/prompts/draft-release.prompt.md` | -| `review-release` | `.github/prompts/review-release.prompt.md` | -| `confirm-release` | `.github/prompts/confirm-release.prompt.md` | -| `draft-operation` | `.github/prompts/draft-operation.prompt.md` | -| `review-operation` | `.github/prompts/review-operation.prompt.md` | -| `confirm-operation` | `.github/prompts/confirm-operation.prompt.md` | - -`confirm-*` 서브스텝 실행 시 `APPROVER_NAME`을 해당 문서의 Freeze 섹션 `Confirmed By:` 값으로 주입한다. -해당 줄이 문서에 없거나 플레이스홀더로 되어 있으면, 실행 전 `APPROVER_NAME`으로 교체한다. - ---- - -## 중요 규칙 - -- 각 단계는 정해진 순서대로만 실행하며, 이전 단계가 `confirmed`가 아닌 상태에서 다음 단계를 시작하지 않는다. -- `run-implementation`은 실제 코드를 변경하는 단계이므로, 블로킹 조건이 없어도 실행 전 `4_implementation.md`의 구현 계획(`# 2 구현 계획`)과 변경 파일 목록(`# 3 변경 파일 목록`)을 요약해 사용자에게 안내한 뒤 진행한다. -- 사용자 판단 없이 임의로 결정할 수 없는 항목(담당자 지정, 외부 환경 정보, 정책 결정 등)은 반드시 중단하고 사용자에게 문의한다. -- 블로킹 처리 후 사용자가 문서를 직접 수정하면 `/run-sdlc `을 재실행해 이어서 진행할 수 있다. -- 현재 시각은 시스템 또는 컨텍스트에서 제공된 날짜/시간을 사용한다. diff --git a/.github/scripts/stagepilot-bootstrap-seed.py b/.github/scripts/stagepilot-bootstrap-seed.py new file mode 100644 index 0000000..2937b72 --- /dev/null +++ b/.github/scripts/stagepilot-bootstrap-seed.py @@ -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()) \ No newline at end of file diff --git a/.github/scripts/stagepilot-doctor.py b/.github/scripts/stagepilot-doctor.py new file mode 100644 index 0000000..44c68c2 --- /dev/null +++ b/.github/scripts/stagepilot-doctor.py @@ -0,0 +1,1289 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +from datetime import datetime +import re +import sys +from dataclasses import dataclass +from pathlib import Path +from typing import Iterable + + +PLACEHOLDER_PATTERN = re.compile(r"\{\{[^{}]+\}\}") +LINK_PATTERN = re.compile(r"\[[^\]]+\]\(([^)]+)\)") +REQ_ID_PATTERN = re.compile(r"req-(\d+)", re.IGNORECASE) +BATCH_ID_PATTERN = re.compile(r"bat-(\d+)", re.IGNORECASE) +DISCOVERY_ID_PATTERN = re.compile(r"dcy-(\d+)", re.IGNORECASE) +RELEASE_ID_PATTERN = re.compile(r"rel-(\d+)", re.IGNORECASE) +STATUS_PATTERN = re.compile(r"^-\s*(?:Status|상태):\s*(.+?)\s*$", re.MULTILINE) +BATCH_PROFILE_PATTERN = re.compile(r"^-\s*Profile:\s*(.+?)\s*$", re.MULTILINE) +RELEASE_PROFILE_PATTERN = re.compile(r"^-\s*Profile:\s*(.+?)\s*$", re.MULTILINE) +REQ_TYPE_LINE_PATTERN = re.compile(r"^-\s*Type:\s*(.+)$", re.MULTILINE) +INLINE_CODE_PATTERN = re.compile(r"`([^`]+)`") + +BATCH_PROFILES = {"standard", "batch-lite"} +RELEASE_PROFILES = {"docs-only", "tooling", "app-service"} + +FINALIZED_STATUSES = { + "approved", + "archived", + "completed", + "confirmed", + "deprecated", + "feedback-captured", + "implemented", + "in-delivery", + "release-candidate", + "released", +} + +ACTIVE_INDEX_FILES = [ + Path("docs/discovery/index.md"), + Path("docs/srs/index.md"), + Path("docs/batches/index.md"), + Path("docs/releases/index.md"), +] + +BASELINE_DOC_FILES = [ + Path("docs/project-structure.md"), + Path("docs/runtime-flows.md"), +] + +OPTIONAL_CROSS_CUTTING_DOC_FILES = [ + Path("docs/interface-contract.md"), + Path("docs/data-model.md"), +] + +BOOTSTRAP_REQUIRED_FILES = ACTIVE_INDEX_FILES + BASELINE_DOC_FILES + + +@dataclass(frozen=True) +class Finding: + level: str + code: str + path: Path + message: str + + +@dataclass(frozen=True) +class TraceabilityRow: + req_id: str + status: str + discovery_ids: tuple[str, ...] + batch_ids: tuple[str, ...] + release_ready_batch_ids: tuple[str, ...] + release_ids: tuple[str, ...] + flags: tuple[str, ...] + + +@dataclass(frozen=True) +class FeedbackHandoffRow: + release_id: str + status: str + discovery_inputs: tuple[str, ...] + req_inputs: tuple[str, ...] + change_req_inputs: tuple[str, ...] + flags: tuple[str, ...] + + +@dataclass(frozen=True) +class ChangeReqImpact: + change_id: str + status_recommendation: str + reverification_needed: str + implementation_invalidated: str + + +class Doctor: + def __init__(self, workspace_root: Path, package_root: Path, strict_missing_docs: bool, report_path: Path | None = None) -> None: + self.workspace_root = workspace_root + self.package_root = package_root + self.strict_missing_docs = strict_missing_docs + self.report_path = report_path + self.report_written = False + self.findings: list[Finding] = [] + self.traceability_rows: list[TraceabilityRow] = [] + self.feedback_handoff_rows: list[FeedbackHandoffRow] = [] + + def add(self, level: str, code: str, path: Path, message: str) -> None: + self.findings.append(Finding(level=level, code=code, path=path, message=message)) + + def run(self) -> int: + self.check_allowlist_targets() + self.check_req_type_contract() + self.check_design_template_contract() + self.check_markdown_links(self.package_markdown_files(), relative_to=self.package_root) + + workspace_mode = self.check_active_workspace_roots() + if workspace_mode: + self.check_discovery_index() + self.check_srs_index() + self.check_batch_index() + self.check_release_index() + self.build_traceability_matrix() + self.build_feedback_handoff_summary() + self.check_placeholders(self.workspace_markdown_files()) + self.check_markdown_links(self.workspace_markdown_files(), relative_to=self.workspace_root) + + if self.report_path is not None: + self.write_report() + self.print_report() + return 1 if any(f.level == "ERROR" for f in self.findings) else 0 + + def package_markdown_files(self) -> list[Path]: + patterns = [ + Path("README.md"), + Path(".github/copilot-instructions.md"), + Path(".github/instructions"), + Path(".github/skills"), + Path(".github/templates"), + ] + files: list[Path] = [] + for pattern in patterns: + full_path = self.package_root / pattern + if full_path.is_file(): + files.append(full_path) + continue + if full_path.is_dir(): + files.extend(sorted(full_path.rglob("*.md"))) + return files + + def workspace_markdown_files(self) -> list[Path]: + docs_root = self.workspace_root / "docs" + if not docs_root.exists(): + return [] + return sorted(docs_root.rglob("*.md")) + + def check_active_workspace_roots(self) -> bool: + existing = [path for path in ACTIVE_INDEX_FILES if (self.workspace_root / path).exists()] + missing_bootstrap_files = [path for path in BOOTSTRAP_REQUIRED_FILES if not (self.workspace_root / path).exists()] + if not existing: + level = "ERROR" if self.strict_missing_docs else "WARN" + self.add( + level, + "missing-active-docs", + self.workspace_root, + "No active SDLC docs were found under docs/. Workspace-specific checks were skipped.", + ) + self.add_bootstrap_required_hint(missing_bootstrap_files) + return False + + for path in ACTIVE_INDEX_FILES: + if not (self.workspace_root / path).exists(): + self.add( + "ERROR", + "missing-root-index", + self.workspace_root / path, + "Missing active index file.", + ) + + if missing_bootstrap_files: + self.add_bootstrap_required_hint(missing_bootstrap_files) + else: + self.check_optional_cross_cutting_docs() + return True + + def check_optional_cross_cutting_docs(self) -> None: + if self.is_package_repo_self_check(): + return + + for path in OPTIONAL_CROSS_CUTTING_DOC_FILES: + if (self.workspace_root / path).exists(): + continue + self.add( + "WARN", + "missing-cross-cutting-baseline-doc", + self.workspace_root / path, + "Missing optional cross-cutting baseline doc. Run /bootstrap-baseline to backfill it or add the document manually if the project needs this shared contract.", + ) + + def add_bootstrap_required_hint(self, missing_files: list[Path]) -> None: + if not missing_files or self.is_package_repo_self_check(): + return + + missing_list = ", ".join(str(path) for path in missing_files[:6]) + if len(missing_files) > 6: + missing_list += ", ..." + + self.add( + "INFO", + "bootstrap-required", + self.workspace_root, + "Fresh host repos should run /bootstrap-baseline in Copilot Chat before the first real Discovery. " + f"Missing bootstrap files: {missing_list}", + ) + + def is_package_repo_self_check(self) -> bool: + if self.workspace_root.resolve() != self.package_root.resolve(): + return False + + required_paths = [ + Path("bootstrap/install.sh"), + Path("bootstrap/source-allowlist.txt"), + Path("examples/p3-change-management"), + ] + return all((self.workspace_root / path).exists() for path in required_paths) + + def check_allowlist_targets(self) -> None: + allowlist_path = self.package_root / "bootstrap/source-allowlist.txt" + if not allowlist_path.exists(): + self.add("ERROR", "missing-allowlist", allowlist_path, "source-allowlist.txt is missing.") + return + + github_root = self.package_root / ".github" + for raw_line in allowlist_path.read_text(encoding="utf-8").splitlines(): + line = raw_line.split("#", 1)[0].strip() + if not line: + continue + target = github_root / line.rstrip("/") + if line.endswith("/"): + if not target.is_dir(): + self.add("ERROR", "allowlist-missing-dir", allowlist_path, f"Allowlist entry '{line}' does not exist under .github/.") + elif not target.is_file(): + self.add("ERROR", "allowlist-missing-file", allowlist_path, f"Allowlist entry '{line}' does not exist under .github/.") + + def check_req_type_contract(self) -> None: + skill_path = self.package_root / ".github/skills/draft-req/SKILL.md" + template_path = self.package_root / ".github/templates/srs/req-template.md" + index_path = self.package_root / ".github/templates/srs/index.md" + + if not skill_path.exists() or not template_path.exists() or not index_path.exists(): + self.add("ERROR", "missing-req-contract-files", self.package_root, "REQ type contract files are missing.") + return + + skill_types = self.parse_req_types_from_skill(skill_path) + template_types = self.parse_req_types_from_template(template_path) + index_types = self.parse_req_types_from_index(index_path) + + if not skill_types or not template_types or not index_types: + self.add("ERROR", "unparseable-req-types", skill_path, "Could not parse REQ types from skill/template/index files.") + return + + normalized_sets = { + tuple(sorted(skill_types)), + tuple(sorted(template_types)), + tuple(sorted(index_types)), + } + if len(normalized_sets) != 1: + self.add( + "ERROR", + "req-type-mismatch", + skill_path, + "REQ type taxonomy differs across draft-req skill, req-template, and srs index.", + ) + + def check_design_template_contract(self) -> None: + skill_path = self.package_root / ".github/skills/draft-batch-design/SKILL.md" + template_path = self.package_root / ".github/templates/batches/design.md" + if not skill_path.exists() or not template_path.exists(): + self.add("ERROR", "missing-design-contract-files", self.package_root, "Batch design contract files are missing.") + return + + required_sections = self.parse_design_required_sections(skill_path) + template_sections = self.parse_markdown_headings(template_path) + missing = [section for section in required_sections if section not in template_sections] + for section in missing: + self.add( + "ERROR", + "design-template-missing-section", + template_path, + f"Missing required section '{section}' declared by draft-batch-design.", + ) + + def check_markdown_links(self, files: Iterable[Path], relative_to: Path) -> None: + for file_path in files: + text = file_path.read_text(encoding="utf-8") + for target in LINK_PATTERN.findall(text): + target = target.strip() + if not target or target.startswith(("http://", "https://", "mailto:")): + continue + if target.startswith("#"): + continue + if any(token in target for token in ("<", ">", "{{", "}}")): + continue + link_target = target.split("#", 1)[0] + resolved = (file_path.parent / link_target).resolve() + if not resolved.exists(): + self.add( + "ERROR", + "broken-link", + file_path, + f"Link target '{target}' does not exist.", + ) + + def check_placeholders(self, files: Iterable[Path]) -> None: + for file_path in files: + text = file_path.read_text(encoding="utf-8") + matches = sorted(set(PLACEHOLDER_PATTERN.findall(text))) + if not matches: + continue + status = self.parse_status(text) + level = "ERROR" if status in FINALIZED_STATUSES else "WARN" + preview = ", ".join(matches[:3]) + if len(matches) > 3: + preview += ", ..." + self.add(level, "placeholder-found", file_path, f"Found unresolved placeholders: {preview}") + + def check_discovery_index(self) -> None: + index_path = self.workspace_root / "docs/discovery/index.md" + if not index_path.exists(): + return + + for row in self.parse_markdown_table(index_path, "## Discovery 목록"): + doc_target = self.extract_link_target(row.get("문서", "")) + doc_path = index_path.parent / doc_target if doc_target else None + if not doc_target or not doc_path or not doc_path.exists(): + self.add("ERROR", "discovery-index-link", index_path, f"Discovery row has a missing document target: {row}") + continue + doc_text = doc_path.read_text(encoding="utf-8") + doc_status = self.parse_status(doc_text) + row_status = row.get("상태", "").strip().lower() + if doc_status and row_status and doc_status != row_status: + self.add("ERROR", "discovery-status-mismatch", doc_path, f"Index status '{row_status}' does not match document status '{doc_status}'.") + + def check_srs_index(self) -> None: + index_path = self.workspace_root / "docs/srs/index.md" + if not index_path.exists(): + return + + index_text = index_path.read_text(encoding="utf-8") + req_files = sorted((self.workspace_root / "docs/srs").glob("*/req-*.md")) + register = self.parse_markdown_table(index_path, "## Requirement Register") + register_map = {self.normalize_req_id(row.get("ID", "")): row for row in register if row.get("ID")} + + max_req_number = 0 + for req_path in req_files: + req_id = self.normalize_req_id(req_path.stem.split("_", 1)[0]) + max_req_number = max(max_req_number, self.req_id_number(req_id)) + text = req_path.read_text(encoding="utf-8") + req_status = self.parse_status(text) + req_type = self.parse_req_type(text) + latest_change_req_impact = self.parse_latest_change_req_impact(text) + expected_type = req_path.parent.name + if req_type and expected_type and req_type != expected_type: + self.add("ERROR", "req-folder-type-mismatch", req_path, f"REQ type '{req_type}' does not match folder '{expected_type}'.") + self.check_req_change_rollback(req_path, req_status, latest_change_req_impact) + if req_id not in register_map: + self.add("ERROR", "req-missing-register-row", req_path, "REQ file is missing from Requirement Register.") + continue + row = register_map[req_id] + row_status = row.get("Status", "").strip().lower() + row_type = row.get("Type", "").strip() + row_link = self.extract_link_target(row.get("Link", "")) + if req_status and row_status and req_status != row_status: + self.add("ERROR", "req-status-mismatch", req_path, f"Register status '{row_status}' does not match REQ status '{req_status}'.") + if req_type and row_type and req_type != row_type: + self.add("ERROR", "req-type-register-mismatch", req_path, f"Register type '{row_type}' does not match REQ type '{req_type}'.") + if row_link: + resolved = (index_path.parent / row_link).resolve() + if resolved != req_path.resolve(): + self.add("ERROR", "req-link-mismatch", req_path, f"Register link points to '{row_link}', expected '{req_path.relative_to(index_path.parent)}'.") + + for req_id, row in register_map.items(): + link_target = self.extract_link_target(row.get("Link", "")) + if not link_target: + self.add("ERROR", "req-register-link-missing", index_path, f"Requirement Register row for '{req_id}' is missing a link target.") + continue + linked_path = (index_path.parent / link_target).resolve() + if not linked_path.exists(): + self.add("ERROR", "req-register-link-broken", index_path, f"Requirement Register link '{link_target}' does not exist.") + + next_req = self.parse_next_requirement_id(index_text) + if next_req is not None: + expected_next = max_req_number + 1 if max_req_number else 1 + if next_req != expected_next: + self.add( + "ERROR", + "next-req-id-mismatch", + index_path, + f"Next Requirement ID is REQ-{next_req:03d}, expected REQ-{expected_next:03d}.", + ) + + def check_batch_index(self) -> None: + index_path = self.workspace_root / "docs/batches/index.md" + if not index_path.exists(): + return + + rows = self.parse_markdown_table(index_path, "## Batch Register") + row_map = {row.get("BAT ID", "").strip().lower(): row for row in rows if row.get("BAT ID")} + batch_dirs = sorted(path for path in (self.workspace_root / "docs/batches").glob("bat-*") if path.is_dir()) + for batch_dir in batch_dirs: + batch_id = batch_dir.name.split("_", 1)[0].lower() + batch_index = batch_dir / "index.md" + if not batch_index.exists(): + self.add("ERROR", "batch-index-missing", batch_dir, "Batch folder is missing index.md.") + continue + batch_index_text = batch_index.read_text(encoding="utf-8") + batch_status = self.parse_status(batch_index_text) + batch_profile = self.parse_batch_profile(batch_index_text) + if batch_profile and batch_profile not in BATCH_PROFILES: + self.add( + "ERROR", + "batch-profile-invalid", + batch_index, + f"Unsupported batch profile '{batch_profile}'. Expected 'standard' or 'batch-lite'.", + ) + for doc_name in self.required_batch_docs(batch_profile, batch_status): + if not (batch_dir / doc_name).exists(): + self.add("ERROR", "batch-doc-missing", batch_dir / doc_name, "Batch folder is missing a required document.") + if batch_id not in row_map: + self.add("ERROR", "batch-missing-register-row", batch_index, "Batch folder is missing from Batch Register.") + continue + row = row_map[batch_id] + row_profile = row.get("Profile", "").strip().lower() + row_status = row.get("Status", "").strip().lower() + if row_profile and batch_profile and row_profile != batch_profile: + self.add("ERROR", "batch-profile-mismatch", batch_index, f"Register profile '{row_profile}' does not match batch profile '{batch_profile}'.") + if batch_status and row_status and batch_status != row_status: + self.add("ERROR", "batch-status-mismatch", batch_index, f"Register status '{row_status}' does not match batch status '{batch_status}'.") + + for batch_id, row in row_map.items(): + folder_target = self.extract_link_target(row.get("Folder", "")) or row.get("Folder", "").strip() + if not folder_target: + self.add("ERROR", "batch-register-folder-missing", index_path, f"Batch Register row for '{batch_id}' is missing a folder path.") + continue + linked_path = (index_path.parent / folder_target).resolve() + if not linked_path.exists(): + self.add("ERROR", "batch-register-folder-broken", index_path, f"Batch Register folder '{folder_target}' does not exist.") + + def check_release_index(self) -> None: + index_path = self.workspace_root / "docs/releases/index.md" + if not index_path.exists(): + return + + rows = self.parse_markdown_table(index_path, "## Release Register") + row_map = {row.get("REL ID", "").strip().lower(): row for row in rows if row.get("REL ID")} + release_files = sorted((self.workspace_root / "docs/releases").glob("rel-*.md")) + for release_path in release_files: + rel_id = release_path.stem.split("_", 1)[0].lower() + if rel_id not in row_map: + self.add("ERROR", "release-missing-register-row", release_path, "Release document is missing from Release Register.") + continue + row = row_map[rel_id] + release_text = release_path.read_text(encoding="utf-8") + release_status = self.parse_status(release_text) + release_profile = self.parse_release_profile(release_text) + if release_profile and release_profile not in RELEASE_PROFILES: + self.add( + "ERROR", + "release-profile-invalid", + release_path, + f"Unsupported release profile '{release_profile}'. Expected 'docs-only', 'tooling', or 'app-service'.", + ) + row_profile = row.get("Profile", "").strip().lower() + row_status = row.get("Status", "").strip().lower() + if row_profile and release_profile and row_profile != release_profile: + self.add("ERROR", "release-profile-mismatch", release_path, f"Register profile '{row_profile}' does not match release profile '{release_profile}'.") + if release_status and row_status and release_status != row_status: + self.add("ERROR", "release-status-mismatch", release_path, f"Register status '{row_status}' does not match release status '{release_status}'.") + + for rel_id, row in row_map.items(): + link_target = self.extract_link_target(row.get("Link", "")) + if not link_target: + self.add("ERROR", "release-register-link-missing", index_path, f"Release Register row for '{rel_id}' is missing a link target.") + continue + linked_path = (index_path.parent / link_target).resolve() + if not linked_path.exists(): + self.add("ERROR", "release-register-link-broken", index_path, f"Release Register link '{link_target}' does not exist.") + + def build_traceability_matrix(self) -> None: + req_files = sorted((self.workspace_root / "docs/srs").glob("*/req-*.md")) + if not req_files: + return + + discovery_refs = self.parse_discovery_traceability() + batch_refs, batch_sources, batch_statuses = self.parse_batch_traceability() + release_refs, release_statuses, release_feedback_states = self.parse_release_traceability() + + for release_id, release_status in release_statuses.items(): + feedback_state = release_feedback_states.get(release_id, "missing") + release_path = self.resolve_release_path(release_id) + if release_status == "released": + if feedback_state != "resolved": + self.add( + "WARN", + "release-feedback-unlinked", + release_path, + "Released release has no resolved Feedback Handoff content.", + ) + else: + self.add( + "WARN", + "release-feedback-pending", + release_path, + "Released release has Feedback Handoff content but is not yet closed with feedback-captured status.", + ) + elif release_status == "feedback-captured" and feedback_state != "resolved": + self.add( + "ERROR", + "release-feedback-unresolved", + release_path, + "Release is marked feedback-captured but Feedback Handoff is still unresolved.", + ) + + rows: list[TraceabilityRow] = [] + for req_path in req_files: + req_id = self.normalize_req_id(req_path.stem.split("_", 1)[0]) + if not req_id: + continue + + req_text = req_path.read_text(encoding="utf-8") + req_status = self.parse_status(req_text) + req_batches = set(batch_refs.get(req_id, set())) + req_discoveries = set(discovery_refs.get(req_id, set())) + req_releases: set[str] = set() + + for batch_id in req_batches: + req_discoveries.update(batch_sources.get(batch_id, set())) + req_releases.update(release_refs.get(batch_id, set())) + + releasable_batches = { + batch_id + for batch_id in req_batches + if batch_statuses.get(batch_id) in {"release-candidate", "released"} + } + + flags: list[str] = [] + has_discovery = bool(req_discoveries) + has_batch = bool(req_batches) + + if req_status == "implemented" and not has_batch: + flags.append("implemented-without-batch") + self.add( + "ERROR", + "implemented-req-no-batch", + req_path, + "Implemented REQ has no batch traceability.", + ) + elif req_status in {"proposed", "approved", "implemented"} and not has_discovery and not has_batch: + flags.append("orphan") + self.add( + "WARN", + "orphan-req", + req_path, + "REQ has no Discovery or Batch linkage.", + ) + elif req_status == "approved" and not has_batch: + flags.append("approved-without-batch") + self.add( + "WARN", + "orphan-approved-req", + req_path, + "Approved REQ is not included in any batch.", + ) + elif req_status == "approved" and not releasable_batches: + flags.append("approved-without-release-candidate-batch") + self.add( + "WARN", + "approved-req-no-release-candidate-batch", + req_path, + "Approved REQ is not included in any release-candidate or released batch.", + ) + + rows.append( + TraceabilityRow( + req_id=req_id, + status=req_status or "unknown", + discovery_ids=tuple(sorted(req_discoveries)), + batch_ids=tuple(sorted(req_batches)), + release_ready_batch_ids=tuple(sorted(releasable_batches)), + release_ids=tuple(sorted(req_releases)), + flags=tuple(flags), + ) + ) + + self.traceability_rows = sorted(rows, key=lambda row: self.req_id_number(row.req_id)) + + def parse_discovery_traceability(self) -> dict[str, set[str]]: + refs: dict[str, set[str]] = {} + discovery_dir = self.workspace_root / "docs/discovery" + if not discovery_dir.exists(): + return refs + + for discovery_path in sorted(discovery_dir.glob("dcy-*.md")): + discovery_id = self.normalize_discovery_id(discovery_path.stem) + if not discovery_id: + continue + for line in discovery_path.read_text(encoding="utf-8").splitlines(): + if "생성된 REQ 참조" not in line: + continue + for req_id in self.extract_req_ids(line): + refs.setdefault(req_id, set()).add(discovery_id) + return refs + + def parse_batch_traceability(self) -> tuple[dict[str, set[str]], dict[str, set[str]], dict[str, str]]: + req_to_batches: dict[str, set[str]] = {} + batch_to_discoveries: dict[str, set[str]] = {} + batch_statuses: dict[str, str] = {} + batches_dir = self.workspace_root / "docs/batches" + if not batches_dir.exists(): + return req_to_batches, batch_to_discoveries, batch_statuses + + for batch_dir in sorted(path for path in batches_dir.glob("bat-*") if path.is_dir()): + batch_index = batch_dir / "index.md" + if not batch_index.exists(): + continue + batch_id = self.normalize_batch_id(batch_dir.name) + if not batch_id: + continue + + batch_text = batch_index.read_text(encoding="utf-8") + batch_statuses[batch_id] = self.parse_status(batch_text) + + for line in batch_text.splitlines(): + if "Included REQ" in line: + for req_id in self.extract_req_ids(line): + req_to_batches.setdefault(req_id, set()).add(batch_id) + if "Source Discovery" in line: + for discovery_id in self.extract_discovery_ids(line): + batch_to_discoveries.setdefault(batch_id, set()).add(discovery_id) + + return req_to_batches, batch_to_discoveries, batch_statuses + + def parse_release_traceability(self) -> tuple[dict[str, set[str]], dict[str, str], dict[str, str]]: + batch_to_releases: dict[str, set[str]] = {} + release_statuses: dict[str, str] = {} + release_feedback_states: dict[str, str] = {} + releases_dir = self.workspace_root / "docs/releases" + if not releases_dir.exists(): + return batch_to_releases, release_statuses, release_feedback_states + + for release_path in sorted(releases_dir.glob("rel-*.md")): + release_id = self.normalize_release_id(release_path.stem) + if not release_id: + continue + release_text = release_path.read_text(encoding="utf-8") + release_statuses[release_id] = self.parse_status(release_text) + release_feedback_states[release_id] = self.parse_release_feedback_state(release_text) + for line in release_text.splitlines(): + if "Included Batch" not in line: + continue + for batch_id in self.extract_batch_ids(line): + batch_to_releases.setdefault(batch_id, set()).add(release_id) + + return batch_to_releases, release_statuses, release_feedback_states + + def write_report(self) -> None: + if self.report_path is None: + return + + try: + self.report_path.parent.mkdir(parents=True, exist_ok=True) + self.report_path.write_text(self.render_markdown_report(), encoding="utf-8") + self.report_written = True + except OSError as exc: + self.add( + "ERROR", + "report-write-failed", + self.report_path, + f"Failed to write Markdown report: {exc}", + ) + + def render_markdown_report(self) -> str: + error_count, warn_count, info_count = self.summarize_findings() + lines = [ + "# StagePilot Doctor Report", + "", + "## Metadata", + "", + f"- Generated At: `{datetime.now().astimezone().isoformat(timespec='seconds')}`", + f"- Workspace Root: `{self.workspace_root}`", + f"- Package Root: `{self.package_root}`", + f"- Strict Missing Docs: `{str(self.strict_missing_docs).lower()}`", + ] + if self.report_path is not None: + lines.append(f"- Requested Report Path: `{self.report_path}`") + + lines.extend( + [ + "", + "## Summary", + "", + f"- Errors: {error_count}", + f"- Warnings: {warn_count}", + f"- Info: {info_count}", + "", + "## Findings", + "", + ] + ) + + sorted_findings = self.sorted_findings() + if not sorted_findings: + lines.append("- None") + else: + for level in ("ERROR", "WARN", "INFO"): + level_findings = [finding for finding in sorted_findings if finding.level == level] + if not level_findings: + continue + lines.append(f"### {level}") + lines.append("") + for finding in level_findings: + lines.append( + f"- [{finding.code}] `{self.display_path(finding.path)}`: {finding.message}" + ) + lines.append("") + + lines.extend(["## Traceability Matrix", ""]) + if not self.traceability_rows: + lines.append("- No traceability rows generated.") + else: + lines.extend( + [ + "| REQ ID | Status | Discovery | Batch | Release-Ready Batch | Release | Flags |", + "| --- | --- | --- | --- | --- | --- | --- |", + ] + ) + for row in self.traceability_rows: + discovery = ", ".join(row.discovery_ids) if row.discovery_ids else "-" + batch = ", ".join(row.batch_ids) if row.batch_ids else "-" + release_ready_batch = ", ".join(row.release_ready_batch_ids) if row.release_ready_batch_ids else "-" + release = ", ".join(row.release_ids) if row.release_ids else "-" + flags = ", ".join(row.flags) if row.flags else "-" + lines.append( + f"| {row.req_id} | {row.status} | {discovery} | {batch} | {release_ready_batch} | {release} | {flags} |" + ) + + lines.extend(["", "## Feedback Loop Summary", ""]) + if not self.feedback_handoff_rows: + lines.append("- No feedback handoff rows generated.") + else: + lines.extend( + [ + "| Release | Status | Discovery Input | REQ Input | Change Request Input | Flags |", + "| --- | --- | --- | --- | --- | --- |", + ] + ) + for row in self.feedback_handoff_rows: + discovery_inputs = ", ".join(row.discovery_inputs) if row.discovery_inputs else "-" + req_inputs = ", ".join(row.req_inputs) if row.req_inputs else "-" + change_req_inputs = ", ".join(row.change_req_inputs) if row.change_req_inputs else "-" + flags = ", ".join(row.flags) if row.flags else "-" + lines.append( + f"| {row.release_id} | {row.status} | {discovery_inputs} | {req_inputs} | {change_req_inputs} | {flags} |" + ) + + return "\n".join(lines) + "\n" + + def sorted_findings(self) -> list[Finding]: + severity_order = {"ERROR": 0, "WARN": 1, "INFO": 2} + return sorted( + self.findings, + key=lambda item: (severity_order.get(item.level, 99), str(item.path), item.code), + ) + + def summarize_findings(self) -> tuple[int, int, int]: + error_count = sum(1 for finding in self.findings if finding.level == "ERROR") + warn_count = sum(1 for finding in self.findings if finding.level == "WARN") + info_count = sum(1 for finding in self.findings if finding.level == "INFO") + return error_count, warn_count, info_count + + def print_report(self) -> None: + if not self.findings: + print("stagepilot-doctor: no issues found") + else: + for finding in self.sorted_findings(): + display_path = self.display_path(finding.path) + print(f"{finding.level} [{finding.code}] {display_path}: {finding.message}") + + if self.traceability_rows: + print() + print("Traceability Matrix") + print("REQ ID | Status | Discovery | Batch | Release-Ready Batch | Release | Flags") + print("--- | --- | --- | --- | --- | --- | ---") + for row in self.traceability_rows: + discovery = ", ".join(row.discovery_ids) if row.discovery_ids else "-" + batch = ", ".join(row.batch_ids) if row.batch_ids else "-" + release_ready_batch = ", ".join(row.release_ready_batch_ids) if row.release_ready_batch_ids else "-" + release = ", ".join(row.release_ids) if row.release_ids else "-" + flags = ", ".join(row.flags) if row.flags else "-" + print(f"{row.req_id} | {row.status} | {discovery} | {batch} | {release_ready_batch} | {release} | {flags}") + + if self.feedback_handoff_rows: + print() + print("Feedback Loop Summary") + print("Release | Status | Discovery Input | REQ Input | Change Request Input | Flags") + print("--- | --- | --- | --- | --- | ---") + for row in self.feedback_handoff_rows: + discovery_inputs = ", ".join(row.discovery_inputs) if row.discovery_inputs else "-" + req_inputs = ", ".join(row.req_inputs) if row.req_inputs else "-" + change_req_inputs = ", ".join(row.change_req_inputs) if row.change_req_inputs else "-" + flags = ", ".join(row.flags) if row.flags else "-" + print(f"{row.release_id} | {row.status} | {discovery_inputs} | {req_inputs} | {change_req_inputs} | {flags}") + + error_count, warn_count, info_count = self.summarize_findings() + print(f"stagepilot-doctor: {error_count} error(s), {warn_count} warning(s), {info_count} info message(s)") + if self.report_written and self.report_path is not None: + print(f"stagepilot-doctor: wrote Markdown report to {self.report_path}") + + def display_path(self, path: Path) -> str: + for base in (self.workspace_root, self.package_root): + try: + return str(path.resolve().relative_to(base.resolve())) or "." + except ValueError: + continue + return str(path) + + def resolve_release_path(self, release_id: str) -> Path: + releases_dir = self.workspace_root / "docs/releases" + matches = sorted(releases_dir.glob(f"{release_id}_*.md")) + if matches: + return matches[0] + return releases_dir / f"{release_id}.md" + + def check_req_change_rollback(self, req_path: Path, req_status: str, latest_change_req_impact: ChangeReqImpact | None) -> None: + if latest_change_req_impact is None: + return + + recommendation = latest_change_req_impact.status_recommendation + implementation_invalidated = latest_change_req_impact.implementation_invalidated == "yes" + reverification_needed = latest_change_req_impact.reverification_needed == "yes" + + if recommendation == "revert-to-approved" and req_status == "implemented": + self.add( + "ERROR", + "req-change-rollback-missing", + req_path, + f"Latest change '{latest_change_req_impact.change_id}' recommends reverting to Approved, but REQ status is still Implemented.", + ) + elif recommendation == "revert-to-proposed" and req_status in {"approved", "implemented"}: + self.add( + "ERROR", + "req-change-rollback-missing", + req_path, + f"Latest change '{latest_change_req_impact.change_id}' recommends reverting to Proposed, but REQ status is still '{req_status}'.", + ) + elif implementation_invalidated and req_status == "implemented": + self.add( + "ERROR", + "req-change-rollback-missing", + req_path, + f"Latest change '{latest_change_req_impact.change_id}' invalidates existing implementation, but REQ status is still Implemented.", + ) + elif reverification_needed and req_status == "implemented": + self.add( + "WARN", + "req-change-reverification-pending", + req_path, + f"Latest change '{latest_change_req_impact.change_id}' requires reverification while REQ remains Implemented.", + ) + + def build_feedback_handoff_summary(self) -> None: + releases_dir = self.workspace_root / "docs/releases" + if not releases_dir.exists(): + self.feedback_handoff_rows = [] + return + + existing_req_ids = { + self.normalize_req_id(path.stem.split("_", 1)[0]) + for path in sorted((self.workspace_root / "docs/srs").glob("*/req-*.md")) + } + rows: list[FeedbackHandoffRow] = [] + + for release_path in sorted(releases_dir.glob("rel-*.md")): + release_id = self.normalize_release_id(release_path.stem) + if not release_id: + continue + + release_text = release_path.read_text(encoding="utf-8") + feedback_inputs = self.parse_release_feedback_inputs(release_text) + discovery_inputs = self.normalize_feedback_values(feedback_inputs.get("discovery", [])) + req_inputs = self.normalize_feedback_values(feedback_inputs.get("req", [])) + change_req_inputs = self.normalize_feedback_values(feedback_inputs.get("change-req", [])) + + flags: list[str] = [] + if not discovery_inputs and not req_inputs and not change_req_inputs: + flags.append("no-follow-up-input") + + referenced_change_req_ids = { + req_id + for value in change_req_inputs + for req_id in self.extract_req_ids(value) + } + missing_change_req_ids = sorted(req_id for req_id in referenced_change_req_ids if req_id not in existing_req_ids) + if missing_change_req_ids: + flags.append("unknown-change-req-target") + self.add( + "WARN", + "feedback-change-req-target-missing", + release_path, + f"Change Request Input references missing REQ IDs: {', '.join(missing_change_req_ids)}", + ) + + rows.append( + FeedbackHandoffRow( + release_id=release_id, + status=self.parse_status(release_text) or "unknown", + discovery_inputs=discovery_inputs, + req_inputs=req_inputs, + change_req_inputs=change_req_inputs, + flags=tuple(flags), + ) + ) + + self.feedback_handoff_rows = rows + + @staticmethod + def parse_req_types_from_skill(path: Path) -> list[str]: + lines = path.read_text(encoding="utf-8").splitlines() + collecting = False + types: list[str] = [] + for line in lines: + if "아래 폴더 중 정확히 하나를 선택한다." in line: + collecting = True + continue + if collecting and line.startswith("- 새 REQ 경로"): + break + if collecting: + match = INLINE_CODE_PATTERN.search(line) + if match: + types.append(match.group(1)) + return types + + @staticmethod + def parse_req_types_from_template(path: Path) -> list[str]: + text = path.read_text(encoding="utf-8") + match = REQ_TYPE_LINE_PATTERN.search(text) + if not match: + return [] + return [part.strip() for part in match.group(1).split("|") if part.strip()] + + @staticmethod + def parse_req_types_from_index(path: Path) -> list[str]: + rows = Doctor.parse_markdown_table(path, "## Requirement 타입 분류 도표") + types: list[str] = [] + for row in rows: + type_name = row.get("타입", "").strip().strip("*") + if type_name: + types.append(type_name) + return types + + @staticmethod + def parse_design_required_sections(path: Path) -> list[str]: + lines = path.read_text(encoding="utf-8").splitlines() + collecting = False + sections: list[str] = [] + for line in lines: + if "design.md에는 최소한 아래 내용을 포함해야 한다." in line: + collecting = True + continue + if collecting and not line.startswith(("\t-", " -", "- ")): + if line.strip(): + break + if collecting: + entry = line.strip().lstrip("-").strip() + if not entry: + continue + cleaned = entry.strip("`") + if "(" in cleaned: + cleaned = cleaned.split("(", 1)[0].strip() + sections.append(cleaned) + return sections + + @staticmethod + def parse_markdown_headings(path: Path) -> set[str]: + headings = set() + for line in path.read_text(encoding="utf-8").splitlines(): + if line.startswith("## "): + headings.add(line[3:].strip()) + return headings + + @staticmethod + def parse_markdown_table(path: Path, heading: str) -> list[dict[str, str]]: + lines = path.read_text(encoding="utf-8").splitlines() + start_index = None + for index, line in enumerate(lines): + if line.strip() == heading: + start_index = index + 1 + break + if start_index is None: + return [] + + table_lines: list[str] = [] + for line in lines[start_index:]: + if line.strip().startswith("|"): + table_lines.append(line) + continue + if table_lines: + break + + if len(table_lines) < 2: + return [] + + header = [cell.strip() for cell in table_lines[0].strip().strip("|").split("|")] + rows: list[dict[str, str]] = [] + for line in table_lines[2:]: + cells = [cell.strip() for cell in line.strip().strip("|").split("|")] + if len(cells) != len(header): + continue + rows.append(dict(zip(header, cells))) + return rows + + @staticmethod + def extract_link_target(cell: str) -> str | None: + match = LINK_PATTERN.search(cell) + if match: + return match.group(1).split("#", 1)[0] + return None + + @staticmethod + def parse_status(text: str) -> str: + match = STATUS_PATTERN.search(text) + if not match: + return "" + value = match.group(1).strip().strip("`") + return value.split("|")[0].strip().lower() + + @staticmethod + def parse_batch_profile(text: str) -> str: + match = BATCH_PROFILE_PATTERN.search(text) + if not match: + return "standard" + value = match.group(1).strip().strip("`") + return value.split("|")[0].strip().lower() + + @staticmethod + def parse_release_profile(text: str) -> str: + match = RELEASE_PROFILE_PATTERN.search(text) + if not match: + return "app-service" + value = match.group(1).strip().strip("`") + return value.split("|")[0].strip().lower() + + @staticmethod + def required_batch_docs(profile: str, status: str) -> tuple[str, ...]: + normalized_profile = profile or "standard" + normalized_status = status or "draft" + if normalized_profile == "batch-lite": + required_docs = ["planning.md"] + if normalized_status in {"in-delivery", "release-candidate", "released", "archived"}: + required_docs.append("implementation.md") + if normalized_status in {"release-candidate", "released", "archived"}: + required_docs.append("verification.md") + return tuple(required_docs) + return ("planning.md", "design.md", "implementation.md", "verification.md") + + @staticmethod + def parse_req_type(text: str) -> str: + match = REQ_TYPE_LINE_PATTERN.search(text) + if not match: + return "" + value = match.group(1).strip() + return value.split("|")[0].strip() + + @staticmethod + def parse_next_requirement_id(text: str) -> int | None: + match = re.search(r"Current:\s*`REQ-(\d+)`", text) + if not match: + return None + return int(match.group(1)) + + @staticmethod + def parse_release_feedback_state(text: str) -> str: + lines = text.splitlines() + in_section = False + values: list[str] = [] + for line in lines: + stripped = line.strip() + if stripped == "## Feedback Handoff": + in_section = True + continue + if in_section and stripped.startswith("## "): + break + if not in_section: + continue + if stripped.startswith("- "): + value = stripped[2:].strip() + if value.endswith(":"): + continue + values.append(value) + + if not in_section: + return "missing" + if not values: + return "missing" + + normalized_values = {value.strip().lower() for value in values} + unresolved_tokens = ( + "<", + ">", + "{{", + "}}", + "후속 discovery 후보", + "후속 req 후보", + "tbd", + "미정", + ) + if any(any(token in value for token in unresolved_tokens) for value in normalized_values): + return "unresolved" + if normalized_values.issubset({"없음", "none", "n/a", "na"}): + return "resolved" + return "resolved" + + @staticmethod + def parse_latest_change_req_impact(text: str) -> ChangeReqImpact | None: + sections = re.split(r"^###\s+(CHG-\d{8}-\d+)\s*$", text, flags=re.MULTILINE) + if len(sections) < 3: + return None + + latest_change_id = sections[-2].strip() + latest_change_body = sections[-1] + status_recommendation = Doctor.parse_change_log_field(latest_change_body, "Status Recommendation") + reverification_needed = Doctor.parse_change_log_field(latest_change_body, "Reverification Needed") + implementation_invalidated = Doctor.parse_change_log_field(latest_change_body, "Existing Implementation Invalidated") + + if not status_recommendation and not reverification_needed and not implementation_invalidated: + return None + + return ChangeReqImpact( + change_id=latest_change_id, + status_recommendation=status_recommendation, + reverification_needed=reverification_needed, + implementation_invalidated=implementation_invalidated, + ) + + @staticmethod + def parse_change_log_field(text: str, field_name: str) -> str: + pattern = rf"^-\s*{re.escape(field_name)}:\s*(.+?)\s*$" + match = re.search(pattern, text, flags=re.MULTILINE) + if not match: + return "" + return match.group(1).strip().strip("`").lower() + + @staticmethod + def parse_release_feedback_inputs(text: str) -> dict[str, list[str]]: + lines = text.splitlines() + in_section = False + current_group: str | None = None + groups: dict[str, list[str]] = { + "observation": [], + "discovery": [], + "req": [], + "change-req": [], + } + group_labels = { + "Observation Summary": "observation", + "Discovery Input": "discovery", + "REQ Input": "req", + "Change Request Input": "change-req", + } + + for line in lines: + stripped = line.strip() + if stripped == "## Feedback Handoff": + in_section = True + current_group = None + continue + if in_section and stripped.startswith("## "): + break + if not in_section or not stripped.startswith("- "): + continue + + value = stripped[2:].strip() + if value.endswith(":"): + current_group = group_labels.get(value[:-1].strip()) + continue + if current_group is not None: + groups[current_group].append(value) + + return groups + + @staticmethod + def normalize_feedback_values(values: Iterable[str]) -> tuple[str, ...]: + normalized: list[str] = [] + for value in values: + cleaned = value.strip() + if not cleaned or cleaned.lower() in {"없음", "none", "n/a", "na"}: + continue + normalized.append(cleaned) + return tuple(normalized) + + @staticmethod + def extract_req_ids(text: str) -> set[str]: + return {f"req-{int(match.group(1)):03d}" for match in REQ_ID_PATTERN.finditer(text)} + + @staticmethod + def extract_batch_ids(text: str) -> set[str]: + return {f"bat-{int(match.group(1)):03d}" for match in BATCH_ID_PATTERN.finditer(text)} + + @staticmethod + def extract_discovery_ids(text: str) -> set[str]: + return {f"dcy-{int(match.group(1)):03d}" for match in DISCOVERY_ID_PATTERN.finditer(text)} + + @staticmethod + def extract_release_ids(text: str) -> set[str]: + return {f"rel-{int(match.group(1)):03d}" for match in RELEASE_ID_PATTERN.finditer(text)} + + @staticmethod + def normalize_req_id(raw_value: str) -> str: + match = REQ_ID_PATTERN.search(raw_value or "") + if not match: + return "" + return f"req-{int(match.group(1)):03d}" + + @staticmethod + def normalize_batch_id(raw_value: str) -> str: + match = BATCH_ID_PATTERN.search(raw_value or "") + if not match: + return "" + return f"bat-{int(match.group(1)):03d}" + + @staticmethod + def normalize_discovery_id(raw_value: str) -> str: + match = DISCOVERY_ID_PATTERN.search(raw_value or "") + if not match: + return "" + return f"dcy-{int(match.group(1)):03d}" + + @staticmethod + def normalize_release_id(raw_value: str) -> str: + match = RELEASE_ID_PATTERN.search(raw_value or "") + if not match: + return "" + return f"rel-{int(match.group(1)):03d}" + + @staticmethod + def req_id_number(req_id: str) -> int: + match = REQ_ID_PATTERN.search(req_id) + return int(match.group(1)) if match else 0 + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="Validate StagePilot package contracts and active SDLC workspace documents.") + parser.add_argument("root", nargs="?", default=".", help="Workspace root to validate (default: current directory)") + parser.add_argument( + "--strict-missing-docs", + action="store_true", + help="Treat a missing active docs workspace as an error instead of a warning.", + ) + parser.add_argument( + "--report", + help="Write a Markdown report to the given path.", + ) + return parser + + +def main() -> int: + parser = build_parser() + args = parser.parse_args() + + workspace_root = Path(args.root).resolve() + package_root = Path(__file__).resolve().parents[2] + report_path = Path(args.report).resolve() if args.report else None + + if not workspace_root.exists(): + parser.error(f"Workspace root does not exist: {workspace_root}") + + doctor = Doctor( + workspace_root=workspace_root, + package_root=package_root, + strict_missing_docs=args.strict_missing_docs, + report_path=report_path, + ) + return doctor.run() + + +if __name__ == "__main__": + sys.exit(main()) \ No newline at end of file diff --git a/.github/skills/bootstrap-baseline/SKILL.md b/.github/skills/bootstrap-baseline/SKILL.md new file mode 100644 index 0000000..9c7f34b --- /dev/null +++ b/.github/skills/bootstrap-baseline/SKILL.md @@ -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 문서를 생성하지 않았는지 확인한다. \ No newline at end of file diff --git a/.github/skills/capture-release-feedback/SKILL.md b/.github/skills/capture-release-feedback/SKILL.md new file mode 100644 index 0000000..43a0339 --- /dev/null +++ b/.github/skills/capture-release-feedback/SKILL.md @@ -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 상태가 문서 본문과 일치하는지 확인한다. \ No newline at end of file diff --git a/.github/skills/change-req/SKILL.md b/.github/skills/change-req/SKILL.md new file mode 100644 index 0000000..f65683f --- /dev/null +++ b/.github/skills/change-req/SKILL.md @@ -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`에 누락되지 않았는지 확인한다. \ No newline at end of file diff --git a/.github/skills/confirm-batch-verification/SKILL.md b/.github/skills/confirm-batch-verification/SKILL.md new file mode 100644 index 0000000..9a1bf40 --- /dev/null +++ b/.github/skills/confirm-batch-verification/SKILL.md @@ -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/ 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//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 부재가 검증 근거와 모순되지 않는지 확인한다. \ No newline at end of file diff --git a/.github/skills/confirm-discovery/SKILL.md b/.github/skills/confirm-discovery/SKILL.md new file mode 100644 index 0000000..2b8824c --- /dev/null +++ b/.github/skills/confirm-discovery/SKILL.md @@ -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/.md` 같은 직접 경로 +- Discovery 문서 본문 +- `docs/discovery/index.md` +- 현재 저장소 구현 상태 + - 관련 소스 파일 + - 설정 파일 + - 관련 문서 +- 현재 시각 (KST) + +# Core Rules + +## 1. 입력 해석 규칙 + +- 입력이 `dcy-001`처럼 prefix만 주어지면 `docs/discovery/` 아래에서 해당 prefix로 시작하는 문서를 찾는다. +- 입력이 전체 Discovery ID면 `docs/discovery/.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/.md` 형식을 만족하는지 +- 대상 Discovery 문서가 실제로 존재하는지 +- 보강 후에도 C 유형 플레이스홀더와 `상태: Open` 오픈 질문이 정확히 식별되었는지 +- 승인 완료인 경우 문서 상태와 `docs/discovery/index.md` 상태가 모두 `confirmed`인지 +- 승인 보류인 경우 `confirmed`, `승인`, `true` 같은 승인 전환 값이 잘못 들어가지 않았는지 +- 문서 본문 보강이 새로운 요구사항 생성이나 범위 재정의로 번지지 않았는지 +- 결과 보고에 자동 처리 항목과 차단 항목이 모두 포함되는지 \ No newline at end of file diff --git a/.github/skills/confirm-release/SKILL.md b/.github/skills/confirm-release/SKILL.md new file mode 100644 index 0000000..222e7e3 --- /dev/null +++ b/.github/skills/confirm-release/SKILL.md @@ -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과 모순되지 않는지 확인한다. \ No newline at end of file diff --git a/.github/skills/confirm-req-implemented/SKILL.md b/.github/skills/confirm-req-implemented/SKILL.md new file mode 100644 index 0000000..42a480f --- /dev/null +++ b/.github/skills/confirm-req-implemented/SKILL.md @@ -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//req-XXX_.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//index.md` +- 관련 `docs/batches//verification.md` +- 필요하면 관련 `docs/batches//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만 처리되었는지 확인한다. \ No newline at end of file diff --git a/.github/skills/confirm-req/SKILL.md b/.github/skills/confirm-req/SKILL.md new file mode 100644 index 0000000..6b0aef2 --- /dev/null +++ b/.github/skills/confirm-req/SKILL.md @@ -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//req-XXX_.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는 기존 상태가 유지되는지 확인한다. \ No newline at end of file diff --git a/.github/skills/draft-batch-design/SKILL.md b/.github/skills/draft-batch-design/SKILL.md new file mode 100644 index 0000000..0d8aebc --- /dev/null +++ b/.github/skills/draft-batch-design/SKILL.md @@ -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//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//planning.md` +- 포함된 REQ 문서들 +- `docs/batches//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이 그 결정을 설명하는지 확인한다. \ No newline at end of file diff --git a/.github/skills/draft-batch-planning/SKILL.md b/.github/skills/draft-batch-planning/SKILL.md new file mode 100644 index 0000000..3cf5e1a --- /dev/null +++ b/.github/skills/draft-batch-planning/SKILL.md @@ -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//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//index.md` +- 포함된 REQ 문서들 +- `docs/batches//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 목록이 일치하는지 확인한다. \ No newline at end of file diff --git a/.github/skills/draft-batch-verification/SKILL.md b/.github/skills/draft-batch-verification/SKILL.md new file mode 100644 index 0000000..5d9ed16 --- /dev/null +++ b/.github/skills/draft-batch-verification/SKILL.md @@ -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//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//design.md` (존재하는 경우) +- `docs/batches//planning.md` +- `docs/batches//implementation.md` +- `docs/batches//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 중 하나가 명시됐는지 확인한다. \ No newline at end of file diff --git a/.github/skills/draft-batch/SKILL.md b/.github/skills/draft-batch/SKILL.md new file mode 100644 index 0000000..0b99c58 --- /dev/null +++ b/.github/skills/draft-batch/SKILL.md @@ -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// 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 행이 추가되었는지 확인한다. \ No newline at end of file diff --git a/.github/skills/draft-release/SKILL.md b/.github/skills/draft-release/SKILL.md new file mode 100644 index 0000000..61be50d --- /dev/null +++ b/.github/skills/draft-release/SKILL.md @@ -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_.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_.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 행이 함께 생성됐는지 확인한다. \ No newline at end of file diff --git a/.github/skills/draft-req/SKILL.md b/.github/skills/draft-req/SKILL.md new file mode 100644 index 0000000..03f918c --- /dev/null +++ b/.github/skills/draft-req/SKILL.md @@ -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//req-XXX_.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/.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//req-XXX_.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//req-XXX_.md` 형식을 만족하는지 확인한다. +- 생성된 REQ 수와 `Requirement Register` 행 수가 일치하는지 확인한다. +- `Next Requirement ID`가 마지막 생성 번호보다 정확히 1 큰지 확인한다. +- baseline 문서 갱신 또는 baseline 갭 보완이 source Discovery 범위에 있으면, 이를 다루는 REQ가 실제로 생성되었는지 확인한다. \ No newline at end of file diff --git a/.github/skills/new-discovery/SKILL.md b/.github/skills/new-discovery/SKILL.md new file mode 100644 index 0000000..144494c --- /dev/null +++ b/.github/skills/new-discovery/SKILL.md @@ -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-__.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-__.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-__` 형식이어야 한다. + +## 4. 문서 생성/갱신 규칙 + +- 판정 결과가 `새 Discovery 생성`이면 새 파일을 `docs/discovery/.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자리>__}}` -> 계산한 `DISCOVERY_ID` +- `{{SUPERSEDED_BY_DISCOVERY:없음 또는 docs/discovery/.md}}` -> `없음` 또는 대체 Discovery 경로 +- `{{FOLLOW_UP_DISCOVERY_REF:없음 또는 docs/discovery/.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/.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/.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자리>__}}` -> 계산한 `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/.md}}` -> `없음` 또는 대체 Discovery 경로 + - `{{FOLLOW_UP_DISCOVERY_REF:없음 또는 docs/discovery/.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](./.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/.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의 참조 필드가 함께 갱신되었는지 +- 추론 가능한 섹션은 실제 문장으로 채워졌는지 +- 사용자 확인이 필요한 항목만 플레이스홀더로 남았는지 \ No newline at end of file diff --git a/.github/skills/run-batch-implementation/SKILL.md b/.github/skills/run-batch-implementation/SKILL.md new file mode 100644 index 0000000..a943c6b --- /dev/null +++ b/.github/skills/run-batch-implementation/SKILL.md @@ -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/, 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//planning.md` +- `docs/batches//design.md` +- `docs/batches//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`에 실제 변경 파일과 검증 기록이 반영됐는지 확인한다. +- 구현 직후 수행한 가장 좁은 검증 명령 또는 결과가 문서에 남았는지 확인한다. \ No newline at end of file diff --git a/.github/skills/run-sdlc/SKILL.md b/.github/skills/run-sdlc/SKILL.md new file mode 100644 index 0000000..6a11936 --- /dev/null +++ b/.github/skills/run-sdlc/SKILL.md @@ -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 문서가 필요한 상황에서 상태 요약 또는 추천 사유에 그 정보가 누락되지 않았는지 확인한다. \ No newline at end of file diff --git a/.github/skills/suggest-batch-reqs/SKILL.md b/.github/skills/suggest-batch-reqs/SKILL.md new file mode 100644 index 0000000..35c590a --- /dev/null +++ b/.github/skills/suggest-batch-reqs/SKILL.md @@ -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 권장`을 명시한다. \ No newline at end of file diff --git a/.github/skills/suggest-next-discovery/SKILL.md b/.github/skills/suggest-next-discovery/SKILL.md new file mode 100644 index 0000000..457b85f --- /dev/null +++ b/.github/skills/suggest-next-discovery/SKILL.md @@ -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로 과도하게 승격하지 않았는지 확인한다. \ No newline at end of file diff --git a/.github/templates/batches/batch-index.md b/.github/templates/batches/batch-index.md new file mode 100644 index 0000000..8aca9a2 --- /dev/null +++ b/.github/templates/batches/batch-index.md @@ -0,0 +1,25 @@ +# {{BAT_ID}}: <배치 제목> + +- Status: draft | in-delivery | release-candidate | released | archived +- Profile: standard | batch-lite +- Source Discovery: +- Included REQ: +- Excluded REQ: + +## 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 +- <공통 리스크, 공통 결정 사항> diff --git a/.github/templates/batches/design.md b/.github/templates/batches/design.md new file mode 100644 index 0000000..87d718b --- /dev/null +++ b/.github/templates/batches/design.md @@ -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 +- + +## Reference Doc Update Plan +- project-structure.md: <갱신 계획 또는 none> +- runtime-flows.md: <갱신 계획 또는 none> diff --git a/.github/templates/batches/implementation.md b/.github/templates/batches/implementation.md new file mode 100644 index 0000000..d69112e --- /dev/null +++ b/.github/templates/batches/implementation.md @@ -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 +- <잔여 이슈> diff --git a/.github/templates/batches/index.md b/.github/templates/batches/index.md new file mode 100644 index 0000000..158750c --- /dev/null +++ b/.github/templates/batches/index.md @@ -0,0 +1,10 @@ +# Batch Index + +## 목적 +- 이 문서는 batch delivery 단위의 전역 인덱스다. +- 각 batch는 `docs/batches//` 아래에서 profile(`standard` | `batch-lite`)에 맞는 산출물을 관리한다. + +## Batch Register + +| BAT ID | Profile | Status | Included REQ | Discovery | Folder | +| --- | --- | --- | --- | --- | --- | diff --git a/.github/templates/batches/planning.md b/.github/templates/batches/planning.md new file mode 100644 index 0000000..324adbd --- /dev/null +++ b/.github/templates/batches/planning.md @@ -0,0 +1,28 @@ +# {{BAT_ID}} Planning + +- Status: draft | confirmed +- Batch: {{BAT_ID}} +- Profile: standard | batch-lite + +## Included REQ +- + +## Delivery Plan +- <구현 범위, 순서, 선행 조건> + +## Dependencies +- Internal: + - <내부 의존성> +- External: + - <외부 의존성> + +## Design Gate +- Design Required Before Implementation: yes | no +- Reason: <왜 즉시 design이 필요한지 또는 왜 생략 가능한지> + +## Milestones +1. <마일스톤> +2. <마일스톤> + +## Risks +- <리스크와 대응> diff --git a/.github/templates/batches/verification.md b/.github/templates/batches/verification.md new file mode 100644 index 0000000..0a7971e --- /dev/null +++ b/.github/templates/batches/verification.md @@ -0,0 +1,21 @@ +# {{BAT_ID}} Verification + +- Status: draft | confirmed +- Batch: {{BAT_ID}} + +## Acceptance Mapping +- : + - + +## Evidence +- Test: + - <테스트 결과> +- Manual: + - <수동 검증 결과> +- Logs: + - <로그 또는 스크린샷 경로> + +## Result +- Ready for Release: false +- Blocking Issues: + - <차단 이슈 또는 없음> diff --git a/.github/templates/bootstrap/baseline-seed.yaml b/.github/templates/bootstrap/baseline-seed.yaml new file mode 100644 index 0000000..41c3cbf --- /dev/null +++ b/.github/templates/bootstrap/baseline-seed.yaml @@ -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}} \ No newline at end of file diff --git a/.github/templates/data-model.md b/.github/templates/data-model.md new file mode 100644 index 0000000..9832d0b --- /dev/null +++ b/.github/templates/data-model.md @@ -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: `{{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:- :: :: }} + +### Relationships + +{{ENTITY_RELATIONSHIPS_1:- :: }} + +### State Rules + +{{ENTITY_STATE_RULES_1:- }} + +## 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:- :: :: }} + +### Relationships + +{{ENTITY_RELATIONSHIPS_2:- :: }} + +### State Rules + +{{ENTITY_STATE_RULES_2:- }} + +## Shared Consistency Rules + +{{CONSISTENCY_RULE_BULLETS:- - }} + +## Persistence / Integration Notes + +{{PERSISTENCE_NOTES_BULLETS:- - }} + +## Current Gaps / Planned Changes + +{{MODEL_CURRENT_GAPS_BULLETS:- - }} + +## 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:- - }} \ No newline at end of file diff --git a/.github/templates/sdlc/1_discovery.md b/.github/templates/discovery/discovery.md similarity index 84% rename from .github/templates/sdlc/1_discovery.md rename to .github/templates/discovery/discovery.md index b701b8b..dc3c13d 100644 --- a/.github/templates/sdlc/1_discovery.md +++ b/.github/templates/discovery/discovery.md @@ -2,16 +2,19 @@ 이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다. - 상태: {{DOC_STATUS:draft|review|confirmed}} -- 문서 ID: {{CYCLE_ID:sdlc-<3자리>__}} +- 문서 ID: {{DISCOVERY_ID:dcy-<3자리>__}} - 이슈명: {{ISSUE_NAME:짧은 한글 또는 영문 이슈명}} - 작성 시각(KST): {{CREATED_AT_KST:TBD}} - 마지막 갱신 시각(KST): {{UPDATED_AT_KST:TBD}} +- 대체됨: {{SUPERSEDED_BY_DISCOVERY:없음 또는 docs/discovery/.md}} +- 후속 Discovery 참조: {{FOLLOW_UP_DISCOVERY_REF:없음 또는 docs/discovery/.md}} +- 생성된 REQ 참조: 없음 # 1. 계획 상태 요약 현재 Discovery가 어떤 배경에서 작성되고 있는지, 연계 문서가 있는지, 지금 시점의 해석이 무엇인지 짧게 요약한다. - 연계 문서 현황: - - Planning 점수 파일: {{PLANNING_SCORE_FILE:미생성 또는 경로}} + - 관련 점수 파일: {{RELATED_SCORE_FILE:미생성 또는 경로}} - 관련 TODO/메모: {{TODO_FILE:경로 또는 없음}} - 해석: - {{SUMMARY_LINE_1:현재 검토/작성 배경 요약}} @@ -25,7 +28,7 @@ - {{CLASSIFICATION_REASON_1}} - {{CLASSIFICATION_REASON_2}} -> **판정이 `완전 중복`인 경우**: 이하 섹션 작성을 중단하고 `# 9. 파일 처리 결과`에 중복 판정 사유와 참조 문서 경로를 기록한 뒤 문서를 닫는다. Planning으로 넘기지 않는다. +> **판정이 `완전 중복`인 경우**: 이하 섹션 작성을 중단하고 `# 9. 파일 처리 결과`에 중복 판정 사유와 참조 문서 경로를 기록한 뒤 문서를 닫는다. REQ 초안 작성으로 넘기지 않는다. # 3. 문제점의 요약 문제의 현재 상태, 기대 상태, 관련 이해관계자, 제약사항을 정리한다. Discovery의 핵심 맥락을 가장 먼저 이해할 수 있어야 한다. @@ -59,10 +62,10 @@ - {{CHANGE_ITEM_3:필요 없으면 삭제}} ## 영향 범위 -변경이 미칠 코드/문서/운영 범위를 명시해 Planning에서 추정 누락을 줄인다. +변경이 미칠 코드/문서/운영 범위를 명시해 REQ 정제와 batch planning에서 추정 누락을 줄인다. - 코드 영향: - - {{CODE_IMPACT_1:예. docs/sdlc/index.md 갱신 로직}} + - {{CODE_IMPACT_1:예. docs/discovery/index.md 갱신 로직}} - {{CODE_IMPACT_2:필요 없으면 삭제}} - 문서 영향: - {{DOC_IMPACT_1}} @@ -116,7 +119,7 @@ - A-3: {{ASSUMPTION_3:필요 없으면 삭제}} ## 오픈 질문 -답을 아직 모르는 항목을 적는다. 추정으로 덮지 말고 Planning 이전에 확인할 질문으로 남긴다. +답을 아직 모르는 항목을 적는다. 추정으로 덮지 말고 REQ 초안 작성 이전에 확인할 질문으로 남긴다. - OQ-1: {{OPEN_QUESTION_1}} - 상태: {{OPEN_QUESTION_STATUS_1:Open|Answered|Deferred|Dropped}} @@ -138,7 +141,7 @@ - `Dropped`: 더 이상 유효하지 않은 질문이다. 삭제 사유를 짧게 남기고 목록에서 제거한다. - 처리 원칙 1: 질문만 남기지 말고 반드시 `상태`, `처리 방안`, `종료 조건`을 함께 적는다. - 처리 원칙 2: 답이 나온 질문은 본문 반영 없이 단순 삭제하지 않는다. 반영 위치를 먼저 갱신한다. -- 처리 원칙 3: High 영향 질문은 `Deferred` 처리 후 처리 방안에 Planning 인계 추적 방식을 명시한다. +- 처리 원칙 3: High 영향 질문은 `Deferred` 처리 후 처리 방안에 REQ 인계 추적 방식을 명시한다. # 7. 초기 성공 기준 이 변경이 성공했다고 판단할 기준을 측정 가능하게 정의한다. 가능하면 데이터 출처까지 연결한다. @@ -154,8 +157,8 @@ - S-2 측정 방식: {{MEASURE_METHOD_2}} / 데이터 출처: {{MEASURE_SOURCE_2}} - S-3 측정 방식: {{MEASURE_METHOD_3:필요 없으면 삭제}} / 데이터 출처: {{MEASURE_SOURCE_3:필요 없으면 삭제}} -# 8. Planning으로 넘기기 전 확인 체크 -Planning 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. 미완료 항목은 후속 결정이 필요함을 뜻한다. +# 8. REQ로 넘기기 전 확인 체크 +REQ 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. 미완료 항목은 후속 결정이 필요함을 뜻한다. - [ ] 범위(In Scope/Out of Scope) 확정 - 기준: {{CHECK_SCOPE_CRITERIA}} @@ -194,19 +197,19 @@ Planning 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인 - {{DATA_ITEM_2:필요 없으면 삭제}} # 11. Discovery Freeze -Planning 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다. +REQ 초안 작성 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다. ## 섹션 참조 - 범위: [# 5. 요구사항 목록 > 범위 경계](#5-요구사항-목록) - 리스크/오픈 질문: [# 6. 리스크/가정 목록](#6-리스크가정-목록) - 성공 기준: [# 7. 초기 성공 기준](#7-초기-성공-기준) -- 인계 전 확인: [# 8. Planning으로 넘기기 전 확인 체크](#8-planning으로-넘기기-전-확인-체크) +- 인계 전 확인: [# 8. REQ로 넘기기 전 확인 체크](#8-req로-넘기기-전-확인-체크) - 사용자 결정 필요: [# 10. 사용자 결정 필요 항목 요약](#10-사용자-결정-필요-항목-요약) ## Freeze 플래그 -- Handoff Decision: {{FREEZE_HANDOFF_DECISION:Planning 진행 가능|보류}} +- Handoff Decision: {{FREEZE_HANDOFF_DECISION:REQ Drafting 진행 가능|보류}} - Handoff Rationale: {{FREEZE_HANDOFF_RATIONALE:진행 가능 또는 보류 판단 근거 1-2줄}} -- Ready for Planning: {{READY_FOR_PLANNING:false}} +- Ready for REQ Drafting: {{READY_FOR_REQ_DRAFTING:false}} - Confirmed By: {{CONFIRMED_BY:TBD}} - Confirmed At (KST): {{CONFIRMED_AT_KST:TBD}} @@ -216,4 +219,6 @@ Planning 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내 - 이 파일은 템플릿이다. 실제 문서 작성 시 `{{...}}` 플레이스홀더를 구체 값으로 교체한다. - 필요 없는 항목은 삭제하고, 부족한 항목은 같은 형식으로 추가한다. - Open Questions는 가정으로 대체하지 말고 그대로 유지한다. -- Discovery Freeze는 문서 하단에 반드시 유지한다. +- `대체됨`은 현재 Discovery가 더 이상 기준 문서가 아닐 때 대체 Discovery 경로를 기록하고, 해당 사항이 없으면 `없음`으로 둔다. +- `후속 Discovery 참조`는 범위를 이어받는 별도 Discovery가 생성된 경우 그 Discovery 경로를 기록하고, 없으면 `없음`으로 둔다. +- Discovery Freeze는 문서 하단에 반드시 유지한다. \ No newline at end of file diff --git a/.github/templates/discovery/index.md b/.github/templates/discovery/index.md new file mode 100644 index 0000000..8c9f028 --- /dev/null +++ b/.github/templates/discovery/index.md @@ -0,0 +1,8 @@ +# Discovery 전체 인덱스 + + + +## Discovery 목록 + +| ID | 날짜 | 이슈명 | 문서 | 상태 | +|---|---|---|---|---| \ No newline at end of file diff --git a/.github/templates/interface-contract.md b/.github/templates/interface-contract.md new file mode 100644 index 0000000..9b039b9 --- /dev/null +++ b/.github/templates/interface-contract.md @@ -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: `{{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:- :: }} + +### Outputs + +{{INTERFACE_OUTPUTS_1:- :: }} + +### Error Contract + +{{INTERFACE_ERRORS_1:- :: }} + +### Compatibility Rules + +{{INTERFACE_COMPATIBILITY_1:- }} + +## 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:- :: }} + +### Outputs + +{{INTERFACE_OUTPUTS_2:- :: }} + +### Error Contract + +{{INTERFACE_ERRORS_2:- :: }} + +### Compatibility Rules + +{{INTERFACE_COMPATIBILITY_2:- }} + +## Shared Constraints + +{{INTERFACE_SHARED_CONSTRAINTS_BULLETS:- - }} + +## Current Gaps / Planned Changes + +{{INTERFACE_CURRENT_GAPS_BULLETS:- - }} + +## 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:- - }} \ No newline at end of file diff --git a/.github/templates/project-structure.md b/.github/templates/project-structure.md new file mode 100644 index 0000000..bfda5f0 --- /dev/null +++ b/.github/templates/project-structure.md @@ -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:- +- }} + +## Primary Runtime +- Type: {{PRIMARY_RUNTIME:cli|api-service|web-app|worker|library|mixed|other}} +- Planned Entry Points: +{{PRIMARY_ENTRYPOINT_BULLETS:- :: }} + +## 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:}} +``` + +## Package / Module Responsibilities + +{{MODULE_RESPONSIBILITY_BULLETS:- `` + - }} + +## Dependency Rules + +{{DEPENDENCY_RULE_BULLETS:- }} + +## Shared Boundaries + +{{SHARED_BOUNDARY_BULLETS:- }} + +## Current Gaps / Planned Changes + +{{CURRENT_GAPS_BULLETS:- }} + +## 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:- - }} diff --git a/.github/templates/releases/index.md b/.github/templates/releases/index.md new file mode 100644 index 0000000..1b66789 --- /dev/null +++ b/.github/templates/releases/index.md @@ -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 | +| --- | --- | --- | --- | --- | --- | diff --git a/.github/templates/releases/release.md b/.github/templates/releases/release.md new file mode 100644 index 0000000..ce1e43c --- /dev/null +++ b/.github/templates/releases/release.md @@ -0,0 +1,92 @@ +# {{REL_ID}}: <릴리즈 제목> + +- Status: draft | confirmed | released | feedback-captured +- Profile: docs-only | tooling | app-service +- Included Batch: + +## 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: + - + - Request Log Fields: + - + - Smoke or Manual Verification: + - <배포 후 재실행한 검증과 결과> + +### Rollback Outcome +- Rollback Required: + - +- Rollback Trigger: + - <발생 시 원인, 없으면 none> +- Rollback Action: + - <수행한 조치, 없으면 none> + +### Release Decision Evidence +- Released Decision: + - +- Rationale: + - +- Recorded By: + - <기록자> +- Recorded At: + - <기록 시각> + +## Feedback Handoff +- Observation Summary: + - <운영 관찰 사실 요약 또는 없음> +- Discovery Input: + - <후속 discovery 후보> +- REQ Input: + - <후속 req 후보> +- Change Request Input: + - <기존 req 변경 후보> \ No newline at end of file diff --git a/.github/templates/runtime-flows.md b/.github/templates/runtime-flows.md new file mode 100644 index 0000000..90078f1 --- /dev/null +++ b/.github/templates/runtime-flows.md @@ -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:- :: }} + +## Shared Components + +{{SHARED_COMPONENT_BULLETS:- }} + +## Flow: `{{FLOW_NAME_1:bootstrap or first runtime flow}}` + +{{FLOW_STEPS_1:1. +2. +3. }} + +## Flow: `{{FLOW_NAME_2:secondary runtime flow or operation}}` + +{{FLOW_STEPS_2:1. +2. +3. }} + +## Flow Constraints + +{{FLOW_CONSTRAINT_BULLETS:- }} + +## Current Gaps / Planned Changes + +{{CURRENT_GAPS_BULLETS:- }} + +## 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:- - }} diff --git a/.github/templates/sdlc/2_planning.md b/.github/templates/sdlc/2_planning.md deleted file mode 100644 index cd346f2..0000000 --- a/.github/templates/sdlc/2_planning.md +++ /dev/null @@ -1,205 +0,0 @@ -# 0. 문서 상태 -이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다. - -- 상태: {{DOC_STATUS:draft|review|confirmed}} -- 문서 ID: {{CYCLE_ID:sdlc-<3자리>__}} -- 이슈명: {{ISSUE_NAME:짧은 한글 또는 영문 이슈명}} -- 참조 Discovery: {{DISCOVERY_PATH:docs/sdlc//1_discovery.md}} -- 작성 시각(KST): {{CREATED_AT_KST:TBD}} -- 마지막 갱신 시각(KST): {{UPDATED_AT_KST:TBD}} - -# 1. Discovery 인계 요약 -Discovery에서 확정된 핵심 내용을 요약한다. 원본은 1_discovery.md를 참조하며, 이 섹션은 Planning 작업의 입력 기준선이 된다. - -## 이슈 목적 -- {{PLANNING_ISSUE_PURPOSE:Discovery 이슈명과 핵심 목적 1-2줄}} - -## 확정 범위 -- In Scope - - {{PLANNING_IN_SCOPE_1}} - - {{PLANNING_IN_SCOPE_2}} -- Out of Scope - - {{PLANNING_OUT_OF_SCOPE_1}} - - {{PLANNING_OUT_OF_SCOPE_2}} - -## 기능 요구사항 (FR) 요약 -- FR-1: {{PLANNING_FR_1}} -- FR-2: {{PLANNING_FR_2}} -- FR-3: {{PLANNING_FR_3:필요 없으면 삭제}} -- FR-4: {{PLANNING_FR_4:필요 없으면 삭제}} - -## 비기능 요구사항 (NFR) 요약 -- NFR-1: {{PLANNING_NFR_1}} -- NFR-2: {{PLANNING_NFR_2:필요 없으면 삭제}} - -## 이월된 오픈 질문 / 리스크 -Discovery에서 `Deferred` 처리되어 Planning 단계에서 해소해야 하는 항목을 기록한다. - -- {{DEFERRED_ITEM_1:없으면 "없음"}} -- {{DEFERRED_ITEM_2:필요 없으면 삭제}} - -# 2. 작업 분해 (Task Breakdown) -FR/NFR 각각을 실행 가능한 단위 태스크로 분해한다. 각 태스크는 하나의 완료 조건을 가져야 한다. - -| ID | 태스크 제목 | 유형 | 참조 요구사항 | 의존 태스크 | 담당자 | -|-----|-----------|------|--------------|------------|--------| -| T-1 | {{TASK_TITLE_1}} | {{TASK_TYPE_1:개발\|문서\|검토\|설계\|운영}} | {{TASK_REF_1:FR-1}} | - | {{TASK_OWNER_1:TBD}} | -| T-2 | {{TASK_TITLE_2}} | {{TASK_TYPE_2:개발\|문서\|검토\|설계\|운영}} | {{TASK_REF_2:FR-2}} | {{TASK_DEP_2:-}} | {{TASK_OWNER_2:TBD}} | -| T-3 | {{TASK_TITLE_3:필요 없으면 삭제}} | {{TASK_TYPE_3:개발\|문서\|검토\|설계\|운영}} | {{TASK_REF_3}} | {{TASK_DEP_3:-}} | {{TASK_OWNER_3:TBD}} | -| T-4 | {{TASK_TITLE_4:필요 없으면 삭제}} | {{TASK_TYPE_4:개발\|문서\|검토\|설계\|운영}} | {{TASK_REF_4}} | {{TASK_DEP_4:-}} | {{TASK_OWNER_4:TBD}} | - -## 태스크 완료 조건 (DoD) -각 태스크의 완료 기준을 명시한다. - -- T-1: {{TASK_DOD_1}} -- T-2: {{TASK_DOD_2}} -- T-3: {{TASK_DOD_3:필요 없으면 삭제}} -- T-4: {{TASK_DOD_4:필요 없으면 삭제}} - -# 3. 공수 추정 -각 태스크의 예상 공수를 적는다. 단위는 팀 기준에 맞게 선택한다(SP 또는 시간). - -| ID | 태스크 제목 | 추정 공수 | 추정 단위 | 비고 | -|-----|-----------|---------|---------|------| -| T-1 | {{TASK_TITLE_1}} | {{EFFORT_1}} | {{EFFORT_UNIT:SP\|시간\|일}} | {{EFFORT_NOTE_1:필요 없으면 삭제}} | -| T-2 | {{TASK_TITLE_2}} | {{EFFORT_2}} | {{EFFORT_UNIT}} | {{EFFORT_NOTE_2:필요 없으면 삭제}} | -| T-3 | {{TASK_TITLE_3:필요 없으면 삭제}} | {{EFFORT_3}} | {{EFFORT_UNIT}} | {{EFFORT_NOTE_3:필요 없으면 삭제}} | -| T-4 | {{TASK_TITLE_4:필요 없으면 삭제}} | {{EFFORT_4}} | {{EFFORT_UNIT}} | {{EFFORT_NOTE_4:필요 없으면 삭제}} | - -- 총 추정 공수: {{TOTAL_EFFORT}} -- 추정 신뢰도: {{EFFORT_CONFIDENCE:High|Medium|Low}} -- 추정 근거: {{EFFORT_BASIS:추정에 사용한 방법 또는 유사 사례}} - -# 4. 일정 계획 -이터레이션 또는 스프린트 단위로 태스크 배분 계획을 적는다. - -## 마일스톤 -| 마일스톤 | 목표 날짜 | 포함 태스크 | 완료 조건 | -|---------|---------|-----------|---------| -| M-1: {{MILESTONE_1_NAME}} | {{MILESTONE_1_DATE:TBD}} | {{MILESTONE_1_TASKS:T-1, T-2}} | {{MILESTONE_1_DONE}} | -| M-2: {{MILESTONE_2_NAME:필요 없으면 삭제}} | {{MILESTONE_2_DATE:TBD}} | {{MILESTONE_2_TASKS}} | {{MILESTONE_2_DONE}} | - -## 이터레이션 계획 -- 이터레이션 단위: {{ITERATION_UNIT:스프린트|주|없음(단일 배포)}} -- 이터레이션 1 ({{ITERATION_1_PERIOD:날짜 범위 또는 TBD}}): {{ITERATION_1_TASKS:T-1, T-2}} -- 이터레이션 2 ({{ITERATION_2_PERIOD:날짜 범위 또는 TBD}}): {{ITERATION_2_TASKS:T-3, T-4}} - -# 5. 의존성 및 제약 -태스크 간 의존 관계와 외부 의존성을 기록한다. - -## 태스크 간 의존성 -- {{TASK_DEPENDENCY_1:예. T-2는 T-1 완료 후 시작 가능}} -- {{TASK_DEPENDENCY_2:필요 없으면 삭제}} - -## 외부 의존성 -다른 팀, 시스템, 도구에 의존하는 항목을 적는다. - -- {{EXTERNAL_DEP_1:예. CI/CD 파이프라인 설정 필요}} -- {{EXTERNAL_DEP_2:필요 없으면 삭제}} - -## 기술/환경 제약 -- {{TECH_CONSTRAINT_1}} -- {{TECH_CONSTRAINT_2:필요 없으면 삭제}} - -# 6. 검증 계획 개요 -Discovery의 성공 기준과 연결해 어떻게 검증할지 초안을 적는다. 상세 검증은 Verification 단계에서 정의한다. - -| 성공 기준 | 검증 방법 초안 | 담당자 | -|---------|-------------|--------| -| {{VERIFY_CRITERIA_1:S-1 요약}} | {{VERIFY_METHOD_1}} | {{VERIFY_OWNER_1:TBD}} | -| {{VERIFY_CRITERIA_2:S-2 요약}} | {{VERIFY_METHOD_2}} | {{VERIFY_OWNER_2:TBD}} | -| {{VERIFY_CRITERIA_3:S-3 요약 또는 삭제}} | {{VERIFY_METHOD_3}} | {{VERIFY_OWNER_3:TBD}} | - -# 7. 리스크 -Planning 단계에서 새로 식별된 리스크를 기록한다. Discovery에서 이월된 리스크는 `# 1` 이월 항목에서 확인한다. - -## 리스크 -- R-1 ({{PLAN_RISK_LEVEL_1:High|Medium|Low}}): {{PLAN_RISK_1}} - - 완화 방안: {{PLAN_MITIGATION_1}} -- R-2 ({{PLAN_RISK_LEVEL_2:High|Medium|Low}}): {{PLAN_RISK_2:필요 없으면 삭제}} - - 완화 방안: {{PLAN_MITIGATION_2:필요 없으면 삭제}} - -## 가정 -Planning 수행의 전제가 되는 가정을 적는다. - -- PA-1: {{PLAN_ASSUMPTION_1}} -- PA-2: {{PLAN_ASSUMPTION_2:필요 없으면 삭제}} - -## 오픈 질문 -Planning 진행 중 확인이 필요한 질문을 적는다. - -- OQ-1: {{PLAN_OPEN_QUESTION_1}} - - 상태: {{PLAN_OQ_STATUS_1:Open|Answered|Deferred|Dropped}} - - 처리 방안: {{PLAN_OQ_ACTION_1}} - - 종료 조건: {{PLAN_OQ_EXIT_1}} -- OQ-2: {{PLAN_OPEN_QUESTION_2:필요 없으면 삭제}} - - 상태: {{PLAN_OQ_STATUS_2:Open|Answered|Deferred|Dropped}} - - 처리 방안: {{PLAN_OQ_ACTION_2}} - - 종료 조건: {{PLAN_OQ_EXIT_2}} - -# 8. Design으로 넘기기 전 확인 체크 -Design 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. - -- [ ] 전체 태스크 목록 확정 및 담당자 지정 - - 기준: {{CHECK_TASKS_CRITERIA:모든 태스크에 담당자가 지정되어야 한다}} -- [ ] 공수 추정 완료 및 총 공수 확인 - - 기준: {{CHECK_EFFORT_CRITERIA:모든 태스크의 추정 공수가 채워져야 한다}} -- [ ] 마일스톤 및 이터레이션 계획 확정 - - 기준: {{CHECK_SCHEDULE_CRITERIA:M-1 이상의 마일스톤과 이터레이션 경계가 정의되어야 한다}} -- [ ] 외부 의존성 해소 계획 확인 - - 기준: {{CHECK_DEP_CRITERIA:외부 의존성 각 항목에 담당자 또는 해소 방안이 있어야 한다}} -- [ ] 모든 오픈 질문(OQ) `Open` 상태 없음 확인 - - 기준: OQ 목록에 `Open` 상태 항목이 0개이거나, 잔여 항목 전부 `Deferred` 처리 완료 -- [ ] Freeze 확정 담당자(CONFIRMED_BY) 지정 - - 기준: {{CHECK_CONFIRMEDBY_CRITERIA:문서 승인 또는 인계 결정을 내릴 담당자가 명시되어야 한다}} - -# 9. 파일 처리 결과 -이 Planning 문서 생성/갱신 결과와 참조 문서를 기록한다. - -- 처리 결과: {{FILE_RESULT:생성|갱신|미생성}} -- 생성 경로: {{OUTPUT_PATH}} -- 참조 문서: - - {{DISCOVERY_PATH:docs/sdlc//1_discovery.md}} - - {{REFERENCE_1:필요 없으면 삭제}} - -# 10. 사용자 결정 필요 항목 요약 -사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. - -## DECIDE -- {{DECIDE_ITEM_1}} -- {{DECIDE_ITEM_2:필요 없으면 삭제}} - -## CONFIRM -- {{CONFIRM_ITEM_1}} -- {{CONFIRM_ITEM_2:필요 없으면 삭제}} - -## DATA -- {{DATA_ITEM_1}} -- {{DATA_ITEM_2:필요 없으면 삭제}} - -# 11. Planning Freeze -Design 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다. - -## 섹션 참조 -- 작업 분해: [# 2. 작업 분해](#2-작업-분해-task-breakdown) -- 공수/일정: [# 3. 공수 추정](#3-공수-추정), [# 4. 일정 계획](#4-일정-계획) -- 의존성: [# 5. 의존성 및 제약](#5-의존성-및-제약) -- 검증 계획: [# 6. 검증 계획 개요](#6-검증-계획-개요) -- 리스크/오픈 질문: [# 7. 리스크](#7-리스크) -- 인계 전 확인: [# 8. Design으로 넘기기 전 확인 체크](#8-design으로-넘기기-전-확인-체크) -- 사용자 결정 필요: [# 10. 사용자 결정 필요 항목 요약](#10-사용자-결정-필요-항목-요약) - -## Freeze 플래그 -- Handoff Decision: {{FREEZE_HANDOFF_DECISION:Design 진행 가능|보류}} -- Handoff Rationale: {{FREEZE_HANDOFF_RATIONALE:진행 가능 또는 보류 판단 근거 1-2줄}} -- Ready for Design: {{READY_FOR_DESIGN:false}} -- Confirmed By: {{CONFIRMED_BY:TBD}} -- Confirmed At (KST): {{CONFIRMED_AT_KST:TBD}} - -# 12. 작성 가이드 -템플릿 사용 시의 기본 규칙을 적는다. 실제 문서를 만들 때는 이 가이드를 기준으로 플레이스홀더를 치환한다. - -- 이 파일은 템플릿이다. 실제 문서 작성 시 `{{...}}` 플레이스홀더를 구체 값으로 교체한다. -- 필요 없는 태스크/마일스톤 행은 삭제하고, 부족한 항목은 같은 형식으로 추가한다. -- 공수 추정은 팀 기준 단위(SP/시간/일)를 통일해서 사용한다. -- Planning Freeze는 문서 하단에 반드시 유지한다. diff --git a/.github/templates/sdlc/3_design.md b/.github/templates/sdlc/3_design.md deleted file mode 100644 index 4dd5ded..0000000 --- a/.github/templates/sdlc/3_design.md +++ /dev/null @@ -1,187 +0,0 @@ -# 0. 문서 상태 -이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다. - -- 상태: {{DOC_STATUS:draft|review|confirmed}} -- 문서 ID: {{CYCLE_ID:sdlc-<3자리>__}} -- 이슈명: {{ISSUE_NAME:짧은 한글 또는 영문 이슈명}} -- 참조 Planning: {{PLANNING_PATH:docs/sdlc//2_planning.md}} -- 작성 시각(KST): {{CREATED_AT_KST:TBD}} -- 마지막 갱신 시각(KST): {{UPDATED_AT_KST:TBD}} - -# 1. Planning 인계 요약 -Planning에서 확정된 핵심 내용을 요약한다. 원본은 2_planning.md를 참조하며, 이 섹션은 Design 작업의 입력 기준선이 된다. - -## 이슈 목적 -- {{DESIGN_ISSUE_PURPOSE:Planning 이슈명과 핵심 목적 1-2줄}} - -## 확정 태스크 목록 -| ID | 태스크 제목 | 참조 요구사항 | 담당자 | -|----|-----------|------------|--------| -| T-1 | {{DESIGN_TASK_TITLE_1}} | {{DESIGN_TASK_REF_1}} | {{DESIGN_TASK_OWNER_1:TBD}} | -| T-2 | {{DESIGN_TASK_TITLE_2}} | {{DESIGN_TASK_REF_2}} | {{DESIGN_TASK_OWNER_2:TBD}} | -| T-3 | {{DESIGN_TASK_TITLE_3:필요 없으면 삭제}} | {{DESIGN_TASK_REF_3}} | {{DESIGN_TASK_OWNER_3:TBD}} | - -## 이월된 오픈 질문 / 리스크 -Planning에서 `Deferred` 처리되어 Design 단계에서 해소해야 하는 항목을 기록한다. - -- {{DESIGN_DEFERRED_ITEM_1:없으면 "없음"}} -- {{DESIGN_DEFERRED_ITEM_2:필요 없으면 삭제}} - -# 2. 아키텍처 및 구조 설계 -변경이 미치는 전체 구조와 주요 컴포넌트 관계를 설명한다. - -## 전체 구조 개요 -{{ARCH_OVERVIEW:시스템/모듈/파일 구조를 개요 수준으로 설명. 다이어그램 또는 목록 형태 모두 가능}} - -## 주요 컴포넌트 -| 컴포넌트 | 역할 | 영향 범위 | -|---------|------|---------| -| {{COMPONENT_1_NAME}} | {{COMPONENT_1_ROLE}} | {{COMPONENT_1_SCOPE}} | -| {{COMPONENT_2_NAME}} | {{COMPONENT_2_ROLE}} | {{COMPONENT_2_SCOPE}} | -| {{COMPONENT_3_NAME:필요 없으면 삭제}} | {{COMPONENT_3_ROLE}} | {{COMPONENT_3_SCOPE}} | - -## 데이터 흐름 -변경과 관련된 주요 데이터 흐름 또는 처리 순서를 적는다. 복잡하면 단계별 목록으로 표현한다. - -- {{DATA_FLOW_1}} -- {{DATA_FLOW_2}} -- {{DATA_FLOW_3:필요 없으면 삭제}} - -# 3. 상세 설계 -태스크(T-N)별로 구체적인 구현/변경 방법을 기술한다. - -## T-1: {{DESIGN_TASK_TITLE_1}} -- 설계 방향: {{DESIGN_DETAIL_1}} -- 변경 대상: {{DESIGN_TARGET_1:파일 경로, 함수명, 설정 키 등}} -- 입력/출력: {{DESIGN_IO_1:입력값과 출력값 또는 사이드이펙트}} -- 예외/엣지 케이스: {{DESIGN_EDGE_1:필요 없으면 삭제}} - -## T-2: {{DESIGN_TASK_TITLE_2}} -- 설계 방향: {{DESIGN_DETAIL_2}} -- 변경 대상: {{DESIGN_TARGET_2}} -- 입력/출력: {{DESIGN_IO_2}} -- 예외/엣지 케이스: {{DESIGN_EDGE_2:필요 없으면 삭제}} - -## T-3: {{DESIGN_TASK_TITLE_3:필요 없으면 삭제}} -- 설계 방향: {{DESIGN_DETAIL_3}} -- 변경 대상: {{DESIGN_TARGET_3}} -- 입력/출력: {{DESIGN_IO_3}} -- 예외/엣지 케이스: {{DESIGN_EDGE_3:필요 없으면 삭제}} - -# 4. 인터페이스 정의 -외부 시스템, 모듈 간 계약(API, 이벤트, 파일 포맷 등)을 명시한다. 해당 없으면 "해당 없음"으로 기재한다. - -## API / 함수 시그니처 -- {{INTERFACE_1:예. function foo(bar: string): boolean — 설명}} -- {{INTERFACE_2:필요 없으면 삭제}} - -## 데이터 스키마 / 포맷 -- {{SCHEMA_1:예. { id: string, status: "draft"|"confirmed" } — 설명}} -- {{SCHEMA_2:필요 없으면 삭제}} - -## 이벤트 / 메시지 -- {{EVENT_1:필요 없으면 삭제}} -- {{EVENT_2:필요 없으면 삭제}} - -# 5. 보안 고려사항 -OWASP Top 10 기준으로 이번 변경에서 주의해야 할 보안 항목을 점검한다. - -| 항목 | 해당 여부 | 대응 방안 | -|------|---------|---------| -| 입력값 검증 (Injection) | {{SEC_INJECTION:해당|비해당}} | {{SEC_INJECTION_ACTION:비해당이면 삭제}} | -| 인증/인가 | {{SEC_AUTH:해당|비해당}} | {{SEC_AUTH_ACTION:비해당이면 삭제}} | -| 민감 데이터 노출 | {{SEC_DATA:해당|비해당}} | {{SEC_DATA_ACTION:비해당이면 삭제}} | -| 의존성 취약점 | {{SEC_DEP:해당|비해당}} | {{SEC_DEP_ACTION:비해당이면 삭제}} | -| 기타 | {{SEC_OTHER:필요 없으면 삭제}} | {{SEC_OTHER_ACTION:필요 없으면 삭제}} | - -# 6. 리스크 -Design 단계에서 새로 식별된 리스크를 기록한다. Planning에서 이월된 리스크는 `# 1` 이월 항목에서 확인한다. - -## 리스크 -- R-1 ({{DESIGN_RISK_LEVEL_1:High|Medium|Low}}): {{DESIGN_RISK_1}} - - 완화 방안: {{DESIGN_MITIGATION_1}} -- R-2 ({{DESIGN_RISK_LEVEL_2:High|Medium|Low}}): {{DESIGN_RISK_2:필요 없으면 삭제}} - - 완화 방안: {{DESIGN_MITIGATION_2:필요 없으면 삭제}} - -## 가정 -Design 수행의 전제가 되는 가정을 적는다. - -- DA-1: {{DESIGN_ASSUMPTION_1}} -- DA-2: {{DESIGN_ASSUMPTION_2:필요 없으면 삭제}} - -## 오픈 질문 -Design 진행 중 확인이 필요한 질문을 적는다. - -- OQ-1: {{DESIGN_OPEN_QUESTION_1}} - - 상태: {{DESIGN_OQ_STATUS_1:Open|Answered|Deferred|Dropped}} - - 처리 방안: {{DESIGN_OQ_ACTION_1}} - - 종료 조건: {{DESIGN_OQ_EXIT_1}} -- OQ-2: {{DESIGN_OPEN_QUESTION_2:필요 없으면 삭제}} - - 상태: {{DESIGN_OQ_STATUS_2:Open|Answered|Deferred|Dropped}} - - 처리 방안: {{DESIGN_OQ_ACTION_2}} - - 종료 조건: {{DESIGN_OQ_EXIT_2}} - -# 7. Implementation으로 넘기기 전 확인 체크 -Implementation 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. - -- [ ] 전체 컴포넌트 및 태스크별 설계 완성 - - 기준: {{CHECK_DESIGN_COMPLETE:모든 T-N 태스크에 설계 방향과 변경 대상이 채워져야 한다}} -- [ ] 인터페이스 계약 확정 - - 기준: {{CHECK_INTERFACE:외부 의존 컴포넌트와의 계약이 명시되어야 한다}} -- [ ] 보안 점검 완료 - - 기준: {{CHECK_SECURITY:OWASP 점검 항목 중 해당 항목은 대응 방안이 있어야 한다}} -- [ ] 모든 오픈 질문(OQ) `Open` 상태 없음 확인 - - 기준: OQ 목록에 `Open` 상태 항목이 0개이거나, 잔여 항목 전부 `Deferred` 처리 완료 -- [ ] Freeze 확정 담당자(CONFIRMED_BY) 지정 - - 기준: {{CHECK_CONFIRMEDBY_CRITERIA:문서 승인 또는 인계 결정을 내릴 담당자가 명시되어야 한다}} - -# 8. 파일 처리 결과 -이 Design 문서 생성/갱신 결과와 참조 문서를 기록한다. - -- 처리 결과: {{FILE_RESULT:생성|갱신|미생성}} -- 생성 경로: {{OUTPUT_PATH}} -- 참조 문서: - - {{PLANNING_PATH:docs/sdlc//2_planning.md}} - - {{REFERENCE_1:필요 없으면 삭제}} - -# 9. 사용자 결정 필요 항목 요약 -사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. - -## DECIDE -- {{DECIDE_ITEM_1}} -- {{DECIDE_ITEM_2:필요 없으면 삭제}} - -## CONFIRM -- {{CONFIRM_ITEM_1}} -- {{CONFIRM_ITEM_2:필요 없으면 삭제}} - -## DATA -- {{DATA_ITEM_1}} -- {{DATA_ITEM_2:필요 없으면 삭제}} - -# 10. Design Freeze -Implementation 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다. - -## 섹션 참조 -- 아키텍처/구조: [# 2. 아키텍처 및 구조 설계](#2-아키텍처-및-구조-설계) -- 상세 설계: [# 3. 상세 설계](#3-상세-설계) -- 인터페이스: [# 4. 인터페이스 정의](#4-인터페이스-정의) -- 보안: [# 5. 보안 고려사항](#5-보안-고려사항) -- 리스크/오픈 질문: [# 6. 리스크](#6-리스크) -- 인계 전 확인: [# 7. Implementation으로 넘기기 전 확인 체크](#7-implementation으로-넘기기-전-확인-체크) -- 사용자 결정 필요: [# 9. 사용자 결정 필요 항목 요약](#9-사용자-결정-필요-항목-요약) - -## Freeze 플래그 -- Handoff Decision: {{FREEZE_HANDOFF_DECISION:Implementation 진행 가능|보류}} -- Handoff Rationale: {{FREEZE_HANDOFF_RATIONALE:진행 가능 또는 보류 판단 근거 1-2줄}} -- Ready for Implementation: {{READY_FOR_IMPLEMENTATION:false}} -- Confirmed By: {{CONFIRMED_BY:TBD}} -- Confirmed At (KST): {{CONFIRMED_AT_KST:TBD}} - -# 11. 작성 가이드 -템플릿 사용 시의 기본 규칙을 적는다. 실제 문서를 만들 때는 이 가이드를 기준으로 플레이스홀더를 치환한다. - -- 이 파일은 템플릿이다. 실제 문서 작성 시 `{{...}}` 플레이스홀더를 구체 값으로 교체한다. -- 필요 없는 컴포넌트/태스크 항목은 삭제하고, 부족한 항목은 같은 형식으로 추가한다. -- 보안 고려사항은 "비해당"이라도 근거를 남긴다. -- Design Freeze는 문서 하단에 반드시 유지한다. diff --git a/.github/templates/sdlc/4_implementation.md b/.github/templates/sdlc/4_implementation.md deleted file mode 100644 index 0d3a1a8..0000000 --- a/.github/templates/sdlc/4_implementation.md +++ /dev/null @@ -1,155 +0,0 @@ -# 0. 문서 상태 -이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다. - -- 상태: {{DOC_STATUS:draft|review|confirmed}} -- 문서 ID: {{CYCLE_ID:sdlc-<3자리>__}} -- 이슈명: {{ISSUE_NAME:짧은 한글 또는 영문 이슈명}} -- 참조 Design: {{DESIGN_PATH:docs/sdlc//3_design.md}} -- 작성 시각(KST): {{CREATED_AT_KST:TBD}} -- 마지막 갱신 시각(KST): {{UPDATED_AT_KST:TBD}} - -# 1. Design 인계 요약 -Design에서 확정된 핵심 내용을 요약한다. 원본은 3_design.md를 참조하며, 이 섹션은 Implementation 작업의 입력 기준선이 된다. - -## 이슈 목적 -- {{IMP_ISSUE_PURPOSE:Design 이슈명과 핵심 목적 1-2줄}} - -## 확정 태스크 및 변경 대상 -| ID | 태스크 제목 | 변경 대상 파일/함수 | 담당자 | -|----|-----------|-------------------|--------| -| T-1 | {{IMP_TASK_TITLE_1}} | {{IMP_TASK_TARGET_1}} | {{IMP_TASK_OWNER_1:TBD}} | -| T-2 | {{IMP_TASK_TITLE_2}} | {{IMP_TASK_TARGET_2}} | {{IMP_TASK_OWNER_2:TBD}} | -| T-3 | {{IMP_TASK_TITLE_3:필요 없으면 삭제}} | {{IMP_TASK_TARGET_3}} | {{IMP_TASK_OWNER_3:TBD}} | - -## 이월된 오픈 질문 / 리스크 -Design에서 `Deferred` 처리되어 Implementation 단계에서 해소해야 하는 항목을 기록한다. - -- {{IMP_DEFERRED_ITEM_1:없으면 "없음"}} -- {{IMP_DEFERRED_ITEM_2:필요 없으면 삭제}} - -# 2. 구현 계획 -태스크(T-N)별 구현 순서와 접근 방법을 기술한다. - -## 구현 순서 -태스크 간 의존 관계와 우선순위를 고려한 구현 순서를 정의한다. - -1. {{IMP_ORDER_1:예. T-1 — 기반 구조 구현 (다른 태스크의 의존 대상)}} -2. {{IMP_ORDER_2:예. T-2 — 핵심 기능 구현}} -3. {{IMP_ORDER_3:필요 없으면 삭제}} - -## T-1: {{IMP_TASK_TITLE_1}} -- 구현 방법: {{IMP_METHOD_1:설계 방향을 실제 코드/설정으로 구현하는 접근}} -- 변경 대상: {{IMP_TARGET_1:실제 파일 경로, 함수명, 설정 키}} -- 완료 조건: {{IMP_DOD_1:이 태스크가 완료된 것으로 간주하는 기준}} -- 주의사항: {{IMP_NOTE_1:구현 중 주의해야 할 사항. 필요 없으면 삭제}} - -## T-2: {{IMP_TASK_TITLE_2}} -- 구현 방법: {{IMP_METHOD_2}} -- 변경 대상: {{IMP_TARGET_2}} -- 완료 조건: {{IMP_DOD_2}} -- 주의사항: {{IMP_NOTE_2:필요 없으면 삭제}} - -## T-3: {{IMP_TASK_TITLE_3:필요 없으면 삭제}} -- 구현 방법: {{IMP_METHOD_3}} -- 변경 대상: {{IMP_TARGET_3}} -- 완료 조건: {{IMP_DOD_3}} -- 주의사항: {{IMP_NOTE_3:필요 없으면 삭제}} - -# 3. 변경 파일 목록 -이번 Implementation에서 생성/수정/삭제되는 파일을 미리 나열한다. 구현 완료 후 실제 결과를 반영해 갱신한다. - -| 파일 경로 | 변경 유형 | 관련 태스크 | 비고 | -|---------|---------|-----------|------| -| {{IMP_FILE_1}} | {{IMP_FILE_TYPE_1:생성\|수정\|삭제}} | {{IMP_FILE_TASK_1:T-1}} | {{IMP_FILE_NOTE_1:필요 없으면 삭제}} | -| {{IMP_FILE_2}} | {{IMP_FILE_TYPE_2:생성\|수정\|삭제}} | {{IMP_FILE_TASK_2}} | {{IMP_FILE_NOTE_2:필요 없으면 삭제}} | -| {{IMP_FILE_3:필요 없으면 삭제}} | {{IMP_FILE_TYPE_3:생성\|수정\|삭제}} | {{IMP_FILE_TASK_3}} | {{IMP_FILE_NOTE_3:필요 없으면 삭제}} | - -# 4. 리스크 및 제약 -Implementation 단계에서 새로 식별된 리스크와 제약사항을 기록한다. - -## 리스크 -- R-1 ({{IMP_RISK_LEVEL_1:High|Medium|Low}}): {{IMP_RISK_1}} - - 완화 방안: {{IMP_MITIGATION_1}} -- R-2 ({{IMP_RISK_LEVEL_2:High|Medium|Low}}): {{IMP_RISK_2:필요 없으면 삭제}} - - 완화 방안: {{IMP_MITIGATION_2:필요 없으면 삭제}} - -## 가정 -Implementation 수행의 전제가 되는 가정을 적는다. - -- IA-1: {{IMP_ASSUMPTION_1}} -- IA-2: {{IMP_ASSUMPTION_2:필요 없으면 삭제}} - -## 오픈 질문 -Implementation 진행 중 확인이 필요한 질문을 적는다. - -- OQ-1: {{IMP_OPEN_QUESTION_1}} - - 상태: {{IMP_OQ_STATUS_1:Open|Answered|Deferred|Dropped}} - - 처리 방안: {{IMP_OQ_ACTION_1}} - - 종료 조건: {{IMP_OQ_EXIT_1}} -- OQ-2: {{IMP_OPEN_QUESTION_2:필요 없으면 삭제}} - - 상태: {{IMP_OQ_STATUS_2:Open|Answered|Deferred|Dropped}} - - 처리 방안: {{IMP_OQ_ACTION_2}} - - 종료 조건: {{IMP_OQ_EXIT_2}} - -# 5. Verification으로 넘기기 전 확인 체크 -Verification 단계로 넘기기 전에 무엇이 완료되어야 하는지 확인한다. - -- [ ] 모든 T-N 태스크 구현 완료 - - 기준: {{CHECK_ALL_TASKS:각 태스크의 완료 조건(DoD)을 충족해야 한다}} -- [ ] 변경 파일 목록과 실제 변경 일치 - - 기준: {{CHECK_FILE_LIST:3_design.md의 변경 대상과 실제 변경된 파일이 일치해야 한다}} -- [ ] 단위 테스트 또는 로컬 검증 완료 - - 기준: {{CHECK_LOCAL_VERIFY:변경 사항이 로컬 환경에서 의도대로 동작하는지 확인해야 한다}} -- [ ] 모든 오픈 질문(OQ) `Open` 상태 없음 확인 - - 기준: OQ 목록에 `Open` 상태 항목이 0개이거나, 잔여 항목 전부 `Deferred` 처리 완료 -- [ ] Freeze 확정 담당자(CONFIRMED_BY) 지정 - - 기준: {{CHECK_CONFIRMEDBY_CRITERIA:문서 승인 또는 인계 결정을 내릴 담당자가 명시되어야 한다}} - -# 6. 파일 처리 결과 -이 Implementation 문서 생성/갱신 결과와 참조 문서를 기록한다. - -- 처리 결과: {{FILE_RESULT:생성|갱신|미생성}} -- 생성 경로: {{OUTPUT_PATH}} -- 참조 문서: - - {{DESIGN_PATH:docs/sdlc//3_design.md}} - - {{REFERENCE_1:필요 없으면 삭제}} - -# 7. 사용자 결정 필요 항목 요약 -사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. - -## DECIDE -- {{DECIDE_ITEM_1}} -- {{DECIDE_ITEM_2:필요 없으면 삭제}} - -## CONFIRM -- {{CONFIRM_ITEM_1}} -- {{CONFIRM_ITEM_2:필요 없으면 삭제}} - -## DATA -- {{DATA_ITEM_1}} -- {{DATA_ITEM_2:필요 없으면 삭제}} - -# 8. Implementation Freeze -Verification 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다. - -## 섹션 참조 -- 구현 계획: [# 2. 구현 계획](#2-구현-계획) -- 변경 파일 목록: [# 3. 변경 파일 목록](#3-변경-파일-목록) -- 리스크/오픈 질문: [# 4. 리스크 및 제약](#4-리스크-및-제약) - -## 확정 플래그 -- Handoff Decision: {{FREEZE_HANDOFF_DECISION:보류}} -- Handoff Rationale: {{FREEZE_HANDOFF_RATIONALE:구현 완료 및 로컬 검증 후 Verification으로 인계}} -- Ready for Verification: {{READY_FOR_VERIFICATION:false}} -- Confirmed By: {{CONFIRMED_BY:TBD}} -- Confirmed At (KST): {{CONFIRMED_AT_KST:TBD}} - ---- - -# 12. 작성 가이드 -*이 섹션은 작성 참고용이다. 문서 완성 후 삭제해도 된다.* - -- **변경 대상 파일 경로**: 실제 저장소 파일 경로를 명시한다. 추정이나 가상 경로를 쓰지 않는다. -- **완료 조건(DoD)**: "구현 완료"처럼 모호한 표현 대신 "파일 X에 함수 Y가 추가되고 입력 Z에 대해 올바른 결과를 반환한다"처럼 측정 가능하게 작성한다. -- **오픈 질문**: 구현 중 발생한 기술적 판단 사항, 외부 확인 필요 항목 등을 기록한다. -- **Freeze 섹션**: 모든 태스크 완료 및 로컬 검증 후 담당자가 직접 갱신한다. diff --git a/.github/templates/sdlc/5_verification.md b/.github/templates/sdlc/5_verification.md deleted file mode 100644 index be15e8b..0000000 --- a/.github/templates/sdlc/5_verification.md +++ /dev/null @@ -1,160 +0,0 @@ -# 0. 문서 상태 -이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다. - -- 상태: {{DOC_STATUS:draft|review|confirmed}} -- 문서 ID: {{CYCLE_ID:sdlc-<3자리>__}} -- 이슈명: {{ISSUE_NAME:짧은 한글 또는 영문 이슈명}} -- 참조 Implementation: {{IMP_PATH:docs/sdlc//4_implementation.md}} -- 작성 시각(KST): {{CREATED_AT_KST:TBD}} -- 마지막 갱신 시각(KST): {{UPDATED_AT_KST:TBD}} - -# 1. Implementation 인계 요약 -Implementation에서 완료된 핵심 내용을 요약한다. 원본은 4_implementation.md를 참조하며, 이 섹션은 Verification 작업의 입력 기준선이 된다. - -## 이슈 목적 -- {{VER_ISSUE_PURPOSE:Implementation 이슈명과 핵심 목적 1-2줄}} - -## 구현 완료 태스크 -| ID | 태스크 제목 | 변경 파일/함수 | 완료 조건(DoD) | -|----|-----------|--------------|--------------| -| T-1 | {{VER_TASK_TITLE_1}} | {{VER_TASK_TARGET_1}} | {{VER_TASK_DOD_1}} | -| T-2 | {{VER_TASK_TITLE_2}} | {{VER_TASK_TARGET_2}} | {{VER_TASK_DOD_2}} | -| T-3 | {{VER_TASK_TITLE_3:필요 없으면 삭제}} | {{VER_TASK_TARGET_3}} | {{VER_TASK_DOD_3}} | - -## 이월된 오픈 질문 / 리스크 -Implementation에서 `Deferred` 처리되어 Verification 단계에서 해소해야 하는 항목을 기록한다. - -- {{VER_DEFERRED_ITEM_1:없으면 "없음"}} -- {{VER_DEFERRED_ITEM_2:필요 없으면 삭제}} - -# 2. 검증 계획 -Discovery `# 7` 성공 기준(S-N)을 기반으로 Verification 항목을 정의한다. - -## 검증 범위 -- {{VER_SCOPE_1:예. 기능 요구사항(FR) 전체 충족 여부}} -- {{VER_SCOPE_2:예. 비기능 요구사항(NFR) 성능 기준 충족 여부}} -- {{VER_SCOPE_3:필요 없으면 삭제}} - -## 검증 항목 -| ID | 검증 항목 | 검증 방법 | 성공 기준 | 담당자 | -|----|---------|---------|---------|--------| -| VC-1 | {{VER_ITEM_1}} | {{VER_METHOD_1:수동\|자동\|혼합}} | {{VER_CRITERIA_1}} | {{VER_OWNER_1:TBD}} | -| VC-2 | {{VER_ITEM_2}} | {{VER_METHOD_2:수동\|자동\|혼합}} | {{VER_CRITERIA_2}} | {{VER_OWNER_2:TBD}} | -| VC-3 | {{VER_ITEM_3:필요 없으면 삭제}} | {{VER_METHOD_3:수동\|자동\|혼합}} | {{VER_CRITERIA_3}} | {{VER_OWNER_3:TBD}} | -| VC-4 | {{VER_ITEM_4:필요 없으면 삭제}} | {{VER_METHOD_4:수동\|자동\|혼합}} | {{VER_CRITERIA_4}} | {{VER_OWNER_4:TBD}} | - -## 성공 기준 연결 -Discovery의 성공 기준(S-N)과 검증 항목(VC-N)의 연결을 명시한다. - -- S-1 → {{VER_S1_LINK:VC-1, VC-2 등}} -- S-2 → {{VER_S2_LINK:VC-3 등}} -- S-3 → {{VER_S3_LINK:필요 없으면 삭제}} - -# 3. 검증 결과 -검증 수행 후 각 항목의 결과를 기록한다. 초안 생성 시 모두 `미완료`로 초기화한다. - -| ID | 검증 항목 | 결과 | 비고 | -|----|---------|------|------| -| VC-1 | {{VER_ITEM_1}} | {{VER_RESULT_1:미완료\|통과\|실패\|블로킹}} | {{VER_RESULT_NOTE_1:필요 없으면 삭제}} | -| VC-2 | {{VER_ITEM_2}} | {{VER_RESULT_2:미완료\|통과\|실패\|블로킹}} | {{VER_RESULT_NOTE_2:필요 없으면 삭제}} | -| VC-3 | {{VER_ITEM_3:필요 없으면 삭제}} | {{VER_RESULT_3:미완료\|통과\|실패\|블로킹}} | {{VER_RESULT_NOTE_3:필요 없으면 삭제}} | - -## 전체 검증 결과 -- 통과: {{VER_PASS_COUNT:0}} / {{VER_TOTAL_COUNT:0}} -- 실패/블로킹: {{VER_FAIL_COUNT:0}} -- 검증 완료 여부: {{VER_COMPLETE:false}} - -# 4. 결함 및 재작업 사항 -검증 중 발견된 결함과 재작업이 필요한 항목을 기록한다. - -- BUG-1: {{BUG_1:없으면 "없음"}} - - 심각도: {{BUG_SEVERITY_1:Critical|High|Medium|Low}} - - 재작업 내용: {{BUG_FIX_1}} - - 상태: {{BUG_STATUS_1:Open|Fixed|Deferred}} -- BUG-2: {{BUG_2:필요 없으면 삭제}} - - 심각도: {{BUG_SEVERITY_2:Critical|High|Medium|Low}} - - 재작업 내용: {{BUG_FIX_2}} - - 상태: {{BUG_STATUS_2:Open|Fixed|Deferred}} - -# 5. 리스크 및 오픈 질문 -Verification 단계에서 새로 식별된 리스크와 오픈 질문을 기록한다. - -## 리스크 -- R-1 ({{VER_RISK_LEVEL_1:High|Medium|Low}}): {{VER_RISK_1}} - - 완화 방안: {{VER_MITIGATION_1}} -- R-2 ({{VER_RISK_LEVEL_2:High|Medium|Low}}): {{VER_RISK_2:필요 없으면 삭제}} - - 완화 방안: {{VER_MITIGATION_2:필요 없으면 삭제}} - -## 오픈 질문 -- OQ-1: {{VER_OPEN_QUESTION_1}} - - 상태: {{VER_OQ_STATUS_1:Open|Answered|Deferred|Dropped}} - - 처리 방안: {{VER_OQ_ACTION_1}} - - 종료 조건: {{VER_OQ_EXIT_1}} -- OQ-2: {{VER_OPEN_QUESTION_2:필요 없으면 삭제}} - - 상태: {{VER_OQ_STATUS_2:Open|Answered|Deferred|Dropped}} - - 처리 방안: {{VER_OQ_ACTION_2}} - - 종료 조건: {{VER_OQ_EXIT_2}} - -# 6. Release로 넘기기 전 확인 체크 -Release 단계로 넘기기 전에 무엇이 완료되어야 하는지 확인한다. - -- [ ] 모든 검증 항목(VC-N) 통과 - - 기준: {{CHECK_ALL_VC:VC 목록의 모든 항목이 "통과" 상태여야 한다}} -- [ ] 결함(BUG) `Open` 상태 없음 - - 기준: {{CHECK_BUGS:BUG 목록에 `Open` 상태 항목이 0개여야 한다. `Deferred`는 근거와 함께 허용}} -- [ ] 성공 기준(S-N) 전체 충족 - - 기준: {{CHECK_SUCCESS_CRITERIA:Discovery에서 정의된 S-N 기준이 모두 VC 항목과 연결되어 통과되었는가}} -- [ ] 모든 오픈 질문(OQ) `Open` 상태 없음 확인 - - 기준: OQ 목록에 `Open` 상태 항목이 0개이거나, 잔여 항목 전부 `Deferred` 처리 완료 -- [ ] Freeze 확정 담당자(CONFIRMED_BY) 지정 - - 기준: {{CHECK_CONFIRMEDBY_CRITERIA:문서 승인 또는 인계 결정을 내릴 담당자가 명시되어야 한다}} - -# 7. 파일 처리 결과 -이 Verification 문서 생성/갱신 결과와 참조 문서를 기록한다. - -- 처리 결과: {{FILE_RESULT:생성|갱신|미생성}} -- 생성 경로: {{OUTPUT_PATH}} -- 참조 문서: - - {{IMP_PATH:docs/sdlc//4_implementation.md}} - - {{REFERENCE_1:필요 없으면 삭제}} - -# 8. 사용자 결정 필요 항목 요약 -사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. - -## DECIDE -- {{DECIDE_ITEM_1}} -- {{DECIDE_ITEM_2:필요 없으면 삭제}} - -## CONFIRM -- {{CONFIRM_ITEM_1}} -- {{CONFIRM_ITEM_2:필요 없으면 삭제}} - -## DATA -- {{DATA_ITEM_1}} -- {{DATA_ITEM_2:필요 없으면 삭제}} - -# 9. Verification Freeze -Release 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다. - -## 섹션 참조 -- 검증 계획: [# 2. 검증 계획](#2-검증-계획) -- 검증 결과: [# 3. 검증 결과](#3-검증-결과) -- 결함/재작업: [# 4. 결함 및 재작업 사항](#4-결함-및-재작업-사항) - -## 확정 플래그 -- Handoff Decision: {{FREEZE_HANDOFF_DECISION:보류}} -- Handoff Rationale: {{FREEZE_HANDOFF_RATIONALE:검증 완료 및 결함 없음 확인 후 Release로 인계}} -- Ready for Release: {{READY_FOR_RELEASE:false}} -- Confirmed By: {{CONFIRMED_BY:TBD}} -- Confirmed At (KST): {{CONFIRMED_AT_KST:TBD}} - ---- - -# 10. 작성 가이드 -*이 섹션은 작성 참고용이다. 문서 완성 후 삭제해도 된다.* - -- **검증 항목(VC-N)**: Discovery 성공 기준(S-N)과 반드시 연결한다. FR/NFR 각 항목이 하나 이상의 VC와 연결되어야 한다. -- **검증 방법**: 수동(테스터가 직접 실행), 자동(CI/테스트 코드), 혼합(일부 자동 + 수동 확인) 중 선택한다. -- **성공 기준**: "정상 동작"처럼 모호한 표현 대신 "입력 X에 대해 결과 Y를 반환한다"처럼 측정 가능하게 작성한다. -- **결함(BUG)**: 검증 중 발견된 모든 문제를 기록한다. `Deferred` 처리 시 근거와 후속 처리 계획을 명시한다. -- **Freeze 섹션**: 모든 VC 통과 및 BUG `Open` 없음 확인 후 담당자가 직접 갱신한다. diff --git a/.github/templates/sdlc/6_release.md b/.github/templates/sdlc/6_release.md deleted file mode 100644 index 2f934be..0000000 --- a/.github/templates/sdlc/6_release.md +++ /dev/null @@ -1,162 +0,0 @@ -# 0. 문서 상태 -이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다. - -- 상태: {{DOC_STATUS:draft|review|confirmed}} -- 문서 ID: {{CYCLE_ID:sdlc-<3자리>__}} -- 이슈명: {{ISSUE_NAME:짧은 한글 또는 영문 이슈명}} -- 참조 Verification: {{VER_PATH:docs/sdlc//5_verification.md}} -- 작성 시각(KST): {{CREATED_AT_KST:TBD}} -- 마지막 갱신 시각(KST): {{UPDATED_AT_KST:TBD}} - -# 1. Verification 인계 요약 -Verification에서 완료된 핵심 내용을 요약한다. 원본은 5_verification.md를 참조하며, 이 섹션은 Release 작업의 입력 기준선이 된다. - -## 이슈 목적 -- {{REL_ISSUE_PURPOSE:Verification 이슈명과 핵심 목적 1-2줄}} - -## 검증 결과 요약 -- 검증 항목 수: {{REL_VC_TOTAL}}개 -- 전체 통과 여부: {{REL_VC_ALL_PASS:true|false}} -- 결함(BUG) 잔여: {{REL_BUG_REMAIN:0}}건 - -## 이월된 오픈 질문 / 리스크 -Verification에서 `Deferred` 처리되어 Release 단계에서 해소해야 하는 항목을 기록한다. - -- {{REL_DEFERRED_ITEM_1:없으면 "없음"}} -- {{REL_DEFERRED_ITEM_2:필요 없으면 삭제}} - -# 2. 배포 준비 -배포 환경, 배포 전 체크리스트, 배포 순서를 정의한다. - -## 배포 환경 -- 대상 환경: {{REL_TARGET_ENV:예. production, staging}} -- 배포 방식: {{REL_DEPLOY_METHOD:예. git push, CI/CD 파이프라인, 수동 복사}} -- 배포 도구/채널: {{REL_DEPLOY_TOOL:예. GitHub Actions, 수동 SSH, 없음}} - -## 배포 전 체크리스트 -배포 실행 전에 확인해야 할 항목을 나열한다. - -- [ ] {{REL_PRE_CHECK_1:예. 대상 환경 설정 파일 백업 완료}} -- [ ] {{REL_PRE_CHECK_2:예. 롤백 계획 확인 완료}} -- [ ] {{REL_PRE_CHECK_3:필요 없으면 삭제}} - -## 배포 순서 -변경 사항의 배포 순서를 적는다. 의존 관계가 있는 경우 순서를 명확히 기술한다. - -1. {{REL_STEP_1:예. 설정 파일 배포}} -2. {{REL_STEP_2:예. 코드 변경 배포}} -3. {{REL_STEP_3:필요 없으면 삭제}} - -# 3. 롤백 계획 -배포 후 문제가 발생했을 때 이전 상태로 되돌리는 방법을 기술한다. - -## 롤백 조건 -아래 조건 중 하나라도 충족되면 롤백을 즉시 실행한다. - -- {{REL_ROLLBACK_TRIGGER_1:예. 배포 후 핵심 기능 오류 발생}} -- {{REL_ROLLBACK_TRIGGER_2:예. 성능 지표가 임계값 이하로 하락}} -- {{REL_ROLLBACK_TRIGGER_3:필요 없으면 삭제}} - -## 롤백 절차 -1. {{REL_ROLLBACK_STEP_1:예. 이전 버전 파일/설정 복원}} -2. {{REL_ROLLBACK_STEP_2:예. 배포 채널에서 롤백 실행}} -3. {{REL_ROLLBACK_STEP_3:필요 없으면 삭제}} - -## 롤백 담당자 -- {{REL_ROLLBACK_OWNER:TBD}} - -# 4. 배포 후 확인 -배포 완료 후 정상 동작을 확인하는 방법을 기술한다. - -## 스모크 테스트 항목 -| 항목 | 확인 방법 | 성공 기준 | -|------|---------|---------| -| {{REL_SMOKE_ITEM_1}} | {{REL_SMOKE_METHOD_1}} | {{REL_SMOKE_CRITERIA_1}} | -| {{REL_SMOKE_ITEM_2}} | {{REL_SMOKE_METHOD_2}} | {{REL_SMOKE_CRITERIA_2}} | -| {{REL_SMOKE_ITEM_3:필요 없으면 삭제}} | {{REL_SMOKE_METHOD_3}} | {{REL_SMOKE_CRITERIA_3}} | - -## 모니터링 확인 항목 -배포 후 일정 시간 동안 모니터링해야 하는 지표나 로그를 기록한다. - -- {{REL_MONITOR_1:예. 오류 로그 발생 여부 확인 (1시간)}} -- {{REL_MONITOR_2:필요 없으면 삭제}} - -# 5. 리스크 및 오픈 질문 -Release 단계에서 새로 식별된 리스크와 오픈 질문을 기록한다. - -## 리스크 -- R-1 ({{REL_RISK_LEVEL_1:High|Medium|Low}}): {{REL_RISK_1}} - - 완화 방안: {{REL_MITIGATION_1}} -- R-2 ({{REL_RISK_LEVEL_2:High|Medium|Low}}): {{REL_RISK_2:필요 없으면 삭제}} - - 완화 방안: {{REL_MITIGATION_2:필요 없으면 삭제}} - -## 오픈 질문 -- OQ-1: {{REL_OPEN_QUESTION_1}} - - 상태: {{REL_OQ_STATUS_1:Open|Answered|Deferred|Dropped}} - - 처리 방안: {{REL_OQ_ACTION_1}} - - 종료 조건: {{REL_OQ_EXIT_1}} -- OQ-2: {{REL_OPEN_QUESTION_2:필요 없으면 삭제}} - - 상태: {{REL_OQ_STATUS_2:Open|Answered|Deferred|Dropped}} - - 처리 방안: {{REL_OQ_ACTION_2}} - - 종료 조건: {{REL_OQ_EXIT_2}} - -# 6. Operations로 넘기기 전 확인 체크 -Operations 단계로 넘기기 전에 무엇이 완료되어야 하는지 확인한다. - -- [ ] 배포 완료 및 스모크 테스트 통과 - - 기준: {{CHECK_DEPLOY:배포 절차대로 실행되었고 스모크 테스트 전 항목이 통과되었는가}} -- [ ] 롤백 계획 확정 - - 기준: {{CHECK_ROLLBACK:롤백 조건, 절차, 담당자가 모두 명시되었는가}} -- [ ] 모든 오픈 질문(OQ) `Open` 상태 없음 확인 - - 기준: OQ 목록에 `Open` 상태 항목이 0개이거나, 잔여 항목 전부 `Deferred` 처리 완료 -- [ ] Freeze 확정 담당자(CONFIRMED_BY) 지정 - - 기준: {{CHECK_CONFIRMEDBY_CRITERIA:문서 승인 또는 인계 결정을 내릴 담당자가 명시되어야 한다}} - -# 7. 파일 처리 결과 -이 Release 문서 생성/갱신 결과와 참조 문서를 기록한다. - -- 처리 결과: {{FILE_RESULT:생성|갱신|미생성}} -- 생성 경로: {{OUTPUT_PATH}} -- 참조 문서: - - {{VER_PATH:docs/sdlc//5_verification.md}} - - {{REFERENCE_1:필요 없으면 삭제}} - -# 8. 사용자 결정 필요 항목 요약 -사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. - -## DECIDE -- {{DECIDE_ITEM_1}} -- {{DECIDE_ITEM_2:필요 없으면 삭제}} - -## CONFIRM -- {{CONFIRM_ITEM_1}} -- {{CONFIRM_ITEM_2:필요 없으면 삭제}} - -## DATA -- {{DATA_ITEM_1}} -- {{DATA_ITEM_2:필요 없으면 삭제}} - -# 9. Release Freeze -Operations 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다. - -## 섹션 참조 -- 배포 준비: [# 2. 배포 준비](#2-배포-준비) -- 롤백 계획: [# 3. 롤백 계획](#3-롤백-계획) -- 배포 후 확인: [# 4. 배포 후 확인](#4-배포-후-확인) - -## 확정 플래그 -- Handoff Decision: {{FREEZE_HANDOFF_DECISION:보류}} -- Handoff Rationale: {{FREEZE_HANDOFF_RATIONALE:배포 완료 및 스모크 테스트 통과 후 Operations로 인계}} -- Ready for Operations: {{READY_FOR_OPERATIONS:false}} -- Confirmed By: {{CONFIRMED_BY:TBD}} -- Confirmed At (KST): {{CONFIRMED_AT_KST:TBD}} - ---- - -# 10. 작성 가이드 -*이 섹션은 작성 참고용이다. 문서 완성 후 삭제해도 된다.* - -- **배포 방식**: git 기반 프로젝트는 커밋 해시, 브랜치, 태그를 명시하면 롤백이 쉽다. -- **롤백 계획**: "문제가 생기면 롤백한다"가 아니라 구체적인 조건, 절차, 담당자를 미리 정의한다. -- **스모크 테스트**: 배포 직후 서비스가 최소한 동작하는지 확인하는 핵심 시나리오만 포함한다. 전체 기능 검증은 Verification 단계에서 완료한 것을 전제로 한다. -- **모니터링**: 배포 후 지켜봐야 하는 지표(오류율, 응답 시간, 로그 패턴 등)를 구체적으로 기록한다. diff --git a/.github/templates/sdlc/7_operation.md b/.github/templates/sdlc/7_operation.md deleted file mode 100644 index 8e6478a..0000000 --- a/.github/templates/sdlc/7_operation.md +++ /dev/null @@ -1,154 +0,0 @@ -# 0. 문서 상태 -이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다. - -- 상태: {{DOC_STATUS:draft|review|confirmed}} -- 문서 ID: {{CYCLE_ID:sdlc-<3자리>__}} -- 이슈명: {{ISSUE_NAME:짧은 한글 또는 영문 이슈명}} -- 참조 Release: {{REL_PATH:docs/sdlc//6_release.md}} -- 작성 시각(KST): {{CREATED_AT_KST:TBD}} -- 마지막 갱신 시각(KST): {{UPDATED_AT_KST:TBD}} - -# 1. Release 인계 요약 -Release에서 완료된 핵심 내용을 요약한다. 원본은 6_release.md를 참조하며, 이 섹션은 Operations 작업의 입력 기준선이 된다. - -## 이슈 목적 -- {{OPS_ISSUE_PURPOSE:Release 이슈명과 핵심 목적 1-2줄}} - -## 배포 결과 요약 -- 배포 환경: {{OPS_DEPLOY_ENV:예. production}} -- 배포 완료 시각(KST): {{OPS_DEPLOYED_AT:TBD}} -- 스모크 테스트 결과: {{OPS_SMOKE_RESULT:통과|일부 실패|미완료}} - -## 이월된 오픈 질문 / 리스크 -Release에서 `Deferred` 처리되어 Operations 단계에서 해소해야 하는 항목을 기록한다. - -- {{OPS_DEFERRED_ITEM_1:없으면 "없음"}} -- {{OPS_DEFERRED_ITEM_2:필요 없으면 삭제}} - -# 2. 운영 모니터링 -배포 후 지속적으로 모니터링해야 하는 항목과 기준을 정의한다. - -## 모니터링 항목 -| 항목 | 확인 방법 | 임계값 / 이상 기준 | 대응 방안 | -|------|---------|----------------|---------| -| {{OPS_MONITOR_ITEM_1}} | {{OPS_MONITOR_METHOD_1}} | {{OPS_MONITOR_THRESHOLD_1}} | {{OPS_MONITOR_ACTION_1}} | -| {{OPS_MONITOR_ITEM_2}} | {{OPS_MONITOR_METHOD_2}} | {{OPS_MONITOR_THRESHOLD_2}} | {{OPS_MONITOR_ACTION_2}} | -| {{OPS_MONITOR_ITEM_3:필요 없으면 삭제}} | {{OPS_MONITOR_METHOD_3}} | {{OPS_MONITOR_THRESHOLD_3}} | {{OPS_MONITOR_ACTION_3}} | - -## 모니터링 담당자 -- {{OPS_MONITOR_OWNER:TBD}} - -# 3. 운영 절차 (런북) -이 변경 사항과 관련된 운영 중 발생할 수 있는 상황별 대응 절차를 정의한다. - -## 정상 운영 확인 절차 -배포 후 일정 주기로 정상 동작을 확인하는 절차를 기술한다. - -1. {{OPS_ROUTINE_STEP_1:예. 오류 로그 확인 (일 1회)}} -2. {{OPS_ROUTINE_STEP_2:필요 없으면 삭제}} - -## 장애 대응 절차 -이 변경과 관련된 장애가 발생했을 때의 초기 대응 절차를 기술한다. - -1. {{OPS_INCIDENT_STEP_1:예. 오류 로그에서 관련 스택 트레이스 확인}} -2. {{OPS_INCIDENT_STEP_2:예. 롤백 판단 기준 확인 후 롤백 또는 핫픽스 결정}} -3. {{OPS_INCIDENT_STEP_3:필요 없으면 삭제}} - -## 에스컬레이션 경로 -장애 대응 중 에스컬레이션이 필요한 경우 연락 대상을 기록한다. - -- {{OPS_ESCALATION_1:TBD}} - -# 4. 운영 중 발생한 이슈 -운영 중 발견된 이슈를 기록한다. 초안 생성 시 비워 두고 운영 중 갱신한다. - -- {{OPS_ISSUE_1:없음 (운영 중 발견 시 기록)}} - -# 5. 리스크 및 오픈 질문 -Operations 단계에서 새로 식별된 리스크와 오픈 질문을 기록한다. - -## 리스크 -- R-1 ({{OPS_RISK_LEVEL_1:High|Medium|Low}}): {{OPS_RISK_1}} - - 완화 방안: {{OPS_MITIGATION_1}} -- R-2 ({{OPS_RISK_LEVEL_2:High|Medium|Low}}): {{OPS_RISK_2:필요 없으면 삭제}} - - 완화 방안: {{OPS_MITIGATION_2:필요 없으면 삭제}} - -## 오픈 질문 -- OQ-1: {{OPS_OPEN_QUESTION_1}} - - 상태: {{OPS_OQ_STATUS_1:Open|Answered|Deferred|Dropped}} - - 처리 방안: {{OPS_OQ_ACTION_1}} - - 종료 조건: {{OPS_OQ_EXIT_1}} -- OQ-2: {{OPS_OPEN_QUESTION_2:필요 없으면 삭제}} - - 상태: {{OPS_OQ_STATUS_2:Open|Answered|Deferred|Dropped}} - - 처리 방안: {{OPS_OQ_ACTION_2}} - - 종료 조건: {{OPS_OQ_EXIT_2}} - -# 6. 다음 Discovery 환류 -운영 중 발견된 인사이트와 개선 사항을 다음 SDLC Discovery의 입력으로 기록한다. - -- {{OPS_FEEDBACK_1:없으면 "없음"}} -- {{OPS_FEEDBACK_2:필요 없으면 삭제}} -- {{OPS_FEEDBACK_3:필요 없으면 삭제}} - -# 7. 확인 체크 -Operations 문서가 완성되었는지 확인한다. - -- [ ] 모니터링 항목 및 임계값 정의 완료 - - 기준: {{CHECK_MONITORING:모니터링 항목에 임계값과 대응 방안이 명시되어야 한다}} -- [ ] 런북(정상 운영/장애 대응 절차) 정의 완료 - - 기준: {{CHECK_RUNBOOK:운영 중 발생 가능한 상황에 대한 절차가 1단계 이상 있어야 한다}} -- [ ] 에스컬레이션 경로 정의 완료 - - 기준: {{CHECK_ESCALATION:장애 시 연락할 담당자가 명시되어야 한다}} -- [ ] 다음 Discovery 환류 항목 작성 (없으면 "없음" 기재) - - 기준: OPS_FEEDBACK 항목이 "없음"이 아닐 경우 구체적으로 기술되었는가 -- [ ] Freeze 확정 담당자(CONFIRMED_BY) 지정 - - 기준: {{CHECK_CONFIRMEDBY_CRITERIA:문서 승인 담당자가 명시되어야 한다}} - -# 8. 파일 처리 결과 -이 Operations 문서 생성/갱신 결과와 참조 문서를 기록한다. - -- 처리 결과: {{FILE_RESULT:생성|갱신|미생성}} -- 생성 경로: {{OUTPUT_PATH}} -- 참조 문서: - - {{REL_PATH:docs/sdlc//6_release.md}} - - {{REFERENCE_1:필요 없으면 삭제}} - -# 9. 사용자 결정 필요 항목 요약 -사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. - -## DECIDE -- {{DECIDE_ITEM_1}} -- {{DECIDE_ITEM_2:필요 없으면 삭제}} - -## CONFIRM -- {{CONFIRM_ITEM_1}} -- {{CONFIRM_ITEM_2:필요 없으면 삭제}} - -## DATA -- {{DATA_ITEM_1}} -- {{DATA_ITEM_2:필요 없으면 삭제}} - -# 10. Operations Freeze -이 SDLC 주기의 최종 확정 플래그를 기록한다. - -## 섹션 참조 -- 운영 모니터링: [# 2. 운영 모니터링](#2-운영-모니터링) -- 런북: [# 3. 운영 절차 런북](#3-운영-절차-런북) -- 다음 Discovery 환류: [# 6. 다음 Discovery 환류](#6-다음-discovery-환류) - -## 확정 플래그 -- Handoff Decision: {{FREEZE_HANDOFF_DECISION:보류}} -- Handoff Rationale: {{FREEZE_HANDOFF_RATIONALE:모니터링 안정화 및 런북 완비 후 주기 완료}} -- SDLC 주기 완료: {{SDLC_CYCLE_COMPLETE:false}} -- Confirmed By: {{CONFIRMED_BY:TBD}} -- Confirmed At (KST): {{CONFIRMED_AT_KST:TBD}} - ---- - -# 11. 작성 가이드 -*이 섹션은 작성 참고용이다. 문서 완성 후 삭제해도 된다.* - -- **모니터링 항목**: "오류가 없는지 확인"처럼 모호한 기준 대신 "5xx 오류율 1% 이상 시 알림" 같이 수치화된 임계값을 명시한다. -- **런북**: 실제 운영자가 참고할 수 있도록 구체적인 명령, 경로, 연락처를 기록한다. -- **다음 Discovery 환류**: 이 주기에서 발견된 기술 부채, 개선 아이디어, 범위에서 제외된 요구사항 등을 기록한다. 이 항목이 다음 `/new-sdlc` 의 입력이 된다. -- **SDLC 주기 완료**: 모니터링 안정화 기간(배포 후 일정 시간 경과, 이상 없음) 확인 후 `true`로 변경한다. diff --git a/.github/templates/sdlc/index.md b/.github/templates/sdlc/index.md deleted file mode 100644 index fa240da..0000000 --- a/.github/templates/sdlc/index.md +++ /dev/null @@ -1,12 +0,0 @@ -# {{CYCLE_ID}} - -| 단계 | 문서 | 상태 | -|------|------|------| -| 1. Discovery | [1_discovery.md](./1_discovery.md) | `draft` | -| 2. Planning | [2_planning.md](./2_planning.md) | `-` | -| 3. Design | [3_design.md](./3_design.md) | `-` | -| 4. Implementation | [4_implementation.md](./4_implementation.md) | `-` | -| 5. Verification | [5_verification.md](./5_verification.md) | `-` | -| 6. Release | [6_release.md](./6_release.md) | `-` | -| 7. Operations | [7_operations.md](./7_operations.md) | `-` | -| Summary | [summary.md](./summary.md) | `-` | diff --git a/.github/templates/sdlc/summary.md b/.github/templates/sdlc/summary.md deleted file mode 100644 index ee472ea..0000000 --- a/.github/templates/sdlc/summary.md +++ /dev/null @@ -1,16 +0,0 @@ -# Summary - {{CYCLE_ID:sdlc-<3자리>__}} - -- 이슈명: {{ISSUE_NAME:짧은 한글 또는 영문 이슈명}} -- 상태: {{SUMMARY_STATUS:draft|review|confirmed}} -- 작성 시각(KST): {{CREATED_AT_KST:TBD}} -- 마지막 갱신 시각(KST): {{UPDATED_AT_KST:TBD}} - -## 핵심 요약 - -- {{SUMMARY_POINT_1}} -- {{SUMMARY_POINT_2:필요 없으면 삭제}} - -## 단계별 문서 - -- [Discovery](./1_discovery.md) -- [Index](./index.md) diff --git a/.github/templates/srs/index.md b/.github/templates/srs/index.md new file mode 100644 index 0000000..67c789c --- /dev/null +++ b/.github/templates/srs/index.md @@ -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//req-XXX_.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//` 폴더명도 같은 문자열을 사용한다. +- 각 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 + +- 없음 \ No newline at end of file diff --git a/.github/templates/srs/req-template.md b/.github/templates/srs/req-template.md new file mode 100644 index 0000000..2fd39c7 --- /dev/null +++ b/.github/templates/srs/req-template.md @@ -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 +- <검증 방법과 완료 조건> \ No newline at end of file diff --git a/README.md b/README.md index c50f819..02d61c1 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,22 @@ git subtree add --prefix=.vendor/stage-pilot stage-pilot main --squash bash .vendor/stage-pilot/bootstrap/install.sh . ``` +설치 직후에는 Copilot Chat에서 `/bootstrap-baseline`을 먼저 실행해 `docs/project-structure.md`, `docs/runtime-flows.md`, `docs/interface-contract.md`, `docs/data-model.md`, 각 active index를 초기화한다. 이 단계는 Discovery/REQ/Batch/Release 중 어느 것도 아니며, 첫 real Discovery 전에 수행하는 bootstrap 단계다. + +greenfield 저장소처럼 읽을 코드나 설정이 없으면 `bootstrap-baseline`은 사용자에게 최소 질문 세트와 필요한 선택 follow-up(`interface-contracts`, `interface-inputs`, `interface-outputs`, `interface-errors`, `core-entities`, `persistence-backend`, `compatibility-rules`)를 묻고, 답변을 `.stagepilot/bootstrap/baseline.yaml`에 저장한 뒤 baseline 문서를 렌더링한다. + +seed 파일만 먼저 만들고 싶으면 helper를 사용할 수 있다. + +```bash +# vendor wrapper 사용 +bash .vendor/stage-pilot/bootstrap/stagepilot.sh bootstrap-seed . + +# 설치된 script 직접 사용 +python3 .github/scripts/stagepilot-bootstrap-seed.py . +``` + +bootstrap-baseline 실행 결과 예시는 `examples/bootstrap-baseline/`에 포함돼 있다. + ## 업데이트 ```bash @@ -29,112 +45,369 @@ bash .vendor/stage-pilot/bootstrap/update.sh --repo-url https://github.com/genic bash .vendor/stage-pilot/bootstrap/update.sh --skip-install . ``` -## SDLC 프롬프트 사용법 +## 검증 -`.github/prompts/`에 단계별 프롬프트가 정의되어 있으며, Copilot Chat에서 `/프롬프트이름 인자` 형태로 실행한다. +```bash +# vendor subtree에서 doctor 실행 +bash .vendor/stage-pilot/bootstrap/stagepilot.sh doctor . -### 빠른 시작 +# 설치된 .github/scripts를 직접 실행 +python3 .github/scripts/stagepilot-doctor.py . -처음부터 전체 SDLC 초안 세트를 만들고 싶다면 아래 명령으로 같은 번호의 draft 문서 세트를 한 번에 생성할 수 있다. +# active docs가 반드시 있어야 하는 workspace라면 엄격 모드 사용 +python3 .github/scripts/stagepilot-doctor.py --strict-missing-docs . -```text -/new-sdlc 결제 실패 알림 정책을 도입한다 +# Markdown 리포트를 파일로 저장 +python3 .github/scripts/stagepilot-doctor.py --report artifacts/stagepilot-doctor.md . ``` -이 명령은 `dcy/pln/dsn/imp/ver/rel/ops` 문서를 같은 번호로 모두 `draft` 상태로 만든다. 다만 승인 작업은 Discovery부터 순차적으로 진행해야 한다. +`stagepilot-doctor`는 아래 항목을 검사한다. -초안 생성 후 순차 검토/승인을 자동 실행하려면 아래 명령을 사용한다. +- active 문서 루트 존재 여부 +- index와 본문 문서의 상태 동기화 +- REQ traceability matrix (`Discovery -> REQ -> Batch -> Release`) +- feedback loop summary (`Release -> Discovery/REQ/change-req input`) +- change-req 이후 상태 되돌림 누락 (`Status Recommendation`, 재검증 필요, 구현 무효화와 현재 REQ 상태의 불일치) +- orphan REQ (`Approved`인데 batch 미포함, release-candidate batch 미포함 등) +- feedback 미연결 release (`released`인데 `feedback-captured` 미전환 등) +- 남아 있는 placeholder +- 상대 markdown 링크 경로 +- REQ 타입 분류 일관성 +- `Next Requirement ID` 규칙 +- template-skill contract 불일치 +- bootstrap source allowlist drift +- bootstrap 완료 저장소에서 선택 cross-cutting baseline 문서(`docs/interface-contract.md`, `docs/data-model.md`) 누락 -```text -/run-sdlc dcy-001 홍길동 -``` +active 문서가 아직 없는 패키지 저장소나 초기 host 저장소에서는 package contract 검사만 수행하고, active docs 부재는 기본적으로 warning으로 보고한다. -이 명령은 Discovery부터 Operations까지 순서대로 검토/승인을 시도한다. 이미 승인된 단계는 건너뛰며, 중간 단계에서 승인 불가면 해당 단계에서 멈추고 미충족 항목과 추가 결정사항을 알려준다. +fresh host 저장소에서 baseline 초기화가 아직 끝나지 않았으면 doctor는 `INFO [bootstrap-required]`로 `/bootstrap-baseline` 실행과 누락된 bootstrap 파일 목록을 함께 안내한다. -### 기본 실행 순서 +`--report`를 주면 findings와 traceability matrix를 별도 Markdown 리포트로 저장한다. 기본 동작은 stdout 출력만 유지한다. -1. Discovery -2. Planning -3. Design -4. Implementation -5. Verification -6. Release -7. Operations +## 예제 -### 단계별 명령 예시 +- `examples/bootstrap-baseline/`: fresh host 저장소에서 `/bootstrap-baseline`을 실행한 직후의 baseline 문서와 sample output +- `examples/p3-change-management/`: change-req와 suggest-next-discovery가 연결되는 P3 sample workspace -```text -# Discovery -/new-sdlc 결제 실패 알림 정책을 도입한다 -/review-discovery sdlc-001 -/confirm-discovery sdlc-001 +## Active 문서 루트와 Source of Truth -# Planning -/draft-planning sdlc-001 -/review-planning sdlc-001 -/confirm-planning sdlc-001 +### 필수 루트 -# Design -/draft-design sdlc-001 -/review-design sdlc-001 -/confirm-design sdlc-001 +| 경로 | 역할 | +| --- | --- | +| `docs/discovery/index.md` | Discovery 전역 인덱스 | +| `docs/discovery/*.md` | Discovery 본문 | +| `docs/srs/index.md` | REQ 전역 인덱스와 상태 정의 | +| `docs/srs//req-XXX_.md` | 개별 REQ 문서 | +| `docs/batches/index.md` | batch 전역 인덱스 | +| `docs/batches//planning.md` | batch 계획 | +| `docs/batches//design.md` | batch 설계 | +| `docs/batches//implementation.md` | batch 구현 로그 | +| `docs/batches//verification.md` | batch 검증 근거 | +| `docs/releases/index.md` | release 전역 인덱스 | +| `docs/releases/rel-XXX_*.md` | 개별 release 문서 | -# Implementation -/draft-implementation sdlc-001 -/run-implementation sdlc-001 -/review-implementation sdlc-001 -/confirm-implementation sdlc-001 +### 선택 cross-cutting 문서 -# Verification -/draft-verification sdlc-001 -/review-verification sdlc-001 -/confirm-verification sdlc-001 +| 경로 | 역할 | +| --- | --- | +| `docs/project-structure.md` | 저장소 구조, 모듈 경계, 의존 규칙 baseline | +| `docs/runtime-flows.md` | 대표 entry point와 실행 흐름 baseline | +| `docs/interface-contract.md` | 외부 API, CLI, 이벤트, 파일 I/O 계약 baseline | +| `docs/data-model.md` | 핵심 엔티티, 관계, 상태, persistence 규칙 baseline | -# Release -/draft-release sdlc-001 -/review-release sdlc-001 -/confirm-release sdlc-001 +이 문서들은 active unit 자체는 아니지만 여러 REQ와 batch에서 반복 참조하는 공통 기술 기준선이다. -# Operations -/draft-operation sdlc-001 -/review-operation sdlc-001 -/confirm-operation sdlc-001 -/operation-triage 문제: 로그인 후 세션 만료 시 특정 브라우저에서 무한 리다이렉트가 발생한다. 증상: 만료된 세션으로 접근하면 /login 과 /callback 사이를 반복 이동한다. 기대 동작: 세션 만료 시 로그인 페이지로 1회 이동하고 재로그인 안내를 보여야 한다. 영향도: Safari 사용자 일부가 서비스 재진입 불가. 재현 조건: Safari 17, 기존 세션 쿠키 보유, rel-001 배포 이후. 관련 문서: rel-001 ops-001 -``` +### 4.2 명령, 템플릿, 가이드 경로 -### 문서 ID 규칙 +| 경로 | 역할 | +| --- | --- | +| `.github/skills/bootstrap-baseline/SKILL.md` | 프로젝트 시작 시 baseline 문서와 active index를 초기화하는 bootstrap entrypoint | +| `.github/skills/` | active skill entrypoint 집합 | +| `.github/skills/run-sdlc/SKILL.md` | 현재 상태를 읽고 다음 skill을 안내하는 orchestrator | +| `.github/templates/bootstrap/baseline-seed.yaml` | bootstrap 질문 결과를 저장하는 seed 템플릿 | +| `.github/templates/discovery/discovery.md` | Discovery 생성 템플릿 | +| `.github/templates/project-structure.md` | baseline 구조 문서 템플릿 | +| `.github/templates/runtime-flows.md` | baseline 실행 흐름 문서 템플릿 | +| `.github/templates/interface-contract.md` | 선택형 인터페이스 계약 문서 템플릿 | +| `.github/templates/data-model.md` | 선택형 데이터 모델 문서 템플릿 | +| `.github/instructions/placeholder-guide.md` | placeholder 치환 규칙과 active 경로 가이드 | -모든 단계 문서는 동일한 CYCLE_ID를 공유한다. +### 4.3 비활성 경로 정책 -- CYCLE_ID 형식: `sdlc-<3자리>__` (예: `sdlc-001_20260417_stage-pilot`) -- 각 단계 파일: `1_discovery.md` ~ `7_operation.md` +- prompt 기반 stage command는 active flow에 포함하지 않는다. +- legacy stage template는 active source of truth가 아니다. +- active 작업은 `docs/discovery/`, `docs/srs/`, `docs/batches/`, `docs/releases/` 기준으로만 수행한다. -### 언제 새 Discovery를 만드는가 +## 5. 단위별 상태 모델 -운영 중 문제를 발견했을 때는 먼저 `/operation-triage`로 분류한 뒤 아래 기준으로 판단한다. +### 5.1 Discovery 상태 -| operation-triage 판정 결과 | 상황 | 새 Discovery 필요 여부 | 권장 처리 | -|---|---|---:|---| -| 구현 문제 | 기존 요구사항/설계/검증 기준은 있었는데 구현이 어긋남, 그리고 관련 문서가 `confirmed` 이후 상태임 | 필요 | corrective change용 Discovery를 새로 만들고 Planning부터 다시 진행 | -| 구현 문제 | 관련 문서가 모두 `draft`이고 기존 범위 안에서 수정 가능 | 불필요 | 기존 Discovery/Design/Implementation/Verification 문서에 흡수 | -| 설계·요구사항 누락 | 기능은 있었지만 예외 시나리오, 비기능 요구, 운영 리스크가 빠짐 | 필요 | 누락 요구를 위한 새 Discovery 생성 | -| 신규 범위 | 기존 SDLC 문서에 실질적으로 없는 기능/정책/요구 | 필요 | 새 Discovery 생성 | -| 운영 보완만 필요 | 코드/요구 변경 없이 모니터링, 런북, 공지, 절차만 보완 | 불필요 | Operations 문서 보강 | -| 판단 보류 | 관련 문서 부족, 근거 상충, 재현 불충분 | 보류 | 정보 보강 후 `/operation-triage` 재실행 | -| Hotfix 필요 | 서비스 중단, 데이터 손실, 보안 영향 등 긴급 대응 우선 | 필요 | Hotfix로 즉시 대응 후 후속 Discovery 생성 및 Postmortem 환류 | +| 상태 | 의미 | +| --- | --- | +| `draft` | 초안 상태이며 REQ drafting 전 | +| `confirmed` | REQ drafting으로 넘길 수 있도록 확인 완료 | -짧은 판단 기준: +Discovery는 구현 완료 상태를 표현하는 단위가 아니다. Discovery의 역할은 문제 정의와 handoff 준비다. -1. 완료된 SDLC 결과물을 바꾸는 수정이면 새 Discovery를 만든다. -2. 아직 draft 단계 문서 보정이면 기존 문서에 흡수한다. -3. 운영 문서 보완만 하면 되면 새 Discovery는 만들지 않는다. +### 5.2 REQ 상태 -### 참고 파일 +| 상태 | 의미 | +| --- | --- | +| `Proposed` | 초안 상태이며 구현 기준으로 확정되지 않음 | +| `Approved` | 구현 기준으로 승인됨 | +| `Implemented` | 구현과 검증이 완료됨 | +| `Deprecated` | 더 이상 유지하지 않음 | -1. 시작 가이드: `.github/START-HERE.md` -2. 단계 규칙: `.github/instructions/` -3. 프롬프트 정의: `.github/prompts/` -4. 템플릿: `.github/templates/` -5. Operations 템플릿: `.github/templates/operations-note.template.md` -6. 플레이스홀더 가이드: `.github/instructions/placeholder-guide.md` +### 5.3 Batch 상태 +| 상태 | 의미 | +| --- | --- | +| `draft` | batch 초안만 생성된 상태 | +| `in-delivery` | planning, design, implementation, verification 중 일부가 진행 중 | +| `release-candidate` | verification 확인이 끝나 release 입력으로 사용 가능 | +| `released` | 하나 이상의 release에 포함됨 | +| `archived` | 더 이상 active delivery 단위로 사용하지 않음 | + +### 5.4 Release 상태 + +| 상태 | 의미 | +| --- | --- | +| `draft` | release 초안 상태 | +| `confirmed` | rollout, rollback, verification 준비가 승인됨 | +| `released` | 배포 실행이 완료됨 | +| `feedback-captured` | 운영 환류까지 기록 완료 | + +## 6. 기본 운영 흐름 + +### 6.0 프로젝트 시작 시 baseline 초기화 + +새 저장소에 StagePilot을 처음 적용할 때는 Discovery를 만들기 전에 `bootstrap-baseline`을 먼저 실행한다. + +1. `bootstrap-baseline` + 필요하면 최소 질문 세트(`project-summary`, `primary-domain`, `tech-stack`, `primary-runtime`, `primary-entrypoints`)와 선택 follow-up(`interface-contracts`, `core-entities`)를 묻고, 답을 `.stagepilot/bootstrap/baseline.yaml`에 저장한 뒤 `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`를 렌더링한다. + 이 단계는 bootstrap 단계이며, Discovery/REQ/Batch/Release 단위로 계산하지 않는다. + 샘플 결과는 `examples/bootstrap-baseline/bootstrap-baseline-output.md`를 참고한다. +2. `new-discovery` + baseline 초기화가 끝난 뒤 첫 real Discovery를 실제 제품/서비스 변경 주제로 생성한다. + +이미 코드와 실행 경로가 있는 기존 저장소에 StagePilot을 처음 적용할 때도 시작점은 동일하게 `bootstrap-baseline`이다. 차이는 bootstrap이 질문만으로 baseline을 만들지 않고, 현재 저장소 구조와 실행 흔적을 먼저 읽어 `observed` 또는 `mixed` baseline을 만든다는 점이다. + +1. 설치 직후 `python3 .github/scripts/stagepilot-doctor.py .` 또는 `bash .vendor/stage-pilot/bootstrap/stagepilot.sh doctor .`로 누락된 bootstrap 파일과 active docs 상태를 확인한다. +2. active SDLC 문서가 아직 없다면 `/bootstrap-baseline`을 실행해 기존 저장소 기준의 `docs/project-structure.md`, `docs/runtime-flows.md`, `docs/interface-contract.md`, `docs/data-model.md`, active index를 만든다. +3. 저장소만으로 프로젝트 정체성이나 계획 runtime을 충분히 설명할 수 없으면 `python3 .github/scripts/stagepilot-bootstrap-seed.py .` 또는 `bash .vendor/stage-pilot/bootstrap/stagepilot.sh bootstrap-seed .`로 `.stagepilot/bootstrap/baseline.yaml`을 먼저 만들고, 그 다음 `/bootstrap-baseline`을 실행해 baseline을 `mixed`로 보강한다. +4. bootstrap이 끝난 뒤 첫 real Discovery는 baseline 생성 자체가 아니라 현재 진행하려는 기능 변경, 운영 이슈, 기술 결정 중 하나를 주제로 `new-discovery`에서 시작한다. +5. 이미 `docs/discovery/`, `docs/srs/`, `docs/batches/`, `docs/releases/` 아래 active unit가 운영 중인 저장소라면 bootstrap을 광범위하게 다시 수행하지 말고 `run-sdlc ` 또는 해당 active unit의 skill로 이어서 처리한다. 이 경우 `bootstrap-baseline`은 단순 누락 복구에만 사용한다. + +### 6.1 Requirements Phase + +1. `new-discovery` + baseline 초기화 이후 사용자 요청, 운영 피드백, issue 입력을 실제 변경 주제의 Discovery 초안으로 만든다. +2. `confirm-discovery` + Discovery를 저장소 현실과 대조하고 REQ drafting 가능 상태로 `confirmed` 전환한다. +3. `draft-req` + confirmed Discovery에서 승인 가능한 REQ 문서를 만든다. +4. `confirm-req` + REQ를 `Approved`로 전환한다. +5. `change-req` + 기존 REQ 수정이 필요할 때 Change Log 기반 변경 요청을 먼저 기록하고 상태 되돌림/재검증 범위를 판정한다. +6. `suggest-batch-reqs` + Approved REQ를 어떤 batch로 묶을지 후보를 제시한다. + `change-req` 이후에도 delivery로 이어질 REQ만 batch 후보로 본다. +7. `draft-batch` + 선택된 REQ 묶음으로 `standard` 또는 `batch-lite` profile의 batch 폴더와 기본 문서를 생성한다. + +### 6.2 Delivery Phase + +1. `draft-batch-planning` + batch 범위, 제외 범위, 의존성, 마일스톤, 리스크를 정리한다. +2. `draft-batch-design` + batch 수준의 architecture summary, changed areas, key decisions를 정리한다. `batch-lite`에서 구조 영향이 없으면 생략할 수 있다. +3. `run-batch-implementation` + 실제 코드 변경을 수행하고 implementation 문서에 changed files, execution log, validation을 기록한다. +4. `draft-batch-verification` + REQ acceptance criteria를 evidence에 연결한다. `batch-lite`는 planning과 implementation만으로도 검증할 수 있지만, 구조 영향이 생기면 design을 추가해야 한다. +5. `confirm-batch-verification` + evidence가 충분하면 batch를 `release-candidate`로 전환한다. +6. `confirm-req-implemented` + `release-candidate` 또는 `released` batch의 verification evidence를 기준으로 포함 REQ를 `Implemented`로 동기화한다. + +### 6.3 Release & Feedback Phase + +1. `draft-release` + 하나 이상의 `release-candidate` batch로 release 문서를 생성하고 `docs-only`, `tooling`, `app-service` 중 하나의 release profile을 선택한다. +2. `confirm-release` + rollout, rollback, verification checklist와 profile별 검증 항목을 점검하고 release를 `confirmed`로 전환한다. +3. `capture-release-feedback` + 배포 후 운영 관찰 결과와 후속 Discovery/REQ/change-req 입력을 release 문서에 남긴다. +4. `suggest-next-discovery` + release feedback, baseline gap, 미구현/변경 대기 REQ를 읽고 다음 반복 후보를 추천한다. + +### 6.4 경량 변경 경로 + +아래 조건을 모두 만족하면 `minor-change` fast path를 사용할 수 있다. + +- `Approved` REQ가 정확히 1개다. +- 범위가 문서, 템플릿, 스크립트, bootstrap, 설정처럼 국소적이다. +- 구조, 인터페이스, runtime flow 변경이 없다. +- 독립 release가 가능하고 사람 선택이 필요한 묶음 판단이 남아 있지 않다. + +이 경로에서는 `suggest-batch-reqs`를 생략하고 바로 `draft-batch`를 실행해 `Profile: batch-lite` batch를 만든다. `batch-lite`는 최초에 `index.md`와 `planning.md`만 만들고, implementation/verification 문서는 해당 단계 진입 시 추가한다. design은 planning의 `Design Gate`가 `yes`가 될 때만 생성한다. + +### 6.5 Orchestrator 사용 기준 + +`run-sdlc`는 현재 문서 상태를 읽고 다음에 실행할 skill을 1단계씩 안내하는 entrypoint다. + +- active unit가 아직 없고 baseline 문서나 active index가 비어 있으면 `bootstrap-baseline`을 먼저 제안한다. +- Discovery 입력이면 `confirm-discovery`, `draft-req`, `suggest-batch-reqs` 중 다음 단계를 제안한다. +- REQ 입력이면 `confirm-req`, `change-req`, `suggest-batch-reqs`, `draft-batch`, `confirm-req-implemented` 중 다음 단계를 제안한다. 단일 저위험 REQ면 `minor-change -> batch-lite` 경로를 우선 제안할 수 있다. +- Batch 입력이면 `draft-batch-planning`, `draft-batch-design`, `run-batch-implementation`, `draft-batch-verification`, `confirm-batch-verification`, `confirm-req-implemented`, `draft-release` 중 다음 단계를 제안한다. +- Release 입력이면 선택된 release profile과 feedback handoff 상태를 기준으로 `confirm-release`, `capture-release-feedback`, `suggest-next-discovery`, `change-req`를 제안한다. + +### 6.6 변경 관리와 개선 루프 + +- 기존 REQ의 `Requirement`, `Acceptance Criteria`, `Impacted Area`를 바꿀 때는 먼저 `change-req`로 새 Change Log 항목을 만든다. +- 변경이 기존 구현/검증을 무효화하면 REQ 상태를 `Implemented -> Approved` 또는 필요 시 `Proposed`로 되돌린다. +- release feedback는 `Discovery Input`, `REQ Input`, `Change Request Input`으로 나눠 기록한다. +- 다음 개선 루프의 우선순위만 먼저 정하고 싶으면 `suggest-next-discovery`를 사용한다. + +## 7. Phase Gate 기준 + +### 7.1 Requirements 완료 기준 + +아래 조건을 만족해야 Delivery로 넘어간다. + +- Discovery가 `confirmed` 상태다. +- 구현 대상으로 채택할 REQ가 `Approved` 상태다. +- REQ의 Acceptance Criteria가 구현 판단 가능한 수준이다. +- 사람 결정 필요 항목과 후속 backlog 항목이 분리되어 있다. +- 기존 REQ 변경이 있었다면 `change-req` 기록과 상태 동기화가 끝났다. + +### 7.2 Delivery 완료 기준 + +아래 조건을 만족해야 Release & Feedback으로 넘어간다. + +- batch planning, implementation, verification 문서가 존재한다. +- `standard` batch이거나 `batch-lite`에서 구조 영향이 생긴 경우 design 문서가 존재한다. +- batch에 포함된 REQ acceptance criteria가 evidence와 연결된다. +- verification blocker가 해소되었다. +- batch 상태가 `release-candidate`다. +- 구현과 검증이 완료된 포함 REQ는 필요 시 `Implemented` 상태로 동기화되었다. + +### 7.3 Release & Feedback 완료 기준 + +아래 조건을 만족해야 release 단위를 닫는다. + +- release 계획이 `confirmed` 상태를 통과했다. +- 배포 결과가 기록되었다. +- 운영 관찰 결과가 release 문서에 남았다. +- 후속 Discovery, REQ, change-req 입력이 정리되었다. + +## 8. 사람 판단이 필요한 경계 + +다음 항목은 AI가 임의로 확정하지 않는다. + +- 승인자 지정 +- Owner 지정 +- 정책 선택 +- 우선순위 승인 +- 외부 시스템 또는 외부 데이터 확인 결과 +- `suggest-batch-reqs` 결과 중 어떤 후보를 실제 batch로 채택할지에 대한 선택 + +특히 `suggest-batch-reqs`는 추천안을 만드는 단계이며, 최종 batch 묶음은 사람 선택이 필요하다. 따라서 orchestrator는 이 경계에서 자동 진행하지 않고 멈춘다. 단, 단일 저위험 REQ는 `minor-change` fast path로 바로 `batch-lite`를 만들 수 있다. + +## 9. 자동화 규칙 + +### 9.1 Discovery 자동 생성 확장 규칙 + +현재 StagePilot 기본 패키지에는 GitHub issue label 기반 Discovery 자동 생성 workflow/script가 포함되어 있지 않다. + +호스트 저장소가 별도 workflow 또는 script를 추가해 Discovery 자동 생성을 확장할 수 있으며, 그런 자동화는 아래 규칙을 따라야 한다. + +- Discovery ID는 `dcy-<3자리>__` 형식을 사용한다. +- 동일 issue에 대해 반복 실행해도 중복 Discovery를 만들지 않는다. +- discovery index에 문서 링크와 상태를 등록한다. +- 결과는 issue comment로 다시 보고한다. + +자동화를 추가하지 않는 경우에도 Discovery 생성과 index 갱신의 source of truth는 여전히 `new-discovery` skill과 `docs/discovery/` 문서다. + +### 9.2 Index 관리 규칙 + +- `docs/discovery/index.md`는 자동 생성 및 자동 갱신 결과를 포함할 수 있다. +- `docs/srs/index.md`, `docs/batches/index.md`, `docs/releases/index.md`는 각 confirm 또는 draft 단계에서 상태와 register를 함께 맞춘다. +- 상태 변경은 본문 문서와 index가 항상 함께 갱신되어야 한다. + +## 10. 표준 작업 절차 + +### 10.1 신규 기능 또는 운영 이슈가 들어온 경우 + +1. issue 또는 요청 내용을 기준으로 `new-discovery`를 실행한다. +2. Discovery를 저장소 현실과 맞춰 보강한 뒤 `confirm-discovery`를 실행한다. +3. Discovery를 REQ로 쪼개고 `draft-req`를 수행한다. +4. 각 REQ를 `confirm-req`로 승인한다. +5. REQ가 여러 개이거나 묶음 판단이 필요하면 `suggest-batch-reqs`로 batch 후보를 받고, 사람이 묶음을 선택한다. +6. 단일 저위험 REQ면 `draft-batch`를 `minor-change -> batch-lite` 경로로 바로 실행한다. +7. 그 외 경우 선택된 묶음으로 `draft-batch`를 실행한다. +8. planning, design(필요한 경우), implementation, verification을 순서대로 수행한다. +9. `confirm-batch-verification`으로 release-candidate를 만든다. +10. `confirm-req-implemented`로 구현/검증 완료 REQ를 `Implemented`로 동기화한다. +11. `draft-release`, `confirm-release`로 배포를 준비하고 실행한다. 이때 release profile은 `docs-only`, `tooling`, `app-service` 중 하나를 선택한다. +12. `capture-release-feedback`으로 운영 환류를 남긴다. +13. 필요하면 `suggest-next-discovery`로 다음 반복 후보를 정리하거나, 기존 REQ 수정이면 `change-req`로 바로 연결한다. + +### 10.2 이미 존재하는 문서를 이어서 처리하는 경우 + +1. 가장 가까운 식별자 하나를 선택한다. +2. `run-sdlc `로 현재 단위의 다음 skill을 확인한다. +3. 제안된 다음 skill을 실행한다. +4. 사람이 결정해야 하는 경계에 도달하면 그 결정만 먼저 확정한다. + +## 11. Hotfix 예외 경로 + +긴급 핫픽스는 Requirements와 Delivery 설계를 경량화할 수 있다. 단, 아래 4가지는 생략하지 않는다. + +1. 최소 요구사항 정의 + 증상, 영향, 성공 조건을 기록한다. +2. 최소 검증 + 재현 테스트 또는 핵심 시나리오 확인을 남긴다. +3. 배포 전 롤백 계획 + 실패 시 복구 방법을 명시한다. +4. 배포 후 Postmortem + 운영 결과를 기록하고 다음 sprint 입력으로 환류한다. + +## 12. 유지보수 규칙 + +이 메뉴얼을 수정해야 하는 경우는 아래와 같다. + +- skill 이름이 바뀌는 경우 +- active 문서 루트가 바뀌는 경우 +- 상태 모델이 바뀌는 경우 +- workflow 또는 자동 생성 경로가 바뀌는 경우 +- phase gate 기준이 바뀌는 경우 + +위 항목이 바뀌면 아래 파일들도 함께 점검한다. + +- `.github/copilot-instructions.md` +- `.github/skills/run-sdlc/SKILL.md` +- 관련 `confirm-*`, `draft-*`, `run-*`, `capture-*` skill +- `docs/discovery/index.md` +- `docs/srs/index.md` +- `docs/batches/index.md` +- `docs/releases/index.md` + +## 13. 빠른 점검표 + +### 13.1 Requirements 진입 전 + +- 요청 또는 운영 이슈가 명확한가 +- 기존 Discovery를 갱신할지 새로 만들지 판단했는가 + +### 13.2 Delivery 진입 전 + +- 관련 REQ가 모두 `Approved`인가 +- batch 범위와 제외 범위가 정리되었는가 + +### 13.3 Release 진입 전 + +- batch가 `release-candidate`인가 +- rollout plan, rollback plan, verification checklist가 준비되었는가 \ No newline at end of file diff --git a/bootstrap/bootstrap.sh b/bootstrap/bootstrap.sh index 7734dfc..08a7b6d 100644 --- a/bootstrap/bootstrap.sh +++ b/bootstrap/bootstrap.sh @@ -26,7 +26,10 @@ ensure_host_structure() { ".github/runbooks/services" ".github/scripts" ".github/templates" - "docs/sdlc" + "docs/discovery" + "docs/srs" + "docs/batches" + "docs/releases" ) for dir in "${dirs[@]}"; do diff --git a/bootstrap/source-allowlist.txt b/bootstrap/source-allowlist.txt index 905262c..0341831 100644 --- a/bootstrap/source-allowlist.txt +++ b/bootstrap/source-allowlist.txt @@ -1,14 +1,12 @@ # Relative paths from selected source .github directory. # Files -AGENTS.md -START-HERE.md copilot-instructions.md # Directories agents/ instructions/ prompts/ +runbooks/ scripts/ skills/ templates/ -tools/ diff --git a/bootstrap/stagepilot.sh b/bootstrap/stagepilot.sh new file mode 100644 index 0000000..fd5f566 --- /dev/null +++ b/bootstrap/stagepilot.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash + +set -euo pipefail + +usage() { + cat <<'EOF' +Usage: stagepilot.sh [args] + +Commands: + bootstrap-seed [HOST_ROOT] [options] + Create .stagepilot/bootstrap/baseline.yaml from interactive answers + or explicit CLI arguments. + doctor [HOST_ROOT] [--strict-missing-docs] [--report ] + Run the StagePilot validation script against a workspace. +EOF +} + +fail() { + printf '[stagepilot] ERROR: %s\n' "$*" >&2 + exit 1 +} + +run_doctor() { + local script_dir package_root doctor_script + script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + package_root="$(cd "${script_dir}/.." && pwd)" + doctor_script="${package_root}/.github/scripts/stagepilot-doctor.py" + + [ -f "${doctor_script}" ] || fail "Doctor script not found: ${doctor_script}" + command -v python3 >/dev/null 2>&1 || fail "python3 is required to run doctor" + + python3 "${doctor_script}" "$@" +} + +run_bootstrap_seed() { + local script_dir package_root seed_script + script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + package_root="$(cd "${script_dir}/.." && pwd)" + seed_script="${package_root}/.github/scripts/stagepilot-bootstrap-seed.py" + + [ -f "${seed_script}" ] || fail "Bootstrap seed helper not found: ${seed_script}" + command -v python3 >/dev/null 2>&1 || fail "python3 is required to generate a bootstrap seed" + + python3 "${seed_script}" "$@" +} + +main() { + local command="${1:-}" + if [ -z "${command}" ]; then + usage + exit 1 + fi + shift || true + + case "${command}" in + bootstrap-seed) + run_bootstrap_seed "$@" + ;; + doctor) + run_doctor "$@" + ;; + -h|--help|help) + usage + ;; + *) + usage + fail "Unknown command: ${command}" + ;; + esac +} + +main "$@" \ No newline at end of file diff --git a/docs/sdlc/index.md b/docs/sdlc/index.md deleted file mode 100644 index 6f71d3d..0000000 --- a/docs/sdlc/index.md +++ /dev/null @@ -1,21 +0,0 @@ -# SDLC 전체 주기 인덱스 - - - -## 주기 목록 - -| ID | 날짜 | 이슈명 | Discovery | 상태 | -|---|---|---|---|---| -| sdlc-001_20260417_stage-pilot | 20260417 | stage-pilot 프로젝트의 사용 설명서 작성 | [Discovery](./sdlc-001_20260417_stage-pilot/1_discovery.md) | draft | - -## 단계별 횡단 조회 - -| 단계 | 문서 목록 | -|---|---| -| Discovery | [sdlc-001_20260417_stage-pilot](./sdlc-001_20260417_stage-pilot/1_discovery.md) | -| Planning | | -| Design | | -| Implementation | | -| Verification | | -| Release | | -| Operations | | \ No newline at end of file diff --git a/docs/sdlc/sdlc-001_20260417_stage-pilot/1_discovery.md b/docs/sdlc/sdlc-001_20260417_stage-pilot/1_discovery.md deleted file mode 100644 index a0aa58a..0000000 --- a/docs/sdlc/sdlc-001_20260417_stage-pilot/1_discovery.md +++ /dev/null @@ -1,202 +0,0 @@ -# 0. 문서 상태 -이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다. - -- 상태: draft -- 문서 ID: sdlc-001_20260417_stage-pilot -- 이슈명: stage-pilot 프로젝트의 사용 설명서 작성 -- 작성 시각(KST): 2026-04-17 13:45:58 KST -- 마지막 갱신 시각(KST): 2026-04-17 14:12:00 KST - -# 1. 계획 상태 요약 -현재 Discovery가 어떤 배경에서 작성되고 있는지, 연계 문서가 있는지, 지금 시점의 해석이 무엇인지 짧게 요약한다. - -- 연계 문서 현황: - - Planning 점수 파일: 미생성 - - 관련 TODO/메모: 없음 -- 해석: - - stage-pilot 저장소를 처음 도입하거나 업데이트하려는 사용자가 설치, 업데이트, SDLC 프롬프트 사용법을 빠르게 이해할 수 있도록 공식 사용 설명서가 필요하다. - - 이번 Discovery에서는 README 중심의 사용 설명서를 어떤 범위와 수준으로 작성할지 정의하고, 설치 절차와 운영성 정보를 문서 구조에 반영할 기준을 정해야 한다. - -# 2. 요구사항 판정 결과 -이번 요청이 기존 요구사항과 비교해 신규인지, 유사한지, 중복인지 판단하고 그 근거를 남긴다. - -- 판정: 신규 -- 근거 - - 현재 저장소에는 기본 사용방법과 SDLC 프롬프트 요약은 있으나, 프로젝트 전체 사용 설명서를 별도 산출물로 정의한 SDLC 주기나 관련 문서 세트가 존재하지 않는다. - - 요청은 기존 README 보완 수준을 넘어 설치, 업데이트, 프롬프트 사용 흐름을 체계화하는 신규 문서 작업으로 해석하는 것이 합리적이다. - -# 3. 문제점의 요약 -문제의 현재 상태, 기대 상태, 관련 이해관계자, 제약사항을 정리한다. Discovery의 핵심 맥락을 가장 먼저 이해할 수 있어야 한다. - -- 현재 상태 - - README에 최초 등록, 업데이트, SDLC 프롬프트 사용법이 간단히 정리되어 있지만, 사용자의 목표별 진입 경로와 단계별 설명이 충분히 구조화되어 있지 않다. - - 설치 스크립트와 운영 흐름은 존재하지만 어떤 순서로 실행해야 하는지, 어떤 상황에서 어떤 명령을 선택해야 하는지에 대한 사용 설명서가 부족하다. -- 기대 상태 - - 신규 사용자가 저장소 도입부터 업데이트, SDLC 프롬프트 실행까지를 하나의 사용 설명서만 읽고 재현 가능하게 따라갈 수 있어야 한다. - - 사용 설명서의 위치(README 확장 또는 별도 문서)가 확정된 후, 사용자가 해당 위치에서 설치/업데이트 절차와 참고 문서를 빠르게 찾을 수 있어야 한다. -- 이해관계자 - - 문서 작성자(AI agent 또는 프로젝트 유지보수자) - - 저장소를 도입하는 개발자 또는 팀 - - stage-pilot 운영/관리 담당자 -- 제약사항 - - 현재 확인 가능한 근거 문서는 README와 bootstrap 스크립트, 프롬프트/템플릿 구조로 제한되므로 세부 운영 정책은 추후 확인이 필요할 수 있다. - - 사용 설명서는 실제 저장소 구조와 스크립트 동작을 기준으로 작성해야 하며, 존재하지 않는 자동화나 미확인 절차를 단정적으로 문서화하면 안 된다. - -## 주요 사용자 시나리오 -사용자 또는 운영자가 실제로 어떤 상황에서 이 변경을 필요로 하는지 대표 시나리오를 적는다. - -- 신규 팀원이 stage-pilot을 기존 저장소에 연결하고 bootstrap 설치를 적용하기 위해 공식 사용 설명서를 따라 최초 설정을 수행한다. -- 기존 사용자가 stage-pilot subtree를 최신 상태로 갱신하면서 `--no-overwrite`, `--skip-install` 같은 옵션 차이를 확인한다. -- Copilot Chat 사용자가 어떤 프롬프트를 어떤 순서로 실행해야 하는지 이해하기 위해 SDLC 실행 흐름과 예시 명령을 참조한다. - -# 4. 이번에 정의할 변경 -이번 Discovery에서 다루는 핵심 변경 항목을 목록으로 적는다. 기능, 구조, 규칙 변경을 함께 포함해도 된다. - -- stage-pilot의 설치, 업데이트, SDLC 프롬프트 사용 흐름을 설명하는 공식 사용 설명서의 초안 범위를 정의한다. -- 기존 README와 bootstrap 스크립트 기준으로 사용자 관점의 작업 절차와 주요 명령 예시를 문서 구조에 반영한다. -- 향후 Planning에서 문서 위치, 섹션 구성, 검증 방법을 세분화할 수 있도록 문서 산출물과 성공 기준의 기준선을 세운다. - -## 영향 범위 -변경이 미칠 코드/문서/운영 범위를 명시해 Planning에서 추정 누락을 줄인다. - -- 코드 영향: - - 코드 변경 자체는 제한적이거나 없을 가능성이 높지만, 문서 경로를 README에서 연결하거나 프롬프트 안내 문구를 조정하는 변경이 필요할 수 있다. - - bootstrap 스크립트 사용 예시와 실제 옵션 동작의 일치 여부를 확인하기 위한 점검이 필요하다. -- 문서 영향: - - README 또는 별도 사용 설명서 문서가 새로 작성되거나 대폭 보강될 수 있다. - - SDLC 관련 안내 문서와 시작 가이드에서 사용 설명서 링크를 추가해야 할 수 있다. -- 운영 영향: - - 배포/운영 절차 변경은 없으나, 문서가 최신 상태로 유지되도록 이후 업데이트 시 문서 동기화 책임이 필요하다. - - 사용자 문의 대응 시 참조 기준 문서가 새로 생기므로 운영 커뮤니케이션 비용이 줄어들 수 있다. - -# 5. 요구사항 목록 -실제로 구현과 검증으로 이어질 요구사항을 기능/비기능으로 나누어 정리하고, 범위 경계를 명확히 적는다. - -## 기능 요구사항 -- FR-1: 사용 설명서는 stage-pilot의 최초 등록 절차를 리모트 등록, subtree 추가, bootstrap 설치 순서대로 설명해야 한다. -- FR-2: 사용 설명서는 업데이트 절차를 기본 업데이트, 덮어쓰기 방지, 원격 URL 직접 사용, 설치 생략 옵션으로 구분해 설명해야 한다. -- FR-3: 사용 설명서는 Copilot Chat 기반 SDLC 프롬프트의 기본 실행 순서와 대표 명령 예시를 포함해야 한다. -- FR-4: 사용 설명서는 사용자가 추가 참고 문서를 찾을 수 있도록 관련 파일 또는 디렉터리 위치를 명시해야 한다. - -## 비기능 요구사항 -성능, 운영성, 일관성, 자동화 안정성 등 기능 외 요구사항을 적는다. - -- NFR-1: 문서 내용은 현재 저장소에 실제 존재하는 파일, 스크립트, 명령만 기준으로 작성되어야 한다. -- NFR-2: 문서는 신규 사용자가 한 번에 읽을 수 있도록 작업 흐름 중심으로 구조화되어야 하며, 명령 예시는 복사 가능한 형태로 제공되어야 한다. -- NFR-3: README 및 관련 가이드와 용어가 일관되어야 하며, 단계 명칭과 문서 ID 규칙이 서로 충돌하지 않아야 한다. - -## 범위 경계 -이번 반복에서 반드시 포함할 범위와 명시적으로 제외할 범위를 구분한다. - -- In Scope - - stage-pilot 저장소 사용 설명서의 목적, 주요 섹션, 포함할 명령/예시 범위 정의 - - 설치, 업데이트, SDLC 프롬프트 사용 흐름에 대한 초안 수준의 문서 요구사항 정리 -- Out of Scope - - bootstrap 스크립트의 기능 변경 또는 신규 자동화 추가 - - README 외 별도 웹 문서 사이트 구축이나 다국어 번역 지원 (후속 반복에서 검토) - -# 6. 리스크/가정 목록 -불확실성과 전제 조건을 분리해서 적는다. 리스크는 영향과 완화 방안을, 가정은 현재 판단의 전제를 기록한다. - -## 리스크 -- R-1 (Medium): 사용 설명서가 README의 현재 내용만 재서술하고 실제 사용자 질문에 필요한 맥락을 충분히 추가하지 못할 수 있다. - - 완화 방안: Planning 단계에서 사용자 작업 시나리오 기준의 섹션 구조와 예시 수준을 명확히 정의한다. -- R-2 (Medium): 스크립트 옵션이나 프롬프트 예시가 실제 최신 동작과 어긋나면 문서 신뢰도가 떨어질 수 있다. - - 완화 방안: 문서 작성 전에 bootstrap 스크립트와 프롬프트 정의 파일을 대조해 명령과 옵션을 검증한다. -- R-3 (Low): 문서 위치가 README 확장인지 별도 가이드 문서인지 결정되지 않으면 이후 링크 구조가 바뀔 수 있다. - - 완화 방안: 사용자 결정 필요 항목으로 위치 정책을 확인하고, 확정 전까지는 문서 산출물 형태를 초안 수준으로 유지한다. - -## 가정 -아직 확정되지 않았지만 현재 문서 작성의 기반이 되는 전제를 적는다. - -- A-1: 이번 작업의 1차 산출물은 개발자 중심의 사용 설명서이며, 운영자/리뷰어 안내까지 포함하는 범위는 Planning 이후 반복에서 검토한다. -- A-2: 설치 및 업데이트 절차의 정본은 현재 README와 bootstrap 스크립트이며, 사용 설명서는 이를 재구성해 설명하는 형태가 된다. -- A-3: 문서 초안은 우선 한국어 기준으로 작성해도 무방하며, 영문 병행 여부는 후속 결정 사항이다. - -## 오픈 질문 -답을 아직 모르는 항목을 적는다. 추정으로 덮지 말고 Planning 이전에 확인할 질문으로 남긴다. - -- OQ-1: 사용 설명서를 README 확장으로 작성할지, 별도 문서 파일로 분리할지 최종 산출물 위치를 어디로 할 것인가? - - 상태: Open - - 처리 방안: 사용자 또는 승인자가 문서 배치 정책을 결정한다. - - 종료 조건: Planning 시작 전 최종 산출물 경로가 확정된다. -- OQ-2: 사용 설명서에 포함할 대상 독자 범위를 개발자 전용으로 제한할지, 운영자/리뷰어 안내까지 포함할지 확정할 필요가 있는가? - - 상태: Open - - 처리 방안: 사용자와 범위 경계를 확인해 In Scope를 확정한다. - - 종료 조건: 대상 독자와 제외 범위가 승인된다. - -### 오픈 질문 처리 기준 -- `Open`: 아직 답이 없고 다음 단계 진행에 영향이 있는 상태다. 문서에 유지한다. -- `Answered`: 답이 확정된 상태다. 관련 본문/요구사항에 반영한 뒤 오픈 질문 목록에서는 제거하거나 resolved 기록으로 이동한다. -- `Deferred`: 지금 단계에서 결정하지 않고 다음 단계 또는 후속 이슈로 넘기는 상태다. 넘길 대상과 이유를 반드시 적는다. -- `Dropped`: 더 이상 유효하지 않은 질문이다. 삭제 사유를 짧게 남기고 목록에서 제거한다. -- 처리 원칙 1: 질문만 남기지 말고 반드시 `상태`, `처리 방안`, `종료 조건`을 함께 적는다. -- 처리 원칙 2: 답이 나온 질문은 본문 반영 없이 단순 삭제하지 않는다. 반영 위치를 먼저 갱신한다. -- 처리 원칙 3: High 영향 질문은 `Deferred` 처리 후 처리 방안에 Planning 인계 추적 방식을 명시한다. - -# 7. 초기 성공 기준 -이 변경이 성공했다고 판단할 기준을 측정 가능하게 정의한다. 가능하면 데이터 출처까지 연결한다. - -- S-1: 사용 설명서 초안에 최초 등록, 업데이트, SDLC 프롬프트 사용 흐름이 모두 포함되어 있다. -- S-2: 사용 설명서 초안의 각 주요 절차에 대해 사용자가 실행 가능한 명령 예시 또는 참조 경로를 확인할 수 있다. -- S-3: 문서 검토 시 실제 저장소 구조와 맞지 않는 경로 또는 존재하지 않는 명령이 발견되지 않는다. - -## 측정 방식 및 데이터 출처 -각 성공 기준을 어떻게 측정할지와 어떤 데이터나 문서를 근거로 쓸지 적는다. - -- S-1 측정 방식: 문서 섹션 체크리스트로 포함 여부 검토 / 데이터 출처: README, bootstrap 스크립트, 프롬프트 정의 파일 -- S-2 측정 방식: 절차별 예시 명령과 링크 존재 여부 수동 검토 / 데이터 출처: 사용 설명서 초안, README -- S-3 측정 방식: 경로/명령 대조 검토 또는 샘플 실행 검토 / 데이터 출처: 저장소 파일 구조, bootstrap/*.sh, .github/prompts/ - -# 8. Planning으로 넘기기 전 확인 체크 -Planning 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. 미완료 항목은 후속 결정이 필요함을 뜻한다. - -- [ ] 범위(In Scope/Out of Scope) 확정 - - 기준: 최종 독자와 포함 대상 문서 범위가 승인되어야 한다. -- [ ] 성공 지표의 측정 방식/데이터 출처 확정 - - 기준: 샘플 실행 여부와 문서 검토 체크리스트의 적용 방법이 정리되어야 한다. -- [ ] High 영향 리스크 우선순위 및 해소 책임자 지정 - - 기준: 문서 정확성 검증 책임자 또는 검토 방식이 지정되어야 한다. -- [ ] 모든 오픈 질문(OQ) `Open` 상태 없음 확인 - - 기준: OQ 목록에 `Open` 상태 항목이 0개이거나, 잔여 항목 전부 `Deferred` 처리 완료 -- [ ] Freeze 확정 담당자(CONFIRMED_BY) 지정 - - 기준: 문서 승인 또는 인계 결정을 내릴 담당자가 명시되어야 한다. - -# 9. 파일 처리 결과 -이 Discovery 문서 생성/갱신 결과와 참조 문서를 기록한다. 이후 추적과 리뷰 시 근거로 사용한다. - -- 처리 결과: 생성 -- 생성 경로: docs/sdlc/sdlc-001_20260417_stage-pilot/1_discovery.md -- 참조 문서: - - README.md - - 없음 - -# 10. 사용자 결정 필요 항목 요약 -사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. 결정, 확인, 데이터 요청을 구분해서 적는다. - -## DECIDE -- 사용 설명서 최종 산출물을 README 확장으로 할지, 별도 문서 파일로 분리할지 결정 - -## CONFIRM -- 대상 독자 범위를 개발자 전용으로 한정할지, 운영자/리뷰어 역할까지 포함할지 확인 -- 승인 및 Freeze 확정 책임자 지정 (섹션 11의 CONFIRMED_BY에 입력) - -## DATA -- 성공 기준 #S-3 검증 시 샘플 실행 환경 및 검증 기록 방식 확인 - -# 11. Discovery Freeze -Planning 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다. - -## 섹션 참조 -- 범위: [# 5. 요구사항 목록 > 범위 경계](#5-요구사항-목록) -- 리스크/오픈 질문: [# 6. 리스크/가정 목록](#6-리스크가정-목록) -- 성공 기준: [# 7. 초기 성공 기준](#7-초기-성공-기준) -- 인계 전 확인: [# 8. Planning으로 넘기기 전 확인 체크](#8-planning으로-넘기기-전-확인-체크) -- 사용자 결정 필요: [# 10. 사용자 결정 필요 항목 요약](#10-사용자-결정-필요-항목-요약) - -## Freeze 플래그 -- Handoff Decision: 보류 -- Handoff Rationale: 초기 Discovery 초안 생성 완료, Planning 인계 전 사용자 확인 필요 -- Ready for Planning: false -- Confirmed By: TBD -- Confirmed At (KST): TBD \ No newline at end of file diff --git a/docs/sdlc/sdlc-001_20260417_stage-pilot/index.md b/docs/sdlc/sdlc-001_20260417_stage-pilot/index.md deleted file mode 100644 index 70379e4..0000000 --- a/docs/sdlc/sdlc-001_20260417_stage-pilot/index.md +++ /dev/null @@ -1,12 +0,0 @@ -# sdlc-001_20260417_stage-pilot - -| 단계 | 문서 | 상태 | -|------|------|------| -| 1. Discovery | [1_discovery.md](./1_discovery.md) | `draft` | -| 2. Planning | [2_planning.md](./2_planning.md) | `-` | -| 3. Design | [3_design.md](./3_design.md) | `-` | -| 4. Implementation | [4_implementation.md](./4_implementation.md) | `-` | -| 5. Verification | [5_verification.md](./5_verification.md) | `-` | -| 6. Release | [6_release.md](./6_release.md) | `-` | -| 7. Operations | [7_operations.md](./7_operations.md) | `-` | -| Summary | [summary.md](./summary.md) | `-` | \ No newline at end of file diff --git a/docs/sdlc/sdlc-001_20260417_stage-pilot/summary.md b/docs/sdlc/sdlc-001_20260417_stage-pilot/summary.md deleted file mode 100644 index 6c9619d..0000000 --- a/docs/sdlc/sdlc-001_20260417_stage-pilot/summary.md +++ /dev/null @@ -1,14 +0,0 @@ -# Summary - sdlc-001_20260417_stage-pilot - -- 이슈명: stage-pilot 프로젝트의 사용 설명서 작성 -- 상태: draft -- 작성 시각(KST): 2026-04-17 13:45:58 KST -- 마지막 갱신 시각(KST): 2026-04-17 13:45:58 KST - -## 핵심 요약 -- stage-pilot의 설치, 업데이트, SDLC 프롬프트 흐름을 설명하는 사용 설명서 작성 필요성이 Discovery 초안으로 정리되었다. -- 최종 문서 위치와 대상 독자 범위는 사용자 확인이 필요해 Planning 인계 전 결정이 남아 있다. - -## 단계별 문서 -- [Discovery](./1_discovery.md) -- [Index](./index.md) \ No newline at end of file diff --git a/examples/bootstrap-baseline/.stagepilot/bootstrap/baseline.yaml b/examples/bootstrap-baseline/.stagepilot/bootstrap/baseline.yaml new file mode 100644 index 0000000..ef31bc4 --- /dev/null +++ b/examples/bootstrap-baseline/.stagepilot/bootstrap/baseline.yaml @@ -0,0 +1,115 @@ +schema_version: 1 +capture_mode: declared + +project: + repository_name: sample-host-project + display_name: Sample Host Project + summary: Python-based API service for curated market data analysis. + primary_domain: financial analytics + +stack: + tech_stack: + - Python + - FastAPI + - PostgreSQL + +runtime: + primary_runtime: api-service + primary_entrypoints: + - name: uvicorn src.main:app + purpose: serve the HTTP API + - name: python -m src.jobs.refresh_market_data + purpose: refresh curated market data snapshots + +interfaces: + contracts: + - name: HTTP market data API + type: http-api + actors: internal dashboards and downstream service clients + purpose: serve curated market data and derived analytics to clients + stability: experimental + inputs: + - client requests for curated market data and analytics + outputs: + - JSON market snapshot payloads and derived analytics payloads + errors: + - 404 not_found :: symbol is not available in the curated dataset + - 503 upstream_unavailable :: refreshed data is temporarily unavailable + compatibility_rules: + - response payload changes should remain backward compatible within the same API version + - name: Refresh job command + type: cli + actors: operators and scheduled automation + purpose: update stored market data snapshots from upstream sources + stability: internal + inputs: + - python -m src.jobs.refresh_market_data :: trigger a refresh of curated market data snapshots + outputs: + - refreshed local snapshot artifacts persisted for later API reads + errors: + - non-zero exit code :: refresh failed and data should be treated as stale + compatibility_rules: + - command arguments and exit-code semantics should remain stable for automation callers + shared_constraints: + - all interfaces assume symbol identifiers are validated before persistence or response rendering + - refresh failures must not silently overwrite previously known-good snapshots + current_gaps: + - authentication and authorization rules are not defined yet + - API versioning strategy is still undecided + +structure: + planned_top_level_areas: + - path: src/ + responsibility: application code and background jobs + - path: scripts/ + responsibility: developer and operator helper commands + - path: tests/ + responsibility: automated validation and regression coverage + +data_model: + persistence_backend: PostgreSQL + entities: + - name: Market Snapshot + purpose: represent the latest curated market data for a tracked symbol + source_of_truth: PostgreSQL market_snapshots table + lifecycle: collected -> normalized -> published -> superseded + key_fields: + - symbol :: string :: tracked market identifier + - captured_at :: timestamp :: time the upstream data snapshot was collected + - payload :: json :: normalized market data stored for API responses and analytics inputs + relationships: + - Analytics Snapshot :: derived from one published Market Snapshot + state_rules: + - only one published snapshot per symbol should be treated as current + - superseded snapshots remain queryable for audit or replay use cases + - name: Analytics Snapshot + purpose: represent derived metrics computed from a market snapshot + source_of_truth: PostgreSQL analytics_snapshots table + lifecycle: queued -> computed -> published -> superseded + key_fields: + - symbol :: string :: tracked market identifier + - derived_at :: timestamp :: time analytics were computed + - metrics :: json :: derived indicators and summary values + relationships: + - Market Snapshot :: source snapshot used to compute analytics + state_rules: + - published analytics must reference an existing published or superseded market snapshot + - analytics should be recomputed whenever a new published market snapshot replaces the current one + consistency_rules: + - symbol identifiers must remain consistent across snapshot and analytics entities + - analytics records must not exist without a corresponding source market snapshot + persistence_notes: + - refresh jobs write Market Snapshot rows before recomputing Analytics Snapshot rows + - future retention and archival policies are not defined yet + current_gaps: + - exact table schema and indexing strategy are still undecided + - historical retention policy is still undecided + +notes: + known_unknowns: + - deployment target is undecided + +metadata: + captured_at_kst: 2026-04-30 16:20 + source: bootstrap-baseline-questionnaire + updated_from: user-answer \ No newline at end of file diff --git a/examples/bootstrap-baseline/README.md b/examples/bootstrap-baseline/README.md new file mode 100644 index 0000000..e3d5a6e --- /dev/null +++ b/examples/bootstrap-baseline/README.md @@ -0,0 +1,38 @@ +# Bootstrap Baseline Example + +이 예시는 fresh host 저장소에 StagePilot을 설치한 뒤 `/bootstrap-baseline`을 실행했을 때 남아야 하는 최소 active baseline 상태를 보여 준다. + +## Scenario + +1. host 저장소에 StagePilot을 설치했다. +2. 아직 Discovery, REQ, Batch, Release 문서는 하나도 없었다. +3. doctor를 실행하면 `INFO [bootstrap-required]`로 `/bootstrap-baseline`이 필요하다는 안내가 나온다. +4. `/bootstrap-baseline`이 최소 질문 세트를 받고 `.stagepilot/bootstrap/baseline.yaml`을 만든 뒤 baseline 문서와 active index를 초기화했다. +5. 첫 real Discovery는 아직 시작하지 않았고, 이 예시는 그 직후 상태를 보여 준다. + +## Files to inspect + +- `doctor-before-bootstrap-output.md` + - bootstrap 이전 fresh host 저장소에서 기대하는 doctor 출력 예시다. +- `bootstrap-baseline-output.md` + - `/bootstrap-baseline` 실행 결과 예시다. +- `.stagepilot/bootstrap/baseline.yaml` + - bootstrap 질문 답변을 저장한 seed file 예시다. +- `docs/project-structure.md` + - bootstrap으로 생성된 구조 baseline 초안 예시다. +- `docs/runtime-flows.md` + - bootstrap으로 생성된 runtime flow baseline 초안 예시다. +- `docs/interface-contract.md` + - bootstrap으로 생성된 인터페이스 계약 baseline 초안 예시다. +- `docs/data-model.md` + - bootstrap으로 생성된 데이터 모델 baseline 초안 예시다. +- `docs/discovery/index.md`, `docs/srs/index.md`, `docs/batches/index.md`, `docs/releases/index.md` + - 첫 real Discovery 전까지 비어 있어도 되는 register 골격이다. + +## Validation + +이 예시 루트는 doctor로 독립 검증할 수 있다. + +```bash +python3 .github/scripts/stagepilot-doctor.py examples/bootstrap-baseline +``` \ No newline at end of file diff --git a/examples/bootstrap-baseline/bootstrap-baseline-output.md b/examples/bootstrap-baseline/bootstrap-baseline-output.md new file mode 100644 index 0000000..62ca05b --- /dev/null +++ b/examples/bootstrap-baseline/bootstrap-baseline-output.md @@ -0,0 +1,45 @@ +# Sample Output: bootstrap-baseline + +- Input: + - fresh host repository after StagePilot install +- Asked Questions: + - `project-summary` -> `Python-based API service for curated market data analysis` + - `primary-domain` -> `financial analytics` + - `tech-stack` -> `Python, FastAPI, PostgreSQL` + - `primary-runtime` -> `api-service` + - `primary-entrypoints` -> `uvicorn src.main:app :: serve the HTTP API`, `python -m src.jobs.refresh_market_data :: refresh curated market data snapshots` + - `interface-contracts` -> `HTTP market data API :: http-api :: internal dashboards and downstream service clients :: serve curated market data and derived analytics to clients`, `Refresh job command :: cli :: operators and scheduled automation :: update stored market data snapshots from upstream sources` + - `interface-inputs` -> `HTTP market data API :: GET /markets/{symbol} :: request the current curated snapshot for a symbol`, `HTTP market data API :: GET /analytics/{symbol} :: request derived analytics for a symbol`, `Refresh job command :: python -m src.jobs.refresh_market_data :: trigger a refresh of curated market data snapshots` + - `interface-outputs` -> `HTTP market data API :: JSON market snapshot payload :: current normalized market data for the requested symbol`, `HTTP market data API :: JSON analytics payload :: derived analytics and summary metrics for the requested symbol`, `Refresh job command :: refreshed local snapshot artifacts :: normalized data persisted for later API reads` + - `interface-errors` -> `HTTP market data API :: 404 not_found :: symbol is not available in the curated dataset`, `HTTP market data API :: 503 upstream_unavailable :: refreshed data is temporarily unavailable`, `Refresh job command :: non-zero exit code :: refresh failed and data should be treated as stale` + - `core-entities` -> `Market Snapshot :: represent the latest curated market data for a tracked symbol`, `Analytics Snapshot :: represent derived metrics computed from a market snapshot` + - `persistence-backend` -> `PostgreSQL` + - `compatibility-rules` -> `HTTP market data API :: response payload changes should remain backward compatible within the same API version`, `Refresh job command :: command arguments and exit-code semantics should remain stable for automation callers` +- Created Files: + - `.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` +- Seed Status: + - `.stagepilot/bootstrap/baseline.yaml`: created +- Baseline Status: + - `docs/project-structure.md`: created + - `docs/runtime-flows.md`: created + - `docs/interface-contract.md`: created + - `docs/data-model.md`: created +- Index Status: + - `docs/discovery/index.md`: created + - `docs/srs/index.md`: created + - `docs/batches/index.md`: created + - `docs/releases/index.md`: created +- Notes: + - baseline docs were rendered from `.stagepilot/bootstrap/baseline.yaml` + - no Discovery document was created + - no REQ, Batch, or Release unit was opened +- Next Action: + - `/new-discovery ` \ No newline at end of file diff --git a/examples/bootstrap-baseline/docs/batches/index.md b/examples/bootstrap-baseline/docs/batches/index.md new file mode 100644 index 0000000..8df4c90 --- /dev/null +++ b/examples/bootstrap-baseline/docs/batches/index.md @@ -0,0 +1,6 @@ +# Batch Index + +## Batch Register + +| BAT ID | Profile | Status | Included REQ | Discovery | Folder | +| --- | --- | --- | --- | --- | --- | \ No newline at end of file diff --git a/examples/bootstrap-baseline/docs/data-model.md b/examples/bootstrap-baseline/docs/data-model.md new file mode 100644 index 0000000..5ed6138 --- /dev/null +++ b/examples/bootstrap-baseline/docs/data-model.md @@ -0,0 +1,97 @@ +# Sample Host Project Data Model + +- Baseline Mode: declared +- Baseline Seed: .stagepilot/bootstrap/baseline.yaml +- Status: confirmed +- Owner: Platform Team +- Last Updated (KST): 2026-04-30 16:30 +- Source Discovery / Batch: bootstrap-baseline + +## Project Summary +- Python-based API service for curated market data analysis. + +## Primary Domain +- financial analytics + +## Primary Persistence Backend +- PostgreSQL + +## Purpose +- This document captures the initial data model baseline after StagePilot bootstrap. +- It provides a shared reference for later REQ, delivery, migration, and verification work. + +## Scope +- Covers core entities, relationships, lifecycle rules, and persistence assumptions for the sample host project. +- Does not replace ORM code, migrations, or detailed acceptance criteria. + +## Model Summary + +- Market Snapshot :: normalized raw and curated market data for a tracked symbol +- Analytics Snapshot :: derived metrics computed from a Market Snapshot + +## Entity: `Market Snapshot` + +- Purpose: represent the latest curated market data for a tracked symbol +- Source of Truth: PostgreSQL `market_snapshots` table +- Lifecycle: collected -> normalized -> published -> superseded + +### Key Fields + +- `symbol` :: string :: tracked market identifier +- `captured_at` :: timestamp :: time the upstream data snapshot was collected +- `payload` :: json :: normalized market data stored for API responses and analytics inputs + +### Relationships + +- `Analytics Snapshot` :: derived from one published Market Snapshot + +### State Rules + +- only one published snapshot per symbol should be treated as current +- superseded snapshots remain queryable for audit or replay use cases + +## Entity: `Analytics Snapshot` + +- Purpose: represent derived metrics calculated from a market snapshot +- Source of Truth: PostgreSQL `analytics_snapshots` table +- Lifecycle: queued -> computed -> published -> superseded + +### Key Fields + +- `symbol` :: string :: tracked market identifier +- `derived_at` :: timestamp :: time analytics were computed +- `metrics` :: json :: derived indicators and summary values + +### Relationships + +- `Market Snapshot` :: source snapshot used to compute analytics + +### State Rules + +- published analytics must reference an existing published or superseded market snapshot +- analytics should be recomputed whenever a new published market snapshot replaces the current one + +## Shared Consistency Rules + +- `symbol` identifiers must remain consistent across snapshot and analytics entities +- analytics records must not exist without a corresponding source market snapshot + +## Persistence / Integration Notes + +- refresh jobs write Market Snapshot rows before recomputing Analytics Snapshot rows +- future retention and archival policies are not defined yet + +## Current Gaps / Planned Changes + +- exact table schema and indexing strategy are still undecided +- historical retention policy is still undecided + +## 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 + +- 2026-04-30: bootstrap-baseline created the initial data model baseline from declared project inputs. \ No newline at end of file diff --git a/examples/bootstrap-baseline/docs/discovery/index.md b/examples/bootstrap-baseline/docs/discovery/index.md new file mode 100644 index 0000000..8c9f028 --- /dev/null +++ b/examples/bootstrap-baseline/docs/discovery/index.md @@ -0,0 +1,8 @@ +# Discovery 전체 인덱스 + + + +## Discovery 목록 + +| ID | 날짜 | 이슈명 | 문서 | 상태 | +|---|---|---|---|---| \ No newline at end of file diff --git a/examples/bootstrap-baseline/docs/interface-contract.md b/examples/bootstrap-baseline/docs/interface-contract.md new file mode 100644 index 0000000..ec504b7 --- /dev/null +++ b/examples/bootstrap-baseline/docs/interface-contract.md @@ -0,0 +1,97 @@ +# Sample Host Project Interface Contract + +- Baseline Mode: declared +- Baseline Seed: .stagepilot/bootstrap/baseline.yaml +- Status: confirmed +- Owner: Platform Team +- Last Updated (KST): 2026-04-30 16:30 +- Source Discovery / Batch: bootstrap-baseline +- Primary Runtime: api-service + +## Project Summary +- Python-based API service for curated market data analysis. + +## Primary Domain +- financial analytics + +## Purpose +- This document captures the initial interface contract baseline after StagePilot bootstrap. +- It provides a shared reference for future REQ, design, implementation, and verification work. + +## Scope +- Covers the planned API and job interfaces exposed by the sample host project. +- Does not duplicate detailed acceptance criteria or generated OpenAPI/schema artifacts. + +## Interface Summary + +- HTTP market data API :: serve curated market data and derived analytics to clients +- Refresh job command :: update stored market data snapshots from upstream sources + +## Interface: `HTTP market data API` + +- Type: http-api +- Consumers / Producers: internal dashboards and downstream service clients +- Purpose: serve curated market data and derived analytics to clients +- Stability: experimental + +### Inputs + +- `GET /markets/{symbol}` :: request the current curated snapshot for a symbol +- `GET /analytics/{symbol}` :: request derived analytics for a symbol + +### Outputs + +- JSON market snapshot payload :: current normalized market data for the requested symbol +- JSON analytics payload :: derived analytics and summary metrics for the requested symbol + +### Error Contract + +- `404 not_found` :: symbol is not available in the curated dataset +- `503 upstream_unavailable` :: refreshed data is temporarily unavailable + +### Compatibility Rules + +- response payload changes should remain backward compatible within the same API version + +## Interface: `Refresh job command` + +- Type: cli +- Consumers / Producers: operators and scheduled automation +- Purpose: update stored market data snapshots from upstream sources +- Stability: internal + +### Inputs + +- `python -m src.jobs.refresh_market_data` :: trigger a refresh of curated market data snapshots + +### Outputs + +- refreshed local snapshot artifacts :: normalized data persisted for later API reads + +### Error Contract + +- non-zero exit code :: refresh failed and data should be treated as stale + +### Compatibility Rules + +- command arguments and exit-code semantics should remain stable for automation callers + +## Shared Constraints + +- all interfaces assume symbol identifiers are validated before persistence or response rendering +- refresh failures must not silently overwrite previously known-good snapshots + +## Current Gaps / Planned Changes + +- authentication and authorization rules are not defined yet +- API versioning strategy is still undecided + +## 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 + +- 2026-04-30: bootstrap-baseline created the initial interface contract baseline from declared project inputs. \ No newline at end of file diff --git a/examples/bootstrap-baseline/docs/project-structure.md b/examples/bootstrap-baseline/docs/project-structure.md new file mode 100644 index 0000000..3d827b0 --- /dev/null +++ b/examples/bootstrap-baseline/docs/project-structure.md @@ -0,0 +1,91 @@ +# Sample Host Project Structure + +- Baseline Mode: declared +- Baseline Seed: .stagepilot/bootstrap/baseline.yaml +- Status: confirmed +- Owner: Platform Team +- Last Updated (KST): 2026-04-30 16:30 +- Source Discovery / Batch: bootstrap-baseline + +## Project Summary +- Python-based API service for curated market data analysis. + +## Primary Domain +- financial analytics + +## Tech Stack +- Python +- FastAPI +- PostgreSQL + +## Primary Runtime +- Type: api-service +- Planned Entry Points: +- uvicorn src.main:app :: serve the HTTP API +- python -m src.jobs.refresh_market_data :: refresh curated market data snapshots + +## Purpose +- This document captures the initial repository structure baseline after StagePilot bootstrap. +- It becomes a shared reference before the first real Discovery starts. + +## Scope +- Covers top-level repository layout and broad module boundaries. +- Does not define feature-specific acceptance criteria or delivery units. + +## Top-Level Structure + +```text +. +├── .github/ +├── .stagepilot/ +├── docs/ +├── src/ +├── scripts/ +├── tests/ +└── README.md +``` + +## Package / Module Responsibilities + +- `.github/` + - StagePilot skills, templates, and host instructions installed into the repository. +- `.stagepilot/` + - bootstrap declaration seed used to render the baseline documents. +- `docs/` + - Active SDLC docs, index files, and cross-cutting baseline references. +- `src/` + - Product and service implementation code. +- `scripts/` + - developer and operator helper commands. +- `tests/` + - Automated checks and regression coverage. + +## Dependency Rules + +- Delivery documents under `docs/` must not be treated as implementation modules. +- `src/` can evolve independently, but structure changes should update this baseline. +- `.stagepilot/bootstrap/baseline.yaml` should be updated when the declared project identity changes before code exists. +- Tooling automation under `.github/` must not overwrite host source code. + +## Shared Boundaries + +- `.github/` provides SDLC workflow assets. +- `.stagepilot/` stores bootstrap declarations outside active SDLC units. +- `docs/` is the source of truth for active SDLC state. +- `src/`, `scripts/`, and `tests/` remain host-project owned implementation surfaces. + +## Current Gaps / Planned Changes + +- The first real Discovery has not been created yet. +- Deployment target is still undecided. +- Actual domain module boundaries will be refined once the first delivery topic is defined. + +## Update Triggers + +- Update this document when top-level directories change. +- Update this document when module ownership boundaries change. +- Update this document when a batch changes the approved structure baseline. + +## Change Log + +- 2026-04-30: bootstrap-baseline created the initial repository structure baseline from `.stagepilot/bootstrap/baseline.yaml`. \ No newline at end of file diff --git a/examples/bootstrap-baseline/docs/releases/index.md b/examples/bootstrap-baseline/docs/releases/index.md new file mode 100644 index 0000000..a7717ce --- /dev/null +++ b/examples/bootstrap-baseline/docs/releases/index.md @@ -0,0 +1,6 @@ +# Release Index + +## Release Register + +| REL ID | Profile | Status | Included Batch | Discovery/REQ Input | Link | +| --- | --- | --- | --- | --- | --- | \ No newline at end of file diff --git a/examples/bootstrap-baseline/docs/runtime-flows.md b/examples/bootstrap-baseline/docs/runtime-flows.md new file mode 100644 index 0000000..310b601 --- /dev/null +++ b/examples/bootstrap-baseline/docs/runtime-flows.md @@ -0,0 +1,68 @@ +# Sample Host Project Runtime Flows + +- Baseline Mode: declared +- Baseline Seed: .stagepilot/bootstrap/baseline.yaml +- Status: confirmed +- Owner: Platform Team +- Last Updated (KST): 2026-04-30 16:30 +- Source Discovery / Batch: bootstrap-baseline +- Primary Runtime: api-service + +## Project Summary +- Python-based API service for curated market data analysis. + +## Purpose +- This document captures the initial command and runtime flow baseline after StagePilot bootstrap. +- It gives later Discovery and Batch work a stable reference before product-specific flows exist. + +## Scope +- Covers bootstrap, discovery start, and validation entry points. +- Does not define detailed feature behavior. + +## Covered Entry Points + +- uvicorn src.main:app :: serve the HTTP API +- python -m src.jobs.refresh_market_data :: refresh curated market data snapshots +- Copilot Chat /bootstrap-baseline :: initialize declared baseline docs + +## Shared Components + +- .stagepilot/bootstrap/baseline.yaml +- `.github/skills/` +- `docs/project-structure.md` +- `docs/*/index.md` + +## Flow: `bootstrap baseline initialization` + +1. StagePilot assets are installed into the host repository. +2. `/bootstrap-baseline` collects the minimum declaration set and writes `.stagepilot/bootstrap/baseline.yaml`. +3. baseline docs and active index skeletons are rendered from that seed. +4. The repository becomes ready for the first real Discovery. + +## Flow: `planned host runtime` + +1. Operator starts `uvicorn src.main:app` to serve the planned HTTP API. +2. Background refresh can run with `python -m src.jobs.refresh_market_data`. +3. Detailed production flows remain subject to later Discovery and delivery work. + +## Flow Constraints + +- Fresh host repositories should complete baseline initialization before the first real Discovery. +- Declared runtime assumptions must stay in sync with `.stagepilot/bootstrap/baseline.yaml` until observed implementation evidence exists. +- Structure or orchestration changes must update this document or `docs/project-structure.md`. + +## Current Gaps / Planned Changes + +- Product-specific runtime orchestration is not defined yet. +- Deployment target is undecided. +- Delivery and release flows will be added by later Discovery and Batch work. + +## Update Triggers + +- Update this document when command entry points change. +- Update this document when runtime orchestration changes. +- Update this document when a batch changes the approved flow baseline. + +## Change Log + +- 2026-04-30: bootstrap-baseline created the initial runtime flow baseline from `.stagepilot/bootstrap/baseline.yaml`. \ No newline at end of file diff --git a/examples/bootstrap-baseline/docs/srs/index.md b/examples/bootstrap-baseline/docs/srs/index.md new file mode 100644 index 0000000..be0d471 --- /dev/null +++ b/examples/bootstrap-baseline/docs/srs/index.md @@ -0,0 +1,19 @@ +# Software Requirement Specification Index + +## 목적 +- 이 문서는 bootstrap-baseline 직후의 requirement register 골격 예시다. +- 첫 real Discovery 이후 `draft-req`가 실제 requirement를 추가한다. + +## Next Requirement ID + +- Current: `REQ-001` +- Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다. + +## Requirement Register + +| ID | Title | Type | Status | Priority | Owner | Link | +| --- | --- | --- | --- | --- | --- | --- | + +## Recent Change Log Summary + +- none \ No newline at end of file diff --git a/examples/bootstrap-baseline/doctor-before-bootstrap-output.md b/examples/bootstrap-baseline/doctor-before-bootstrap-output.md new file mode 100644 index 0000000..4181d8d --- /dev/null +++ b/examples/bootstrap-baseline/doctor-before-bootstrap-output.md @@ -0,0 +1,9 @@ +# Sample Output: doctor before bootstrap-baseline + +fresh host 저장소에서 아직 baseline이 초기화되지 않은 경우 doctor는 아래처럼 bootstrap 안내를 함께 출력한다. + +```text +WARN [missing-active-docs] .: No active SDLC docs were found under docs/. Workspace-specific checks were skipped. +INFO [bootstrap-required] .: Fresh host repos should run /bootstrap-baseline in Copilot Chat before the first real Discovery. Missing bootstrap files: docs/discovery/index.md, docs/srs/index.md, docs/batches/index.md, docs/releases/index.md, docs/project-structure.md, docs/runtime-flows.md +stagepilot-doctor: 0 error(s), 1 warning(s), 1 info message(s) +``` \ No newline at end of file diff --git a/examples/p3-change-management/README.md b/examples/p3-change-management/README.md new file mode 100644 index 0000000..b7514f7 --- /dev/null +++ b/examples/p3-change-management/README.md @@ -0,0 +1,32 @@ +# P3 Example: change-req and suggest-next-discovery + +이 예시는 release feedback 이후 개선 루프를 어떻게 닫는지 보여 주는 self-contained sample workspace다. + +## Scenario + +1. `rel-001` 배포가 `feedback-captured` 상태로 닫혔다. +2. 운영 피드백에서 두 종류의 후속 작업이 나왔다. + - 기존 REQ 강화: 문서 release checklist의 acceptance criteria를 더 엄격하게 바꿔야 한다. + - 신규 반복 후보: release feedback를 기반으로 follow-up triage를 자동 추천하는 개선이 필요하다. +3. `suggest-next-discovery rel-001`는 위 두 항목을 각각 `change-req`와 `new-discovery`로 분류한다. +4. 이 예시의 active docs는 그 결과 `change-req req-001`를 이미 한 번 적용한 뒤의 상태를 보여 준다. + +## Files to inspect + +- `docs/releases/rel-001_20260428_docs_release_hardening.md` + - `Feedback Handoff`에 `Discovery Input`, `REQ Input`, `Change Request Input`이 모두 있다. +- `docs/srs/Documentation/req-001_docs_release_checklist.md` + - 두 번째 `Change Log` 항목이 `change-req` 실행 결과를 나타낸다. + - 구현 근거가 무효화되어 상태가 `Approved`로 되돌아간 상태다. +- `suggest-next-discovery-output.md` + - `suggest-next-discovery rel-001`의 예시 결과다. +- `change-req-output.md` + - `change-req req-001`의 예시 결과다. + +## Validation + +이 예시 루트는 doctor로 독립 검증할 수 있다. + +```bash +python3 .github/scripts/stagepilot-doctor.py examples/p3-change-management +``` \ No newline at end of file diff --git a/examples/p3-change-management/change-req-output.md b/examples/p3-change-management/change-req-output.md new file mode 100644 index 0000000..0bea906 --- /dev/null +++ b/examples/p3-change-management/change-req-output.md @@ -0,0 +1,22 @@ +# Sample Output: change-req req-001 + +- Target REQ: `docs/srs/Documentation/req-001_docs_release_checklist.md` +- New Change Entry: `CHG-2026-04-30-02` represented as `CHG-20260430-02` +- Change Summary: + - docs-only release profile에서도 broken-link 검증을 필수 acceptance criteria로 승격 + - delivery trace에 기존 batch/release 영향과 재검증 필요 여부를 추가 +- Impacted Delivery Trace: + - Batches: `bat-001` + - Releases: `rel-001` +- Revalidation Impact: + - Reverification Needed: `yes` + - Existing Implementation Invalidated: `yes` + - Status Recommendation: `revert-to-approved` +- Result: + - REQ status changed from `Implemented` to `Approved` + - `docs/srs/index.md` register status changed to `Approved` + - `Recent Change Log Summary` updated with the new change entry + +## Rationale + +이 변경은 기존 release evidence만으로는 새 acceptance criteria를 충족했다고 볼 수 없으므로 `Implemented` 상태를 유지할 수 없다. 따라서 REQ는 `Approved`로 되돌아가고, 후속 batch verification을 다시 거쳐야 한다. \ No newline at end of file diff --git a/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/design.md b/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/design.md new file mode 100644 index 0000000..22684fe --- /dev/null +++ b/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/design.md @@ -0,0 +1,23 @@ +# bat-001 Design + +- Status: confirmed + +## Architecture Summary +- docs-only release는 app-service health signal 대신 문서 품질 증거를 사용한다. + +## Changed Areas +- release template +- feedback handoff structure + +## Key Decisions +- docs-only release는 broken-link와 release note update를 핵심 evidence로 남긴다. + +## Edge Cases +- release 후 feedback로 acceptance criteria가 강화되면 REQ 상태를 되돌릴 수 있다. + +## Architecture Impact +- runtime-flows + +## Reference Doc Update Plan +- project-structure.md: none +- runtime-flows.md: docs-only release feedback flow 반영 \ No newline at end of file diff --git a/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/implementation.md b/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/implementation.md new file mode 100644 index 0000000..a5a8e5c --- /dev/null +++ b/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/implementation.md @@ -0,0 +1,22 @@ +# bat-001 Implementation + +- Status: completed +- Batch: bat-001 + +## Plan Summary +- release template와 docs-only verification structure를 구현했다. + +## Changed Files +- .github/templates/releases/release.md +- README.md + +## Execution Log +1. docs-only release profile 섹션 추가 +2. feedback handoff를 Discovery/REQ로 나누어 기록 + +## Validation +- manual release review +- doctor sample workspace check + +## Remaining Risks +- 후속 feedback가 REQ 변경으로 이어질 수 있다. \ No newline at end of file diff --git a/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/index.md b/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/index.md new file mode 100644 index 0000000..9899f86 --- /dev/null +++ b/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/index.md @@ -0,0 +1,26 @@ +# bat-001: docs release hardening + +- Status: released +- Profile: standard +- Source Discovery: dcy-001 +- Included REQ: req-001 +- Excluded REQ: 없음 + +## Summary +- docs-only release checklist를 requirement와 release evidence로 연결하는 batch다. + +## Scope +- In Scope: + - release template update + - docs-only verification structure +- Out of Scope: + - runtime health checks + +## Documents +- Planning: [planning.md](./planning.md) +- Design: [design.md](./design.md) +- Implementation: [implementation.md](./implementation.md) +- Verification: [verification.md](./verification.md) + +## Notes +- release feedback 이후 req-001이 다시 `Approved`로 되돌아갔다. \ No newline at end of file diff --git a/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/planning.md b/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/planning.md new file mode 100644 index 0000000..0fd10cd --- /dev/null +++ b/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/planning.md @@ -0,0 +1,30 @@ +# bat-001 Planning + +- Status: confirmed +- Batch: bat-001 +- Profile: standard + +## Included REQ +- req-001 + +## Delivery Plan +- release template와 docs-only release evidence 구조를 정리한다. + +## Dependencies +- Internal: + - release template + - README validation guide +- External: + - none + +## Design Gate +- Design Required Before Implementation: yes +- Reason: docs-only release profile과 evidence structure를 새로 정의해야 한다. + +## Milestones +1. release template 정리 +2. release evidence 반영 +3. feedback handoff 확인 + +## Risks +- docs-only validation 기준이 release 후 강화될 수 있다. \ No newline at end of file diff --git a/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/verification.md b/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/verification.md new file mode 100644 index 0000000..0132a0f --- /dev/null +++ b/examples/p3-change-management/docs/batches/bat-001_20260427_docs_release_hardening/verification.md @@ -0,0 +1,22 @@ +# bat-001 Verification + +- Status: confirmed +- Batch: bat-001 + +## Acceptance Mapping +- req-001: + - AC1 -> docs-only release checklist evidence + - AC2 -> feedback handoff structure + +## Evidence +- Test: + - doctor sample validation passed before release +- Manual: + - docs-only release note and checklist reviewed +- Logs: + - release review notes + +## Result +- Ready for Release: true +- Blocking Issues: + - 없음 \ No newline at end of file diff --git a/examples/p3-change-management/docs/batches/index.md b/examples/p3-change-management/docs/batches/index.md new file mode 100644 index 0000000..4930146 --- /dev/null +++ b/examples/p3-change-management/docs/batches/index.md @@ -0,0 +1,7 @@ +# Batch Index + +## Batch Register + +| BAT ID | Profile | Status | Included REQ | Discovery | Folder | +| --- | --- | --- | --- | --- | --- | +| bat-001 | standard | released | req-001 | dcy-001 | [batch](./bat-001_20260427_docs_release_hardening) | \ No newline at end of file diff --git a/examples/p3-change-management/docs/discovery/dcy-001_20260425_docs_release_quality_loop.md b/examples/p3-change-management/docs/discovery/dcy-001_20260425_docs_release_quality_loop.md new file mode 100644 index 0000000..085d8ba --- /dev/null +++ b/examples/p3-change-management/docs/discovery/dcy-001_20260425_docs_release_quality_loop.md @@ -0,0 +1,149 @@ +# Discovery + +- 상태: confirmed +- 문서 ID: dcy-001_20260425_docs_release_quality_loop +- 이슈명: Docs release quality loop +- 작성 시각(KST): 2026-04-25 10:00 +- 마지막 갱신 시각(KST): 2026-04-30 13:00 +- 대체됨: 없음 +- 후속 Discovery 참조: 없음 +- 생성된 REQ 참조: req-001 + +# 1. 계획 상태 요약 + +- 연계 문서 현황: + - 관련 점수 파일: 미생성 + - 관련 TODO/메모: 없음 +- 해석: + - docs-only release에서도 문서 검증 품질이 release 판단 근거에 직접 연결돼야 한다. + - 운영 피드백으로 checklist 강화를 반복적으로 흡수할 수 있어야 한다. + +# 2. 요구사항 판정 결과 + +- 판정: 신규 +- 근거 + - 기존 release checklist는 docs-only profile 세분화 기준이 부족했다. + - follow-up feedback를 기존 REQ와 연결할 필요가 있었다. + +# 3. 문제점의 요약 + +- 현재 상태 + - docs release는 수동 검토 메모에 의존한다. + - broken-link 점검과 release note 점검이 acceptance criteria로 명확히 드러나지 않는다. +- 기대 상태 + - release checklist가 명시적 acceptance criteria와 evidence로 연결된다. + - 운영 피드백이 후속 REQ 또는 Discovery로 자연스럽게 이어진다. +- 이해관계자 + - maintainer + - reviewer + - docs consumer +- 제약사항 + - 문서 패키지는 app-service 운영 지표를 사용하지 않는다. + - doctor 검증과 release 문서만으로도 추적 가능해야 한다. + +## 주요 사용자 시나리오 + +- maintainer가 docs-only release 전 broken-link와 release note 상태를 확인한다. +- reviewer가 release feedback를 보고 기존 REQ 변경인지 신규 반복인지 판단한다. + +# 4. 이번에 정의할 변경 + +- docs release checklist를 REQ와 release evidence에 연결한다. +- feedback handoff에서 후속 작업 분류 기준을 남긴다. + +## 영향 범위 + +- 코드 영향: + - 없음 +- 문서 영향: + - docs/srs/Documentation/req-001_docs_release_checklist.md + - docs/releases/rel-001_20260428_docs_release_hardening.md +- 운영 영향: + - docs-only release review 절차 강화 + +# 5. 요구사항 목록 + +## 기능 요구사항 +- FR-1: docs-only release는 broken-link 검증을 acceptance criteria로 포함해야 한다. +- FR-2: release feedback는 후속 Discovery/REQ/change-req 입력으로 분리되어야 한다. + +## 비기능 요구사항 +- NFR-1: 변경 이력은 Change Log와 release feedback 양쪽에서 추적 가능해야 한다. + +## 범위 경계 +- In Scope + - docs release checklist + - feedback handoff structure +- Out of Scope + - app-service runtime health check + - 외부 배포 자동화 + +# 6. 리스크/가정 목록 + +## 리스크 +- R-1 (Medium): checklist 강화 시 기존 구현 증거가 부족해질 수 있다. + - 완화 방안: change-req로 상태 되돌림과 재검증 계획을 남긴다. +- R-2 (Low): feedback 분류가 모호하면 follow-up 경로가 섞일 수 있다. + - 완화 방안: suggest-next-discovery에서 분류 근거를 명시한다. + +## 가정 +- A-1: docs-only release는 doctor와 수동 리뷰 결과로 검증 가능하다. +- A-2: feedback handoff는 release 문서가 source of truth다. + +# 7. 초기 성공 기준 + +- S-1: docs checklist REQ가 release feedback까지 추적된다. +- S-2: feedback에서 change-req와 new-discovery가 구분된다. + +## 측정 방식 및 데이터 출처 + +- S-1 측정 방식: doctor traceability 확인 / 데이터 출처: docs/srs, docs/releases +- S-2 측정 방식: feedback handoff review / 데이터 출처: release 문서 + +# 8. REQ로 넘기기 전 확인 체크 + +- [x] 범위(In Scope/Out of Scope) 확정 + - 기준: docs checklist와 feedback 구조만 포함 +- [x] 성공 지표의 측정 방식/데이터 출처 확정 + - 기준: doctor와 release 문서로 추적 가능 +- [x] High 영향 리스크 우선순위 및 해소 책임자 지정 + - 기준: maintainer가 후속 변경 관리 수행 +- [x] 모든 오픈 질문(OQ) `Open` 상태 없음 확인 + - 기준: open question 없음 +- [x] Freeze 확정 담당자(CONFIRMED_BY) 지정 + - 기준: maintainer confirmed + +# 9. 파일 처리 결과 + +- 처리 결과: 생성 +- 생성 경로: docs/discovery/dcy-001_20260425_docs_release_quality_loop.md +- 참조 문서: + - docs/srs/Documentation/req-001_docs_release_checklist.md + - docs/releases/rel-001_20260428_docs_release_hardening.md + +# 10. 사용자 결정 필요 항목 요약 + +## DECIDE +- 없음 + +## CONFIRM +- 없음 + +## DATA +- 없음 + +# 11. Discovery Freeze + +## 섹션 참조 +- 범위: [# 5. 요구사항 목록 > 범위 경계](#5-요구사항-목록) +- 리스크/오픈 질문: [# 6. 리스크/가정 목록](#6-리스크가정-목록) +- 성공 기준: [# 7. 초기 성공 기준](#7-초기-성공-기준) +- 인계 전 확인: [# 8. REQ로 넘기기 전 확인 체크](#8-req로-넘기기-전-확인-체크) +- 사용자 결정 필요: [# 10. 사용자 결정 필요 항목 요약](#10-사용자-결정-필요-항목-요약) + +## Freeze 플래그 +- Handoff Decision: REQ Drafting 진행 가능 +- Handoff Rationale: docs release quality loop를 REQ와 release feedback에 연결할 준비가 됨 +- Ready for REQ Drafting: true +- Confirmed By: maintainer +- Confirmed At (KST): 2026-04-25 11:00 \ No newline at end of file diff --git a/examples/p3-change-management/docs/discovery/index.md b/examples/p3-change-management/docs/discovery/index.md new file mode 100644 index 0000000..3dde566 --- /dev/null +++ b/examples/p3-change-management/docs/discovery/index.md @@ -0,0 +1,7 @@ +# Discovery 전체 인덱스 + +## Discovery 목록 + +| ID | 날짜 | 이슈명 | 문서 | 상태 | +|---|---|---|---|---| +| dcy-001 | 20260425 | Docs release quality loop | [Discovery](./dcy-001_20260425_docs_release_quality_loop.md) | confirmed | \ No newline at end of file diff --git a/examples/p3-change-management/docs/releases/index.md b/examples/p3-change-management/docs/releases/index.md new file mode 100644 index 0000000..f454a80 --- /dev/null +++ b/examples/p3-change-management/docs/releases/index.md @@ -0,0 +1,7 @@ +# Release Index + +## Release Register + +| REL ID | Profile | Status | Included Batch | Discovery/REQ Input | Link | +| --- | --- | --- | --- | --- | --- | +| rel-001 | docs-only | feedback-captured | bat-001 | dcy-001, req-001 | [release](./rel-001_20260428_docs_release_hardening.md) | \ No newline at end of file diff --git a/examples/p3-change-management/docs/releases/rel-001_20260428_docs_release_hardening.md b/examples/p3-change-management/docs/releases/rel-001_20260428_docs_release_hardening.md new file mode 100644 index 0000000..f630951 --- /dev/null +++ b/examples/p3-change-management/docs/releases/rel-001_20260428_docs_release_hardening.md @@ -0,0 +1,94 @@ +# rel-001: docs release hardening + +- Status: feedback-captured +- Profile: docs-only +- Included Batch: bat-001 + +## Scope +- Included: + - docs-only release profile evidence + - feedback handoff structure +- Excluded: + - app-service rollout automation + +## Rollout Plan +1. merge release template updates +2. publish package update + +## Rollback Plan +- revert package update and release note changes + +## Verification Checklist +- docs-only release note updated +- broken-link verification reviewed +- feedback handoff recorded + +## Release Execution Evidence +- Release Status Transition Target: released + +### Deployment Facts +- Executed At: + - 2026-04-28T09:00:00Z +- Completed At: + - 2026-04-28T09:12:00Z +- Environment: + - repository package +- Operator: + - docs maintainer +- Revision or Artifact: + - main@HEAD +- Commands or Procedure: + - merge release prep and publish package update + +### Profile-Specific Checks +- docs-only: + - Published or Packaged Targets: + - release template and README guidance + - Link or Rendering Check: + - doctor broken-link validation reviewed during release + - Navigation or Consumer Update: + - release note updated for docs-only profile +- tooling: + - Install or Upgrade Smoke: + - none + - CLI or Script Execution: + - none + - Compatibility Note: + - none +- app-service: + - Health Endpoint: + - n/a + - Startup Log Fields: + - n/a + - Request Log Fields: + - n/a + - Smoke or Manual Verification: + - n/a + +### Rollback Outcome +- Rollback Required: + - no +- Rollback Trigger: + - none +- Rollback Action: + - none + +### Release Decision Evidence +- Released Decision: + - yes +- Rationale: + - docs-only release evidence was sufficient at release time +- Recorded By: + - docs maintainer +- Recorded At: + - 2026-04-28T09:12:00Z + +## Feedback Handoff +- Observation Summary: + - docs consumers requested stricter broken-link evidence and clearer follow-up triage +- Discovery Input: + - release feedback triage automation for maintainers +- REQ Input: + - release note checklist for docs-only profile +- Change Request Input: + - req-001 docs release checklist needs stricter broken-link acceptance criteria \ No newline at end of file diff --git a/examples/p3-change-management/docs/srs/Documentation/req-001_docs_release_checklist.md b/examples/p3-change-management/docs/srs/Documentation/req-001_docs_release_checklist.md new file mode 100644 index 0000000..cda9af4 --- /dev/null +++ b/examples/p3-change-management/docs/srs/Documentation/req-001_docs_release_checklist.md @@ -0,0 +1,110 @@ +# req-001: Docs release checklist + +- Status: Approved +- Type: Documentation +- Priority: Medium +- Owner: Docs Maintainer + +## Intent +- docs-only release에서도 소비자 관점의 품질 게이트를 문서화하고 검증 근거로 남긴다. + +## Requirement +- docs-only release는 release note 반영과 broken-link 검증 결과를 release evidence에 포함해야 한다. + +## Acceptance Criteria +1. Given docs-only release가 준비되었을 때, When release evidence를 검토하면, Then broken-link 검증 결과가 명시되어야 한다. +2. Given release feedback가 수집되었을 때, When follow-up를 분류하면, Then Discovery/REQ/change-req 입력이 구분되어야 한다. + +## Impacted Area +- Docs: docs/releases/rel-001_20260428_docs_release_hardening.md, README.md +- Modules: bootstrap/stagepilot.sh, .github/scripts/stagepilot-doctor.py +- Tests: doctor release feedback summary validation + +## Notes +- `CHG-20260430-02`로 acceptance criteria가 강화되어 기존 구현 증거는 재검증이 필요하다. + +## Change Log + +### CHG-20260426-01 +- Date: 2026-04-26 +- Author: Docs Maintainer + +#### Change Summary +- initial requirement created + +#### Intent +- docs-only release checklist를 requirement로 관리한다. + +#### Acceptance Criteria Delta +- Added: + - release evidence must include release note update result +- Updated: + - none +- Removed: + - none + +#### Impacted Area Delta +- Docs: + - release template +- Modules: + - none +- Tests: + - manual release review + +#### Delivery Trace Delta +- Batches: + - bat-001 +- Releases: + - rel-001 + +#### Revalidation Impact +- Reverification Needed: no +- Existing Implementation Invalidated: no +- Status Recommendation: keep-current +- Follow-up Action: implement through bat-001 + +#### Validation Plan +- verify release checklist before approval + +### CHG-20260430-02 +- Date: 2026-04-30 +- Author: Docs Maintainer + +#### Change Summary +- strengthen docs-only release criteria to require broken-link evidence and explicit feedback triage + +#### Intent +- release feedback에서 드러난 품질 gap을 기존 REQ에 반영한다. + +#### Acceptance Criteria Delta +- Added: + - broken-link 검증 결과가 release evidence에 포함되어야 한다. + - feedback handoff는 Discovery/REQ/change-req 입력을 구분해야 한다. +- Updated: + - release note update alone is no longer sufficient for docs-only release verification. +- Removed: + - none + +#### Impacted Area Delta +- Docs: + - docs/releases/rel-001_20260428_docs_release_hardening.md + - README.md +- Modules: + - .github/scripts/stagepilot-doctor.py +- Tests: + - doctor feedback summary sample + +#### Delivery Trace Delta +- Batches: + - bat-001 needs reverification or successor batch is required +- Releases: + - rel-001 remains historical evidence only + +#### Revalidation Impact +- Reverification Needed: yes +- Existing Implementation Invalidated: yes +- Status Recommendation: revert-to-approved +- Follow-up Action: prepare a follow-up batch to reverify docs-only release criteria + +#### Validation Plan +- rerun doctor on a follow-up batch and verify release feedback summary plus broken-link evidence \ No newline at end of file diff --git a/examples/p3-change-management/docs/srs/index.md b/examples/p3-change-management/docs/srs/index.md new file mode 100644 index 0000000..dc68960 --- /dev/null +++ b/examples/p3-change-management/docs/srs/index.md @@ -0,0 +1,26 @@ +# Software Requirement Specification Index + +## 목적 +- 이 문서는 프로젝트의 SRS 운영 기준과 requirement 목록을 관리하는 entry point이다. +- 개별 requirement의 상세 내용은 타입별 폴더 하위 `req-XXX_*.md` 파일에서 관리한다. + +## 사용 방법 +1. 새로운 requirement가 필요하면 `Next Requirement ID`를 확인하고 `docs/srs/req-template.md`를 복사해 `docs/srs//req-XXX_.md` 파일을 생성한다. +2. 초안 작성은 `draft-req`, 승인 전환은 `confirm-req`, 변경 대응은 `change-req`, 구현 완료 전환은 `confirm-req-implemented` skill을 기준으로 수행한다. +3. 작성 또는 수정 후 누락과 모호성을 점검한다. +4. requirement 추가 또는 변경 후 `Next Requirement ID`, `Requirement Register`, `Recent Change Log Summary`를 함께 갱신한다. + +## Next Requirement ID + +- Current: `REQ-002` +- Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다. + +## Requirement Register + +| ID | Title | Type | Status | Priority | Owner | Link | +| --- | --- | --- | --- | --- | --- | --- | +| REQ-001 | Docs release checklist | Documentation | Approved | Medium | Docs Maintainer | [req-001](./Documentation/req-001_docs_release_checklist.md) | + +## Recent Change Log Summary + +- 2026-04-30 `REQ-001` `CHG-20260430-02`: broken-link acceptance criteria 강화, 상태 `Implemented -> Approved` \ No newline at end of file diff --git a/examples/p3-change-management/suggest-next-discovery-output.md b/examples/p3-change-management/suggest-next-discovery-output.md new file mode 100644 index 0000000..cd722ae --- /dev/null +++ b/examples/p3-change-management/suggest-next-discovery-output.md @@ -0,0 +1,44 @@ +# Sample Output: suggest-next-discovery rel-001 + +- Input Release: `rel-001` +- Release Status: `feedback-captured` +- Basis: + - `Discovery Input`: `release feedback triage automation for maintainers` + - `REQ Input`: `release note checklist for docs-only profile` + - `Change Request Input`: `req-001 docs release checklist needs stricter broken-link acceptance criteria` + +## CANDIDATE-1 + +- Classification: `change-req` +- Target: `req-001` +- Value: High +- Risk: Medium +- Effort: Low +- Reason: + - 피드백이 기존 REQ acceptance criteria 강화로 닫힌다. + - 기존 batch/release trace를 유지한 채 REQ 상태를 재검증 대상으로 되돌릴 수 있다. +- Next Command: + - `/change-req req-001` + +## CANDIDATE-2 + +- Classification: `new-discovery` +- Target: `release feedback triage automation for maintainers` +- Value: Medium +- Risk: Low +- Effort: Medium +- Reason: + - release feedback를 다음 반복 후보로 자동 분류하는 기능은 기존 REQ 수정만으로 닫히지 않는다. + - 독립 Discovery로 추적하는 편이 범위와 성공 기준을 명확히 유지한다. +- Next Command: + - `/new-discovery release feedback triage automation for maintainers` + +## CANDIDATE-3 + +- Classification: `no-action` +- Target: `release note checklist for docs-only profile` +- Value: Low +- Risk: Low +- Effort: Low +- Reason: + - 현재 `req-001` 변경에 흡수 가능하므로 별도 반복으로 분리하지 않는다. \ No newline at end of file