# G3 stale fail marker hygiene — 착수 packet (코드 수정 전 검토용)

상태명: `G3_STALE_FAIL_MARKER_HYGIENE_KICKOFF_PACKET_ACTIVE_FALSE`
작성: ANU 직접 (2026-07-05 KST). **착수 packet only — 코드 수정 0 · PR 0 · merge 0 · dispatch 0.** 근거: GPT 판정(메타인프라 마지막 hygiene closeout으로 G3 stale marker 1건만 bounded·착수 packet부터·아직 코드 수정 금지). 관측: [[project-pr266-task2785-observability-diagnostics-merged-260705]] dev2 봇 finish-task 중 실측.

## 1. 현상 (task-2785에서 실측)
dev2 봇 finish-task 중 — G3가 첫 실행에서 보고서 형식(SCQA 헤더 정규식 불일치·검증표 부재)으로 **FAIL** → g3-fail 마커 생성. 봇이 보고서를 고쳐 **G3 재검증 PASS**. 그러나 finish-task가 `.done` 발행 단계에서 **이전 stale fail 마커를 보고 차단** → 봇이 수동으로 마커 제거(`rm task-2785.g3-fail` + supervisor-crash-marker.json) 후 finish-task 재실행(멱등)으로 완료. **매번 사람이 stale 마커를 지워야 하는 자동화 신뢰성 갭.**

## 2. 근본 원인 (코드 실측 — canonical main cedea4be)
**두 개의 fail 마커 writer가 있고, PASS 시 정리하는 코드가 없다:**
- **`.g3-fail`** ← `scripts/g3_independent_verifier.py:397 write_fail_file()`(라인 402), FAIL 시 `{task_id}.g3-fail` 작성. `main()`의 fail 분기(586·616)에서 호출.
- **`.g3-failed`** ← `scripts/finish-task.sh:1519`, G3 gate FAIL(`G3_EXIT != 0`) 시 `{TASK_ID}.g3-failed` 작성 후 `exit 1`.
- **G3 PASS 분기**(finish-task.sh:1517 "[G3-GATE] PASS")는 **이전 stale fail 마커를 정리하지 않음**.
- **차단 지점**: finish-task.sh:1806이 `lifecycle_guards.check_g3_fail_blocks_done($TASK_ID)` 호출 → `find_g3_fail_markers`(4변종 `g3-fail`/`g3-failed`/`g3_fail`/`g3_failed` 인식)가 stale 마커를 찾으면 `ok=False` → `.done` 차단.
- ★ `check_g3_fail_blocks_done`은 **마커 존재만 검사**(라인 152~170) — 마커 timestamp를 현재 G3 결과와 **비교하지 않음**. 그래서 이전 FAIL의 stale 마커가 현재 PASS를 무효화한다.
- `lifecycle_guards.py`에 **clear/정리 함수 없음**(grep 0).

## 3. 수정 방향 (clear-on-PASS · 실패 숨김 금지)
★ **원칙(GPT): 실패를 숨기는 방향 금지 — 진짜 현재 G3 FAIL은 계속 `.done` 차단해야 한다.**
- **권고안 = clear-on-PASS**: G3가 **현재 PASS일 때만** stale fail 마커(4변종 전부)를 정리.
  - (a) `g3_independent_verifier.py`: PASS 결정 경로에서 자기 `.g3-fail` 마커 제거(producer가 자기 마커 lifecycle 소유).
  - (b) `finish-task.sh` G3 PASS 분기(1517, `G3_EXIT=0` 확인 직후): 모든 변종 stale 마커 정리(자신이 쓴 `.g3-failed` + belt-and-suspenders). 정리는 `lifecycle_guards`의 신규 `clear_g3_fail_markers(task_id)`(마커명 단일소스) 통해.
- **안전성(구조적 보장)**: 정리는 **현재 G3_EXIT=0(PASS) 확인 이후에만** 실행. 현재 FAIL이면 verifier가 `.g3-fail` 쓰고 nonzero 반환 → finish-task 1519가 `.g3-failed` 쓰고 `exit 1` → `.done` 미도달 → **여전히 차단**. 즉 진짜 실패는 보존.
- **timestamp/run-id 필요성 검토**: clear-on-PASS는 "현재 run 결과가 authoritative"라 **timestamp 비교 불필요**(현재 PASS일 때만 정리하므로 stale-only 정리가 자연 보장). 단 감사성 위해 마커에 run-id 기록은 **선택적 보강**(필수 아님). → 1차는 clear-on-PASS, timestamp 게이트는 미채택 권고.

