# task-2729+9 — BASE_SOURCE_ISOLATION (worktree base를 fresh origin/main으로 고정)

## 레벨
Lv.3 (인프라 hardening 구현 + isolated 검증 — canonical workspace 무손상)

## 한 줄 목표
dispatch/봇 worktree 생성이 **stale 로컬 `main`(14ff8339)** 이 아니라 **fresh `origin/main`(e386d4cf)** 에서 분기하도록 base source를 격리·고정한다. canonical workspace(task-2716 branch·58 modified·1418 untracked·65 stash·25 unmerged commits)는 **무손상 보존**. 모든 검증은 isolated temp git repo에서 수행.

## 확정 root cause (단일 소스, ANU audit 2026-06-06)
- **로컬 `main` ref = 14ff8339 (stale)** ≠ `origin/main` = e386d4cf. `git rev-parse main` == 14ff8339.
- task-2729+8 worktree가 14ff8339(=로컬 main)에서 분기 → #181 hardening 없는 driver 위에 작업 → merge 충돌·stale base.
- 동일 근본이 EXTERNAL_DIRTY_BLOCKER(callback/finalize 차단)도 유발.
- evidence: `memory/events/task-2729+8.pr-blocked-stale-base-hold.json`, `canonical_workspace_restore_audit_260606.json`.

## 확정 call chain 후보 (audit 결과)
- 봇 경로: `prompts/DIRECT-WORKFLOW.md:174` → `scripts/worktree_manager.py create`.
- `worktree_manager.cmd_create`(line ~286): `enforce_origin_base=True` 기본. 로직: `git fetch origin` → `git rev-parse --verify origin/main` → 성공 시 `worktree add -b <branch> <path> <origin_base_sha>`(line 383, **올바름**) / 실패 시 `base_fallback=True` → `worktree add -b <branch> <path>`(line 390, **로컬 HEAD/main base**).
- 대조(정상): `scripts/taskctl.py:2241` = `worktree add <path> -b <branch> origin/main`(literal, 올바름) — 봇 미사용.
- ★ 미특정: task-2729+8 실제 base=14ff8339(로컬 main)인데 fallback(390)은 canonical 현재 HEAD(75fdf540, task-2716)를 줘야 함 → 14ff8339(로컬 main)이 나온 정확한 분기점 미상. **본 task 1순위 = 계측 재현으로 정확한 base 결정 코드 라인 특정.**

## 목표 (회장 verbatim)
1. dispatch / worktree_manager / start_task_guard / pre-push guard 중 **어느 경로가 canonical HEAD/로컬 main을 base로 삼는지 식별**.
2. origin/main 쓰는 경로 vs canonical HEAD/로컬 main 쓰는 경로 **분리**.
3. task-2729+8 stale base **재현 evidence**(계측 로그) 정리.
4. canonical dirty 여부 무관하게 **fresh origin/main에서 worktree 생성**하는 안전 설계.
5. 기존 task-2716 작업물·live memory artifacts **무손상**.
6. 별도 main-tracking worktree 방식 vs dispatch base override 방식 **장단점 비교**.
7. expected_files / forbidden_paths / regression 후보 작성.
8. DISPATCH_READY 또는 HOLD_FOR_CHAIR로만 보고.

## 설계 (구현 가능 범위)
### B1. base source 고정 (worktree_manager.cmd_create)
- `origin_base_sha` 미해결(rev-parse origin/main 실패) 시 **로컬 HEAD/main fallback 금지** → fail-closed(에러/HOLD 마커). stale 로컬 main으로 silent 분기 차단.
- fetch 후 `git rev-parse origin/main` 강제. base는 항상 origin/main SHA(또는 그 이후 최신).
- ★ literal `"main"`(로컬 ref) 사용 경로가 발견되면 `origin/main`으로 교정.
### B2. base marker 강제 기록
- dispatch/worktree 생성 시 marker에 `base_source`(예: "origin/main") · `base_sha` · `merge_base` · `origin_main_sha` · `canonical_head_sha` 기록. stale base 사후 추적 가능.
### B3. pre-push guard two-dot 오탐/실제 stale 구분 (scripts/git-hooks/pre-push)
- 현재 `git diff --name-only origin/main..HEAD`(two-dot) → stale base 시 과다 차단(정상 방어이나 메시지 모호).
- 개선: `merge_base=$(git merge-base origin/main HEAD)` 계산. `merge_base == origin/main`(HEAD가 fresh origin/main 후손) → three-dot diff만 scope 검사. `merge_base != origin/main`(stale base) → **STALE_BASE 명시 차단** + 재dispatch 권고. 오탐과 실제 stale 구분.

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "scripts/worktree_manager.py"
    - "scripts/git-hooks/pre-push"
    - "tests/regression/test_base_source_isolation_2729p9.py"
    - "memory/reports/task-2729+9.md"
    - "memory/plans/p0b-pickup/base_source_isolation_design_260606.md"
    - "memory/events/task-2729+9.*"
    - "memory/tasks/task-2729+9-base-source-isolation.md"
  read_only_reference:
    - "scripts/taskctl.py (★ :2241 origin/main literal 정상 경로 참조 — 수정 0)"
    - "scripts/start_task_guard.py (base_sha 마커 경로 참조 — 수정 0)"
    - "prompts/DIRECT-WORKFLOW.md:174 (worktree create 호출 — 참조)"
    - "memory/events/task-2729+8.pr-blocked-stale-base-hold.json (evidence)"
    - "memory/events/canonical_workspace_restore_audit_260606.json (evidence)"
  forbidden_paths:
    - "dispatch.py"
    - "dispatch/**"
    - "scripts/finish-task.sh"
    - "scripts/taskctl.py"
    - "scripts/start_task_guard.py"
    - "/home/jay/workspace (canonical working tree — 브랜치전환/reset/clean/stash 금지)"
    - "memory/events/task-* (다른 task live 마커)"
    - "memory/tasks/** (task-2729+9 제외)"
    - ".github/**"
    - "hooks/**"
    - "/home/jay/.claude/**"
    - "/usr/local/bin/cokacdir"
