yield-audit 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. yield_audit-0.3.2/.github/workflows/ci.yml +26 -0
  2. yield_audit-0.3.2/.github/workflows/pypi.yml +46 -0
  3. yield_audit-0.3.2/.gitignore +23 -0
  4. yield_audit-0.3.2/AGENTS.md +80 -0
  5. yield_audit-0.3.2/CHANGELOG.md +237 -0
  6. yield_audit-0.3.2/HANDOFF.md +86 -0
  7. yield_audit-0.3.2/LICENSE +202 -0
  8. yield_audit-0.3.2/PKG-INFO +197 -0
  9. yield_audit-0.3.2/README.ko.md +88 -0
  10. yield_audit-0.3.2/README.md +169 -0
  11. yield_audit-0.3.2/pyproject.toml +55 -0
  12. yield_audit-0.3.2/src/yield_audit/__init__.py +3 -0
  13. yield_audit-0.3.2/src/yield_audit/__main__.py +8 -0
  14. yield_audit-0.3.2/src/yield_audit/attribute.py +117 -0
  15. yield_audit-0.3.2/src/yield_audit/audit.py +453 -0
  16. yield_audit-0.3.2/src/yield_audit/cli.py +230 -0
  17. yield_audit-0.3.2/src/yield_audit/cohorts.py +70 -0
  18. yield_audit-0.3.2/src/yield_audit/costs.py +52 -0
  19. yield_audit-0.3.2/src/yield_audit/events.py +107 -0
  20. yield_audit-0.3.2/src/yield_audit/gitdata.py +335 -0
  21. yield_audit-0.3.2/src/yield_audit/lenses/AGENTS.md +35 -0
  22. yield_audit-0.3.2/src/yield_audit/lenses/__init__.py +1 -0
  23. yield_audit-0.3.2/src/yield_audit/lenses/accepted.py +79 -0
  24. yield_audit-0.3.2/src/yield_audit/lenses/cache_locality.py +112 -0
  25. yield_audit-0.3.2/src/yield_audit/lenses/retry.py +82 -0
  26. yield_audit-0.3.2/src/yield_audit/lenses/rework.py +152 -0
  27. yield_audit-0.3.2/src/yield_audit/lenses/survival.py +239 -0
  28. yield_audit-0.3.2/src/yield_audit/lenses/verify_gap.py +101 -0
  29. yield_audit-0.3.2/src/yield_audit/lenses/waste.py +102 -0
  30. yield_audit-0.3.2/src/yield_audit/pricing.py +124 -0
  31. yield_audit-0.3.2/src/yield_audit/redact.py +117 -0
  32. yield_audit-0.3.2/src/yield_audit/report.py +239 -0
  33. yield_audit-0.3.2/src/yield_audit/transcripts/__init__.py +130 -0
  34. yield_audit-0.3.2/src/yield_audit/transcripts/base.py +208 -0
  35. yield_audit-0.3.2/src/yield_audit/transcripts/claude.py +160 -0
  36. yield_audit-0.3.2/src/yield_audit/transcripts/codex.py +195 -0
  37. yield_audit-0.3.2/tests/AGENTS.md +33 -0
  38. yield_audit-0.3.2/tests/conftest.py +367 -0
  39. yield_audit-0.3.2/tests/test_attribute.py +133 -0
  40. yield_audit-0.3.2/tests/test_e2e.py +320 -0
  41. yield_audit-0.3.2/tests/test_lenses.py +246 -0
  42. yield_audit-0.3.2/tests/test_prefilter.py +147 -0
  43. yield_audit-0.3.2/tests/test_pricing_costs.py +136 -0
  44. yield_audit-0.3.2/tests/test_redact.py +96 -0
  45. yield_audit-0.3.2/tests/test_rework.py +112 -0
  46. yield_audit-0.3.2/tests/test_transcripts.py +214 -0
  47. yield_audit-0.3.2/tests/test_transcripts_codex.py +168 -0
  48. yield_audit-0.3.2//352/270/260/355/232/215/354/204/234-AIDD-/354/240/204/355/231/230/352/263/204/353/237/211.md +89 -0
