Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
- name: Install ruff
run: pip install --quiet ruff
# ruff에 디렉터리를 넘기면 확장자가 .py인 파일만 훑는다(실측 확인). git이
# 이름을 고정하는 훅 3개(prepare-commit-msg/commit-msg/post-commit)는 확장자가
# 이름을 고정하는 훅(prepare-commit-msg, GF-128부터 하나)은 확장자가
# 없어, Python으로 포팅돼도 hooks/ 하나만 지정하면 조용히 검사에서 빠진다 -
# 검사가 아무것도 안 하고 통과하는 GF-32와 같은 유형이다. 그래서 셔뱅으로
# Python 파일을 찾아 함께 넘긴다. 이 근거는 GF-135로 hooks/checks/*.py가
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
id: DRAFT-22
title: Signed-off-by 자동 삽입을 재검토한다 — DCO 의미 충돌
status: Draft
assignee: []
created_date: '2026-10-04 01:43'
updated_date: '2026-10-04 01:43'
labels:
- trailers
- policy
dependencies: []
references:
- decision-25
- decision-19
documentation:
- backlog/docs/doc-22 - 유사-프로젝트-조사-—-AI-커밋-출처-기록-도구-비교.md
priority: medium
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
post-commit은 모든 커밋에 커미터 정보로 Signed-off-by를 자동으로 붙인다(decision-25가 decision-19의 제거 조항을 대체해 유지). 그런데 Signed-off-by는 관례상 사람이 DCO를 인증한다는 서명이다.

- Linux 커널 정책: "AI agents MUST NOT add Signed-off-by tags. Only humans can legally certify the DCO."
- ai-attribution-hooks와 crashoverride 가이드는 Signed-off-by를 AI 커밋에 대한 사람의 책임 인정으로 쓰고, AI 트레일러가 있으면 이를 요구한다.

이 훅이 에이전트 커밋에도 자동으로 붙이면, DCO를 요구하는 저장소에 설치했을 때 사람이 인증하지 않은 커밋이 인증된 것처럼 보인다. 조사 근거는 doc-22.
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 Signed-off-by를 유지·제거·사람 커밋에만 붙임 중 하나로 정하고 decision으로 기록한다
- [ ] #2 결정에 맞게 GF-128 AC #10을 갱신한다
- [ ] #3 DCO를 요구하는 저장소에 설치할 때의 동작이 README에 적혀 있다
<!-- AC:END -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
id: decision-30
title: Signed-off-by는 사람이 만든 커밋에만 붙인다 (decision-25·28의 유지 조항 대체)
date: '2026-10-04 01:58'
status: accepted
---
## Context

`post-commit`은 모든 커밋에 커미터 정보로 `Signed-off-by`를 붙여 왔다(decision-25, 유저 확정은
decision-28). 2026-10-04 유사 프로젝트 조사(doc-22)에서 이 트레일러가 업계에서 쓰이는 의미와
충돌한다는 게 드러났다.

- Linux 커널 정책: "AI agents MUST NOT add Signed-off-by tags. Only humans can legally certify
the DCO."
- ai-attribution-hooks, crashoverride 가이드: `Signed-off-by`를 AI 커밋에 대한 사람의 책임
인정으로 쓴다.

에이전트 커밋에 훅이 자동으로 붙이면, DCO를 요구하는 저장소에서 사람이 인증하지 않은 커밋이
인증된 것처럼 보인다(DRAFT-22).

## Decision

**`Signed-off-by`는 사람이 만든 커밋에만 붙인다** — 유저 결정(2026-10-04).

- "사람이 만든 커밋"은 훅이 AI 도구를 감지하지 못한 커밋이다. 판정은 `AI-Agent`를 붙일지
정하는 신호와 같은 것을 쓴다(지금은 `AI_AGENT` 환경변수, GF-130에서 재작성 예정).
- 에이전트 커밋에는 붙이지 않는다. 사람이 메시지에 직접 쓴 `Signed-off-by`는 키 단위 중복
판정(GF-128)에 따라 그대로 둔다 — 운영자가 스스로 서명하는 것은 막지 않는다.

decision-25의 `Signed-off-by` 유지 조항과 decision-28을 이 decision이 대체한다.

## Consequences

- GF-128 AC #10을 이 decision에 맞게 고친다.
- DRAFT-19가 `Signed-off-by`와 실제 커미터의 불일치를 이력 재작성의 증거로 쓰려던 검사는
사람 커밋에만 적용된다. 에이전트 커밋은 다른 증거(예: `Hooks-Commit`, 커밋 객체의
committer)로 봐야 한다.
- 판정이 에이전트 감지에 기대므로, 감지가 틀리면(에이전트인데 신호가 없으면) 에이전트
커밋에 `Signed-off-by`가 붙는다. 감지의 정확도는 GF-130의 몫이다.
- DRAFT-22는 이 decision과 GF-128로 처리되어 보관한다.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
id: doc-22
title: 유사 프로젝트 조사 — AI 커밋 출처 기록 도구 비교
type: other
created_date: '2026-10-04 01:43'
updated_date: '2026-10-04 01:43'
---
2026-10-04 조사. AI 에이전트 커밋의 출처를 git에 남기는 도구·관례를 이 프로젝트와 비교한다.

