<!-- task=m-iop-owned-single-request-agent-execution/06+05_stream_terminal plan=3 tag=REVIEW_API milestone-task=stream-terminal -->

# Propagate Single-request Anthropic SSE Flush Failures

## For the Implementing Agent

Implement this follow-up exactly within the listed write boundary, run every verification command, fill all implementation-owned sections of `CODE_REVIEW-cloud-G07.md` with actual notes and stdout/stderr, keep the active pair in place, and report ready for review. Finalization belongs only to the code-review skill. If blocked, record the exact blocker, attempted commands/output, and resume condition in implementation-owned evidence fields; do not ask the user, call user-input tools, create control-plane stop files, classify the next state, archive logs, or write `complete.log`.

## Background

The marked single-request projector currently detects `Write` errors but discards the error-reporting flush path supported by Go's HTTP response controller. It can therefore acknowledge coordinator completion even when the final `message_stop` was not flushed to the caller. This follow-up closes that terminal-commit gap without changing the generic Anthropic/Hot Path helper.

## Archive Evidence Snapshot

- Superseded pair: `plan_cloud_G09_2.log`, `code_review_cloud_G10_2.log`.
- Verdict: `FAIL`; Required R1 found that `single_request_anthropic_stream.go` uses error-blind `http.Flusher.Flush()` through `writeDirectAnthropicEvent` and can call `AcknowledgeTerminal(true)` after a terminal flush failure.
- Existing focused/race, package, vet, Edge/streamgate regression, documentation search, and `git diff --check` commands passed. A focused reviewer reproducer with `FlushError() == io.ErrClosedPipe` failed as `pump error=<nil>, want flush failure` and was removed after the check.
- Roadmap carryover remains `milestone-task=stream-terminal`, SDD Acceptance Scenario S03, and one-envelope/one-terminal evidence.

## Finding Resolution Map

| Finding | Mode | Exact Fix / Evidence | Changed Precondition |
|---------|------|----------------------|----------------------|
| Required R1 | direct-fix | Add a projector-owned error-reporting event flush in `apps/edge/internal/openai/single_request_anthropic_stream.go` and a deterministic terminal `FlushError` regression in `apps/edge/internal/openai/single_request_anthropic_stream_test.go`. | Every projector event can now report flush failure, so `AcknowledgeTerminal(true)` is reachable only after the final `message_stop` write and flush both succeed. |

## Analysis

### Files Read

- `apps/edge/internal/openai/single_request_anthropic_stream.go`
- `apps/edge/internal/openai/single_request_anthropic_stream_test.go`
- `apps/edge/internal/openai/hot_path_direct.go`
- `apps/edge/internal/openai/anthropic_handler.go`
- `apps/edge/internal/service/single_request.go`
- `go.mod`
- `agent-contract/outer/anthropic-compatible-api.md`
- `agent-spec/input/openai-compatible-surface.md`
- `agent-spec/runtime/stream-evidence-gate.md`
- `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/iop-owned-single-request-agent-execution.md`
- `agent-roadmap/sdd/knowledge-tool-optimization-extension/iop-owned-single-request-agent-execution/SDD.md`
- `agent-task/m-iop-owned-single-request-agent-execution/06+05_stream_terminal/code_review_cloud_G10_2.log`
- `agent-task/m-iop-owned-single-request-agent-execution/06+05_stream_terminal/plan_cloud_G09_2.log`

### SDD Criteria

- SDD: `agent-roadmap/sdd/knowledge-tool-optimization-extension/iop-owned-single-request-agent-execution/SDD.md`; status `[승인됨]`, SDD lock released, and no `USER_REVIEW.md` exists.
- First-line Milestone task: `stream-terminal`; targeted Acceptance Scenario: S03.
- S03 and its Evidence Map require fragmented multi-stage SSE with one outer envelope, collision-free blocks, no private wire, and one final terminal. The state invariant also requires `completed` only after successful response commit. Those criteria require the flush-failure regression and the negative terminal acknowledgement in REVIEW_API-1.

### Verification Context

