Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
id: GF-145
title: Sigkill Foundry 형식 설계 문서 세우기
status: Done
assignee: []
created_date: '2026-10-05 11:52'
updated_date: '2026-10-10 22:38'
labels:
- docs
dependencies: []
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
최상위 Sigkill Foundry 설계 문서와 같은 5문서 세트(design/: 0 문서 정보, 1 제안서 ~ 5 구현 결과 보고서, 부록)를 이 저장소에 세우고, Claude 앱 문서를 편집 원본으로 둔다. 이 저장소의 README·backlog 레퍼런스 문서·decision에서 1.01 배경과 문제, 1.02 원칙, 3.01 시스템 구성을 채우고 나머지 장은 골격으로 둔다(원천은 기존 문서). 진척 서술 금지.

수용 기준(승격 시 AC로 등록):
1. design/ 구조·장 형식이 최상위 Sigkill Foundry와 같다
2. 1.01 · 1.02 · 3.01을 기존 문서 근거로 채우고 나머지는 골격으로 둔다
3. Claude 앱에 장별 문서와 목차 문서를 만들고 design/README.md에 링크한다
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [x] #1 design/ 구조·장 형식이 최상위 Sigkill Foundry와 같다
- [x] #2 1.01 · 1.02 · 3.01을 기존 문서 근거로 채우고 나머지는 골격으로 둔다
- [x] #3 설계 문서의 원본은 design/ 하나다 — Claude 앱 편집 원본 문구 · 링크 칸을 두지 않고, 목차 상태는 실제 파일 기준
<!-- AC:END -->

## Final Summary

<!-- SECTION:FINAL_SUMMARY:BEGIN -->
최상위 Sigkill Foundry와 같은 5문서 설계 세트(design/)를 세웠다. 장 파일 구성은 최상위와 일치.
- 0 문서 정보: 최상위 TRL · NFR 번호를 같은 ID · 같은 뜻으로 이어받음(로컬 번호 대역 없음).
- 1.01 배경과 문제(계측 컴포넌트, 검사와 기록, 문제-대응 7행, 세 기둥), 1.02 원칙 P1~P12(대체 관계 표 포함), 3.01 시스템 구성(구성 요소 8개, 커밋 생애주기 DOT 흐름도, 트레일러 11종 표, TRL ↔ 훅 함수 대응). 나머지는 골격.
- 3.01은 현재 코드 기준(훅 3개) — decision-18·19의 통합 구조와의 차이는 3.05 · 4.03에서 다룸.
- 원본은 design/ 하나(Claude 앱 편집 원본 규칙 없음).
- 검증: python3 -m unittest discover -s tests → 106 OK.
<!-- SECTION:FINAL_SUMMARY:END -->
77 changes: 77 additions & 0 deletions design/00-문서-정보.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# 0. 문서 정보

이 문서는 coding-agent-git-commit-tool의 설계 문서다. 상위 문서는 최상위 Sigkill Foundry 설계 문서이고,
이 컴포넌트는 그 3.03 컴포넌트 명세 §3에 해당한다. 스펙 주도 개발(SDD)을 따른다 — 구현은 이 명세에서
도출하고, 명세와 코드가 어긋나면 명세를 먼저 고친 뒤 코드를 맞춘다.

## 문서 구성

설계 문서는 다섯 문서로 이어진다. 문서마다 하나의 질문에 답하고, 앞 문서의 답이 뒤 문서의 입력이 된다.

| 번호 | 문서 | 답하는 질문 |
| --- | --- | --- |
| 1 | 프로젝트 제안서 | 왜 만들고, 무엇을 어디까지 하는가 |
| 2 | 요구사항 명세서 | 무엇을 만족해야 하는가 |
| 3 | 아키텍처 설계서 | 어떻게 구성되고 동작하는가 |
| 4 | 구현 계획서 | 어떤 순서로 만들고, 무엇으로 판정하는가 |
| 5 | 구현 결과 보고서 | 무엇을 만들었고, 판정은 어떻게 나왔는가 |

장은 `문서 번호.장 번호`로 가리킨다 (예: 3.05 설계 결정). 장 안의 절은 `§`로 가리킨다 (예: 3.03 §1).
최상위 Sigkill Foundry 문서의 장은 앞에 "최상위"를 붙여 가리킨다 (예: 최상위 3.03 §3).

## 규범 용어

| 표현 | 뜻 |
| --- | --- |
| 반드시 ~한다 (MUST) | 어기면 명세 위반이다 |
| ~해야 한다 (SHOULD) | 어길 때는 이유를 3.05 설계 결정에 남긴다 |
| ~할 수 있다 (MAY) | 선택 사항이다 |

## 요구사항 표기

