Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
61 changes: 41 additions & 20 deletions spec/README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,44 @@
# Spec v5 Draft
# Spec v6 Draft

> **Date**: 2026-03-22
> **Status**: Draft (reviewed)
> **Date**: 2026-04-04
> **Status**: Draft
> **구조**: 설계 개요 + 관심사별 상세 스펙 + 사용자 플로우

## 핵심 변경 (v4v5)
## 핵심 변경 (v5v6)

- **Daemon = 상태 머신 + 실행기**: yaml에 정의된 prompt/script만 호출하는 단순 실행기로 축소
- **Task trait 제거**: 5개 구현체 → prompt/script로 대체
- **workspace = 1 repo**: 다른 DataSource 지원을 위한 추상화
- **QueuePhase 8개**: Pending/Ready/Running/Completed/Done/HITL/Failed/Skipped
- **worktree는 인프라**: 항상 worktree에서 작업, Done 시 정리
- **환경변수 최소화**: `WORK_ID` + `WORKTREE`만, 나머지는 `belt context` CLI
- **evaluate = CLI 도구 호출**: LLM이 `belt queue done/hitl` 실행
- **LifecycleHook 분리**: on_done/on_fail/on_enter를 yaml script에서 `LifecycleHook` trait으로 분리. handler(작업)와 hook(반응) 관심사 분리. DataSource별 impl, workspace별 바인딩, lazy 로딩
- **Daemon = CPU**: yaml script 실행기 → 상태 머신 CPU. hook 트리거만, 실행 책임은 Hook impl이 소유
- **Stagnation Detection**: 실패 횟수가 아니라 실패 패턴(SPINNING, OSCILLATION)을 감지
- **Daemon 모듈 분리**: 단일 daemon.rs → Advancer + Executor + HitlService + StagnationDetector 모듈
- **Phase 전이 캡슐화**: `item.phase` 직접 대입 금지, `QueueItem::transit()` 메서드 강제
- **ItemContext 확장**: `source_data: serde_json::Value` 추가 — 새 DataSource 추가 시 코어 변경 0
- **hitl_terminal_action 타입 안전**: `Option<String>` → `Option<EscalationAction>`
- **Dependency Gate DB 기반**: in-memory → DB 조회, 재시작 시 순서 보장
- **Evaluator per-item 판정**: workspace 배치 → per-work_id 개별 LLM 판정

## 설계 문서

- **[DESIGN-v5.md](./DESIGN-v5.md)** — 설계 철학 + 전체 구조 개요 (간결)
- **[DESIGN-v6.md](./DESIGN-v6.md)** — 설계 철학 + 전체 구조 개요 (간결)

## 관심사별 상세 스펙 (concerns/)

"이 시스템은 내부적으로 어떻게 동작하지?" — 구현자 대상

| 문서 | 설명 |
|------|------|
| [QueuePhase 상태 머신](./concerns/queue-state-machine.md) | 8개 phase 전이 다이어그램, worktree 생명주기, on_fail 조건 |
| [Daemon](./concerns/daemon.md) | 실행 루프 의사코드, concurrency, graceful shutdown |
| [DataSource](./concerns/datasource.md) | 외부 시스템 추상화 trait + context CLI + 워크플로우 yaml |
| [QueuePhase 상태 머신](./concerns/queue-state-machine.md) | 8개 phase 전이, **전이 캡슐화**, worktree 생명주기, on_fail 조건 |
| [Daemon](./concerns/daemon.md) | **내부 모듈 구조**, 실행 루프, **DB dependency gate**, concurrency, graceful shutdown |
| [Evaluator](./concerns/evaluator.md) | **v6 신규** — Progressive Evaluation Pipeline, Evaluate before Execute |
| [Stagnation Detection](./concerns/stagnation.md) | **v6 신규** — 4가지 정체 패턴, 해시 기반 탐지 |
| [LifecycleHook](./concerns/lifecycle-hook.md) | **v6 신규** — 상태 전이 반응 trait, handler/hook 분리, lazy 로딩 |
| [DataSource](./concerns/datasource.md) | 외부 시스템 추상화 trait + **source_data** + 워크플로우 yaml |
| [AgentRuntime](./concerns/agent-runtime.md) | LLM 실행 추상화 trait + Registry |
| [Agent 워크스페이스](./concerns/agent-workspace.md) | 대화형 에이전트 + evaluate + slash command |
| [Cron 엔진](./concerns/cron-engine.md) | 주기 실행 + 품질 루프 + force trigger |
| [Agent 워크스페이스](./concerns/agent-workspace.md) | 대화형 에이전트 + **per-item evaluate** + slash command |
| [Cron 엔진](./concerns/cron-engine.md) | 주기 실행 + 품질 루프 (evaluate는 Daemon tick으로 이동) |
| [CLI 레퍼런스](./concerns/cli-reference.md) | 3-layer SSOT + `belt context` + 전체 커맨드 트리 |
| [Cross-Platform](./concerns/cross-platform.md) | OS 추상화 (ShellExecutor, DaemonNotifier) |
| [Distribution](./concerns/distribution.md) | 배포 전략 |
| [Data Model](./concerns/data-model.md) | SQLite 스키마, **StagnationPattern enum**, **EscalationAction FromStr**, **source_data** |