- No separate verification handoff was supplied. Repository-native evidence is the reviewer reproducer, the existing exact-wire/race tests, the service acknowledgement state machine, the Anthropic outer contract, the approved SDD, and the local Edge smoke profile.
- Precondition `05+03_single_ingress` is satisfied by `agent-task/archive/2026/08/m-iop-owned-single-request-agent-execution/05+03_single_ingress/complete.log`.
- Deterministic local verification needs no credential, remote runner, or provider. Go `1.24` is declared by `go.mod`, and the current toolchain supports `http.NewResponseController`.
- The later `claude-smoke` packet still owns credentialed real-Claude qualification. This repair changes only error propagation at the endpoint writer and does not require external execution.
- Confidence is high because the reviewer reproduced the exact false-success state and the new test can use the same service handle and deterministic writer seam.

### Test Coverage Gaps

- Existing `TestSingleRequestAnthropicStreamTerminalWriteFailureDoesNotComplete` proves a direct `Write` error fails the coordinator.
- No existing test exposes `FlushError`; the projector therefore returned nil and completed the coordinator in the reviewer reproducer. Add one exact regression for a `message_stop` flush failure.
- Existing ordering, privacy, ping shutdown, disconnect, one-POST, ordinary Anthropic, and Hot Path tests remain sufficient after the localized fix.

### Symbol References

- No symbol is renamed or removed.
- `writeDirectAnthropicEvent` remains used by generic direct/Hot Path streaming. The follow-up must not change its behavior; the marked projector gets its own error-reporting event write.

### Split Judgment

- Keep one plan. Event write, flush, terminal ownership, service acknowledgement, and the regression test form one indivisible commit invariant.
- Runtime predecessor `05` is satisfied by the exact archived `complete.log` above; no dependency wait remains.

### Scope Rationale

- Modify only the marked projector and its tests. Do not alter generic Anthropic relay, Hot Path codecs/helpers, Stream Evidence Gate, service state transitions, contracts, or specs because their current behavior and text are not the root cause.
- Do not add retry or alternate terminal behavior after a failed/partial flush. The existing terminal owner remains closed and the service receives a negative acknowledgement.

### Final Routing

- `evaluation_mode=isolated-reassessment`; finalizer `finalize-task-policy.sh` in `pair` mode.
- Build closures are all true; scores are 1/2/2/1/1 = G07. Base route is `local-fit`; positive risks are `temporal_state`, `concurrent_consistency`, `boundary_contract`, `structured_interpretation`, and `variant_product` (5), so final route is `risk-boundary`, lane `cloud`, filename `PLAN-cloud-G07.md`.
- Build signals: `large_indivisible_context=false`, `review_rework_count=1`, `evidence_integrity_failure=false`; no capability gap.
- Review closures are all true; scores are 1/2/2/1/1 = G07; route `official-review`, lane `cloud`, filename `CODE_REVIEW-cloud-G07.md`.

## Dependencies and Execution Order

1. Preserve the satisfied packet 05 dependency and the existing marked-stream public contract.
2. Replace only the marked projector's event flush path and add the terminal flush-failure regression.
3. Run the focused race test before the full compatibility and Edge regression set.

## Implementation Checklist

- [ ] Resolve Required R1 by making every marked-projector event use an error-reporting flush path, preserving exactly-once terminal ownership, and add a deterministic terminal flush-failure regression proving negative acknowledgement.
- [ ] Preserve generic Anthropic/Hot Path behavior and rerun the focused flush, exact-wire race, compatibility, package, vet, full Edge/streamgate, and diff checks.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

## Implementation Plan

### [REVIEW_API-1] Make marked SSE flush part of terminal success

**Problem**

- `apps/edge/internal/openai/single_request_anthropic_stream.go:196` sends `message_stop` through `writeDirectAnthropicEvent`.
- `apps/edge/internal/openai/hot_path_direct.go:478` invokes `http.Flusher.Flush()` without an error result, so `Final` returns nil even when the writer supports `FlushError()` and reports a failed commit.
- `apps/edge/internal/openai/single_request_anthropic_stream.go:378-380` then acknowledges the coordinator as completed from that false nil result.

**Solution**

Before (`apps/edge/internal/openai/single_request_anthropic_stream.go:188`):

```go
if err := writeDirectAnthropicEvent(s.w, s.flusher, "message_delta", delta); err != nil {
    s.terminalErr = err
    return err
}
if err := writeDirectAnthropicEvent(s.w, s.flusher, "message_stop", map[string]any{"type": "message_stop"}); err != nil {
    s.terminalErr = err
    return err
}
```

After, keep event encoding local to the projector and flush through the response controller:

```go
func (s *singleRequestAnthropicStream) writeEventLocked(event string, value any) error {
    if err := writeAnthropicSSEEvent(s.w, event, value); err != nil {
        return err
    }
    return http.NewResponseController(s.w).Flush()
}
```

