# Agent 미팅 — `.done` 시맨틱 재설계 (실제 머지 일치)

**날짜**: 2026-05-02
**진행자**: 헤르메스(개발1팀장)
**소집 사유**:
1. task-2364 PR #5 사례 — `.done` 17:08 → 머지 18:11 (63분 갭) → 아누가 회장께 "머지 누락" 잘못 보고
2. 회장 메시지: "정말 모든 작업이 끝나야 .done 생성할 수 있게 할 방법 없을까????? 실제 상황이랑 일치하게 만들고 싶은데!!!"
3. Codex G1 사전 검증 critical 1건 + high 2건 — 현재 `finish-task.sh`는 이미 `worktree_manager.py finish` 실패 무시 후 `.done` 생성 (fail-open)

**참여 페르소나** (10명):
- **1팀 (주최)**: 헤르메스(진행), 불칸(BE), 이리스(FE), 아테나(UX), 아르고스(테스터)
- **외부 (회장 지정)**: 로키(DA), 마아트(QC), 비너스(디자인 세컨드), 아틀라스(아키텍처/Unconventional), 다빈치(통합)

**미팅 모드**: hybrid
**토론 깊이**: thorough
**총 사이클**: 5

---

## 사전 브리핑 — Codex G1 검증 발견

| 심각도 | 핵심 지적 | 본 미팅 반영 |
|---|---|---|
| **critical** | `scripts/finish-task.sh`가 `worktree_manager.py finish --action auto` 실패를 무시하고 `.merge-done`/`.done`을 무조건 생성 (라인 434-438, 940-959). 실제 머지/PR 없이도 `.done` 생성 가능 — **이미 fail-open** | 옵션 A/B/C 평가에 "fail-closed 보장" 게이트 강제 |
| high | 3가지 완료 경로 — (a) local git merge / (b) GitHub PR merge / (c) PROJECT_PATH 없는 시스템·문서 task — 단일 정의 어려움 | Cycle 1 후 작업 유형별 상태 모델 정의 |
| high | 기존 `.done` 소비자(whisper-compile.py, session-watchdog.sh, notify-completion.py, auto_merge.py) 마이그레이션 누락 시 중복/누락/상태 불일치 | Cycle 5 합의에 마이그레이션 표 필수 |
| medium | 코드 계약(scripts) 검증 없는 결론은 구현 단계에서 뒤집힘 | 후속 task 초안에 코드 계약 매핑 명시 |

**진행자 결정**: Codex 지적은 본 미팅의 **사전 입력**으로 통합 (안건 확장). 옵션 A/B/C는 좁게 정의되어 있어 fail-open + 3 완료 경로 + 마이그레이션을 동시에 다루지 못함 → 합의 옵션 D 도출이 목표.

---

## Cycle 1 — Independent (옵션 A/B/C 독립 평가)

### 로키 (Devil's Advocate)

**A 약점**: `.work-done` → `.merged` → `.fully-done` 3단계는 **race window를 3개로 늘린다**. auto_merge.py가 `.merged` 직전 크래시 시 PR은 main에 들어갔는데 마커 영영 미생성 → 아누는 "머지 누락" 보고를 *여전히* 함. 결함을 분산시켰을 뿐.

**B 약점**: GitHub 장애·rate limit·네트워크 단절 시 finish-task.sh 무한 점유 → **DoS 벡터**. 공격자가 reviewer block, status check 방해로 의도적 지연 가능.

**C 약점**: done-watcher.py = **단일 장애점(SPOF)**. 워처 죽으면 모든 task 영구 정체. PROJECT_PATH 없는 시스템·문서 task는 PR 부재 → mergedAt 영원히 null → **이 부류 task는 절대 완료되지 않는다**.

**핵심 반박 (옵션 A/B/C 모두에 적용)**:
> 시맨틱 재설계는 fail-open과 **직교(orthogonal)**. 마커 이름 바꾸기 ≠ 에러 핸들링 수정.
> `finish-task.sh` 라인 434-438, 940-959를 직접 수정하지 않으면 결함 잔존.

### 마아트 (QC)

**5게이트 검증 매트릭스**:

| 게이트 | A (3마커) | B (동기 폴링) | C (watcher) |
|---|---|---|---|
| G1 fail-closed | 조건부 | PASS | **PASS** (구조적) |
| G2 시스템·문서 (c) | PASS | 조건부 | 조건부 |
| G3 마이그레이션 비용 | **FAIL** (4 소비자 전수) | PASS (소비자 무변경) | 조건부 |
| G4 외부 검증성 | PASS | FAIL (회색지대) | **PASS** (mergedAt SoT) |
| G5 race 차단 | FAIL | PASS | PASS |

