iop/agent-task/single_request_plan_review_templates/PLAN-cloud-G08.md
toki 31fada5d08 fix(single_request): 템플릿 승인 경계를 닫고 회귀 근거를 채운다
공식 리뷰가 지적한 두 가지 승인 경계 결함을 고친다. `plan_file`/`review_file`은
edge.yaml 디렉터리 기준 상대 경로만 허용하고 절대/빈 경로는 파일 접근 전에 거부한다.
필수 heading과 Review `PASS`는 부분 문자열이 아니라 정확한 단독 줄로 검증하며,
문서화된 placeholder를 제거한 뒤 남는 `{{`/`}}`를 거부해 문법을 닫는다.

리뷰가 존재한다고 기술했지만 실제로는 없던 회귀 근거를 추가한다. admission 시
고정된 effective 템플릿 쌍이 clone과 workspace 재검증을 통과하는지, refresh가
이미 승인된 요청이 아니라 새 요청에만 적용되는지, custom Review 템플릿이 내부
artifact만 바꾸고 caller 최종 출력은 그대로인지를 각각 확정 검증한다.

현재 문서도 실제 동작에 맞춘다. Edge 실행 spec의 낡은 Plan JSON Schema 서술을
direct PlanMD 검증으로 고치고, outer Anthropic 계약과 input spec에 템플릿이
Edge 내부 stage 입력일 뿐 caller 요청/응답 계약을 바꾸지 않음을 명시한다.

Refs: agent-task/single_request_plan_review_templates/PLAN-cloud-G08.md
2026-08-09 09:25:27 +09:00

19 KiB

Single-request Template Contract Repair - REVIEW_API

For Implementing Agent: Implement only the checked-in scope below. Do not archive task files, create complete.log, or start/monitor orchestration. Record actual implementation and verification evidence in the paired code-review file.

Background

The preceding implementation introduced configurable single-request Plan and Review templates, but official review found two admission-boundary defects, material gaps in the prescribed regression suite, and stale public/current documentation. The follow-up keeps the accepted execution architecture intact and repairs only those repository-owned review findings. Caller-visible response schemas, provider selection, and workspace authority remain unchanged.

Archive Evidence Snapshot

  • Prior task: single_request_plan_review_templates, plan 0, tag API (active origin).
  • Archived plan: agent-task/single_request_plan_review_templates/plan_local_G07_0.log.
  • Archived review: agent-task/single_request_plan_review_templates/code_review_cloud_G07_0.log.
  • Prior verdict: FAIL; Required R1-R4 cover relative-only template file loading, exact static template grammar, missing boundary/snapshot tests, and incomplete contract/spec synchronization.
  • Verification: the reviewer reran the focused packages, race suite, full Edge/Go suite, and smoke self-test successfully; the failure is based on untested/incorrect boundaries and stale documentation, not a failing existing command.
  • Roadmap carryover: none; this is a non-milestone task.

Finding Resolution Map

Finding Closure Direct-fix target Changed precondition / invariant
R1 direct-fix packages/go/config/load.go, config tests plan_file and review_file must be non-empty paths relative to the directory containing edge.yaml; absolute paths are rejected before filesystem access.
R2 direct-fix packages/go/singlerequesttemplate/template.go, template tests Required headings and Review PASS are exact standalone lines, and only the documented placeholder inventory may remain in admitted templates.
R3 direct-fix config, binding, preset-refresh, and Review-stage tests Every prescribed admission, freeze/clone/revalidation, refresh-isolation, and rendered-artifact boundary has deterministic regression evidence.
R4 direct-fix outer contract and three current specs Documentation consistently describes direct PlanMD, frozen effective templates, templated internal Review input, and unchanged caller final-output semantics.

Analysis

