<!-- task=glm_coding_plan plan=1 tag=REVIEW_API -->

# Plan - Repair GLM Coding Plan Verification and Evidence

## For the Implementing Agent

Filling implementation-owned sections in `CODE_REVIEW-*-G??.md` is mandatory. Run every verification command, paste raw stdout/stderr under the matching headings, fill actual implementation notes, keep the active PLAN and CODE_REVIEW files in place, and report ready for review. Finalization is code-review-skill only. If blocked, record only 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 first review found the production `glm` / `glm_coding` split correct, but the verification package was incomplete and internally inconsistent. The local guide prescribed direct use of Coding Plan quota outside an officially supported tool, no deterministic Edge-to-Node full-cycle exercised `profile: glm_coding`, and one pasted `go test` block could not be raw output from the stated invocation. This follow-up preserves the production implementation while replacing the unsafe procedure and rebuilding trustworthy evidence.

## Archive Evidence Snapshot

- Prior plan: `agent-task/glm_coding_plan/plan_local_G06_0.log`.
- Prior review: `agent-task/glm_coding_plan/code_review_cloud_G06_0.log`.
- Verdict: FAIL. Findings: 3 Required, 0 Suggested, 0 Nit.
- Required findings: replace the direct Coding Plan `curl` workflow with an exact supported-tool procedure or an explicit written-authorization gate; add a deterministic `glm_coding` Edge -> Node -> loopback-provider full-cycle; replace contradictory/composed command evidence with raw output from exact commands.
- Affected files from the prior loop: `packages/go/config/protocol_profile.go`, `packages/go/config/protocol_profile_test.go`, `apps/control-plane/internal/credentialstore/route.go`, `apps/control-plane/internal/credentialstore/route_test.go`, `apps/node/internal/adapters/openai_compat/protocol_profile_test.go`, `configs/edge.yaml`, `agent-spec/runtime/provider-pool-config-refresh.md`, and local `agent-test/local/edge-smoke.md`.
- Reviewer verification: fresh focused Go tests passed, `make build-edge` passed, and `make test-e2e` passed after using a workspace-backed executable `TMPDIR`; that target remains auxiliary and did not exercise `glm_coding`. The prior live direct-provider call was not repeated because current Z.AI terms restrict Coding Plan quota to supported tools unless separately authorized.
- Roadmap carryover: none; this is a non-milestone task.

## Analysis

### Files Read

- `agent-task/glm_coding_plan/PLAN-local-G06.md`
- `agent-task/glm_coding_plan/CODE_REVIEW-cloud-G06.md`
- `agent-test/local/edge-smoke.md`
- `Makefile`
- `scripts/dev/edge.sh`
- `scripts/dev/node.sh`
- `scripts/e2e-openai-vllm.sh`
- `scripts/e2e-openai-lemonade.sh`
- `packages/go/config/protocol_profile.go`
- `packages/go/config/protocol_profile_test.go`
- `packages/go/config/provider_types.go`
- `packages/go/config/adapter_types.go`
- `packages/go/config/normalize.go`
- `apps/control-plane/internal/credentialstore/route.go`
- `apps/control-plane/internal/credentialstore/route_test.go`
- `apps/node/internal/adapters/openai_compat/protocol_profile_test.go`
- `configs/edge.yaml`
- `agent-spec/runtime/provider-pool-config-refresh.md`
- `agent-contract/outer/openai-compatible-api.md`
- `agent-contract/inner/edge-config-runtime-refresh.md`

### SDD Criteria

Not applicable. This task is not Milestone-linked.

### Verification Context

The code-review handoff supplied the prior active pair, the three Required findings, the affected production files, fresh reviewer commands, and `review_rework_count=1` / `evidence_integrity_failure=true`. Repository-native fallback evidence came from the Make targets, the existing Lemonade/vLLM loopback scripts, `scripts/dev/edge.sh`, `scripts/dev/node.sh`, the protocol-profile tests, local testing rules, and the project `e2e-smoke` skill.

The production profile and route tests already pass fresh. Existing OpenAI-compatible E2E scripts demonstrate safe temporary configs and process cleanup, but none selects the built-in `glm_coding` profile or asserts `/api/coding/paas/v4/chat/completions`; therefore a dedicated deterministic script is required. `make test-e2e` is auxiliary by `Makefile:97-101` and project testing policy, so it is retained only as regression evidence.

