<!-- task=m-stream-evidence-gate-core/19+18_core_runtime_loop plan=6 tag=REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP -->

# Plan - Stream Gate owner loop 구현 재복구

## 이 파일을 읽는 구현 에이전트에게

구현과 테스트, 실제 검증 evidence만 소유한다. 아래 체크리스트를 끝낸 뒤 active `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 내용과 stdout/stderr로 채우고 active pair를 그대로 둔 채 리뷰 준비 완료를 보고한다. 차단 시에는 정확한 blocker, 시도한 명령/출력, 재개 조건만 구현 소유 evidence에 기록한다. 사용자에게 결정을 묻거나 user-input 도구·control-plane stop 파일을 만들거나 다음 상태를 분류하지 않으며, log archive·`complete.log`·roadmap·`WORK_LOG.md`는 수정하지 않는다.

## 배경

여섯 번째 구현 루프도 active review의 완료표와 evidence를 비운 채 `RequestRuntimeSnapshot` 기준선만 남겼다. 필수 owner API와 lifecycle fixture가 없어 package PASS가 실제 request-local lifecycle을 실행하지 않는다. 이 후속은 transport-agnostic 경계를 유지하며 owner loop, fake-host 검증, 신뢰 가능한 review evidence를 한 번에 닫는다.

## Archive Evidence Snapshot

- 이전 Plan: `agent-task/m-stream-evidence-gate-core/19+18_core_runtime_loop/plan_local_G07_5.log`
- 이전 Review: `agent-task/m-stream-evidence-gate-core/19+18_core_runtime_loop/code_review_cloud_G07_5.log`
- 판정: `FAIL`
- 문제 수: Required 3, Suggested 0, Nit 0
- 문제 요약:
  - `packages/go/streamgate/runtime.go`에 request-local owner와 initial/recovery 공통 binding 설치 경로가 없다.
  - `packages/go/streamgate/runtime_test.go`가 없어 focused lifecycle 명령이 `[no tests to run]`으로 끝난다.
  - active review 구현 체크·설계 결정·실제 검증 출력이 비어 있고 formatting/import 검증은 누락 파일 때문에 rc=2다.
- 영향 파일: `packages/go/streamgate/runtime.go`, `packages/go/streamgate/runtime_test.go`, active review evidence
- 실제 검증 evidence: Go `1.26.2`, GOROOT `/config/opt/go`; `make proto`, package unit/race, `git diff --check`는 PASS했다. focused lifecycle은 `[no tests to run]`, `gofmt`와 import boundary는 `runtime_test.go` 부재로 rc=2였다.
- 기본 재열람은 불필요하다. 세부 판정이 필요할 때만 위 두 archive 파일을 좁게 읽는다.
- Roadmap carryover: 이 subtask 단독 PASS는 Milestone Task id 완료를 주장하지 않으므로 `Roadmap Targets`를 두지 않는다.

## 분석 결과

### 읽은 파일

- `packages/go/streamgate/runtime.go`
- `packages/go/streamgate/runtime_contract_test.go`
- `agent-task/m-stream-evidence-gate-core/19+18_core_runtime_loop/plan_local_G07_5.log`
- `agent-task/m-stream-evidence-gate-core/19+18_core_runtime_loop/code_review_cloud_G07_5.log`
- `agent-task/archive/2026/07/m-stream-evidence-gate-core/18+14,16_runtime_contract/complete.log`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md`
- `agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md`
- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/rules/common/rules-agent-spec.md`
- `agent-spec/index.md`
- `agent-contract/index.md`
- `agent-test/local/rules.md`
- `agent-test/local/platform-common-smoke.md`

### SDD 기준

- SDD: `agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md`, 상태 `[승인됨]`, 잠금 `해제`, 사용자 리뷰 `없음`.
- 대상 Acceptance Scenario는 S03/S05 staged response·commit eligibility, S12/S13 all-complete/single action, S14 cycle당 단일 plan/dispatch와 cap, S16 vertical lifecycle, S18 continuation 보존, S20 abort failure no-dispatch, S23 one-shot prepare다.
- Evidence Map의 eager commit 금지, complete outcome set, single plan/dispatch/terminal, replace reset/continuation preserve, prepare success/failure/no-budget, binding switch/backpressure/cancel/exhausted fixture를 구현 항목 1/2와 fresh unit/race 검증에 직접 연결한다.
- 이 subtask는 `recovery-coordinator`나 `vertical-slice` Roadmap Task 전체를 단독 완료하지 않으므로 Roadmap Task id를 체크하지 않는다.

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`와 `agent-test/local/platform-common-smoke.md`를 읽었다.
- PATH의 host Go는 `/config/.local/bin/go` → `/config/opt/go/bin/go`, `go1.26.2`, GOROOT `/config/opt/go`로 일치한다.
- profile의 `make proto`를 setup으로 실행한다. transport-agnostic package의 실제 동작은 fresh package focused/unit/race로 검증하며 cache를 허용하지 않는다.
- 외부 runner, Docker, provider, port, credential은 필요 없다. repo-local 검증 산출물은 만들지 않는다.
- agent-spec index에는 `streamgate` 매칭 living spec이 없고, agent-contract index에도 이 transport-agnostic owner 전용 계약은 없다. 승인 SDD, 코드, 테스트를 기준으로 판정한다.

