docs: clarify discovery authoring decisions and validation

This commit is contained in:
2026-10-01 05:31:34 +00:00
parent c50440b81b
commit d8320ef429
3 changed files with 17 additions and 11 deletions
@@ -31,20 +31,20 @@ Gitea Issue 원본과 저장소 근거를 조사해 Discovery 초안을 작성
Repository cache의 구조와 운영 규칙은 [Repository cache 운영 지침](../../../../operations/repository-cache.md)만 정본으로 사용한다. 작업할 때마다 이 문서를 새로 읽고 상세 규칙을 이 스킬에 복제하거나 완화하지 않는다. Repository cache의 구조와 운영 규칙은 [Repository cache 운영 지침](../../../../operations/repository-cache.md)만 정본으로 사용한다. 작업할 때마다 이 문서를 새로 읽고 상세 규칙을 이 스킬에 복제하거나 완화하지 않는다.
Discovery 초안을 작성하기 전에 repository cache admission gate를 반드시 통과한다. 대상 cache가 없거나 초기화되지 않았다면 `gitea-repository-cache-bootstrap` 스킬로 초기화한다. 초기화 여부와 관계없이 canonical origin에서 cache를 갱신하고, 갱신 후 다시 읽은 Gitea authoritative default-branch SHA와 local ref SHA가 정확히 일치해야 한다. 일치한 SHA를 pinned source revision으로 고정하며, gate가 실패하면 초안을 작성하지 않는다. Discovery 초안을 작성하기 전에 repository cache admission gate를 반드시 통과한다. 대상 cache가 없으면 Issue lock 획득 전에 `gitea-repository-cache-bootstrap` 스킬로 초기화하며, 기존 cache가 유효하지 않으면 자동 초기화하지 않고 중단한다. 초기화 여부와 관계없이 Issue lock 아래에서 canonical origin의 cache를 갱신하고, 갱신 후 다시 읽은 Gitea authoritative default-branch SHA와 local ref SHA가 정확히 일치해야 한다. 일치한 SHA를 pinned source revision으로 고정하며, gate가 실패하면 초안을 작성하지 않는다.
## 절차 ## 절차
1. 요청에서 exact `owner`, `repository`, Issue 번호를 추출하고 형식을 검증한다. 1. 요청에서 exact `owner`, `repository`, Issue 번호를 추출하고 형식을 검증한다. `read_file`로 `operations/repository-cache.md`를 새로 읽고 canonical cache 경로를 계산·검증한다.
2. Issue lock을 획득한 상태에서 canonical authenticated Gitea API adapter로 spec-agent의 stable account identity를 확인한다. 2. Canonical authenticated Gitea API adapter로 spec-agent의 stable account identity와 exact repository metadata를 확인한다.
3. 같은 adapter로 exact repository metadata, Issue 전체 내용과 전체 comment baseline을 읽는다. Issue title, body, state, labels, assignees, milestone과 `updated_at`을 immutable pre-write snapshot으로 보존한다. 3. 대상 cache가 없으면 `gitea-repository-cache-bootstrap` 스킬로 초기화하고 관련 lock이 해제됐는지 확인한다. 기존 cache가 있으면 자동 초기화하지 않고 canonical 검증 절차를 따른다.
4. `operations/repository-cache.md`를 새로 읽는다. Issue lock을 유지한 채 대상 cache가 없거나 초기화되지 않았다면 `gitea-repository-cache-bootstrap` 스킬을 사용한다. 4. Cache와 lock 경로의 안전성을 검증한 뒤 canonical Issue lock을 획득한다. 같은 adapter로 Issue 전체 내용과 전체 comment baseline을 새로 읽고, Issue title, body, state, labels, assignees, milestone과 `updated_at`을 immutable pre-write snapshot으로 보존한다.
5. bootstrap 완료 여부와 관계없이 canonical 순서에 따라 repository lock을 획득한다. path, bare 상태와 remote identity를 검증한 뒤 authoritative origin에서 prune/fetch한다. fetch 후 Gitea default branch와 SHA를 다시 읽고 local ref가 exact SHA와 일치하는지 확인하여 pinned source revision으로 기록한다. 어느 단계든 실패하면 repository lock을 해제하고 외부 write와 Discovery 작성을 수행하지 않는다. 5. Issue lock을 유지한 채 canonical 순서에 따라 repository lock을 획득한다. path, bare 상태와 remote identity를 검증한 뒤 authoritative origin에서 prune/fetch한다. fetch 후 Gitea default branch와 SHA를 다시 읽고 local ref가 exact SHA와 일치하는지 확인하여 pinned source revision으로 기록한다. 어느 단계든 실패하면 획득한 lock을 canonical 규칙에 따라 해제하고 외부 write와 Discovery 작성을 수행하지 않는다.
6. `read_file`로 `docs/discovery/README.md`와 `docs/discovery/TEMPLATE.md`를 새로 읽는다. 6. `read_file`로 `docs/discovery/README.md`와 `docs/discovery/TEMPLATE.md`를 새로 읽는다.
7. repository lock을 유지한 채 Issue 원본과 pinned repository SHA의 tree 및 파일을 조사한다. 움직이는 branch 이름 대신 exact pinned SHA를 사용하고, `git --git-dir=<path>/repository.git`의 read-only 명령 또는 이에 상응하는 안전한 reader만 사용하며 조사한 경로와 SHA를 기록한다. README가 정한 후속 문서의 exact 경로 존재 여부와 기존 요구사항명세서의 ID·파일명을 함께 조사한다. 7. repository lock을 유지한 채 Issue 원본과 pinned repository SHA의 tree 및 파일을 조사한다. 움직이는 branch 이름 대신 exact pinned SHA를 사용하고, `git --git-dir=<path>/repository.git`의 read-only 명령 또는 이에 상응하는 안전한 reader만 사용하며 조사한 경로와 SHA를 기록한다. README가 정한 후속 문서의 exact 경로 존재 여부와 기존 요구사항명세서의 ID·파일명을 함께 조사한다.
8. 조사 종료 시 Gitea default-branch SHA와 local ref를 다시 읽어 pinned SHA와 모두 일치하는지 확인하고 repository lock을 해제한다. Issue lock은 전체 Issue workflow가 끝날 때까지 유지한다. 8. 조사 종료 시 Gitea default-branch SHA와 local ref를 다시 읽어 pinned SHA와 모두 일치하는지 확인하고 repository lock을 해제한다. Issue lock은 전체 Issue workflow가 끝날 때까지 유지한다.
9. README의 작성 규칙과 TEMPLATE의 visible 구조를 그대로 적용해 Discovery body artifact를 작성한다. `문서 영향 및 산출물`은 README가 정한 모든 문서 유형을 빠짐없이 판정하고 문서별 필수 내용을 구현 에이전트가 추가 설계 없이 작성할 수 있을 정도로 구체화한다. 요구사항명세서는 pinned SHA에서 충돌 여부를 확인한 exact 문서 ID·경로·제목·포함할 내용·제외할 내용을 기록한다. 모든 `${...}` placeholder를 교체하고 TEMPLATE에 없는 hidden state, marker 또는 metadata를 추가하지 않는다. 9. README의 작성 규칙과 TEMPLATE의 visible 구조를 그대로 적용해 Discovery body artifact를 작성한다. `문서 영향 및 산출물`은 README가 정한 모든 문서 유형을 빠짐없이 판정하고 문서별 필수 내용을 구현 에이전트가 추가 설계 없이 작성할 수 있을 정도로 구체화한다. 요구사항명세서는 pinned SHA에서 충돌 여부를 확인한 exact 문서 ID·경로·제목·포함할 내용·제외할 내용을 기록한다. 모든 `${...}` placeholder를 교체하고 TEMPLATE에 없는 hidden state, marker 또는 metadata를 추가하지 않는다.
10. body artifact의 첫 marker, 섹션 순서·제목, placeholder 부재, `문서 영향 및 산출물`의 문서 유형·순서·조치·경로·변경 내용·근거와 문서별 필수 내용 및 모든 저장소 근거가 pinned SHA에서 확인됐는지 검증한다. 신규 요구사항명세서의 경로에 `NNN`, `<slug>` 또는 다른 미확정 값이 남아 있거나 ID 충돌·형식 오류를 해소할 수 없으면 외부 write 없이 중단한다. 10. README의 작성 후 검증에 따라 형식 검증과 내용 검토를 각각 수행한다. body artifact의 첫 marker, 섹션 순서·제목, placeholder 부재, `문서 영향 및 산출물`의 문서 유형·순서·조치·경로·변경 내용·근거와 문서별 필수 내용 및 모든 저장소 근거가 pinned SHA에서 확인됐는지 검증한다. 신규 요구사항명세서의 경로에 `NNN`, `<slug>` 또는 다른 미확정 값이 남아 있거나 ID 충돌·형식 오류를 해소할 수 없으면 외부 write 없이 중단한다.
11. write 직전에 Issue와 comments를 다시 읽는다. pre-write snapshot의 body와 `updated_at`이 달라졌거나 comment baseline이 drift했으면 중단한다. 11. write 직전에 Issue와 comments를 다시 읽는다. pre-write snapshot의 body와 `updated_at`이 달라졌거나 comment baseline이 drift했으면 중단한다.
12. 아래의 단순 원본 보존 comment 형식으로 exact comment artifact를 만들고 한 번 작성한 뒤, 곧바로 comment 목록에서 authoritative readback한다. 12. 아래의 단순 원본 보존 comment 형식으로 exact comment artifact를 만들고 한 번 작성한 뒤, 곧바로 comment 목록에서 authoritative readback한다.
13. comment readback 직후 Issue와 comments를 다시 읽어 post-comment snapshot을 만든다. body와 비본문 필드가 pre-write snapshot과 같고 comments가 baseline과 exact 신규 comment 하나로만 구성돼야 한다. 다르면 body를 변경하지 않고 partial 상태로 중단한다. 13. comment readback 직후 Issue와 comments를 다시 읽어 post-comment snapshot을 만든다. body와 비본문 필드가 pre-write snapshot과 같고 comments가 baseline과 exact 신규 comment 하나로만 구성돼야 한다. 다르면 body를 변경하지 않고 partial 상태로 중단한다.
@@ -96,7 +96,7 @@ comment는 다음 형식을 사용한다. `<original-body>`에는 write 직전 G
- repository cache 경로, 신규 초기화 또는 기존 재사용 여부, fetch 결과, bare 상태, pinned branch와 Gitea/local SHA 일치 - repository cache 경로, 신규 초기화 또는 기존 재사용 여부, fetch 결과, bare 상태, pinned branch와 Gitea/local SHA 일치
- 원본 Issue snapshot과 comment baseline - 원본 Issue snapshot과 comment baseline
- 조사한 repository evidence - 조사한 repository evidence
- Discovery 문서 정본 검증 결과 - Discovery 문서의 형식 검증·내용 검토 결과와 미해결 질문 여부
- `문서 영향 및 산출물`의 문서별 조치와 검증 결과 - `문서 영향 및 산출물`의 문서별 조치와 검증 결과
- 원본 보존 comment ID, author, marker와 digest readback - 원본 보존 comment ID, author, marker와 digest readback
- Issue body exact readback과 비본문 필드 불변성 - Issue body exact readback과 비본문 필드 불변성
+8 -2
View File
@@ -44,14 +44,20 @@ Discovery는 Gitea Issue 본문으로 작성한다.
- `조치`는 세 값 중 하나만 사용한다. - `조치`는 세 값 중 하나만 사용한다.
- pinned source revision에 정본 문서가 없고 문서 영향이 있으면 `신규 작성`, 정본 문서가 있고 문서 영향이 있으면 `갱신`으로 기록한다. - pinned source revision에 정본 문서가 없고 문서 영향이 있으면 `신규 작성`, 정본 문서가 있고 문서 영향이 있으면 `갱신`으로 기록한다.
- `영향 없음`인 경우에도 변경 내용에 영향이 없는 이유를 기록한다. - `영향 없음`인 경우에도 변경 내용에 영향이 없는 이유를 기록한다.
- 요구사항명세서는 pinned source revision의 기존 `docs/requirements/req-NNN_<slug>.md` 파일을 조사해 충돌하지 않는 `REQ-NNN`을 결정하고, 확정된 범위를 나타내는 소문자 ASCII 케밥 표기법의 slug를 사용해 exact 경로를 기록한다. README와 TEMPLATE는 할당된 요구사항 ID로 세지 않는다. - 요구사항명세서는 pinned source revision의 기존 `docs/requirements/req-NNN_<slug>.md` 파일을 조사해 이번 변경을 기존 문서에 반영할지, 별도 문서로 작성할지 판단한다. 기존 기능의 동작이나 정책을 변경·확장하는 경우에는 기존 ID와 경로를 유지하여 갱신한다. 독립된 기능을 추가하는 경우에는 신규 작성하며, 선택 이유를 `근거`에 간단히 기록한다. 기존 문서가 승인됐거나 변경 내용이 기존 제외 범위에 있었다는 사실만으로 신규 문서를 만들지는 않는다.
- 기존 요구사항 파일이 없으면 `REQ-001`부터 시작한다. 기존 ID가 `REQ-001`부터 빠짐없이 연속이면 가장 큰 ID의 다음 값을 사용한다. 기존 ID가 중복·비연속·형식 오류 상태이거나 exact 파일명을 안전하게 결정할 수 없으면 값을 추측하지 않고 Discovery 작성을 중단한다. - 기존 문서를 갱신할 때는 `변경 내용`에 변경할 계약, 유지할 계약, revision 및 추적성 갱신을 기록한다. 신규 작성할 때만 기존 ID를 조사해 충돌하지 않는 다음 `REQ-NNN`과 exact 경로를 결정한다. 기존 요구사항 파일이 없으면 `REQ-001`부터 시작한다. 기존 ID가 `REQ-001`부터 빠짐없이 연속이면 가장 큰 ID의 다음 값을 사용한다. 기존 ID가 중복·비연속·형식 오류 상태이거나 exact 파일명을 안전하게 결정할 수 없으면 값을 추측하지 않고 Discovery 작성을 중단한다. 확정된 범위를 나타내는 소문자 ASCII 케밥 표기법의 slug를 사용해 exact 경로를 기록한다. README와 TEMPLATE는 할당된 요구사항 ID로 세지 않는다.
- 요구사항명세서 항목에는 `문서 ID`, `제목`, `포함할 내용`, `제외할 내용`을 추가한다. 포함할 내용은 구현 에이전트가 요구사항과 acceptance criteria로 내려야 할 동작, 오류, 보안, 데이터·인터페이스, 호환성 및 추적성 계약을 구체적으로 나열한다. - 요구사항명세서 항목에는 `문서 ID`, `제목`, `포함할 내용`, `제외할 내용`을 추가한다. 포함할 내용은 구현 에이전트가 요구사항과 acceptance criteria로 내려야 할 동작, 오류, 보안, 데이터·인터페이스, 호환성 및 추적성 계약을 구체적으로 나열한다.
- 데이터 모델은 변경할 엔터티·필드·관계·불변조건·마이그레이션을, 인터페이스 계약은 입력·출력·인증·오류·호환성을, 프로젝트 구조는 경로·책임·의존 방향·배치 규칙을, 런타임 흐름은 시작 조건·단계·상태 변경·외부 호출·실패 복구·동시성·관찰 가능성을 변경 내용에 기록한다. - 데이터 모델은 변경할 엔터티·필드·관계·불변조건·마이그레이션을, 인터페이스 계약은 입력·출력·인증·오류·호환성을, 프로젝트 구조는 경로·책임·의존 방향·배치 규칙을, 런타임 흐름은 시작 조건·단계·상태 변경·외부 호출·실패 복구·동시성·관찰 가능성을 변경 내용에 기록한다.
- 문서가 `영향 없음`이면 해당 문서 계약이 왜 바뀌지 않는지 확정 범위와 저장소 근거를 사용해 설명한다. - 문서가 `영향 없음`이면 해당 문서 계약이 왜 바뀌지 않는지 확정 범위와 저장소 근거를 사용해 설명한다.
- 변경 내용에는 구현 에이전트가 문서에 반영할 계약과 범위만 기록한다. Discovery 작성 중 후속 문서를 생성하거나 수정하지 않는다. - 변경 내용에는 구현 에이전트가 문서에 반영할 계약과 범위만 기록한다. Discovery 작성 중 후속 문서를 생성하거나 수정하지 않는다.
- 저장소 근거나 확정된 결정 없이 엔터티, 인터페이스, 디렉터리, 실행 흐름 또는 문서 변경을 만들어내지 않는다. - 저장소 근거나 확정된 결정 없이 엔터티, 인터페이스, 디렉터리, 실행 흐름 또는 문서 변경을 만들어내지 않는다.
## 작성 후 검증
- 형식 검증: TEMPLATE의 marker·섹션 순서, 필수 항목과 placeholder 부재를 확인한다.
- 내용 검토: 저장소 근거가 작성 내용을 뒷받침하는지, 요구사항 문서의 갱신·신규 선택이 적절한지, 확정된 결정과 미해결 질문이 서로 모순되지 않는지 확인한다.
- 형식 검증 통과만으로 내용 검토나 구현 준비가 완료됐다고 판단하지 않는다. 미해결 질문이 있는 초안은 질문을 남긴 상태로 게시할 수 있으며, 완료 보고에 이를 명시한다.
## OQ(${open_questions}) 작성 방법 ## OQ(${open_questions}) 작성 방법
각 OQ에는 질문에 대한 설명과 선택지를 작성하고 추천안을 표시한다. 모든 선택지는 체크박스(`[ ]`)를 사용한다. 각 OQ에는 질문에 대한 설명과 선택지를 작성하고 추천안을 표시한다. 모든 선택지는 체크박스(`[ ]`)를 사용한다.
+1 -1
View File
@@ -62,7 +62,7 @@ Repository cache 경로는 고정된 machine-local 절대경로나 현재 작업
- Linux OS advisory lock을 사용한다. lock file descriptor는 symlink를 따라가지 않는 방식으로 열고 원자적으로 lock을 획득한다. - Linux OS advisory lock을 사용한다. lock file descriptor는 symlink를 따라가지 않는 방식으로 열고 원자적으로 lock을 획득한다.
- 독립적인 신규 cache 초기화 순서는 `bootstrap.lock → repository.lock`이다. - 독립적인 신규 cache 초기화 순서는 `bootstrap.lock → repository.lock`이다.
- Issue workflow가 기존 cache를 사용할 때의 순서는 `issue-<issue-number>.lock → repository.lock`이다. - Issue workflow가 기존 cache를 사용할 때의 순서는 `issue-<issue-number>.lock → repository.lock`이다.
- Issue workflow가 cache 초기화까지 수행할 때의 순서는 `issue-<issue-number>.lock → bootstrap.lock → repository.lock`이다. bootstrap 절차는 이미 획득한 Issue lock을 해제하거나 다시 획득하지 않는다. - Issue 작업에 사용할 cache가 없으면 Issue lock 획득 전에 신규 cache 초기화 절차를 완료한다. 초기화 중에는 Issue를 변경하지 않는다. Bootstrap의 repository lock과 bootstrap lock을 모두 해제한 뒤 Issue lock을 획득하며, 이후에는 기존 cache 사용 순서인 `issue-<issue-number>.lock → repository.lock`을 따른다. Issue 작업의 기준 snapshot은 Issue lock 획득 후 읽는다.
- Worktree 생성, 등록, lock, 이동, 제거 또는 repair는 Issue lock을 유지한 채 repository lock을 추가로 획득해서 수행한다. 일반 파일 편집, 테스트와 commit에는 Issue lock만 유지하고 repository lock은 보유하지 않는다. - Worktree 생성, 등록, lock, 이동, 제거 또는 repair는 Issue lock을 유지한 채 repository lock을 추가로 획득해서 수행한다. 일반 파일 편집, 테스트와 commit에는 Issue lock만 유지하고 repository lock은 보유하지 않는다.
- 같은 repository의 다른 Issue worktree를 검사, 변경 또는 제거하지 않는다. 한 Issue workflow는 자신의 exact Issue worktree만 다룬다. - 같은 repository의 다른 Issue worktree를 검사, 변경 또는 제거하지 않는다. 한 Issue workflow는 자신의 exact Issue worktree만 다룬다.
- 반대 순서로 lock을 획득하거나 이미 잡은 상위 lock을 해제한 뒤 하위 작업을 계속하지 않는다. - 반대 순서로 lock을 획득하거나 이미 잡은 상위 lock을 해제한 뒤 하위 작업을 계속하지 않는다.