```

## EXPECTED FILES (정확히 5 — 초과 시 즉시 HOLD_FOR_CHAIR)
1. `scripts/worktree_manager.py` — B1 base 고정(fail-closed) + B2 base marker
2. `scripts/git-hooks/pre-push` — B3 merge-base 기반 stale/오탐 구분
3. `tests/regression/test_base_source_isolation_2729p9.py` — isolated temp git repo 회귀(stale local main 시 origin/main base 강제 / fallback 차단 / pre-push 구분)
4. `memory/reports/task-2729+9.md` — 재현 evidence + 구현 결과
5. `memory/plans/p0b-pickup/base_source_isolation_design_260606.md` — OPT3/별도 worktree 비교 설계
- (충돌 0 확인: worktree_manager/pre-push 는 14ff8339↔e386d4cf IDENTICAL)

## ★ 즉시 중단(HOLD_FOR_CHAIR) 조건 (회장 verbatim B)
1. dispatch.py / worktree_manager / guard 핵심 파일 수정이 **expected_files 5 초과**.
2. canonical workspace **상태 변경 필요**(브랜치전환/reset/clean/stash 등).
3. task-2716 **보존 정책 결정 필요**.
4. live memory artifacts **처분 필요**.
5. 실제 buggy base-resolution 경로가 **expected_files 밖**(dispatch spawn wrapper/cokacdir 등) → 해당 파일 명시 + HOLD.

## 선호 방향 (회장 verbatim)
- canonical workspace = live state root 보존.
- dispatch base source = origin/main 또는 별도 clean base worktree 분리.
- worktree 생성은 항상 **explicit base SHA 기록**.
- marker: base_source · base_sha · merge_base · origin_main_sha · canonical_head_sha.
- pre-push guard: merge-base ↔ origin/main 비교 명시(two-dot 오탐/실제 stale 구분).

## 금지 (회장 verbatim)
1. canonical workspace reset/clean/checkout -f  2. git stash -u로 1418 untracked 이동  3. task-2716 branch 수정·삭제  4. unmerged 25 commits 변경  5. live memory/events/tasks/reports 이동·삭제  6. stale task-2729+8 branch push  7. task-2729+8 PR 생성  8. rebase/force  9. production ACTIVE/systemctl enable/activation_epoch/real spawn
- 모든 검증은 **isolated temp git repo**에서. canonical /home/jay/workspace 무손상.

## ★ 실행 순서 강제 (REPRODUCTION-FIRST — 추측 fix 금지)
- ⚠️ 미스터리: 실제 base=14ff8339(로컬 main)인데 cmd_create fallback(390)은 canonical HEAD(75fdf540 task-2716)를 줘야 함 → fallback 만으로 설명 안 됨. **추측으로 worktree_manager 만 고치지 말 것.**
- 1순위: **계측 재현**(isolated temp repo + 실제 dispatch/worktree 생성 경로 trace)으로 "정확히 어느 명령/스크립트가 로컬 main 을 base로 줬는지" 특정.
- buggy 경로가 expected_files 밖(dispatch spawn wrapper / cokacdir / 기타) 이면 **즉시 HOLD_FOR_CHAIR**(해당 파일 명시). expected_files 안일 때만 fix.

## ★ self-referential 리스크 (봇 사전 인지)
- 본 task 봇의 worktree **자체도 같은 버그로 stale base(14ff8339)에서 생성**됨. worktree_manager/pre-push 가 14ff8339↔e386d4cf IDENTICAL 이라 **merge 충돌 0** 이나, finalize/push 시 **현 two-dot pre-push guard 가 막거나 EXTERNAL_DIRTY_BLOCKER** 가능 → **수동 .done 생성 금지**, ANU normal callback envelope(독립 ANU key) 작성 후 ANU manual pickup 회수 허용. 산출물은 worktree branch 보존.

## 완료 판정
- **`BASE_SOURCE_ISOLATION_VERIFIED`** 또는 **HOLD_FOR_CHAIR**.
- 본 task는 base source 격리 인프라 수정 — pickup activation/real wake와 독립. PASS 후 task-2729+8 fresh 재dispatch는 **별도 단계**. task-2729+8 stale branch는 계속 evidence-only 보존.

## doctrine
직접 코딩 금지(ANU)/봇 위임 / canonical 무손상 / isolated temp root 검증 / same-PR post-Gemini push 금지 / callback ANU key 독립 발사·self-collector 금지.
