공식 리뷰가 지적한 두 가지 승인 경계 결함을 고친다. `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
25 KiB
Code Review Reference - REVIEW_API
Date: 2026-08-09 KST
Task: Repair the single-request template admission contract, missing regression evidence, and current documentation after official review failure.
Review Agent Instructions
- Review only the paired
PLAN-cloud-G08.mdscope and repository changes implementing it. - Re-run verification independently; implementation-supplied output is evidence input, not the verdict.
- Only the review agent may append
Code Review Result, archive the active pair, writecomplete.log, or move the task directory. - On
WARNorFAIL, follow the review routing policy and do not writecomplete.log.
Archive Evidence Snapshot
- Prior task:
single_request_plan_review_templates, plan0, tagAPI(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.
Implementation Item Completion
- REVIEW_API-1 — Close Template Admission Boundaries
- REVIEW_API-2 — Prove Freeze, Refresh, and Render Semantics
- REVIEW_API-3 — Synchronize Current Contracts and Specs
- REVIEW_API-4 — Produce Trustworthy Verification Evidence
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.mdwith actual implementation notes and verification output.
Review-Only Checklist
- Review verdict and routing signals are appended.
- Finding severities, verdict, and routing are mutually consistent.
- On PASS only:
complete.logis written with exact header, verdict, review path, and summary. - On PASS only: task directory is moved under
agent-task/archive/. - Active review is archived as
agent-task/single_request_plan_review_templates/code_review_cloud_G08_1.log. - Active plan is archived as
agent-task/single_request_plan_review_templates/plan_cloud_G08_1.logwhen closure policy requires it. .gitignoreadmits generated task Markdown/log artifacts.- On WARN/FAIL: the required next active state is materialized and
complete.logis absent.
Deviations from Plan
- Branch name. The plan's Final Verification asserts
feature/single_request_plan_review_templates(underscores). The actual branch — local and on the approved remote checkout — isfeature/single-request-plan-review-templates(hyphens). Every branch-scoped command was run against the real hyphenated branch. No branch was created or renamed. utf8validation was added, not retained. REVIEW_API-1 says to "retain existing regular-file, size, UTF-8, and fallback behavior".loadTemplateFilehad no UTF-8 check; there was nothing to retain. Autf8.Validrejection was added so the loader boundary the plan describes is real, and it is covered byTestLoadEdgeSingleRequestTemplates/non-UTF-8_template_file_fails_closed.- Grammar errors no longer echo template text. The old validator returned
unknown placeholder %qwith the offending token from the template body. The plan's REVIEW_API-1 Verification requires rejection "without exposing file content in errors", so unknown-placeholder and delimiter-residue errors now name the violation category only. Documented required lines and documented placeholder names (compile-time constants, not file content) are still echoed. ..traversal was not added to the loader. The plan scopes R1 to rejecting empty and absolute values. A relative path containing..still resolves throughfilepath.Join. This is unchanged behavior, in scope for a follow-up if the operator-config threat model warrants path containment; it was not silently broadened here.- Remote
makevariables in the plan do not exist. The plan's remote command passesEDGE_CONFIG=/SOPS_CONFIG=. The smoke targets inMakefile:206-236readIOP_SINGLE_REQUEST_SMOKE_*variables only, so those two assignments are inert and the preflight runs with empty arguments regardless of the config files. Recorded here because it changes how the remote blocker below must be resolved. - Remote evidence required two commits. The plan asks for a clean tree and a pushed commit before the remote rebuild, and for the remote output to be pasted into this file. Those cannot both hold in one commit. The implementation commit was pushed first, the remote profile was exercised against exactly that commit, and this file's remote section was then updated and committed. Both hashes are recorded below.
WORK_LOG.mdis dispatcher-owned. It is admitted by.gitignore(agent-task/**/*.md) and was committed with the task directory, but the dispatcher appends itsFINISHrow after this agent exits, sogit status --shortcannot stay empty past that point. The clean-tree assertion below is true as of the recorded implementation commit.
Key Design Decisions
Relative-only template loading (packages/go/config/load.go:721-762). The parameter was renamed from relOrAbsPath to relativePath, and empty and absolute values are rejected before os.Lstat/os.Open, so an absolute path never reaches the filesystem at all. filepath.Join(baseDir, target) is now the only resolution path, which is what agent-contract/inner/edge-config-runtime-refresh.md already specified. Existing Lstat-based non-regular-file rejection (which also rejects symlinks), the io.LimitReader(f, 8193) size boundary, and independent per-file default fallback in resolveSingleRequestTemplates are unchanged.
Exact standalone-line grammar (packages/go/singlerequesttemplate/template.go:63-104). exactLineOffsets compares maximal \n-delimited segments byte for byte and reports both the first offset and the occurrence count; requireExactLines demands exactly one occurrence of each required line. This is what closes the reported defect: ### Plan, # Plan Mismatch, Result: PASS, and NOTPASS all previously satisfied the substring checks and are now rejected. Offsets feed the same structural ordering assertions as before, so no ordering semantics changed.
Closed placeholder inventory (packages/go/singlerequesttemplate/template.go:106-128). requirePlaceholderInventory removes exactly one occurrence of each documented placeholder and then rejects any surviving {{ or }}. Removing first is what makes the check closed rather than a denylist: it catches unknown placeholders ({{severity}}), unbalanced delimiters ({{goal}}}}), and nesting ({{{{goal}}}}), which the old \{\{[^}]*\}\} scan could not.
Templates are strings, so freezing is structural. SingleRequestTemplateBinding holds two immutable Go strings, so the "frozen" property follows from the type rather than from a defensive copy. That is exactly why the plan's R3 gap mattered: the invariant was true but unproven and unprotected. The new tests assert it explicitly at admission, through Clone, through cloneValidatedSingleRequestBinding, and across a simulated refresh, so a future change to a mutable representation fails loudly.
Validation is re-run at revalidation, not just admission. cloneValidatedSingleRequestBinding routes back through NewSingleRequestBindingWithTemplates, so a template tampered with after admission fails workspace revalidation instead of being cloned forward. TestSingleRequestBindingTemplateSnapshot/an_invalid_template_cannot_survive_workspace_revalidation pins that.
Review template selects the artifact, never the caller response. renderSingleRequestReview builds the internal artifact from binding.Templates.Review while singleRequestReviewResult.Output stays the trimmed decision.output. TestSingleRequestReviewStageCustomTemplateSnapshot renders the same decision through both the custom and the built-in template, asserts two different exact artifacts, and asserts one identical caller-visible output — which is the property the outer contract now states.
No production behavior was changed for REVIEW_API-2. Every file under that item is a _test.go file. The three regressions were mutation-checked against the pre-fix behavior (see Verification Results) rather than assumed to be meaningful.
Documentation scope. The inner contract agent-contract/inner/edge-config-runtime-refresh.md already described relative-only loading, the 8192-byte cap, digest-only refresh evidence, and frozen effective templates; the implementation converged to it and it was left unmodified, per the plan's instruction not to broaden it. The outer contract, the two runtime specs, and the input spec were the surfaces that contradicted the shipped behavior.
Reviewer Checkpoints
- Confirm absolute
plan_fileandreview_filevalues are rejected before filesystem access, while independent fallback and exact size/file-kind boundaries remain correct. - Confirm required Plan/Review headings and Review
PASSare exact lines and the admitted placeholder inventory is closed. - Confirm binding snapshot, clone/workspace revalidation, preset refresh isolation, and custom Review artifact tests exist and assert caller-output invariance.
- Confirm the outer contract and current specs consistently describe direct PlanMD, frozen effective templates, templated internal Review artifacts, and unchanged caller-visible I/O.
Verification Results
REVIEW_API-1 — Template and Config Boundaries
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
$ 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)"
exit=0
$ go test -count=1 ./packages/go/singlerequesttemplate ./packages/go/config
ok iop/packages/go/singlerequesttemplate 0.005s
ok iop/packages/go/config 0.144s
exit=0
New boundary subtests actually executed (-v, abridged to the added cases):
=== RUN TestLoadEdgeSingleRequestTemplates/absolute_plan_file_rejected_before_filesystem_access
=== RUN TestLoadEdgeSingleRequestTemplates/absolute_review_file_rejected_before_filesystem_access
=== RUN TestLoadEdgeSingleRequestTemplates/plan_file_configured_and_review_file_falls_back
=== RUN TestLoadEdgeSingleRequestTemplates/review_file_configured_and_plan_file_falls_back
=== RUN TestLoadEdgeSingleRequestTemplates/exact_8192_byte_template_file_accepted
=== RUN TestLoadEdgeSingleRequestTemplates/symlinked_template_file_fails_closed
=== RUN TestLoadEdgeSingleRequestTemplates/directory_template_path_fails_closed
=== RUN TestLoadEdgeSingleRequestTemplates/unreadable_template_file_fails_closed
=== RUN TestLoadEdgeSingleRequestTemplates/non-UTF-8_template_file_fails_closed
=== RUN TestLoadEdgeSingleRequestTemplates/invalid_grammar_matrix_fails_closed
(11 subcases: plan missing/decorated heading, unknown placeholder, delimiter residue,
duplicate placeholder; review missing PASS, NOTPASS, decorated heading,
missing placeholder, unknown placeholder, wrong order)
--- PASS: TestLoadEdgeSingleRequestTemplates (0.02s)
Mutation check — the three grammar/path fixes were temporarily reverted in place (filepath.IsAbs fallthrough restored in loadTemplateFile; requireExactLines reverted to strings.Index/strings.Count) and the same suites re-run, proving the new cases fail against the pre-fix behavior rather than passing vacuously. The files were restored byte-for-byte afterwards and re-verified green:
--- FAIL: TestLoadEdgeSingleRequestTemplates/absolute_plan_file_rejected_before_filesystem_access
expected error for absolute plan_file "/tmp/.../plan.md"
--- FAIL: TestLoadEdgeSingleRequestTemplates/absolute_review_file_rejected_before_filesystem_access
expected error for absolute review_file "/tmp/.../review.md"
--- FAIL: TestValidatePlanTemplate/decorated_heading_###_Plan err = <nil>, wantErr true
--- FAIL: TestValidatePlanTemplate/heading_line_carries_trailing_text err = <nil>, wantErr true
--- FAIL: TestValidatePlanTemplate/heading_embedded_inside_a_prose_line err = <nil>, wantErr true
--- FAIL: TestValidatePlanTemplate/duplicate_required_heading err = <nil>, wantErr true
--- FAIL: TestValidateReviewTemplate/NOTPASS_does_not_satisfy_the_PASS_result_line err = <nil>, wantErr true
--- FAIL: TestValidateReviewTemplate/PASS_embedded_in_a_prose_line err = <nil>, wantErr true
--- FAIL: TestValidateReviewTemplate/decorated_heading_###_Review err = <nil>, wantErr true
--- FAIL: TestValidateReviewTemplate/duplicate_PASS_result_line err = <nil>, wantErr true
FAIL iop/packages/go/config 0.014s
FAIL iop/packages/go/singlerequesttemplate 0.010s
REVIEW_API-2 — Binding, Refresh, Review Rendering, and Race Coverage
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/internal/service -run 'TestSingleRequestBinding'
ok iop/apps/edge/internal/service 0.026s
exit=0
$ go test -count=1 ./apps/edge/internal/openai -run 'TestSingleRequest(PresetBinding|ReviewStage)'
ok iop/apps/edge/internal/openai 0.044s
exit=0
$ go test -race -count=1 ./apps/edge/internal/openai ./apps/edge/internal/service ./apps/edge/internal/configrefresh ./packages/go/config ./packages/go/singlerequesttemplate
ok iop/apps/edge/internal/openai 12.349s
ok iop/apps/edge/internal/service 9.384s
ok iop/apps/edge/internal/configrefresh 1.210s
ok iop/packages/go/config 1.893s
ok iop/packages/go/singlerequesttemplate 1.037s
exit=0
The three prescribed regressions exist and executed (-v, added cases only):
=== RUN TestSingleRequestBindingTemplateSnapshot
=== RUN TestSingleRequestBindingTemplateSnapshot/admitted_binding_carries_the_exact_effective_pair
=== RUN TestSingleRequestBindingTemplateSnapshot/template-less_admission_falls_back_to_the_built-in_defaults
=== RUN TestSingleRequestBindingTemplateSnapshot/clone_preserves_the_frozen_pair
=== RUN TestSingleRequestBindingTemplateSnapshot/workspace_revalidation_preserves_the_frozen_pair
=== RUN TestSingleRequestBindingTemplateSnapshot/invalid_effective_templates_are_rejected_at_admission
=== RUN TestSingleRequestBindingTemplateSnapshot/an_invalid_template_cannot_survive_workspace_revalidation
--- PASS: TestSingleRequestBindingTemplateSnapshot (0.00s)
=== RUN TestSingleRequestPresetBindingTemplateRefreshIsolation
--- PASS: TestSingleRequestPresetBindingTemplateRefreshIsolation (0.00s)
=== RUN TestSingleRequestPresetBindingTemplateFallback
=== RUN TestSingleRequestPresetBindingTemplateFallback/both_templates_fall_back
=== RUN TestSingleRequestPresetBindingTemplateFallback/plan_configured_and_review_falls_back
=== RUN TestSingleRequestPresetBindingTemplateFallback/review_configured_and_plan_falls_back
=== RUN TestSingleRequestPresetBindingTemplateFallback/invalid_effective_template_fails_admission_closed
--- PASS: TestSingleRequestPresetBindingTemplateFallback (0.00s)
=== RUN TestSingleRequestReviewStageCustomTemplateSnapshot
=== RUN TestSingleRequestReviewStageCustomTemplateSnapshot/custom_template_renders_the_exact_internal_artifact
=== RUN TestSingleRequestReviewStageCustomTemplateSnapshot/default_template_renders_the_exact_internal_artifact
=== RUN TestSingleRequestReviewStageCustomTemplateSnapshot/stage_run_writes_the_custom_artifact_and_preserves_caller_output
=== RUN TestSingleRequestReviewStageCustomTemplateSnapshot/an_invalid_effective_template_fails_the_render_closed
--- PASS: TestSingleRequestReviewStageCustomTemplateSnapshot (0.00s)
ok iop/apps/edge/internal/openai 0.038s
Assertions are exact rather than substring: the refresh test compares the whole admitted template pair before and after mutating preset.SingleRequest.Templates.* and compiles a second binding to show the refreshed pair reaches only the new admission; the Review test compares the full rendered artifact byte string for both the custom and the built-in template while asserting one identical caller-visible result.Output.
REVIEW_API-3 — Full Suite and Documentation Guard
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
$ go test -count=1 ./apps/edge/... ./packages/go/...
ok iop/apps/edge/cmd/edge 0.237s
ok iop/apps/edge/internal/authprojection 0.055s
ok iop/apps/edge/internal/bootstrap 0.493s
ok iop/apps/edge/internal/configrefresh 0.117s
ok iop/apps/edge/internal/controlplane 6.676s
ok iop/apps/edge/internal/edgecmd 0.135s
ok iop/apps/edge/internal/edgevalidate 0.104s
ok iop/apps/edge/internal/events 0.043s
ok iop/apps/edge/internal/input 0.067s
ok iop/apps/edge/internal/input/a2a 0.058s
ok iop/apps/edge/internal/node 0.046s
ok iop/apps/edge/internal/openai 8.361s
ok iop/apps/edge/internal/opsconsole 0.062s
ok iop/apps/edge/internal/service 8.221s
ok iop/apps/edge/internal/transport 4.810s
ok iop/packages/go/audit 0.010s
ok iop/packages/go/auth 10.035s
ok iop/packages/go/config 0.161s
ok iop/packages/go/credentiallease 0.038s
? iop/packages/go/events [no test files]
ok iop/packages/go/execution 0.017s
ok iop/packages/go/hostsetup 0.011s
? iop/packages/go/jobs [no test files]
? iop/packages/go/metadata [no test files]
ok iop/packages/go/observability 0.024s
? iop/packages/go/policy [no test files]
ok iop/packages/go/singlerequesttemplate 0.007s
ok iop/packages/go/streamgate 0.884s
? iop/packages/go/version [no test files]
ok iop/packages/go/workspaceprotocol 0.016s
exit=0
$ make test-single-request-claude-smoke-self-test
./scripts/e2e-single-request-claude.sh --self-test
[single-request-claude-smoke] self-test passed: exact Claude base-route coverage, structured observation admission, child-only zero retry, authenticated model admission, closed failure classification, model/Edge/Node/runtime binding, zero-child preflight, derived verification, redaction, cleanup, signal handling, and atomic publication
exit=0
$ 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
(rg produced no matches; the guard did not trip)
exit=0
Documentation surfaces updated for REVIEW_API-3:
| File | Change |
|---|---|
agent-contract/outer/anthropic-compatible-api.md |
Added the effective-template subsection to Marked preset: single-request admission (Edge-owned internal stage input, unchanged caller request/response schema, no caller selection, no path/content/digest exposure, admission freeze); added the five single-request/template source paths to 계약 메타; added the caller-boundary 금지 사항 entry. |
agent-contract/index.md |
iop.anthropic-compatible-api 읽는 조건 and 원본 경로 now name the marked-preset template boundary and its source files. |
agent-spec/runtime/edge-node-execution.md |
Rewrote the stale Plan json_schema passage to frozen-template prompting and direct PlanMD parsing; added the Review artifact-rendering boundary; added the single-request effective templates feature row; rewrote the two superseded 변경 기록 entries and added the 2026-08-09 entry; added the template/config source_evidence and the three new verification commands. |
agent-spec/runtime/provider-pool-config-refresh.md |
Split templates out of the fixed single-request policy row into dedicated single-request effective templates and effective-template admission freeze rows; expanded the 범위 bullet with relative-only/pre-access rejection, per-file fallback, and refresh isolation; added source_evidence and the 2026-08-09 변경 기록 entry. |
agent-spec/input/openai-compatible-surface.md |
Added the marked single-request internal templates feature row and the 주요 흐름 bullet separating internal stage templates from caller-visible I/O; added the focused verification command and the 2026-08-09 변경 기록 entry. |
agent-spec/index.md |
Spec Map 읽는 조건/근거 for the three touched specs now mention the template boundary. |
agent-contract/inner/edge-config-runtime-refresh.md was deliberately not modified: it already specifies edge.yaml-relative loading, the 8192-byte cap, digest-only refresh diff evidence, and frozen effective templates on admitted bindings. The implementation converged to it.
REVIEW_API-4 — Approved Remote Profile
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'
Implementing agent: paste actual stdout/stderr, tested commit, and exit status. If the approved SOPS identity remains unavailable, record the raw failure and exact resume condition without claiming a pass.
[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section? If anything is blank, go back and fill it in before saving this file. Leave review-agent-only sections unchanged.
Section Ownership
| Section | Owner | Note |
|---|---|---|
| Header comment, Overview, Review Agent Instructions | Fixed at stub creation | Implementing agent must not modify or execute archive, complete.log, or task-directory moves. |
| Archive Evidence Snapshot | Fixed at stub creation from plan | Implementing agent reads only the cited evidence needed for this follow-up. |
| Implementation Item Completion | Fixed item names | Implementing agent checks [ ] to [x] only after actual completion. |
| Implementation Checklist | Fixed text/order from plan | Implementing agent checks [ ] to [x] only after actual completion. |
| Review-Only Checklist | Review agent only | Implementing agent must not modify or check this section. |
| Deviations from Plan, Key Design Decisions | Implementing agent | Replace placeholders with actual content. |
| Reviewer Checkpoints | Fixed at stub creation | Review agent verifies independently. |
| Verification Results | Fixed headings and commands | Implementing agent fills actual output only; command changes require a deviation entry. |
| Code Review Result | Review agent appends | Not included in this stub. |