## 사용자 플로우 (flows/)

Expand All @@ -40,6 +48,19 @@
|---|------|------|
| 01 | [온보딩](./flows/01-setup.md) | workspace 등록 → 컨벤션 부트스트랩 |
| 02 | [스펙 생명주기](./flows/02-spec-lifecycle.md) | 스펙 등록 → 이슈 분해 → 완료 판정 |
| 03 | [이슈 파이프라인](./flows/03-issue-pipeline.md) | handlers 실행 → evaluate → on_done |
| 04 | [실패 복구와 HITL](./flows/04-failure-and-hitl.md) | escalation → on_fail → 사람 개입 |
| 05 | [모니터링](./flows/05-monitoring.md) | TUI + CLI + /agent 시각화 |
| 03 | [이슈 파이프라인](./flows/03-issue-pipeline.md) | handlers 실행 → **stagnation detection** → evaluate → hook.on_done |
| 04 | [실패 복구와 HITL](./flows/04-failure-and-hitl.md) | **stagnation + lateral thinking** → escalation → hook 트리거 → 사람 개입 |
| 05 | [모니터링](./flows/05-monitoring.md) | TUI + CLI + /agent 시각화 + **stagnation 표시** |

## 이슈 매핑

| 이슈 | 주요 반영 문서 |
|------|-------------|
| 신규 LifecycleHook 분리 | lifecycle-hook.md, datasource.md, daemon.md, DESIGN |
| #723 Stagnation/Oscillation 탐지 | stagnation.md, daemon.md, data-model.md, flow-04, DESIGN |
| #717 Daemon 내부 모듈 분리 | daemon.md, DESIGN |
| #718 Phase 전이 캡슐화 | queue-state-machine.md, data-model.md, DESIGN |
| #719 ItemContext source_data | data-model.md, datasource.md |
| #720 hitl_terminal_action 타입 | data-model.md, flow-04 |
| #721 Dependency Gate DB 기반 | daemon.md |
| #722 Evaluator per-item 판정 | cron-engine.md, agent-workspace.md, daemon.md |
File renamed without changes.
45 changes: 45 additions & 0 deletions spec/archive/v5/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Spec v5 Draft

> **Date**: 2026-03-22
> **Status**: Draft (reviewed)
> **구조**: 설계 개요 + 관심사별 상세 스펙 + 사용자 플로우

## 핵심 변경 (v4 → v5)

- **Daemon = 상태 머신 + 실행기**: yaml에 정의된 prompt/script만 호출하는 단순 실행기로 축소
- **Task trait 제거**: 5개 구현체 → prompt/script로 대체
- **workspace = 1 repo**: 다른 DataSource 지원을 위한 추상화
- **QueuePhase 8개**: Pending/Ready/Running/Completed/Done/HITL/Failed/Skipped
- **worktree는 인프라**: 항상 worktree에서 작업, Done 시 정리
- **환경변수 최소화**: `WORK_ID` + `WORKTREE`만, 나머지는 `belt context` CLI
- **evaluate = CLI 도구 호출**: LLM이 `belt queue done/hitl` 실행

