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

# Kotlin annotation type modifier generic-closer 보정

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

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

## 배경

현재 Kotlin type-context scanner는 `@Name`만 type annotation으로 처리한다. qualified 또는 constructor annotation이 있는 cast/type-test RHS는 generic opener를 놓쳐 outer closer를 comparison으로 해석하고 다음 member까지 function span에 포함한다. Kotlin type modifier의 annotation user type과 argument delimiter를 인식하는 bounded scanner로 보정한다.

## 사용자 리뷰 요청 흐름

사용자 리뷰 요청은 선택된 Milestone의 잠금 결정만 active review stub의 `사용자 리뷰 요청`에 기록한다. 구현 중 직접 사용자 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), `plan_local_G09_1.log`/`code_review_local_G09_1.log`(FAIL Required 5), `plan_cloud_G07_2.log`/`code_review_cloud_G07_2.log`(FAIL Required 5), `plan_cloud_G07_3.log`/`code_review_cloud_G07_3.log`(FAIL Required 4), `plan_local_G09_4.log`/`code_review_local_G09_4.log`(FAIL Required 2), `plan_local_G09_5.log`/`code_review_local_G09_5.log`(FAIL Required 1), `plan_local_G09_6.log`/`code_review_local_G09_6.log`(FAIL Required 1), `plan_local_G09_7.log`/`code_review_local_G09_7.log`(FAIL Required 1), `plan_local_G09_8.log`/`code_review_local_G09_8.log`(FAIL Required 3), `plan_local_G09_9.log`/`code_review_local_G09_9.log`(FAIL Required 1).
- 현재 아카이브 작업: `agent-task/m-agent-readable-repository-refactor/12+03,06,10,11_readability_baseline/plan_local_G09_9.log`
- 현재 아카이브 리뷰: `agent-task/m-agent-readable-repository-refactor/12+03,06,10,11_readability_baseline/code_review_local_G09_9.log`
- 판정: FAIL — Required 1 / Suggested 0 / Nit 0.
- 문제: `value as @com.example.Ann List<String>`에서 qualified annotation을 type modifier로 인식하지 못해 `C.qualified`가 2–5행을 차지하고 뒤 sibling이 누락됐다.
- 검증 증거: 121 unit, worktree/tracked RATCHET, byte-identical JSON, baseline exact projection, Make target, `git diff --check`는 PASS했다. 위 independent probe만 FAIL했다.
- 영향 파일: `scripts/readability_audit.py`, `scripts/readability_audit_test.py`, `scripts/readability_baseline.json`.
- Roadmap carryover: `readability-baseline` Task는 PASS 전까지 미완료로 유지한다.
- 추가 상세가 필요하면 위 `plan_local_G09_9.log`와 `code_review_local_G09_9.log`만 좁게 재확인한다.

## 분석 결과

### 읽은 파일

