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

# Kotlin 연속 표현식과 Shell comment token 경계 보정

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

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

## 배경

제출된 115개 unit과 공식 ratchet은 통과하지만, 독립 probe에서 유효한 Kotlin depth-0 연속 표현식과 Shell의 comment가 아닌 `#`가 함수 경계를 오염시킨다. 현재 테스트는 Kotlin leading-chain을 오히려 `loc=1`로 고정하고 Shell comment boundary의 반대 사례를 검증하지 않는다. 두 lexical 경계와 고정점 baseline만 좁게 보정한다.

## 사용자 리뷰 요청 흐름

사용자 리뷰 요청은 선택된 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 / Suggested 0 / Nit 0.
  - `plan_local_G09_1.log` / `code_review_local_G09_1.log`: FAIL, Required 5 / Suggested 0 / Nit 0.
  - `plan_cloud_G07_2.log` / `code_review_cloud_G07_2.log`: FAIL, Required 5 / Suggested 0 / Nit 0.
  - `plan_cloud_G07_3.log` / `code_review_cloud_G07_3.log`: FAIL, Required 4 / Suggested 0 / Nit 0.
  - `plan_local_G09_4.log` / `code_review_local_G09_4.log`: FAIL, Required 2 / Suggested 0 / Nit 0.
- 현재 아카이브 작업: `agent-task/m-agent-readable-repository-refactor/12+03,06,10,11_readability_baseline/plan_local_G09_4.log`
- 현재 아카이브 리뷰: `agent-task/m-agent-readable-repository-refactor/12+03,06,10,11_readability_baseline/code_review_local_G09_4.log`
- 판정: FAIL
- Required 2 / Suggested 0 / Nit 0
  - Kotlin `_find_expression_end`가 depth-0 leading chain과 trailing operator continuation을 선언 줄에서 종료한다.
  - Shell lexer가 모든 `#`를 comment로 처리해 word/parameter expansion 뒤 same-line function close를 지운다.
- 영향 파일: `scripts/readability_audit.py`, `scripts/readability_audit_test.py`, `scripts/readability_baseline.json`.
- 검증 증거: 공식 115 unit, worktree 2회 byte-identical JSON, tracked/worktree RATCHET, baseline exact projection, Make target과 `git diff --check`는 PASS했다. 독립 probe는 Kotlin 2건을 `loc=1`로 축소하고 Shell 2건에서 첫 함수가 다음 함수까지 삼키는 것을 재현했다. 두 Shell fixture는 `bash -n`을 통과한다.
- Roadmap carryover: `readability-baseline` Task는 PASS 전까지 미완료로 유지한다.
- 추가 상세가 필요하면 위 `plan_local_G09_4.log`와 `code_review_local_G09_4.log`만 좁게 재확인한다.

## 분석 결과

### 읽은 파일

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

### 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, Bash syntax check, 임시 `/tmp` JSON, worktree/tracked audit, 반복 `cmp`, Make target, whitespace 검증을 적용한다. 사용자 실행/runtime 동작은 바꾸지 않으므로 repo 내부 edge-node 진단, 보조 E2E, full-cycle, 외부 provider/Docker 검증은 대상이 아니다.

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

- Kotlin: bracket depth가 열린 multiline list는 검증하지만 `compute()` 다음 줄 `.size`는 잘못 `loc=1`로 assertion되어 있고, 후행 연산자 continuation은 없다.
- Shell: `:;# }` comment와 `\}` escape는 검증하지만 `foo#bar`와 `${value#x}`의 non-comment `#` 뒤 same-line function close 및 다음 함수 identity는 없다.
- read-set exact schema와 Go type brace 회귀는 현재 unit 및 독립 재실행에서 통과했으므로 변경하지 않는다.

### 심볼 참조

renamed/removed symbol은 없다. 수정 대상 내부 경계는 `_find_expression_end`, `_blank_lex_strings_and_comments`, `_extract_functions_brace` 호출 흐름으로 한정한다.

### 분할 판단

split 정책을 재평가했으며 같은 `12+03,06,10,11_readability_baseline` subtask에서 단일 후속 plan을 유지한다. 두 결함은 같은 lexical cleaning/function-end 파이프라인과 같은 Python test/baseline 고정점 검증을 공유해 분리하면 동일 파일 충돌과 projection 재생성을 중복한다. predecessor `03`, `06`, `10`, `11`은 각각 아래 archived `complete.log`로 충족됐다.

- `agent-task/archive/2026/07/m-agent-readable-repository-refactor/03+02_openai_provider_tools/complete.log`
- `agent-task/archive/2026/07/m-agent-readable-repository-refactor/06+04,05_core_edge_tests/complete.log`
- `agent-task/archive/2026/07/m-agent-readable-repository-refactor/10+07,08,09_adapter_control_plane_tests/complete.log`
- `agent-task/archive/2026/07/m-agent-readable-repository-refactor/11_client_tests/complete.log`

