# SDD: 공통 Agent Task Runtime과 Desktop Agent

## 위치

- Milestone: [공통 Agent Task Runtime과 Desktop Agent](../../../phase/automation-runtime-bridge/milestones/shared-agent-task-runtime-desktop-agent.md)
- Phase: [PHASE.md](../../../../phase/automation-runtime-bridge/PHASE.md)

## 상태

[대체됨]

## SDD 잠금

- 상태: 해제
- 사용자 리뷰: 없음
- 잠금 항목: 없음

## 문제 / 비목표

- 문제: 이미 agent-ops 작업 체계를 가진 project의 Agent Task 실행·관측·복구 책임은 Python dispatcher를 모델이 감시하는 스킬 흐름과 Node 내부 CLI runtime에 나뉘어 있다. 이 구조는 감시 모델의 토큰 비용을 지속 발생시키고, Desktop Agent를 만들 때 provider 실행을 복사할 위험이 있다. 이 SDD는 project-owned workflow 의미는 유지한 채 provider와 AgentTaskManager를 단일 Go runtime으로 모으고 Node와 Edge 없는 Desktop host가 함께 소비하는 책임, lifecycle, config와 evidence 경계를 고정한다.
- 비목표:
  - 기능을 줄인 MVP나 일부 provider만 동작하는 선행판을 정의하지 않는다.
  - Python 코드를 production에서 호출·이식하거나 Python process의 활성 상태를 Desktop으로 이전하지 않는다.
  - Desktop에 Edge, Control Plane, remote terminal bridge를 포함하지 않는다.
  - CLI 인증·credential·계정 회전, 외부 알림, 완성형 설정 UI, Windows/Linux, signing/notarization은 다루지 않는다.
  - agent-ops 공통 skill/rule을 runtime monitoring engine으로 바꾸지 않는다.
  - agent-ops를 사용하지 않는 일반 사용자 요청을 direct/Plan/Milestone으로 분류하거나 IOP 소유 skill/tool call로 작업 파일을 생성하는 상위 오케스트레이션을 구현하지 않는다.

## Source of Truth

| 영역 | 기준 | 메모 |
|------|------|------|
| Roadmap | [공통 Agent Task Runtime과 Desktop Agent](../../../phase/automation-runtime-bridge/milestones/shared-agent-task-runtime-desktop-agent.md) | 제품 목표, 전체 동등성 범위, 기능 Task와 제외 범위 |
| Policy | [Agent Task 동적 실행 Target Selector](../../../phase/automation-runtime-bridge/milestones/agent-task-runtime-target-selector.md), [CLI Agent Group Grade Routing](../../../../phase/automation-runtime-bridge/milestones/cli-agent-group-grade-routing.md) | 선택, route pin, quota, failover와 agent/model rule의 우선 기준 |
| Project Workflow | 등록 workspace의 `agent-ops/rules/project`, `agent-ops/skills/project`, Milestone·Plan·Code Review 파일과 project workflow adapter | workflow 의미와 artifact contract는 project가 소유하고, 공통 runtime은 adapter의 구조 판정으로 이미 선택된 work step과 review lifecycle을 실행한다 |
| Separate Orchestration | [에이전트 작업 루프 오케스트레이션 MVP](../../../../phase/automation-runtime-bridge/milestones/agent-workflow-loop-orchestration-mvp.md) | agent-ops를 직접 쓰지 않는 사용자의 일반 요청 분류, IOP 소유 Plan/Milestone skill과 합성 tool call은 별도 상위 기능이다 |
| Reference Behavior | `agent-ops/skills/project/orchestrate-agent-task-loop/scripts`, target-selector의 최종 PASS·`complete.log`·fixture와 `WORK_LOG.md` | Python은 동작·오류·관측 evidence일 뿐 production dependency가 아니다. 미종결 active plan/review는 결함 후보로만 사용하고 공통 계약으로 승격하지 않는다 |
| Code | `packages/go/agentruntime`, `apps/node`, `apps/desktop-agent`, `apps/desktop-agent-ui`, `packages/go/config` | 단일 runtime 구현과 host integration의 구현 source of truth 후보 |
| Existing Contract | [Edge-Node Runtime Wire](../../../../../agent-contract/inner/edge-node-runtime-wire.md), [Edge Config Runtime Refresh](../../../../../agent-contract/inner/edge-config-runtime-refresh.md) | Node bridge가 보존해야 할 현재 wire/config 의미. 변경이 필요하면 구현 전 agent-contract를 갱신한다 |
| Project State | 각 등록 workspace의 `agent-task`, `agent-roadmap`, `WORK_LOG.md`, `agent-log` | 작업 원문·진행·evidence의 durable source of truth |
| App State | app-owned YAML config tree, project registry, 최소 runtime checkpoint | provider/global 설정과 registry id별 project override를 모두 소유한다. workspace config나 project 작업 원문을 중앙 권위로 복제하지 않는다 |
| External Provider | 사용자가 YAML에 선언하고 이미 인증한 CLI provider | app은 discovery/readiness/status/실행만 하며 인증을 소유하지 않는다 |
| User Decision | 없음 | D01은 결합 범위 분리에 따라 [범위 이관 기록](user_review_0.log)으로 남기고 후속 Flutter Desktop Milestone에서 다시 검토한다 |

## State Machine

