<!-- task=m-iop-hot-path-one-shot-execution/17+15,16_hot_smoke plan=0 tag=TEST milestone-task=hot-smoke -->

# Claude/Pi Hot Path streaming smoke harness

## For the Implementing Agent

구현 후 `CODE_REVIEW-cloud-G08.md`의 구현 담당 섹션에 self-test와 실제 external run의 원문 출력을 채우고 active 파일을 유지한다. 외부 환경이 없으면 정확한 preflight blocker와 재개 조건만 기록하며 사용자 질문, 상태 판정, archive, `complete.log` 작성은 하지 않는다.

## Background

단위·handler fixture만으로는 실제 Claude Messages와 Pi Chat agent가 tool loop, visible stage output, artifact lifecycle, terminal을 소비하는지 증명할 수 없다. secret을 출력하지 않는 공통 harness와 재현 가능한 manifest를 만들고 두 agent×핵심 시나리오를 외부 runtime에서 실행한다.

## Analysis

### Files Read

- `agent-roadmap/sdd/knowledge-tool-optimization-extension/iop-hot-path-one-shot-execution/SDD.md`
- `Makefile`
- `scripts/e2e-openai-cli-workspace.sh`
- `agent-test/local/rules.md`
- `agent-test/local/edge-smoke.md`
- `agent-test/dev/edge-smoke.md`
- `agent-test/inventory-agent.yaml`

### SDD Criteria

- 승인 SDD, `milestone-task=hot-smoke`, S16.
- Evidence Map S16은 actual Claude/Pi streaming log와 workspace before/after를 요구한다. direct, light pass, defect repair, write unavailable, timeout/cancel 및 cleanup을 protocol별 manifest rows로 고정한다.

### Verification Context

- handoff 없음. local이 기본 환경이며 현재 checkout은 `/config/workspace/iop-s0`, branch `feature/iop-hot-path-one-shot-execution`, HEAD `6650e9f70d0104220d8077dd1d469b6a1facb9da`; 계획 작성 시작 시 worktree clean이었다.
- OS/arch=`Linux 6.10.14-linuxkit aarch64`; Go=`/config/.local/bin/go`, `go1.26.2`; `curl`, `jq`, `timeout` 사용 가능하고 `ss`는 없다.
- `claude`=`/config/.npm-global/bin/claude`, version `2.1.220`; `claude --help`에서 `--print --output-format stream-json --include-partial-messages --no-session-persistence` 확인.
- `pi`=`/config/.npm-global/bin/pi`, version `0.81.1`; `pi --help`에서 `--provider --model --mode json --print --no-session` 확인. inventory의 기록 버전 0.80.3과 drift가 있으므로 actual manifest에 관측 버전을 기록한다.
- 현재 local에는 확인된 preset-backed Edge/Node listener나 runtime identity가 없고 여러 공유 Claude/Pi process가 실행 중이므로 건드리지 않는다. dev inventory에서 Pi는 configured, Claude는 not_configured이며 dev base 후보는 `http://toki-labs.com:18083/v1`이나 실제 S16 runner로 확정하지 않는다.

#### External Verification Preflight

- runner owner: credential과 writable disposable workspace를 가진 operator/review runner.
- preflight는 repo root/branch/HEAD/dirty, CLI absolute path/version/help capability, supplied config/profile path, non-secret runtime identity, runtime evidence manifest의 source HEAD/source fingerprint/binary/config/edge id/fixture revision, `/healthz`·`/v1/models`, deterministic direct/pass/repair/slow scenario aliases, readable Hot Path observation log, workspace writability와 before snapshot을 manifest에 기록한다.
- secret은 environment/config에서만 읽고 값·header·command expansion을 출력하지 않는다. missing runtime/model/auth/workspace는 provider 호출 전에 exit 69와 exact resume condition을 남긴다.
- current blocker: active test-only preset Edge, Claude auth, Pi config, deterministic direct/pass/repair/slow virtual model aliases, runtime evidence manifest, readable observation log, disposable workspace parent, output path가 공급되지 않았다. harness self-test 구현은 가능하지만 S16 PASS는 external run까지 보류된다.

### Test Coverage Gaps

- 실제 Claude/Pi direct/light/repair/failure/cancel 및 workspace cleanup을 한 형식으로 수집하는 repo script가 없다.
- harness parser/preflight 자체는 credential-free self-test가 필요하다.

### Symbol References

- none.

### Split Judgment

- stable contract: external agent invocation + raw-free JSON manifest + workspace before/after oracle.
- predecessors 15와 16의 active `complete.log`는 현재 missing이며 둘 다 실제 smoke 전에 필요하다.