Current official Z.AI sources distinguish `https://api.z.ai/api/coding/paas/v4` from the General API and document Pi as a supported Coding Plan tool. The Subscription Terms and Usage Policy restrict subscription quota to officially supported tools unless separate written authorization exists. The local Pi installation independently declares provider `zai`, base URL `https://api.z.ai/api/coding/paas/v4`, model `glm-5.1`, and the `ZAI_API_KEY` environment variable.

#### External Verification Preflight

- Runner/workdir: current Linux aarch64 host at `/config/workspace/iop-s2`.
- Source state: branch `feature/glm-coding-plan`, HEAD `9b2fc2ae473993bc2d9f308658438ff45018f5b6`, merge-base with `origin/dev` verified as `32c0754f91b05ee95ab25b1062016d44fba18bf2`; the checkout is dirty only for the active task and dispatcher-owned work log.
- Commands: Pi `/config/.npm-global/bin/pi` version `0.81.1`; SOPS `/config/.local/bin/sops` version `3.13.1`; jq `/bin/jq` version `1.7`; curl `/bin/curl` version `8.5.0`; Go `1.26.2 linux/arm64`.
- Credential/config: `/config/.config/iop/secrets/dev-openai-toki.sops.yaml`, age key `/config/.config/sops/age/keys.txt`, scalar `tokens.glm-coding-plan`; both files exist and their mode/encryption/non-empty preflight passed without revealing the token.
- Runtime identity: the live check uses only Pi provider `zai`, model `glm-5.1`, and Pi's built-in Coding Plan endpoint. It must not point Pi at Edge or any proxy.
- Network/ports: the live Pi check requires outbound HTTPS to `api.z.ai`; the deterministic repository full-cycle uses randomized loopback ports and no external host.
- Setup: no sync or rebuild is required before implementation. Recheck that current official supported-tool documentation still lists Pi immediately before the live command; if it no longer does, do not call the subscription endpoint and record the exact policy blocker and resume condition.

### Test Coverage Gaps

- Supported-tool subscription smoke: not covered. The existing local guide uses direct `curl`; replace it with an exact Pi command and secret-safe criteria.
- `glm_coding` full runtime route: not covered. Unit tests prove profile resolution and Node URL assembly, but no Edge -> Node -> provider execution asserts the profile path, model rewrite, auth header, streaming, and tool forwarding together.
- Evidence fidelity: not covered by code. The new review artifact must contain raw output from the exact commands, with every environment override recorded.
- Production profile behavior: already covered by fresh package tests; no new production test or source change is needed unless the new full-cycle exposes a real defect.

### Symbol References

None. No symbol is renamed or removed.

### Split Judgment

Keep one plan. The supported-tool operator procedure and the deterministic loopback full-cycle are two evidence sources for one acceptance boundary: prove the Coding Plan configuration safely without treating a fake provider as subscription authorization or treating a supported-tool call as proof of Edge/Node routing. Splitting them would permit an independently passing but incomplete verification package.

### Scope Rationale

Do not change the implemented protocol profiles, credential compatibility matrix, public API contract, config schema, example production mapping, spec, roadmap, SOPS files, or token values. The prior review found production behavior correct; this follow-up is limited to the local operator guide, a dedicated repository smoke, its Make target, and the active review evidence. Do not add live Coding Plan calls to `make test-e2e` because auxiliary CI must remain independent of credentials, network, and subscription quota.

### Final Routing

- `evaluation_mode`: `isolated-reassessment`
- `finalizer`: `finalize-task-policy.sh` in `pair` mode
- Build closures: scope/context/verification/evidence/ownership/decision all closed; the exact policy-safe live command and deterministic loopback oracle make the packet implementable without user judgment.
- Build grade scores: scope coupling 2, state/concurrency 1, blast/irreversibility 1, evidence/diagnosis 2, verification complexity 2; grade `G08`.
- Build base route: `local-fit`; final route: `recovery-boundary`, lane `cloud`, filename `PLAN-cloud-G08.md`.
- Review closures: scope/context/verification/evidence/ownership/decision all closed.
- Review grade scores: scope coupling 2, state/concurrency 1, blast/irreversibility 0, evidence/diagnosis 2, verification complexity 2; grade `G07`.
- Review route: `official-review`, lane `cloud`, adapter `codex`, model `gpt-5.6-sol`, reasoning effort `xhigh`, filename `CODE_REVIEW-cloud-G07.md`.
- `large_indivisible_context=false`.
- Positive loop-risk signatures: `boundary_contract`, `structured_interpretation`; count 2. The script spans Edge, Node, provider, generated YAML, JSON, and SSE framing.
- Recovery signals: `review_rework_count=1`, `evidence_integrity_failure=true`; recovery boundary matched, risk boundary did not match.
- Capability gap: none.