**Silent corruption 사례**:
- A: `.merged` 후 `.fully-done` 직전 크래시 → 소비자 OK 판정, squash 충돌 롤백 미감지
- B: rate limit 폴링 미스 → **finish-task.sh fail-open 버그가 살아있으면 폴링 결과 무시 후 `.done` 작성 (task-2364 재현)**
- C: watcher 자체 장애 시 `.merged` 영구 미생성 (외부 단언으로 즉시 적발 가능)

**상태 모델 제안**: Codex 5상태(`merged | kept | blocked_by_timeout | merge_failed | system_task`)를 **C 위에 직교**시키는 게 최적. `state.json`을 SoT로, 마커는 캐시.

**비관습적 — Merkle-style 검증 마커**: 마커 내부 `{commit_sha, merge_commit_sha, mergedAt, signed_by}` JSON + HMAC. 소비자가 `git cat-file`로 SHA 검증.

**최종 추천**: **C + state.json SoT + Merkle 서명 = 옵션 D**. A는 race 폭증으로 기각, B는 fail-open 잔존 위험으로 기각.

### 아틀라스 (시스템 아키텍처, Unconventional Mandate)

**외부 시스템 채택**: **Argo CD declared/observed**. 핵심 통찰 — task-2364의 63분 갭은 "마커가 부족해서"가 아니라 **declared(작업자 의도)와 observed(GitHub 사실)를 같은 파일에 욱여넣어서** 발생한 카테고리 오류.

| 시스템 | 적합도 | 차용 포인트 |
|---|---|---|
| GitHub Actions check_suite | 중 | conclusion enum 8종 (timed_out, action_required 추가) |
| GitLab CI | 중 | `running` 상태 명시 — 17:08~18:11 갭이 곧 이 부재 |
| **Argo CD** | **최상** | **declared vs observed 분리** |
| Drone | 하 | 과설계 |
| Spinnaker | 중 | 인프라 비용 과다 |

**Unconventional 1 — `.done` 파일 자체 폐기 (채택 확률 ~7%)**:
- 상태는 `git log --grep="task-2364"` + `gh pr view --json mergedAt` 두 곳에서만 도출
- 모든 마커 제거, done-watcher가 ad-hoc 판정
- **5항목 평가**:
  - 지지: fail-open 구조 자체 소멸, 단일 SoT
  - 반론: GitHub propagation lag (수초~수분), 회장 보고 시점 race
  - 시나리오: 17:08 push → 17:09 watcher → state:OPEN → "in-progress" 보고 → 18:11 머지 → "done" → 잘못 보고 0건
  - 노력: 중상 (finish-task.sh 마커 로직 제거, watcher 재작성, 보고 enum 확장)
  - 리스크: GitHub API 장애 시 마비 → fallback git log only

**Unconventional 2 — 책임 경계 재배치 (보고자 직접 검증)**:
> 시맨틱 재설계는 잘못된 질문. 진짜 질문 = "왜 보고자(아누)가 생산자(finish-task.sh) 출력을 무비판적으로 신뢰하는가?"

생산자는 그대로 두고, **아누 보고 함수가 보고 직전 항상 `gh pr view --json mergedAt` 호출**. mergedAt null 또는 `.done` mtime 이후 10분 초과 시 "머지 진행 중"으로 강등. Argo CD `observedGeneration < generation` 체크와 동형.

### 다빈치 (멀티 도메인 통합)

**트레이드오프 매트릭스 (5축 × 3옵션)**:

| 옵션 | 신뢰성 | 단순성 | 마이그 비용 | 시스템·문서 처리 | 운영 가시성 |
|---|---|---|---|---|---|
| A | 85 | 45 | 30 | 70 | 90 |
| B | 70 | 75 | 75 | 50 | 60 |
| C | 90 | 65 | 60 | 40 | 85 |

**외부 패턴 차용 3건**:
- **CI/CD**: GitHub Actions `job.status` + `conclusion` 이중 필드 → `.work-done`(status) + `.merged`(conclusion)
- **메시징**: RabbitMQ publisher confirms + consumer ack → `finish-task.sh`가 publish, `done-watcher`가 ack
- **GitOps**: Argo CD desired vs observed → `.work-done` = desired, `.merged` = observed, auto_merge.py = reconciler