| 상태 | 진입 조건 | 다음 상태 | 근거 |
|------|-----------|-----------|------|
| `host-starting` | Node process 또는 Desktop app이 시작됐다 | `config-validating` 또는 `host-error` | process/app lifecycle |
| `config-validating` | app-owned YAML의 global 설정과 registry id별 project override를 읽고 schema·provider reference를 검증한다 | `provider-discovering` 또는 `config-error` | config revision과 validation event |
| `provider-discovering` | 선언 provider의 binary/version/authenticated readiness/model capability를 read-only 조회한다 | `project-watching` 또는 `provider-error` | discovery snapshot |
| `project-watching` | 명시 등록 workspace의 기존 agent-ops task/roadmap watcher와 app-owned config watcher가 활성화됐다 | `workspace-claiming`, `config-pending` 또는 `stopped` | project registry와 watcher event |
| `workspace-claiming` | enabled workspace에서 auto-run 또는 resume가 요청됐다 | lease와 checkpoint가 유효하면 `reconciling`, 충돌·손상·판독 실패면 `failed` | canonical workspace identity, lease owner, checkpoint schema/runtime build revision |
| `reconciling` | lease 획득 또는 host restart 뒤 active task/checkpoint/process/archive/ledger를 대조한다 | `idle`, 동적 lineage의 다음 dependency-ready `work-ready`, live execution의 `running`, 재시도 가능한 `blocked` 또는 `failed` | process start identity, execution/attempt id, task별 active-pair loop와 locator, WORK_LOG archive baseline, valid complete evidence와 last-writer state |
| `config-pending` | agent 실행 중 새 유효 config revision이 관측됐다 | `running` 후 `work-ready` 또는 `idle` | 현재 execution은 기존 snapshot을 유지하고 다음 호출에 새 revision 적용 |
| `work-ready` | 기존 agent-task 또는 기존 priority-queue의 최상위 ready Milestone이 있거나 persisted route에 pinned selfcheck/resume이 준비됐다 | pinned selfcheck/resume은 selector 재평가 없이 `running`, 그 밖의 실행은 `selecting`, preview이면 비영속 `previewing`, 또는 `stopped` | project filesystem scan과 persisted route/continuation. 일반 요청으로 새 work item을 합성하지 않는다 |
| `previewing` | 사용자가 initial/resume/dependency/blocker preview를 요청했다 | persistent state transition 없이 caller로 반환 | 현재 filesystem, config revision과 immutable quota view로 만든 `PreviewResult`; checkpoint/project 파일/provider process를 변경하지 않는다 |
| `selecting` | stage/work-unit/config revision/quota snapshot으로 ordered rules를 평가한다 | 유효한 target이면 `running`, policy상 eligible target 부재면 `blocked`, malformed policy/route state면 `selection-error` | 외부 RouteDecision 하나와 ordered candidates·eligibility/rejection·rule/used history를 가진 durable PersistedRoutePlan |
| `running` | provider process가 immutable route/config snapshot으로 시작됐다 | `running`, worker/selfcheck 성공의 `submission-validating`, review 성공의 `review-validating`, `retrying`, `failing-over`, `blocked`, `failed` 또는 `cancelling` | runtime stream, heartbeat, process/session locator와 provider adapter의 normalized failure |
| `submission-validating` | 어떤 declared provider/model·execution 방식의 worker 또는 selfcheck process가 성공 종료했다 | worker가 pinned selfcheck 대상이면 actual completing target·persisted route와 PLAN/CODE_REVIEW pair·task/plan/tag identity 검증 뒤 worker-owned field matcher 전 selfcheck stage의 `work-ready`, selfcheck 불필요 worker 또는 selfcheck 완료는 provider-neutral matcher 통과 뒤 official review stage의 `work-ready`, Pi selfcheck 뒤 미완성은 `selfcheck-evidence-repairing`, 그 밖의 보완 가능 상태는 bounded `retrying`, 계약 위반·한도 소진은 `blocked` | completing decision, locator와 project workflow adapter의 pair·identity·worker-owned field assessment; Pi 전용 matcher bypass가 없다 |
| `selfcheck-evidence-repairing` | Pi selfcheck가 성공했지만 CODE_REVIEW matcher가 worker-owned field 미완성을 반환했고 직전 selfcheck native session/context identity가 유효하다 | dispatch intent를 선기록한 뒤 같은 native context의 `running` 후 `submission-validating`, 이미 외부에서 완성됐거나 응답 뒤 matcher가 통과하면 `selfcheck_done`·repair `validated`·pending 제거를 원자 commit하고 official review stage의 `work-ready`, cancel이면 repair intent/ordinal을 보존한 `cancelling`, budget 소진·identity·unknown-delivery 오류면 `blocked` | persisted repair intent, selfcheck execution/attempt와 native locator, matcher snapshot/revision/missing field, incomplete ordinal, prompt dispatch/response state, 고정 영문 prompt 및 selector/quota-probe/new-session 0회 evidence |
| `review-validating` | official review process가 성공 종료했다 | valid PASS finalization은 `reconciling`, WARN/FAIL follow-up은 `work-ready`, USER_REVIEW는 `blocked`, 무변경 budget 내에서는 `retrying`, invalid finalization은 `failed` | exact verdict section, 새 artifact fingerprint, filesystem state와 no-progress count |
| `retrying` | 알려진 동일-target 복구 가능 오류와 failure budget이 남았다 | bounded backoff 뒤 `running`, stop/cancel이면 `cancelling`, 한도·비복구 오류면 `blocked` 또는 `failed` | typed failure, transition history, retry ordinal/deadline과 cancellation evidence; restart에도 같은 retry를 중복 예약하지 않는다 |
| `failing-over` | provider adapter가 quota/context/model/stream failure를 확정해 failover 평가가 필요하다. quota이면 base admission snapshot을 참조하는 별도 runtime observation을 생성하고 app-global key 갱신을 요청한다 | route/context의 fault-atomic commit 뒤 `running`, alternate 부재 또는 준비·commit 오류 시 exact pre-state를 보존한 `blocked` | 같은 work-unit/candidate order/used history, runtime observation, selected route와 identity가 일치하는 readable locator package 및 durable continuation handoff |
| `cancelling` | 사용자가 project/app 자동 실행을 중단했다 | `stopped` 또는 `failed` | cancel event, process group/session termination evidence |
| `completed` | 한 task의 official review valid PASS, 유일한 project-owned complete archive와 runtime ledger finalization이 함께 확인됐다 | 새로 해제된 dependency-ready task는 자신의 active-pair loop로 `work-ready`, lineage terminal closure면 `reconciling` 뒤 `idle` | review artifact, complete evidence, START/FINISH ledger, task별 loop와 project filesystem state. 개별 task 완료는 task-group WORK_LOG archive가 아니다 |
| `blocked` | 알려진 failure에서 eligible alternate가 없거나 failure budget이 소진되어 해당 work unit을 더 진행할 수 없다 | identity가 일치하는 사용자 재시도 또는 policy-authorized status refresh의 `recovery-pending`, 그 밖에는 유지 | work-unit blocker와 project log. 독립 project/branch는 계속 실행 |
| `recovery-pending` | recovery trigger의 blocker/route/work-unit/selected-target과 readable locator package identity가 현재 persisted state와 일치한다 | persisted route와 continuation handoff commit 뒤 `running`, 재입장 불가 시 `blocked`, validation·준비·commit 오류 시 기존 state를 보존한 `recovery-pending` | recovery intent, fresh provider status, pending handoff/attempt locator와 exactly-once consume evidence |
| `failed` | unknown/unrecoverable 오류, invalid provider/config 또는 전이 준비·commit 오류가 발생했다 | `idle`, 독립 project의 `work-ready`, 또는 사용자 수정 뒤 `config-validating` | surfaced error와 project log. 기존 route/history/recovery intent는 손상하지 않는다 |
| `stopped` | auto-run off, project stop 또는 D01에서 정의한 app 종료가 완료됐다 | `config-validating` 또는 `project-watching` | 명시 재시작/enable event |

## Interface Contract

- 계약 원문: 현재 Node 경계는 [Edge-Node Runtime Wire](../../../../../agent-contract/inner/edge-node-runtime-wire.md)와 [Edge Config Runtime Refresh](../../../../../agent-contract/inner/edge-config-runtime-refresh.md)를 유지한다. 공통 runtime host/config/event schema는 구현 계획 전에 agent-contract create/update gate로 별도 고정한다.
- 입력:
  - `HostConfig`: host kind, app-owned config revision, provider catalog, selection policy, log/state root, background lifecycle와 runtime defaults다.
  - `ProjectRegistration`: stable project registration id, canonical workspace instance, enabled/auto-run flag와 app config tree 안의 override key다. workspace-local runtime config location을 가리키지 않는다.
  - `WorkspaceLease`: canonical workspace instance, owner host/manager identity, acquired/renewed-at과 lease generation이다. 같은 workspace에서 invocation 권한을 한 owner에게만 부여한다.
  - `WorkRequest`: project/workspace identity, project workflow가 이미 선택한 task 또는 Milestone path, stage/work-unit identity, dependency state와 optional persisted route다. 일반 사용자 요청이나 direct/Plan/Milestone 분류 입력이 아니다.
  - `PreviewRequest`: project/workspace, optional task selection과 initial/resume mode다. runtime execution과 같은 config/quota/dependency 판정기를 사용하지만 state·filesystem·provider side effect를 허용하지 않는다.
  - `ProjectWorkflowAdapter`: project-owned artifact contract를 해석해 active pair/identity, active CODE_REVIEW의 worker-owned field completeness, contract-valid USER_REVIEW blocker, review artifact visibility, exact verdict, progress와 finalization state를 normalized assessment로 반환하는 경계다. 필수 section, placeholder와 checklist 완료 여부는 versioned 정규식/구조 matcher set으로 검사하고 동일 set을 Pi를 포함한 모든 declared provider/model, local/cloud execution class와 one-shot/persistent worker에 적용한다. Pi selfcheck 뒤 incomplete assessment는 missing field와 allowed action `same-context-selfcheck-evidence-repair`를 반환하고 manager가 native context resume과 prompt를 소유한다. USER_REVIEW는 파일명만으로 승인하지 않고 상태·유형·대상·차단 근거·미해결 결정·재개 조건이 실제 다음 단계를 막는지 판정한다. active/archive recovery source는 exact basename grammar, ASCII numeric suffix ordering, regular-file와 work-unit identity로 결정하고 mtime·Unicode digit·유사 이름을 canonical source로 승인하지 않는다. 공통 core에 skill/rule 원문을 복제하지 않는다.
  - `ProviderProfile`: stable provider/profile id, executable/args/env reference, renderer/emitter/session/status capability와 approval bypass mapping이다.
  - `SelectionPolicy`: default provider/model과 ordered conditional rule array다. app registry의 project override를 적용한 뒤 평가하며 첫 일치 rule이 승리한다.
  - `NodeCompatibilityPolicyFixture`: 선행 selector Milestone에서 freeze한 KST 경계, G01~G10 worker route, 공식 review 전용 route, 단방향 failover/bounce 금지와 completing-target selfcheck다. Node 기본 선택 정책의 conformance 입력이며 공통 evaluator 구현에 모델명·failover chain을 하드코딩하지 않는다.
  - `NodeCompatibilityBehaviorFixture`: stage/selfcheck/review no-progress 10회 budget, work-unit/candidate별 unknown 1회 admission, target/write-set dispatch barrier 부재, tool phase 밖 3분 silence inspection, 새 tool/file/state 변화 없는 동일 normalized chunk 3회 반복의 observation-only 처리, contract-valid USER_REVIEW 판정과 Pi post-selfcheck same-context evidence repair다. Pi repair prompt는 `The code review file has not been filled in. Fill in every missing implementation-owned field in {CODE_REVIEW_PATH}. Do not perform the official review.`이고 같은 selfcheck native context와 incomplete budget을 사용한다. Node 기본 runtime 동등성 입력이며 공통 core나 Desktop/project 정책에 threshold·provider 이름을 하드코딩하지 않는다.
  - `QuotaSnapshot`: provider credential/profile별 app-global `available | exhausted | unknown | not_applicable`, cap/remaining/reason/snapshot id/checked-at이다. 같은 key를 쓰는 모든 project가 admission에서 공유하며 batch 동안 immutable하다.
  - `QuotaProbeIdentity`: credential/profile, adapter, target, status command/profile과 ordered required-cap set이다. 모든 필드가 같은 조회만 admission batch에서 재사용한다.
  - `RetryEvidencePackage`: execution/attempt, work-unit, stage/role, terminal failure class, selected route, locator와 workspace/task/PLAN/raw/normalized artifact identity다. 모든 identity와 readable regular artifact가 현재 blocker에 일치해야 recovery intent 입력이 된다.
  - `ConfigRevision`: 현재 execution이 고정한 immutable revision이다. watcher의 새 revision은 다음 agent invocation 전에만 교체한다.