Files Read

  • agent-ops/rules/project/rules.md
  • agent-ops/rules/common/rules-roadmap.md
  • agent-roadmap/current.md
  • agent-ops/skills/common/router.md
  • agent-ops/skills/common/code-review/SKILL.md
  • agent-ops/skills/common/plan/SKILL.md
  • agent-ops/skills/common/finalize-task-routing/SKILL.md
  • agent-ops/rules/common/rules-agent-spec.md
  • agent-ops/rules/project/domain-edge.md
  • agent-ops/rules/project/domain-platform-common.md
  • agent-ops/rules/project/domain-testing.md
  • agent-test/local/rules.md
  • agent-test/local/smoke/edge.md
  • agent-test/local/smoke/platform-common.md
  • agent-test/local/smoke/testing.md
  • agent-contract/index.md
  • agent-contract/inner/edge-config.md
  • agent-contract/outer/anthropic-compatible-api.md
  • agent-spec/index.md
  • agent-spec/runtime/provider-pool-config-refresh.md
  • agent-spec/runtime/edge-node-execution.md
  • agent-spec/input/openai-compatible-surface.md
  • packages/go/singlerequesttemplate/template.go
  • packages/go/singlerequesttemplate/template_test.go
  • packages/go/config/load.go
  • packages/go/config/model_execution_preset_config_test.go
  • apps/edge/internal/service/single_request_types.go
  • apps/edge/internal/service/single_request_types_test.go
  • apps/edge/internal/openai/single_request_preset_binding.go
  • apps/edge/internal/openai/single_request_preset_binding_test.go
  • apps/edge/internal/openai/single_request_plan_stage.go
  • apps/edge/internal/openai/single_request_plan_stage_test.go
  • apps/edge/internal/openai/single_request_review_stage.go
  • apps/edge/internal/openai/single_request_review_stage_test.go
  • agent-task/single_request_plan_review_templates/plan_local_G07_0.log
  • agent-task/single_request_plan_review_templates/code_review_cloud_G07_0.log

SDD / Contract Context

  • SDD is not applicable: the accepted architecture is unchanged and this plan repairs review findings within existing contracts.
  • agent-contract/inner/edge-config.md already establishes edge.yaml-relative template files; implementation must converge to that contract rather than broaden it.
  • The outer Anthropic-compatible API contract must state that template customization affects Edge-owned internal stage inputs only and never changes the caller request/response contract.

Verification Context

  • There is no separate handoff. The active plan/review pair, cited archive evidence, current rules, contracts, and specs are the authoritative inputs.
  • Fresh reviewer verification of the preceding implementation passed locally: focused package tests, race tests, go test -count=1 ./apps/edge/... ./packages/go/..., and make test-single-request-claude-smoke-self-test all exited 0.
  • Archived remote-profile evidence identifies toki@toki-labs.com, /Users/toki/agent-work/iop-dev, Darwin/arm64, Claude CLI 2.1.177, SOPS 3.13.1, and implementation commit b6e0080f. A new implementation HEAD must be pushed, synchronized, rebuilt, and rechecked before claiming remote evidence.
  • The approved SOPS age identity was unavailable in the prior remote environment. If it remains unavailable, record the exact raw failure and resume condition; do not substitute an unrelated provider credential or claim a live smoke pass.

Test Gaps to Close

  • Config loading lacks per-file fallback, absolute-path rejection, exact 8192-byte acceptance, symlink/non-regular/unreadable rejection, and a complete invalid-grammar matrix.
  • Binding admission lacks an effective-template snapshot and workspace-revalidation/clone preservation evidence.
  • Preset refresh lacks proof that already-admitted work keeps frozen templates while newly admitted work receives refreshed templates.
  • Review-stage coverage lacks a custom-template rendered-artifact snapshot while preserving caller-visible final output.

Symbol / Text Reference Audit

  • No production symbol rename is planned.
  • Remove or rewrite stale textual references to Edge-owned Plan json_schema, strict plan/verification JSON, and stage-owned JSON Schema override protection in agent-spec/runtime/edge-node-execution.md.