- 목표는 `G-<번호>`로 식별하고 1.03 목표와 범위에 둔다. 최상위 목표는 "최상위 G-n"으로 적는다.
- 원칙은 `P<번호>`로 식별하고 1.02 원칙에 둔다. 최상위 원칙은 "최상위 P<번호>"로 적는다.
- 기능 요구사항의 영역 접두어는 `TRL`이다. 최상위 2.03이 이 컴포넌트에 쓰는 접두어와 같다. 품질 요구사항은 `NFR`이다.
- 요구사항 ID는 `<영역>-<세 자리 번호>`이고 번호는 재사용하지 않는다. 번호 공간은 최상위 문서 하나다.
- 최상위 2.03의 `TRL-nnn`과 2.04의 `NFR-nnn`(이 컴포넌트는 NFR-004 · NFR-005)을 같은 ID · 같은 뜻으로 이어받는다.
- 하위 번호나 이 저장소 전용 번호 대역(`TRL-101` 같은)은 두지 않는다. 최상위에 없는 요구사항이 필요하면 최상위 2.03 · 2.04에 먼저 올려 번호를 받는다.

- 설계 결정은 `ADR-<번호>`로 3.05에, 미결 사항은 `Q-<번호>`로 4.03에 둔다. 둘 다 이 저장소 안의 번호이고,
최상위 것은 "최상위 ADR-n" · "최상위 Q-n"으로 적는다.
- 원천인 backlog decision은 `decision-<번호>`, 태스크는 `GF-<번호>`로 그대로 적는다.
- 모든 요구사항은 수용 기준을 하나 이상 가진다(4.02).
- 아직 정하지 않은 값은 `TBD(Q-n)`으로 적고, `Q-n`을 4.03 미결 사항에 둔다.

## 추적 규칙

모든 요구사항은 다음 사슬로 앞뒤가 이어진다. 사슬이 끊긴 항목은 둘 수 없다.

1. 최상위 요구사항 `TRL-0nn` · `NFR-0nn` (최상위 2.03 · 2.04) — 사슬의 위쪽 끝이다.
2. → 이 저장소의 목표 `G-n` (1.03) — 목표는 자신이 이바지하는 최상위 G-n을 적는다.
3. → 요구사항 `TRL-nnn` · `NFR-nnn` (2.03 · 2.04) — 최상위 ID를 그대로 받거나, `1nn`번대로 세분하며 상위 ID를 적는다.
4. → 구성 요소 · 인터페이스 (3.01 · 3.03 · 3.04) — 구성 요소는 자신이 구현하는 요구사항 ID를 적는다.
5. → 수용 기준 (4.02) · backlog 태스크 (4.01) — 요구사항 하나는 backlog 태스크의 AC로 내려간다. 태스크 카드는 자신이 구현하는 요구사항 ID를 적는다.
6. → 결과 판정 (5.02) — 수용 기준마다 통과/실패와 그 증거(테스트 로그 · 실측 커밋)를 남긴다.

- 최상위 요구사항의 문장이 바뀌면 이 저장소의 2.03 · 2.04를 먼저 맞춘다. 이 저장소가 최상위 요구사항을 바꿀 필요를 찾으면 최상위 문서에 먼저 올린다.
- 원칙(1.02)에 어긋나는 요구사항은 둘 수 없다. 원칙을 바꾸려면 3.05 설계 결정에 결정을 먼저 남긴다.
- 계획과 다르게 구현한 것은 5.03 계획 대비 편차에 적고, 해당 설계 결정(3.05)에 연결한다.

## 대상 저장소

| 컴포넌트 | 저장소 | 최상위 장 |
| --- | --- | --- |
| coding-agent-git-commit-tool | [coralstay/coding-agent-git-commit-tool][repo] | 3.03 §3 |

## 편집 규칙

- 설계 내용의 원본은 저장소의 `design/**/*.md` 하나다. 다른 곳(Claude 앱 문서 · 위키 등)에 사본이나 편집 원본을 두지 않는다. 고칠 때는 이 파일을 직접 고치고(Claude Code · GitHub 편집기) 커밋 · PR로 남긴다. 최상위 Sigkill Foundry도 같은 규칙이다.
- `backlog/docs` · `backlog/decisions` · README는 이 설계 문서의 원천이다. 설계 문서가 원천을 대신하지 않고, 원천을 지우지 않는다.
- 한 장 = 한 문서. 같은 내용을 두 장에서 고치고 있다면 한쪽을 장 참조 한 줄로 접는다.
- 외부 문헌은 저장소에 옮겨 담지 않는다(decision-14). 인용과 검증 상태는 부록 참고 문헌에서만 관리한다.
- 다이어그램 원본은 `design/diagrams/*.dot`이다. DOT으로 먼저 쓰고, DOT으로 표현할 수 없는 것(시퀀스 등)만 mermaid(`.mmd`)로 쓴다.
- `design/build-diagrams.py`가 원본을 `design/diagrams/<이름>.svg`로 렌더한다. 색은 원본에 센티넬 hex로 적고, 빌드가 SVG 안의 CSS 변수(라이트 기본 · 다크 재정의)로 바꾼다. 빌드 전제: graphviz(`dot`), mermaid 렌더용 `npx` + 로컬 Chrome.
- 생성된 SVG는 손으로 고치지 않는다. 원본을 고치고 빌드를 다시 돌려 같은 커밋에 넣는다. 장 사본은 `![설명](../diagrams/<이름>.svg)`로 참조한다.
- 저장소 Markdown의 외부 링크는 문서 맨 아래 링크 정의 블록에 모으고, 본문은 `[표시][키]`로만 쓴다.