- 출력:
  - `RouteDecision`: 외부에 노출하는 정확히 하나의 provider/profile/model, persisted route plan id, reason, matched rule index, quota snapshot, config revision과 evaluated-at이다.
  - `PersistedRoutePlan`: schema revision, task/plan/tag generation, stage/work-unit pin, ordered candidates와 각 eligibility/rejection reason, applied rule/priority, selected target, used/unknown-admission history, transition과 pin revision이다. resume/failover는 이를 재사용하고 현재 시각으로 새 candidate를 만들지 않는다. schema나 selected/candidate/history identity가 손상되면 명시 오류가 된다.
  - `PreviewResult`: 선택된 target 또는 blocked/waiting 상태, persisted/예상 route evidence, dependency와 quota view 및 side-effect counter다. preview 전후 state/filesystem deep equality와 provider invocation 0회를 검증할 수 있어야 한다.
  - `RuntimeEvent`: start, stdout/stderr delta, normalized delta, provider phase와 matching tool-call/result activity, silence/repetition inspection, heartbeat, session/process locator, selfcheck evidence-repair ordinal·dispatch·response·validation, retry/failover, complete, error, cancelled다.
  - `WorkspaceCheckpoint`: schema revision, runtime build/config revision, active work-unit/stage/persisted route plan, attempt별 pinned task/pair loop, execution/attempt/process/session identity, active task-group WORK_LOG path와 전체 월별 archive에서 계산해 별도로 고정한 timeline archive ordinal, continuation handoff, pending selfcheck evidence-repair의 ordinal·matcher snapshot·dispatch/response state, retry deadline, failure budgets와 finalization state다. 원자적으로 저장하며 project 작업 원문을 복제하지 않는다.
  - `ExecutionLedgerRecord`: monotonic sequence, pinned task/pair loop, execution/work-unit/attempt identity, runtime build, START/FINISH·transition·terminal result와 locator/archive reference다. runtime이 작성하고 project log/`WORK_LOG` lifecycle을 재조정하는 근거다.
  - `WorkLogRecord`: `seq | time | loop | event | task | role | attempt | model | result | locator`의 고정 schema다. `seq`는 active task-group log의 event 순서, `loop`는 그 attempt가 시작한 task의 active PLAN/CODE_REVIEW pair future archive suffix, `attempt`는 같은 task/pair/role의 호출 회차다. 정상 active pair에서는 같은 task의 exact `plan_*.log`/`code_review_*.log` count와 pair metadata가 loop에 일치해야 하며, 0~10 archive 뒤 active pair는 loop 11이다. loop는 START 전에 checkpoint/ledger/locator에 pin하고 matching FINISH가 filesystem의 후속 pair나 task archive 상태를 다시 계산하지 않고 같은 값을 사용한다. 같은 pair의 retry·resume은 loop를 유지하고 WARN/FAIL archive와 follow-up pair materialization 뒤 다음 attempt에서만 증가한다. 서로 다른 task 행은 각자의 loop를 가지며 task-group `work_log_N.log` suffix와 독립이다. timeline archive N은 같은 task group의 전체 월별 exact `work_log_N.log` suffix 최대값 다음 수(없으면 0)를 별도로 고정한다. locator가 pinned loop, provider native context/session id, process identity와 stream/heartbeat 경로를 포함한 attempt metadata의 권위 포인터이므로 별도 `context_id` 컬럼은 만들지 않는다.
  - `WorkflowArtifactAssessment`: adapter/schema/matcher revision, task/plan/tag identity, actual provider/model/execution class, pair validity, USER_REVIEW validity/blocking reason, matched/missing/placeholder/unchecked worker fields, artifact visibility preflight, review verdict/fingerprint/finalization과 allowed next action이다. provider별 bypass 없이 같은 matcher 결과를 반환하며 Pi selfcheck 뒤 미완성에는 `same-context-selfcheck-evidence-repair`만 허용한다. review progress fingerprint는 plan-declared write-set source와 review/finding artifact를 사용하고 runtime-owned WORK_LOG/heartbeat는 제외한다.
  - `SelfcheckEvidenceRepair`: work-unit/task/plan/tag와 CODE_REVIEW path, completing route/config revision, 직전 성공 Pi selfcheck execution/attempt/native session/context locator, matcher revision·artifact fingerprint·missing fields, 고정 영문 prompt/hash, incomplete ordinal, dispatch attempt identity와 `pending | dispatch-recorded | response-observed | validated` 상태다. matcher를 prompt 직전에 다시 실행하고 incomplete이면 해당 ordinal의 dispatch intent를 원자 저장한 뒤 같은 native context를 resume한다. 정상 경로는 ordinal당 exactly-once이고 restart는 live/terminal attempt를 reconcile한다. dispatch 여부가 불명확하면 blind resend 대신 task-local blocker가 되며, matcher 통과 commit은 `selfcheck_done`, repair `validated`, pending 제거와 official-review work-ready를 함께 확정한다. 새 selection, quota probe 또는 fresh session을 만들지 않고 worker/review failure budget과 route used history를 변경하지 않는다.
  - `ProviderFailure`: provider/profile, typed class, provider-confirmed 여부, source, bounded evidence, signal과 observed-at이다. provider codec이 생성하며 work-unit role이나 route 결정을 포함하지 않는다.
  - `RuntimeQuotaObservation`: observation id, credential/profile key, target, status, base admission snapshot id, provider failure reference와 observed-at이다. app quota service의 후속 admission 갱신과 현재 work-unit failover가 같은 관측을 참조한다.
  - `WorkUnitBlocker`: work-unit/stage, persisted route plan id, selected target, terminal failure class, retry evidence package와 provider failure 또는 runtime observation reference다. AgentTaskManager가 생성한다.
  - `ContinuationHandoff`: handoff id, work-unit/route/previous-next target, source locator와 workspace/task/PLAN/raw/normalized artifact identity, exact continuation payload 및 `pending | locator-recorded | consumed` 상태다.
  - `RecoveryIntent`: blocker/route/work-unit/selected-target identity, trigger, persisted candidate order/used history, validated locator package reference, continuation handoff id와 commit 상태다. attempt locator가 handoff identity와 source context를 durable하게 기록한 뒤 한 번만 소비한다.
  - `ProjectLogRecord`: execution/work-unit/project/task-pair loop identity로 persisted route plan/rule/candidate/reason, quota, config, process/session, stream/heartbeat, transition과 terminal 결과를 연결한다.
  - `ProviderStatus`: 외부에는 official provider/model/profile id로 보이는 discovery/readiness/authenticated state, capability, app-global quota/status와 오류 근거다. generic `cli` adapter는 Desktop 주 식별자가 아니다.