## 4. expected_files 후보 (실측 결과 — GPT "finish-task + G3 verifier + regression test"에 마커명 소유자 추가)
- `scripts/g3_independent_verifier.py` (PASS 시 자기 `.g3-fail` 제거)
- `scripts/finish-task.sh` (G3 PASS 분기에서 stale 마커 정리 호출)
- `scripts/lifecycle_guards.py` (마커명 단일소스 — 신규 `clear_g3_fail_markers` helper)
- `tests/regression/test_g3_stale_fail_marker_hygiene_<id>.py` (신규 회귀)
- ★ 이 4개 밖(terminal_state_callback / merge-executor / .github / ruleset 등) 수정 필요해지면 **STOP_REPORT**. (lifecycle_guards 제외하고 3파일로 줄이려면 clear를 finish-task/verifier에 인라인 가능 — 단 마커명 중복 → lifecycle_guards helper 권고.)

## 5. ★ 불변 / 안전게이트 (변경 금지)
- **진짜 현재 G3 FAIL → `.done` 계속 차단**(안전게이트 약화 0).
- terminal artifact(.done/.done.escalated) · result.json envelope · callback contract(owner-pickup·self-key 0) **무변경**(PR#264 축 무접촉).
- G3 verifier의 실제 판정 로직(PASS/FAIL 기준) 무변경 — 마커 lifecycle(정리)만 추가.
- `check_g3_fail_blocks_done`의 차단 의미 무변경(stale 마커가 없어지면 자연히 통과).

## 6. 테스트 계획 (신규 회귀 — mock/tmp 격리)
1. 첫 G3 FAIL → `.g3-fail`(verifier) / `.g3-failed`(finish-task) 마커 생성 확인.
2. 보고서 수정/재검증 **PASS** → stale fail 마커(4변종) 정리 확인 + `check_g3_fail_blocks_done` ok=True → `.done` 발행 허용.
3. **현재 G3 FAIL** → 여전히 `.done` 차단(안전 보존) 확인.
4. task-2785 유사 흐름 재현(FAIL→마커→PASS→정리→.done).
5. 기존 finish-task / terminal artifact(test_finish_task_terminal_termination_2782) / callback artifact 회귀 보존.
6. clear-on-PASS가 **다른 task의 마커를 지우지 않음**(task_id 격리) 확인.

## 7. STOP_REPORT 조건
- 진짜 현재 G3 FAIL을 통과시키는 방향 필요 · 안전게이트 약화 필요 · terminal artifact/result.json/callback contract 변경 필요 · expected_files 4개 밖 수정 필요 · `.github`/ruleset/Merge Queue 요구 · G3 판정 로직 변경 필요.

## 8. 산출물 & 다음 (승인 후)
- 본 착수 packet(코드 0). 승인 시 → **bounded task dispatch(ANU 코딩 0·dev팀 위임)** → 구현+회귀 → ANU 독립검증(4파일 갇힘·회귀 보존·현재 FAIL 여전히 차단·PASS 시 정리) → PR 후보 packet(현재 main 기준 stale 확인) → 회장 승인 후 PR → merge → **메타인프라 closeout → 사업/ANU-Work 복귀**.
- ★ 이후 Stage2 shadow / Merge Queue activation / required check로 자동 진행 **금지**. G3 hygiene가 **메타인프라 마지막 closeout**.

## 결론 (회장 결정 요청)
1. 본 G3 hygiene 착수 packet 수용 여부.
2. 수정 방향 = **clear-on-PASS(권고)** 승인 여부(timestamp 게이트 미채택).
3. expected_files 4개(verifier·finish-task·lifecycle_guards·신규 test) 승인 여부(또는 3개로 인라인).
4. 승인 시 dev팀 dispatch(ANU 코딩 0)로 진행할지.
