Files
multi-agent-mux/docs/contracts/issue-5/task.md
T

136 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 📑 Issue #5 Task Checklist & Verification Evidence
- **Document Version**: Rev.8 (Phase 3 실행 완료 — P3-01~P3-03 증거 기록)
- **Issue**: [Gitea Issue #5](https://git.godopu.com/tmpl/multi-agent-mux/issues/5)
- **Status**: Phase 0 Complete / **Phase 1 Complete (v4.3.0)** / **Phase 2a Complete (shadow-only)** / **Phase 2b Complete (default-off)** / **Phase 3 Complete (thin wrapper)** / Phase 4 Staged
---
## Phase 0: 사전 계약 기준선 및 Fixture 수집 (이번 실행 범위)
- [x] **P0-01** 기준 commit, dirty diff, Herdr/Python 버전, pytest collection 수 기록.
- *증거*: Commit `47640e2`, Herdr `0.8.2`, Python `3.9.6`, Pytest `469 tests collected initially` ➔ `510 tests collected with Phase 0 suite` (+41 contract & mutation tests).
- [x] **P0-02** `docs/contracts/issue-5/baseline.md` 작성: 공개 CLI/default/invalid input/stdout-stderr/exit/interpreter/path/signal 계약과 소스·기존 테스트 매핑.
- *증거*: `docs/contracts/issue-5/baseline.md` §2 (`--all-reviewer` 우선순위 및 L192–196 소스 매핑 반영).
- [x] **P0-03** event schema/HMAC/seq/retain/audit/디스크 fallback 및 publisher 실패 후 로컬 commit 동작 기록.
- *증거*: `docs/contracts/issue-5/baseline.md` §3 (감사 로그 경로 `.mam/delegate_job_logs/<job_id>/` 정확히 반영).
- [x] **P0-04** event와 registry status 분리; permission clearance·cancelled subscriber 차이·pick_pending 등 writer inventory/gap 기록.
- *증거*: `docs/contracts/issue-5/baseline.md` §3, `job_subscriber.py:46, 80` vs `publish_event.py:49` 간극 명시.
- [x] **P0-05** report strictness/promotion/cleanup 및 job/session/loop lock 획득·해제/ownership 계약 기록.
- *증거*: `docs/contracts/issue-5/baseline.md` §4, §5.
- [x] **P0-06** `docs/contracts/issue-5/state-transitions.md` 작성: 4중 귀속, dispatch anchor, target CAS 표와 duplicate/conflict/deadline 정책.
- *증거*: `docs/contracts/issue-5/state-transitions.md` §2, §3.
- [x] **P0-07** writing/stable_candidate/finalized 및 manifest/hash/부수효과 확정 계약 기록; debounce만으로 completed 금지.
- *증거*: `docs/contracts/issue-5/state-transitions.md` §4.
- [x] **P0-08** Herdr native wait version/help/spec 및 단일 결과 capture 수집. timeout/unknown target/transport failure와 unknown 상태를 분리하고 외부 collector의 before/after 참조를 검증.
- *증거*: `tests/fixtures/issue_5/herdr/wait-contract.json`, `docs/contracts/issue-5/herdr-runtime.md` §1 (timeout stderr 채널 반영).
- [x] **P0-09** claude native 상태/call-outcome 행렬·실측 provenance·미관측 gap 기록.
- *증거*: `tests/fixtures/issue_5/herdr/claude/idle.json`, `herdr/manifest.json`.
- [x] **P0-10** agy native 상태/call-outcome 행렬·실측 provenance·미관측 gap 기록.
- *증거*: `tests/fixtures/issue_5/herdr/agy/working.json`, `tests/fixtures/issue_5/herdr/agy/wait_timeout.json`, `herdr/manifest.json`.
- [x] **P0-11** hermes native 상태/call-outcome 행렬·실측 provenance·미관측 gap 기록.
- *증거*: `herdr/manifest.json` (미가동 세션 gap으로 정직하게 기록).
- [x] **P0-12** grok native 상태/call-outcome 행렬·실측 provenance·미관측 gap 기록.
- *증거*: `tests/fixtures/issue_5/herdr/grok/idle.json`, `herdr/manifest.json`.
- [x] **P0-13** opencode native 상태/call-outcome 행렬·실측 provenance·미관측 gap 기록.
- *증거*: `herdr/manifest.json` (미가동 세션 gap으로 정직하게 기록).
- [x] **P0-14** codex native 상태/call-outcome 행렬·실측 provenance·미관측 gap 기록.
- *증거*: `tests/fixtures/issue_5/herdr/codex/done.json`, `herdr/manifest.json`.
- [x] **P0-15** `herdr/manifest.json`과 `watcher/manifest.json` 분리. native observed 캡처만 저장; watcher timeline source별 observed/simulated, 전체 mixed 여부, identity association과 redaction 검증.
- *증거*: `tests/fixtures/issue_5/herdr/manifest.json`, `tests/fixtures/issue_5/watcher/manifest.json`.
- [x] **P0-16** 두 계층 schema/reference/coverage 테스트 추가: native payload에 job/attempt/report phase 주입 거부, 오류와 상태 분리, simulated를 observed로 표기 거부. 운영 session 쓰기 금지.
- *증거*: `tests/test_issue5_phase0_contracts.py`.
- *Rev.5 보강 (Codex [P1] 대응)*: `source_kind` 명시적 분기(`SUPPORTED_SOURCE_KINDS`), 관측 증거 스키마 미구현 kind(event/filesystem/harness)의 `observed` 표기 fail-closed 거부, Herdr 항목의 필수 필드·전 필드 대응·세션 UUID/pane/backend 정체성 대응, `capture_ref` 증거 루트 격리, 1캡처=1관측, 매니페스트↔파일 정합성 검증. 계약 명세는 `herdr-runtime.md` §3-1.
- [x] **P0-16a** watcher 복합 시나리오 7종 작성: initial idle, tool active, report pause, finalized candidate, blocked, disconnect, generation restart. source별 증거/가상 시계/expected policy를 구분.
- *증거*: `tests/fixtures/issue_5/watcher/*.json` (7개 시나리오 완료).
- [x] **P0-16b** `herdr-runtime.md`에 native API·단일 wait·외부 collector·file/event/dispatch source 경계를 명시.
- *증거*: `docs/contracts/issue-5/herdr-runtime.md`.
- [x] **P0-17** Phase 1–4 `implementation_plan.md`/`task.md` 작성, live-helper version/공통 CAS/notification 복구 결정 기록.
- *증거*: `docs/contracts/issue-5/implementation_plan.md`, `docs/contracts/issue-5/task.md`.
- [x] **P0-18** 관련 CLI/lock/rebuttal/adapter 테스트와 전체 suite 실행; 수집·실행·통과·실패 숫자 분리.
- *증거 (Rev.3 당시)*: 전체 484개 수집, 선행 전체 실행 481개 통과(0 failed, 0 skipped, 786.18s), 15개 계약/변이 테스트 전체 통과, 집중 코어 회귀 155개 통과(60.48s).
- *증거 (Rev.5, job `fb7fadd4`)*: 전체 suite 실행 **499 passed, 0 failed, 0 skipped (848.90s)** — 커밋 `19d798b` 기준선(계약 테스트 30개 포함)에서 실행. Rev.5 보강 후 계약 테스트 파일 단독 재실행 **41 passed** (`+11`), 수집 총계 **510** (`--collect-only`). Rev.5 변경은 `tests/test_issue5_phase0_contracts.py` 및 `docs/`에 국한되어 나머지 469개 테스트에 영향 없음.
- [x] **P0-19** 문서 링크/JSON/git diff --check/production 코드 무변경 확인.
- *증거*: `git diff --check` 클린, 공백 린트 완료, 프로덕션 `.sh`/`.py` 무변경 (오직 `docs/`, `tests/` 변경).
- [x] **P0-20** 결과 보고: Phase 0 산출물 완료 여부, backend별 native live gap·mixed/simulated scenario 현황, 남은 gate를 별도 명시하고 peer review 요청.
- *증거*: `.mam/jobs/61f2fa87/agy-reports/report-final.md` (Rev.3 최초 보고), `.mam/jobs/f29cb24e/claude-code-reports/report-final.md` (Codex [P1]·Claude [Finding 2] 정정, 커밋 `19d798b`), `.mam/jobs/fb7fadd4/claude-reports/report-final.md` (Rev.5 자체 재리뷰 및 보강).
---
## Phase 1: `lib_py/delegation/` 구축 (완료, v4.3.0)
- [x] **P1-00** 이동 전 특성화 테스트 선행. 위임 셸 헬퍼 3종의 기존 직접 커버리지는 0건이었다.
- *증거*: `tests/test_issue5_phase1_delegation.py` C-01~C-09 (`MAM_DELEGATION_PY` 0/1 양쪽 parametrize), CLI 계약 스냅샷, 자동완료 3표면 불변 가드. 커밋 `265a1f6`.
- [x] **P1-01** delegation 스크립트 4종을 `lib_py/delegation/`으로 `git mv` 하고 `scripts/*.py`는 패키지 바인딩 shim으로 보존. 저장소 통합 없음, non-fatal 계약 보존.
- *증거*: 커밋 `fb3498e`. PV-1 정체성+출처, PV-4 10개 시나리오(A/A_pe/B/B2/C1/C1_pe/C2/C2_pe/D/E) + K1/K3/K6 서브프로세스 매트릭스, PV-5 shim 바이트 동일성, AST 기반 형제 임포트 금지 검사, `--help` 이동 전 캡처와 무차이.
- *설계 근거*: `creator-claude-01`의 이의제기(job `c0b9c987`)로 `sys.path.insert(0)` 방식이 pytest에서 `lib_py.agents`까지 샌드박스 사본으로 가로채는 것이 실증되어, 패키지 단위 bind-once로 확정.
- [x] **P1-02** `DelegationService`/`cli.py`/`daemon.py` 구현 및 `lib.sh` 헬퍼 교체. daemon PID·중복·수명 계약 일치.
- *증거*: 커밋 `78cb9ec`. C-01~C-09가 레거시·파이썬 두 본체에서 통과, daemon 부모 종료 후 생존 및 `pgrep` 중복 검출, cli가 레거시 실패 문구를 정확히 재현, 발행 실패 시맨틱(status 동기화·seq 소비·`published: false`)이 shim 경로와 cli 경로에서 동일.
- [x] **P1-03** 장수 MQTT 연결 프로토타입 및 벤치마크. HMAC/seq/retain/디스크 폴백 회귀 유지, 자동완료 비활성 유지.
- *증거*: 커밋 `a4b7b45` + 자체 리뷰 수정 `f5286a0`(job `5e3c7660`에서 발견한 `PersistentPublisher` CONNACK 상태 공유 결함 수정 및 회귀 3종 추가). `publish_event.main`을 `prepare_event`/`record_outcome`/`main`으로 분리(동작 불변, G-1~G-4 통과). 가짜 전송에서 OneShot N connect vs Persistent 1 connect, 두 전송의 레지스트리·감사 레코드 필드 단위 동일, PUBACK 미확인 시 재시도 후 `published=false`, 브로커 상이 시 거부. 네트워크 접촉 0.
- [x] **P1-04** 벤치마크 실측 및 문서 동기화, 롤백 드릴.
- *증거*: `docs/contracts/issue-5/phase1-benchmark.md`. 가짜 전송 p50 54.813ms → 0.002ms(연결 50회 → 1회), 실브로커 p50 1892.728ms → 275.992ms(정보성). `MAM_DELEGATION_PY=0` 롤백 드릴 및 K2(freeze 사본 + 라이브 `PYTHONPATH`) 실증 완료.
---
## Phase 2a: `lib_py/loop/` 코어 & Shadow Watcher (완료, shadow-only)
- [x] **P2A-00** 이동 전 writer 특성화 선행 (X-01~X-04, `MAM_ENGINE_CAS` 0/1 parametrize).
- *증거*: 커밋 `9389d7e`. X-02가 계획서의 초기 가정을 정정한다 — `pick_pending`은 락 안에서 `pending`을 필터하므로 **이미 올바른 CAS**이며, 문제는 정확성이 아니라 **중복**이다.
- [x] **P2A-01** 단일 전이 경계 구현 및 writer 2종 라우팅.
- *증거*: 커밋 `2532e78`. `engine.transition`이 유일한 상태 writer. `state-transitions.md` §3 표 전 항목(claim/비terminal/explicit terminal/멱등 재수신/상충 거부+감사/stale attempt/deadline) 테스트. `MAM_ENGINE_CAS=0` 레거시 본체 보존.
- *계획 대비 구조 정정*: 계획서는 `engine.py`를 `lib_py/loop/`에 두었으나, 그러면 `lib_py.delegation`이 **형제 패키지를 임포트**하게 되어 freeze 하에서 트리가 섞인다(Phase 1이 명문화한 규칙). Phase 1의 기존 가드 테스트가 이를 즉시 검출했고, 엔진을 레지스트리 writer들이 있는 `lib_py/delegation/`으로 옮겼다.
- *락 규율*: 락은 판정 + 레코드 1회 쓰기만 덮고, 감사 mirror는 큐잉 후 락 해제 뒤 flush한다. 순서는 `transition_seq`로 복원한다. 락 보유 중 `subprocess`/`socket`/`sleep` 호출 0건을 테스트로 감시한다.
- [x] **P2A-02** watcher·귀속·dispatch 증거·재연결 백오프.
- *증거*: 커밋 `b49af56`. `--timeout`은 **밀리초**(파라미터명 `timeout_ms`), `--until` 항상 명시(생략 시 `working` 누락), exit 1은 **stderr**에서 파싱. 백오프 1→2→4→8→16s 상한, 실패 시 캐시 스냅샷 폐기. 귀속 증거는 **레지스트리가 아닌 shadow 전용 저장소**(`.mam/shadow/`)에 둔다 — 레코드에 3개 필드가 전부 없고 Phase 1이 스키마를 동결했기 때문.
- [x] **P2A-03** shadow-only가 terminal을 쓰지 않음을 검증.
- *증거*: 커밋 `964abc6`. `ShadowRunner`는 engine 참조를 **갖지 않는다**(구조적 차단, AST 단정). 측정: 전체 시나리오 실행 전후 **레지스트리 디렉터리 전 파일 SHA-256 동일**.
- [x] **P2A-05** 교차 리뷰(`68abd0ff` Claude / `cae12436` Codex) 지적 5건 전건 수용·수정.
- *증거*: 커밋 `56d08ef`. F-A(래퍼 loop/discuss 전이 2건 누락 → 운영자 권한 요청 `redispatch`/`finalize` 신설 + CLI 거부 시 non-zero), F-B(감사 mirror 순서 회귀 → `transition_seq` 비교), R1(관측 식별자 미대조 → `collect_observed_identity` 전량 대조 + 매니페스트 attempt 검증), R2(`expected_attempt`가 레코드에 없으면 무시 → fail-closed), R3(raw `status` 필드 우회 → 요청만이 status를 설정). 신규 회귀 11종 전부 수정 전 코드에서 실패함을 역검증.
- [x] **P2A-06** 교차 리뷰 Round 2(`cb792e91` Claude / `0026165b` Codex) 지적 4건 전건 수용·수정.
- *증거*: 커밋 `cb575fa`. F-C(멱등 ACK를 거부로 분류 → 래퍼 성공 경로가 `set -e`로 중단; 멱등은 rc 0, 진짜 거부만 rc 4), F-D(`VALID_STATUSES` 검증 소실 → 두 모드 공통 rc 1·레코드 불변), R1(증거 부재 시에도 승인 → 4식별자와 매니페스트 attempt **필수**, 식별자는 네이티브 payload가 아닌 `collector_attribution` 봉투에서 수집), R4(비원자적 비교-후-쓰기 → per-job 감사 락 + 고유 임시 파일). 신규 회귀 8종 전부 수정 전 코드에서 실패함을 역검증.
- [x] **P2A-04** race/attempt 재사용/부분 report/도구 실행/blocked/unknown/재시작 시나리오.
- *증거*: 신규 5종(`race_double_dispatch`, `attempt_reuse`, `partial_report`, `unknown_status`, `restart_midflight`)을 Phase 0 스키마로 작성해 **Phase 0의 `validate_watcher_scenario`를 통과**시켰고, 기존 7종과 합쳐 **12종 전부 `expected_policy.decision`과 일치**함을 단정한다.
---
## Phase 2b: 이중 감지 자동완료 활성화 (완료, 기본 비활성)
- [x] **P2B-00** 자동완료 도입 전 fail-closed 선행 조건 특성화 (X-01~X-05).
- *증거*: 커밋 `9a827b3`. 매니페스트 없는 job이 이미 `hold`임을 고정 — 미지원 경로 보존이 새 분기 없이 성립하는 근거.
- [x] **P2B-01** 리포트 확정 계약(매니페스트·SHA-256) 및 부수효과 증거 프로토콜.
- *증거*: 커밋 `3ea5757`. `lib_py/delegation/finalize.py` + `publish_event --finalize-report/--side-effect`. **선언은 에이전트가, 해시 재계산은 읽는 쪽이** — 워처가 만든 매니페스트는 자기 증명이므로 채택하지 않았다. 리포트 재작성 시 즉시 무효, 선언한 부수효과는 전부 증거 필요.
- [x] **P2B-02** terminal + pending notification, 재전송·재시작·늦은 conflict.
- *증거*: 커밋 `803ba43`. `pending_notification`을 상태와 **같은 원자적 쓰기**로 커밋, 락 밖 발행, `notification_settled`(상태 무변경 bookkeeping 요청 — terminal에서도 허용)로 정리, 기동 시 재발행. 발행 실패 시 intent 보존.
- [x] **P2B-03** 검증된 backend/job 한정 default-off 플래그.
- *증거*: 커밋 `803ba43`. 3중 게이트(전역 OFF 기본 / 관측 증거 기반 허용목록 `claude,grok,codex` / 잡별 opt-in). 허용목록은 좁히기만 가능. 자동완료 terminal에 `completed_by` 표식.
- [x] **P2B-05** 교차 리뷰 3인(`3fa76e08` Claude / `a0de0e5e` Grok / `e5f26823` Codex) 차단 지적 7건 전건 수용·수정.
- *증거*: 커밋 `cb7ed1a`. 필수 매니페스트 검증(`report_dir` 생략 = 거부), 증거의 대상 일치(job/attempt/session/pane), Reviewer 판정 토큰 게이트(Phase 0 안전 계약), bookkeeping 필드 제한, 조건부 settle + intent 신원 전달, 부수효과 evidence 스키마 검증, `MAM_ENGINE_CAS=0` 준수, 백엔드 정확 일치, 절대 경로. 신규 회귀 21종 전부 수정 전 코드에서 실패함을 역검증.
- *배선 현황*: `evaluate`/`recover`의 **프로덕션 호출자는 아직 없다**(Phase 3 배선). 운영 노트 §2-1에 정정 기록.
- [x] **P2B-06** 교차 리뷰 Round 2(`a45e5b7f` Codex) 지적 2건 수용·수정.
- *증거*: 커밋 `01b465f`. R2(귀속이 커밋과 원자적이지 않음 → `dispatch_token`을 레코드에 도입, `claim`/`redispatch`에서 발급, `expected_dispatch_token`으로 락 안에서 대조), R4(intent 신원을 발행만 하고 소비자가 무시 → `job_subscriber`가 안정 신원으로 중복 제거). 신규 회귀 7종 전부 수정 전 코드에서 실패함을 역검증.
- *이전 판단 정정*: "시도 보증이 증거 계층에 있으므로 레코드 스키마 변경 불필요"는 **대조**에는 맞지만 **원자성**에는 틀렸다. 추가 필드이므로 `SCHEMA_VERSION`은 1 유지.
- [x] **P2B-07** 교차 리뷰 Round 3(Codex) 지적 1건 + 그 과정에서 드러난 인접 결함 1건 수용·수정.
- *증거*: `job_subscriber._Watcher.on_message`의 `seen_intents` 기록이 단조 seq 가드보다 **앞서** 실행되어, 늦게 도착한 과거 패킷이 자기 intent를 "이미 처리함"으로 태우고 **뒤따르는 정당한 재시도가 드롭**됐다(`last_seq=10`, seq=9 거부 후 동일 intent의 seq=11 → `qsize()==0`). 신원 **대조**는 seq 가드 앞에, 신원 **기록**은 seq 가드 뒤에 두어 "본 적 있다"가 "받아들였다"를 뜻하도록 고쳤다. 함께: 해시 불가능·비객체 intent가 `TypeError`로 콜백을 빠져나가 **그 구독자의 모든 job 수신을 끊을 수 있던** 경로를 드롭+경고로 닫았다. 신규 회귀 6종(그중 3종은 수정 전 코드에서 실패함을 역검증, 3종은 보존·커버리지 가드) + 발행→소비 실경로 종단 테스트.
- [x] **P2B-04** 부수효과 예외·무판정 fail-closed·경쟁/재시작 시나리오.
- *증거*: 신규 시나리오 3종(`side_effect_unproven`, `no_verdict_fail_closed`, `notification_crash_window`)을 Phase 0 스키마로 추가, **총 15종 전부** `expected_policy.decision` 일치.
- *계획 대비 이탈(이후 정정됨)*: 처음에는 계획서 §D2의 `attempt_id` 레코드 승격이 불필요하다고 판단했으나, **P2B-06에서 이 판단의 절반을 철회했다.** 증거를 dispatch와 *대조*하는 데에는 증거 계층으로 충분하지만 커밋과의 *원자성*에는 부족하다. 최종적으로 승격한 것은 `attempt_id`가 아니라 **불투명한 `dispatch_token`**이다(`iteration`은 루프 회차라는 다른 뜻을 이미 갖고 있다). 레코드 스키마는 필드 추가만이며 `SCHEMA_VERSION`은 1 유지. 상세는 `phase2b-autocomplete.md` §9(부분 철회 표시).
---
## Phase 3: `run_loop.sh` Thin Wrapper 전환 및 전면 회귀 (완료)
- [x] **P3-01** `parser.py` (Strict Parser: 코드 펜스 무시, fail-closed) 및 `runner.py` 오케스트레이션 로직 이식 (`tests/test_issue5_phase3_loop.py`).
- *증거*: `tests/test_issue5_phase3_loop.py` 12개 테스트 100% 통과 (0.29s). 코드 펜스(` ``` `, `~~~`) 내부 허위 판정/태그 무시, 마지막 비공백 행 엄격 검사, Rebuttal/Adjudication/Arbitration 흐름, Plan/Report 원자적 승격 및 cleanup 완료.
- [x] **P3-02** `run_loop.sh` Thin Wrapper 전환 및 런타임 호환 검증.
- *증거*: `run_loop.sh`에 `MAM_LOOP_PY=1` 기본값 위임 및 `MAM_LOOP_PY=0` 레거시 롤백 경로 탑재. `--help` exit 1 계약 유지. B-13 freeze 하 인터프리터 앵커링(O-4 인계 사항: `AGENT_PYTHON_BIN` 사전 export) 해결. 기존 테스트 텍스트 앵커(`test_o1_rebuttal.py`, `test_deploy_freshness.py`, `test_b7_diff_untracked.py`, `test_o3_scoped_guard.py`, `test_tier4_e2e.py` Scenario 5 E2E 루프 포함) 100% 0-Fail 통과.
- [x] **P3-03** 전면 회귀(744개 테스트 0-Fail, 816.30s), 체크포인트(`.mam/loop-checkpoint.json`) 원자적 기록 및 핸드오프/시그널 정리 검증.
- *증거*: 전체 744개 테스트 무결점 통과 (`744 passed in 816.30s`). `checkpoint.save_checkpoint`/`load_checkpoint` 원자적 파일 교체 및 `SIGINT`/`SIGTERM` 핸들러의 안전 락 해제(`release_guard`) 실증.
---
## Phase 4: 불변 런타임 검증 및 Freeze 제거 (후속)
- [ ] **P4-01** eager import+child/helper/template 실행 버전 정책 구현/검증.
- [ ] **P4-02** 실행 중 코드 교체와 늦은 재심/승격/rollback 스트레스 검증.
- [ ] **P4-03** gate 통과 후에만 Freeze 제거 및 운영 문서 갱신.