- 금지:
  - WorkRequest를 일반 사용자 요청 triage 계약으로 확장하거나 그 입력만으로 runtime core가 direct/Plan/Milestone을 분류·생성하지 않는다. 명시 요청한 task group이 관측·persist된 적이 없을 때 이를 empty completion으로 보고하지 않는다.
  - project-owned agent-ops Milestone·Plan·Code Review skill/rule을 공통 runtime에 복사·내장하거나 IOP 소유 의미로 재정의하지 않는다.
  - 같은 canonical workspace에서 둘 이상의 manager가 agent invocation을 시작하거나 lease 충돌·checkpoint 손상을 빈 초기 상태로 숨기지 않는다.
  - PID만, locator의 시간 경과만 또는 출력 silence만으로 live execution을 stale로 판정해 중복 호출하지 않는다.
  - 한 work unit의 blocker, review preflight 또는 scheduler control-plane 오류로 dependency-independent 실행을 취소하거나 ready branch의 drain을 중단하지 않는다.
  - dependency가 없는 서로 다른 task를 같은 target, overlapping/unknown plan write-set이라는 이유로 직렬화하지 않는다. write-set은 review progress 입력이며 dispatch lock이 아니다.
  - USER_REVIEW 파일 존재만으로 user-review terminal state를 만들거나 contract가 불완전·충돌한 문서를 정상 사용자 대기로 숨기지 않는다.
  - 자동 target 변경·failover·restart에서 stage failure budget을 초기화하거나 failure count를 새 initial route의 선택 조건으로 사용하지 않는다. 명시적 identity-matched `retry_blocked`만 blocker와 해당 stage budget을 초기화하고 route/history는 보존한다.
  - worker/reviewer에게 runtime START/FINISH timeline 작성을 맡기거나 동적 dependency lineage의 terminal closure, last writer 종료와 모든 task의 유일한 valid completion 확인 전에 task-group `WORK_LOG`를 이동·attempt log를 삭제하지 않는다.
  - dependency frontier가 새로 열릴 때 active `WORK_LOG`를 static batch별로 분리하지 않는다. 서로 다른 task의 loop를 하나의 group-wide 값으로 강제하거나 task loop를 `work_log_N.log` suffix에서 계산하지 않고, 같은 active pair의 restart·blocker·retry 또는 START 뒤 filesystem pair가 바뀐 FINISH에서 loop를 다시 계산하지 않는다. active pair metadata·plan/review count·checkpoint/locator/row loop나 독립 timeline archive ordinal 불일치를 추정 renumber로 숨기지 않는다.
  - loop 컬럼이 없는 archived `work_log_N.log`를 backfill·재작성하거나 active legacy `WORK_LOG.md`에 새 schema 행을 섞지 않는다. active legacy log는 기존 owner가 terminal closure로 archive한 뒤에만 새 runtime이 해당 task group의 다음 WORK_LOG를 생성한다.
  - worker process exit 0, 체크박스 표시 하나 또는 worker의 자체 완료 문구만으로 review-ready/completed를 확정하지 않는다.
  - 출력 silence나 동일 normalized chunk 반복 관측만으로 live process를 종료·block·retry·failover하지 않고, tool-running phase는 call/result identity가 모두 닫히기 전에 완료로 판정하지 않는다.
  - runtime-owned WORK_LOG/heartbeat 변화만으로 official review no-progress counter를 초기화하지 않는다.
  - AgentTaskManager가 worker 제출의 semantic correctness를 모델로 재검토하지 않는다. 구조 완결성은 workflow adapter가, 내용의 타당성은 official review agent가 판정한다.
  - submission artifact gate를 통과하기 전에 official review를 시작하거나 manager-owned 실행 timeline을 worker 제출 증거로 대체하지 않는다.
  - Pi가 아닌 provider, cloud execution, one-shot/persistent 방식이라는 이유로 active CODE_REVIEW의 required section/placeholder/checklist matcher를 생략하거나 provider별로 더 약한 완료 규칙을 적용하지 않는다.
  - Pi selfcheck 뒤 CODE_REVIEW 미완성을 fresh selfcheck context, 새 route·quota probe·session 또는 generic continuation prompt로 복구하지 않는다. 직전 성공 selfcheck context identity가 누락·불일치하거나 기록된 ordinal의 prompt delivery가 불명확하면 prompt를 보내거나 재전송하지 않고 task-local 오류로 표면화하며, pending repair/selfcheck pin을 해제하기 전에 official review를 시작하지 않는다.
  - official review가 collaboration/subagent 도구를 호출하거나 공식 verdict section 밖의 PASS/WARN/FAIL 문자열로 finalization하지 않는다.
  - Node와 Desktop host에 provider renderer/emitter/quota/error parser를 복제하지 않는다.
  - Desktop Agent가 Edge를 기동하거나 Edge config를 app 내부 실행 조건으로 요구하지 않는다.
  - Python process, Python module 또는 monitoring skill 호출을 runtime correctness에 사용하지 않는다.
  - invalid config/provider/auth/model/capability 또는 unknown 오류를 silent fallback으로 숨기지 않는다.
  - generic stderr만으로 provider quota/context/model failure를 확정하지 않는다.
  - AgentTaskManager가 provider raw stderr를 재파싱하거나 provider adapter의 unknown/generic result를 quota failure로 승격하지 않는다.
  - runtime quota observation을 기존 snapshot id의 수정본으로 저장하거나 immutable admission batch 및 이미 실행 중인 sibling route를 변경하지 않는다.
  - blocker 복구에서 현재 시간 기준 selection policy로 새 candidate를 만들거나 이미 떠난 target으로 bounce하거나 ordinary resume·sibling을 probe하지 않는다.
  - public RouteDecision만 저장하고 initial candidate order, eligibility/rejection, rule/priority와 used/unknown-admission history를 유실하지 않는다.
  - malformed/tampered persisted route plan, stage/work-unit pin 또는 selected/candidate/history 불일치를 현재 policy의 새 initial selection으로 덮어 복구하지 않는다.
  - credential/profile만 같다는 이유로 target, status command/profile 또는 required-cap set이 다른 quota probe를 합치지 않는다. local-first 뒤의 cloud 후보, persisted resume, selfcheck와 공식 review를 선행 probe하거나 unknown candidate의 1회 admission 상태를 batch/host restart에서 초기화하지 않는다.
  - preview가 checkpoint, route/history, failure budget, blocker/recovery intent, quota cache, project 파일을 생성·수정하거나 provider process를 시작하지 않는다.
  - non-empty locator 문자열만으로 retry evidence를 승인하거나 execution/attempt·stage/role·terminal failure·selected route·workspace/task/PLAN/raw/normalized identity가 누락·불일치한 package를 logical continuation에 사용하지 않는다.
  - route/context commit과 첫 invocation 사이의 pending handoff를 메모리에만 두거나 attempt locator 기록 전에 소비하지 않는다. save fault에서 absent key를 null로 남기는 부분 rollback도 허용하지 않는다.
  - same-target retry를 unbounded delay/loop로 실행하거나 stop/cancel 뒤 backoff를 계속하고 restart에서 같은 retry를 중복 예약하지 않는다.
  - route/context commit 성공 전에 recovery intent를 소비하거나 기존 decision/history를 덮어쓰지 않는다.
  - 실행 중 config revision이나 시간 경계만으로 현재 work unit의 pinned route를 바꾸지 않는다.
  - credential/token/raw secret을 app discovery result나 project log에 기록하지 않는다.
  - app store에 project의 roadmap/task/work-log 원문을 중앙 복제해 별도 source of truth를 만들지 않는다.

