<!-- task=m-iop-owned-single-request-agent-execution/09+08_workspace_wire plan=3 tag=REVIEW_REVIEW_API milestone-task=tool-executor -->

# Reject Contradictory Workspace Wire Outcomes

## For the Implementing Agent

This is the direct-fix follow-up for remaining Required R3. Change only the two production/test files listed below, run every verification command uncached where specified, fill the paired review stub with actual evidence, keep the active files in place, and report ready for review. If blocked, record the exact blocker, attempted commands/output, and resume condition only in implementation-owned evidence fields. Do not ask the user, call user-input tools, create control-plane stop files, classify the next state, archive artifacts, or write `complete.log`; finalization belongs to the official code reviewer.

## Background

The cancellation and admitted-reference repairs now pass, but the four response validators still accept an allowed terminal status paired with a failure error code and raw Node error text. That contradictory response is returned to the caller with nil error, so the prior R3 raw-free typed-outcome requirement remains open. This packet closes only that validation gap and its missing regression matrix.

## Archive Evidence Snapshot

- Plan 2 and its failed review are preserved at `agent-task/m-iop-owned-single-request-agent-execution/09+08_workspace_wire/plan_cloud_G08_2.log` and `agent-task/m-iop-owned-single-request-agent-execution/09+08_workspace_wire/code_review_cloud_G09_2.log`. The verdict is `FAIL` with remaining Required R3; R1 cancellation and R2 admitted-reference behavior passed fresh verification.
- The reviewer reran the dependency, focused race, package, vet, and whitespace checks successfully. A focused four-family probe then proved that open, tool, cancel, and cleanup validators all accept the allowed status plus `WORKSPACE_ERROR_CODE_INTERNAL` and raw `Error`; the temporary probe file was removed.

## Finding Resolution Map

| Finding | Disposition | Direct-fix targets | Changed precondition and proof |
|---|---|---|---|
| Required R3 | direct-fix | `apps/edge/internal/service/workspace_wire.go`, `apps/edge/internal/service/workspace_wire_test.go` | An accepted open/tool/cleanup success or cancel terminal must also have `WORKSPACE_ERROR_CODE_UNSPECIFIED` and an empty `Error`; every contradictory combination returns nil plus stable `errWorkspaceWireResponse`, proven across all four families. |

## Analysis