### 테스트 커버리지 공백

- `runtime_contract_test.go`는 options, snapshot validation, filter context builder만 검증한다.
- owner construction/Run, response staging, initial/recovery binding re-resolution, arbitration action, prepare/dispatch ordering, terminal convergence를 실행하는 테스트가 없다.
- 새 `runtime_test.go`의 세 public-entry fixture가 disabled/pass, recovery, failure/concurrency matrix를 모두 실행해야 한다.

### 심볼 참조

- rename/remove 대상은 없다.
- `rg` 기준 `RequestRuntime`, `NewRequestRuntime`, `installAttempt` 참조는 없고 `NormalizedEventSource`/`AttemptBinding`은 Core 계약과 Edge 후속 dispatcher에서만 사용된다.

### 분할 판단

- split decision policy를 파일명 확정 전에 평가했다.
- 현재 고정 subtask의 owner state와 fake-host assertions는 같은 public API와 side-effect count를 함께 검증해야 하므로 production/test 분리는 독립 PASS 단위를 만들지 못한다.
- primary ownership은 `packages/go/streamgate` 하나이며 Edge codec/admission/HTTP 연결과 observation은 기존 sibling에 분리돼 있다. 현재 두 파일 범위를 더 쪼개면 artificial coordination만 늘어난다.
- 선행 index `18`은 `agent-task/archive/2026/07/m-stream-evidence-gate-core/18+14,16_runtime_contract/complete.log`의 PASS로 충족됐고 현재 subtask 경로의 dependency metadata는 유지한다.

### 범위 결정 근거

- 수정 범위는 `packages/go/streamgate/runtime.go`, 새 `packages/go/streamgate/runtime_test.go`, active review evidence다.
- raw codec/proto, concrete admission/auth/model selection, OpenAI request rebuild, HTTP/SSE serialization, config, observation sink, Edge handler와 roadmap 문서는 제외한다.
- 기존 `FilterRegistrySnapshot`, `EvidenceTail`, `GateCoordinator`, `DecisionArbiter`, `RecoveryCoordinator`, `StreamReleaser` 계약을 조립하며 해당 component를 재구현하거나 `apps/*/internal`을 import하지 않는다.

### 최종 라우팅

- evaluation_mode: `isolated-reassessment`; finalizer: `finalize-task-policy.sh`; finalizer_mode: `pair`.
- build closures: scope/context/verification/evidence/ownership/decision 모두 `true`.
  - scope: owner lifecycle, fake-host fixture, review evidence가 `runtime.go`, 새 `runtime_test.go`, active review로 닫힌다.
  - context: 승인 SDD state machine, 기존 snapshot·host seam, package component와 현재 실패 출력을 함께 유지할 수 있다.
  - verification/evidence: owner symbol과 test 파일 부재, `[no tests to run]`, rc=2 formatting/import 실패가 재현됐고 fresh focused/unit/race로 성공을 결정할 수 있다.
  - ownership/decision: `packages/go/streamgate` 단일 소유이며 Milestone 잠금은 해제됐고 결정 필요가 없다.
