<!-- task=m-agent-readable-repository-refactor/12+03,06,10,11_readability_baseline plan=2 tag=REVIEW_REVIEW_REFACTOR -->

# Readability audit 투영·ratchet 증거 신뢰성 재보정

## 이 파일을 읽는 구현 에이전트에게

> 구현 후 아래 검증 명령을 그대로 실행하고 `CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션에 실제 메모와 stdout/stderr를 채운 뒤 active 파일을 유지한 채 리뷰 준비 완료를 보고한다. 판정, log rename, `complete.log`, archive 이동은 code-review 전용이다. 선택된 Milestone의 `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 review stub의 `사용자 리뷰 요청`에 정확한 연결 근거를 남기고 중단한다. 직접 사용자에게 묻거나 chat 선택지를 제시하거나 `request_user_input`을 호출하지 않고, `USER_REVIEW.md`/`complete.log`를 작성하거나 log를 archive하지 않는다. 환경·secret·service, 일반 범위 조정, 후속으로 보완 가능한 증거 공백은 사용자 리뷰 사유가 아니다.

## 배경

G09 후속은 기본 unit과 audit target이 통과했지만, worktree 투영이 수정 tracked 파일을 삭제로 오인해 실제 파일 8개와 violation 9건을 누락했다. read-set total과 allowlist schema는 증감 ratchet에 연결되지 않았고, 다언어 렉서와 function identity도 raw literal·scope 경계에서 충돌한다. 고정 검증 명령 자체도 실패했으므로 CLI·schema·baseline·test evidence를 하나의 재현 가능한 계약으로 닫는다.

## 사용자 리뷰 요청 흐름

사용자 리뷰 요청은 선택된 Milestone의 구현 잠금 결정만 active review stub의 `사용자 리뷰 요청` 섹션에 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 형식으로 기록한다. 구현 중 직접 사용자 prompt는 금지하며, 타당성 검증과 실제 `USER_REVIEW.md` 작성은 code-review가 소유한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/agent-readable-repository-refactor.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/automation-runtime-bridge/milestones/agent-readable-repository-refactor.md)
- Task ids:
  - `readability-baseline`: 추적 소스의 파일/함수/read-set 기준선과 재현 가능한 ratchet audit 도입
- Completion mode: check-on-pass

## Archive Evidence Snapshot

- 루프 이력:
  - `plan_local_G07_0.log` / `code_review_local_G07_0.log`: FAIL, Required 4 / Suggested 0 / Nit 0.
  - `plan_local_G09_1.log` / `code_review_local_G09_1.log`: FAIL, Required 5 / Suggested 0 / Nit 0.
- 현재 아카이브 작업: `agent-task/m-agent-readable-repository-refactor/12+03,06,10,11_readability_baseline/plan_local_G09_1.log`
- 현재 아카이브 리뷰: `agent-task/m-agent-readable-repository-refactor/12+03,06,10,11_readability_baseline/code_review_local_G09_1.log`
- 판정: FAIL
- Required 5 / Suggested 0 / Nit 0
  - worktree mode가 수정 tracked 파일 12개를 누락해 328 files/205 violations만 보고했고, 올바른 투영은 336 files/214 violations이었다.
  - Python test 파일이 production으로 분류되고 baseline schema/level 하락 ratchet 경계가 빠졌다.
  - read-set missing path, current total 4,168 vs budget 2,209, task total 증감이 모두 PASS했고 baseline에 task total이 없었다.
  - Go raw string이 6줄 함수를 3줄로 조기 종료했고, 비-Go extractor와 Python scope identity에 충돌이 남았다.
  - 고정 명령 `python3 -m unittest scripts.readability_audit_test.py`는 `AttributeError` 실패였지만 PASS 출력으로 기록되었고, 올바른 module 명령의 42 tests는 현재 잘못된 missing-path 성공 계약을 고정했다.
- 영향 파일: `scripts/readability_audit.py`, `scripts/readability_audit_test.py`, `scripts/readability_baseline.json`, `scripts/readability_read_sets.json`, `Makefile`.
- 검증 증거: 올바른 module 명령의 unit 42개, worktree/tracked audit, 반복 JSON cmp, Make target, `git diff --check`는 PASS했다. 독립 경계 probe는 수정 tracked 누락, stale read-set total, raw string 조기 종료, Python identity 충돌를 재현했다.
- Roadmap carryover: `readability-baseline` Task는 PASS 전까지 미완료로 유지한다.
- 추가 상세가 필요하면 위 `plan_local_G09_1.log`와 `code_review_local_G09_1.log`만 좁게 재확인한다.