### Scope Rationale

- Claude/Pi binary/config patch, secret provisioning, shared process 종료, dev deployment 변경, tracked smoke output은 제외한다.
- harness는 runtime을 소유하지 않고 supplied endpoint/profile을 검증·호출만 한다.

### Final Routing

- evaluation_mode=write, finalizer=`finalize-task-policy.sh pair`.
- build closures 모두 true(외부 소유권/재개 조건 포함), scores=2/1/1/2/2, G08, local-fit → `PLAN-local-G08.md`.
- review closures 모두 true, scores=2/1/1/2/2, G08, official-review → `CODE_REVIEW-cloud-G08.md`.
- `large_indivisible_context=false`; risks=`boundary_contract,structured_interpretation,variant_product`(3); recovery=0/false; capability gap 없음. External execution unavailability is an explicit verification blocker, not an implementation capability gap.

## Implementation Checklist

- [ ] [TEST-1] Add a secret-safe Claude/Pi Hot Path harness with deterministic preflight, scenario matrix, raw-free manifest, workspace before/after, and credential-free self-test.
- [ ] [TEST-2] Add separate self-test, external-preflight, and actual Make targets; run local/common verification, then run the actual two-protocol smoke or record the exact external blocker and resume command.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [TEST-1] Agent smoke harness

**Problem:** `scripts/e2e-openai-cli-workspace.sh:132` verifies a synthetic CLI `/v1/responses` flow only; it neither invokes Claude/Pi nor validates preset stage/cleanup evidence.

**Solution:** Add `scripts/e2e-hot-path-agents.sh` with `--preflight-only`, `--self-test`, and actual run modes. Require non-empty environment values for base URL, direct/pass/repair/slow model aliases, Pi provider/config dir, runtime evidence manifest, readable observation log, disposable workspace parent, and output manifest without echoing secrets; require `ANTHROPIC_API_KEY` only by presence and never serialize it. Compute a deterministic fingerprint over the current tracked Edge/streamgate/config sources and require the runtime evidence `source_fingerprint` to match, in addition to recording HEAD, binary/config hashes, edge id and deterministic fixture revision. Require `/v1/models` to expose four scenario aliases whose test-only provider fixture guarantees direct, light-pass, light-defect→repair, and delayed/cancel behavior; do not depend on natural-language route/review luck. Create isolated per-agent/per-scenario git workspaces under `mktemp -d`, capture before/after `git status --porcelain=v1`, agent stream output, request-correlated observation log slices, and `.iop/job` lifecycle. Run matrix `{claude,pi} × {direct,light-pass,repair,write-unavailable,timeout-cancel}`; verify visible stage markers, native terminal, expected failure class, cleanup/orphan responsibility, and no raw credential in output. Signal cancel with `timeout --signal=INT` to the child only and never kill shared processes.

Before (`Makefile:1`):

```make
.PHONY: ... test-iop-agent-logged-smoke-preflight ...
```

After:

```make
.PHONY: ... test-hot-path-agent-smoke-self-test test-hot-path-agent-smoke-preflight test-hot-path-agent-smoke ...
```

Manifest contains fixed schema/version, runner/checkout/CLI/runtime non-secret facts, scenario model/fixture identity, one row per matrix case, ordered visible event classes, terminal/outcome, workspace before/after hashes/status, reserved artifact created/removed/orphan classification, correlated observation event classes, and log paths. Redact environment names matching token/key/auth/credential and fail if sentinel secret appears.

**Modified Files and Checklist:**

- [ ] Add executable `scripts/e2e-hot-path-agents.sh` with strict argument/env validation, isolated cleanup trap, manifest validation, and fake-agent/fake-runtime `--self-test`.

**Test Strategy:** `--self-test` creates temporary fake `claude`, `pi`, and HTTP/runtime evidence, exercises success, expected failure, cancel, redaction, malformed manifest, and cleanup without network credentials.

**Verification:** `bash -n scripts/e2e-hot-path-agents.sh && ./scripts/e2e-hot-path-agents.sh --self-test` exits 0.

### [TEST-2] Make integration and actual evidence

**Problem:** There is no stable entry point or exact external resume command for S16, and one target cannot simultaneously be a credential-free local check and a strict external preflight that exits 69 when inputs are missing.

**Solution:** Add three Make targets. `test-hot-path-agent-smoke-self-test` runs syntax plus credential-free fixtures and must exit 0 locally. `test-hot-path-agent-smoke-preflight` performs only non-mutating external checks and returns 69 before provider invocation when inputs are absent. `test-hot-path-agent-smoke` calls the harness once and runs both agents/matrix cases into the supplied output file. Do not add credentialed targets to `test-e2e`.