## 조사 대상

| 대상 | 기록 위치 | 기록 시점 | 강제 | 메시지 형식 검증 |
| --- | --- | --- | --- | --- |
| [block/aittributor](https://github.com/block/aittributor) | `Co-authored-by` 트레일러 | `prepare-commit-msg` | 훅 | 없음 |
| [mgoodric/ai-attribution-hooks](https://github.com/mgoodric/ai-attribution-hooks) | `Assisted-by`/`Co-authored-by`/`Generated-by` | `prepare-commit-msg` + `commit-msg` | 훅 + 집계 스크립트 | 없음 |
| [git-ai](https://github.com/git-ai-project/git-ai) | git notes(`refs/notes/ai`), 줄 단위 | 에이전트가 편집할 때마다 `git ai checkpoint` | 에이전트 훅. git 훅·래퍼 없음 | 없음 |
| [Codex CLI `commit_attribution`](https://codex.danielvaughan.com/2026/03/28/codex-cli-commit-attribution/) | 트레일러 | 모델 프롬프트에 지시 주입 | 없음(모델이 따를 뿐) | 없음 |
| [Aider](https://aider.chat/docs/git.html) | `Co-authored-by` 또는 author에 `(aider)` | 도구가 커밋할 때 | 도구 안에서만 | 없음 |
| [Linux 커널 정책](https://docs.kernel.org/process/coding-assistants.html) | `Assisted-by:` 에이전트·모델 + 보조 분석 도구 | 사람이 씀 | 리뷰 | 기존 커널 규칙 |
| [crashoverride 가이드](https://crashoverride.com/resources/knowledge-base/code-ownership/attributing-ai-commits-git) | `Generated-By: <agent>/<version> (model: <id>; operator: <email>)` | — | CI "Agent Trailer Lint" | — |
| commitlint, gitlint | — | `commit-msg`(+ CI에서 커밋 범위 검사) | 훅 + CI | 있음 |

## 각 대상에서 확인한 사실

- **aittributor**: 에이전트 판정을 4단계로 한다 — 환경변수, 자기 프로세스 조상, 같은 저장소의 형제 프로세스, 에이전트 상태 파일(`~/.claude/projects/`, `~/.codex/sessions/`). 같은 이메일의 `Co-authored-by`가 이미 있으면 붙이지 않는다. lefthook 연동 또는 `.git/hooks/`에 심볼릭 링크로 설치.
- **ai-attribution-hooks**: AI 기여 비율에 따라 트레일러를 셋으로 나눈다(~33% / 35–67% / 67%+). AI 트레일러가 있으면 `commit-msg`가 `Signed-off-by`를 요구한다 — 사람이 책임진다는 이중 서명. `ai-attribution-stats.sh`가 커밋 범위에서 AI 커밋 비율과 서명 누락을 집계한다.
- **git-ai**: 커밋 메시지를 건드리지 않는다. 귀속 정보를 notes에 두고, rebase·cherry-pick·squash·reset 뒤에 최종 코드를 분석해 notes를 새 커밋으로 옮긴다(비동기, 결과적 일관성). 프롬프트는 마스킹해 git 밖에 저장. 커밋·PR별 토큰과 비용을 계산한다.
- **Codex**: 훅을 쓰지 않는다. 문서 스스로 "compliance is high but not absolute"라고 하고, 보장이 필요하면 `prepare-commit-msg` 훅을 덧대라고 권한다.
- **Linux 커널**: "AI agents MUST NOT add Signed-off-by tags. Only humans can legally certify the DCO."
- **crashoverride**: `Signed-off-by`를 운영자(사람)의 책임 인정으로 쓰라고 권한다. 과거 커밋은 다시 쓰지 말고 별도 CSV로 감사하라고 한다.

## 이 프로젝트와 비교

### 강점

- **형식·출처·이력 불변을 한 도구에서 강제한다.** 출처 도구들은 메시지 형식을 보지 않고, 형식 검사기는 출처를 남기지 않는다.
- **훅으로 강제한다.** Codex·Aider처럼 도구나 모델이 협조해야 붙는 방식이 아니어서, 에이전트가 잊어도, 사람이 커밋해도 남는다.
- **모델명과 토큰이 서버가 발급한 값이다**(Claude Code 한정). 트랜스크립트의 `message.model`과 usage를 읽는다. 다른 도구는 고정 문자열이거나 에이전트 이름까지만 남긴다.
- **`Hooks-Commit`**: 훅 자체의 버전을 커밋마다 남겨, 훅 버그의 영향 범위를 역추적할 수 있다. 다른 도구에는 없다.
- **`Task-Id` 브랜치 강제**로 커밋과 작업을 잇는다.
- **의존성이 git + python3 표준 라이브러리뿐**이고, 트레일러가 메시지에 있어 `git log`만으로 읽히며 clone·push에 그대로 따라간다. notes는 따로 push·fetch해야 한다.

### 약점

- **커밋 단위다.** git-ai는 줄 단위로 `blame`까지 된다.
- **기록이 메시지에 있어 이력을 다시 쓰면 깨진다.** git-ai는 재작성 뒤 notes를 옮겨 붙이는데, 이 프로젝트는 재작성을 금지하는 쪽(decision-24)으로 풀었다 — 사용자에게 워크플로 제약을 지운다.
- **지금은 `post-commit`의 `--amend`로 붙인다.** 해시가 바뀌고, 트레일러가 중복되고, rebase 중 실패한다. 비교한 훅 기반 도구는 전부 `prepare-commit-msg`에서 메시지 파일에 쓴다(GF-128이 같은 방향).
- **에이전트 판정이 `AI_AGENT` 하나다.** aittributor는 신호 4개를 본다(GF-130).
- **토큰 측정이 Claude Code에만 되고, 커밋 시점에 트랜스크립트를 거슬러 재구성한다**(실험 단계, doc-16). git-ai는 편집 시점에 체크포인트를 쌓는다.
- **`Signed-off-by`를 에이전트 커밋에도 자동으로 붙인다.** 커널·crashoverride·ai-attribution-hooks가 쓰는 의미(사람의 DCO 서명)와 충돌한다.
- **에디터 경로를 거부한다.** commitlint·gitlint는 `commit-msg`에서 돌아 에디터 커밋도 검증한다. 우회 차단(decision-18)과 맞바꾼 비용이다.
- **`core.hooksPath`를 점유해 다른 훅과 조합할 수 없다.** aittributor는 lefthook으로 조합된다.
- **집계 도구가 없다.** ai-attribution-hooks의 stats 스크립트, git-ai의 `stats`/`blame` 같은 읽기 도구가 없다.
- **트레일러를 손으로 위조해도 확인하는 곳이 없다.** CI 검사(DRAFT-19)는 아직 드래프트이고 서명·증명(attestation)도 없다.
- **트레일러 이름이 독자적이다.** 업계는 `Assisted-by`/`Generated-By` 쪽으로 모이는 중이다(표준은 아직 없음). GF-128의 `AI-Agent` 이름을 정할 때 고려할 것.

## 후속

- `Signed-off-by` 재검토, 체크포인트·notes 기반 측정 검토는 각각 드래프트로 남겼다.
- 이미 있는 작업과 겹치는 것: 메시지 파일 직접 쓰기·키 단위 중복 차단(GF-128), 에이전트 판정(GF-130), CI 검사(DRAFT-19).
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
id: DRAFT-23
title: 토큰 측정을 편집 시점 체크포인트와 git notes로 옮길지 검토한다
status: Draft
assignee: []
created_date: '2026-10-04 01:43'
updated_date: '2026-10-04 01:43'
labels:
- measurement
- spike
dependencies: []
references:
- decision-27
- decision-24
documentation:
- backlog/docs/doc-22 - 유사-프로젝트-조사-—-AI-커밋-출처-기록-도구-비교.md
- backlog/docs/doc-16 - 토큰·툴콜-측정-방법과-한계.md
priority: medium
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
Tokens-Used/Tool-Calls는 커밋 시점에 Claude Code 트랜스크립트를 거슬러 읽어 이 커밋의 파일을 건드린 응답을 재구성한다(decision-27, doc-16). 측정 방법론은 아직 실험 단계이고 Claude Code에만 된다.

git-ai는 다르게 한다(doc-22).
- 에이전트가 파일을 고칠 때마다 체크포인트를 남기고, 커밋할 때 합친다 — 사후 재구성이 없다. Claude Code에서는 PostToolUse 훅으로 같은 일을 할 수 있다.
- 결과를 커밋 메시지가 아니라 git notes(refs/notes/ai)에 둔다. 메시지를 다시 쓰지 않아 append-only(decision-24)와 맞고, rebase·cherry-pick 뒤에도 notes를 옮겨 붙인다. 대신 git log만으로 안 보이고 notes를 따로 push·fetch해야 한다.

두 가지(체크포인트 수집, notes 저장)는 독립적으로 채택할 수 있다. 어느 쪽이 지금 방식보다 나은지 판단할 근거가 필요하다.
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 같은 세션을 지금 방식과 체크포인트 방식으로 측정해 결과 차이를 비교한다
- [ ] #2 notes 저장 시 push·fetch·rebase에서 기록이 살아남는지 실측한다
- [ ] #3 채택·기각 여부를 decision으로 기록한다
<!-- AC:END -->
Loading
Loading