**최종 추천**: **하이브리드 D = A의 마커 분리 + C의 mergedAt 폴링**. 시스템·문서 task는 PROJECT_PATH=null 분기에서 `.work-done` 즉시 `.merged` 동시 생성.

**task-2367 영향**: 블로킹 아님, 오히려 시너지 — 마커 스키마 합의 시 auto_merge.py reconciler 재설계로 양 task 동시 진행 가능. 단, **finish-task.sh fail-open 핫픽스(`set -e` + exit code 검사)는 task-2367과 독립적으로 P0 선행**.

---

### Cycle 1 종합 (헤르메스)

**4 외부 페르소나 모두 옵션 D(하이브리드) 또는 그 이상으로 수렴**:
- 마아트: C + state.json + Merkle 서명
- 아틀라스: Argo CD declared/observed (= D 본질)
- 다빈치: A 마커 분리 + C 폴링 = D
- 로키: D 채택 시에도 fail-open 결함 직교 — 시맨틱 재설계 자체 회피 시도

**핵심 합의 영역**:
1. **fail-open 결함은 시맨틱 재설계와 직교** → finish-task.sh 핫픽스 P0 선행 (만장일치)
2. **declared vs observed 분리 필요** → A의 마커 분리 + C의 mergedAt 검증 결합
3. **state.json SoT 권장** (마아트), 마커는 캐시
4. **시스템·문서 task 별도 처리** 필요

**핵심 쟁점 (Cycle 2-3 재논의)**:
- 로키 DA: 시맨틱 재설계 자체 폐기 가능성 (3건 단순 대안)
- 마아트 vs 아틀라스: state.json SoT vs Argo CD declared/observed 누가 더 정합?
- 시스템·문서 task 처리: `kind: meta` schema 신설 vs PROJECT_PATH=null 자동 추론?

---

## Cycle 2 — Sequential (1팀 도메인 의견 + 비너스 세컨드)

### 불칸 (백엔드/auto_merge.py)

옵션 D에서 `auto_merge.py`는 **이벤트 트리거 → reconciler 루프**로 전환.

**구현 3단계**:
1. `MarkerScanner.scan_work_done()` 신설 — `.work-done` 발견 시 `state.json`에 `pending_merge` 항목 append (idempotent: task_id 중복 방지)
2. `Reconciler.tick()` 분리 — pending_merge 큐 순회, GitHub API로 `mergedAt` 확인, 성공 시 `.merged` atomic 생성 + 큐 제거. 실패 시 retry_count 증가, 5회 초과 시 `.merge-failed` + 알림
3. **finish-task.sh 종료코드 검사 강제** — `worktree_manager.py finish` exit≠0 시 `.work-done` 자체 생성 차단 (로키 fail-open 결함 동시 봉합)

**Race condition 차단**: `.merged` 생성은 `flock(LOCK_EX)` + `os.rename()` atomic. 동일 task에 두 reconciler 동시 진입 시 두 번째는 no-op.

### 이리스 (프론트/대시보드)

**색상·메시지 매핑**:
- `.work-done` only → **황색(amber)** + "작업 완료 · 머지 대기" + 회전 스피너 (PR URL 클릭 가능)
- `.merged` → **녹색** + "머지 완료" + commit SHA 7자리
- `.merge-failed` → **적색** + "머지 실패 · 재시도 N/5"

**변경 컴포넌트**:
1. `dashboard/components/TaskStatusBadge.tsx` — `is_done` boolean → `merge_state: work_done|merged|merge_failed` 3-state enum
2. `dashboard/api/task_state.py` — `state.json`의 `pending_merge` 큐를 응답 페이로드 포함, 폴링 주기 reconciler tick과 동기(15s)

**UI 변경**: 회장 화면 상단 "오늘의 완료" 카운터를 **"작업 완료 N건 / 머지 완료 M건"** 2분할 카드로 교체. M < N일 때 amber "머지 지연 K건" 노출.

### 아테나 (UX/회장 알림)

**예/아니오 답: 그렇다, 옵션 D는 task당 알림을 2번 발생시킬 수 있다** — 인지 부담 핵심 회귀.

**알림 시점 권장 (옵션 D + Tier 결합)**:
- **Tier 1 자동 머지**: `.work-done` 알림 억제, `.merged`만 1회 알림
- **Tier 2/3 수동**: `.work-done`에서 알림 (회장 액션 필요), `.merged`는 dashboard-only
- **`.merge-failed`만 즉시 알림** — 회장 개입 진짜 필요한 순간

**5분 batch 묶음**: Tier 1 머지 완료는 5분 윈도우 batch → "최근 5분 내 머지: task-2368, task-2371, task-2375 (3건)" 단일 알림.