Split Decision

  • Use one plan. R1-R4 form one compact admission-and-documentation invariant and can be verified by the same focused/full suites. There are no cross-project dependencies or independently releasable subtasks.

Scope Exclusions

  • Do not change caller request/response schemas, provider routing, workspace authorization, the Review loop decision model, protobufs, Node packages, UI surfaces, or centrally managed agent-ops/rules/common/** and agent-ops/skills/common/**.
  • Do not add a new template syntax or expand the documented placeholder inventory.
  • Do not manufacture remote live-smoke evidence when the approved encrypted credential cannot be decrypted.

Final Routing

  • Closure booleans: all Required findings are repository-owned and direct-fix=true; no external-follow-up or user-decision closure is needed.
  • Build scoring: scope 2, state 1, blast radius 1, evidence 2, verification 2.
  • Review scoring: scope 2, state 1, blast radius 1, evidence 2, verification 2.
  • Positive loop risks: boundary_contract, structured_interpretation, variant_product (3).
  • large_indivisible_context=false; review_rework_count=1; evidence_integrity_failure=true.
  • Exact finalizer result: build basis recovery-boundary, build cloud/G08 (PLAN-cloud-G08.md), review basis official-review, review cloud/G08 (CODE_REVIEW-cloud-G08.md). No route-cap gap applies.

Implementation Checklist

  • [REVIEW_API-1] Enforce relative-only template loading and exact Plan/Review grammar with boundary regressions.
  • [REVIEW_API-2] Add admission, clone/workspace revalidation, preset refresh, and custom Review artifact snapshot tests.
  • [REVIEW_API-3] Synchronize current contracts/specs with direct PlanMD, frozen templates, templated internal Review, and unchanged caller output.
  • [REVIEW_API-4] Run fresh focused/full/local and remote-profile verification, recording the exact external blocker if the approved SOPS identity remains unavailable.
  • Fill implementation-owned sections in CODE_REVIEW-cloud-G08.md with actual implementation notes and verification output.

Implementation Items

REVIEW_API-1 — Close Template Admission Boundaries

Problem

loadTemplateFile accepts absolute paths even though the config contract is relative-only. Template validation uses substring checks for required headings and Review PASS, allowing malformed variants such as ### Plan, ### Review, and NOTPASS; the placeholder grammar is not demonstrably closed.

Solution

  • Trim the configured path, reject empty and absolute values before opening anything, then join only the relative path to the directory containing edge.yaml.
  • Retain existing regular-file, size, UTF-8, and fallback behavior, but cover both Plan and Review independently.
  • Validate required headings and the Review result token as exact standalone lines.
  • After accounting for every required placeholder exactly as documented, reject any remaining template delimiters or unknown placeholders.

Before:

target := strings.TrimSpace(relOrAbsPath)
if !filepath.IsAbs(target) {
	target = filepath.Join(baseDir, target)
}

After:

target := strings.TrimSpace(relativePath)
if filepath.IsAbs(target) {
	return "", fmt.Errorf("template path must be relative to edge.yaml")
}
target = filepath.Join(baseDir, target)

Replace substring grammar checks such as:

if strings.Index(tmpl, "# Plan") < 0 { /* ... */ }

with a line-aware exact matcher and closed-token validation shared by both variants.

Modified Files Checklist

  • packages/go/singlerequesttemplate/template.go
  • packages/go/singlerequesttemplate/template_test.go
  • packages/go/config/load.go
  • packages/go/config/model_execution_preset_config_test.go

Test Strategy

  • Extend TestValidatePlanTemplate and TestValidateReviewTemplate for exact headings/result lines, missing/duplicate/unknown placeholders, and delimiter residue.
  • Extend TestLoadEdgeSingleRequestTemplates for Plan/Review absolute-path rejection, relative success, per-file fallback, exact size boundary, and filesystem-kind failures.