[repo]: https://github.com/coralstay/coding-agent-git-commit-tool
88 changes: 88 additions & 0 deletions design/1-제안서/01-배경과-문제.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# 1.01 배경과 문제

coding-agent-git-commit-tool은 Sigkill Foundry의 계측 컴포넌트다(최상위 3.03 §3) — 코딩 에이전트가 만드는 git 커밋을 검사하고, 그 커밋을 누가 · 어떤 도구와 모델로 · 무슨 태스크로 · 얼마를 들여 만들었는지 커밋 안에 트레일러로 남긴다.

## 무엇을 하는가

커밋할 때마다 두 가지를 한다.

1. **검사** — 사람(또는 에이전트)이 쓴 제목 · 본문이 정해진 형식을 따르는지, 브랜치명에 태스크 번호가
있는지 확인하고, 어기면 커밋을 거부한다.
2. **기록** — 통과한 커밋 끝에 `Task-Id` · `AI-Tool` · `AI-Model` · `Tokens-Used` · `Tool-Calls` ·
`Hooks-Commit` 같은 트레일러를 자동으로 붙인다. 사람이 타이핑하지 않는다.

```text
[docs][backlog] DRAFT-18을 GF-136으로 승격 ← 사람(또는 에이전트)이 쓴다

왜 바꿨는지 설명하는 본문. 한 줄 72자 이내. ← 선택

Task-Id: GF-136 ↓ 아래는 전부 훅이 붙인다
AI-Tool: claude-code
AI-Tool-Version: 2.1.267
Co-Authored-By: Claude <noreply@anthropic.com>
AI-Model: claude-opus-5
Tokens-Used: in=5067994 out=15794
Tool-Calls: 31
Hooks-Commit: c828491
Signed-off-by: cpu-once <231006716+cpu-once@users.noreply.github.com>
```

목표는 `git log` 한 번으로 "무엇을, 왜, 누가(사람인지 어떤 모델인지), 얼마를 써서 바꿨는지"가 읽히는
것이다. 동작은 `core.hooksPath` · `init.templateDir` · `git interpret-trailers` 같은 git 자체 기능과
Python 3 표준 라이브러리만으로 이뤄진다.

## 문제

에이전트가 커밋을 대량으로 남기면 이력이 작업 로그 구실을 해야 한다. 그런데 git의 기본 커밋에는 그
구실에 필요한 정보가 없고, 있는 정보도 믿을 수 없게 되기 쉽다.

| 문제 | 왜 생기는가 | 이 컴포넌트의 대응 |
| --- | --- | --- |
| 커밋이 어느 작업의 일부인지 모른다 | 태스크 번호를 커밋마다 손으로 쓰게 하면 잊고, 강제할 방법이 없다 | 작업을 시작할 때 한 번 정하는 브랜치명에서 태스크 번호를 읽어 강제하고 `Task-Id`로 남긴다(decision-4) |
| 사람 커밋과 에이전트 커밋이 구별되지 않는다 | 커밋 객체에는 author · committer만 있고 도구 · 모델이 없다 | `AI-Tool` · `AI-Tool-Version` · `AI-Model`을 남긴다(decision-5) |
| 에이전트가 말한 값은 믿을 수 없다 | 모델명 · 토큰 수를 에이전트에게 물으면 자가신고가 된다. 토큰 수는 모델이 아는 값이 아니라 API가 응답마다 실어 주는 메타데이터다 | 값은 Claude Code가 하위 프로세스에 주입하는 환경변수와, API 응답을 그대로 기록한 세션 트랜스크립트(`message.model` · `message.usage`)에서만 얻는다(decision-5 · decision-20) |
| 작업의 비용이 이력에 남지 않는다 | 토큰 사용량은 세션 단위로만 보이고 커밋과 이어지지 않는다 | 이 커밋이 바꾼 파일을 실제로 건드린 응답의 토큰을 합해 `Tokens-Used: in=<입력> out=<출력>`으로 남긴다(decision-27) |
| 검사를 건너뛸 수 있다 | `git commit --no-verify`는 `commit-msg`를 건너뛴다 | 건너뛸 수 없는 `prepare-commit-msg`로 강제를 옮기고, 건너뛴 사실은 `Verify-Bypassed`로 기록한다(decision-3 · decision-18) |
| 기록이 나중에 거짓이 된다 | rebase · force push로 커밋을 다시 만들면 트레일러가 자기 커밋에 대해 거짓을 말한다 — 실측에서 `Signed-off-by`와 실제 커미터가 어긋났다 | 이력은 append-only로 둔다. push된 이력의 보호는 원격 저장소 설정이 맡는다(decision-24) |
| 훅에 버그가 있으면 어느 커밋이 영향을 받았는지 모른다 | 훅 버전이 커밋에 남지 않는다 | 이 커밋을 검사한 훅 클론의 커밋 해시를 `Hooks-Commit`으로 남긴다(decision-5) |