## Acceptance Scenarios

| ID | Milestone Task | Given | When | Then |
|----|----------------|-------|------|------|
| S01 | `provider-runtime` | Node와 Desktop이 동일 provider profile을 선언했다 | 각각 짧은 실행과 cancel을 수행한다 | 동일 common provider implementation과 event/failure 의미를 사용하고 host별 provider 복제가 없다 |
| S02 | `agent-task-manager` | agent-ops 작업 체계를 가진 project에 기존 task와 ready Milestone이 있다 | supervisor 모델 없이 auto-run을 시작한다 | 남은 task를 먼저 처리하고 이후 기존 priority queue를 순차 소비한다 |
| S03 | `host-boundary` | Node run request와 Desktop local request가 같은 logical provider target을 가리킨다 | 두 host가 실행한다 | Node는 기존 wire event로, Desktop은 local event로 변환하되 core lifecycle은 동일하다 |
| S04 | `parity-cutover` | current Milestone/work evidence, Python dispatcher/selector와 Node behavior inventory, loop 컬럼이 없는 archived work logs 및 active legacy WORK_LOG 유무가 있다 | 영역별 동작을 absorb/replace/not-applicable로 분류하고 cutover를 검증한다 | 미분류 동작이 없고 absorb/replace 행이 test/smoke evidence를 가지며 Python runtime dependency와 Node provider duplicate가 남지 않는다. legacy archive는 byte-identical이고 active legacy log가 있으면 mixed-schema append 없이 기존 owner의 terminal archive까지 cutover가 차단된다 |
| S05 | `provider-catalog` | declared provider가 설치·인증됨, 미설치, 미인증, model 미지원 상태 중 하나다 | read-only discovery를 실행한다 | 공식 계열 이름과 내부 id가 정규화되고 실행 불가 상태는 구체적인 오류가 된다 |
| S06 | `config-ownership` | agent가 revision A로 실행 중이고 app-owned project override revision B가 저장된다 | watcher가 B를 검증한다 | 현재 agent는 A로 끝나고 다음 호출은 B를 사용하며 invalid B면 새 dispatch가 config error로 중단된다 |
| S07 | `selector-policy` | default와 둘 이상의 겹치는 ordered rule이 있다 | Node 또는 Desktop 정책을 평가한다 | 첫 일치 rule의 provider/model 하나만 반환되고 host별 policy 차이가 core evaluator 의미를 바꾸지 않는다 |
| S08 | `quota-admission` | 서로 다른 project가 같은 provider credential/profile을 사용하고 같은 admission batch에 정상, exhausted, parser-error와 local key가 있다 | quota snapshot과 selection을 실행한다 | 같은 provider key는 app-global quota와 snapshot id를 공유하고 parser error는 해당 key의 unknown으로 격리되어 work unit별 한 번만 시도되며 다른 key의 cap이 되지 않고 local은 not_applicable이다 |
| S09 | `workspace-registry` | 같은 repository의 clone/worktree 두 경로와 다른 project가 등록됐다 | auto-run을 동시에 시작한다 | 각 canonical workspace instance가 독립 queue/log/session identity로 병렬 실행된다 |
| S10 | `task-order` | project A는 기존 active agent-task가 있고 project B는 기존 task가 없지만 ready priority item이 있으며 별도로 관측·persist된 적 없는 task group이 명시 요청됐다 | scheduler가 work를 고른다 | A는 active task를, B는 최상위 ready Milestone을 선택하고 blocked dependency는 건너뛰며 일반 요청에서 새 작업 파일을 만들지 않는다. unknown task group 요청은 empty completion이 아니라 typed state error다 |
| S11 | `concurrency-stop` | 여러 project가 병렬 실행 중이다 | 한 project를 사용자가 중단한다 | 해당 process group/session과 후속 auto-call만 멈추고 다른 project는 계속된다 |
| S12 | `session-recovery` | 실행 중 host가 비정상 종료되거나 persisted route 이후 본문·시간·config가 바뀌고, valid 또는 malformed/tampered route plan과 compatible native session 또는 cross-adapter locator가 남았다 | host가 filesystem/checkpoint/locator로 현재 stage를 복원한다 | valid pinned route는 유지되고 compatible identity만 native resume하며 cross-adapter는 동일 workspace/attempt의 검증된 artifact만 logical transfer한다. malformed route나 범위 밖·누락 artifact는 silent reselection 없이 명시 오류가 되고 in-memory/on-disk pre-state를 보존하며 재개는 한 번만 수행된다 |
| S13 | `stream-observer` | provider가 stdout/stderr, delta, matching·누락 tool-call/result, awaiting-model phase, 출력 공백, 새 tool/file/state 변화 없는 동일 normalized chunk 3회 반복과 terminal을 발생시킨다 | common runtime이 관측한다 | raw/normalized 순서와 phase/heartbeat/process identity가 남고 모든 call id가 result로 닫힐 때만 tool phase가 끝난다. silence·반복 신호만으로 종료/block/retry/failover하지 않으며 정확히 한 terminal event가 생성된다 |
| S14 | `failure-taxonomy` | Python 관측 fixture를 Go provider codec fixture로 옮겼고 manager에는 normalized result가 입력된다 | provider classifier와 manager transition을 실행한다 | codec은 context/quota/model/connection/stream/generic/process class를 반환하고 manager는 raw 문자열 재해석 없이 review-control/work-unit blocker를 결합한다 |
| S15 | `project-logs` | 실행이 select, run, runtime quota observation, app-global refresh, recovery/failover와 terminal 단계를 거친다 | project log를 조회한다 | persisted route plan/rule/candidate/reason, admission snapshot·runtime observation·provider failure·manager transition이 하나의 execution/work-unit identity로 연결되고 secret은 없다 |
| S16 | `surface-errors` | invalid config/provider/auth/model/capability 또는 unknown 오류가 발생한다 | Node와 Desktop에서 실행한다 | 양쪽 surface와 project log에 오류가 보이고 unknown은 silent retry/fallback하지 않는다 |
| S17 | `desktop-host` | 둘 이상의 project가 Desktop registry에 명시 등록됐다 | Edge와 Python 없이 app을 시작·중단·재시작한다 | common AgentTaskManager가 각 project lifecycle을 관리하고 자동 실행 toggle을 지킨다 |
| S18 | `flutter-shell` | clean macOS 사용자 환경에 app bundle이 있다 | 설치·실행·창 닫기·명시 Quit·login-start 설정을 확인한다 | Flutter shell과 Go runtime이 D01의 background lifecycle을 지키고 명시 Quit 뒤 orphan process가 없다 |
| S19 | `yaml-operations` | UI 편집 화면 없이 app-owned provider/global/project override 설정을 운영한다 | discovery 기반 생성, validation, reload와 조회를 수행한다 | 같은 config service/schema가 roundtrip되고 향후 Flutter UI가 재사용 가능한 scaffold가 있다 |
| S20 | `logged-in-smoke` | 실제 로그인된 지원 CLI와 macOS app bundle이 준비됐다 | discovery, run, stream, quota/status, cancel, config-next-call smoke를 실행한다 | provider/model/environment/result/evidence 경로가 smoke manifest와 project log에 남는다 |
| S21 | `workflow-ownership-boundary` | 등록 project에 기존 agent-ops work item은 없고 일반 코딩 요청만 있다 | AgentTaskManager auto-run이 작업을 탐색한다 | no-work/idle로 남고 Milestone/Plan을 분류·생성하지 않으며 별도 오케스트레이션이 WorkRequest를 제공해야 한다 |
| S22 | `runtime-quota-failover` | admission에서 available이던 Gemini target에 Agy codec이 confirmed quota failure를 반환했고 persisted route에 unused eligible alternate가 있거나 없다 | quota service와 AgentTaskManager가 normalized failure를 소비한다 | immutable base snapshot과 in-flight sibling은 유지되고 별도 runtime observation이 app-global key의 후속 admission 갱신과 현재 work unit에 연결되며, alternate가 있으면 같은 route/history와 locator/context로 전환하고 없으면 task-local blocker가 된다 |
| S23 | `blocked-failover-recovery` | 알려진 provider failure로 막힌 work unit에 사용자 재시도 또는 policy-authorized status refresh가 발생했다 | AgentTaskManager가 blocker와 persisted decision identity를 검증한다 | 새 initial route 없이 unused alternate와 현재 blocked target에 허용된 same-target retry만 평가하고 성공 commit 뒤 intent를 한 번 소비한다. identity mismatch나 status/route/context/commit 실패에는 기존 decision/history/intent가 유지된다 |
| S24 | `review-artifact-lifecycle` | Pi를 포함한 각 declared worker provider/model과 local/cloud·one-shot/persistent 방식이 complete, placeholder, unchecked, checklist-only, runtime identity mismatch 또는 pair/identity mismatch CODE_REVIEW를 만들고, official review가 artifact 비노출, arbitrary verdict, write-set/review artifact 무변경과 runtime WORK_LOG-only 변경, WARN/FAIL follow-up, USER_REVIEW, active/archive 유사 이름·ASCII/Unicode suffix·mtime 교란, verdict 후 restart 또는 valid PASS archive 중 하나를 만들었다 | project workflow adapter와 AgentTaskManager가 동일 matcher revision으로 completing route, submission completeness, canonical artifact와 persisted finalization state를 판정한다 | 모든 worker provider/execution matrix에서 actual target이 persisted route와 일치하고 필요한 pinned selfcheck 및 같은 정규식/구조 gate를 통과한 제출만 official review로 가며 incomplete case의 review invocation은 0회다. WORK_LOG-only 변화는 no-progress budget을 초기화하지 않고 exact basename/ASCII numeric suffix/regular-file/work-unit identity와 exact verdict/filesystem state가 일치한 전이만 허용되며 crash/restart에도 valid PASS archive가 정확히 한 번 task를 완료한다 |
| S25 | `workspace-runtime-ownership` | 같은 canonical workspace에 중복 manager, PID가 재사용된 locator, live child, 손상 checkpoint 또는 scheduler 예외가 있다 | host가 lease를 획득하거나 재시작 reconciliation을 수행한다 | invocation owner는 하나뿐이고 live child는 process start/attempt identity로 drain·인계되며 충돌·손상은 명시 오류가 되고 새 agent가 중복 시작되지 않는다 |
| S26 | `workflow-state-drain` | duplicate/incomplete active pair, valid·filename-only·불완전·충돌 USER_REVIEW, malformed identity, missing/ambiguous predecessor와 동일 target 또는 overlapping/unknown write-set의 독립 ready branch가 함께 있다 | project workflow adapter와 scheduler가 work set을 평가한다 | contract-valid USER_REVIEW와 invalid work unit만 대기·차단되고 target/write-set barrier 없이 독립 branch와 실행 중 agent는 계속되며 동일 task 중복 attempt만 배제되고 predecessor의 유일한 완료 뒤 follow-up이 정확히 한 번 실행된다 |
| S27 | `stage-failure-budget` | 한 worker가 primary와 alternate에서 실패하고 host가 재시작되며 별도 review stage도 실패했다 | 자동 retry/failover, stage success와 identity-matched `retry_blocked`를 수행한다 | worker budget은 자동 target/restart를 넘어 누적되고 review budget과 분리되며 stage 성공은 해당 budget을 초기화한다. 명시 retry는 해당 blocker/budget만 초기화하고 route/history를 보존하며 failure count는 새 route를 만들지 않는다 |
| S28 | `completion-ledger-reconciliation` | `11+10_unknown_isolation` task에 paired plan/review logs suffix 0~10과 active pair가 있고, task group에는 `work_log_0.log`~`work_log_2.log`가 있으며 다른 task들은 각자 다른 loop에서 병렬 실행된다. 1 완료 뒤 2·3, 2 완료 뒤 5·6이 해제되는 동안 same-pair retry/restart, WARN/FAIL follow-up, partial pair archive crash, task 소실, 새 completion archive 없음·복수 archive, orphan START, active last writer 또는 WORK_LOG archive 이동 실패가 있다 | manager가 checkpoint/filesystem/ledger, attempt별 pinned task/pair loop, 독립 timeline archive ordinal과 동적 dependency closure를 재조정한다 | 예시 task의 current-pair worker/selfcheck/review START·FINISH는 loop 11이고 same-pair retry는 attempt만 증가한다. WARN/FAIL review가 pair 11을 archive하고 follow-up을 만들어도 그 FINISH는 11이며 다음 START부터 12가 된다. 다른 task의 독립 loop도 같은 WORK_LOG에 기록된다. locator metadata에서 pinned loop와 context/session id를 조회하고 별도 context_id 컬럼은 없다. 유일한 valid task completion만 exactly-once 확정되고 lineage terminal closure와 last writer 뒤에만 task loop와 독립적인 `work_log_3.log` archive와 attempt-log cleanup이 수행된다. pair/count/checkpoint/locator/row identity나 timeline ordinal이 불명확하면 추정 renumber 없이 오류가 된다 |
| S29 | `selector-policy` | Node compatibility policy fixture에 KST 경계, G01~G10 worker, 공식 review route와 failover/selfcheck가 있고 일부 rule이 겹친다 | selection과 persisted route 저장 및 policy conformance를 실행한다 | 외부에는 우선 rule의 target 하나만 반환되며 내부 plan에는 ordered candidate/eligibility/rejection/rule/used history가 보존되고 공식 review는 worker quota route로 재평가되지 않으며 route/failover/selfcheck는 injected policy로 재현된다 |
| S30 | `quota-admission` | adapter/target/command-profile/required-cap 조합이 같거나 일부만 다른 후보와 local-first, resume, selfcheck, official review work가 여러 batch와 host restart를 지난다 | admission quota를 평가한다 | full probe identity가 같은 initial worker 조회만 재사용하고 다른 identity는 분리되며 local-first 뒤 cloud와 resume/selfcheck/review는 zero-probe이고 unknown의 1회 admission은 work-unit/candidate에 격리되어 batch/restart에도 초기화되지 않는다 |
| S31 | `agent-task-manager` | persisted state가 없거나 있는 여러 ready task에 initial/resume preview를 요청한다 | read-only preview를 반복한다 | 실행과 같은 route/dependency/blocker 결과를 반환하지만 state/filesystem/quota cache는 deep-equal이고 provider invocation은 0회이며 task 결과가 서로 오염되지 않는다 |
| S32 | `blocked-failover-recovery` | canonical 또는 execution/attempt·stage/role·failure·route·artifact identity가 malformed/missing/mismatched인 retry package, commit-before-invoke/locator-before-consume restart와 selector/context/checkpoint save fault가 있다 | identity 검증과 recovery commit/continuation을 수행한다 | valid package만 durable handoff가 되고 attempt locator 기록 뒤 exactly once 소비된다. invalid package는 marker 없는 pinned resume이며 모든 fault에서 absent key를 포함한 blocked task와 정상 sibling의 in-memory/on-disk exact state가 보존되고 commit 전 provider invocation은 0회다 |
| S33 | `stage-failure-budget` | same-target recoverable failure가 반복되고 backoff 중 stop 또는 host restart가 발생한다 | retry scheduler를 실행한다 | delay가 선언된 상한 안에서 증가하고 stop/cancel은 즉시 해제하며 restart 후 retry가 중복되지 않고 stage budget/route는 기존 규칙대로 유지된다 |
| S34 | `parity-cutover` | final Python selector/dispatcher evidence와 전체 Node policy/behavior fixture가 freeze됐다 | 한 work unit의 select→pin/resume→recovery/failover→blocker→selfcheck/completion audit, provider conformance와 behavior fixture suite를 실행한다 | work-unit/rule/candidate/reason/quota/transition trace가 끝까지 연결되고 declared provider의 primary/alternate/no-alternate와 Node 기본 budget/admission/scheduling/observation/review 의미가 재현되며 stale Python monitoring/static route/cap 의존성은 zero-match다 |
| S35 | `review-artifact-lifecycle` | Pi가 작업·검증·selfcheck를 성공 종료했지만 CODE_REVIEW matcher가 미완성을 반환했고 직전 selfcheck native context와 incomplete budget이 남아 있다 | manager가 제출 상태를 다시 확인하고 필요한 경우 고정 영문 evidence-repair prompt를 보낸다 | 이미 파일이 완성됐으면 prompt 0회로 selfcheck pin과 pending repair를 원자 해제한 뒤 official review가 시작된다. 미완성이면 dispatch intent/attempt identity를 먼저 저장하고 같은 selfcheck session/context에서 각 incomplete ordinal의 prompt를 exactly once 전달하며 매 응답 뒤 matcher를 재실행해 통과 전 review 0회, 통과 commit 뒤 review 1회가 된다. restart는 live/terminal attempt를 reconcile하고 delivery outcome 불명은 blind resend 없는 task-local blocker가 된다. 반복 미완성은 durable budget/repair intent를 유지하고, cancel은 review 0회인 stopped/resumable 상태로 전이하며, identity 누락·불일치는 fresh context 없이 task-local blocker가 된다 |