### 범위 결정 근거

`scripts/readability_audit.py`와 회귀 테스트만 동작 수정한다. `scripts/readability_baseline.json`은 실제 worktree projection이 바뀌는 필연적 결과만 고정점으로 갱신하고 기존 reason을 identity 기준으로 보존한다. `scripts/readability_read_sets.json`, Makefile, runtime 소스, roadmap, agent-spec/contract는 수정하지 않는다. 새 helper 자체의 신규 LOC violation은 baseline에 넣지 않는다. lexical 보정으로 기존 소스의 실제 장기 함수가 새로 드러나면 identity와 측정 근거를 별도 확인한 뒤에만 reason을 추가한다.

### 빌드 등급

`local-G09`. 두 결함은 두 Python 파일의 in-memory fixture와 Bash syntax check로 결정적으로 재현되며 외부 판단은 없지만, Kotlin continuation·Shell lexical state·self-referential baseline 고정점을 함께 보존해야 한다.

### Spec 판단

`agent-spec/index.md`에 repository readability tooling과 매칭되는 living spec이 없다. Spec update not needed: runtime/API 동작이나 기존 spec evidence를 바꾸지 않는다.

## 구현 체크리스트

- [ ] [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1] Kotlin depth-0 leading-chain과 trailing-operator expression body를 실제 종료 줄까지 측정한다.
- [ ] [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-2] Shell `#`를 실제 comment token boundary에서만 blank하고 word/parameter expansion과 same-line body close를 보존한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1] Kotlin depth-0 expression continuation

- 문제: `scripts/readability_audit.py:606-609`는 첫 비어 있지 않은 줄의 delimiter depth가 0이면 무조건 종료한다. `scripts/readability_audit_test.py:905-907`도 유효한 `compute()` 다음 줄 `.size`를 `loc=1`로 잘못 고정하며 `1 +` 다음 줄 `2`도 같은 방식으로 축소된다.
- 해결 방법:

~~~text
Before
non-empty line + depth 0 -> expression 종료

After
depth 0이어도 현재 줄의 Kotlin continuation suffix 또는 다음 nonblank 줄의 chain prefix를 확인
continuation이면 계속 스캔하고 첫 완결 expression 줄에서 종료
다음 선언/타입 closing brace는 삼키지 않음
~~~

- 수정 파일 및 체크리스트:
  - [ ] `scripts/readability_audit.py`: 언어별 depth-0 continuation 판별을 `_find_expression_end`에 추가하되 Dart의 `;` 종료 계약을 보존한다.
  - [ ] `scripts/readability_audit_test.py`: leading `.size`, trailing `+`, 뒤따르는 sibling function을 포함한 start/end/LOC fixture를 추가한다.
  - [ ] `scripts/readability_baseline.json`: 전체 worktree projection의 기존 identity 값이 바뀔 때만 reason을 보존해 고정점 갱신한다.
- 테스트 작성: 작성한다. `test_kotlin_depth_zero_expression_continuations_span_full_expression`이 chain/연산자 각 2 LOC와 다음 함수 1 LOC를 assert한다.
- 중간 검증:

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

기대 결과: 1 test PASS이고 `C.call=(2,3,2)`, `C.total=(4,5,2)`, `C.done=(6,6,1)` 의미가 고정된다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-2] Shell comment token boundary

- 문제: `scripts/readability_audit.py:202-204`는 shell lexical 위치와 무관하게 모든 `#`부터 줄 끝까지 지운다. 유효한 `echo foo#bar; }`와 `echo ${value#x}; }`에서 실제 function closing brace까지 사라져 첫 함수가 다음 함수까지 삼키고 sibling identity가 누락된다.
- 해결 방법:

~~~text
Before
unquoted # anywhere -> comment to EOL

After
parameter expansion 밖에서 shell word 시작에 놓인 #만 comment
foo#bar와 ${value#x}의 #는 non-comment token으로 유지
${...} brace balance와 실제 function close를 서로 구분
escaped/quoted/hash comment/heredoc 기존 동작 보존
~~~

- 수정 파일 및 체크리스트:
  - [ ] `scripts/readability_audit.py`: shell word/comment 시작과 parameter expansion 상태를 분리해 comment 여부를 판정한다.
  - [ ] `scripts/readability_audit_test.py`: embedded hash, `${value#x}`, same-line close, 후속 함수 identity/LOC와 기존 `:;# }` comment를 함께 검증한다.
  - [ ] `scripts/readability_baseline.json`: 두 코드/테스트 파일 LOC와 `readability-baseline` read-set total을 포함한 실제 projection만 고정점으로 갱신한다.