- build route_basis: `local-fit`; capability_gap: `none`; grade scores: scope_coupling=2, state_concurrency=2, blast_irreversibility=1, evidence_diagnosis=1, verification_complexity=1, 합계 G07.
- build loop risk: state 16개와 retry/cancel/recovery/duplicate 경로, owner·Gate·filter evaluator 3 actor와 single-flight/exactly-once 제약, 7개 Core component immutable boundary, commit×resume×enforcement×cap variant 축이 있다. structured interpretation은 없다. matched signatures는 `temporal_state`, `concurrent_consistency`, `boundary_contract`, `variant_product`; triggered=true.
- build output: lane=`local`, grade=`G07`, filename=`PLAN-local-G07.md`.
- review closures: scope/context/verification/evidence/ownership/decision 모두 `true`; 공식 reviewer가 SDD, owner state, concurrency fixture와 실제 명령 출력을 독립 대조할 수 있다.
- review route_basis: `official-review`; capability_gap: `none`; grade scores: scope_coupling=2, state_concurrency=2, blast_irreversibility=1, evidence_diagnosis=1, verification_complexity=1, 합계 G07.
- review output: lane=`cloud`, grade=`G07`, filename=`CODE_REVIEW-cloud-G07.md`, target=`Codex gpt-5.6-sol xhigh`.

## 구현 체크리스트

- [ ] REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP-1 initial/recovery binding을 같은 attempt 설치 경로로 연결하고 normalized event → evidence/evaluation/arbitration → release/recovery/terminal request-local owner loop를 구현한다.
- [ ] REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP-2 fake host로 disabled/pass, one recovery, simultaneous violation, prepare success/failure, binding switch, failure policy, backpressure, cancel, 0/1/3 exhausted single-terminal fixture를 추가한다.
- [ ] REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP-3 environment/proto setup, streamgate focused/unit/race, formatting/import boundary, diff 검증을 fresh 실행하고 review evidence를 복구한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP-1] request-local owner lifecycle

- 문제: `packages/go/streamgate/runtime.go:113-296`은 immutable snapshot과 `BuildAttemptFilterContext`에서 끝난다. initial binding 설치, event owner, staged response, attempt-local filter resolve, evidence epoch, arbitration, recovery rebinding, terminal convergence가 없다.
- 해결 방법:
  - `import ("context"; "errors")`를 사용해 host initial `AttemptBinding`과 model group을 받는 `RequestRuntime`/constructor/`Run(context.Context)`를 추가한다.
  - private `installAttempt(binding, resumeMode)` 하나가 initial/recovery binding을 검증하고 actual model/provider/path로 fixed registry snapshot의 active set을 다시 resolve한다. replace는 pending/look-behind/cursor를 reset하고 continuation은 committed look-behind/cursor와 downstream commit state를 보존한다.
  - response-start는 stage만 하고 나머지 normalized event는 tail → immutable batch → Gate all-complete → Arbiter single action으로 직렬화한다. release/terminal은 `StreamReleaser`, recovery는 request-local `RecoveryCoordinator`만 호출한다.
  - cycle/terminal/stale guard로 plan/dispatch/terminal 중복과 terminal 이후 sink 호출을 거부하고 모든 종료 경로에서 Gate를 닫는다.
- Before (`packages/go/streamgate/runtime.go:115`):

```go
type RequestRuntimeSnapshot struct {
    // immutable request state and host seams only
}
```

- After:

```go
type RequestRuntime struct {
    snapshot RequestRuntimeSnapshot
    // request-local attempt, evidence, gate, recovery, release and terminal state
}

func NewRequestRuntime(snapshot RequestRuntimeSnapshot, modelGroup string, initial AttemptBinding) (*RequestRuntime, error)
func (r *RequestRuntime) Run(ctx context.Context) error
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/streamgate/runtime.go`: owner constructor/state와 shared attempt install을 추가한다.
  - [ ] `packages/go/streamgate/runtime.go`: staged response/event/evidence/all-complete arbitration action loop를 추가한다.
  - [ ] `packages/go/streamgate/runtime.go`: replace/continuation rebinding과 cancel/error/cap single-terminal convergence를 추가한다.
- 테스트 작성: 작성. `runtime_test.go`의 세 public-entry test가 normal/boundary/concurrency path를 실행한다.
- 중간 검증: `go test -count=1 ./packages/go/streamgate -run '^TestRequestRuntime(DisabledAndPass|RecoveryLifecycle|FailureMatrix)$'`가 `[no tests to run]` 없이 PASS해야 한다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP-2] fake-host lifecycle fixtures