## Evidence Map

| Scenario | Required Evidence | `agent-task` 연결 | 완료 Evidence 기대 |
|----------|-------------------|------------------|---------------------------|
| S01 | shared provider conformance test와 duplicate implementation search | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `provider-runtime` Roadmap Completion, Node/Desktop test output |
| S02 | deterministic scheduler integration test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `agent-task-manager` Roadmap Completion, no-supervisor execution trace |
| S03 | Node wire adapter와 Desktop host contract test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `host-boundary` Roadmap Completion, event mapping evidence |
| S04 | 영역별 Python/Node inventory, disposition-complete parity matrix, code search, legacy archive byte-equality와 active legacy WORK_LOG cutover-block test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `parity-cutover` Roadmap Completion, zero-unclassified matrix·no-mixed-schema·legacy preservation evidence links |
| S05 | provider discovery table tests와 authenticated readiness smoke | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `provider-catalog` Roadmap Completion, discovery/error output |
| S06 | config merge/watcher/revision integration test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `config-ownership` Roadmap Completion, A/B revision trace |
| S07 | ordered selector rule matrix for Node/Desktop policies | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `selector-policy` Roadmap Completion, selected rule/reason output |
| S08 | Go usage parser, batch isolation, unknown-once와 local not-applicable tests | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `quota-admission` Roadmap Completion, snapshot id/error isolation evidence |
| S09 | multi-project and same-repo clone integration test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `workspace-registry` Roadmap Completion, independent identity/log evidence |
| S10 | remaining-task/priority/dependency와 unobserved explicit task-group scheduler matrix | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `task-order` Roadmap Completion, selected work와 typed state-error trace |
| S11 | concurrent project cancellation and orphan-process test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `concurrency-stop` Roadmap Completion, unaffected project trace |
| S12 | crash/restart native compatibility, malformed/tampered route rejection, cross-adapter context scope와 logical-transfer test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `session-recovery` Roadmap Completion, no-silent-reselection·single-resume·no-foreign-session evidence |
| S13 | fake emitter exact tool phase/silence/repetition tests plus actual CLI stream/cancel smoke | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `stream-observer` Roadmap Completion, ordered events/observation-only signals/single terminal evidence |
| S14 | provider codec conformance fixture와 manager no-raw-reparse test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `failure-taxonomy` Roadmap Completion, provider/manager responsibility table |
| S15 | snapshot/observation/failure/transition log schema golden test와 secret scan | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `project-logs` Roadmap Completion, linked trace and redaction evidence |
| S16 | Node/Desktop error matrix integration test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `surface-errors` Roadmap Completion, surfaced terminal/log evidence |
| S17 | Desktop multi-project lifecycle integration test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `desktop-host` Roadmap Completion, Edge/Python absence evidence |
| S18 | macOS app bundle install/window-close/quit/login-start smoke | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `flutter-shell` Roadmap Completion, bundle contents, lifecycle와 orphan check |
| S19 | YAML/discovery roundtrip and config service test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `yaml-operations` Roadmap Completion, schema/reload evidence |
| S20 | actual logged-in macOS field-smoke manifest | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `logged-in-smoke` Roadmap Completion, environment/result/evidence manifest |
| S21 | workflow ownership contract test와 common package dependency scan | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `workflow-ownership-boundary` Roadmap Completion, no-work/no-artifact trace |
| S22 | provider-agnostic primary/alternate/no-alternate conformance, Agy quota positive/negative codec fixture, runtime observation/app-global refresh test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `runtime-quota-failover` Roadmap Completion, provider/manager boundary와 batch/sibling isolation evidence |
| S23 | manual/auto trigger, identity, persisted-route boundary, status/context/commit failure와 exactly-once continuation matrix | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `blocked-failover-recovery` Roadmap Completion, decision/history/intent와 saved-locator evidence |
| S24 | all-provider/model/execution submission matcher, completing route/selfcheck, canonical archive, artifact visibility, exact verdict와 write-set/review/runtime-log fingerprint, no-progress/finalization/restart matrix | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `review-artifact-lifecycle` Roadmap Completion, matcher revision·provider matrix·incomplete review invocation-zero·runtime-log exclusion·exactly-once PASS evidence |
| S25 | duplicate manager/lease, process identity, corrupt checkpoint, scheduler-exception/restart integration matrix | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `workspace-runtime-ownership` Roadmap Completion, single-owner와 no-duplicate evidence |
| S26 | task topology/dependency ambiguity, USER_REVIEW contract와 same-target/overlapping-write-set independent-branch drain test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `workflow-state-drain` Roadmap Completion, task-local blocker·no-write-set-barrier·follow-up once trace |
| S27 | cross-target/restart stage budget, explicit retry와 worker/review isolation test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `stage-failure-budget` Roadmap Completion, durable counter/reset evidence |
| S28 | same-task paired plan/review archive 0~10→active loop 11→follow-up loop 12 fixture, START/FINISH loop pin, concurrent task별 독립 loop, group work_log 0~2→independent archive 3, 1→2·3→5·6 dynamic frontier, row/checkpoint/locator/pair-count identity, partial archive/restart/blocker/retry/crash와 cleanup ordering test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `completion-ledger-reconciliation` Roadmap Completion, per-attempt pair loop·same-pair retry stability·no-static-batch-split·exact independent `work_log_3.log`·exactly-once archive evidence |
| S29 | Node compatibility policy fixture와 external decision/persisted plan golden test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `selector-policy` Roadmap Completion, KST/G/review/failover/selfcheck와 route-plan evidence |
| S30 | full probe identity dedupe, initial-worker-only/zero-probe와 unknown-once restart test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `quota-admission` Roadmap Completion, probe/admission call ledger와 durable isolation evidence |
| S31 | initial/resume multi-task preview state/filesystem deep-equality와 invocation-zero test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `agent-task-manager` Roadmap Completion, preview result와 no-side-effect evidence |
| S32 | full retry evidence identity, two-phase handoff, restart/save-fault와 in-memory/on-disk sibling deep-equality matrix | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `blocked-failover-recovery` Roadmap Completion, pre-state/pending/locator/consume와 pre-commit invocation-zero evidence |
| S33 | bounded backoff, cancellation과 restart dedupe fake-clock test | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `stage-failure-budget` Roadmap Completion, delay/cancel/retry ledger evidence |
| S34 | end-to-end selector audit, provider conformance, full Node policy/behavior fixture suite와 stale dependency search | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `parity-cutover` Roadmap Completion, linked trace·behavior parity·zero-match evidence |
| S35 | Pi post-selfcheck matcher before/after fixture, exact prompt/hash capture, native session/context identity equality, ordinal별 dispatch ledger, live/terminal/unknown-delivery restart와 budget/cancel/identity matrix, selector/quota-probe/new-session/review invocation counters | `agent-task/m-shared-agent-task-runtime-desktop-agent/...` | `review-artifact-lifecycle` Roadmap Completion, persisted repair intent·same-context trace·deduplicated prompt·matcher 재검증·atomic selfcheck-pin/pending clear·review 0→1 evidence |