### 아르고스 (테스터/회귀)

**회귀 시나리오 3건 + 차단 테스트**:

1. **4개 소비자 호환성** — `.work-done`/`.merged` 분리 시 `.done` 직접 stat/glob하는 4 소비자 silent miss
   - **차단**: `tests/regression/test_done_marker_consumers.py` — (a)`.work-done`만, (b)`.merged`만, (c)둘다 × 4 소비자 = 12 cell 매트릭스
2. **PROJECT_PATH 없는 시스템·문서 task** — PR 부재 시 reconciler가 `.merged` 영영 못 찍음 → amber 영구 정체
   - **차단**: `tests/regression/test_meta_task_terminal_state.py` — `task.yaml: kind: meta` 또는 `merge_required: false` schema validator. meta task는 `.work-done` = terminal state로 인정되도록 reconciler 분기. 미설정 시 CI fail
3. **PR 머지 실패/타임아웃 영구 정체** — 5xx/conflict 시 `.merged` 미생성, retry 무한 → 큐 누적
   - **차단**: `tests/regression/test_merge_failure_escalation.py` — GitHub API mocking (a)5xx 3회 후 성공, (b)5xx 5회 초과, (c)merge conflict. 5회 초과 시 `.merge-failed` + 알림 + 큐 제거. 24h 후 `.merged` 없으면 자동 escalation

### 비너스 (디자인 세컨드 오피니언)

**아테나 권고 약점**: Tier 2/3에서 `.work-done` 즉시 알림은 인지 부담을 *재배치*만 한다. 회장 결정 시점은 `.merged` 직전이지 `.work-done` 시점이 아님. 작업자 신호 그대로 노출 시 *작업자 페이스*에 회장이 끌려감. 5분 batch도 동시 다발 시 다이제스트 자체가 또 다른 큐.

**보강 — Dwell + Progressive Disclosure**: `.work-done` 후 **dwell window 90초** 동안 알림 보류, 같은 PR 추가 이벤트 흡수. dwell 종료 시 단일 카드 승격. 색/강도 3단계: 회색(work-done) → 황색(approval needed, 5분 미응답) → 적색(merge-failed/SLA 초과).

**회장 첫 화면 (Decision Cockpit)**:
1. **결정 큐**: 승인 대기 PR 카드 (Tier·dwell 잔여시간·diff 요약) — 상단 고정
2. **조용한 스트림**: 자동 머지 완료 다이제스트 (접힌 상태, 카운트만)
3. **경보 배너**: `.merge-failed` 단독 적색 (1건이라도 즉시 부상)
4. **하단 회복 패널**: 24h 머지율·평균 dwell·실패 재시도 (인지 회복 지표)

---

### Cycle 2 종합