## Implementation Checklist

- [ ] [REVIEW_API-1] Replace the direct Coding Plan API workflow with one exact, secret-safe Pi command and current supported-tool policy guardrails.
- [ ] [REVIEW_API-2] Add and run a deterministic `glm_coding` Edge -> Node -> loopback-provider full-cycle plus a dedicated Make target.
- [ ] [REVIEW_API-3] Run fresh focused, build, auxiliary E2E, deterministic full-cycle, and supported-tool verification and paste only raw command output.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REVIEW_API-1] Replace the direct subscription API workflow

#### Problem

`agent-test/local/edge-smoke.md:78-104` instructs the operator to use a Coding Plan token with `curl` against the subscription API. Current Z.AI terms permit subscription quota through officially supported tools unless separate written authorization exists, and the prose procedure is not the exact executable redacted command required by the prior API-4 item.

#### Solution

Replace the direct `/models`, chat, SSE, and tool-call `curl` steps with an exact non-interactive Pi invocation. Pi must receive the decrypted token only through the process-local `ZAI_API_KEY` environment variable; disable tools, extensions, skills, prompt templates, context files, sessions, and project-local configuration; capture the model output without echoing it; assert a fixed marker; unset the shell token; and print only a redacted PASS marker. Keep an explicit current-terms guard and state that direct API/proxy use requires separate written authorization.

Before (`agent-test/local/edge-smoke.md:94`):

```text
1. Extract the SOPS scalar.
2. Write a temporary curl config containing the Bearer token.
3. Call /models, non-streaming chat, SSE chat, and tool calling directly.
```

After:

```bash
set -euo pipefail
SOPS_FILE=/config/.config/iop/secrets/dev-openai-toki.sops.yaml
AGE_KEY_FILE=/config/.config/sops/age/keys.txt
test "$(stat -c '%a' "$SOPS_FILE")" = 600
test "$(stat -c '%a' "$AGE_KEY_FILE")" = 600
test "$(SOPS_AGE_KEY_FILE="$AGE_KEY_FILE" sops filestatus "$SOPS_FILE" | jq -r '.encrypted')" = true
token="$(SOPS_AGE_KEY_FILE="$AGE_KEY_FILE" sops decrypt --extract '["tokens"]["glm-coding-plan"]' "$SOPS_FILE")"
test -n "$token"
pi_output="$(ZAI_API_KEY="$token" pi --offline --provider zai --model glm-5.1 --no-session --no-tools --no-extensions --no-skills --no-prompt-templates --no-context-files --no-approve --print 'Reply with exactly: IOP_GLM_CODING_PI_OK')"
unset token
grep -Fq 'IOP_GLM_CODING_PI_OK' <<<"$pi_output"
unset pi_output
printf '%s\n' 'glm coding pi smoke: PASS'
```

#### Modified Files and Checklist

- [ ] `agent-test/local/edge-smoke.md` — replace direct subscription API calls with the exact Pi command, official supported-tool terms guard, secret handling, success criteria, and 2026-08-02 verification date.

#### Test Strategy

Do not add a source unit test for an ignored local operator guide. Use deterministic `rg --sort path` checks to reject direct `api.z.ai` curl instructions and require the exact Pi provider/model/environment pattern. Execute the documented command once after the secret-safe preflight; accept only the fixed PASS marker and do not paste model output.

#### Verification

```bash
if rg -n --sort path 'curl.*api\.z\.ai|api\.z\.ai.*curl' agent-test/local/edge-smoke.md; then exit 1; fi
rg -n --sort path --fixed-strings 'ZAI_API_KEY="$token" pi --offline --provider zai --model glm-5.1' agent-test/local/edge-smoke.md
rg -n --sort path --fixed-strings 'glm coding pi smoke: PASS' agent-test/local/edge-smoke.md
```