## 설계 문서

- **[DESIGN-v5.md](./DESIGN-v5.md)** — 설계 철학 + 전체 구조 개요 (간결)

## 관심사별 상세 스펙 (concerns/)

"이 시스템은 내부적으로 어떻게 동작하지?" — 구현자 대상

| 문서 | 설명 |
|------|------|
| [QueuePhase 상태 머신](./concerns/queue-state-machine.md) | 8개 phase 전이 다이어그램, worktree 생명주기, on_fail 조건 |
| [Daemon](./concerns/daemon.md) | 실행 루프 의사코드, concurrency, graceful shutdown |
| [DataSource](./concerns/datasource.md) | 외부 시스템 추상화 trait + context CLI + 워크플로우 yaml |
| [AgentRuntime](./concerns/agent-runtime.md) | LLM 실행 추상화 trait + Registry |
| [Agent 워크스페이스](./concerns/agent-workspace.md) | 대화형 에이전트 + evaluate + slash command |
| [Cron 엔진](./concerns/cron-engine.md) | 주기 실행 + 품질 루프 + force trigger |
| [CLI 레퍼런스](./concerns/cli-reference.md) | 3-layer SSOT + `belt context` + 전체 커맨드 트리 |

## 사용자 플로우 (flows/)

"사용자가 X를 하면 어떻게 되지?" — 시나리오 기반, 기획자/사용자 대상

| # | Flow | 설명 |
|---|------|------|
| 01 | [온보딩](./flows/01-setup.md) | workspace 등록 → 컨벤션 부트스트랩 |
| 02 | [스펙 생명주기](./flows/02-spec-lifecycle.md) | 스펙 등록 → 이슈 분해 → 완료 판정 |
| 03 | [이슈 파이프라인](./flows/03-issue-pipeline.md) | handlers 실행 → evaluate → on_done |
| 04 | [실패 복구와 HITL](./flows/04-failure-and-hitl.md) | escalation → on_fail → 사람 개입 |
| 05 | [모니터링](./flows/05-monitoring.md) | TUI + CLI + /agent 시각화 |
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,27 @@

분류 로직은 코어에 속한다. Agent와 무관.