**1팀 + 비너스 의견 일치점**:
1. 옵션 D 채택 시 자연스러운 구현 경로 (불칸의 reconciler 패턴 + 이리스 3-state UI + 아테나 Tier별 알림 + 아르고스 12-cell 매트릭스)
2. **fail-open 핫픽스 동시 봉합** (불칸 #3 — finish-task.sh exit code 검사)
3. **dwell window 90초** 도입 (비너스 보강) — 5분 batch 대안 또는 보완

**Cycle 3-4 입력 정리**:
- 로키 DA 3대 답변 처리 → Cycle 3
- 아틀라스 비관습 2건(마커 폐기 / 책임 경계 재배치) 평가 → Cycle 4

---

## Cycle 3 — Devil's Advocate (로키)

### DA 3대 질문 + 반박

**[DA Q1] 가장 현실적 실패 시나리오**
> 마이그레이션 중 혼재 상태. 구버전 finish-task.sh는 `.done` 생성, 신버전 watcher는 `.merged`만 인식. 4개 소비자 중 하나라도 업데이트 누락 시 **현재보다 더 나쁜 상태 불일치**.

**반박 (다빈치 + 아르고스)**:
- 다빈치 마이그레이션 우선순위 표 (P0/P1/P2) 채택 → 단일 PR로 전수 수정 강제
- 아르고스 12-cell 호환성 매트릭스 CI 강제 → silent miss 차단
- **호환 shim**: `.merged` 생성 시 `.done` symlink 6개월 유지 (마아트 deprecated alias 제안 차용)
- **판정**: 반박 수용 (단, 마이그레이션 PR이 단일 atomic + shim 6개월 필수 조건)

**[DA Q2] 6개월 후 후회 이유**
> 마커 시맨틱 3개로 늘면 신규 요구사항마다 또 마커 추가(`.deployed`, `.verified`, `.rolled-back`). 마커 파일 시스템 = 가난한 자의 상태 DB. "왜 sqlite/Redis 안 썼지?" 후회.

**반박 (마아트 + 아틀라스)**:
- **state.json SoT 채택** → 마커는 캐시일 뿐, 신규 상태 추가는 state.json enum 확장으로 흡수 (마커 파일 추가 X)
- Argo CD declared/observed 모델 명시 → 향후 enum 확장은 declared/observed 양 축에서 자연스럽게 정의 가능
- **판정**: 반박 수용 (state.json SoT + 마커는 캐시 명시 조건)

**[DA Q3] 더 단순한 대안 — 시맨틱 재설계 폐기**
> 회장의 진짜 요구는 "잘못 보고 차단"이지 "마커 시맨틱 정합성"이 아니다. 3건 제시:
> 1. 아누 프롬프트에 "보고 전 `gh pr list --state merged` 검증" 추가 (제로 코드)
> 2. `.done.meta` JSON 추가 (10줄 패치, 기존 소비자 무변경)
> 3. 63분 갭은 정상 비동기 — "Merge ETA" 표시로 기대치 재조정

**부분 수용 + 부분 기각 (헤르메스 + 마아트 + 아틀라스 합의)**:
- **대안 1 (운영 룰)**: **부분 채택** — 즉시 적용 가능 핫픽스. 단, 운영 룰만으로는 silent corruption 차단 불가 (마아트 G4 외부 검증성 FAIL). **임시 대응**으로 인정, 옵션 D 구현까지의 가교
- **대안 2 (메타 파일)**: **기각** — 4 소비자 모두 메타 파일 분기 추가 필요 (마이그레이션 비용 옵션 A와 동등). 불칸 reconciler 모델보다 분산도 큼
- **대안 3 (기대치 재조정)**: **기각** — 회장 메시지 명시: "실제 상황이랑 일치하게 만들고 싶다". 기대치 재조정은 회장 의사 거역
- **판정**: 대안 1만 잠정 채택 (옵션 D 구현 전 임시 가드), 시맨틱 재설계 자체는 진행

### 로키 결정적 반론 (fail-open 직교성)

**로키 핵심 반박**:
> 시맨틱 재설계는 fail-open과 직교. `finish-task.sh` 라인 434-438, 940-959를 직접 수정하지 않으면 옵션 A/B/C 모두 결함 잔존.

**반박 (불칸 + 아틀라스 HOUR 1 + 다빈치 합의)**:
- 옵션 D 구현 패키지에 **finish-task.sh fail-open 핫픽스 P0 선행 명시** (불칸 구현 3단계 #3, 아틀라스 HOUR 1 첫 결정, 다빈치 추천 사유 #2)
- 두 작업을 별도 PR로 분리 → 옵션 D PR 비대화 차단 (로키 우려 해소)
- **판정**: 로키 핵심 반박 **완전 수용**. fail-open 핫픽스를 후속 task의 Phase 1으로 분리

---

## Cycle 4 — Unconventional Alternative (아틀라스)

### 비관습적 대안 채택 결정

| 대안 | 채택 여부 | 사유 |
|---|---|---|
| **마커 자체 폐기 (git log + GitHub API SoT)** | **부분 채택** | state.json SoT가 마아트 제안과 결합되어 사실상 "마커는 SoT 아님"으로 격상. 단, 마커 파일은 캐시·관측성 목적으로 유지. **GitHub API rate limit 회피용 캐시** 역할로 재정의 |
| **책임 경계 재배치 (보고자 직접 검증)** | **채택** | 아누 보고 함수에 `gh pr view --json mergedAt` 검증 강제 — 옵션 D 구현 전 운영 룰로 즉시 적용 가능 (Cycle 3 DA Q3 대안 1과 결합). Postel's law 역방향 = "데이터는 거짓말한다고 가정" |
| **Merkle-style 검증 마커 (마아트)** | **보류** | HMAC 키 관리 + 시계 동기화 비용. **task-2369(가칭) 별도 P3 검토** — 옵션 D 안정화 후 보안 강화 단계로 분리 |
| **dwell + progressive disclosure (비너스)** | **채택** | `.work-done` 후 90초 dwell window. UI/알림 시스템 일관 적용 |

### Unconventional 5항목 평가 — 채택 대안

#### 책임 경계 재배치 (보고자 검증)

| 항목 | 내용 |
|---|---|
| 지지 | 옵션 D 구현 전 즉시 적용 가능. 코드 변경 < 20줄. silent corruption 즉시 차단 |
| 반론 | 운영 룰 의존 — 아누 프롬프트 변경만으로 강제력 약함. 시스템 가드 필요 |
| 시나리오 | task-2364 17:08 보고 시점에 `gh pr view` 호출 → mergedAt null → "머지 진행 중" 강등 → 회장 잘못 보고 0건 |
| 노력 | 매우 낮음 (운영 룰 + 코드 < 20줄) |
| 리스크 | 낮음 (기존 마커 시맨틱 무변경) |

#### Dwell + Progressive Disclosure (비너스)

| 항목 | 내용 |
|---|---|
| 지지 | 알림 폭증 차단 + 회장 결정 시점 명확화 |
| 반론 | dwell 윈도우 동안 사용자가 못 보는 정보 발생 (정보 지연 vs 신호 정제 트레이드오프) |
| 시나리오 | 동시 5 PR 머지 시 5분 batch 대신 90초 dwell + 단일 카드 승격 → 회장 화면 5건 폭증 차단 |
| 노력 | 중 (dashboard SSE + 알림 시스템 dwell 로직 추가) |
| 리스크 | 중 (dwell 윈도우 동안 `.merge-failed` 발생 시 즉시 노출 로직 분기 필요) |

---

## Cycle 5 — 최종 합의 + 후속 task 권장

### 최종 합의 — 옵션 D (하이브리드)

#### 합의 1 — `.done` 시맨틱 재설계 모델

**`.work-done` (declared, 작업자 의도)**
- `finish-task.sh`가 **`worktree_manager.py finish` 종료코드 검사 후** 생성 (fail-closed)
- 시스템·문서 task (PROJECT_PATH 부재)는 `.work-done` = terminal state
- 마커 내부 JSON: `{task_id, kind: "code"|"meta", project_path?, pr_url?}`

**`.merged` (observed, GitHub 사실)**
- `done-watcher` (또는 reconciler 통합 auto_merge.py)가 `gh pr view --json mergedAt` 폴링 후 atomic 생성
- 시스템·문서 task는 `.work-done` 생성 시 즉시 동시 생성 (PR 부재 분기)
- 마커 내부 JSON: `{task_id, merge_commit_sha, mergedAt, kind}`

**`.merge-failed` (실패 명시)**
- 5회 retry 초과 시 reconciler 생성 → 회장 즉시 알림
- 침묵 대신 비명 (아르고스 시나리오 3)

**state.json SoT (마아트 채택)**
- `memory/state/{task_id}.json` 단일 진실. 마커는 캐시
- 상태 enum: `WORK_PUSHED | PR_OPEN | PR_MERGING | PR_MERGED | LOCAL_MERGED | SYSTEM_DONE | MERGE_FAILED`
- Codex 5상태(`merged | kept | blocked_by_timeout | merge_failed | system_task`)와 호환

#### 합의 2 — finish-task.sh fail-open 핫픽스 P0 선행

**별도 PR로 분리** (옵션 D PR 비대화 차단, 로키 우려 해소):
1. `worktree_manager.py finish --action auto` exit code 검사 강제
2. exit ≠ 0 시 `.work-done`/`.done`/`.merge-done` 생성 차단
3. `set -e` 또는 명시적 `|| exit 1` 패턴 적용
4. 회귀 테스트: task-2364 시뮬레이션 (worktree finish 실패 → 마커 미생성 검증)

#### 합의 3 — 마이그레이션 표 (다빈치 P0/P1/P2)

| 소비자 | 현재 | 새 시맨틱 후 | 우선순위 | 호환 shim |
|---|---|---|---|---|
| `notify-completion.py` | `.done` → "완료" | `.merged` → "머지 완료" / `.work-done` → "작업 완료, 머지 대기" 분리 | **P0** | `.merged` 생성 시 `.done` symlink 6개월 |
| `session-watchdog.sh` | `.done` 세션 종료 | `.merged` 시 종료 (작업만 끝나고 머지 안 된 케이스 방지) | **P0** | symlink 호환 |
| `auto_merge.py` | `.done` 후 머지 | `.work-done` 트리거 reconcile, 성공 시 `.merged` 생성 | **P1** | reconciler 패턴 전환 |
| `whisper-compile.py` | `.done` 컴파일 | `.work-done` (머지 무관 조기 컴파일 OK) | **P2** | 무변경 |

#### 합의 4 — 작업 유형별 상태 모델 (시스템·문서 task 처리)

**task.yaml 신설 필드** (아르고스 schema validator 강제):
```yaml
kind: code | meta       # 기본값 code
merge_required: bool    # kind=meta 시 false
```

**처리 분기**:
- `kind: code` + `merge_required: true` → 표준 흐름 (`.work-done` → reconcile → `.merged`)
- `kind: meta` 또는 `merge_required: false` → `.work-done` = terminal, reconciler가 즉시 `.merged` 동시 생성 (또는 `.system-done` 별칭)

#### 합의 5 — 알림 UX (Tier 결합)

| Tier | `.work-done` 시점 | `.merged` 시점 | `.merge-failed` 시점 |
|---|---|---|---|
| 1 (자동) | **알림 억제** | 5분 batch 다이제스트 | **즉시 알림** |
| 2 (1-tap) | **즉시 알림** (회장 액션 필요) | dashboard-only 업데이트 | **즉시 알림** |
| 3 (수동) | 즉시 알림 + dwell 90초 | dashboard-only | **즉시 알림** |

**비너스 보강 — dwell 90초**: `.work-done` 후 90초 윈도우 동안 알림 보류, 같은 PR 추가 이벤트 흡수, 단일 카드 승격.

#### 합의 6 — 12-cell 호환성 회귀 테스트 (아르고스)

```python
# tests/regression/test_done_marker_consumers.py
@pytest.mark.parametrize("marker", [".work-done", ".merged", "both"])
@pytest.mark.parametrize("consumer", [
    "whisper-compile.py", "session-watchdog.sh",
    "notify-completion.py", "auto_merge.py"
])
def test_consumer_marker_compatibility(marker, consumer):
    # 기대 동작 매트릭스 (사전 명세) vs 실제 동작
    ...
```
+ `test_meta_task_terminal_state.py` (시스템 task 처리)
+ `test_merge_failure_escalation.py` (5회 retry → `.merge-failed`)

#### 합의 7 — 임시 운영 가드 (옵션 D 구현 전)

**아누 보고 함수에 `gh pr view --json mergedAt` 검증 강제**:
- 보고 전 mergedAt null 또는 `.done` mtime 이후 10분 초과 시 "머지 진행 중"으로 강등
- Argo CD `observedGeneration < generation` 동형
- **즉시 적용 가능, 코드 < 20줄**

---

### Temporal Interrogation (구현 시간대별 결정)

#### [HOUR 1] 작업 시작 첫 1시간
- [RESOLVED] 첫 변경 파일: `scripts/finish-task.sh` — `worktree_manager.py finish` exit code 검사 강제 (`set -e` 또는 `|| exit 1`)
- [RESOLVED] 첫 결정: **fail-open 핫픽스를 옵션 D PR과 분리** (로키 우려 + 다빈치 추천)
- [RESOLVED] 즉시 임시 가드 적용: 아누 보고 함수에 `gh pr view --json mergedAt` 검증 (< 20줄, 옵션 D 구현 전 silent corruption 차단)

#### [HOUR 2-3] 핵심 구현 중반
- [RESOLVED] 마커 스키마: `.work-done` JSON `{task_id, kind, project_path?, pr_url?}` / `.merged` JSON `{task_id, merge_commit_sha, mergedAt, kind}` / `.merge-failed` JSON `{task_id, retry_count, last_error}`
- [RESOLVED] state.json SoT 위치: `memory/state/{task_id}.json` (마아트 제안 + 다빈치 통합 모델)
- [RESOLVED] task.yaml schema 확장: `kind: code|meta`, `merge_required: bool` (아르고스 schema validator 강제)
- [OPEN] reconciler 폴링 주기: 15s vs 30s — task-2370(가칭) 구현 task에서 결정 (rate limit 안전 마진 vs 응답성)

#### [HOUR 4-5] 구현 후반 + 통합
- [RESOLVED] 컨트랙트 테스트 픽스처: task-2364 시나리오 재현 — 17:08 push, 17:09 PR open, 18:11 merge → 잘못 보고 0건 검증
- [RESOLVED] 12-cell 호환성 매트릭스 CI 강제 (4 소비자 × 3 마커 상태)
- [RESOLVED] 시스템·문서 task (`kind: meta`) 분기 — reconciler가 `.work-done` 생성 시 즉시 `.merged` 동시 생성
- [OPEN] 알림 시스템 dwell 90초 구현 — 비너스 제안, dashboard SSE 또는 알림 게이트웨이 위치 결정 필요

#### [HOUR 6+] 마무리
- [RESOLVED] 마이그레이션: 단일 atomic PR + `.done` symlink 6개월 호환 shim (로키 우려 + 마아트 deprecated alias)
- [RESOLVED] 문서: `docs/task-lifecycle.md` 신규 (declared vs observed 다이어그램 + Argo CD 패턴 인용)
- [RESOLVED] 배포: done-watcher 단독 선행 → 1주일 shadow mode (기존 마커와 새 판정 diff 로깅) → 보고 파이프라인 cutover (아틀라스 HOUR 6+)
- [RESOLVED] 롤백 플래그: `LEGACY_DONE_SEMANTICS=1` 환경변수 1개월 유지

---

### 검증 시나리오 결과

#### 1. 합의 5+ 도출 ✅ (7건)
1. 옵션 D 채택 (`.work-done` + `.merged` + `.merge-failed`)
2. finish-task.sh fail-open 핫픽스 P0 선행
3. 마이그레이션 표 (P0/P1/P2 + symlink shim)
4. 작업 유형별 상태 모델 (`kind: code|meta`)
5. Tier별 알림 UX + dwell 90초
6. 12-cell 호환성 회귀 테스트
7. 임시 운영 가드 (아누 mergedAt 검증)

#### 2. 로키 DA 3대 질문 + 반박 ✅
- [DA Q1] 마이그레이션 혼재 → 단일 atomic PR + 12-cell 매트릭스 CI + symlink shim
- [DA Q2] 마커 인플레이션 후회 → state.json SoT (마커는 캐시)
- [DA Q3] 시맨틱 재설계 폐기 → 대안 1(운영 룰) 임시 채택, 대안 2/3 기각, 옵션 D 구현 진행

#### 3. 아틀라스 Unconventional 1+ + 5항목 평가 ✅ (2건)
- 마커 폐기 (부분 채택, 캐시로 재정의)
- 책임 경계 재배치 (전면 채택, 임시 운영 가드)
- 비너스 dwell + progressive disclosure (채택)
- 마아트 Merkle 서명 (보류, 별도 task)

#### 4. Temporal Interrogation HOUR 1/2-3/4-5/6+ ✅ (위 4구간 모두 기록)

---

### 후속 task 권장

#### task-2367 (P1 Tiered Auto-Merge, dev7 진행 중) 영향

**결론: 블로킹 아님, 시너지 (다빈치 통합 분석)**:
- task-2367의 Tier 분류 로직에 `.work-done`/`.merged` 마커 자연스럽게 매핑
- `auto_merge.py`가 reconciler로 재설계되면 양 task 동시 진행 가능
- **단, `finish-task.sh` fail-open 핫픽스는 task-2367과 독립적으로 P0 선행**

**권장 조치**:
- task-2367 dev7 작업 일시 보류 → 본 미팅 합의 사항 리뷰 후 범위 조정
- task-2367 범위에 `.work-done`/`.merged` 마커 모델 통합 또는 별도 task 분리 결정 (회장 판단)

#### 신규 후속 task 권장 (3개)

**task-2369 (P0 핫픽스 — finish-task.sh fail-open)**:
- 단일 PR, 1팀 또는 7팀 (이참나)
- `worktree_manager.py finish` exit code 검사 + 회귀 테스트
- 옵션 D 구현 무관하게 즉시 dispatch 가능

**task-2370 (P1 옵션 D 구현)**:
- 마커 모델 + state.json SoT + reconciler 패턴 + 마이그레이션
- 1팀 + 7팀 협업 (auto_merge.py = 7팀, finish-task.sh = 7팀, dashboard = 1팀)
- task-2369 머지 후 dispatch

**task-2371 (P2 옵션 D 안정화 + Merkle 서명)**:
- 1주일 shadow mode 운영 후 cutover
- Merkle HMAC 서명 (마아트 보류 안건) 도입 검토
- 임시 운영 가드(아누 mergedAt 검증) 제거 시점

---

## 미팅 종료

**진행 시간**: 2026-05-02 18:24 ~ 18:33 (약 9분)
**결과**: 옵션 D 채택, 후속 task 3개 권장 (task-2369/2370/2371)
**회장 승인 게이트**: 본 미팅 합의안 + 후속 task 초안 보고 후 회장 명시 승인 필요. 승인 없이 구현 dispatch 금지.

**미팅 파일**: `memory/meetings/2026-05-02-done-semantics-redesign.md` (본 파일)
**후속 task 초안**: `memory/tasks/dispatch-done-semantics-impl-DRAFT.md`
**보고서**: `memory/reports/task-2368.md`