## 다루는 범위 — 세 기둥

git 이력을 작업 로그로 만드는 데 필요한 세 가지다(decision-25). 세 기둥은 서로를 필요로 한다 —
이력이 다시 쓰이면 트레일러가 거짓이 되고, 기록할 내용이 정형화돼 있지 않으면 지킬 가치가 줄어든다.

| 기둥 | 하는 일 | 해당하는 것 |
| --- | --- | --- |
| 형식 | 사람이 쓰는 제목 · 본문을 정해진 양식으로 | 제목 · 본문 검증, 에디터 경로 거부, 커밋 단위 규칙(decision-22) |
| 출처 기록 | 누가 · 어떤 도구와 모델로 · 얼마를 들여 만들었는지 자동으로 남김 | 트레일러 전체, 토큰 측정, `AI-Model` 게이트, `Task-Id` 브랜치 강제 |
| 이력 불변 | 한 번 남긴 기록은 다시 쓰지 않음 | append-only 정책(decision-24), 원격 저장소 설정(doc-20) |

용어로 말하면 trail(감사 추적)이 세 기둥 전체이고, provenance(출처 기록)가 두 번째 기둥이다.
attestation(서명된 증명)과 audit(사후 검사)이 어느 훅 · 함수 · 설정에 구현돼 있는지는 doc-21 개념
지도에 있다.

**다루지 않는 것.** 언어별 lint는 세 기둥 어디에도 속하지 않고 사용자에게 언어 도구를 전제하게 만들어
범위에서 뺐다(decision-23). push 단계에서 테스트 · 빌드를 돌리지 않는다(decision-12).

## Sigkill Foundry 안의 자리

| 항목 | 내용 |
| --- | --- |
| 층 | 계측 — 커밋 형식 검사 · 트레일러(태스크 · 모델 · 토큰) 부착 (최상위 3.01 컴포넌트 지도) |
| 어디서 도는가 | 대상 저장소의 git 훅(`core.hooksPath`). 에이전트 프로세스의 커밋이 이 훅을 거친다 |
| 구현하는 최상위 요구사항 | TRL-001 ~ TRL-009, NFR-004 · NFR-005 (최상위 2.03 · 2.04) |
| 이바지하는 최상위 목표 | G-4 계측과 감사 추적 |
| 부트스트랩 순서 | git init → backlog.md CLI → `backlog init` → **coding-agent-git-commit-tool** → claude-code-agile-hooks (최상위 3.02) |
| 소비자 | agent-orchestrator의 `CommitLedger`가 Done 시점에 태스크 브랜치의 트레일러를 읽어 태스크 카드에 기록한다 (최상위 ORC-021) |

최상위 설계는 "커밋 = 함수, 커밋당 토큰 계량"을 핵심 성질로 둔다(최상위 1.02 P7). 그 성질을 실제
커밋 안에 남기는 것이 이 컴포넌트다. 역할마다 별도 프로세스로 뜨는 구조(최상위 1.02 P2)는 세션
트랜스크립트가 역할마다 따로 생긴다는 뜻이고, 이 컴포넌트는 그 트랜스크립트로 커밋마다 토큰을
잰다. 역할 세션별 귀속이 정확한지는 아직 실측 근거가 없다(최상위 TRL-007, `TBD(최상위 Q-18)`).

## 원천

- README.md — 소개 · 완성되는 커밋은 이런 모양입니다 · 각 필드가 무엇이고 언제 만들어지는지 · 다루는 범위
- decision-3 · decision-4 · decision-5 · decision-18 · decision-20 · decision-24 · decision-25 · decision-27 · decision-29
- doc-21 개념 지도 — trail · provenance · attestation · audit
- 최상위 3.01 시스템 구성 · 3.03 §3 coding-agent-git-commit-tool
Loading
Loading