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

105 lines
8.1 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 #6 Task Checklist & Verification Evidence
- **Document Version**: Rev.2 (Planner `planner-reviewer-claude-01`, job `f4873d82` — Creator 이의제기 3건 반영)
- **Issue**: [Gitea Issue #6](https://git.godopu.com/tmpl/multi-agent-mux/issues/6)
- **Plan**: `docs/contracts/issue-6/implementation_plan.md` (Rev.2)
- **Baseline**: `f98b958` (v4.4.0), 750 passed
- **Status**: Phase 1 대기
> 각 항목은 완료 시 `[x]`로 바꾸고 바로 아래 `*증거*:` 줄에 커밋 해시·테스트 ID·실측 수치를 기록한다(Issue #5 관례). 신규 회귀 테스트는 **수정 전 코드에서 실패함을 역검증**한 뒤 통과 증거를 남긴다.
---
## Phase 1: 레지스트리 CAS 표준 연동 및 delegate-job Fail-Closed
- [ ] **P1-01** `registry.py close --job <id> --request {deadline_timeout,cancelled} [--detail] [--expect-dispatch-token]` 서브커맨드 추가 (`engine.transition(..., request, source="delegate_wrapper")`). rc: 커밋/멱등/terminal 거부 0, 레코드 없음 1, 토큰 불일치 4.
- *증거*:
- [ ] **P1-02** 래퍼에 `reap_subscriber`, `_disk_status`, `_map_sub_rc`(기존 `:340-354` 리터럴 보존), `_rc_for`, `finalize_unfinished` 헬퍼 추가. phase `preflight|idle_wait`는 `cancelled`/`session_busy`(rc 5), 그 외는 `deadline_timeout`. `MAM_DELEGATE_FAIL_CLOSED=0` 롤백 분기 포함.
- *증거*:
- [ ] **P1-03** direct 경로 `:227` `|| true` 제거 → `sub_rc` 매핑 → `finalize_unfinished` → 종료 코드 0/1/2/3/5. 마지막 stdout 줄(감사 경로) 유지.
- *증거*:
- [ ] **P1-04** loop/discuss 워커(`:359`)·리뷰어(`:375`) `break` 직전 `finalize_unfinished` 호출. **loop 경로에서 `publish_event --event error` 발행 금지**(O-1).
- *증거*:
- [ ] **P1-05** `run_agent` 실패 분기 명시화(`if ! run_agent`): `reap_subscriber` + `finalize_unfinished … inject` + `exit 1`. trap(`:523`)에 `--registry-dir "$REGISTRY_DIR"` 추가.
- *증거*:
- [ ] **P1-06** rc=3 처리: 남은 데드라인 동안 3s 간격 디스크 재관측, terminal 발견 시 채택, 아니면 `deadline_timeout`(rc=3).
- *증거*:
- [ ] **P1-07** dry-run direct에서 구독자 미기동 (현재 `:166` 기동 후 `:224` `return 0`).
- *증거*:
- [ ] **P1-08** 결정적 재현 4종(T1-1, T1-2, T1-4, T1-7)이 수정 전 실패·수정 후 통과. `test_wrapper_exit_code_mapping_literals_are_frozen` 통과.
- *증거*:
- [ ] **P1-09** 롤백 드릴: `MAM_DELEGATE_FAIL_CLOSED=0`에서 T1-8 재현(rc=0, `pending`).
- *증거*:
- [ ] **P1-10** (Rev.2 Tertiary) `attempt_id` 규약: `registry.py update --attempt-id`, `engine._decide` redispatch가 `attempt_id` 공급 시 이를 전진 조건으로 사용(미공급 시 기존 iteration 규칙), `redispatch`/`claim` 커밋 시 레코드 기록, `publish_event --finalize-report` 기본 attempt_id가 `record.attempt_id` 우선.
- *증거*:
- [ ] **P1-11** 래퍼 loop 경로: phase 디스패치마다 `attempt` 증가 후 `update … --attempt-id "$attempt"`. T1-10(수정 전 rc=4 역검증)/T1-11/T1-12, F-A 3종 무변경 통과.
- *증거*:
- [ ] **P1-12** T1-13 `close --request cancelled` 전이 규칙 고정.
- *증거*:
---
## Phase 2: 사전 TUI 유휴 핸드셰이크 및 제출 검증 보강
- [ ] **P2-01** `lib_py/loop/watcher.py`에 `main()`/`__main__` 추가: `wait <target> --session S --until … --timeout-ms N`, JSON 1줄 stdout, rc matched 0 / timeout 2 / agent_not_found 3 / transport_error 4. `build_argv(..., session=None)`가 `default`가 아닌 세션이면 `herdr --session S agent wait …`로 구성(Rev.2 Primary-A). `lib_py.delegation`→`lib_py.loop` 임포트 0건 유지(`test_delegation_package_imports_no_sibling_lib_py_modules`).
- *증거*:
- [ ] **P2-02** `lib.sh: wait_for_agent_idle`: `SKS_IDLE_HANDSHAKE`, 사전 `_sks_herdr agent get`(`unknown`→3, `blocked`→2, `idle|done`→0), `working`→`"$(_delegate_py_bin)" -m lib_py.loop.watcher wait <t> --session "$HERDR_SESSION_NAME" --until idle --until done --until blocked --timeout-ms ${SKS_IDLE_TIMEOUT_MS:-120000}`, timeout은 `SKS_IDLE_RETRIES`(2)×`SKS_IDLE_RETRY_BACKOFF_S`(10) 재시도 후 rc 1. bare `python` 금지. `interactive_ready` 미사용.
- *증거*:
- [ ] **P2-03** 래퍼 `run_agent`를 `preflight_agent` + `inject_agent`로 분리. 순서: register → preflight → idle wait → `_disp_tok` 읽기 → 구독자 기동 → inject → wait → finalize. direct·loop 양 경로 적용. 프리플라이트/idle 실패 시 `finalize_unfinished … preflight|idle_wait`(→ `cancelled`/`session_busy`) + `exit 5`.
- *증거*:
- [ ] **P2-04** `send_keys_safe` 제출 검증: pre_submit에 존재한 busy 토큰 배제(`:2330-2332`).
- *증거*:
- [ ] **P2-05** `send_keys_safe` 네이티브 경로 `agent prompt --wait --until working --timeout 5000` (`SKS_PROMPT_WAIT=1` 기본). stalled/timeout → 재제출 없이 `agent get` 1회 확인, `agent_blocked` → rc 2, 불명 → rc 4.
- *증거*:
- [ ] **P2-06** 폴백(`unknown`) 경로 busy 토큰 게이트(`SKS_BUSY_TIMEOUT` 기본 120s).
- *증거*:
- [ ] **P2-07** T2-1~T2-11 통과, `test_h16`/`test_b8`/`test_c1_*`/`test_herdr_shim_contract` 무변경 통과. 롤백 드릴 `SKS_IDLE_HANDSHAKE=0`.
- *증거*:
- [ ] **P2-08** (Rev.2 Primary) T2-10 `--session` argv 단정, T2-11 bare `python` 정적 린트 0건.
- *증거*:
---
## Phase 3: 오케스트레이터 러너 Fail-Fast 연결
- [ ] **P3-01** `runner.delegate_job`: rc≠0에서도 `registered job:` 파싱 → `created_jobs`·checkpoint 기록 → id 반환. 미매치 시만 `None`.
- *증거*:
- [ ] **P3-02** `run_loop.sh` `delegate_job_safe`/`:373` 파싱 동등성(`MAM_LOOP_PY=0`).
- *증거*:
- [ ] **P3-03** T3-1(`wait_for_job` ≤ 2s False), T3-2(checkpoint 기록), `test_issue5_phase3_loop.py` 무변경 통과.
- *증거*:
- [ ] **P3-04** (Rev.2 Secondary) `delegate_job` rc=5 → `MAM_SESSION_BUSY_RETRY_S`(30) 대기 후 1회 재위임. T3-3.
- *증거*:
---
## Phase 4: 단위/계약 회귀 스위트 및 문서
- [ ] **P4-01** `tests/conftest.py` mock_herdr 확장: `agent get/list`에 `agent_status`(기본 `idle`), `agent wait`(`status_sequence` 소비, timeout 시 stderr JSON rc 1), `agent prompt --wait`(`prompt_wait_result`), 전역 `--session <name>` 인자 수용·호출 기록. 기존 테스트 무변경 통과.
- *증거*:
- [ ] **P4-02** `tests/test_issue6_fail_closed.py` T1-1~T1-13, T3-1~T3-3 작성 및 역검증.
- *증거*:
- [ ] **P4-03** `tests/test_issue6_turn_handshake.py` T2-1~T2-11 작성 및 역검증.
- *증거*:
- [ ] **P4-04** 문서: `multi-agent-mux-delegate-job/SKILL.md` 종료 코드 표, `MESSAGING.md` §5.1 구독자 타임아웃→레지스트리 반영, `BOOTSTRAP.md`/`BOOTSTRAP.ko.md` "completed 발행 후 도구 호출 없이 턴 종료" 1문장. `test_deploy_freshness.py`(`MQTT_*` 10종)·`test_o1_rebuttal.py` 통과.
- *증거*:
- [ ] **P4-05** 전체 스위트 0-Fail (750 + 신규 ≥ 20), `git diff --check` 클린, 수집 수·통과 수·소요 시간 기록.
- *증거*:
---
## Phase 5: 실기동 E2E, 정리, 릴리스
- [ ] **P5-01** 4개 백엔드(Claude/Grok/Codex/OpenCode) 연속 위임 E2E(**direct 모드**; loop 모드 종단은 O-1 이슈 완료 후): `completed`→다음 잡 `started` 타임라인, idle 대기 시간, 주입 실패·중복 0건. `docs/contracts/issue-6/phase5-e2e.md` 작성.
- *증거*:
- [ ] **P5-02** 타임아웃 주입 E2E(`--idle-timeout 30`, 프롬프트 무시): 래퍼 rc=2, `error`, `wait_for_job` ≤ 2s.
- *증거*:
- [ ] **P5-03** 잔존 레코드 `93a44347`, `2961b822`, `ee242671` `registry.py close --request deadline_timeout … --detail "Issue #6 backfill"`로 폐쇄.
- *증거*:
- [ ] **P5-04** `IMPROVEMENTS.md` §5 `Issue-6-FailClosed-TurnHandshake` 블록 추가(§6 표·헤더 키 목록·건수 동기화). 별도 이슈 등록: O-1 리테인 재수락(**loop/discuss 모드 사용 전 필수**로 표기), 레지스트리 오염.
- *증거*:
- [ ] **P5-05** `v4.4.1` 4-way 락스텝(`lib.sh:32`, `eager.py:16`, `VERSIONS.md` 개요·매트릭스·Changelog, 8개 `SKILL.md`), `test_version_consistency.py` 통과.
- *증거*:
- [ ] **P5-06** 리뷰어 교차 검토 `[VERDICT: PASS]` 후 `main` 병합.
- *증거*: