8.5 KiB
8.5 KiB
📑 Target State Transitions and CAS Specification
- Document Version: Rev.2
- Issue: Gitea Issue #5
- Scope: Target Compare-And-Swap (CAS) State Machine & Attribution Contract
1. 이벤트(Event)와 상태(Status)의 개념적 분리
기존 시스템의 혼선을 방지하기 위해 용어를 명확하게 분리하여 정의합니다:
- 이벤트 (Event): 에이전트, 워처(Watcher), 또는 외부 운영자가 특정 시점에 메시징 백플레인(MQTT)이나 로컬 채널로 전달하는 **사건(Fact)**입니다 (
started,progress,permission_required,completed,error,cancelled). - 상태 (Status): 단일 상태 제어 엔진(Engine)이 원자적 CAS 트랜잭션을 통해 공통 레지스트리에 영속적으로 기록하는 현재 작업의 공식 생애주기 단계입니다 (
pending,running,completed,error,cancelled).
📌 핵심 원칙: 이벤트는 상태를 변경해 달라는 **전이 요청(Transition Request)**일 뿐이며, 엔진의 유효성 검증과 CAS 게이트를 통과하기 전까지는 레지스트리 상태가 변경되지 않습니다.
2. 4중 실행 귀속(Execution Attribution) 보장 계약
단순히 에이전트 터미널이 유휴(idle) 상태라고 해서 작업이 성공적으로 종료되었다고 추론(Inferred Completion)해서는 안 됩니다. 이전 작업의 잔여 유휴 상태, 세션 재사용, 또는 프로세스 재시작으로 인한 오탐을 원천 방지하기 위해 다음 4중 식별자 튜플을 필수로 검증합니다:
\text{Attribution Tuple} = (\text{job\_id}, \text{attempt\_id}, \text{agent\_session\_uuid}, \text{pane\_process\_generation})
job_id: 등록된 고유 작업 식별자 (32-bit hex 또는 UUID).attempt_id: 단일 Job 내에서 재시도 시 단조 증가하는 시도 번호.agent_session_uuid: 에이전트 프로세스 기동 시 할당된 영속 고유 식별자.pane_process_generation: TMUX/Herdr 창 및 기저 셸 프로세스의 시작 시각(lstart) 및 PID 조합.
귀속 및 실행 앵커 불변식:
- 동일 에이전트 세션에는 동시에 단 하나의 활성 작업(
job_id)만 배정됩니다. - 디스패치 확인(
dispatch_ack) 이후, 해당attempt_id에 속하는 실제 터미널 출력 및 활동(Execution Anchor)이 관측된 경우에만 완료 후보로 인정합니다. - 네이티브 API가 제공하지 못하는 식별자는
null + reason으로 표기하며, 가짜 값을 임의로 주입하지 않습니다.
3. 목표 CAS 상태 전이표 (Target State Machine)
모든 상태 변경은 Registry Lock 보호 하에서 기대 상태(expected_state), 시도 세대(attempt_id), 버전 번호(version)를 원자적으로 비교한 후 갱신(CAS)합니다.
현재 상태 (Current) |
요청 신호 (Request) |
전이 조건 및 검증 규칙 | 결과 상태 (Next) |
비고 및 갈등 처리 |
|---|---|---|---|---|
pending |
started / claim |
작업 할당 세션 및 attempt_id 일치 확인 |
running |
started는 상태 enum이 아니며 running으로 전이 |
running |
progress |
비-Terminal 유지. 최근 활동 시각 및 세부 정보 갱신 | running |
상태 변경 없이 메타데이터만 갱신 |
running |
permission_required |
비-Terminal 유지. blocked_reason 기록 |
running |
권한 대기 중에는 자동완료 전면 금지 |
running |
explicit terminal |
유효한 작업자 세션의 서명된 completed/error/cancelled 수신 |
요청된 Terminal | 정상 종료 커밋 |
running |
inferred completed |
4중 귀속 일치 + 실행 앵커 확인 + 확정 해시/매니페스트 존재 + Fresh idle/done + 블로커 없음 + 부수효과 검증 |
completed |
Fail-Closed AND 게이트 통과 시에만 CAS 커밋 |
terminal |
동일 논리적 완료 재수신 | 기 커밋된 Terminal 상태와 동일한 요청 | terminal (No-op) |
멱등(Idempotent) ACK 반환, 추가 디스패치 금지 |
terminal |
상충 신호 (progress/다른 Terminal) |
이미 Terminal 상태에 도달한 후 늦게 도착한 신호 | 기 커밋 상태 유지 | 상태 역행 및 덮어쓰기 거부, Conflict Audit Log 기록 |
| 임의 상태 | Stale Attempt / Generation | 과거 시도 세대 또는 프로세스 세대 불일치 신호 | 전이 거부 | Stale Attempt 경고 기록 및 패킷 폐기 |
running |
deadline_timeout |
작업 타임아웃 경과 및 실행 중단 확인 | error |
타임아웃 원인 기록 |
4. 리포트 확정 단계 (Report Finalization Lifecycle)
자동완료 추론 시 파일 쓰기 도중 발생하는 불완전 리포트 채택을 방지하기 위해 3단계 확정 계약을 수립합니다:
[writing] ──(쓰기 진행 중)──> [stable_candidate] ──(원자적 교체 및 매니페스트)──> [finalized]
writing단계:- 에이전트가 임시 파일(
report-final.md.tmp)을 작성 중인 상태. - 워처는 이 상태에서 완료를 절대 인정하지 않음 (Hold).
- 에이전트가 임시 파일(
stable_candidate단계 (1차/보조 필터):- 리포트 파일의 mtime이 단조 시계(monotonic clock) 기준 최소 15초(기본 권장값) 동안 불변인 상태.
- ⚠️ 불변식: 디바운스 경과(15s)만으로는 완료 권한이 성립되지 않습니다. 이는 일시적인 LLM 생각 중단이나 네트워크 지연일 수 있으므로 오직 '후보 필터'로만 기능합니다.
finalized단계 (2차/확정 계약):- 최종 대상 경로(
report-final.md)로의 원자적 이름 변경(Atomic Rename) 완료. - 해당 시도의
attempt_id와report SHA-256 hash가 명시된 완료 매니페스트(Commit Manifest) 생성 완료. - 외부 부수효과(Git push, API 호출)가 수반되는 작업인 경우, 해당 부수효과의 완료 증거가 매니페스트에 첨부되어야 함.
- 리포트가 재작성되면 이전 해시는 즉시 무효화되며 새로운 확정 절차가 필요함.
- 최종 대상 경로(
5. 지연 알림 (Pending Notification) 및 트랜잭션 복구 설계
상태 전이 락(Registry Lock) 하에서 외부 I/O(MQTT 브로커 전송, 네트워크 호출)를 수행하면 데드락과 심각한 지연이 발생할 수 있습니다. 이를 방지하기 위해 다음 내구성 지연 알림(Pending Notification) 트랜잭션을 명세합니다:
sequenceDiagram
participant Engine
participant Registry as Job Registry (Disk)
participant Publisher as Async Publisher (Wire)
participant Broker as MQTT Broker
Note over Engine: 1. CAS 전이 결정
activate Engine
Engine->>Registry: 락 획득 (fcntl.flock)
Engine->>Registry: 원자적 상태 커밋 (status=completed, pending_notification=intent)
Engine->>Registry: 락 즉시 해제
deactivate Engine
Note over Publisher: 2. 비동기 알림 전송
Publisher->>Broker: MQTT 이벤트 발행 (HMAC 서명 포함)
alt 전송 성공
Broker-->>Publisher: ACK (PUBACK)
Publisher->>Registry: pending_notification 완료 표시
else 전송 실패 / 크래시
Note over Publisher: 백오프 재시도 및 기동 시 미완료 알림 복구 전송
end
트랜잭션 보장 규칙:
- 단일 내구성 작업 레코드:
- 독립된 별도의 Outbox DB를 신설하지 않고, 기존
.mam/jobs/<id>.json레코드 내에pending_notification: { event, timestamp, seq, signature }를 원자적으로 기록합니다.
- 독립된 별도의 Outbox DB를 신설하지 않고, 기존
- 락 해제 후 전송:
- 레지스트리 락을 해제한 후 비동기 워커가 MQTT 발행을 수행합니다.
- 크래시 복구(Crash Recovery):
- 엔진 재시작 시
status in TERMINAL이면서pending_notification이 남아있는 레코드를 스캔하여 멱등적으로 재전송합니다.
- 엔진 재시작 시
6. 권한 차단(Permission Blocked) 해제 정책
- 에이전트 터미널이
blocked(권한 승인 대기) 상태로 관측되면, 어떠한 경우에도 자동완료 전이를 시도하지 않습니다. - 차단 해제 판단:
- 묵시적 전이 금지: 단순히 다음 관측에서
working이 되었다고 해서 이전 차단이 정당하게 해결되었다고 단정하지 않습니다. - 명시적 승인 증거 또는 운영자의 승인 입력 로그가 확인되지 않는 한, 작업은
running (blocked)상태를 유지하며 데드라인 도달 시 안전하게 타임아웃 처리합니다.
- 묵시적 전이 금지: 단순히 다음 관측에서