**v6 (#722)**: evaluate는 **per-work_id 단위**로 LLM 판정을 실행한다.

```
handler 전부 성공 → Completed
Evaluator (Daemon tick에서 Executor보다 먼저 실행):
Progressive Pipeline:
Stage 1: Mechanical (cargo test 등, 비용 0)
→ 실패 시 Retry (LLM 안 부름)
Stage 2: Semantic (LLM 1회, belt agent -p)
→ LLM이 belt context로 컨텍스트 조회 후 판정
evaluate cron (force_trigger로 즉시 실행 가능):
belt agent -p "Completed 아이템의 완료 여부를 판단해줘"
│ LLM이 belt context로 컨텍스트 조회 후 CLI 도구로 결정:
├── Done → hook.on_done() 트리거
│ ├── hook 성공 → Done (worktree 정리)
│ └── hook 실패 → Failed (worktree 보존)
├── belt queue done $WORK_ID
│ → Daemon이 on_done script 실행 (CLI 명령이 상태 전이를 트리거하고, Daemon이 script를 실행)
│ ├── script 성공 → Done (worktree 정리)
│ └── script 실패 → Failed (worktree 보존, 로그 기록)
└── HITL → HITL 이벤트 생성 → 사람 대기 (worktree 보존)
└── belt queue hitl $WORK_ID --reason "..."
→ HITL 이벤트 생성 → 사람 대기 (worktree 보존)
```

- Evaluator는 Daemon tick의 정규 단계. 상세: [Evaluator](./evaluator.md)
- SemanticStage에서 LLM이 `belt queue done/hitl` CLI를 직접 호출하여 상태를 전이한다
- 개별 판정 실패 시 해당 아이템만 Completed에 머물고, 다른 아이템 판정에 영향 없다
- evaluate LLM 호출도 `daemon.max_concurrent` slot을 소비한다
evaluate cron: `interval 60s + force_trigger on Completed 전이`. LLM이 JSON을 파싱하는 게 아니라, 직접 `belt queue done/hitl` CLI를 호출하여 상태를 전이한다.

evaluate의 판단 입력: `belt context $WORK_ID --json` (queue 메타데이터 + 외부 시스템 컨텍스트 + append-only history).

---

Expand Down Expand Up @@ -184,9 +181,14 @@ v4 (15개) → v5 (3개):
### classify-policy.md 로딩 경로 및 해석 (R-CW-007)

`classify-policy.md`는 LLM 에이전트가 큐 아이템을 Done / HITL로 분류할 때
참조하는 자연어 정책 문서다. `.claude/rules/` 하위에 위치하며, system prompt에 주입된다.
참조하는 정책 문서다. 두 가지 형태로 존재한다:

#### 로딩 경로
| 파일 | 위치 | 소비자 | 용도 |
|------|------|--------|------|
| `classify-policy.md` | `.claude/rules/` 하위 | LLM agent (system prompt) | 자연어 분류 기준 |
| `classify-policy.yaml` | workspace root | daemon evaluator | machine-readable 라우팅 규칙 |

#### 로딩 경로 (classify-policy.md)

`agent::resolve_rules_dir` 함수가 아래 우선순위로 **디렉토리**를 탐색한다.
첫 번째로 존재하는 디렉토리 안의 **모든 `.md` 파일**이 로드된다.
Expand All @@ -201,9 +203,11 @@ Priority 3: $BELT_HOME/claw-workspace/.claude/rules/ (global, belt claw init)

#### 파일 미존재 시 fallback

- 디렉토리 자체가 없는 경우: agent는 built-in Claw rules(대화 턴 제한, 응답 포맷, 에러 핸들링)만으로 실행. 에러 없음.
- 디렉토리 자체가 없는 경우: agent는 built-in Claw rules(대화 턴 제한, 응답 포맷,
에러 핸들링)만으로 실행. 에러 없음.
- 디렉토리는 있지만 `.md` 파일이 없는 경우: 동일하게 built-in rules만 사용.
- `classify-policy.md`만 없고 다른 `.md`가 있는 경우: 다른 정책 파일은 정상 로드, 분류 정책 가이던스만 빠진 채 실행.
- `classify-policy.md`만 없고 다른 `.md`가 있는 경우: 다른 정책 파일은 정상 로드,
분류 정책 가이던스만 빠진 채 실행.

#### 구현 위치

Expand All @@ -223,22 +227,19 @@ Priority 3: $BELT_HOME/claw-workspace/.claude/rules/ (global, belt claw init)
| `belt hitl list --json` | HITL 목록 조회 | 대화형 세션 |
| `belt queue list --json` | 큐 목록 조회 | 대화형 세션 |

### Evaluator와의 관계
### evaluate cron과의 관계

Evaluator의 SemanticStage가 내부적으로 `belt agent -p`를 호출한다. 이때:
- **per-item**: 각 아이템에 대해 개별 프롬프트 발행 (v6 #722)
- LLM이 `belt context $WORK_ID`로 해당 아이템 정보를 조회
evaluate cron은 내부적으로 `belt agent --workspace <path> -p "<prompt>"`를 호출한다. 이때:
- Completed 아이템 목록을 프롬프트에 포함
- LLM이 `belt context`로 아이템 정보를 조회
- 판단 후 `belt queue done/hitl` CLI를 직접 호출하여 상태 전이
- classify-policy.md의 state별 Done 조건이 판단 기준
- evaluate LLM 호출도 `daemon.max_concurrent` slot을 소비

상세: [Evaluator](./evaluator.md)

---

### 관련 문서

- [DESIGN-v6](../DESIGN-v6.md) — QueuePhase 상태 머신 + evaluate 위치
- [DESIGN-v5](../DESIGN-v5.md) — QueuePhase 상태 머신 + evaluate 위치
- [CLI 레퍼런스](./cli-reference.md) — CLI 전체 커맨드 트리
- [Cron 엔진](./cron-engine.md) — evaluate cron
- [Data Model](./data-model.md) — 컨텍스트 모델 (belt context 출력)
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@

```
1. 인프라 유지 — hitl-timeout, log-cleanup, daily-report (결정적)
2. 품질 루프 — gap-detection, knowledge-extract (LLM 사용)

※ evaluate는 Daemon tick 루프의 정규 단계로 이동. 상세: [Evaluator](./evaluator.md)
2. 품질 루프 — evaluate, gap-detection, knowledge-extract (LLM 사용)
```

---
Expand Down Expand Up @@ -59,6 +57,7 @@ gap 발견 → DataSource에서 open 아이템 조회 (Pending/Ready/Running)

| Job | 주기 | 동작 |
|-----|------|------|
| evaluate | 60초 | 완료 아이템 분류 (Done or HITL) — `belt agent -p` |
| gap-detection | 1시간 | 스펙-코드 대조, gap 발견 시 이슈 생성 |
| knowledge-extract | 1시간 | merged PR 지식 추출 |

Expand All @@ -71,19 +70,39 @@ gap 발견 → DataSource에서 open 아이템 조회 (Pending/Ready/Running)

---

## Force Trigger
## Force Trigger (하이브리드 실행 모델)

force_trigger는 cron job을 다음 tick에서 우선 실행하도록 스케줄링한다.
evaluate는 **cron 주기 폴링 + force_trigger 즉시 실행**의 하이브리드 모델로 동작한다:

```
force_trigger(job_name):
job.last_run_at = NULL → 다음 tick에서 즉시 실행
1. 주기 폴링: evaluate cron이 60초마다 Completed 아이템을 스캔
2. 즉시 실행: handler 성공 → Completed 전이 → force_trigger("evaluate")
→ last_run_at = NULL → 다음 tick(10초 이내)에서 즉시 실행
```

- 동기적으로 실행하지 않는다. cron의 `last_run_at`을 리셋할 뿐.
- gap-detection 등 품질 루프 job에 사용.
- **force_trigger**는 동기적으로 evaluate를 실행하지 않는다. cron의 `last_run_at`을 리셋하여 다음 tick에서 우선 실행되도록 스케줄링한다.
- evaluate LLM 호출도 concurrency slot을 소비한다 (`daemon.max_concurrent`에 `active_evaluate_count`가 포함됨).
- 주기 폴링은 force_trigger가 누락된 경우(예: 프로세스 재시작)의 안전망 역할을 한다.

> handler 실패 시에는 force_trigger 없이 즉시 escalation 정책이 적용된다 (evaluate 불필요).

---

## 스크립트 구조

Cron job의 스크립트도 `belt context`를 활용하여 필요한 정보를 조회한다.

> **evaluate는 v6에서 Daemon tick 정규 단계로 이동**. Completed 아이템은 Evaluator가 다음 tick에서 Progressive Pipeline으로 판정한다. 상세: [Evaluator](./evaluator.md)
```bash
#!/bin/bash
# Guard: Completed 상태 아이템 있을 때만
COMPLETED=$(belt queue list --workspace "$WORKSPACE" --phase completed --json | jq 'length')
if [ "$COMPLETED" = "0" ]; then exit 0; fi

# 실행: evaluate
# LLM이 context를 조회하고 belt queue done/hitl CLI를 직접 호출
belt agent --workspace "$WORKSPACE" -p \
"Completed 아이템의 완료 여부를 판단하고, belt queue done 또는 belt queue hitl 을 실행해줘"
```

---

Expand Down Expand Up @@ -113,7 +132,6 @@ Cron 스크립트에는 workspace 정보가 필요하므로 추가 변수를 주

### 관련 문서

- [DESIGN-v6](../DESIGN-v6.md) — evaluate 아키텍처
- [DESIGN-v5](../DESIGN-v5.md) — evaluate 아키텍처
- [DataSource](./datasource.md) — belt context 스키마
- [Agent](./agent-workspace.md) — evaluate와 Agent의 관계
- [Stagnation Detection](./stagnation.md) — handler 실패 시 패턴 감지 (cron이 아닌 동기 실행)
Loading
Loading