- 테스트 작성: 작성한다. `test_shell_hash_comment_boundary_preserves_function_close`가 `bash -n`으로도 유효한 fixture의 `hash_word=(1,2,2)`, `trim=(3,4,2)`, `next=(5,7,3)`를 assert한다.
- 중간 검증:

~~~bash
python3 -m unittest \
  scripts.readability_audit_test.TestMultiLanguageFunctionIdentity.test_shell_hash_comment_boundary_preserves_function_close \
  scripts.readability_audit_test.TestMultiLanguageFunctionIdentity.test_shell_escaped_and_operator_comment_braces_are_ignored \
  scripts.readability_audit_test.TestMultiLanguageFunctionIdentity.test_shell_parameter_expansion_and_quotes_still_scan
bash -n <<'SH'
hash_word() {
  echo foo#bar; }
trim() {
  echo ${value#x}; }
SH
~~~

기대 결과: 3 tests와 `bash -n`이 PASS하고 comment/escape 회귀 없이 두 same-line close가 보존된다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `scripts/readability_audit.py` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1, 2 |
| `scripts/readability_audit_test.py` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1, 2 |
| `scripts/readability_baseline.json` | 실제 worktree projection 고정점 갱신 시 |

## 최종 검증

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

kotlin = '''class C {
  fun call() = compute()
    .size
  fun total() = 1 +
    2
  fun done() = 3
}
'''
shell = '''hash_word() {
  echo foo#bar; }
trim() {
  echo ${value#x}; }
next() {
  echo done
}
'''

kotlin_actual = [(f['name'], f['start'], f['end'], f['loc'])
                 for f in ra._extract_functions_kotlin(kotlin, 'probe.kt')]
shell_actual = [(f['name'], f['start'], f['end'], f['loc'])
                for f in ra._extract_functions_shell(shell, 'probe.sh')]
assert kotlin_actual == [('C.call', 2, 3, 2), ('C.total', 4, 5, 2), ('C.done', 6, 6, 1)], kotlin_actual
assert shell_actual == [('next', 5, 7, 3), ('hash_word', 1, 2, 2), ('trim', 3, 4, 2)], shell_actual
print('kotlin-depth-zero-continuations=exact')
print('shell-hash-boundaries=exact')
PY
bash -n <<'SH'
hash_word() {
  echo foo#bar; }
trim() {
  echo ${value#x}; }
SH
rm -f /tmp/iop-readability-followup-i.json /tmp/iop-readability-followup-j.json /tmp/iop-readability-followup-tracked-5.json
python3 scripts/readability_audit.py --check --input-mode worktree --output /tmp/iop-readability-followup-i.json
python3 scripts/readability_audit.py --check --input-mode worktree --output /tmp/iop-readability-followup-j.json
cmp /tmp/iop-readability-followup-i.json /tmp/iop-readability-followup-j.json
python3 scripts/readability_audit.py --check --input-mode tracked --output /tmp/iop-readability-followup-tracked-5.json
python3 - <<'PY'
import collections
import json

with open('/tmp/iop-readability-followup-i.json', encoding='utf-8') as handle:
    report = json.load(handle)
with open('scripts/readability_baseline.json', encoding='utf-8') as handle:
    baseline = json.load(handle)

identities = [(entry['path'], function['name'])
              for entry in report['files']
              for function in entry.get('functions', [])]
assert not [key for key, count in collections.Counter(identities).items() if count > 1]

current_violations = sorted(
    (v['path'], v['metric'], v.get('function', ''), v['level'], v['value'])
    for v in report['violations'])
baseline_violations = sorted(
    (v['path'], v['metric'], v.get('function', ''), v['level'], v['value'])
    for section in ('file_thresholds', 'function_thresholds')
    for v in baseline[section])
assert current_violations == baseline_violations

current_totals = sorted(
    (task['task_id'], task['total_loc'])
    for task in report['task_read_sets']
    if task['total_loc'] > task['budget']['max_total_loc'])
baseline_totals = sorted((entry['task_id'], entry['value'])
                         for entry in baseline['task_read_set_totals'])
assert current_totals == baseline_totals
print('duplicate-function-identities=[]')
print('baseline-projection=exact')
PY
make readability-audit
git diff --check
~~~

기대 결과: 전체 unit PASS, Kotlin/Shell 독립 probe exact, Bash syntax PASS, worktree JSON byte-identical, tracked/worktree RATCHET OK, identity 중복 0, report/baseline exact projection, Make target PASS, whitespace 오류 없음. 코드/테스트 LOC로 baseline 값이 증가하면 기존 reason을 보존해 수렴할 때까지 고정점 갱신하되 신규 helper violation은 허용하지 않는다.

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