@@ -0,0 +1,26 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ${{ matrix.os }}
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ os: [ubuntu-latest, macos-latest, windows-latest]
15
+ python: ["3.10", "3.12", "3.14"]
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python }}
21
+ - name: Install
22
+ run: python -m pip install -e '.[dev]'
23
+ - name: Lint
24
+ run: ruff check .
25
+ - name: Test
26
+ run: pytest -v
@@ -0,0 +1,46 @@
1
+ name: Publish to PyPI
2
+
3
+ # PyPI trusted publishing (OIDC): the project's pending publisher on
4
+ # pypi.org is configured for this exact workflow filename — no API tokens
5
+ # anywhere. First successful run claims the `yield-audit` project name.
6
+
7
+ on:
8
+ push:
9
+ tags: ["v*"]
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ # required for the OIDC minting the publish action performs
14
+ id-token: write
15
+
16
+ jobs:
17
+ build:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.12"
24
+ - name: Build sdist and wheel
25
+ run: |
26
+ python -m pip install --upgrade build
27
+ python -m build
28
+ - name: Check metadata
29
+ run: |
30
+ python -m pip install --upgrade twine
31
+ twine check dist/*
32
+ - uses: actions/upload-artifact@v4
33
+ with:
34
+ name: dist
35
+ path: dist/
36
+
37
+ publish:
38
+ needs: build
39
+ runs-on: ubuntu-latest
40
+ steps:
41
+ - uses: actions/download-artifact@v4
42
+ with:
43
+ name: dist
44
+ path: dist/
45
+ - name: Publish to PyPI
46
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,23 @@
1
+ # macOS
2
+ .DS_Store
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.egg-info/
8
+ .eggs/
9
+ build/
10
+ dist/
11
+ .venv/
12
+ venv/
13
+
14
+ # Tooling
15
+ .pytest_cache/
16
+ .ruff_cache/
17
+ .coverage
18
+ htmlcov/
19
+ # library: lockfile stays local (CI installs via pip)
20
+ uv.lock
21
+
22
+ # yield-audit local cache
23
+ .yield/
@@ -0,0 +1,80 @@
1
+ # AGENTS.md — yield-audit
2
+
3
+ AI 코딩 에이전트(ZCode, Claude Code 등)가 이 저장소에서 작업할 때의 규약입니다.
4
+ 사람 기여자는 먼저 [README.md](README.md)를 읽으세요. 내용이 겹치면 이 문서가 우선합니다.
5
+ 렌즈 패키지와 테스트에는 하위 규약이 있습니다: [src/yield_audit/lenses/AGENTS.md](src/yield_audit/lenses/AGENTS.md), [tests/AGENTS.md](tests/AGENTS.md).
6
+
7
+ ## 이 프로젝트가 하는 일
8
+
9
+ AI 코딩 에이전트(Claude Code)의 로컬 세션 트랜스크립트와 git 이력을 대조해 **성과를 회계**합니다:
10
+ 무엇이 살아남았는지(M1 생존율), 무엇이 낭비였는지(M2), 재시도 세금(M3), 채택 작업당 비용(M4),
11
+ 캐시 지역성(M5), 검증 공백(M8), AI 리워크율(M11, 코호트 certain/probable/human). 원칙: **완전 로컬, 읽기 전용, 결정적, 런타임 의존성 0**
12
+ (Python ≥3.10 표준라이브러리 + git CLI), **절감 주장 금지 — 측정만**.
13
+
14
+ ## 명령어
15
+
16
+ ```bash
17
+ python3 -m pip install -e '.[dev]' # 또는 uv pip install -e '.[dev]'
18
+ pytest # ~3초, 커밋 전 반드시 통과
19
+ ruff check . # 반드시 클린
20
+ ```
21
+
22
+ 스모크 실행은 **픽스처/tmp 저장소에만**:
23
+
24
+ ```bash
25
+ yield-audit audit --repo <tmp fixture repo> --transcripts-dir <tmp fixtures> --now 2026-08-20T00:00:00Z --format json
26
+ ```
27
+
28
+ ⚠️ **절대 금지**: 실제 데이터 감사 — `--repo`/`--transcripts-dir`를 `/Users/*/.claude`·`~/.codex`나
29
+ 사용자의 실제 프로젝트로 향하면 1.3GB+ 전체 스캔으로 수십 초~수 분이 걸리고 사생활을 침범합니다.
30
+ 에이전트가 실데이터 스모크가 필요하면 사용자에게 먼저 물으세요.
31
+
32
+ ## 구조 (데이터 흐름)
33
+
34
+ ```
35
+ cli.py argparse, 종료코드 0/2, stdout 로케일 방어
36
+ └─ audit.py 파이프라인 오케스트레이터 — 리포트 dict 조립, 마지막에 deep_sanitize
37
+ ├─ transcripts/ 벤더 어댑터 패키지: base(공통 계약·레지스트리) + claude + codex
38
+ │ → events.Session (키 기반 방어적 파싱, 세션 id는 "vendor:<raw>" 네임스페이스)
39
+ ├─ gitdata.py 읽기 전용 git 래퍼 (스트리밍, blame=SHA 카운터, GIT_* env 제거)
40
+ ├─ attribute.py 세션↔커밋 매칭 (high/medium 등급, 1/n 분할, 모호 플래그)
41
+ ├─ cohorts.py 커밋 코호트 라벨 (certain=푸터/probable=세션 조인/human — 근거 등급, 판정 아님)
42
+ ├─ pricing/costs 공시 요금표(USD/MTok)와 관측 usage 기반 비용
43
+ ├─ lenses/ M1–M11 측정 렌즈 (순수 함수 — 하위 AGENTS.md 참고)
44
+ ├─ redact.py 출력 경계: 살균·레닥션·deep_sanitize
45
+ └─ report.py console/json/markdown 렌더러
46
+ ```
47
+
48
+ ## 필수 규약 (어기다면 버그)
49
+
50
+ 1. **렌즈는 순수 함수** — I/O·시계·난수 금지. `now`와 horizon은 인자로 받는다.
51
+ 2. **정직성 라벨** — 모든 리포트 블록에 `measurement`가 있어야 한다:
52
+ `observed`(기록에서 직접) / `estimate`(관측 × 공시요금) / `proxy`(명시된 대체량).
53
+ 라벨 없는 새 메트릭은 버그로 취급.
54
+ 3. **출력 경계** — 트랜스크립트에서 온 모든 문자열은 `redact.py`를 거친다.
55
+ `run_audit`의 deep_sanitize는 안전망이지 레닥션의 대체품이 아니다
56
+ (안전망은 이스케이프 제거만 하고, 경로 치환은 필드 단계에서 한다).
57
+ 4. **결정성** — 출력에 흐르는 모든 순회는 `sorted()` 먼저. 메트릭에 벽시계 금지
58
+ (재현은 `--now`). 스키마는 `yieldaudit.report.v1`, 변경은 하위호환(additive)만.
59
+ 5. **런타임 의존성 0** — 표준라이브러리 + `git` CLI만. pytest/ruff는 dev에서만.
60
+ 6. **서브프로세스 규율** — list argv(셸 금지), `gitdata._clean_env`로 GIT_* 제거,
61
+ 스트림은 stderr=DEVNULL + stdout EOF 후 wait, 프로세스 수는 집계 단위로 캐싱
62
+ (유닛당 무캐시 호출 금지).
63
+ 7. **측정 전용** — 절감 개입은 로드맵(v1.x) 게이트 뒤에. 리포트·문서에 절감 수치 주장 금지.
64
+
65
+ ## 테스트
66
+
67
+ - `tests/conftest.py`가 고정 날짜의 픽스처 git 저장소와 실제 스키마를 모사한 합성
68
+ 트랜스크립트를 만든다. 타임라인은 conftest 모듈 docstring이 유일한 진실원천.
69
+ - 새 렌즈/메트릭 = 렌즈 단위 테스트 + `test_e2e.py` 골든 단언 추가.
70
+ 골든 수치(13/24 생존율, $0.00643 등)는 픽스처 타임라인에서 유도된 값이므로
71
+ 픽스처 변경 시 docstring과 골든 전부를 함께 갱신.
72
+ - 악성 입력 픽스처( malformed JSONL, Infinity usage, 이스케이프 문자열)는
73
+ `test_transcripts.py`와 `test_redact.py`에. "리포트에 이스케이프 바이트 0" 보증은
74
+ `test_e2e.py::test_report_has_no_escape_bytes_anywhere`가 지킨다.
75
+
76
+ ## 릴리스
77
+
78
+ - 버전은 두 곳을 함께: `src/yield_audit/__init__.py` + `pyproject.toml`.
79
+ - Keep-a-Changelog 형식의 CHANGELOG.md 항목 추가. CI 매트릭스: 3.10–3.14 × 3 OS.
80
+ - PyPI는 미게시 상태 — README 설치 안내는 소스 설치 기준으로 유지.
@@ -0,0 +1,237 @@
1
+ # Changelog
2
+
3
+ All notable changes to yield-audit are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning is
5
+ SemVer.
6
+
7
+ ## [0.3.2] - 2026-09-06
8
+
9
+ Distribution release: published to PyPI via trusted publishing (OIDC —
10
+ the pending publisher registered on pypi.org for `.github/workflows/
11
+ pypi.yml` claims the name on first run; no API tokens anywhere).
12
+
13
+ ### Changed
14
+ - README is now fully English (the PyPI landing page) with the M11
15
+ rework-rate one-liner as the headline and a sample console report;
16
+ the Korean README moved to `README.ko.md`. Install docs switched from
17
+ source-install to `pip install yield-audit` / `uvx yield-audit`.
18
+
19
+ ### Added
20
+ - `.github/workflows/pypi.yml` — build + `twine check` + publish on
21
+ `v*` tag push (and manual dispatch).
22
+
23
+ ## [0.3.1] - 2026-09-06
24
+
25
+ Trust, first-run, and performance fixes from the v0.3.0 review.
26
+
27
+ ### Fixed
28
+ - OpenAI models priced from the table instead of the conservative
29
+ claude-opus fallback: gpt-5.1 / gpt-5.1-codex (1.25/10/0.125),
30
+ gpt-5.3-codex (1.75/14/0.175), gpt-5-mini, o3, o4-mini (standard tier,
31
+ published list prices 2026-09; codex variants share the gpt-5.1 base —
32
+ no separate listing). Codex sessions' USD figures are no longer
33
+ inflated ~4x.
34
+ - Empty-state UX: a missing `--transcripts-dir` or absent vendor roots
35
+ now fail (exit 2) with a `doctor` hint instead of producing a silent
36
+ empty report; zero matching sessions print a prominent warning line in
37
+ console/markdown while staying a valid exit-0 measurement.
38
+
39
+ ### Changed — performance
40
+ - Blame prefilter: one `git log --name-only` pass builds a per-path
41
+ touch map (committer dates, matching snapshot selection). Paths no
42
+ commit touched inside a measurement window are decided without a
43
+ single `git blame` process — same values, provably. A merge commit
44
+ inside a window forces blaming (merge resolutions rewrite lines
45
+ invisibly to the pass). Shared by M1 and M11 via the blame cache;
46
+ smoke: 102-commit full-history M11 audit in 0.12s.
47
+
48
+ ## [0.3.0] - 2026-09-05
49
+
50
+ M11 AI rework rate — the first ADD-transition lens (기획서-AIDD-전환계량.md
51
+ v0.3.0 scope): compares how quickly AI-marked commits get reworked against
52
+ human ones, measured locally from git history alone.
53
+
54
+ ### Added
55
+ - `cohorts.py`: every commit lands in one evidence-graded cohort —
56
+ `certain` (AI footer in the commit message: `Co-Authored-By: …`,
57
+ `Generated with …`, 🤖), `probable` (no footer but claimed by a
58
+ transcript session via the usual attribution join), or `human`.
59
+ Labels state matching evidence, never authorship verdicts; every
60
+ cohort percentage ships with the evidence distribution.
61
+ - `lenses/rework.py` (M11): rework = lines a commit added that are no
62
+ longer present verbatim at the snapshot `--rework-days` (default 14)
63
+ later — the complement of M1's blame survival, applied to every commit
64
+ and aggregated by cohort plus an `ai_combined` view. Pending horizons
65
+ are excluded from rates and counted honestly; `--rework-days 0`
66
+ disables the lens.
67
+ - Report block `m11_rework` and `parameters.rework_horizon_days`
68
+ (schema v1, additive); console/markdown renderers gained an M11
69
+ section; `gitdata.commit_messages` streams full commit messages for
70
+ footer evidence.
71
+
72
+ ### Changed
73
+ - Fixture repo grew commits C3 (AI-footered, new file) and C4 (human
74
+ rework of it); M1/attribution goldens are unchanged, window counts
75
+ updated (commits_in_window 4, unclaimed 3).
76
+
77
+ ## [0.2.0] - 2026-09-05
78
+
79
+ Vendor-agnostic transcripts: the Claude-only ingest module became an
80
+ adapter registry, and the Codex CLI is scanned alongside Claude Code by
81
+ default. Claude-only audits keep identical measured values (regression:
82
+ all v0.1.2 golden numbers unchanged).
83
+
84
+ ### Added
85
+ - `transcripts/` package with a `TranscriptAdapter` base class (find
86
+ files + parse one JSON record into `events.Session`) and a registry;
87
+ adding a vendor is one subclass plus one registry entry.
88
+ - Codex CLI adapter (`~/.codex/sessions` rollout JSONL): session meta /
89
+ turn context / function calls / token counts, with vendor tool names
90
+ normalized to the canonical set (shell execution becomes `Bash`,
91
+ `apply_patch` headers become edited files, exit_code becomes tool
92
+ errors). Compaction boundaries are not present in this format and stay
93
+ empty.
94
+ - `--agent {auto,claude,codex}` on `audit` and `doctor` (default `auto`:
95
+ every registered vendor; missing roots are skipped). An explicit
96
+ `--transcripts-dir` applies to all selected vendors — adapters skip
97
+ records that are not their schema, so mixed directories are safe.
98
+ - Session ids are namespaced per vendor (`"claude:<id>"`,
99
+ `"codex:<id>"`); report keys keep the prefix. Report `parameters` adds
100
+ `agents_scanned` and `transcripts_roots` (schema v1, additive).
101
+
102
+ ### Changed
103
+ - `run_audit`'s `transcripts_root` accepts `None` (each agent's own
104
+ default root) and takes a new `agents` argument; `load_sessions`
105
+ likewise. Ingest internals moved from `transcripts.py` into
106
+ `transcripts/{base,claude,codex}.py` — the public helpers are
107
+ re-exported unchanged.
108
+
109
+ ## [0.1.2] - 2026-09-05
110
+
111
+ Second review round: close the sanitizer bypasses found in v0.1.1's new
112
+ output boundary and harden ingest against hostile transcript values.
113
+ Measured values are unchanged (regression-checked against 0.1.1).
114
+
115
+ ### Fixed — security
116
+ - Session ids are transcript-controlled and reached report keys/cells raw;
117
+ `_sid` now sanitizes, and `run_audit` deep-sanitizes the finished report
118
+ (strings and dict keys) so no future field can bypass the boundary.
119
+ - Path redaction's lookbehind is ASCII-only: a Unicode word (e.g. Hangul)
120
+ before an absolute path no longer suppresses redaction.
121
+ - `~/`-relative paths in commands are redacted to `<path>` like absolute
122
+ ones; Windows UNC free-text paths are a documented gap.
123
+ - Sanitization now also strips C1 control characters (U+0080-U+009F) and
124
+ CSI sequences with intermediate bytes.
125
+
126
+ ### Fixed — robustness
127
+ - Bare `Infinity` token counts (accepted by Python's json parser) crashed
128
+ the run with OverflowError; non-finite values now read as 0.
129
+ - The Windows munged-directory name is separator/colon free, so the
130
+ prefilter can no longer resolve to an absolute path and scan the
131
+ repository itself instead of the transcripts.
132
+ - Transcript discovery prunes symlink cycles by (device, inode) instead of
133
+ looping forever.
134
+ - Blame porcelain parsing ignores tab-prefixed content lines whose first
135
+ token looks like a SHA.
136
+
137
+ ### Changed
138
+ - Discovery notes (prefilter vs full walk) are surfaced in report notes
139
+ instead of being invisible.
140
+ - Hygiene: pending count dedupes contested units by (commit, path);
141
+ survival result annotations reflect share-weighted floats; waste
142
+ classifies each unit once; dead attribution overlap field removed;
143
+ version strings aligned to 0.1.2.
144
+
145
+ ## [0.1.1] - 2026-09-05
146
+
147
+ Post-release review hardening: correctness, performance, and output-boundary
148
+ security. Measured values are unchanged (regression-checked against 0.1.0 on
149
+ a real corpus).
150
+
151
+ ### Fixed — correctness
152
+ - Attribution: contested commits now split across ALL same-grade claimants
153
+ (previously only exact-overlap ties split; other claimants were silently
154
+ dropped, and a high-grade tie picked one winner unflagged). Every
155
+ ambiguity is flagged.
156
+ - Attribution: `shared_files` no longer leaks the last-iterated session's
157
+ file set into other pairs (regression test added).
158
+ - Waste bounds: the share denominator is now computed from units classified
159
+ at the *same* horizon, so bounds can never exceed the session cost when
160
+ horizon differs from the headline.
161
+ - Verification gap: reports both `gap_rate` (never verified) and
162
+ `gap_rate_strict` (not verified before the last commit).
163
+ - Cache locality: a compaction boundary stamped exactly at the previous
164
+ call's timestamp now counts as compaction (tie rule).
165
+ - Accepted: sessions with commits but no cost record land in a status
166
+ instead of vanishing from totals.
167
+
168
+ ### Fixed — performance
169
+ - Survival: file existence is checked via one `git ls-tree -r` per snapshot
170
+ instead of one `cat-file` per unit×horizon (~10x fewer git processes on
171
+ commit-heavy repos).
172
+ - Transcripts: sessions are loaded from the repo's munged project directory
173
+ when present (full-walk fallback preserved) — real-corpus audit went from
174
+ 14.1s to 3.8s on a 1.3GB transcript root.
175
+ - `git log --numstat` and `git blame` stream line-by-line; blame collapses
176
+ to per-SHA counts instead of retaining full porcelain output.
177
+ - Failure chains capped at 200 in the JSON report with a truncation flag.
178
+ - Cache locality boundary matching is a two-pointer scan, not O(calls×boundaries).
179
+
180
+ ### Fixed — security
181
+ - Output boundary: every transcript-derived string is stripped of ANSI
182
+ escape and control sequences before rendering (terminal injection).
183
+ - Markdown: chain commands are escaped for table cells/code spans, so a
184
+ pasted report cannot be broken out of or turned into remote image loads.
185
+ - Chain commands have absolute paths redacted to `<path>` by default
186
+ (`--show-paths` restores them), matching the README's redaction promise.
187
+ - `parameters.transcripts_root` is home-abbreviated; path redaction handles
188
+ Windows separators.
189
+ - Git subprocesses run with `GIT_*` environment variables stripped so a
190
+ stray `GIT_DIR` cannot redirect the audit.
191
+
192
+ ### Fixed — robustness
193
+ - Unparseable commit dates skip the commit with a warning note instead of
194
+ crashing the run.
195
+ - Float token counts in transcripts (e.g. `4096.0`) truncate instead of
196
+ reading as zero.
197
+ - `--days` rejects negative values; stdout/stderr are reconfigured to
198
+ survive non-UTF-8 locales.
199
+ - `core.quotePath=false` keeps non-ASCII file paths intact in numstat.
200
+
201
+ ### Changed
202
+ - Packaging: `license = "Apache-2.0"` (PEP 639) with `license-files`.
203
+ - Transcript discovery follows symlinked directories via `os.walk`.
204
+
205
+ ## [0.1.0] - 2026-09-05
206
+
207
+ Initial release: outcome accounting for AI coding agents, fully local,
208
+ measurement-only.
209
+
210
+ ### Added
211
+ - Claude Code transcript adapter (JSONL, schema-defensive; sidechains and
212
+ malformed records skipped).
213
+ - M1 output survival rate with git-blame snapshots at configurable horizons
214
+ (default 7d headline, 7/30 measured), split by output kind
215
+ (source/test/docs/config); pending-horizon units reported separately;
216
+ aggregates weighted by attribution share so contested commits count once.
217
+ - M2 waste cost bounds (removed = lower+upper, >=50% lost = upper only);
218
+ attribution-share-weighted line-share proxy labeled as such.
219
+ - M3 retry tax: failure chains from repeated normalized Bash commands with
220
+ errors; interval-based token attribution.
221
+ - M4 accepted-task accounting: cost/tokens per accepted session
222
+ (survival >= 0.5); accepted/rejected/pending/no_output classes.
223
+ - M5 cache locality: ttl_expiry / prefix_break / compaction classification
224
+ of cold calls; wasted-vs-cached estimate; compaction excluded by design.
225
+ - M8 verification gap rate plus survival correlation table.
226
+ - Session-commit attribution with high/medium confidence grades, contested
227
+ commit splitting, and ambiguity flags.
228
+ - Pricing table (2026-09 list prices, prefix matching, conservative
229
+ fallback for unknown models) with JSON override file.
230
+ - Report formats: console, JSON (`yieldaudit.report.v1`, every block
231
+ labeled observed/estimate/proxy), markdown; path redaction by default.
232
+ - Graceful degradation on repositories with no commits yet (empty report,
233
+ no crash).
234
+ - CLI: `yield-audit audit`, `yield-audit doctor`; `--now` for reproducible
235
+ runs.
236
+ - Tests: deterministic fixture git repository (pinned dates) + synthetic
237
+ transcripts; unit and end-to-end golden assertions.
@@ -0,0 +1,86 @@
1
+ # HANDOFF — 다음 세션 작업 지시서
2
+
3
+ - **작성 시점**: 2026-09-05, v0.1.2 (커밋 `2fd3ebc` 기준)
4
+ - **업데이트 2026-09-05**: v0.2.0+v0.3.0 출시(커밋 `43054b5` + Windows 테스트 수정). **P0 완료 — 원격 [ictechgy/yield-audit](https://github.com/ictechgy/yield-audit) public 생성, 첫 CI 3 OS × py3.10/3.12/3.14 전부 그린, 태그 v0.1.2·v0.3.0 push.** 첫 CI에서 기존 테스트의 Windows 경로 버그(munged 이름 치환) 발견·수정됨
5
+ - **전제 상태**: 67 tests 통과 · ruff 클린 · 실데이터 회귀 확인(측정값 불변) · PyPI 미게시
6
+ - **에이전트 규약**: 작업 시작 전 [AGENTS.md](AGENTS.md) 읽기. **절대 실데이터(`/Users/*/.claude`, 실제 프로젝트) 감사 금지** — 픽스처/tmp만.
7
+
8
+ ## 0. 현재 상태 빠른 확인 (5초)
9
+
10
+ ```bash
11
+ pytest -q && ruff check . && git log --oneline | head -5
12
+ # 예상: 67 passed, All checks passed, 최신 커밋 = docs 커밋
13
+ ```
14
+
15
+ 문서 지도: README(사용자용) → AGENTS.md(에이전트 규약, 루트+lenses+tests) →
16
+ CHANGELOG(변경 이력) → 기획서-AIDD-전환계량.md(v0.3+ 근거, M11 출시됨) →
17
+ ../AI비용-빈영역-오픈소스-기획서.md(v0.2+ 근거) →
18
+ ../context-guard-개선-보고서.md(별개 프로젝트 참고용).
19
+
20
+ ## 1. 최우선: 원격 저장소 + 첫 CI 실행 (미해결 P0급)
21
+
22
+ CI가 CI워크플로 파일만 있고 **한 번도 돌아본 적이 없다**. 로컬은 macOS+py3.14 하나뿐이므로
23
+ 3 OS × py 3.10/3.12/3.14 매트릭스에서 처음으로 검증되는 것과 같다.
24
+
25
+ - [ ] GitHub 원격 생성 후 push (`gh repo create yield-audit --public --source .` 또는 사용자 선호 방식 — 원격 생성은 사용자 승인 필요할 수 있음)
26
+ - [ ] CI 결과 확인. **예상 실패 후보와 대응**:
27
+ - py3.10 문법 → 전 모듈에 `from __future__ import annotations` 있음(확인됨), 그래도 실패 시 해당 시그니처 수정
28
+ - Windows: `tests/conftest.py` 픽스처 경로, `munged_project_dir_name`(v0.1.2에서 백슬래시·콜론 처리 완료), blame/ls-tree 동작 차이
29
+ - actions 태그 핀(@v4/@v5) → 공식 SHA 확인 후 핀 (아직 미적용 — 기억으로 SHA 쓰지 말 것)
30
+ - [ ] 그린이면 `git tag v0.1.2 && git push --tags`
31
+ - [ ] README의 홈페이지/원격 URL이 실제 원격과 일치하는지 갱신 (현재 placeholder)
32
+
33
+ ## 2. 다음 기능 사이클
34
+
35
+ **v0.2 어댑터 인터페이스 + v0.3.0 M11 리워크율 완료됨**(기획서-AIDD-전환계량.md v0.3.0 스코프:
36
+ cohorts.py 코호트 라벨 + lenses/rework.py + `--rework-days` + 리포트 `m11_rework` 블록).
37
+ 남은 v0.3 항목: M12 정착률(blame 스냅샷, `--snapshot` 서브커맨드), v0.4 `aidd` 서브커맨드 통합 리포트.
38
+
39
+ ### 원래 v0.2 항목 (M7/M9/M10은 미착수)
40
+
41
+ **시작 전 아키텍처 과제가 먼저** — 2차 리뷰의 구조 지적:
42
+
43
+ - [x] **어댑터 인터페이스 추출** (v0.2.0 완료): `transcripts/` 패키지(base+claude+codex, 레지스트리),
44
+ `--agent {auto,claude,codex}`, 세션 id `"vendor:<raw>"` 네임스페이스. Gemini 어댑터는
45
+ 스키마 그라운딩 확보 후 같은 방식으로 추가하면 됨(서브클래스 1개 + 레지스트리 등록).
46
+ - [ ] **M7 컨텍스트 사망율**: 읽어들인 파일 내용이 이후 생성물에 미등장하면 "사망"의 결정적 근사.
47
+ 문자열 매칭 기반(정규화 후 포함 검사)으로 시작. 렌즈 계약 준수(순수 함수, measurement 라벨).
48
+ - [ ] **M9 세션 간 반복 지식 비용**: 콘텐츠 해시 기반 크로스세션 중복 과금 측정.
49
+ 전략적 의미: 메모리·벡터 DB 투자 ROI 역산 — 제작자의 별도 벡터 DB 프로젝트와 상호 판매 구조.
50
+ - [ ] **M10 핸드오프 세금**: 서브에이전트 페이로드 측정. 트랜스크립트에 기록된
51
+ Agent/Task 도구 호출의 부모↔자식 구조 파싱.
52
+
53
+ 각 항목: 단위 테스트 + E2E 골든 + conftest docstring 갱신까지가 완료 정의(tests/AGENTS.md §6).
54
+
55
+ ## 3. 백로그 (우선순위 낮음, 근거 있음)
56
+
57
+ - [x] PyPI 게시 (v0.3.2) — 신뢰 퍼블리셔(OIDC) `pypi.yml`, 태그 푸시로 게시. README 영어화 + 한국어 README.ko.md 분리, 퀵스타트 `uvx yield-audit` 복원
58
+ - [ ] UNC 경로(`\\host\share`) 자유 텍스트 레닥션 — 현재 README에 문서화된 한계
59
+ - [x] 터치 프리필터(v0.3.1) — path_touch_log 원패스로 무터치 파일 blame 스킵(머지 가드 포함).
60
+ 스냅샷 캐시 일(day) 버킷팅 옵션은 여전히 백로그 — rev-list/ls-tree 절감용
61
+ - [ ] `doctor`에 트랜스크립트 루트 용량·파일수 리포트 추가(사용자가 사전 감사 가능하도록)
62
+ - [ ] v0.3 잔여: M12 정착률(blame 스냅샷, `--snapshot` 서브커맨드), M5 기반 배치 스케줄 조언, M6 개인 라우팅 힌트(옵트인 리플레이) — M11은 0.3.0으로 출시됨(기획서-AIDD의 M11 인간 수정 시간과는 별개 표기 정리 필요 없음, 해당 항목은 M13/M14로 통합 검토)
63
+
64
+ ## 4. 절대 어기지 말 것 (회귀 방지)
65
+
66
+ 1. **절감 수치 주장 금지** — 측정만. 개입 기능은 v1.x 게이트 뒤.
67
+ 2. **런타임 의존성 0** 유지 (stdlib + git CLI). dev 의존성은 런타임 import 금지.
68
+ 3. **모든 리포트 블록에 `measurement` 라벨** (observed/estimate/proxy).
69
+ 4. **트랜스크립트 파생 문자열은 redact.py 경유** — deep_sanitize는 안전망이지 대체품 아님.
70
+ 5. **렌즈 순수성** — I/O·시계·난수 금지, 집계는 `attributed_added`(share 가중).
71
+ 6. **커밋 전**: `pytest && ruff check .` 통과 + CHANGELOG 항목 + 버전 2곳 동시 bump.
72
+ 7. **실데이터 감사 금지** (상단 경고 재확인 — 리뷰 에이전트 2회 타임아웃의 원인이었음).
73
+
74
+ ## 5. 검증된 참고 수치 (회귀 비교용, macOS arm64 / speed 저장소 / --days 90)
75
+
76
+ | 항목 | 값 |
77
+ |---|---|
78
+ | 실행 시간 | ~3.5s (v0.1.0 대비 14.1s → 개선) |
79
+ | M1 생존율 | 95.4272% (17,276줄) |
80
+ | M2 낭비 구간 | $4.334524 – $19.773222 |
81
+ | M4 채택당 비용 | $841.384684 (채택 1 / no_output 2) |
82
+ | M5 히트율 | 74.9%, cold 0 |
83
+
84
+ 새 버전 배포 전 이 값을 재현해 수치가 변했다면 그 이유를 설명할 수 있어야 한다.
85
+ (단, speed 저장소 자체가 변하면 당연히 달라진다 — 그 경우 raw 값 비교가 아니라
86
+ "같은 커밋 범위에서 재실행"으로 비교.)