- 문제: `packages/go/streamgate/runtime_test.go:1`이 없고 기존 `runtime_contract_test.go`는 owner lifecycle을 실행하지 않는다.
- 해결 방법:
  - 새 테스트는 `import ("context"; "errors"; "sync"; "testing"; "time")`를 사용하고 deterministic fake event source/controller/dispatcher/rebuilder/preparer/sink와 injected filter를 둔다.
  - disabled/Noop pass에서 staged response-start가 first safe body 직전에 한 번 commit되는지 검증한다.
  - violation/conflict에서 cycle당 plan/abort/rebuild/dispatch 하나, recovery binding target re-resolution, prepare success ordering과 failure no-dispatch/no-budget를 검증한다.
  - replace reset, continuation safe-prefix/look-behind/cursor 보존, blocking/observe-only failure, channel barrier backpressure, caller cancel, 0/1/3 cap exhaustion과 terminal sink 정확히 1회를 table-driven assertion으로 고정한다.
- 수정 파일 및 체크리스트:
  - [ ] 새 `packages/go/streamgate/runtime_test.go`: thread-safe fake host/filter/recorder를 추가한다.
  - [ ] `TestRequestRuntimeDisabledAndPass`: disabled와 enabled Noop staging/release를 검증한다.
  - [ ] `TestRequestRuntimeRecoveryLifecycle`: single conflict recovery, prepare, binding switch, replace/continue를 검증한다.
  - [ ] `TestRequestRuntimeFailureMatrix`: enforcement, backpressure, cancel, exhaustion과 single terminal을 검증한다.
- 테스트 작성: 작성. wall-clock sleep 대신 channel/barrier와 side-effect order/count를 사용한다.
- 중간 검증: `go test -race -count=1 ./packages/go/streamgate -run '^TestRequestRuntime'`가 race와 `[no tests to run]` 없이 PASS해야 한다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP-3] 검증과 evidence 복구

- 문제: `code_review_cloud_G07_5.log:49-175`의 구현 소유 완료/evidence가 비어 있고, 현재 재실행도 누락 테스트 때문에 lifecycle을 증명하지 못한다.
- 해결 방법: 고정 명령을 fresh 실행하고 active review의 완료표·체크리스트·계획 대비 변경·주요 설계 결정·각 `_실제 출력:_`을 채운다. 명령 변경 시 이유와 대체 명령을 `계획 대비 변경 사항`에 기록한다.
- 수정 파일 및 체크리스트:
  - [ ] production/test 파일을 gofmt하고 Core import boundary를 확인한다.
  - [ ] environment/setup/focused/unit/race/diff 명령을 fresh 실행한다.
  - [ ] active review 구현 소유 섹션에 실제 stdout/stderr와 완료 evidence를 기록한다.
- 테스트 작성: 별도 테스트 없음. 항목 1/2의 실제 실행 trust를 닫는 evidence 작업이다.
- 중간 검증: `git diff --check` 출력이 없고 active review에 placeholder `_실제 출력:_`만 남지 않아야 한다.

## 의존 관계 및 구현 순서

`18` (`agent-task/archive/2026/07/m-stream-evidence-gate-core/18+14,16_runtime_contract/complete.log`, PASS) → REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP-1 → REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP-2 → REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP-3. 후속 `20`은 이 subtask PASS 이후 Core owner를 Edge host에 연결한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `packages/go/streamgate/runtime.go` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP-1 |
| 새 `packages/go/streamgate/runtime_test.go` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP-1/2 |
| `agent-task/m-stream-evidence-gate-core/19+18_core_runtime_loop/CODE_REVIEW-cloud-G07.md` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_CORE_RUNTIME_LOOP-3 evidence |

## 최종 검증

- `command -v go && readlink -f "$(command -v go)" && go version && go env GOROOT` — host Go/GOROOT 일치.
- `make proto` — setup 성공.
- `gofmt -d packages/go/streamgate/runtime.go packages/go/streamgate/runtime_test.go` — 출력 없음.
- `go test -count=1 ./packages/go/streamgate -run '^TestRequestRuntime(DisabledAndPass|RecoveryLifecycle|FailureMatrix)$'` — fresh focused PASS, `[no tests to run]` 없음.
- `go test -count=1 ./packages/go/streamgate` — fresh package PASS.
- `go test -race -count=1 ./packages/go/streamgate` — fresh race PASS.
- `rg -n --sort path 'iop/apps/' packages/go/streamgate/runtime.go packages/go/streamgate/runtime_test.go` — 출력 없음.
- `git diff --check` — 출력 없음.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다.