- `scripts/readability_audit.py`
- `scripts/readability_audit_test.py`
- `scripts/readability_baseline.json`
- `scripts/readability_read_sets.json`
- `Makefile`
- `.gitignore`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/testing-smoke.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/automation-runtime-bridge/milestones/agent-readable-repository-refactor.md`
- `agent-spec/index.md`

### 문법 근거

- Kotlin 공식 grammar의 `typeProjection`은 annotation을 type projection modifier로 허용하고, `unescapedAnnotation`은 qualified `userType` 또는 constructor invocation을 허용한다. 따라서 `@com.example.Ann`과 `@com.example.Ann("reason")`은 cast RHS type modifier로 처리해야 한다.
- outer generic depth는 annotation constructor argument의 `()`/`[]` 안 토큰과 분리해야 한다. 해당 delimiter 안의 token은 type argument closer가 아니다.

### SDD 기준

선택 Milestone은 `SDD: 불필요`다. 외부 API/proto/config schema나 runtime 책임 경계를 바꾸지 않는 repository readability tooling 보정이라는 기록된 사유를 유지한다.

### 테스트 환경 규칙

`test_env=local`이며 `agent-test/local/rules.md`와 `agent-test/local/testing-smoke.md`를 읽었다. Python stdlib unittest, `/tmp` JSON, worktree/tracked audit, 반복 `cmp`, Make target, whitespace 검증을 적용한다. 사용자 실행/runtime 동작은 바꾸지 않으므로 full-cycle/E2E/external provider 검증은 대상이 아니다.

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

- 기존 projection test는 단순 `@Ann String`만 다루며 qualified annotation과 constructor annotation의 outer closer/sibling exact span이 없다.
- annotation argument 내부 delimiter가 outer generic angle depth에 영향을 주지 않는 회귀 fixture가 없다.

### 심볼 참조

- `KOTLIN_TYPE_OPERAND_RE`와 `_KotlinTypeArgumentState`는 `_kotlin_trailing_generic_type_closer`와 `_find_expression_end`에서만 사용된다. public API 또는 외부 call site 변경은 없다.

### 분할 판단

단일 plan을 선택한다. scanner와 같은 Python unit fixture를 동시에 바꾸는 하나의 parser 경계이며, API/call-site·도메인·검증 전략 분리가 없고 쪼개면 동일 state contract를 두 번 수정하게 된다.

### 범위 결정 근거

Kotlin cast/type-test RHS의 annotation type modifier와 대응 unit, self-referential baseline projection만 수정한다. 다른 언어 extractor, Shell lexer, `scripts/readability_read_sets.json`, Makefile, runtime 코드, roadmap/spec/contract는 변경하지 않는다.

### 빌드 등급

`local-G09`. 하나의 bounded lexer/state 경계와 두 Python 파일·baseline 고정점에서 결정적으로 검증할 수 있으며 외부 runtime 또는 대화형 동작은 없다.

## 구현 체크리스트

- [ ] [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1] Kotlin annotation type modifier와 constructor-argument delimiter를 generic closer context에서 인식하고 immediate sibling identity/span을 보존한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1] Kotlin annotation type modifier scanner

- 문제: `scripts/readability_audit.py:523-570`의 `KOTLIN_TYPE_OPERAND_RE`는 `@Name`만 허용한다. `value as @com.example.Ann List<String>`과 constructor annotation은 `<` opener를 type context로 시작하지 않아 final `>`가 comparison continuation이 되고 sibling declaration을 삼킨다.
- 해결 방법:

~~~text
Before
type modifier = @ + 단순 식별자 + 제한된 단일 괄호 인자
annotation/argument 내부 > = outer generic closer 후보

After
type modifier = annotation의 qualified user type 또는 constructor invocation
annotation argument의 ()/[] depth = outer generic angle depth와 분리
outer generic을 닫은 >만 type closer
~~~

- 수정 파일 및 체크리스트:
  - [ ] `scripts/readability_audit.py`: type operand detection을 qualified/multi or constructor annotation이 포함된 type modifier에 맞게 보정하고 annotation argument delimiter를 구분한다.
  - [ ] `scripts/readability_audit_test.py`: qualified constructor annotation과 annotation argument delimiter를 포함한 generic cast/type-test의 exact name/start/end/LOC 및 immediate sibling 회귀를 추가한다.
  - [ ] `scripts/readability_baseline.json`: worktree projection 또는 read-set total이 바뀌면 기존 reason을 보존해 정확한 고정점으로 갱신한다. 신규 helper violation은 추가하지 않는다.
- 테스트 작성: 작성한다. `test_kotlin_qualified_annotation_type_projection_closer_preserves_siblings`를 추가해 `@com.example.Ann("reason")`과 annotation argument delimiter 뒤 outer closer가 각각 한 줄에 끝나며 뒤 sibling이 보존되는지 assert한다.
- 중간 검증:

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

기대 결과: focused unit PASS, qualified/constructor annotation generic cast 또는 type test가 exact span으로 끝나고 모든 sibling이 보존된다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `scripts/readability_audit.py` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1 |
| `scripts/readability_audit_test.py` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1 |
| `scripts/readability_baseline.json` | 실제 projection/read-set 값 변경 시 |

## 최종 검증

~~~bash
python3 -m unittest scripts.readability_audit_test
python3 - <<'PY'
from scripts import readability_audit as ra

source = '''class C {
  fun qualified(value: Any) = value as @com.example.Ann("reason") List<String>
  fun typed(value: Any) = value is @com.example.Ann("reason") List<String>
  fun done() = 3
}
'''
actual = {f['name']: (f['start'], f['end'], f['loc'])
          for f in ra._extract_functions_kotlin(source, 'probe.kt')}
expected = {
    'C.qualified': (2, 2, 1),
    'C.typed': (3, 3, 1),
    'C.done': (4, 4, 1),
}
assert actual == expected, (actual, expected)
print('kotlin-qualified-annotation-type-projection=exact')
PY
rm -f /tmp/iop-readability-annotation-a.json /tmp/iop-readability-annotation-b.json /tmp/iop-readability-annotation-tracked.json
python3 scripts/readability_audit.py --check --input-mode worktree --output /tmp/iop-readability-annotation-a.json
python3 scripts/readability_audit.py --check --input-mode worktree --output /tmp/iop-readability-annotation-b.json
cmp /tmp/iop-readability-annotation-a.json /tmp/iop-readability-annotation-b.json
python3 scripts/readability_audit.py --check --input-mode tracked --output /tmp/iop-readability-annotation-tracked.json
make readability-audit
git diff --check
~~~

기대 결과: 전체 unit PASS, qualified annotation probe exact, worktree JSON byte-identical, tracked/worktree RATCHET OK, Make target PASS, whitespace 오류 없음. 코드/테스트 LOC가 증가하면 baseline의 기존 reason을 보존해 projection과 read-set total을 갱신한다.

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