## Cross-repo Dependencies

- 없음. 같은 IOP monorepo 안에서 공통 package, Node host, Desktop host와 Flutter shell을 함께 관리한다.
- 구현 순서 선행 조건은 [Agent Task 동적 실행 Target Selector](../../../phase/automation-runtime-bridge/milestones/agent-task-runtime-target-selector.md), [Pi CLI Provider Integration](../../../../phase/automation-runtime-bridge/milestones/pi-cli-provider-integration.md), [CLI Agent Group Grade Routing](../../../../phase/automation-runtime-bridge/milestones/cli-agent-group-grade-routing.md)의 Milestone 결과다.

## Drift Check

- [x] Milestone 기능 Task와 Acceptance Scenario가 일치한다.
- [x] Evidence Map이 code-review/complete.log에서 검증 가능하다.
- [x] agent-contract를 쓰는 경우 SDD에 계약 원문을 복제하지 않았다.
- [x] 기존 D01은 [범위 이관 기록](user_review_0.log)으로 남겼고 현재 구현 gate의 사용자 결정으로 사용하지 않는다.

## 사용자 리뷰 이력

- [user_review_0.log](user_review_0.log) — 결합된 Desktop 범위를 후속 Flutter·Unity Milestone으로 분리하면서 D01을 현재 CLI gate에서 이관했다.