Use this method for `message_start`, progress blocks, pings, success/error terminals, and keep the terminal flag claimed before terminal bytes. Extend the deterministic writer seam with a `FlushError` failure selected for `message_stop`; assert the pump returns the flush error and the execution state is `failed`.

**Modified Files and Checklist**

- [ ] `apps/edge/internal/openai/single_request_anthropic_stream.go` — propagate event flush errors through the marked projector without changing the generic helper.
- [ ] `apps/edge/internal/openai/single_request_anthropic_stream_test.go` — add `TestSingleRequestAnthropicStreamTerminalFlushFailureDoesNotComplete` and keep existing write-failure/order/race assertions.

**Test Strategy**

- Add the regression test with a writer that implements both `http.Flusher` and `FlushError() error`, succeeds through the final bytes, fails the `message_stop` flush with `io.ErrClosedPipe`, and proves no successful acknowledgement.
- Run the full `TestSingleRequestAnthropicStream` prefix under `-race` to cover the shared event method across progress, ping, and terminal concurrency.

**Verification**

- `go test -race ./apps/edge/internal/openai -run '^TestSingleRequestAnthropicStreamTerminalFlushFailureDoesNotComplete$' -count=1`
- Expected: the flush failure is returned and the execution state is failed, with no race.

### [REVIEW_API-2] Revalidate the closed marked-stream boundary

**Problem**

- A projector-local flush change touches every marked SSE event and must not regress event order, privacy, terminal exclusivity, ordinary Anthropic behavior, or the generic Hot Path helper left outside the write boundary.

**Solution**

Run the existing focused race suite, compatibility selection, full package race, vet, Edge/streamgate regression, and diff validation without changing contracts/specs or generic stream helpers.

**Modified Files and Checklist**

- [ ] `agent-task/m-iop-owned-single-request-agent-execution/06+05_stream_terminal/CODE_REVIEW-cloud-G07.md` — record actual implementation decisions, deviations, and command stdout/stderr.

**Test Strategy**

- No additional test file is needed beyond REVIEW_API-1. Existing exact-wire, ping shutdown, disconnect, one-POST, generic Anthropic, and Hot Path tests are the regression oracle.

**Verification**

- `go test -race ./apps/edge/internal/openai -run 'TestSingleRequestAnthropicStream' -count=1`
- `go test ./apps/edge/internal/openai -run 'Test(AnthropicSingleRequestStreaming|AnthropicSingleRequestStream|HotPathAnthropic)' -count=1`
- Expected: all focused and compatibility checks pass freshly.

## Modified Files Summary

| File | Item |
|------|------|
| `apps/edge/internal/openai/single_request_anthropic_stream.go` | REVIEW_API-1 |
| `apps/edge/internal/openai/single_request_anthropic_stream_test.go` | REVIEW_API-1 |
| `agent-task/m-iop-owned-single-request-agent-execution/06+05_stream_terminal/CODE_REVIEW-cloud-G07.md` | REVIEW_API-2 |

## Final Verification

1. `test -f agent-task/m-iop-owned-single-request-agent-execution/05+03_single_ingress/complete.log || test "$(compgen -G 'agent-task/archive/*/*/m-iop-owned-single-request-agent-execution/05+03_single_ingress/complete.log' | wc -l)" -eq 1`
2. `go test -race ./apps/edge/internal/openai -run '^TestSingleRequestAnthropicStreamTerminalFlushFailureDoesNotComplete$' -count=1`
3. `go test -race ./apps/edge/internal/openai -run 'TestSingleRequestAnthropicStream' -count=1`
4. `go test ./apps/edge/internal/openai -run 'Test(AnthropicSingleRequestStreaming|AnthropicSingleRequestStream|HotPathAnthropic)' -count=1`
5. `go test -race ./apps/edge/internal/openai -count=1`
6. `go vet ./apps/edge/...`
7. `go test ./apps/edge/... ./packages/go/streamgate/... -count=1`
8. `git diff --check`

Expected: dependency evidence is unique; the terminal flush regression fails closed; exact-wire/race/privacy/compatibility checks pass; generic helpers remain unchanged; vet, full Edge/streamgate regression, and diff validation exit 0. Cached test output is not acceptable; every Go test command uses `-count=1`.

**After completing all code changes, fill implementation-owned sections in `CODE_REVIEW-*-G??.md`.**