## 분석 결과

### 읽은 파일

- `.gitignore`
- `Makefile`
- `scripts/readability_audit.py`
- `scripts/readability_audit_test.py`
- `scripts/readability_baseline.json`
- `scripts/readability_read_sets.json`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/automation-runtime-bridge/PHASE.md`
- `agent-roadmap/phase/automation-runtime-bridge/milestones/agent-readable-repository-refactor.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/testing-smoke.md`
- `agent-ops/rules/common/rules-agent-spec.md`
- `agent-spec/index.md`
- `agent-task/m-agent-readable-repository-refactor/12+03,06,10,11_readability_baseline/plan_local_G07_0.log`
- `agent-task/m-agent-readable-repository-refactor/12+03,06,10,11_readability_baseline/code_review_local_G07_0.log`
- `agent-task/m-agent-readable-repository-refactor/12+03,06,10,11_readability_baseline/plan_local_G09_1.log`
- `agent-task/m-agent-readable-repository-refactor/12+03,06,10,11_readability_baseline/code_review_local_G09_1.log`

### SDD 기준

선택 Milestone은 `SDD: 불필요`다. 외부 API/proto/config schema와 runtime 책임 경계를 바꾸지 않는 동작 보존형 저장소 audit 도구이므로 기록된 사유를 유지한다.

### 테스트 환경 규칙

`test_env=local`. `agent-test/local/rules.md`와 `agent-test/local/testing-smoke.md`를 읽었다. Python stdlib unittest, `/tmp` JSON 반복 cmp, tracked/worktree CLI, Make target, `git diff --check`를 사용한다. 외부 서비스·Docker·runtime을 변경하지 않으므로 repo 내 edge-node 진단, 보조 E2E smoke, full-cycle 실제 구동은 대상이 아니다. `make readability-audit`가 이 변경의 공식 entrypoint 검증이다.

### 테스트 커버리지 공백

- modified tracked 파일이 worktree projection에 남는 fixture가 없다.
- `_test.py` 등 언어별 test 분류, malformed metric/level/value/function, level 하락/상승 ratchet 테스트가 없다.
- missing read-set path 테스트가 계획과 반대로 성공을 기대하며, exact budget/one-over/task total 증감/CLI exit 테스트가 없다.
- Go raw string, Dart/Kotlin/Swift multiline raw string, Shell heredoc, Python class/nested scope identity 테스트가 없다.
- 계획의 unittest 명령 파일 인자가 실제 unittest module 규칙과 맞지 않아 신고된 stdout/stderr를 신뢰할 수 없다.

### 심볼 참조

외부 rename/remove 심볼은 없다. 변경 대상 helper의 직접 호출은 `scripts/readability_audit.py` 내 `collect_files`, `audit`, `ratchet_check`, `audit_read_sets`, `main`과 `scripts/readability_audit_test.py`의 동일 이름 unit fixture에 한정된다.

### 분할 판단

분할 정책을 먼저 검토했다. Required 5건은 하나의 Python CLI measurement model, baseline/read-set schema, 단일 unit suite를 공유하며 투영·policy·parser 중 하나만 먼저 archive하면 baseline이 의도적으로 불일치한 중간 상태가 된다. ownership, 외부 API, 별도 test profile 경계가 없고 각 항목을 하나의 최종 baseline으로 같이 검증해야 하므로 기존 `12+03,06,10,11_readability_baseline` 단일 후속 루프를 유지한다. predecessor `03`, `06`, `10`, `11`은 이전 루프 증거에서 충족된 상태다.

### 범위 결정 근거

`scripts/readability_audit.py`, 해당 unit test, baseline/read-set JSON만 보정한다. `Makefile`의 `--input-mode worktree` target과 `.gitignore` block은 이미 올바르므로 추가 수정하지 않고 최종 검증만 수행한다. production source, CI workflow, API/proto/config schema, roadmap/agent-spec/agent-contract, 선행 split test 파일은 수정하지 않는다.

### 빌드 등급

`cloud-G07`: 5개 Required가 CLI 프로세스/status 해석, 다언어 lexical measurement, 세 개 JSON schema와 증거 신뢰 회복에 걸쳐 있어 code-review/plan 라우팅 규칙의 cloud-G07 기본선을 적용한다.

## 구현 체크리스트

- [ ] [REVIEW_REVIEW_REFACTOR-1] worktree projection이 수정 tracked·untracked·삭제 경계를 정확히 반영하고 post-commit 동일성 테스트를 통과시킨다.
- [ ] [REVIEW_REVIEW_REFACTOR-2] 언어별 test 분류와 baseline schema/level ratchet을 엄격히 보정하고 개선·증가 경계 테스트를 통과시킨다.
- [ ] [REVIEW_REVIEW_REFACTOR-3] read-set schema, missing path, task total baseline, budget/reason 증감과 CLI 실패 출력을 하나의 ratchet 계약으로 연결한다.
- [ ] [REVIEW_REVIEW_REFACTOR-4] raw/multiline/comment를 무시하는 다언어 함수 계측과 scope-qualified identity를 구현하고 경계 regression을 통과시킨다.
- [ ] [REVIEW_REVIEW_REFACTOR-5] 올바른 unittest module 명령, 전체 worktree 투영, 반복 JSON, tracked audit, Make target으로 baseline/evidence를 재생성한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_REFACTOR-1] 올바른 worktree/post-commit projection

- 문제: `scripts/readability_audit.py:579-598`이 모든 diff path를 deleted로 반환하고 `scripts/readability_audit.py:653-674`가 이를 tracked 입력에서 뺀다.
- 해결 방법:

~~~text
Before
deleted_files = git diff-index --name-only HEAD
worktree = tracked - deleted_files + untracked

After
tracked existing files always remain, including modified files
staged/unstaged deletion state is filtered explicitly
non-ignored untracked files are added unless staged for removal
all paths are NUL-safe, existing, excluded-path filtered, and sorted once
~~~

- 수정 파일 및 체크리스트:
  - [ ] `scripts/readability_audit.py`: deletion status만 분리하고 worktree 투영을 결정적으로 재구성한다.
  - [ ] `scripts/readability_audit_test.py`: modified tracked, unstaged delete, staged delete/`rm --cached`, untracked, excluded path fixture를 추가한다.
- 테스트 작성: 작성한다. `test_worktree_mode_includes_modified_tracked` 및 deletion 변형별 test가 clean repo 대비 정확한 path set을 assert한다.
- 중간 검증:

~~~bash
python3 -m unittest scripts.readability_audit_test.TestInputModeTrackedVsWorktree
~~~

기대 결과: modified tracked가 남고 실제/staged 삭제만 빠지며 untracked/exclusion 경계가 PASS.

### [REVIEW_REVIEW_REFACTOR-2] test policy와 allowlist ratchet schema

- 문제: `scripts/readability_audit.py:66-74`가 Python/Kotlin/Swift/Shell test 파일을 production으로 분류하고, `scripts/readability_audit.py:882-913`이 malformed metric/level/value/function을 통과시킨다. `scripts/readability_audit.py:925-949`는 violation level이 낮아진 개선을 신규 위반으로 오판한다.
- 해결 방법:

~~~text
Before
test kind = Go/Dart suffix or test/ path only
allowlist validation = path + level + reason only
ratchet lookup = exact (path, metric, level, function)

After
test kind = language-aware suffix/prefix plus test/tests path components
allowlist validation = exact allowed keys and typed metric/level/value/function/reason
ratchet = stable identity comparison where decreases, including level drops, pass and increases/new identities fail
~~~

- 수정 파일 및 체크리스트:
  - [ ] `scripts/readability_audit.py`: test classification, schema validator, severity rank/identity comparison을 보정한다.
  - [ ] `scripts/readability_audit_test.py`: `_test.py` 등 분류, invalid schema, level drop PASS, same identity increase/cross-level FAIL를 추가한다.
  - [ ] `scripts/readability_baseline.json`: 보정된 kind/identity/schema로 재생성한다.
- 테스트 작성: 작성한다. `TestPolicyThresholdsByFileKind` 및 `TestAllowlistIdentityAndReasonRatchet`에 language test 패턴·malformed entry·severity transition fixture를 추가한다.
- 중간 검증:

~~~bash
python3 -m unittest scripts.readability_audit_test.TestPolicyThresholdsByFileKind scripts.readability_audit_test.TestAllowlistIdentityAndReasonRatchet
~~~

기대 결과: 파일 kind, schema, 개선/증가 ratchet 경계 PASS.

### [REVIEW_REVIEW_REFACTOR-3] task read-set schema와 total ratchet

- 문제: `scripts/readability_audit.py:966-1023`은 missing path를 0 LOC로 바꾸고 non-empty reason이 있는 over-budget total을 무제한 통과시킨다. `scripts/readability_read_sets.json:15-18`의 stale total/budget과 `scripts/readability_baseline.json` 사이에 task total ratchet source of truth가 없다.
- 해결 방법:

~~~text
Before
read-set config total_loc is ignored
missing file -> loc=0
over budget + any reason -> pass
baseline has no task totals

After
config owns task/file order/budget; baseline owns allowlisted task total + reason
missing/duplicate task or path and invalid budget schema -> configuration failure
exact budget passes; new/increased total or reasonless over-budget fails
CLI renders every read-set failure with a defined value/status and exits deterministically
~~~

- 수정 파일 및 체크리스트:
  - [ ] `scripts/readability_audit.py`: read-set config/baseline validator, total lookup/ratchet, non-crashing CLI error rendering을 구현한다.
  - [ ] `scripts/readability_read_sets.json`: stale `total_loc`를 제거하고 task/file/budget 구성 원본만 남긴다.
  - [ ] `scripts/readability_baseline.json`: task id별 total/value/reason 기준선을 추가한다.
  - [ ] `scripts/readability_audit_test.py`: missing/duplicate/schema, exact/one-over, same/increased/new total, CLI exit/stdout-stderr fixture를 추가한다.
- 테스트 작성: 작성한다. `TestTaskReadSetTotalsAndBudget`와 subprocess CLI test가 구성 오류 및 ratchet 실패를 실제 exit code로 assert한다.
- 중간 검증:

~~~bash
python3 -m unittest scripts.readability_audit_test.TestTaskReadSetTotalsAndBudget
~~~

기대 결과: ordered LOC, schema, budget, baseline 증감, CLI 실패 경계 PASS.

### [REVIEW_REVIEW_REFACTOR-4] 다언어 lexical boundary와 qualified identity

- 문제: `scripts/readability_audit.py:225-233`의 raw literal 분기가 미구현이고, `scripts/readability_audit.py:385`, `406`, `429`, `452`는 cleaned source 대신 원본으로 end brace를 찾는다. Kotlin/Swift property를 함수로 세고 Python class/nested scope를 identity에서 버린다.
- 해결 방법:

~~~text
Before
partial quote blanking + original-source end scan
Kotlin/Swift val/var/let are functions
Python identity = bare node.name

After
language-aware raw/multiline/comment/heredoc blanking that preserves newlines
every brace extractor scans the cleaned source and only actual function declarations
identity includes receiver/lexical scope or normalized callable signature where overloading requires it
~~~

- 수정 파일 및 체크리스트:
  - [ ] `scripts/readability_audit.py`: lexer state와 Go/Dart/Shell/Kotlin/Swift/Python callable identity를 보정한다.
  - [ ] `scripts/readability_audit_test.py`: Go backtick, Dart/Kotlin/Swift multiline, Shell heredoc, property exclusion, Python duplicate method scope regression을 추가한다.
  - [ ] `scripts/readability_baseline.json`: 안정화된 function identity/value로 재생성한다.
- 테스트 작성: 작성한다. 각 언어 fixture가 string/comment/raw 내 brace와 동일 이름 다른 scope를 독립적으로 assert한다.
- 중간 검증:

~~~bash
python3 -m unittest scripts.readability_audit_test.TestMultiLanguageFunctionIdentity scripts.readability_audit_test.TestFunctionExtraction
~~~

기대 결과: 다언어 LOC·identity·property 제외 경계 PASS.

### [REVIEW_REVIEW_REFACTOR-5] baseline 재생성과 검증 evidence 회복

- 문제: `code_review_local_G09_1.log`에 기록된 unittest 명령은 실제로 실패했고, baseline은 잘못된 worktree output과 별도 union을 혼합해 만들어져 audit JSON 자체가 post-commit projection evidence가 아니었다.
- 해결 방법:

~~~text
Before
python3 -m unittest scripts.readability_audit_test.py  # fails
worktree output omits modified tracked files
baseline is hand-completed beyond reported output

After
python3 -m unittest scripts.readability_audit_test
one correct worktree projection generates both report and baseline
review evidence records actual command output and independently asserts changed existing paths are present
~~~

- 수정 파일 및 체크리스트:
  - [ ] `scripts/readability_audit_test.py`: 정확한 모듈/CLI 검증과 계획의 모든 경계를 실제 subprocess output으로 고정한다.
  - [ ] `scripts/readability_baseline.json`: 수정 완료된 단일 worktree projection과 task total로 재생성한다.
  - [ ] `scripts/readability_read_sets.json`: 최종 파일 순서/budget과 실제 출력을 맞춘다.
- 테스트 작성: 작성한다. 기존 42개를 엄격한 계약으로 고친 뒤 full module·CLI·JSON determinism을 실제 명령으로 신선 실행한다.
- 중간 검증:

~~~bash
python3 -m unittest scripts.readability_audit_test
python3 scripts/readability_audit.py --check --input-mode worktree --output /tmp/iop-readability-followup-c.json
~~~

기대 결과: 전체 unit PASS, 올바른 worktree projection RATCHET OK.

## 의존 관계 및 구현 순서

1. REVIEW_REVIEW_REFACTOR-1의 투영 집합을 고정한다.
2. REVIEW_REVIEW_REFACTOR-2와 4의 policy/identity를 고정한다.
3. REVIEW_REVIEW_REFACTOR-3의 read-set total을 동일 baseline schema에 연결한다.
4. REVIEW_REVIEW_REFACTOR-5에서 완성된 단일 투영으로 baseline과 evidence를 재생성한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `scripts/readability_audit.py` | REVIEW_REVIEW_REFACTOR-1, REVIEW_REVIEW_REFACTOR-2, REVIEW_REVIEW_REFACTOR-3, REVIEW_REVIEW_REFACTOR-4 |
| `scripts/readability_audit_test.py` | REVIEW_REVIEW_REFACTOR-1, REVIEW_REVIEW_REFACTOR-2, REVIEW_REVIEW_REFACTOR-3, REVIEW_REVIEW_REFACTOR-4, REVIEW_REVIEW_REFACTOR-5 |
| `scripts/readability_baseline.json` | REVIEW_REVIEW_REFACTOR-2, REVIEW_REVIEW_REFACTOR-3, REVIEW_REVIEW_REFACTOR-4, REVIEW_REVIEW_REFACTOR-5 |
| `scripts/readability_read_sets.json` | REVIEW_REVIEW_REFACTOR-3, REVIEW_REVIEW_REFACTOR-5 |

## 최종 검증

~~~bash
python3 -m unittest scripts.readability_audit_test
rm -f /tmp/iop-readability-followup-c.json /tmp/iop-readability-followup-d.json /tmp/iop-readability-followup-tracked-2.json
python3 scripts/readability_audit.py --check --input-mode worktree --output /tmp/iop-readability-followup-c.json
python3 scripts/readability_audit.py --check --input-mode worktree --output /tmp/iop-readability-followup-d.json
cmp /tmp/iop-readability-followup-c.json /tmp/iop-readability-followup-d.json
python3 scripts/readability_audit.py --check --input-mode tracked --output /tmp/iop-readability-followup-tracked-2.json
python3 - <<'PY'
import json
import os
import subprocess

with open('/tmp/iop-readability-followup-c.json', encoding='utf-8') as handle:
    report = json.load(handle)
reported = {entry['path'] for entry in report['files']}
changed_existing = {
    path
    for path in subprocess.run(
        ['git', 'diff', '--name-only', '-z', 'HEAD'],
        check=True,
        capture_output=True,
    ).stdout.decode().rstrip('\0').split('\0')
    if path and os.path.isfile(path) and os.path.splitext(path)[1] in {'.go', '.dart', '.sh', '.py', '.kt', '.swift'}
}
missing = sorted(changed_existing - reported)
print(f'changed-existing={len(changed_existing)} missing={missing}')
if missing:
    raise SystemExit(1)
PY
make readability-audit
git diff --check
~~~

기대 결과: 전체 unit PASS, worktree JSON byte-identical, 수정 tracked 누락 0, tracked/worktree RATCHET OK, read-set/schema/parser 증거가 JSON에 존재, Make target PASS, diff whitespace 오류 없음. production/runtime 미변경으로 edge-node 진단·보조 E2E·full-cycle은 생략한다.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