Verification

  • Run the focused template/config tests and confirm every malformed variant is rejected without exposing file content in errors.

REVIEW_API-2 — Prove Freeze, Refresh, and Render Semantics

Problem

The preceding review claimed coverage that is absent from the actual test files. The admitted effective template snapshot, clone/workspace revalidation, refresh isolation, and custom Review artifact are therefore not protected against regression.

Solution

  • Add deterministic service-level assertions that admitted bindings carry the exact effective Plan/Review template pair through clone and workspace revalidation paths.
  • Add preset refresh assertions that existing work retains its frozen templates and newly admitted work observes the refreshed pair.
  • Add a Review-stage custom-template snapshot proving internal artifact rendering uses the frozen template while decision.output remains the caller-visible final response.
  • Do not change production behavior unless a new regression exposes a concrete defect.

Modified Files Checklist

  • apps/edge/internal/service/single_request_types_test.go
  • apps/edge/internal/openai/single_request_preset_binding_test.go
  • apps/edge/internal/openai/single_request_review_stage_test.go

Test Strategy

  • Add/extend TestSingleRequestBindingTemplateSnapshot.
  • Add/extend TestSingleRequestPresetBindingTemplateRefreshIsolation.
  • Add/extend TestSingleRequestReviewStageCustomTemplateSnapshot.
  • Assert both the internal rendered artifact and unchanged caller output; do not rely on substring-only assertions where an exact snapshot is stable.

Verification

  • Run the named focused packages, then the race suite covering OpenAI stages, service admission, refresh, config, and template validation.

REVIEW_API-3 — Synchronize Current Contracts and Specs

Problem

The current runtime spec still describes a Plan JSON Schema path that the implementation removed. The outer API contract and input spec do not yet document the accepted frozen-template/direct-PlanMD/internal-Review model, leaving the current documentation contradictory.

Solution

  • Update the outer Anthropic-compatible contract to describe unchanged caller I/O and Edge-owned internal template customization.
  • Update the provider-pool refresh spec with admission-time effective-template freezing and refresh isolation.
  • Rewrite stale Plan JSON Schema passages in the Edge execution spec to direct PlanMD validation and templated Review artifact semantics.
  • Update the OpenAI-compatible input surface to distinguish internal stage templates from caller-visible input/output.
  • Preserve existing terminology and add the required current-spec change records where that spec format requires them.

Modified Files Checklist

  • agent-contract/outer/anthropic-compatible-api.md
  • agent-spec/runtime/provider-pool-config-refresh.md
  • agent-spec/runtime/edge-node-execution.md
  • agent-spec/input/openai-compatible-surface.md

Test Strategy

  • Search the current spec for the known stale Plan JSON Schema phrases and require no matches.
  • Cross-check every new statement against the implementation and the inner Edge config contract.

Verification

  • Run the documented rg guard and manually confirm the four surfaces agree on admission, execution, refresh, and caller-output boundaries.

REVIEW_API-4 — Produce Trustworthy Verification Evidence

Problem

The earlier implementation evidence checked off work and named tests/docs that were absent. Local behavior passed, but the recorded completeness and remote live-smoke claims cannot be trusted without fresh evidence.

Solution

  • Run every command in Final Verification against the completed working tree and paste actual output into the paired review file.
  • Confirm the pushed commit and the remote checkout are identical before a remote rebuild or live smoke.
  • If approved SOPS decryption remains unavailable, record the exact failing command, raw error, exit code, and resume condition. Treat that as an allowed external-profile blocker only; never convert it into a local pass.

Modified Files Checklist

  • agent-task/single_request_plan_review_templates/CODE_REVIEW-cloud-G08.md

Test Strategy

  • Verify formatting, focused tests, race tests, the full Edge/Go suite, the deterministic smoke self-test, the documentation guard, and the approved remote profile.

Verification

  • Evidence must identify the tested commit and clearly separate local success from any externally blocked live qualification.

