- Enforce evidence-root confinement for capture_ref and 1:1 capture citation uniqueness - Add pane identity and backend identity cross-validation - Add bidirectional agreement checks between watcher/herdr manifests and scenario fixtures - Expand contract test suite to 41 tests (100% pass) - Document evidence confinement rules in herdr-runtime.md and update task.md - Archive Codex 4th review report (Job 1bd561e6: [VERDICT: PASS])
13 KiB
📑 Herdr Runtime Contract and Backend Capability Matrix
- Document Version: Rev.5 (Evidence Source-Kind Dispatch & Identity Correspondence — §3-1 신설)
- Issue: Gitea Issue #5
- Target Herdr Version:
herdr 0.8.2 - Scope: Native Herdr API Contract, External Collector Specification, and Backend Matrix
1. Herdr 0.8.2 네이티브 API 계약 (Native API Contract)
1-1. 핵심 CLI 명령어 및 반환 페이로드
herdr는 AI 코딩 에이전트 전용 터미널 멀티플렉서로서, 소켓 API를 통해 터미널 스크린 감시 상태를 제공합니다:
herdr agent list: 현재 활성화된 모든 에이전트 목록 및 상태 반환 (JSON stdout, exit 0).herdr agent get <target>: 특정 에이전트의 단일 시점 스냅샷 반환 (agent_status,interactive_ready,pane_id,revision,state_change_seq등).herdr agent wait <target> [OPTIONS]: 에이전트가 지정된 상태에 도달할 때까지 블로킹 대기.herdr agent explain [OPTIONS] [target]: 내부 정규식 매칭 규칙(matched_rule,evaluated_rules) 평가 세부정보 반환.
1-2. 네이티브 상태 집합 (agent_status)
- 지원 Enum:
idle,working,blocked,done,unknown(총 5종). interactive_ready(boolean):- 터미널이 키 입력을 수신할 준비가 되었는지를 나타내는 플래그.
- 실측 불변식: 에이전트가 코딩 작업 중(
agent_status: "working")일 때도interactive_ready: true임이 입증됨. 따라서interactive_ready단독으로는 작업 완료의 충분조건이 될 수 없으며, 오직agent_status in {"idle", "done"}상태와 결합되어야 합니다.
1-3. herdr agent wait 호출 규격 및 채널 분리 실측
실제 herdr 0.8.2 실행(wait-contract.json 및 evidence/timeout_stderr.json)을 통해 검증된 입출력 채널 및 종료 코드 계약은 다음과 같습니다:
| 호출 조건 | 명령 예시 | 종료 코드 | 출력 채널 | 반환 JSON 페이로드 구조 |
|---|---|---|---|---|
| 상태 도달 (성공) | herdr agent wait creator-agy-01 --until working --timeout 1000 |
exit 0 |
stdout |
{"id":"cli:agent:wait","result":{"agent":{...},"type":"agent_info"}} |
| 타임아웃 (Timeout) | herdr agent wait creator-agy-01 --until done --timeout 50 |
exit 1 |
stderr |
{"error":{"code":"timeout","message":"timed out waiting for agent status"},"id":"cli:agent:wait"} |
| 대상 부재 (Unknown) | herdr agent wait non-existent --until idle --timeout 50 |
exit 1 |
stderr |
{"error":{"code":"agent_not_found","message":"agent target non-existent not found"},"id":"cli:agent:wait"} |
| 기본 대기 옵션 생략 | herdr agent wait <target> |
N/A | N/A | --until 생략 시 기본 매칭 대상은 idle, done, blocked임. --timeout 생략 시 무기한 대기함 |
🚨 Critical Empirical Finding (수정 반영):
herdr agent wait에서 성공(상태 일치) 시에는 정상 JSON이stdout으로 출력되지만, **타임아웃(timeout) 및 대상 부재(agent_not_found) 등 모든 에러 응답은stderr로 에러 JSON이 출력되며 종료 코드는exit 1**입니다 (stdout은 비어있음). 따라서 Watcher 엔진은exit 1시 반드시stderr스트림에서 JSON 에러 페이로드를 파싱해야 합니다.
2. 외부 시퀀스 수집기 계약 (External Sequence Collector)
2-1. 단일 wait 호출의 본질적 한계
herdr agent wait는 타겟이 특정 상태에 도달한 시점에 단 1개의 최종 스냅샷 JSON만 반환하는 동기적 장벽(Barrier)입니다.- 호출 도중 거쳐간 중간 전이 과정(Transition Stream)을 반환하지 않습니다.
- 따라서
working ➔ idle과 같은 상태 전이를 입증하려면, 외부 오케스트레이터/수집기가 사전 스냅샷(before)과 사후 스냅샷(after)을 독립적으로 획득하여 타임스탬프와 함께 연결해야 합니다.
2-2. 수집기(Collector) 권장 규격
- 폴링 주기: 1~2초 수준의 유계(Bounded) 폴링 (
agent get). 고정밀 10ms 스핀 폴링은 불필요하며 CPU 낭비를 초래합니다. - Envelope 메타데이터: 단조 시계 오프셋(
monotonic_start,monotonic_end),collector_clock_id,capture_id,source_command를 필수로 보존하여 시점 간 왜곡을 방지합니다.
3. 이벤트, 파일시스템 및 디스패치 연계 경계
Herdr 네이티브 페이로드와 Multi-Agent-Mux 오케스트레이션 메타데이터 사이에는 엄격한 책임 격리가 유지되어야 합니다:
┌─────────────────────────────────────────────────────────────┐
│ Herdr Native API Boundary │
│ • agent_status (idle/working/blocked/done/unknown) │
│ • interactive_ready (true/false) │
│ • pane_id, state_change_seq, terminal_title │
└──────────────────────────────┬──────────────────────────────┘
│ 관측 증거 제공 (채널 2)
▼
┌─────────────────────────────────────────────────────────────┐
│ Multi-Agent-Mux Watcher Boundary │
│ • 4-Fold Attribution: │
│ (job_id, attempt_id, session_uuid, │
│ pane_process_generation) │
│ • File Evidence (report mtime debounce >=15s, hash) │
│ • Backplane Events (seq, HMAC signature, started/progress)│
└─────────────────────────────────────────────────────────────┘
- 불변식: Herdr 원본 응답 페이로드에는
job_id,attempt_id,report phase,expected_decision등의 MAM 내부 필드를 절대 주입하지 않습니다.
3-1. Watcher 타임라인 증거 스키마 및 source_kind 분기 계약 (Rev.5)
Watcher 복합 시나리오(tests/fixtures/issue_5/watcher/*.json)의 각 타임라인 항목은 아래 계약을 따르며, tests/test_issue5_phase0_contracts.py의 validate_watcher_scenario가 이를 기계적으로 강제합니다. 위반 시 fixture 검증은 fail-closed(거부) 입니다.
| 규칙 | 내용 | 강제 지점 |
|---|---|---|
| 지원 source_kind 집합 | herdr, event, filesystem, harness 4종만 허용. 그 외 값은 provenance와 무관하게 거부 |
SUPPORTED_SOURCE_KINDS |
| 관측(observed) 증거 스키마 | 독립 증거 스키마가 구현된 kind만 source_provenance: observed를 선언할 수 있음. 현재 herdr만 해당. event/filesystem/harness는 스키마가 생길 때까지 simulated(또는 synthetic)로만 기록하며, observed로 표기 시 capture_ref가 유효하더라도 즉시 거부 |
OBSERVED_EVIDENCE_SCHEMAS |
| capture_ref 격리 | repo 상대 경로여야 하며(절대 경로 금지), 해석 결과가 tests/fixtures/issue_5/herdr/ 하위여야 함(.. 우회 금지). .json이고 schema_version 1.0.0·provenance observed·capture_id를 갖는 네이티브 캡처만 증거로 인정 |
_load_observed_capture_ref |
| Herdr 항목 대응성 | ① 참조 캡처는 Layer 1 네이티브 계약(validate_native_capture)을 재통과 ② 항목 payload는 비어있지 않은 dict이며 agent_status를 필수 선언(누락 시 비교 생략이 아닌 거부) ③ 캡처는 result.agent 객체를 포함해야 함(wait timeout 등 nonzero-exit 캡처는 agent_status를 입증할 수 없으므로 거부) ④ 선언된 모든 필드가 agent 객체의 네이티브 필드에 존재하고 값이 정확히 일치(비네이티브 필드 선언 시 거부) |
_validate_observed_herdr_item |
| 정체성 대응 (4중 귀속 연동) | 캡처의 agent_session.value == dispatch_context.agent_session_uuid, 캡처의 pane_id가 dispatch_context.pane_process_generation(<pane_id>:<pid>:<start>)의 선두 구성요소여야 함. 시나리오 backend가 backend_agnostic이 아니면 캡처 backend와 일치해야 함 |
_validate_observed_herdr_item |
| 1캡처 = 1관측 | 하나의 capture_id는 시나리오 내 관측 항목 하나만 입증할 수 있음(동일 스냅샷의 재인용 금지) |
validate_watcher_scenario |
| provenance 정직성 | observed·simulated 혼재 시 전체 provenance는 mixed, 전량 관측 시 observed_composite, 전량 모의 시 simulated여야 함 (synthetic 항목은 비관측으로 집계) |
validate_watcher_scenario |
| 매니페스트 정합성 | watcher/manifest.json의 provenance/expected_decision은 시나리오 파일과 일치해야 하며, herdr/manifest.json의 observed 슬롯은 동일 backend의 캡처가 슬롯명과 같은 agent_status(또는 wait_timeout 슬롯은 error.code=timeout)를 기록해야 함. 디스크의 모든 캡처는 정확히 하나의 observed 슬롯에 색인되어야 함(고아 캡처 금지) |
validate_watcher_manifest, validate_herdr_manifest |
📌 이 계약은 fixture 검증 계약이며 프로덕션 Watcher 구현(Phase 2a)이 아닙니다. Phase 2a의
watcher.py는 이 표의 "관측 증거 스키마" 열을 확장(event/filesystem 스키마 추가)할 때OBSERVED_EVIDENCE_SCHEMAS를 함께 갱신해야 하며, 스키마 없는 kind를 관측으로 승격하는 일은 허용되지 않습니다.
4. 6개 백엔드 기능 및 실측 증거 행렬 (Capability Matrix)
본 프로젝트가 지원하는 6개 에이전트 백엔드(claude, agy, hermes, grok, opencode, codex)의 현 환경 실측 상태 및 Gap 현황입니다 (모든 슬롯은 tests/fixtures/issue_5/herdr/manifest.json과 100% 일치):
| 백엔드 | 설치 바이너리 경로 | 활성 세션명 | 실측 캡처 슬롯 | 미관측 슬롯 (Gaps) 및 사유 | Provenance |
|---|---|---|---|---|---|
claude |
~/.local/bin/claude |
planner-reviewer-claude-01 |
idle (claude/idle.json) |
working, blocked, done, unknown (캡처 시점에 idle 상태였음) |
observed |
agy |
~/.local/bin/agy |
creator-agy-01 |
working (agy/working.json), wait_timeout (agy/wait_timeout.json) |
idle, blocked, done, unknown (작업 수행 중이며 권한 건너뛰기 적용) |
observed |
grok |
~/.grok/bin/grok |
reviewer-creator-grok-01 |
idle (grok/idle.json) |
working, blocked, done, unknown (리뷰 대기 중 유휴 상태 캡처) |
observed |
codex |
~/.local/bin/codex |
planner-reviewer-codex-01 |
done (codex/done.json) |
idle, working, blocked, unknown (이전 플래너 작업 완료 직후 캡처) |
observed |
hermes |
~/.local/bin/hermes |
N/A (미가동) | 없음 | idle, working, blocked, done, unknown (Herdr 서버에 활성 세션 부재) |
unobserved |
opencode |
~/.opencode/bin/opencode |
N/A (미가동) | 없음 | idle, working, blocked, done, unknown (Herdr 서버에 활성 세션 부재) |
unobserved |
📌 정직한 증거 보고 원칙 (D3, D6):
- 오직 실제로 실행하여 캡처한 슬롯만
observed로 인정하며, 모의 실행이나 가상 시뮬레이션을 네이티브 캡처로 둔갑시키지 않습니다.hermes와opencode의 미가동 슬롯 및 기존 4개 백엔드의 미관측 상태는 모두 정직하게unobserved gap으로 기록합니다.- Grok 세션 등은 캡처 시점에
idle이었으나 리뷰 실행 시working으로 전이되므로, 정적 캡처가 에이전트의 영구 불변 능력을 뜻하지 않음을 명시합니다.
5. 복합 시나리오 기대 정책 (Composite Expected Policy)
Watcher가 다중 채널 증거를 결합하여 내리는 최종 완료 판정 정책:
initial_idle: 디스패치 기록은 있으나 해당 시도의 실행 앵커가 없으면 ➔hold(완료 거부).tool_running: Herdr는working이나 하네스에서 도구 실행 중이면 ➔hold(대기).report_pause_15s: 파일이 15초간 멈추었으나 확정 매니페스트가 없으면 ➔hold(대기).finalized_candidate: 4중 귀속 일치 + Freshidle/done+ 원자적 매니페스트/해시 일치 ➔candidate_approved(CAS 커밋 허용).blocked_permission: Herdr가blocked이면 ➔hold_blocked(완료 금지).transport_disconnected: 소켓 통신 실패 시 ➔hold_reconnect(스냅샷 재동기화).restarted_generation: PID/세션 식별자가 변경된 과거 시도의 신호 ➔reject_stale(전이 거부).