Expected: the first search has no match; both exact supported-tool procedure markers are present.

### [REVIEW_API-2] Add a deterministic GLM Coding profile full-cycle

#### Problem

`agent-task/glm_coding_plan/code_review_cloud_G06_0.log:345-366` has no successful full-cycle for the new profile. The existing scripts read during analysis exercise legacy OpenAI-compatible routes or other profiles, not `profile: glm_coding` with the Coding base path.

#### Solution

Create `scripts/e2e-openai-glm-coding.sh` following the existing temporary-config lifecycle. Embed a minimal Go fake provider with full imports:

```go
import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "os"
    "sync/atomic"
)
```

The fake must accept only `/api/coding/paas/v4/models` and `/api/coding/paas/v4/chat/completions`, require `Authorization: Bearer fake-glm-coding-token`, require upstream model `glm-5.1`, return deterministic non-streaming/SSE/tool-call responses, and expose an `/assert` endpoint that fails unless the expected request counts and variants were observed. Any General API `/api/paas/v4` request must fail.

Generate an Edge config with client model `glm-coding-smoke`, provider `glm-coding-smoke-provider`, `type: openai_api`, `profile: glm_coding`, a root-only loopback `endpoint`, the fake Authorization header, and served model `glm-5.1`. A root-only endpoint is intentional: profile normalization must retain `/api/coding/paas/v4`. Start Edge and Node via `scripts/dev/edge.sh` and `scripts/dev/node.sh`, wait for registration, then send non-streaming, streaming, and tool-call requests through Edge. Assert response markers, `[DONE]`, `emit_marker`, the fake provider counts/path/header/model, clean process shutdown, absence of runtime failure markers, and one stable success line.

Use a repository-local ignored temp root such as `.local/` and `GOTMPDIR` so generated executables do not depend on a noexec `/tmp`. Do not add a real-provider mode or read SOPS credentials in this script.

Add `test-openai-glm-coding` to `.PHONY` and invoke the script from that target. Do not add it to `test-e2e`; it is a dedicated required diagnostic and its status must be reported separately from auxiliary E2E.

#### Modified Files and Checklist

- [ ] `scripts/e2e-openai-glm-coding.sh` — add the deterministic fake provider, temporary Edge/Node configs, full-cycle requests/assertions, cleanup, and stable PASS output.
- [ ] `Makefile` — add the `.PHONY` declaration and `test-openai-glm-coding` target without changing existing target semantics.

#### Test Strategy

The new script is the regression test. It covers profile selection, root endpoint overlay, exact Coding chat path, model alias rewrite, Bearer header propagation, non-streaming response, SSE termination, tool-call forwarding, Edge/Node registration, process cleanup, and General API non-use. Existing production unit tests remain the lower-level boundary tests.

#### Verification

```bash
bash -n scripts/e2e-openai-glm-coding.sh
make test-openai-glm-coding
```

Expected: shell syntax passes and the full-cycle exits 0 with one `[openai-glm-coding] glm_coding Edge-Node-provider full-cycle PASSED.` line. The fake `/assert` confirms every observed upstream chat URI starts with `/api/coding/paas/v4/`, no General API path was used, the header/model match, and non-streaming, streaming, and tool-call variants ran.

### [REVIEW_API-3] Rebuild trustworthy verification evidence

#### Problem

`agent-task/glm_coding_plan/code_review_cloud_G06_0.log:107-110` reports the same Go package as both `[no test files]` and `ok` for one exact invocation, while `:362-366` records an auxiliary E2E failure caused by a noexec `/tmp`. The production tests pass under fresh reviewer execution, but the implementation evidence must be regenerated from exact commands.

#### Solution

Run each command below exactly once after implementation. Paste unedited stdout/stderr under its matching `Actual Output` heading. Keep the workspace-backed `TMPDIR` assignment visible in the command and record no synthesized status lines. For the live Pi check, paste only preflight command output and the fixed redacted PASS marker; never paste the captured model response or credential.

#### Modified Files and Checklist

- [ ] `agent-task/glm_coding_plan/CODE_REVIEW-cloud-G07.md` — fill implementation decisions, deviations, and raw outputs for every exact verification command.

#### Test Strategy

