docs(roadmap): stall watchdog 제거 작업을 준비한다

무출력 기반 종료 계층을 단계적으로 제거할 수 있도록 승인 SDD와 구현·리뷰 작업 경계를 feature 브랜치에 고정한다.
This commit is contained in:
toki 2026-08-15 09:22:10 +09:00
parent 8620512d32
commit a1816a7fac
12 changed files with 1103 additions and 0 deletions

View file

@ -67,6 +67,10 @@ Phase를 가로지르는 실제 다음 작업 선택은 [전역 마일스톤 실
- 경로: [[observe-02] Provider 부하 메트릭과 Live Queue Dashboard](milestones/provider-load-metrics-queue-dashboard.md)
- 요약: provider별 capacity 사용률, in-flight, queue 적체, queue wait를 Prometheus time series와 Grafana dashboard로 노출해 시간대별 live 부하 분석을 가능하게 한다.
- [계획] [liveness-01] Provider Stall Watchdog 제거
- 경로: [[liveness-01] Provider Stall Watchdog 제거](milestones/provider-stall-watchdog-removal.md)
- 요약: provider 무출력 시간을 실행 정지로 추정하던 Node watchdog과 전용 health probe·Edge recovery 계층을 제거하고 request hard timeout, caller cancel, transport terminal만 실행 종료 권한으로 유지한다.
- [스케치] [observe-03] 요청 실행 로그와 Usage Ledger 기반
- 경로: [[observe-03] 요청 실행 로그와 Usage Ledger 기반](milestones/request-execution-log-usage-ledger-foundation.md)
- 요약: 사용자 요청 하나의 device/provider/model 선택, queue/dispatch/start/first-token/end 시간, token breakdown, status/error를 구조화된 실행 로그와 usage ledger로 남기는 로그 시스템 개편 후보를 스케치한다.

View file

@ -0,0 +1,74 @@
# Milestone: [liveness-01] Provider Stall Watchdog 제거
## 위치
- Roadmap: [ROADMAP.md](../../../ROADMAP.md)
- Phase: [PHASE.md](../PHASE.md)
## 목표
provider가 일정 시간 HTTP body 또는 normalized progress를 내지 않는다는 이유만으로 정상 추론을 취소하지 않는다. Node response-stall watchdog과 그 전용 probe·failure·Edge recovery 계층을 제거하고 request hard timeout, caller cancel, provider terminal과 transport lifecycle만 종료 권한으로 유지한다.
## 상태
[계획]
## 승격 조건
- 없음
## 구현 잠금
- 상태: 해제
- SDD: 필요
- SDD 문서: [SDD.md](../../../sdd/operational-observability-provider-management/provider-stall-watchdog-removal/SDD.md)
- SDD 사유: Node/Edge lifecycle, API·proto·config 계약, provider health와 retry 의미를 함께 축소한다.
- 잠금 해제 조건:
- [x] SDD 잠금이 해제되어 있다.
- [x] SDD 사용자 리뷰가 없거나 승인/해결되었다.
- [x] Acceptance Scenario가 Milestone 기능 Task와 연결되어 있다.
- [x] Evidence Map이 완료 시 `complete.log``milestone-task` id별 집계와 최종 검증 evidence로 검증 가능하게 연결되어 있다.
- 결정 필요: 없음
## 범위
- Node normalized run과 provider tunnel의 no-progress timer, stall claim, attempt fence용 watchdog orchestration과 전용 health probe를 제거한다.
- `response_stalled` typed failure, `response_stall_timeout_ms` config/wire propagation과 전용 metric/log를 제거한다.
- Edge provider health overlay와 StreamGate의 typed-stall recovery·provider avoidance 경로를 제거한다.
- 기존 request hard timeout, provider HTTP client timeout, caller cancel, transport disconnect, provider terminal과 admission lease cleanup을 보존한다.
- 관련 contract, living spec, dev 운영 문서와 회귀 테스트를 현재 동작에 맞춘다.
## 기능
### Epic: [stall-removal] 추정 기반 Liveness 계층 제거
명시적 lifecycle 신호만 요청 종료와 자원 정리를 소유하도록 Node·Edge·계약·검증을 함께 단순화한다.
- [ ] [watchdog-removal] Node의 response-stall observer/watchdog, stall claim·fence, 전용 probe·failure·관측 계층을 제거하고 hard timeout·cancel·provider terminal의 exactly-once cleanup을 보존한다. 검증: Node 대상 package test와 race test에서 60초를 넘는 무출력 fixture가 watchdog terminal 없이 유지되고 hard timeout·cancel·provider terminal만 요청을 종료한다.
- [ ] [edge-recovery-removal] Edge의 typed-stall reception, provider health overlay, StreamGate stall recovery·provider avoidance 분기를 제거하고 일반 provider error와 transport terminal 처리를 보존한다. 검증: Edge service/OpenAI test에서 stall 전용 replay·overlay 전이가 사라지고 일반 오류·cancel·terminal·lease release가 한 번만 발생한다.
- [ ] [wire-config-cleanup] `response_stall_timeout_ms``response_stalled` 전용 proto/config/runtime 계약을 제거하고 protobuf field number를 재사용하지 않도록 보존한다. 검증: config/proto 생성·round-trip·compile 검증과 전체 symbol 검색에서 의도한 reserved/과거 문서 근거 외 실행 참조가 남지 않는다.
- [ ] [contract-spec-sync] Edge-Node runtime, config refresh, OpenAI surface 계약과 living spec, dev 가이드를 명시적 hard-timeout/cancel 소유권 기준으로 갱신한다.
- [ ] [dev-rollout] 동일 source ref로 Edge와 macOS/Linux/Windows Node를 rebuild·재배포하고 Pi `ornith:35b` 장시간 tool-call 경로를 검증한다. 검증: GX10/OneX provider에서 60초 무출력 구간이 있어도 `response_stalled` terminal 없이 완료하거나 명시적 hard timeout까지 유지되며 4개 Node와 provider queue가 정상 회복한다.
## 완료 리뷰
- 상태: 없음
- 요청일: 없음
- 완료 근거: 없음
- 검토 항목: 기능 Task별 `complete.log` evidence와 최종 dev rollout 검증
- 리뷰 코멘트: 없음
## 범위 제외
- 새 idle heuristic, heartbeat 또는 대체 watchdog을 추가하지 않는다.
- provider 내부 reasoning 상태를 추정하거나 heartbeat를 모델 progress로 재해석하지 않는다.
- request hard timeout 값, provider capacity·priority·route, output content filter 정책을 변경하지 않는다.
- 과거 archive 문서를 최신 설계로 재작성하지 않는다.
## 작업 컨텍스트
- 관련 경로: `apps/node/internal/node`, `apps/edge/internal/service`, `apps/edge/internal/openai`, `packages/go/execution`, `packages/go/config`, `proto/iop/runtime.proto`
- 표준선: 무출력은 provider 정지 증거가 아니다. 종료는 caller cancel, 명시적 provider/transport terminal 또는 전체 request hard timeout만 소유한다.
- 실행 순서와 차단 관계: [전역 마일스톤 실행 순서](../../../priority-queue.md)
- 관련 Milestone: [[observe-01] Node Provider 실행 Liveness 관측과 안전 복구](../../../archive/phase/operational-observability-provider-management/milestones/node-provider-execution-liveness-recovery.md)
- 확인 필요: 없음

View file

@ -54,6 +54,11 @@
2. [[observe-03] 요청 실행 로그와 Usage Ledger 기반](phase/operational-observability-provider-management/milestones/request-execution-log-usage-ledger-foundation.md)
요청별 provider/model 선택, timing, token, status/error를 구조화된 ledger로 남기는 기반을 스케치한다.
### liveness
1. [[liveness-01] Provider Stall Watchdog 제거](phase/operational-observability-provider-management/milestones/provider-stall-watchdog-removal.md)
provider 무출력 시간을 정지로 오판하는 watchdog과 전용 probe/recovery 계층을 제거하고 명시적 request·transport lifecycle만 유지한다.
### update
1. [[update-01] Update Plane 안정 프로토콜](phase/update-plane-self-update-foundation/milestones/update-plane-stable-protocol.md)

View file

@ -0,0 +1,99 @@
# SDD: Provider Stall Watchdog 제거
## 위치
- Milestone: [Milestone 문서](../../../phase/operational-observability-provider-management/milestones/provider-stall-watchdog-removal.md)
- Phase: [PHASE.md](../../../phase/operational-observability-provider-management/PHASE.md)
## 상태
[승인됨]
## SDD 잠금
- 상태: 해제
- 사용자 리뷰: 없음
- 잠금 항목: 없음
## 문제 / 비목표
- 문제: provider-originated output이 일정 시간 없다는 사실은 긴 prefill, reasoning 또는 tool-call 생성 중인 정상 실행과 멈춘 실행을 구분하지 못한다. 현재 Node watchdog은 이 모호한 신호로 attempt를 취소하고 typed failure, probe, provider health overlay와 Edge recovery까지 연쇄시켜 정상 요청을 부분 tool-call 상태로 종료한다.
- 비목표:
- 대체 idle heuristic 또는 새 watchdog 도입
- request hard timeout, queue timeout, provider capacity·priority·route 정책 변경
- output content filter 또는 StreamGate 일반 terminal 계약 재설계
## Source of Truth
| 영역 | 기준 | 메모 |
|------|------|------|
| Roadmap | [Milestone 문서](../../../phase/operational-observability-provider-management/milestones/provider-stall-watchdog-removal.md) | 제거 범위와 완료 Task 원장 |
| Code | `apps/node/internal/node`, `apps/edge/internal/service`, `apps/edge/internal/openai` | 현재 watchdog, health handoff와 recovery 구현 |
| Contract | [Execution Runtime](../../../../agent-contract/inner/execution-runtime.md), [Edge-Node Runtime Wire](../../../../agent-contract/inner/edge-node-runtime-wire.md), [Edge Config Refresh](../../../../agent-contract/inner/edge-config-runtime-refresh.md), [OpenAI-compatible API](../../../../agent-contract/outer/openai-compatible-api.md) | 제거 후 현재 lifecycle 계약 |
| User Decision | 2026-08-15 사용자 대화 | watchdog을 우선 비활성화하고 전용 구현을 제거한다. |
## State Machine
| 상태 | 진입 조건 | 다음 상태 | 근거 |
|------|-----------|-----------|------|
| request/running | provider attempt가 admission되고 request context가 유효함 | request/running / request/terminal | provider output 유무는 상태 전이 조건이 아니다. |
| request/running | provider가 text, reasoning, tool fragment 또는 빈 시간 구간을 가짐 | request/running | 무출력 시간은 cancellation 또는 health evidence가 아니다. |
| request/running | provider가 complete/error/end를 반환함 | request/terminal | provider 명시 terminal |
| request/running | caller cancel 또는 request hard deadline이 발생함 | request/terminal | request context owner |
| request/running | transport disconnect가 확정됨 | request/terminal | transport lifecycle owner |
| request/terminal | terminal owner가 attempt를 정리함 | 없음 | exactly-once lease·resource cleanup |
## Interface Contract
- 계약 원문: [Execution Runtime](../../../../agent-contract/inner/execution-runtime.md), [Edge-Node Runtime Wire](../../../../agent-contract/inner/edge-node-runtime-wire.md), [Edge Config Refresh](../../../../agent-contract/inner/edge-config-runtime-refresh.md), [OpenAI-compatible API](../../../../agent-contract/outer/openai-compatible-api.md)
- 입력:
- request hard timeout과 caller context: 요청 전체 실행 한계와 취소의 source of truth다.
- provider terminal과 transport terminal: 명시적 실행 종료 신호다.
- 출력:
- 정상 stream: provider가 보낸 순서와 terminal을 기존 endpoint 계약대로 전달한다.
- timeout/cancel/error: 기존 일반 lifecycle owner가 sanitized terminal과 exactly-once cleanup을 수행한다.
- 금지:
- output silence만으로 provider attempt를 취소하거나 provider health를 변경하지 않는다.
- stall 전용 retry, avoided-provider selection 또는 health probe를 대체 형태로 남기지 않는다.
- 제거한 protobuf field number를 새 의미에 재사용하지 않는다.
## Acceptance Scenarios
| ID | Milestone Task | Given | When | Then |
|----|----------------|-------|------|------|
| S01 | `watchdog-removal` | normalized run 또는 tunnel provider가 terminal 없이 60초보다 긴 무출력 구간에 있음 | request hard deadline과 caller cancel이 아직 없음 | Node가 stall terminal, probe 또는 fence를 만들지 않고 attempt를 유지한다. |
| S02 | `watchdog-removal` | 실행 중인 attempt | provider terminal, caller cancel 또는 hard deadline이 발생함 | 기존 owner가 terminal과 resource cleanup을 정확히 한 번 수행한다. |
| S03 | `edge-recovery-removal` | Edge가 provider stream/error/terminal을 소비함 | 과거 stall metadata가 없거나 일반 provider error가 도착함 | stall recovery·health overlay·provider avoidance 없이 기존 endpoint terminal로 수렴한다. |
| S04 | `wire-config-cleanup` | Edge와 Node가 같은 새 source로 빌드됨 | config/proto/runtime 계약을 생성·검증함 | stall timeout/failure 실행 필드가 없고 제거된 protobuf number는 재사용되지 않는다. |
| S05 | `contract-spec-sync` | 구현과 테스트가 제거된 lifecycle을 반영함 | contract, living spec과 dev guide를 조회함 | 명시적 hard timeout·cancel·provider/transport terminal만 종료 권한으로 문서화된다. |
| S06 | `dev-rollout` | 새 Edge와 4개 Node가 동일 source ref로 dev에 배포됨 | Pi `ornith:35b` 장시간 tool-call을 GX10/OneX 경로에서 실행함 | 60초 무출력로 인한 `response_stalled` 없이 정상 terminal 또는 명시적 hard timeout까지 유지되고 queue가 0/0으로 회복한다. |
## Evidence Map
| Scenario | Required Evidence | `agent-task` 연결 | 완료 Evidence 기대 |
|----------|-------------------|------------------|---------------------------|
| S01-S02 | fake clock/context 기반 Node normalized+tunnel lifecycle test와 race test | `agent-task/m-provider-stall-watchdog-removal/...` | `milestone-task=watchdog-removal` complete.log와 fresh test output |
| S03 | Edge service/OpenAI provider error·terminal·lease release 회귀 test | `agent-task/m-provider-stall-watchdog-removal/...` | `milestone-task=edge-recovery-removal` complete.log와 fresh test output |
| S04 | config validation, protobuf generation/round-trip, deterministic symbol search | `agent-task/m-provider-stall-watchdog-removal/...` | `milestone-task=wire-config-cleanup` complete.log와 generated diff 검증 |
| S05 | matching contract/spec/dev guide diff와 link 검증 | `agent-task/m-provider-stall-watchdog-removal/...` | `milestone-task=contract-spec-sync` complete.log와 문서 정합성 검토 |
| S06 | source/build identity, 4-node snapshot, GX10/OneX Pi 장시간 tool-call와 final queue snapshot | `agent-task/m-provider-stall-watchdog-removal/...` | `milestone-task=dev-rollout` complete.log와 redacted dev evidence |
## Cross-repo Dependencies
- 없음
## Drift Check
- [x] Milestone 기능 Task와 Acceptance Scenario가 일치한다.
- [x] Evidence Map이 code-review/complete.log에서 검증 가능하다.
- [x] agent-contract 원문을 복제하지 않고 링크했다.
- [x] 사용자 리뷰가 필요한 항목이 없다.
## 사용자 리뷰 이력
- 2026-08-15: 사용자가 운영 비활성화와 stall watchdog 전용 구현 제거를 함께 진행하도록 결정했다.
## 작업 컨텍스트
- 표준선: hard timeout과 caller/transport/provider terminal을 재사용하며 무출력 기반 상태 머신을 대체하지 않는다.
- 후속 SDD: 없음

View file

@ -0,0 +1,73 @@
<!-- task=m-provider-stall-watchdog-removal/01_node_watchdog_removal plan=0 tag=REFACTOR milestone-task=watchdog-removal -->
# Code Review Reference - REFACTOR
> **[IMPLEMENTING AGENT — READ FIRST]** 구현 완료의 마지막 단계로 구현 담당 섹션을 모두 채운다. 계획의 원인·범위·파일·의존성을 그대로 실행하고 검증 결과를 기록한 뒤 active 파일을 유지하고 review 준비 상태를 보고한다. blocker는 정확한 증거와 재개 조건만 기록한다. 사용자 질문, 상태 분류, archive/`complete.log` 작성은 금지한다.
## Overview
date=2026-08-15
task=m-provider-stall-watchdog-removal/01_node_watchdog_removal, plan=0, tag=REFACTOR
## For the Review Agent
각 항목을 소스와 대조하고 검증 명령을 fresh 실행한다. PASS면 plan/review를 log로 archive하고 `milestone-task=watchdog-removal`을 보존한 `complete.log` 작성 및 task archive를 수행한다. WARN/FAIL이면 code-review skill의 다음 상태만 작성한다.
## Implementation Item Completion
| Item | Status |
|------|--------|
| REFACTOR-1 Watchdog 실행 경로 제거 | [ ] |
| REFACTOR-2 Node lifecycle 회귀 테스트 전환 | [ ] |
## Implementation Checklist
- [ ] Node normalized run과 provider tunnel에서 watchdog timer, stall claim/fence, 전용 health probe와 `response_stalled` terminal 생성을 제거한다.
- [ ] 전용 liveness metric/log/capability를 제거하고 기존 provider terminal, caller cancel, hard deadline, transport close의 exactly-once cleanup을 보존한다.
- [ ] Node tests를 S01-S02 반대 회귀로 갱신하고 `go test -count=1``go test -race -count=1`을 통과시킨다.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.
## Review-Only Checklist
- [ ] verdict와 routing signals를 기록한다.
- [ ] plan 범위와 S01-S02를 대조한다.
- [ ] fresh 검증을 재실행한다.
- [ ] PASS 시 active pair와 task를 archive하고 `complete.log`를 작성한다.
## Deviations from Plan
_구현 담당 기록._
## Key Design Decisions
_구현 담당 기록._
## Reviewer Checkpoints
- Node가 stall wire 값을 실행 종료에 사용하지 않는가.
- cancel/deadline/provider terminal/transport close와 lease cleanup은 정확히 한 번인가.
- Edge/proto/config 범위를 이 단계에서 변경하지 않았는가.
## Verification Results
### Node fresh tests
```bash
go test -count=1 ./apps/node/internal/node
go test -race -count=1 ./apps/node/internal/node
```
_실제 stdout/stderr 기록._
### Symbol and diff checks
```bash
rg --sort path -n "newAttemptObserver|errProviderResponseStalled|stallObservation|node_response_stall|joinStallEvidence" apps/node/internal/node --glob '*.go'
git diff --check
```
_실제 stdout/stderr 기록._
## Section Ownership
Implementation completion/checklist 체크, deviations, decisions, verification output은 구현 담당이다. verdict, archive, `complete.log`, Review-Only Checklist는 reviewer 전용이다.

View file

@ -0,0 +1,169 @@
<!-- task=m-provider-stall-watchdog-removal/01_node_watchdog_removal plan=0 tag=REFACTOR milestone-task=watchdog-removal -->
# Node response-stall watchdog 제거
## For the Implementing Agent
구현 후 `CODE_REVIEW-cloud-G10.md`의 구현 담당 섹션에 실제 변경·검증 출력을 채우고 active 파일을 유지한 채 review 준비 상태를 보고한다. 막히면 정확한 blocker, 실행 명령·출력, 재개 조건만 기록한다. 사용자 질문, user-input 도구, stop 파일, 다음 상태 분류, archive 이동과 `complete.log` 작성은 금지하며 finalization은 code-review skill만 수행한다.
## Background
Node는 provider 무출력을 기본 60초 뒤 `response_stalled`로 판정해 정상적인 긴 reasoning/tool-call도 취소한다. 이 단계는 wire/config 호환 필드는 남긴 채 Node의 timer, probe, fence, typed terminal과 전용 관측만 제거하여 Edge가 구버전 필드를 보내더라도 무시하는 안정된 중간 상태를 만든다.
## Analysis
### Files Read
- `apps/node/internal/node/node.go`
- `apps/node/internal/node/run_handler.go`
- `apps/node/internal/node/tunnel_handler.go`
- `apps/node/internal/node/runtime_bridge.go`
- `apps/node/internal/node/command_handler.go`
- `apps/node/internal/node/liveness_watchdog.go`
- `apps/node/internal/node/liveness_health_evidence.go`
- `apps/node/internal/node/liveness_observability.go`
- `apps/node/internal/node/health_probe.go`
- `apps/node/internal/node/liveness_watchdog_test.go`
- `apps/node/internal/node/liveness_watchdog_lifecycle_test.go`
- `apps/node/internal/node/liveness_health_evidence_test.go`
- `apps/node/internal/node/liveness_observability_test.go`
- `apps/node/internal/node/provider_tunnel_liveness_test.go`
- `apps/node/internal/node/run_cancel_test.go`
- `apps/node/internal/node/provider_tunnel_test.go`
- `apps/node/internal/node/runtime_bridge_test.go`
- `apps/node/internal/node/health_probe_test.go`
- `agent-test/dev/rules.md`
- `agent-test/dev/node-smoke.md`
- `agent-test/dev/platform-common-smoke.md`
### SDD Criteria
`agent-roadmap/sdd/operational-observability-provider-management/provider-stall-watchdog-removal/SDD.md``[승인됨]`이며 이 pair의 `milestone-task``watchdog-removal`이다. S01은 60초 이상 무출력에도 attempt 유지, S02는 provider terminal/cancel/hard deadline의 exactly-once cleanup을 요구한다. Evidence Map의 fake-clock/context Node normalized+tunnel test와 race test를 구현·검증 항목에 직접 반영한다.
### Verification Context
handoff는 공급되지 않았다. 위 dev test rules를 적용해 Go cache를 우회하는 `-count=1`과 race 검증을 사용한다. 현재 dev 운영 완화는 remote `build/dev-runtime/edge.yaml`의 네 provider timeout을 7,200,000ms로 설정한 상태이며 코드 검증을 대체하지 않는다. 이 단계는 local package 검증만 수행하고 remote 배포는 04 단계에 한정한다.
### Test Coverage Gaps
- 기존 테스트는 watchdog 발생을 검증하므로 제거 후에는 반대 불변식으로 교체해야 한다.
- 60초 실제 대기는 느리므로 fake clock에서 기존 expiry를 발생시켜도 terminal이 생기지 않는지 검증한다.
- cancel/deadline/provider terminal 및 run/tunnel cleanup 회귀는 기존 fixture를 유지·재작성한다.
### Symbol References
제거 대상은 `newAttemptObserver`, `attemptObserver`, `stallObservation`, `joinStallEvidence`, `stalledRuntimeEvent`, `stalledTunnelFrame`, `nodeLivenessObserver`, `errProviderResponseStalled`, `validateRunStallTimeout`이다. 호출 지점은 `node.go`, `run_handler.go`, `tunnel_handler.go`, `runtime_bridge.go`, `command_handler.go`와 위에 열거한 Node 테스트다. wire/config/runtime 타입 필드와 Edge 소비자는 03 단계까지 호환용으로 유지한다.
### Split Judgment
- 이 단계의 안정 계약: Node가 stall wire 값을 수용하되 실행 종료에 사용하지 않으며 기존 명시적 lifecycle owner만 동작한다.
- 02는 이 단계의 `complete.log` 후 Edge의 dormant recovery를 제거한다.
- 03은 02 완료 후 wire/config를 제거한다. 04는 03 완료 후 동일 source로 배포한다.
### Scope Rationale
Edge recovery, protobuf/config 필드, 공용 execution 타입, contract/spec/docs와 dev runtime은 변경하지 않는다. 호환 필드를 먼저 제거하면 구 Edge/신 Node 혼재 시 wire 오류가 생기므로 후속 단계로 분리한다.
### Final Routing
`evaluation_mode=write`, `finalizer=finalize-task-policy.sh pair`. Build는 closure 점수 `2/2/2/1/2=9`, `grade-boundary`, cloud G09, `PLAN-cloud-G09.md`; review는 `official-review`, cloud G10, `CODE_REVIEW-cloud-G10.md`. `large_indivisible_context=false`; loop risk는 concurrency-state, lifecycle-exactly-once, broad-callsite-removal 3개다. rework=0, evidence-integrity-failure=false, capability gap 없음.
## Implementation Checklist
- [ ] Node normalized run과 provider tunnel에서 watchdog timer, stall claim/fence, 전용 health probe와 `response_stalled` terminal 생성을 제거한다.
- [ ] 전용 liveness metric/log/capability를 제거하고 기존 provider terminal, caller cancel, hard deadline, transport close의 exactly-once cleanup을 보존한다.
- [ ] Node tests를 S01-S02 반대 회귀로 갱신하고 `go test -count=1``go test -race -count=1`을 통과시킨다.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.
### [REFACTOR-1] Watchdog 실행 경로 제거
**Problem:** `run_handler.go:24``tunnel_handler.go:96`가 wire timeout을 observer로 연결하고 `liveness_watchdog.go`가 output silence만으로 요청을 취소한다.
**Solution:** handler는 기존 adapter sink를 직접 사용한다. 전용 observer goroutine/timer/probe와 stall terminal 변환 파일을 삭제한다. wire timeout은 이 단계에서 역호환 입력으로 남기되 실행 로직이 읽지 않는다.
```go
// Before: apps/node/internal/node/tunnel_handler.go:96
observer := newAttemptObserver(n.watchdogClock, time.Duration(tr.ResponseStallTimeoutMS)*time.Millisecond)
// After
// Adapter execution is governed by request context and provider/transport terminal only.
```
**Modified Files and Checklist:**
- [ ] `apps/node/internal/node/run_handler.go`: observer wrapping과 stall error branch 제거.
- [ ] `apps/node/internal/node/tunnel_handler.go`: tunnel watchdog와 claimed stall frame 제거.
- [ ] `apps/node/internal/node/node.go`: watchdog clock/liveness observer 필드와 생성 제거.
- [ ] `apps/node/internal/node/command_handler.go`: stall-derived health capability 분기 제거.
- [ ] `apps/node/internal/node/runtime_bridge.go`: stall terminal mapping/validation 호출 제거, wire 필드는 호환용 무시.
- [ ] `apps/node/internal/node/liveness_watchdog.go`: 삭제.
- [ ] `apps/node/internal/node/liveness_health_evidence.go`: 삭제.
- [ ] `apps/node/internal/node/liveness_observability.go`: 삭제.
- [ ] `apps/node/internal/node/health_probe.go`: watchdog 전용 probe orchestration 삭제.
**Test Strategy:** 아래 전용 watchdog/관측 테스트 파일은 삭제하고 lifecycle fixture는 `run_cancel_test.go`, `provider_tunnel_test.go`, `runtime_bridge_test.go`에서 no-stall/cancel/deadline/provider terminal을 검증하도록 수정한다.
**Verification:** `go test -count=1 ./apps/node/internal/node`가 성공하고 `rg --sort path`에서 Node production stall symbols가 0건이어야 한다.
### [REFACTOR-2] Node lifecycle 회귀 테스트 전환
**Problem:** 현재 테스트는 expiry가 `response_stalled`를 발생시키는 동작을 정답으로 고정한다.
**Solution:** 전용 테스트를 삭제하고 fake provider가 과거 timeout 경계를 지나도 실행을 유지하는 테스트, 명시적 terminal/cancel/deadline만 한 번 종료하는 테스트로 교체한다.
**Modified Files and Checklist:**
- [ ] `apps/node/internal/node/liveness_watchdog_test.go`: 삭제.
- [ ] `apps/node/internal/node/liveness_watchdog_lifecycle_test.go`: 삭제.
- [ ] `apps/node/internal/node/liveness_health_evidence_test.go`: 삭제.
- [ ] `apps/node/internal/node/liveness_observability_test.go`: 삭제.
- [ ] `apps/node/internal/node/health_probe_test.go`: watchdog 전용 테스트 삭제.
- [ ] `apps/node/internal/node/provider_tunnel_liveness_test.go`: 삭제 또는 일반 tunnel terminal 회귀를 provider tunnel 테스트로 이동.
- [ ] `apps/node/internal/node/run_cancel_test.go`: `TestOnRunRequestIgnoresStallTimeoutAndHonorsLifecycleTerminal` 추가.
- [ ] `apps/node/internal/node/provider_tunnel_test.go`: `TestOnProviderTunnelRequestIgnoresStallTimeoutAndHonorsLifecycleTerminal` 추가.
- [ ] `apps/node/internal/node/runtime_bridge_test.go`: stall failure mapping 기대 제거, 호환 wire 필드가 실행 상태를 바꾸지 않음을 확인.
**Test Strategy:** 새 테스트는 차단 provider와 cancel/provider terminal 채널을 사용하며 wall-clock 60초 sleep은 사용하지 않는다. race 검증으로 terminal/cleanup 중복을 탐지한다.
**Verification:** 아래 Final Verification 전체를 fresh 실행한다.
## Dependencies and Execution Order
선행 subtask 없음. 이 pair가 PASS되어 `01_node_watchdog_removal/complete.log`를 만든 뒤에만 `02+01_edge_stall_recovery_removal`을 시작한다.
## Modified Files Summary
| File | Item |
|------|------|
| `apps/node/internal/node/run_handler.go` | REFACTOR-1 |
| `apps/node/internal/node/tunnel_handler.go` | REFACTOR-1 |
| `apps/node/internal/node/node.go` | REFACTOR-1 |
| `apps/node/internal/node/command_handler.go` | REFACTOR-1 |
| `apps/node/internal/node/runtime_bridge.go` | REFACTOR-1 |
| `apps/node/internal/node/liveness_watchdog.go` | REFACTOR-1 |
| `apps/node/internal/node/liveness_health_evidence.go` | REFACTOR-1 |
| `apps/node/internal/node/liveness_observability.go` | REFACTOR-1 |
| `apps/node/internal/node/health_probe.go` | REFACTOR-1 |
| `apps/node/internal/node/liveness_watchdog_test.go` | REFACTOR-2 |
| `apps/node/internal/node/liveness_watchdog_lifecycle_test.go` | REFACTOR-2 |
| `apps/node/internal/node/liveness_health_evidence_test.go` | REFACTOR-2 |
| `apps/node/internal/node/liveness_observability_test.go` | REFACTOR-2 |
| `apps/node/internal/node/health_probe_test.go` | REFACTOR-2 |
| `apps/node/internal/node/provider_tunnel_liveness_test.go` | REFACTOR-2 |
| `apps/node/internal/node/run_cancel_test.go` | REFACTOR-2 |
| `apps/node/internal/node/provider_tunnel_test.go` | REFACTOR-2 |
| `apps/node/internal/node/runtime_bridge_test.go` | REFACTOR-2 |
| `agent-task/m-provider-stall-watchdog-removal/01_node_watchdog_removal/CODE_REVIEW-cloud-G10.md` | REFACTOR-1, REFACTOR-2 |
## Final Verification
```bash
go test -count=1 ./apps/node/internal/node
go test -race -count=1 ./apps/node/internal/node
rg --sort path -n "newAttemptObserver|errProviderResponseStalled|stallObservation|node_response_stall|joinStallEvidence" apps/node/internal/node --glob '*.go'
git diff --check
```
첫 두 명령은 성공해야 하고 검색은 production/test 모두 0건이어야 하며 diff check 출력은 없어야 한다. cached test output은 허용하지 않는다.
After completing all code changes, fill implementation-owned sections in `CODE_REVIEW-*-G??.md`.

View file

@ -0,0 +1,71 @@
<!-- task=m-provider-stall-watchdog-removal/02+01_edge_stall_recovery_removal plan=0 tag=REFACTOR milestone-task=edge-recovery-removal -->
# Code Review Reference - REFACTOR
> **[IMPLEMENTING AGENT — READ FIRST]** 계획대로 구현·검증하고 아래 구현 담당 섹션을 실제 출력으로 채운 뒤 active pair를 유지한다. blocker 증거만 기록하며 사용자 질문, 상태 분류, archive/`complete.log`는 금지한다.
## Overview
date=2026-08-15
task=m-provider-stall-watchdog-removal/02+01_edge_stall_recovery_removal, plan=0, tag=REFACTOR
## For the Review Agent
01 `complete.log`와 변경을 대조하고 fresh 검증한다. PASS finalization에서 `milestone-task=edge-recovery-removal`을 보존한다.
## Implementation Item Completion
| Item | Status |
|------|--------|
| REFACTOR-1 StreamGate stall recovery 제거 | [ ] |
| REFACTOR-2 Provider overlay와 recovery 후보 정책 제거 | [ ] |
## Implementation Checklist
- [ ] Edge의 typed-stall reception, recovery replay, avoided-provider selection과 health overlay를 제거한다.
- [ ] 일반 provider error/cancel/terminal과 admission lease release의 exactly-once 동작을 보존한다.
- [ ] OpenAI/service fresh 및 race tests에서 stall 전용 상태 변화가 없음을 검증한다.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.
## Review-Only Checklist
- [ ] predecessor PASS, verdict/routing signals, fresh tests를 확인한다.
- [ ] PASS 시 pair/task archive와 complete.log를 작성한다.
## Deviations from Plan
_구현 담당 기록._
## Key Design Decisions
_구현 담당 기록._
## Reviewer Checkpoints
- 일반 terminal과 lease release가 유지되는가.
- stall replay/overlay/avoidance가 완전히 제거됐는가.
- proto/config는 03까지 호환 유지됐는가.
## Verification Results
### Edge fresh/race tests
```bash
go test -count=1 ./apps/edge/internal/openai ./apps/edge/internal/service
go test -race -count=1 ./apps/edge/internal/openai ./apps/edge/internal/service
```
_실제 stdout/stderr 기록._
### Symbol and diff checks
```bash
rg --sort path -n "response_stalled|livenessRecovery|recovery_eligible|provider_health_overlay|avoidedProvider" apps/edge/internal/openai apps/edge/internal/service --glob '*.go'
git diff --check
```
_실제 stdout/stderr 기록._
## Section Ownership
Implementation sections는 구현 담당, verdict/finalization/Review-Only Checklist는 reviewer 전용이다.

View file

@ -0,0 +1,173 @@
<!-- task=m-provider-stall-watchdog-removal/02+01_edge_stall_recovery_removal plan=0 tag=REFACTOR milestone-task=edge-recovery-removal -->
# Edge stall recovery 계층 제거
## For the Implementing Agent
구현·fresh 검증 후 `CODE_REVIEW-cloud-G10.md`의 구현 담당 섹션을 채우고 active 파일을 유지한 채 review 준비 상태를 보고한다. blocker는 정확한 증거와 재개 조건만 기록한다. 사용자 질문, user-input, stop 파일, 상태 분류, archive/`complete.log` 작업은 금지하며 finalization은 reviewer 소유다.
## Background
Node watchdog이 제거되면 Edge의 typed-stall reception, health overlay, avoided-provider retry는 생산자가 없는 과설계가 된다. 일반 provider error, cancel, transport/provider terminal과 lease release는 유지하면서 stall 전용 분기만 제거한다.
## Analysis
### Files Read
- `apps/edge/internal/openai/stream_gate_runtime.go`
- `apps/edge/internal/openai/stream_gate_dispatcher.go`
- `apps/edge/internal/openai/stream_gate_filters.go`
- `apps/edge/internal/openai/stream_gate_ingress.go`
- `apps/edge/internal/openai/stream_gate_release_sink.go`
- `apps/edge/internal/openai/provider_tunnel.go`
- `apps/edge/internal/openai/server.go`
- `apps/edge/internal/openai/liveness_recovery_observability.go`
- `apps/edge/internal/openai/liveness_recovery_observability_test.go`
- `apps/edge/internal/openai/stream_gate_stall_recovery_test.go`
- `apps/edge/internal/service/provider_pool.go`
- `apps/edge/internal/service/provider_resolution.go`
- `apps/edge/internal/service/provider_tunnel.go`
- `apps/edge/internal/service/run_submit.go`
- `apps/edge/internal/service/run_types.go`
- `apps/edge/internal/service/run_wire.go`
- `apps/edge/internal/service/model_queue_release.go`
- `apps/edge/internal/service/provider_health_observability.go`
- `apps/edge/internal/service/provider_health_observability_test.go`
- `apps/edge/internal/service/provider_health_overlay_test.go`
- `apps/edge/internal/service/provider_recovery_selection_test.go`
- `agent-test/dev/rules.md`
- `agent-test/dev/edge-smoke.md`
### SDD Criteria
승인된 `agent-roadmap/sdd/operational-observability-provider-management/provider-stall-watchdog-removal/SDD.md``milestone-task=edge-recovery-removal`, S03과 Evidence Map을 따른다. stall replay/overlay/avoidance가 사라지고 일반 error/cancel/terminal/lease release가 exactly once임을 service/OpenAI fresh test로 증명한다.
### Verification Context
handoff 없음. local Go test는 `-count=1`, 동시성 경로는 race로 실행한다. remote dev 배포는 04 단계이며 이 단계에서는 repository-native tests만 수행한다.
### Test Coverage Gaps
기존 recovery tests는 재시도를 성공 조건으로 본다. 이를 삭제하고 동일 입력이 일반 terminal로 한 번 수렴하며 provider health/후보군을 변형하지 않는 회귀로 교체한다.
### Symbol References
제거 대상은 `response_stalled` reception fence, `livenessRecoveryObserver`, recovery eligibility/attempt metadata, avoided-provider candidate selection, provider health overlay와 관련 metric/log다. 호출 지점은 위 OpenAI stream gate와 service provider pool/resolution/tunnel/run 파일이다.
### Split Judgment
stable contract는 Node에서 더 이상 stall을 만들지 않는 01의 완료다. 이 단계 PASS 후 Edge는 구 wire stall을 일반 provider error로만 취급하며 03에서 dormant wire/config를 안전하게 제거할 수 있다. predecessor `01_node_watchdog_removal`은 아직 `complete.log`가 없어 대기 상태다.
### Scope Rationale
proto/config/runtime field와 contract/spec/docs는 03, remote rebuild/deploy는 04에 둔다. 일반 StreamGate content/tool validation 및 retry가 아닌 정상 dispatch 정책은 변경하지 않는다.
### Final Routing
`evaluation_mode=write`, pair finalizer. Build `2/2/2/1/2=9`, grade-boundary cloud G09 `PLAN-cloud-G09.md`; review official-review cloud G10 `CODE_REVIEW-cloud-G10.md`. large=false, loop risks reception-fence/concurrent-release/provider-selection 3, rework=0, integrity=false, capability gap 없음.
## Implementation Checklist
- [ ] Edge의 typed-stall reception, recovery replay, avoided-provider selection과 health overlay를 제거한다.
- [ ] 일반 provider error/cancel/terminal과 admission lease release의 exactly-once 동작을 보존한다.
- [ ] OpenAI/service fresh 및 race tests에서 stall 전용 상태 변화가 없음을 검증한다.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.
### [REFACTOR-1] StreamGate stall recovery 제거
**Problem:** `stream_gate_dispatcher.go``stream_gate_runtime.go`가 typed stall을 별도 recovery plan으로 바꾸며 부분 tool-call 이후에도 후보를 재선택한다.
**Solution:** stall failure/metadata reception과 recovery state를 삭제하고 입력은 기존 일반 provider terminal 경로로 수렴시킨다. content/tool validation은 그대로 둔다.
```go
// Before: typed stall selects a recovery plan and avoided provider set.
if failure.Code == responseStalled { return buildRecoveryPlan(...) }
// After: no stall-specific branch; existing terminal handling owns the result.
```
**Modified Files and Checklist:**
- [ ] `apps/edge/internal/openai/stream_gate_runtime.go`: recovery state 제거.
- [ ] `apps/edge/internal/openai/stream_gate_dispatcher.go`: stall dispatch/retry branch 제거.
- [ ] `apps/edge/internal/openai/stream_gate_filters.go`: stall metadata filter 제거.
- [ ] `apps/edge/internal/openai/stream_gate_ingress.go`: typed-stall reception 제거.
- [ ] `apps/edge/internal/openai/stream_gate_release_sink.go`: recovery release signal 제거.
- [ ] `apps/edge/internal/openai/provider_tunnel.go`: stall failure decode branch 제거.
- [ ] `apps/edge/internal/openai/server.go`: liveness observer wiring 제거.
- [ ] `apps/edge/internal/openai/liveness_recovery_observability.go`: 삭제.
**Test Strategy:** liveness observability와 stall recovery 전용 test는 삭제하고 `stream_gate_dispatcher_test.go`에 일반 error/terminal exactly-once 회귀를 둔다.
**Verification:** OpenAI package fresh/race tests 성공, stall/recovery symbol 검색 0건.
### [REFACTOR-2] Provider overlay와 recovery 후보 정책 제거
**Problem:** service가 request-scoped stall evidence로 pool health와 후보군을 바꾼다.
**Solution:** provider base health와 configured scheduling만 사용하고 stall overlay, recovery avoidance, 전용 observation을 삭제한다. queue lease release는 공통 terminal path 하나만 유지한다.
**Modified Files and Checklist:**
- [ ] `apps/edge/internal/service/provider_pool.go`: overlay/recovery state 제거.
- [ ] `apps/edge/internal/service/provider_resolution.go`: avoided-provider selection 제거.
- [ ] `apps/edge/internal/service/provider_tunnel.go`: stall handoff 제거.
- [ ] `apps/edge/internal/service/run_submit.go`: recovery request metadata 제거.
- [ ] `apps/edge/internal/service/run_types.go`: recovery-only state 제거.
- [ ] `apps/edge/internal/service/run_wire.go`: stall failure branch 제거.
- [ ] `apps/edge/internal/service/model_queue_release.go`: recovery release branch를 일반 release로 통합.
- [ ] `apps/edge/internal/service/provider_health_observability.go`: 삭제.
- [ ] `apps/edge/internal/service/provider_health_observability_test.go`: 삭제.
- [ ] `apps/edge/internal/service/provider_health_overlay_test.go`: 삭제.
- [ ] `apps/edge/internal/service/provider_recovery_selection_test.go`: 삭제.
- [ ] `apps/edge/internal/openai/liveness_recovery_observability_test.go`: 삭제.
- [ ] `apps/edge/internal/openai/stream_gate_stall_recovery_test.go`: 삭제.
- [ ] `apps/edge/internal/openai/stream_gate_dispatcher_test.go`: 일반 terminal/lease 회귀 추가.
**Test Strategy:** `go test -race`로 terminal과 lease 중복을 검증하고 provider selection test는 configured priority/capacity가 유지되는 기존 suite를 사용한다.
**Verification:** 아래 Final Verification.
## Dependencies and Execution Order
`01_node_watchdog_removal/complete.log`가 선행 조건이다. 현재는 missing이며 PASS 전에는 이 pair를 구현하지 않는다.
## Modified Files Summary
| File | Item |
|------|------|
| `apps/edge/internal/openai/stream_gate_runtime.go` | REFACTOR-1 |
| `apps/edge/internal/openai/stream_gate_dispatcher.go` | REFACTOR-1 |
| `apps/edge/internal/openai/stream_gate_filters.go` | REFACTOR-1 |
| `apps/edge/internal/openai/stream_gate_ingress.go` | REFACTOR-1 |
| `apps/edge/internal/openai/stream_gate_release_sink.go` | REFACTOR-1 |
| `apps/edge/internal/openai/provider_tunnel.go` | REFACTOR-1 |
| `apps/edge/internal/openai/server.go` | REFACTOR-1 |
| `apps/edge/internal/openai/liveness_recovery_observability.go` | REFACTOR-1 |
| `apps/edge/internal/openai/liveness_recovery_observability_test.go` | REFACTOR-2 |
| `apps/edge/internal/openai/stream_gate_stall_recovery_test.go` | REFACTOR-2 |
| `apps/edge/internal/openai/stream_gate_dispatcher_test.go` | REFACTOR-2 |
| `apps/edge/internal/service/provider_pool.go` | REFACTOR-2 |
| `apps/edge/internal/service/provider_resolution.go` | REFACTOR-2 |
| `apps/edge/internal/service/provider_tunnel.go` | REFACTOR-2 |
| `apps/edge/internal/service/run_submit.go` | REFACTOR-2 |
| `apps/edge/internal/service/run_types.go` | REFACTOR-2 |
| `apps/edge/internal/service/run_wire.go` | REFACTOR-2 |
| `apps/edge/internal/service/model_queue_release.go` | REFACTOR-2 |
| `apps/edge/internal/service/provider_health_observability.go` | REFACTOR-2 |
| `apps/edge/internal/service/provider_health_observability_test.go` | REFACTOR-2 |
| `apps/edge/internal/service/provider_health_overlay_test.go` | REFACTOR-2 |
| `apps/edge/internal/service/provider_recovery_selection_test.go` | REFACTOR-2 |
| `agent-task/m-provider-stall-watchdog-removal/02+01_edge_stall_recovery_removal/CODE_REVIEW-cloud-G10.md` | REFACTOR-1, REFACTOR-2 |
## Final Verification
```bash
go test -count=1 ./apps/edge/internal/openai ./apps/edge/internal/service
go test -race -count=1 ./apps/edge/internal/openai ./apps/edge/internal/service
rg --sort path -n "response_stalled|livenessRecovery|recovery_eligible|provider_health_overlay|avoidedProvider" apps/edge/internal/openai apps/edge/internal/service --glob '*.go'
git diff --check
```
tests는 성공하고 검색은 실행 참조 0건, diff check는 무출력이어야 한다. cache는 허용하지 않는다.
After completing all code changes, fill implementation-owned sections in `CODE_REVIEW-*-G??.md`.

View file

@ -0,0 +1,72 @@
<!-- task=m-provider-stall-watchdog-removal/03+02_wire_contract_cleanup plan=0 tag=API milestone-task=wire-config-cleanup,contract-spec-sync -->
# Code Review Reference - API
> **[IMPLEMENTING AGENT — READ FIRST]** 계획의 schema·generated·문서 경계를 그대로 구현하고 검증 원문을 기록한 뒤 review 준비 상태를 보고한다. 사용자 질문, 상태 분류, archive/`complete.log`는 금지한다.
## Overview
date=2026-08-15
task=m-provider-stall-watchdog-removal/03+02_wire_contract_cleanup, plan=0, tag=API
## For the Review Agent
02 `complete.log`, reserved field numbers, generated diff와 문서 정합성을 fresh 검증한다. PASS 시 두 milestone-task id를 보존한다.
## Implementation Item Completion
| Item | Status |
|------|--------|
| API-1 Wire/config/runtime 타입 제거 | [ ] |
| API-2 Contract/spec/dev guide 동기화 | [ ] |
## Implementation Checklist
- [ ] stall timeout/failure/activity 전용 proto·config·runtime 계약을 제거하고 protobuf 번호를 reserve한다.
- [ ] generated clients와 tests를 재생성·갱신하고 전체 실행 참조가 0건임을 검증한다.
- [ ] matching contract/spec/dev guide를 hard-timeout/cancel/provider/transport terminal 기준으로 동기화한다.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.
## Review-Only Checklist
- [ ] predecessor, schema reservation, generated outputs와 문서 source-of-truth를 확인한다.
- [ ] fresh full test 및 검색 후 PASS finalization을 수행한다.
## Deviations from Plan
_구현 담당 기록._
## Key Design Decisions
_구현 담당 기록._
## Reviewer Checkpoints
- 제거 field number가 같은 message에서 reserved인가.
- archive 외 runtime/config/generated 참조가 0건인가.
- hard timeout/cancel/provider/transport terminal 소유권이 문서와 코드에서 일치하는가.
## Verification Results
### Generation and fresh tests
```bash
make proto
go test -count=1 ./packages/go/config ./packages/go/execution ./apps/edge/internal/configrefresh ./apps/edge/internal/service ./apps/node/internal/node
go test -count=1 ./...
```
_실제 stdout/stderr 기록._
### Search and diff checks
```bash
rg --sort path -n "response_stall_timeout_ms|ResponseStallTimeout|response_stalled|FailureCodeResponseStalled" --glob '!agent-task/archive/**' --glob '!agent-roadmap/archive/**'
git diff --check
```
_실제 stdout/stderr 기록._
## Section Ownership
Implementation sections는 구현 담당, verdict/finalization/Review-Only Checklist는 reviewer 전용이다.

View file

@ -0,0 +1,172 @@
<!-- task=m-provider-stall-watchdog-removal/03+02_wire_contract_cleanup plan=0 tag=API milestone-task=wire-config-cleanup,contract-spec-sync -->
# Stall wire·config·문서 계약 정리
## For the Implementing Agent
구현과 fresh 검증 후 `CODE_REVIEW-cloud-G10.md` 구현 담당 섹션에 실제 출력까지 기록하고 active pair를 유지한다. blocker는 증거/명령/재개 조건만 기록한다. 사용자 질문, user-input, stop 파일, archive 이동과 `complete.log`는 금지하며 reviewer가 finalization한다.
## Background
Node와 Edge 동작 제거 뒤 남은 `response_stall_timeout_ms`, `response_stalled`, activity/liveness 타입은 잘못된 운영 제어를 암시한다. proto field number는 reserve하고 config/runtime/generated clients와 현재 contract/spec/docs를 명시적 lifecycle owner 기준으로 동기화한다.
## Analysis
### Files Read
- `proto/iop/runtime.proto`
- `packages/go/config/provider_types.go`
- `packages/go/execution/liveness.go`
- `packages/go/execution/failure.go`
- `packages/go/execution/types.go`
- `configs/edge.yaml`
- `agent-contract/inner/execution-runtime.md`
- `agent-contract/inner/edge-node-runtime-wire.md`
- `agent-contract/inner/edge-config-runtime-refresh.md`
- `agent-contract/outer/openai-compatible-api.md`
- `agent-spec/runtime/edge-node-execution.md`
- `agent-spec/runtime/provider-pool-config-refresh.md`
- `agent-spec/input/openai-compatible-surface.md`
- `agent-spec/runtime/stream-evidence-gate.md`
- `docs/edge-local-dev-guide.md`
- `agent-test/dev/rules.md`
### SDD Criteria
승인 SDD의 `wire-config-cleanup,contract-spec-sync`, S04-S05 및 Evidence Map을 따른다. proto/config 생성·round-trip·compile과 deterministic 전체 symbol 검색, matching contract/spec/dev guide diff가 완료 evidence다.
### Verification Context
handoff 없음. config/proto 변경이므로 repository의 `make proto`, Go/Dart generated diff 검증, config check와 `-count=1` test가 필수다. remote build는 04로 미룬다.
### Test Coverage Gaps
현재 tests는 timeout default/validation과 failure wire round-trip을 긍정한다. 필드 제거, reserved 번호, unknown-field 호환 및 일반 lifecycle round-trip으로 전환해야 한다.
### Symbol References
`ResponseStallTimeoutMS`, `response_stall_timeout_ms`, `FailureCodeResponseStalled`, `response_stalled`, activity sink와 liveness health enum을 전체 repository에서 제거한다. protobuf의 기존 field number는 `reserved`로 남긴다. archive와 새 SDD의 역사 설명은 검색 예외다.
### Split Judgment
stable contract는 02 완료로 runtime 소비자가 모두 사라진 상태다. predecessor `02+01_edge_stall_recovery_removal`은 현재 complete.log missing이다. 이 단계 PASS 후 source/build 계약이 확정되어 04 배포가 가능하다.
### Scope Rationale
과거 archive는 수정하지 않는다. provider hard timeout, queue timeout, priority/capacity, OpenAI content/tool validation 계약은 변경하지 않는다. dev host runtime mutation은 04에서만 한다.
### Final Routing
`evaluation_mode=write`, pair finalizer. Build `2/1/2/1/2=8`, local-fit local G08 `PLAN-local-G08.md`; review official-review cloud G10 `CODE_REVIEW-cloud-G10.md`. large=false, loop risks generated-contract/cross-layer-schema 2, rework=0, integrity=false, capability gap 없음.
## Implementation Checklist
- [ ] stall timeout/failure/activity 전용 proto·config·runtime 계약을 제거하고 protobuf 번호를 reserve한다.
- [ ] generated clients와 tests를 재생성·갱신하고 전체 실행 참조가 0건임을 검증한다.
- [ ] matching contract/spec/dev guide를 hard-timeout/cancel/provider/transport terminal 기준으로 동기화한다.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.
### [API-1] Wire/config/runtime 타입 제거
**Problem:** `runtime.proto`, provider config와 execution packages가 제거된 watchdog을 공개 계약으로 계속 노출한다.
**Solution:** request/tunnel stall timeout 필드와 stall failure payload를 삭제하고 각 protobuf 번호를 같은 message 안에서 reserve한다. config/runtime symbols와 전용 tests를 제거하고 generated Go/Dart를 `make proto`로 갱신한다.
```proto
// Before: proto/iop/runtime.proto
int64 response_stall_timeout_ms = N;
// After
reserved N;
```
**Modified Files and Checklist:**
- [ ] `proto/iop/runtime.proto`: fields 삭제 및 번호 reserve.
- [ ] `proto/gen/iop/runtime.pb.go`: generator output 갱신.
- [ ] `apps/client/lib/gen/proto/iop/runtime.pb.dart`: generator output 갱신.
- [ ] `apps/client/lib/gen/proto/iop/runtime.pbjson.dart`: generator output 갱신.
- [ ] `packages/go/config/provider_types.go`: provider stall config 제거.
- [ ] `packages/go/config/provider_stall_timeout_test.go`: 삭제.
- [ ] `packages/go/execution/liveness.go`: 삭제.
- [ ] `packages/go/execution/liveness_test.go`: 삭제.
- [ ] `packages/go/execution/failure.go`: stall code 제거.
- [ ] `packages/go/execution/failure_test.go`: stall expectation 제거.
- [ ] `packages/go/execution/types.go`: stall/activity-only fields 제거.
- [ ] `configs/edge.yaml`: 네 provider의 임시/기존 timeout key 제거.
- [ ] `apps/edge/internal/configrefresh/classify.go`: stall field diff 분류 제거.
- [ ] `apps/edge/internal/configrefresh/provider_stall_timeout_test.go`: 삭제.
- [ ] `apps/edge/internal/service/provider_stall_timeout_test.go`: 삭제.
**Test Strategy:** proto reserved declaration과 일반 RunRequest/ProviderTunnelRequest round-trip을 검증한다. config test는 unknown removed key가 명확히 거부되는 현재 parser 정책을 확인한다.
**Verification:** `make proto`, 관련 fresh tests, 전체 symbol 검색.
### [API-2] Contract/spec/dev guide 동기화
**Problem:** 현재 문서가 stall을 lifecycle owner와 recovery signal로 설명해 제거 후 동작과 충돌한다.
**Solution:** 무출력은 상태 전이가 아니며 caller cancel, hard deadline, provider/transport terminal만 종료 권한을 갖는다고 각 source-of-truth 문서에 기록한다. archive는 손대지 않는다.
**Modified Files and Checklist:**
- [ ] `agent-contract/inner/execution-runtime.md`: execution terminal owner 갱신.
- [ ] `agent-contract/inner/edge-node-runtime-wire.md`: 제거 field/reserved 및 terminal 계약 갱신.
- [ ] `agent-contract/inner/edge-config-runtime-refresh.md`: stall config 제거.
- [ ] `agent-contract/outer/openai-compatible-api.md`: stall recovery 표면 제거.
- [ ] `agent-spec/runtime/edge-node-execution.md`: 현재 runtime 동작 갱신.
- [ ] `agent-spec/runtime/provider-pool-config-refresh.md`: provider schema 갱신.
- [ ] `agent-spec/input/openai-compatible-surface.md`: terminal semantics 갱신.
- [ ] `agent-spec/runtime/stream-evidence-gate.md`: stall replay/avoidance 제거.
- [ ] `docs/edge-local-dev-guide.md`: timeout key와 troubleshooting 제거.
**Test Strategy:** 문서는 별도 test를 추가하지 않고 link/symbol search와 code review로 정합성을 검증한다.
**Verification:** Final Verification의 deterministic search에서 archive, SDD의 역사 설명, proto reserved 외 실행 참조가 없어야 한다.
## Dependencies and Execution Order
`02+01_edge_stall_recovery_removal/complete.log`가 선행 조건이며 현재 missing이다. PASS 전 구현 금지.
## Modified Files Summary
| File | Item |
|------|------|
| `proto/iop/runtime.proto` | API-1 |
| `proto/gen/iop/runtime.pb.go` | API-1 |
| `apps/client/lib/gen/proto/iop/runtime.pb.dart` | API-1 |
| `apps/client/lib/gen/proto/iop/runtime.pbjson.dart` | API-1 |
| `packages/go/config/provider_types.go` | API-1 |
| `packages/go/config/provider_stall_timeout_test.go` | API-1 |
| `packages/go/execution/liveness.go` | API-1 |
| `packages/go/execution/liveness_test.go` | API-1 |
| `packages/go/execution/failure.go` | API-1 |
| `packages/go/execution/failure_test.go` | API-1 |
| `packages/go/execution/types.go` | API-1 |
| `configs/edge.yaml` | API-1 |
| `apps/edge/internal/configrefresh/classify.go` | API-1 |
| `apps/edge/internal/configrefresh/provider_stall_timeout_test.go` | API-1 |
| `apps/edge/internal/service/provider_stall_timeout_test.go` | API-1 |
| `agent-contract/inner/execution-runtime.md` | API-2 |
| `agent-contract/inner/edge-node-runtime-wire.md` | API-2 |
| `agent-contract/inner/edge-config-runtime-refresh.md` | API-2 |
| `agent-contract/outer/openai-compatible-api.md` | API-2 |
| `agent-spec/runtime/edge-node-execution.md` | API-2 |
| `agent-spec/runtime/provider-pool-config-refresh.md` | API-2 |
| `agent-spec/input/openai-compatible-surface.md` | API-2 |
| `agent-spec/runtime/stream-evidence-gate.md` | API-2 |
| `docs/edge-local-dev-guide.md` | API-2 |
| `agent-task/m-provider-stall-watchdog-removal/03+02_wire_contract_cleanup/CODE_REVIEW-cloud-G10.md` | API-1, API-2 |
## Final Verification
```bash
make proto
go test -count=1 ./packages/go/config ./packages/go/execution ./apps/edge/internal/configrefresh ./apps/edge/internal/service ./apps/node/internal/node
go test -count=1 ./...
rg --sort path -n "response_stall_timeout_ms|ResponseStallTimeout|response_stalled|FailureCodeResponseStalled" --glob '!agent-task/archive/**' --glob '!agent-roadmap/archive/**'
git diff --check
```
generation과 tests는 성공해야 한다. 검색 결과는 승인 SDD/active plan의 역사 설명과 `runtime.proto` reserved 주석만 허용하고 실행 참조는 0건이어야 한다. cache는 허용하지 않는다.
After completing all code changes, fill implementation-owned sections in `CODE_REVIEW-*-G??.md`.

View file

@ -0,0 +1,74 @@
<!-- task=m-provider-stall-watchdog-removal/04+03_dev_rollout plan=0 tag=TEST milestone-task=dev-rollout -->
# Code Review Reference - TEST
> **[IMPLEMENTING AGENT — READ FIRST]** 동일 source 배포와 redacted 실제 검증 증거를 채우고 active pair를 유지한다. 비밀, 사용자 질문, 상태 분류, archive/`complete.log`는 금지한다.
## Overview
date=2026-08-15
task=m-provider-stall-watchdog-removal/04+03_dev_rollout, plan=0, tag=TEST
## For the Review Agent
03 `complete.log`, source/build identity, 4-node health, GX10/OneX 장시간 Pi 결과와 final queue를 독립 확인한다. PASS 시 `milestone-task=dev-rollout`을 보존한다.
## Implementation Item Completion
| Item | Status |
|------|--------|
| TEST-1 동일 source rebuild와 배포 | [ ] |
| TEST-2 Pi 장시간 tool-call과 queue 회복 | [ ] |
## Implementation Checklist
- [ ] final source ref를 dev runner에 clean sync하고 Edge와 macOS/Linux ARM64/Windows Node를 같은 ref로 rebuild·재배포한다.
- [ ] 네 Node 연결과 source/build identity를 확인한 뒤 Pi `ornith:35b`를 GX10/OneX 각각에서 60초 이상 무출력 가능한 tool-call로 검증한다.
- [ ] `response_stalled` 부재, 정상 terminal 또는 명시적 hard timeout, final provider queue 0/0을 redacted evidence로 기록하고 inventory baseline을 갱신한다.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.
## Review-Only Checklist
- [ ] predecessor와 clean source sync를 확인한다.
- [ ] secrets 노출 없이 runtime identity/smoke/queue evidence를 재검증한다.
- [ ] PASS finalization을 수행한다.
## Deviations from Plan
_구현 담당 기록._
## Key Design Decisions
_구현 담당 기록._
## Reviewer Checkpoints
- 모든 binary source가 동일한가.
- GX10과 OneX가 각각 검증됐고 RTX route를 변형하지 않았는가.
- 60초 silence가 stall terminal을 만들지 않고 final queue가 0/0인가.
## Verification Results
### Identity and config
```bash
git status --short
git rev-parse HEAD
ssh toki@toki-labs.com 'cd /Users/toki/agent-work/iop-dev && git status --short && git rev-parse HEAD && build/dev-runtime/bin/edge config check --config build/dev-runtime/edge.yaml'
ssh toki@toki-labs.com 'cd /Users/toki/agent-work/iop-dev && go version -m build/dev-runtime/bin/edge && go version -m build/dev-runtime/bin/iop-node && go version -m build/dev-runtime/bin/iop-node-linux-arm64 && go version -m build/dev-runtime/bin/iop-node-windows-amd64.exe'
```
_실제 stdout/stderr 기록._
### Runtime evidence and diff
```bash
rg --sort path -n "response_stalled" agent-task/m-provider-stall-watchdog-removal/04+03_dev_rollout/dev-rollout-evidence.log
git diff --check
```
_GX10/OneX smoke와 final queue의 redacted 실제 stdout/stderr 기록._
## Section Ownership
Implementation sections는 구현 담당, verdict/finalization/Review-Only Checklist는 reviewer 전용이다.

View file

@ -0,0 +1,117 @@
<!-- task=m-provider-stall-watchdog-removal/04+03_dev_rollout plan=0 tag=TEST milestone-task=dev-rollout -->
# Watchdog 제거 빌드 dev 배포·장시간 검증
## For the Implementing Agent
배포·검증 후 `CODE_REVIEW-cloud-G10.md` 구현 담당 섹션에 redacted 실제 명령과 출력을 기록하고 active pair를 유지한다. blocker는 증거와 재개 조건만 남긴다. 비밀 출력, 사용자 질문, user-input, stop 파일, 상태 분류, archive/`complete.log`는 금지하며 finalization은 reviewer 소유다.
## Background
코드 제거는 동일 source ref로 Edge 및 macOS/Linux/Windows Node를 다시 빌드해 dev에서 확인해야 완료된다. Pi `ornith:35b`의 GX10/OneX 장시간 tool-call이 60초 침묵으로 종료되지 않고 queue가 회복되는지 검증한다.
## Analysis
### Files Read
- `agent-test/dev/rules.md`
- `agent-test/dev/edge-smoke.md`
- `agent-test/dev/node-smoke.md`
- `agent-test/dev/platform-common-smoke.md`
- `agent-test/inventory-dev.yaml`
- `agent-ops/skills/project/dev-runtime-deploy/SKILL.md`
### SDD Criteria
승인 SDD의 `milestone-task=dev-rollout`, S06과 Evidence Map을 따른다. source/build identity, 4-node snapshot, GX10/OneX Pi 장시간 tool-call, final 0/0 queue를 redacted evidence로 남긴다.
### Verification Context
handoff 없음. external preflight: runner `ssh toki@toki-labs.com`, repo `/Users/toki/agent-work/iop-dev`, branch `release/dev-1058`, observed HEAD `c051529c...`, tracked dirty 0, Darwin arm64. non-login shell에는 Go 경로가 없으므로 skill에 정의된 PATH/login zsh로 Go 1.26.3과 protoc 29.3을 사용한다. 현재 local HEAD는 `8620512d...`라 source sync/rebuild가 필수다. Edge ports 18083/18084/19093과 네 Node(mac/gx10/onex/rtx) 연결을 확인하고 최종 source ref에서 모든 artifact를 새로 빌드한다. config는 `build/dev-runtime/edge.yaml`; secrets는 출력/추적하지 않는다.
### Test Coverage Gaps
local fake-clock은 실제 provider의 60초 이상 reasoning/tool-call을 대체하지 못한다. GX10과 OneX 각각 강제 경로 smoke 및 final queue snapshot이 필요하다. RTX는 `ornith:35b` 후보가 아니므로 대상에서 제외하되 Node 연결은 확인한다.
### Symbol References
코드 symbol 변경 없음. 검증 대상 표면은 Pi `ornith:35b`, Edge OpenAI endpoint, provider selection/queue snapshot과 runtime source/build identity다.
### Split Judgment
stable input은 03의 wire/contract cleanup PASS와 clean final source ref다. predecessor `03+02_wire_contract_cleanup``complete.log`는 현재 missing이다. 이 단계는 runtime mutation과 evidence만 소유한다.
### Scope Rationale
provider capacity/priority/route, model files, Ornith settings, RTX 후보 정책은 변경하지 않는다. 실패 시 새 heuristic이나 watchdog을 추가하지 않고 제거 구현의 결함만 같은 source에서 수정 후 재빌드한다.
### Final Routing
`evaluation_mode=write`, pair finalizer. Build `1/1/2/2/2=8`, local-fit local G08 `PLAN-local-G08.md`; review official-review cloud G10 `CODE_REVIEW-cloud-G10.md`. large=false, loop risks multi-host-rollout/external-evidence 2, rework=0, integrity=false, capability gap 없음.
## Implementation Checklist
- [ ] final source ref를 dev runner에 clean sync하고 Edge와 macOS/Linux ARM64/Windows Node를 같은 ref로 rebuild·재배포한다.
- [ ] 네 Node 연결과 source/build identity를 확인한 뒤 Pi `ornith:35b`를 GX10/OneX 각각에서 60초 이상 무출력 가능한 tool-call로 검증한다.
- [ ] `response_stalled` 부재, 정상 terminal 또는 명시적 hard timeout, final provider queue 0/0을 redacted evidence로 기록하고 inventory baseline을 갱신한다.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.
### [TEST-1] 동일 source rebuild와 배포
**Problem:** 현재 runner HEAD가 local 작업 ref와 다르고 운영 Edge는 config 완화만 적용된 기존 binary다.
**Solution:** dev deploy skill의 preflight/backup/validate/restart 순서를 사용한다. clean sync 후 한 source ref에서 모든 platform artifact를 rebuild하고 exact process를 재시작한다.
```text
Before: remote source=c051529c..., runtime mitigation=7200000ms
After: remote source=<final reviewed ref>, stall config key absent, all binaries report same source
```
**Modified Files and Checklist:**
- [ ] `agent-test/inventory-dev.yaml`: 최종 source/build identity, Node/provider baseline과 검증 시각을 secret 없이 갱신.
**Test Strategy:** 배포 전후 config check, exact PID/port, binary source identity, 4-node connected/healthy snapshot을 기록한다.
**Verification:** dev rules의 Edge/Node smoke를 모두 수행하며 기존 remote backup은 보존한다.
### [TEST-2] Pi 장시간 tool-call과 queue 회복
**Problem:** 실제 장애는 GX10에서 유효한 tool-call fragment 뒤 60초 silence가 Node stall terminal로 변환된 것이었다.
**Solution:** Pi의 `ornith:35b` 경로를 사용해 GX10과 OneX provider를 각각 선택 가능하게 격리 검증한다. 각 요청은 60초 경계를 넘도록 하고 response stream, selected provider, terminal과 queue snapshot을 수집한다.
**Modified Files and Checklist:**
- [ ] `agent-task/m-provider-stall-watchdog-removal/04+03_dev_rollout/dev-rollout-evidence.log`: 명령·redacted raw output·timestamp·source ref·provider별 결과·final queue를 기록.
**Test Strategy:** provider별 최소 1회 장시간 tool-call, 일반 짧은 control request 1회, 실패/중단 후 queue recovery를 검증한다. API key와 prompt 민감값은 기록하지 않는다.
**Verification:** `response_stalled`가 0건이고 결과가 정상 terminal 또는 설정된 request hard timeout이며 모든 provider queue가 `in_flight=0 queued=0`이어야 한다.
## Dependencies and Execution Order
`03+02_wire_contract_cleanup/complete.log`가 선행 조건이며 현재 missing이다. sync → build → config check → backup/deploy/restart → identity/health → provider별 smoke → final queue 순서다.
## Modified Files Summary
| File | Item |
|------|------|
| `agent-test/inventory-dev.yaml` | TEST-1 |
| `agent-task/m-provider-stall-watchdog-removal/04+03_dev_rollout/dev-rollout-evidence.log` | TEST-2 |
| `agent-task/m-provider-stall-watchdog-removal/04+03_dev_rollout/CODE_REVIEW-cloud-G10.md` | TEST-1, TEST-2 |
## Final Verification
```bash
git status --short
git rev-parse HEAD
ssh toki@toki-labs.com 'cd /Users/toki/agent-work/iop-dev && git status --short && git rev-parse HEAD && build/dev-runtime/bin/edge config check --config build/dev-runtime/edge.yaml'
ssh toki@toki-labs.com 'cd /Users/toki/agent-work/iop-dev && go version -m build/dev-runtime/bin/edge && go version -m build/dev-runtime/bin/iop-node && go version -m build/dev-runtime/bin/iop-node-linux-arm64 && go version -m build/dev-runtime/bin/iop-node-windows-amd64.exe'
rg --sort path -n "response_stalled" agent-task/m-provider-stall-watchdog-removal/04+03_dev_rollout/dev-rollout-evidence.log
git diff --check
```
local/remote HEAD와 모든 runtime source identity는 같고 config check는 성공해야 한다. evidence의 검색은 0건이어야 하며 별도 API smoke raw output에서 GX10/OneX 성공과 final queue 0/0을 확인한다. cache는 허용하지 않는다.
After completing all code changes, fill implementation-owned sections in `CODE_REVIEW-*-G??.md`.