# task-2726+4 보고서 — LOOP_BOUNDARY repair (fail-open family 전수 fail-closed + /home/jay 하드코딩 전수 제거)

- 작업 ID: task-2726+4 (round-4 bounded repair)
- 팀: dev3-team (다그다)
- 상태: **MERGE_APPROVAL_CANDIDATE** (PR #171 갱신, head `cc32e5b6` — 회장 승인 전 merge 금지)
- 회장 인가: 2026-06-03 LOOP_BOUNDARY repair (PR #171 fresh HIGH 2건)

## S (Situation)
PR #171(직전 head `9731cc4b`)에서 OWNER `/gemini` fresh HIGH 2건이 식별됨(코드 직접대조, FALSE_POSITIVE 아님):
- **HIGH-1 (line 539-540)**: STRICT mode 에서 `git rev-parse --git-dir` 실패(non-git) 시 `[SCOPE-GUARD] not a git repo — 검증 스킵` = fail-OPEN 잔여 분기. round-3 이 닫은 SCOPE_BASE empty 와 같은 fail-open family.
- **HIGH-2 (line 8 + 56)**: `WORKSPACE="/home/jay/workspace"`(line 8) + `glob.glob(f'/home/jay/.cokacdir/...')`(line 56) = WORKSPACE_ROOT_HARDCODE 재발.
- ANU 전수 audit 추가 발견: line 569 `diff 비어있음 — 검증 스킵` 도 fail-open 후보.

## C (Complication)
fail-open 분기를 1건씩 막으면 같은 family(non-git, diff-empty, SCOPE_BASE empty)가 round 를 거듭하며 재발(LOOP_BOUNDARY). 이번엔 STRICT 스킵 분기를 **전수 fail-closed 일관화**로 종결해야 round-5 를 방지. 동시에 non-strict(default-off) 레거시 호환과 정당한 스킵(.scope-guard-done·non-code·non-strict)은 보존해야 함.

## Q (Question)
STRICT mode 의 모든 "검증 불가능" 분기를 fail-closed(exit 1)로 일관화하되, default-off 레거시 동작을 1바이트도 바꾸지 않고, /home/jay 코드경로 리터럴을 0으로 만들 수 있는가?

## A (Answer) — 변경 내용 (expected_files 2개 내부)

### `scripts/finish-task.sh` (+17 / -3 라인, commit `27035cba`)
1. **HIGH-2 line 8**: `WORKSPACE="/home/jay/workspace"` → `WORKSPACE="${WORKSPACE:-$HOME/workspace}"` (env/default 주입).
2. **HIGH-2 line 56**: `_resolve_task_worktree` 의 cokacdir glob `/home/jay/.cokacdir` → `os.path.expanduser('~')` 기반 `{_home}/.cokacdir`. (`os` 모듈 기존 import 활용.)
3. **HIGH-1 (non-git)**: STRICT 에서 SCOPE_PROJ_DIR 가 git repo 아니면 → `_emit_worktree_unresolved` + `[ERROR][STRICT] ... 미검증 변경 통과 차단(fail-closed)` + `exit 1`. non-strict 는 기존 `not a git repo — 검증 스킵` echo 보존.
4. **fail-open family (diff-empty)**: STRICT 에서 scope diff 비어있음 → `_emit_worktree_unresolved` + `exit 1`(fail-closed). non-strict 는 `diff 비어있음 — 검증 스킵` 보존.
5. round-3 SCOPE_BASE empty fail-closed 유지 / non-strict 레거시 경로(`${MAIN_BRANCH}..HEAD` + `HEAD~1` fallback) 보존.

### `tests/regression/test_finish_task_worktree_isolation_2726.py` (회귀 35→42, commit `cc32e5b6`)
- `TestStrictNonGitFailClosed` (회귀8, 2건): non-git STRICT fail-closed 가드 정적 검증 + non-strict SKIP echo 보존.
- `TestStrictDiffEmptyFailClosed` (회귀9, 2건): diff-empty STRICT fail-closed 가드 + non-strict SKIP echo 보존.
- `TestNoHomeJayHardcode` (회귀10, 3건): /home/jay 코드경로 리터럴 0 + `${WORKSPACE:-$HOME/workspace}` + `expanduser('~')` 사용 검증.

## 모델 사용 기록
- 루(Lugh, 백엔드): **sonnet** — finish-task.sh 4개 Edit (bash/python surgical fix).
- 모리건(Morrigan, 테스터): **sonnet** — 회귀 7건 추가.
- 다그다(팀장, opus): 설계/분배/통합/L1 검증. (직접 코딩 없음 — 정확한 문자열 명세 위임.)
- haiku 미사용 (정밀 exact-match 작업으로 sonnet 이상 필수).

## 회장 10 검증 결과 (전 항목 PASS)
1. STRICT + non-git → fail-closed(exit 1): **L1-B 실동작 PASS** (rc=1, CONTINUED 미도달).
2. STRICT + SCOPE_BASE empty → fail-closed 유지: 회귀7(round-3) 정적 PASS.
3. STRICT + valid git + valid SCOPE_BASE → 정상 diff: 회귀 `test_strict_valid_scope_base_generates_diff` PASS.
4. non-strict/default-off → 기존 호환: 회귀6/회귀10 + L1-B/L1-C STRICT=0 skip PASS.
5. /home/jay literal 코드경로 0: goal_assertion PASS (`HOMEJAY code literal = 0`).
6. main/master default branch 회귀 유지: 회귀7(TestMainBranchDetectionMasterDefault) PASS.
7. regression 35 유지/증가: **42 passed** (35→42, +7).
8. `git diff --name-only merge-base(origin/main,HEAD)..HEAD` = expected_files **2파일** 정확.
9. forbidden 0: critical_gap.py/terminal_state_callback.py/deploy/systemd/.github 변경 0.
10. ANU key 리터럴(`c119085addb0f8b7`) 0: 소스/테스트 모두 0.

## ★ L1 스모크테스트 결과 (필수)
pytest PASS ≠ 실동작. 실제 bash 실행으로 fail-closed 분기 동작을 검증:
- **서버 재시작**: 해당없음 (bash 스크립트 수정 — 서버 무관).
- **API 응답 확인**: 해당없음 (API 아님).
- **스크린샷**: 해당없음 (프론트엔드 아님).
- **L1-A (resolver 실동작)**: 수정된 `_resolve_task_worktree` 실제 실행 → `/home/jay/workspace/.worktrees/task-2726-dev3` 정확 echo, rc=0. **PASS** (Edit2 expanduser 무회귀 확인).
- **L1-B (HIGH-1 non-git fail-closed 실동작)**: 실제 bash 실행 — STRICT=1 + non-git dir → **rc=1 (exit 1, fail-closed)**, `_emit_worktree_unresolved` 발화, CONTINUED 미도달 / STRICT=0 → 검증 스킵 echo 후 정상 계속(rc=0). **PASS**.
- **L1-C (diff-empty fail-closed 실동작)**: 실제 bash 실행 — STRICT=1 + 빈 diff → **rc=1 (fail-closed)** / STRICT=0 → 스킵 후 계속(rc=0). **PASS**.
- **bash -n**: rc=0 (구문 무결).
- **pytest**: 42 passed in 1.21s.

## goal_assertions (auto) 결과
- `pytest tests/regression/test_finish_task_worktree_isolation_2726.py -q` → 42 passed. **PASS**
- `bash -n scripts/finish-task.sh` → rc=0. **PASS**
- `/home/jay` 코드경로(주석 제외) 0 → **PASS**
- `c119085addb0f8b7` 리터럴 0 → **PASS**

## Git / 머지 판단
- **commit**: `27035cba`(루), `cc32e5b6`(모리건).
- **push**: non-force, `9731cc4b..cc32e5b6` fast-forward, **PR #171 갱신**(head=cc32e5b6, OPEN).
- **머지 필요**: Yes — 단 **회장 승인 전 merge 금지 (MERGE_APPROVAL_CANDIDATE)**.
- **브랜치**: task/task-2726-dev3
- **워크트리 경로**: /home/jay/workspace/.worktrees/task-2726-dev3
- **머지 의견**: bounded surgical fix. fail-open family(non-git/diff-empty) 전수 fail-closed 종결 + /home/jay 코드경로 0. 42 회귀 PASS, diff 2파일, forbidden/ANU key 0, STRICT default-off 무회귀(L1 실동작 확인). 새 head OWNER gemini trigger → CI GREEN + fresh unresolved HIGH/CRITICAL 0 시 MERGE_APPROVAL_CANDIDATE.

## 발견 이슈 및 해결
1. **shared main 외부 dirty 4건**(memory/specs, utils/replacement_pr_runner.py 등 — task 무관): git-gate EXTERNAL_DIRTY_BLOCKER 대상이나 **shared main 정리 금지 doctrine** 준수 → 미정리. 본 task 완료(.done)는 PR 머지 후 ANU callback 경유(직전 round 패턴 동일). 범위 외(환경 블로커).
2. 완료 경로: PR 열림 상태 → finish-task.sh PR-GATE/git-gate 가 .done 차단(정상). `.done` 위조 0.

## 비고 (doctrine 준수)
- expected_files 2파일 밖 수정 0 · merge 0 · FINISH_TASK_WORKTREE_STRICT 활성화 0 · force push/rebase/admin override 0 · ACTIVE 변화 0 · shared main stash/reset/clean 0 · 디자인 스킬 미호출.
- ANU normal callback cron 등록(collector_role=ANU, 독립 ANU key, canonical launcher 경유 — self-key 금지) — 본 task 종료 시 등록.
- 또 같은 fail-open/hardcode 계열 fresh HIGH 재발 시 → replacement PR 전환 보고(round-5 bounded 금지).

---

# [ANU consolidated] 독립검증 회수 — watcher CA8C3B0D terminal-state

수집 역할 **ANU(collector_cron 4F4A38A2)**. dev3 의 위 repair 보고와 watcher evidence 를 ANU 가 **PR/GitHub/코드 blob 직접 실측**으로 무관하게 재현함. self-key 금지 준수(ANU_KEY 자기콜백 등록 없음).

## 0. Evidence 무결성 (sha256)
- `memory/events/task-2726+4.watcher-terminal-state.json`
- 기대 = 실측 = `29df523a95887c53389fa72cc7fef4f946d0364366e344342930d9f9909aa796` → **MATCH** (위변조 없음).

## 1. watcher 10-check 전건 독립 재현
1. **non-force/fast-forward**: `9731cc4b` 는 `cc32e5b6` 의 조상(merge-base --is-ancestor 확인). force 아님. **PASS**
2. **CI 11/11 GREEN**: `gh pr checks 171` = 11 pass / 0 fail / 0 pending. **PASS**
3. **owner /gemini trigger(request-only)**: comment `4615663555` @18:44:27Z, author=JonghyukJeon(OWNER), `/gemini review`. dev3 finalize EXTERNAL_DIRTY_BLOCKER 로 watcher 발사(doctrine). **PASS**
4. **fresh review HIGH/CRITICAL=0**: review `4421698758` @18:45:57Z (commit 18:19:54Z < push ≤18:26Z < trigger 18:44:27Z < review 18:45:57Z = 진성 fresh). inline 4건 전부 MEDIUM, HIGH 0/CRITICAL 0. 후속 fresh review 0. **PASS**
5. **★graphql 불신→코드대조 (carry-forward HIGH 반증)**: cc32e5b6 부착 non-outdated `![high]` 2건(thread 3348408140 orig `80416faa`=리뷰4418445439 @12:25Z / thread 3349020425 orig `9731cc4b`=리뷰4419172929 @13:51Z) **둘 다 resolved=true**. 지적 코드 실측: fail-open `': > $SCOPE_DIFF_FILE'` 제거(현 exit 1), `/home/jay` 부재 → stale, fresh 결함 아님. **반증 PASS**
6. **STRICT fail-closed 계열**: non-git(L541)→exit1, SCOPE_BASE empty→exit1, diff-empty→exit1; non-strict 레거시 SKIP 보존. fail-open grep 0. **PASS**
7. **/home/jay 코드경로 0**: finish-task.sh 0건. L8 `${WORKSPACE:-$HOME/workspace}`, L56 `expanduser('~')`. (테스트 파일 출현은 주석+부재검증 assertion.) **PASS**
8. **diff 2파일/forbidden0/ANUkey0**: `6a44d712..cc32e5b6` = finish-task.sh + test_…_2726.py. forbidden 0, ANU key 리터럴 양파일 0. **PASS**
9. **STRICT default-off**: L15 `FINISH_TASK_WORKTREE_STRICT="${...:-0}"`. ACTIVE 변화 0. **PASS**
10. **regression**: 2726 파일 test_ 42개(35→42), py_compile OK, `bash -n` rc=0, CI 그린으로 실행 검증. **PASS**

## 2. thread 집계 (GraphQL 31 thread 전수)
- **BLOCKING(HIGH, non-outdated, unresolved) = 0** / **BLOCKING(CRITICAL …) = 0**
- HIGH 7 = outdated 5 + non-outdated-resolved 2 → unresolved+non-outdated HIGH **0**
- resolved 6 = HIGH 2(stale carry-forward) + MEDIUM 4(fresh)

## 3. 비차단 잔여
- MEDIUM 4(robustness, non-blocking): L48 samefile / L62 relative path resolve / L528 `-ef` / L557 `sys.argv`.
- check#8 `live_prune_not_wired`(정보성): fallback(12CFE4A2) 자동 tombstone 미배선, 런타임 self-suppression 의존. ACTIVE=false. PR 무관·비차단.

## 4. ANU 판정
fresh HIGH 재발 false · replacement PR 불필요 · CHAIR_REQUIRED 아님 · merge 미수행. **terminal_state = MERGE_APPROVAL_CANDIDATE 확정** (watcher 와 동일 결론을 ANU 독립 재현).

## 5. 회장 보고 (한 장)
> **PR #171 (task-2726+4 round-4 LOOP_BOUNDARY)** — fail-open/`/home/jay` 하드코딩 계열을 STRICT fail-closed 로 종결.
> CI 11/11 GREEN · fresh review HIGH/CRITICAL 0 · 차단 thread 0(HIGH carry-forward 2건은 pre-push stale·resolved) · diff 2파일(forbidden0/ANUkey0) · STRICT default-off.
> evidence sha256 일치, ANU 독립 재현 완료.
> **판정: MERGE_APPROVAL_CANDIDATE — 회장 승인 시 merge 가능. ★승인 전 merge 금지(대기 중).**