Use `-count=1` for all Go packages so cached output is not accepted. The dedicated loopback test is mandatory full-cycle evidence; `make test-e2e` remains separately labeled auxiliary regression evidence. The live Pi command proves only supported-tool subscription access and must not be cited as Edge/Node routing evidence.

#### Verification

Run the complete `Final Verification` sequence and require every command to exit 0. Compare pasted output against the exact command boundaries; the same package must appear only once per invocation.

## Modified Files Summary

| File | Item |
|------|------|
| `agent-test/local/edge-smoke.md` | REVIEW_API-1 |
| `scripts/e2e-openai-glm-coding.sh` | REVIEW_API-2 |
| `Makefile` | REVIEW_API-2 |
| `agent-task/glm_coding_plan/CODE_REVIEW-cloud-G07.md` | REVIEW_API-1, REVIEW_API-2, REVIEW_API-3 |

## Final Verification

1. Confirm scope, formatting, and fresh production regressions:

```bash
git diff --check
test -z "$(gofmt -d packages/go/config/protocol_profile.go packages/go/config/protocol_profile_test.go apps/control-plane/internal/credentialstore/route.go apps/control-plane/internal/credentialstore/route_test.go apps/node/internal/adapters/openai_compat/protocol_profile_test.go)"
go test -count=1 ./packages/go/config ./apps/control-plane/internal/credentialstore ./apps/node/internal/adapters/openai_compat
```

Expected: no diff/format errors and each package reports one fresh `ok` result.

2. Run the dedicated deterministic full-cycle:

```bash
bash -n scripts/e2e-openai-glm-coding.sh
make test-openai-glm-coding
```

Expected: exit 0 and the stable GLM Coding full-cycle PASS line after fake-provider assertions.

3. Build Edge and rerun the repository auxiliary E2E with an executable workspace temp root:

```bash
make build-edge
mkdir -p build/e2e-tmp
TMPDIR="$PWD/build/e2e-tmp" make test-e2e
```

Expected: build and auxiliary E2E exit 0. Record this as auxiliary regression evidence only.

4. Confirm the policy-safe operator guide and run the exact documented Pi smoke once:

```bash
if rg -n --sort path 'curl.*api\.z\.ai|api\.z\.ai.*curl' agent-test/local/edge-smoke.md; then exit 1; fi
rg -n --sort path --fixed-strings 'ZAI_API_KEY="$token" pi --offline --provider zai --model glm-5.1' agent-test/local/edge-smoke.md
test "$(stat -c '%a' /config/.config/iop/secrets/dev-openai-toki.sops.yaml)" = 600
test "$(stat -c '%a' /config/.config/sops/age/keys.txt)" = 600
test "$(SOPS_AGE_KEY_FILE=/config/.config/sops/age/keys.txt sops filestatus /config/.config/iop/secrets/dev-openai-toki.sops.yaml | jq -r '.encrypted')" = true
token="$(SOPS_AGE_KEY_FILE=/config/.config/sops/age/keys.txt sops decrypt --extract '["tokens"]["glm-coding-plan"]' /config/.config/iop/secrets/dev-openai-toki.sops.yaml)"
test -n "$token"
pi_output="$(ZAI_API_KEY="$token" pi --offline --provider zai --model glm-5.1 --no-session --no-tools --no-extensions --no-skills --no-prompt-templates --no-context-files --no-approve --print 'Reply with exactly: IOP_GLM_CODING_PI_OK')"
unset token
grep -Fq 'IOP_GLM_CODING_PI_OK' <<<"$pi_output"
unset pi_output
printf '%s\n' 'glm coding pi smoke: PASS'
```

Expected: no direct-provider curl instruction is found, all preflight checks exit 0, and only `glm coding pi smoke: PASS` is emitted for the model call. If current official documentation no longer lists Pi as supported, do not run the live call; record the exact policy blocker instead.

5. Inspect the exact follow-up scope and ensure no secret entered the diff:

```bash
git diff --name-only -- . ':(exclude)agent-task/glm_coding_plan/WORK_LOG.md'
git diff -- . ':(exclude)agent-task/glm_coding_plan/WORK_LOG.md' | rg -n --sort path 'glm-coding-plan|ZAI_API_KEY|Authorization|Bearer|api/coding/paas/v4'
```

Expected: changes are limited to the prior production files plus the four follow-up claims, no SOPS/key file is modified, and every matched credential value is a variable name or fixed fake/redacted value.

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