**Modified Files and Checklist:**

- [ ] Modify `Makefile` with `test-hot-path-agent-smoke-self-test`, `test-hot-path-agent-smoke-preflight`, and `test-hot-path-agent-smoke`, passing required environment without printing values.
- [ ] Fill `agent-task/m-iop-hot-path-one-shot-execution/17+15,16_hot_smoke/CODE_REVIEW-cloud-G08.md` with self-test output, external preflight, actual manifest summary, and saved raw output paths; if blocked, record exit 69 output and exact resume conditions.

**Test Strategy:** Make preflight/self-test is mandatory locally. S16 completion additionally requires actual run with both installed binaries, an active preset runtime, and disposable workspace.

**Verification:** run the local and external commands below. Actual manifest must contain 10 passing/expected-failure rows and no secret sentinel.

## Dependencies and Execution Order

1. `15+13,14_error_cancel` must produce its active `complete.log`.
2. `16+15_route_observability` must produce its active `complete.log`.
3. Implement/test harness, then run external preflight and actual smoke.

## Modified Files Summary

| File | Item |
|---|---|
| `scripts/e2e-hot-path-agents.sh` | TEST-1 |
| `Makefile` | TEST-2 |
| `agent-task/m-iop-hot-path-one-shot-execution/17+15,16_hot_smoke/CODE_REVIEW-cloud-G08.md` | TEST-2 |

## Final Verification

Local deterministic verification:

```bash
bash -n scripts/e2e-hot-path-agents.sh
./scripts/e2e-hot-path-agents.sh --self-test
make test-hot-path-agent-smoke-self-test
go test -race -count=1 ./packages/go/streamgate ./packages/go/config ./apps/edge/internal/openai ./apps/edge/internal/service
git diff --check
```

External preflight and actual run after the required environment is supplied out-of-band:

```bash
test -n "${IOP_HOT_SMOKE_BASE_URL:-}" && test -n "${IOP_HOT_SMOKE_DIRECT_MODEL:-}" && test -n "${IOP_HOT_SMOKE_PASS_MODEL:-}" && test -n "${IOP_HOT_SMOKE_REPAIR_MODEL:-}" && test -n "${IOP_HOT_SMOKE_SLOW_MODEL:-}" && test -n "${IOP_HOT_SMOKE_PI_PROVIDER:-}" && test -n "${PI_CODING_AGENT_DIR:-}" && test -n "${ANTHROPIC_API_KEY:-}" && test -n "${IOP_HOT_SMOKE_RUNTIME_EVIDENCE:-}" && test -n "${IOP_HOT_SMOKE_OBSERVATION_FILE:-}" && test -n "${IOP_HOT_SMOKE_WORKSPACE_PARENT:-}" && test -n "${IOP_HOT_SMOKE_OUTPUT:-}"
IOP_HOT_SMOKE_SOURCE_FINGERPRINT="$(git ls-files --cached --others --exclude-standard -- apps/edge packages/go/streamgate packages/go/config go.mod go.sum | LC_ALL=C sort | while IFS= read -r path; do printf '%s\0%s\n' "$path" "$(git hash-object --no-filters "$path")"; done | git hash-object --stdin)"
export IOP_HOT_SMOKE_SOURCE_FINGERPRINT
jq -e --arg fingerprint "$IOP_HOT_SMOKE_SOURCE_FINGERPRINT" '.source_fingerprint == $fingerprint and (.binary_sha256 | type == "string" and length > 0) and (.config_sha256 | type == "string" and length > 0) and (.fixture_revision | type == "string" and length > 0)' "${IOP_HOT_SMOKE_RUNTIME_EVIDENCE}"
make test-hot-path-agent-smoke-preflight
make test-hot-path-agent-smoke
jq -e '.schema_version == 1 and (.cases | length == 10) and all(.cases[]; .verdict == "pass") and (.redaction.secret_matches == 0)' "${IOP_HOT_SMOKE_OUTPUT}"
```

Expected: local self-test commands exit 0; external preflight proves matching source fingerprint plus runtime binary/config/fixture identity, four deterministic scenario aliases, CLIs, observation source and workspace without secret output; actual manifest has 10 pass rows, visible stream events, correlated lifecycle evidence, expected native terminals, correct artifact before/after, and zero secret matches. Fingerprint mismatch requires rebuilding/redeploying Edge/Node from the current worktree with `make build-edge build-node`, regenerating the runtime evidence manifest and rerunning preflight. Exit 69 is BLOCKED evidence, not PASS. Cached Go output is not acceptable.

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