Modified Files Summary

File Item
packages/go/singlerequesttemplate/template.go REVIEW_API-1
packages/go/singlerequesttemplate/template_test.go REVIEW_API-1
packages/go/config/load.go REVIEW_API-1
packages/go/config/model_execution_preset_config_test.go REVIEW_API-1
apps/edge/internal/service/single_request_types_test.go REVIEW_API-2
apps/edge/internal/openai/single_request_preset_binding_test.go REVIEW_API-2
apps/edge/internal/openai/single_request_review_stage_test.go REVIEW_API-2
agent-contract/outer/anthropic-compatible-api.md REVIEW_API-3
agent-spec/runtime/provider-pool-config-refresh.md REVIEW_API-3
agent-spec/runtime/edge-node-execution.md REVIEW_API-3
agent-spec/input/openai-compatible-surface.md REVIEW_API-3
agent-task/single_request_plan_review_templates/CODE_REVIEW-cloud-G08.md REVIEW_API-4

Final Verification

Run locally from the repository root:

test -z "$(gofmt -l packages/go/singlerequesttemplate/template.go packages/go/singlerequesttemplate/template_test.go packages/go/config/load.go packages/go/config/model_execution_preset_config_test.go apps/edge/internal/service/single_request_types_test.go apps/edge/internal/openai/single_request_preset_binding_test.go apps/edge/internal/openai/single_request_review_stage_test.go)"
go test -count=1 ./packages/go/singlerequesttemplate ./packages/go/config
go test -count=1 ./apps/edge/internal/service -run 'TestSingleRequestBinding'
go test -count=1 ./apps/edge/internal/openai -run 'TestSingleRequest(PresetBinding|ReviewStage)'
go test -race -count=1 ./apps/edge/internal/openai ./apps/edge/internal/service ./apps/edge/internal/configrefresh ./packages/go/config ./packages/go/singlerequesttemplate
go test -count=1 ./apps/edge/... ./packages/go/...
make test-single-request-claude-smoke-self-test
if rg --sort path -n 'Edge-owned OpenAI `json_schema` response format|strict small plan/verification JSON|stage-owned JSON Schema override protection' agent-spec/runtime/edge-node-execution.md; then exit 1; fi

Then verify the approved remote profile against the exact pushed implementation commit:

test "$(git branch --show-current)" = "feature/single_request_plan_review_templates"
test -z "$(git status --short)"
git push origin feature/single_request_plan_review_templates

ssh toki@toki-labs.com 'cd /Users/toki/agent-work/iop-dev && git fetch origin feature/single_request_plan_review_templates && git switch feature/single_request_plan_review_templates && git reset --hard origin/feature/single_request_plan_review_templates && git clean -fd && test "$(git rev-parse HEAD)" = "$(git rev-parse origin/feature/single_request_plan_review_templates)" && test "$(go env GOOS)/$(go env GOARCH)" = "darwin/arm64" && claude --version && sops --version && test -f dev-openai-toki.edge.yaml && test -f dev-openai-toki.sops.yaml'
ssh toki@toki-labs.com 'cd /Users/toki/agent-work/iop-dev && PATH=/opt/homebrew/bin:$PATH make build-edge build-node && PATH=/opt/homebrew/bin:$PATH make test-single-request-claude-smoke-preflight test-single-request-claude-smoke test-single-request-claude-smoke-validate EDGE_CONFIG=dev-openai-toki.edge.yaml SOPS_CONFIG=dev-openai-toki.sops.yaml'

If the remote SOPS age identity is unavailable, paste the exact raw failure and exit code into CODE_REVIEW-cloud-G08.md, state the identity-mount/export resume condition, and leave live API qualification explicitly blocked. Do not reuse old output or substitute another credential.

Do not archive this plan, write complete.log, or move the task directory; those actions belong to the review agent after an official verdict.