## 작업 컨텍스트

- 대체 상태: 결합된 runtime/Desktop 구현 입력으로는 사용하지 않는다. CLI 요구사항은 [IOP Agent CLI Runtime SDD](../../../../sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md)로 이관했고 Flutter·Unity lifecycle은 후속 Milestone에서 다시 작성한다.
- 표준선: `packages/go/agentruntime`이 provider와 AgentTaskManager의 유일한 구현이 되고, Node는 기존 runtime wire bridge, Desktop은 app lifecycle/registry/local IPC host가 된다. Desktop은 Flutter가 Go sidecar를 관리하는 topology를 기본안으로 삼는다.
- 표준선: app-owned YAML config tree가 provider/global 설정과 registry id별 project override를 모두 소유한다. map/scalar는 project override가 덮어쓰고 ordered selection rule array는 전체 교체한다. workspace-local runtime YAML은 권위가 아니다. 실행 중 agent는 immutable config revision으로 끝나며 다음 호출에만 새 revision을 적용한다.
- 표준선: project task/roadmap/work-log/log가 durable source of truth이고 app store는 provider/global config, registry와 최소 checkpoint만 소유한다. canonical workspace instance가 clone/worktree/branch 병렬성의 identity 경계다.
- 표준선: 동등성 inventory는 구현 계획 직전에 active Milestone, 최종 PASS·`complete.log`와 work log를 다시 읽어 freeze한다. 미종결 active plan/review는 gap evidence로만 사용하고 Python의 function/marker/state key는 복제하지 않는다. Python behavior는 provider fixture와 AgentTaskManager 상태 전이 테스트로 변환하되 production dependency로 남기지 않는다.
- 표준선: 외부 selector API는 선택된 provider/model 하나를 반환하지만 checkpoint에는 ordered candidate/eligibility/rejection/rule/used/unknown-admission history를 가진 persisted route plan을 저장하고 malformed/tampered identity를 silent reselection하지 않는다. 선행 Python의 KST/G/review route와 failover/selfcheck는 Node compatibility policy fixture다. 10회 budget/no-progress, unknown-once, no-target/write-set-barrier, tool phase 밖 3분 silence와 새 tool/file/state 변화 없는 3회 exact-repeat observation 및 USER_REVIEW 판정은 별도 behavior fixture다. 둘 다 Desktop/app project policy와 공통 evaluator 코어를 고정하지 않는다.
- 표준선: quota admission probe identity는 credential/profile, adapter, target, status command/profile과 ordered required caps 전체다. 최초 worker의 필요한 후보만 probe하고 persisted resume, selfcheck와 공식 review는 pinned decision/status를 사용하며 unknown 1회 admission은 work-unit/candidate에 durable하게 귀속한다.
- 표준선: Python의 dry-run은 공통 AgentTaskManager read-only preview behavior fixture로 흡수한다. Python CLI flag나 출력 형식을 복사하지 않고 동일 판정과 no-side-effect 불변조건만 유지한다.
- 표준선: retry continuation은 execution/attempt·stage/role·failure·route·artifact identity를 검증한 package, durable pending handoff와 attempt locator의 two-phase handoff로 대체한다. commit/invoke restart와 save fault에서도 in-memory/on-disk exact pre-state·sibling isolation을 보존하고 same-target retry는 bounded/cancellable policy를 따른다.
- 표준선: 실제 로그인 smoke는 fake/unit test를 대체하지 않고 release acceptance evidence로 추가한다. 인증 정보는 기록하지 않는다. Desktop은 official provider/model/profile naming만 사용자 표면에 사용한다.
- 표준선: 등록 project의 agent-ops가 Milestone·Plan·Code Review skill/rule과 작업 파일 의미를 소유하고, 공통 runtime은 이미 선택된 work step의 scheduling/provider execution만 소유한다. 일반 요청 분류와 IOP 소유 skill/tool-call 생성은 별도 [에이전트 작업 루프 오케스트레이션 MVP](../../../../phase/automation-runtime-bridge/milestones/agent-workflow-loop-orchestration-mvp.md)가 이 runtime을 소비해 수행한다.
- 표준선: Python의 active pair, contract-valid USER_REVIEW, local selfcheck checklist, exact verdict/fingerprint, no-progress와 archive 판정을 fixture로 가져오되 Pi에만 적용되던 CODE_REVIEW 정규식 완료 gate, non-empty checkbox 판정과 다른 provider의 사전 gate 부재는 gap evidence다. Go workflow adapter는 provider/model/local-cloud/one-shot-persistent 구분 없이 동일한 versioned 정규식/구조 matcher gate를 적용하고 semantic review는 official review role에 남긴다. plan write-set은 dispatch barrier가 아니라 review progress fingerprint 입력이고 runtime WORK_LOG/heartbeat-only 변화는 progress가 아니다. exact repeated normalized output과 silence inspection은 observation-only이며 terminal evidence를 대신하지 않는다.
- 표준선: Pi 작업·검증·selfcheck 완료 뒤 CODE_REVIEW가 비어 있어도 직전 성공 selfcheck context에 짧은 영문 지시를 주면 파일을 완성하는 관측을 필수 behavior fixture로 둔다. matcher는 provider-neutral하게 유지하고 보완 동작만 Pi profile의 same-context policy로 선언한다. 현재 Python처럼 incomplete 반복마다 새 selfcheck session을 만드는 동작은 흡수하지 않는다.
- 표준선: Python의 non-blocking lock, temporary replace, PID/start token/attempt marker와 archive baseline은 각각 workspace lease, atomic versioned checkpoint, live execution identity와 completion reconciliation의 behavior fixture다. Linux/Python 구현 세부를 공통 계약으로 복사하지 않는다.
- 표준선: stage failure budget은 work-unit/stage scope를 유지하고 자동 target 전환·restart에서는 보존한다. 명시적 identity-matched `retry_blocked`만 blocker와 해당 stage budget을 초기화하고 route/history는 유지한다. `WORK_LOG`는 runtime-owned timeline이며 worker/reviewer의 완료 주장을 manager ledger 대신 신뢰하지 않는다. 각 attempt의 loop는 task별 active PLAN/CODE_REVIEW pair archive 회차로 START부터 FINISH까지 고정되고 같은 pair retry에서도 유지되며 follow-up pair의 다음 attempt에서만 증가한다. task-group `work_log_N.log` archive 회차는 전체 월별 suffix에서 별도로 고정하고 locator metadata가 pinned loop와 context/session id의 권위 위치다.
- 후속 SDD: 완성형 Flutter 설정 UI, Windows/Linux package, 외부 알림/dashboard 또는 remote control을 별도 Milestone으로 올릴 때 작성한다.