### Files Read

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/rules/common/rules-agent-spec.md`
- `agent-ops/rules/project/domain/edge/rules.md`
- `agent-ops/rules/project/domain/node/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/edge-smoke.md`
- `agent-test/local/node-smoke.md`
- `agent-roadmap/phase/knowledge-tool-optimization-extension/PHASE.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-contract/index.md`
- `agent-contract/inner/edge-node-runtime-wire.md`
- `agent-spec/index.md`
- `agent-spec/runtime/edge-node-execution.md`
- `proto/iop/runtime.proto`
- `apps/edge/internal/node/registry.go`
- `apps/edge/internal/service/workspace_wire.go`
- `apps/edge/internal/service/workspace_wire_test.go`
- `apps/node/internal/transport/session.go`
- `apps/node/internal/transport/session_test.go`
- `/config/workspace/proto-socket/go/communicator.go`
- `agent-task/m-iop-owned-single-request-agent-execution/09+08_workspace_wire/plan_cloud_G08_2.log`
- `agent-task/m-iop-owned-single-request-agent-execution/09+08_workspace_wire/code_review_cloud_G09_2.log`

### SDD Criteria

- SDD: `agent-roadmap/sdd/knowledge-tool-optimization-extension/iop-owned-single-request-agent-execution/SDD.md`; status `[승인됨]`, lock released.
- First-line scope remains `milestone-task=tool-executor`.
- Acceptance Scenario S05 requires consistent typed success, failure, timeout, cancel, and bounded result behavior for the dedicated Node tool wire.
- The S05 Evidence Map requires typed wire success/error/cancel evidence. Therefore the implementation checklist requires closed terminal/error consistency and the final verification retains focused race plus affected package regression evidence.

### Verification Context

- No separate verification handoff was supplied. Repository-native fallback came from the local test rules, Edge/Node smoke profiles, the active plan commands, source tests, and fresh reviewer execution.
- Local preflight: repository root `/config/workspace/iop-s0`; Go executable `/config/.local/bin/go`; `go version go1.26.2 linux/arm64`; shared dirty worktree with unrelated in-flight milestone packets.
- Required checks are repository-local and credential-free: predecessor completion, focused race tests, affected package regression, vet, and whitespace validation.
- The archived predecessor is uniquely resolved at `agent-task/archive/2026/08/m-iop-owned-single-request-agent-execution/08+03,07_workspace_admission/complete.log`.
- External Claude/full-cycle execution is not part of this wire-only R3 repair and remains owned by the milestone's later `claude-smoke` packet. Confidence is high because the defect and oracle are deterministic inside the four validators.

### Test Coverage Gaps

- Existing invalid-response coverage rejects disallowed status and identity mismatch cases.
- Missing: allowed open/tool/cleanup success or cancel status combined with a non-unspecified error code.
- Missing: allowed status with an otherwise unspecified error code but non-empty raw `Error`.
- The new regression must cover both contradictions for all four response families and require nil response plus the stable raw-free sentinel error.

### Symbol References

- No symbol is renamed or removed.
- `validateWorkspaceOpenResponse`, `validateWorkspaceToolResponse`, `validateWorkspaceCancelResponse`, and `validateWorkspaceCleanupResponse` are called only by their matching service dispatch functions in `apps/edge/internal/service/workspace_wire.go` and are exercised by `workspace_wire_test.go`.

### Split Judgment

- The four validators implement one closed outcome invariant and share one table-driven regression oracle. Splitting would duplicate the same protocol rule and could leave response families inconsistent, so this compact repair remains one packet.
- Subtask dependency `08` is satisfied by `agent-task/archive/2026/08/m-iop-owned-single-request-agent-execution/08+03,07_workspace_admission/complete.log`.

### Scope Rationale

- Include only Edge workspace response outcome validation, its deterministic tests, and the active review evidence file.
- Exclude Node concurrency/cancellation files because R1 now passes, admitted-reference logic because R2 now passes, and proto/contract/spec because the closed enums and documented raw-free behavior already express the intended contract.
- Exclude roadmap state, executor filesystem/process behavior, public APIs, and unrelated shared-worktree changes.

### Final Routing

- `evaluation_mode=isolated-reassessment`; `finalizer=finalize-task-policy.sh`; both build and review closures are true with no capability gap.
- Build scores are 1/0/1/2/1 = G05. `large_indivisible_context=false`; matched loop-risk signatures are `boundary_contract` and `variant_product`, so `loop_risk_count=2` and the risk boundary is false.
- `review_rework_count=2` and `evidence_integrity_failure=true`, so the local-fit build uses `recovery-boundary`, lane `cloud`, filename `PLAN-cloud-G05.md`.
- Review scores are 1/0/1/2/1 = G05; official review uses lane `cloud`, filename `CODE_REVIEW-cloud-G05.md`.

## Dependencies and Execution Order

1. Keep predecessor packet 08 uniquely complete.
2. Enforce the closed terminal/error invariant across all four validators.
3. Add the missing contradictory-outcome matrix, then rerun the preserved R1/R2 and package checks.

## Implementation Checklist

- [ ] Accept open/tool/cleanup success and cancel terminal responses only when `error_code` is `WORKSPACE_ERROR_CODE_UNSPECIFIED` and `Error` is empty; reject every contradiction with nil response and stable `errWorkspaceWireResponse`.
- [ ] Add deterministic four-family regressions for an allowed status with a failure error code and for an allowed status with raw `Error` text, asserting no raw sentinel is caller-reachable.
- [ ] Preserve the reviewed R1 cancellation and R2 admitted-reference behavior and run every final verification command uncached where specified.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

## Implementation Plan

### [REVIEW_REVIEW_API-1] Close workspace response outcome validation

**Problem**

`apps/edge/internal/service/workspace_wire.go:167-204` validates identities and the expected status only. A Node can return the expected terminal with `WORKSPACE_ERROR_CODE_INTERNAL` or a non-empty raw `Error`, and the service returns that response with nil error.

**Solution**

Before (`apps/edge/internal/service/workspace_wire.go:167`):

```go
if resp.GetStatus() != iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS {
    return nil, errWorkspaceWireResponse
}
return resp, nil
```

After, apply one closed terminal predicate consistently to all four validators:

```go
if resp.GetStatus() != expectedStatus ||
    resp.GetErrorCode() != iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSPECIFIED ||
    resp.GetError() != "" {
    return nil, errWorkspaceWireResponse
}
return resp, nil
```

Keep identity validation unchanged. Do not return, log, or interpolate the raw Node `Error` on any rejected outcome.

**Modified Files and Checklist**

- [ ] `apps/edge/internal/service/workspace_wire.go` — enforce allowed status plus unspecified error code plus empty error for every accepted family.
- [ ] `apps/edge/internal/service/workspace_wire_test.go` — add the eight-case four-family contradictory-outcome regression matrix.

**Test Strategy**

- Add `TestWorkspaceWireRejectsContradictoryTerminalOutcome` in `apps/edge/internal/service/workspace_wire_test.go`.
- Cover open, tool, cancel, and cleanup with two variants each: expected status plus `WORKSPACE_ERROR_CODE_INTERNAL`, and expected status plus a raw sentinel with an unspecified code.
- Assert each call returns nil response, `errors.Is(err, errWorkspaceWireResponse)`, and an error string that excludes the raw sentinel. Existing blocked-tool cancellation, reference no-send, invalid status/identity, and timeout tests remain unchanged.

**Verification**

- `go test -race ./apps/edge/internal/service ./apps/node/internal/transport -run 'Test(WorkspaceWire|SessionWorkspace)' -count=1`
- Expected: the new contradiction matrix and preserved R1/R2/Node concurrency tests pass uncached under race.

## Modified Files Summary

| File | Item |
|---|---|
| `apps/edge/internal/service/workspace_wire.go` | REVIEW_REVIEW_API-1 |
| `apps/edge/internal/service/workspace_wire_test.go` | REVIEW_REVIEW_API-1 |
| `agent-task/m-iop-owned-single-request-agent-execution/09+08_workspace_wire/CODE_REVIEW-cloud-G05.md` | REVIEW_REVIEW_API-1 |

## Final Verification

1. `test -f agent-task/m-iop-owned-single-request-agent-execution/08+03,07_workspace_admission/complete.log || test "$(compgen -G 'agent-task/archive/*/*/m-iop-owned-single-request-agent-execution/08+03,07_workspace_admission/complete.log' | wc -l)" -eq 1`
2. `go test -race ./apps/edge/internal/service ./apps/node/internal/transport -run 'Test(WorkspaceWire|SessionWorkspace)' -count=1`
3. `go test ./apps/edge/internal/node ./apps/edge/internal/service ./apps/edge/internal/transport ./apps/node/internal/transport -count=1`
4. `go vet ./apps/edge/internal/node ./apps/edge/internal/service ./apps/edge/internal/transport ./apps/node/internal/transport`
5. `git diff --check`

Expected: the predecessor remains uniquely complete; all accepted workspace terminals have no failure code or raw error text; contradictory outcomes fail with a nil response and stable raw-free error; preserved cancellation/reference behavior and all affected packages pass. Cached test results are not acceptable for commands using `-count=1`.

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