Why: The r0.4 trial could prove that the parser missed [DONE] but could not distinguish clean EOF, malformed frames, read failure, or provider error without retaining raw SSE.
Evidence: RED receipts fast-slow-u3-r05-task1-terminal-red.json and task1-http-error-red.json; GREEN targeted receipt and full vet/test/race receipt fast-slow-u3-r05-task1-agent-native-full.json.
Impact: Add bounded scalar diagnostics and successful HTTP status to terminal events while preserving the existing incomplete-tool rejection, returned Usage, and retry behavior.
Refs: U3 r0.5 approved design and plan; Agent-Native PR #46
Why: The parser also recognizes function_call as a tool finish, but cannot execute a legacy call when no deltas were collected. It must fail closed like tool_calls.
Evidence: The function_call variant failed before this guard and passed afterward; full Agent-Native vet/test passed.
Impact: Inconsistent legacy tool terminals fail with returned Usage preserved; valid streams are unchanged.
Refs: U3 r0.4 independent review Important 2 closure
Why: A provider can report finish_reason=tool_calls without emitting any tool call. Treating it as a successful empty answer hides an incomplete operation.
Evidence: New SSE regression failed before the guard and passed afterward; full go vet and go test -count=1 ./... passed.
Impact: Inconsistent tool terminals fail closed while preserving returned Usage; valid text and tool streams are unchanged.
Refs: U3 r0.4 independent review issue 2
Why: Backend emitted tool deltas from a separate goroutine, racing with serialized run events and occasionally losing a UI delta.
Evidence: Backend race detector reproduced concurrent event writes; Agent-Native identity test RED→GREEN; full vet and tests pass.
Impact: runtime tool delta events now carry provider slot and call ID for single-owner downstream projection.
Refs: runtime/loop.go; runtime/event_vocabulary_test.go
Why: a model tool finish could execute partial JSON or an unterminated SSE stream, while post-Usage errors could lose their charge.
Evidence: missing-DONE, malformed-JSON, identity, non-object and post-Usage RED→GREEN tests; GOWORK=off go vet ./... and go test -count=1 ./... passed.
Impact: invalid tool terminals fail without execution or automatic retry and retain returned Usage; valid text and multi-part tool streams keep working.
Refs: runtime/llm/sse.go; runtime/loop.go
Why: Mutual exclusion alone does not preserve order. With parallel
execution the host cannot keep order-sensitive tools (card streaming
begin/append/commit, plan updates) correct by locking a mutex, because
whichever goroutine grabs the lock first is not necessarily the first
declared call - a real failure observed in the backend card-stream test.
Evidence: go test ./... green; TestLoopSerialToolsKeepOrder asserts the
serial calls execute in declaration order (s1->s2->s3) while parallel
calls still fan out.
Impact: New Config.SerialTools set. In parallel mode, matching calls run
sequentially on the caller goroutine in model-declared order; others
stay concurrent. Empty set keeps the previous all-parallel behavior;
sequential mode is untouched.
Refs: Dev task feature/agent-e1-parallel-fixes (F5).
Why: With parallel tool execution the host-side tool wrapper can no
longer infer which invocation it is serving from a single in-flight
slot; tools need the call identity (ID/name/arguments) to pair process
state and per-call bookkeeping. Context injection keeps the tools
registry signature unchanged.
Evidence: go test ./... green; TestLoopToolSeesOwnCallInContext runs
two parallel calls and asserts each reads its own ID from ctx.
Impact: Additive WithToolCall/ToolCallFromContext helpers; runOne now
wraps the ctx before Execute. Callers that never inject keep ok=false
and are unaffected.
Refs: Dev task feature/agent-e1-parallel-fixes (F5 parallel wiring).
Why: Parallel tool execution makes same-turn tool events interleave, so
consumers can no longer pair starts and ends by order; the kernel Event
needs the call ID. MiniMax interleaved-thinking models stream their
reasoning inside content <think> blocks unless the OpenAI-compatible
request opts in with reasoning_split=true, which forces reasoning into
the dedicated reasoning_content field the SSE layer already captures.
Evidence: go test ./... green; new tests TestLoopToolEventsCarryCallID
and TestOpenAIChatBodyReasoningSplit pin both behaviors (regression
anchors for the backend parallel-work change).
Impact: Additive Event.CallID (empty for non-tool events; existing
consumers unaffected) and an opt-in Client.ReasoningSplit flag that only
adds a request field when set. No default behavior change.
Refs: Agent-System-Dev proposal 2026-10-10-agent-delegation-routing-sandbox.md
(F2/F5), Dev task feature/agent-e1-parallel-fixes.
Why: Interleaved-thinking models (MiniMax, DeepSeek R1) require the
assistant's thinking to be passed back verbatim in message history; dropping
it degrades later turns. The product's P2-I1 replayed thinking only into the
request-side rebuild; with the session transcript becoming the authoritative
context (quality P2-I2), capture must live in the kernel so thinking persists
in the transcript and replays on every request.
Evidence: SELF - TestReasoningCaptureAndReplay covers capture (SSE
reasoning_content into Message.Thinking, content unpolluted) and replay
(<think> prefix on thinking assistants, untouched non-thinking messages);
go vet + go test ./... pass.
Impact: sse.go accumulates reasoning deltas into the terminal message's
Thinking; client.go toProviderMessages renders captured thinking as a
<think> block prefix for assistant messages. Anthropic path unchanged;
messages without thinking serialize exactly as before.
Why: the delegation task brief must state goal, output format, tools and
boundaries (Q3 acceptance); Request had no carriers for the two new
sections, so delegate_task callers could not declare them.
Evidence: TestDelegateToolRoundTrip extended to assert output_format and
tools survive the tool-call round trip; runtime suite green (SELF); CI
authoritative (GATE).
Impact: additive Request fields + delegate_task schema/description; empty
fields keep today's behavior (task brief sections omitted).
Refs: Q3 plan WP3; Dev card .task/feature-agent-stack-q3.md
Why: squad consumes exec.ProcessEvent, which lacked the split usage
fields, so the WP6 accounting could not reach squad runs.
Evidence: GOWORK=off go vet green; additive fields on ProcessEvent.
Impact: additive only.
Refs: Agent-Native#35 #37, N3 plan WP6
Why: hosts accumulating per message_end could not see cache hits; the
fields now ride the same event as the per-request totals.
Evidence: GOWORK=off go test green.
Impact: additive event fields.
Refs: Agent-Native#35
Why: cache tokens were parsed but never accumulated, the usage event
carried only cumulative totals and was skipped on terminal paths
(audit N20 residual), and stream retry was host-opt-in so subagents,
the verifier, and squad runs were never retried.
Evidence: GOWORK=off go vet + go test -count=1 ./... green;
TestUsageEventSplitsLastAndCache (event carries Last*/cache),
TestUsageAccumulatesCacheTokens, TestBudgetStopEmitsTerminalUsage,
TestDefaultRetryAttemptsTwo (0 value = 2 retries with
auto_retry_start events), TestNegativeRetryAttemptsDisables (negative
= off), TestRetryNeverDuplicatesForwardedDeltas (the only-before-first-delta
invariant holds under the library default).
Impact: usage events now carry Last* and cache fields and are emitted
on budget/error terminal paths too; Config.RetryAttempts defaults to
2 (negative disables) so every host gets the existing retry semantics
without wrapping; default (unset) host wrappers should be retired to
avoid double retries.
Refs: Agent-System-Documents#43 (N3 plan WP6), audit N20
Why: the completion doc assigns the Memory port to the library; today
memory recall is a product-side interface assertion with no library
surface, AgentSpec.MemoryScope has no consumer, and the model has no
write-back path.
Evidence: GOWORK=off go vet + go test -count=1 ./... green;
TestLoopInjectsMemoryAndRegistersWrite (recall block lands after the
system section, memory_write executes through the loop),
TestEmptyRecallInjectsNothing (empty recall changes nothing),
TestBlockRenderOrderingAndCaps (deterministic order, expiry/empty
pruning), TestWriteToolValidation (fail-closed scope/type/content).
Impact: new opt-in Config.Memory/MemoryScope; nil port keeps behavior
byte-identical; injection is request-scoped (never persisted, never
accumulates) and deterministic ([记忆] text shape preserved for the
product migration).
Refs: Agent-System-Documents#43 (N3 plan WP5)
Why: CI runs as root, where chmod-based failure injection does not
fail (root bypasses file permissions), and any filesystem state that
would fail restore is pre-detected by the classification pass. A
package-level test seam makes the injection deterministic on any uid.
Evidence: GOWORK=off go test (-race) green locally.
Impact: test-only seam, documented as never-for-production.
Refs: Agent-Native#33
Why: rollback eligibility was implicit (any struct with a mark field),
restore followed symlinks out of the root, a single failing file
aborted the rewind leaving unreported partial state, and the log grew
unboundedly with an O(N) read per record.
Evidence: GOWORK=off go vet + go test -count=1 ./... green;
TestCheckpointedToolSetIsPinned (eligibility is exactly
{write_file, edit_file, multi_edit}), TestRewindSkipsSymlinkTarget
(link and outside target untouched, classified Skipped),
TestRewindPartialFailureContinues (Failed reported, rest restored),
TestCompactKeepsRecentAnchors (original seqs kept, monotonic after),
plus pinned edges for empty ordered, identical-rewrite=Already, and
per-record roots; all pre-existing rewind tests pass unchanged.
Impact: Result gains Failed (additive); Rewind no longer aborts on a
single file; symlinks classify as external changes; Compact bounds the
log; Seq is computed from a cached counter instead of a full read.
Refs: Agent-System-Documents#43 (N3 plan WP3)
Why: acceptance clause 3 requires span names and attributes to follow
the convention; today names were bare words with two ad-hoc attribute
keys, and every span got a fresh random trace with no parentage.
Evidence: GOWORK=off go vet + go test -count=1 ./... green;
TestSpanNamesFollowGenAIConvention (name suffixes, gen_ai.* key enum,
intValue usage, service.name resource, prompt/reserved-key exclusion),
TestLoopSpansFollowGenAIConvention (invoke_agent root with shared
trace, chat/execute_tool children with parent links, usage attrs on
chat spans); the pre-existing prompt-body denylist test passes
unchanged.
Impact: span names become invoke_agent <agent> / chat <model> /
execute_tool <tool>; attributes move to gen_ai.* with usage as
intValue; one Run shares one trace with invoke_agent as root. New
Config.AgentName/ProviderName (documented defaults keep old hosts
meaningful); telemetry StartFunc gains WithServiceName/WithEndpoint
options (defaults preserve current behavior).
Refs: Agent-System-Documents#43 (N3 plan WP4)
Why: the product conversation path needs the intent journal and
recovery pairing, but making the transcript the authoritative context
would freeze the assembled system prefix (memory/plans/injections go
stale). JournalOnly keeps the session as journal-only: recovery runs
against it, the context always comes from History, and the recovered
outcomes are injected as a system note. Separately, the one-time
History seed was memory-only and silently lost from the second run on
(authority mode); it is now persisted except in JournalOnly mode.
Evidence: GOWORK=off go vet + go test -count=1 ./... green;
TestJournalOnlyRecoversWithoutTranscriptAuthority (journal gets the
replayed pair exactly once, history never enters the journal, the
recovery note precedes the new user message, seeds stay out);
persistedProjection honors JournalOnly; all pre-existing durable and
harness tests pass unchanged (default semantics untouched).
Impact: new opt-in Config.JournalOnly; default (false) behavior is
byte-identical.
Refs: Agent-System-Documents#43 (N3 plan WP2)
Why: a kill between persist(assistant) and commitToolIntent left an
unpaired tail that no recovery path repaired (acceptance clause 1's
library gap), and Stop.Replacement mutated the in-memory assistant
while the transcript kept the original (audit N6 residual).
Evidence: GOWORK=off go vet + go test -count=1 ./... green;
TestResumePairsOrphanTailAfterCrashWindow (no-intent window pairs with
crashInterrupted, run continues), TestResumeMixedIntentAndOrphanTail
(intent path and tail repair never double-pair),
TestRepairOrphanTailNoopOnHealthyTranscript; the harness assertion now
pins replacement-as-user-note (forged=4, notes=3).
Impact: every next Run repairs the trailing assistant's resultless
calls before the first request; replacement text now appears only as a
user message in both memory and transcript (intentional, recorded in
the N3 card).
Refs: Agent-System-Documents#43 (N3 plan WP1)
Why: the host factory decides sync vs background spawning; the request
must carry the declaration (AgentSpec.Background consumption point,
mirroring the product delegate tool's background parameter).
Evidence: GOWORK=off go vet + go test green; the delegate_task schema
gains the background property.
Impact: none for hosts that do not set the field.
Refs: Agent-System-Documents#42 (N2 plan WP5)
Why: the completion doc's N2 requires skills validated per the open
spec; today frontmatter was a description-only line hack with silent
skips, no name field, and no error surface.
Evidence: GOWORK=off go vet + go test -count=1 ./... green; parser
units cover all field forms and reject malformed shapes with located
errors; the validation matrix covers kebab-case/name-equals-dir/
required description/limits; Store.Diagnostics surfaces per-skill
reasons and Load returns the located validation error for same-named
invalid skills; existing fixtures updated to spec form.
Impact: stricter by design — skills without name/description or with
unknown frontmatter keys now produce located errors instead of silently
loading or silently skipping; ValidateSkillDocument is exported so the
product plugin/seed paths share the same validator.
Refs: Agent-System-Documents#42 (N2 plan WP4)
Why: the completion doc requires the client to recognize resultType,
treat input_required as a protocol-level result whose answer retries the
original tools/call, and expose tasks/get|update|cancel; today only a
content-block special case existed and the advertised version was never
checked against the server's.
Evidence: GOWORK=off go vet + go test -count=1 ./... green;
TestInputRequiredResultTypeRetriesOriginalCall (ask → tasks/update →
retry, call order and final content), TestNegotiatedVersionFallbackKeepsLegacyPath
(byte-level legacy behavior on 2024-11-05), TestTasksGetAndCancelRoundTrip,
TestRunEndCancelsSeenTasks, TestDefaultSchemaDeclares202012; the
acceptance-③ regression TestStdioSlowCancelThenEcho passes unchanged.
Impact: advertise 2026-07-28 and branch on the negotiated version
(older servers keep byte-identical behavior); synthesized default tool
schemas now declare JSON Schema 2020-12; runs cancel the MCP tasks they
saw via a per-run TaskTracker (other runs on the shared manager are
unaffected).
Refs: Agent-System-Documents#42 (N2 plan WP3)
Why: acceptance clause 1 requires the anthropic preset to complete a
tool-call round against recorded HTTP fixtures; audit N4's root cause
was an offline body builder the real client never used, with no
tool_use/thinking support on the wire.
Evidence: GOWORK=off go vet + go test -count=1 ./... green;
TestAnthropicPresetToolRound drives the preset through tools request →
tool_use → tool_result → final text with thinking-signature round-trip
against byte-recorded SSE fixtures; TestAnthropicBodyShape pins block
forms and cache_control; legacy OpenAI path untouched (Client.Protocol
zero value).
Impact: the anthropic preset now means the native Messages API (the
compat shim remains reachable via models.json custom providers); audit
N4 closes. BuildBody shares anthropicBody with the live client.
Refs: Agent-System-Documents#42 (N2 plan WP2), audit N4
Why: the completion doc's N2 requires old tool results to become file
paths (ZCode compact pattern) and cache-friendly prefix rules; today the
micro-compactor only left a transcript pointer and nothing pinned prefix
stability. alignToolTail had no direct edge tests.
Evidence: GOWORK=off go vet + go test -count=1 ./... green; new
TestClearOldToolResultsSpillsToDisk / TestSpillResultSanitizesCallID /
TestAlignToolTailEdges / TestSystemTextDeterministicAcrossIdenticalBuilds;
legacy placeholder bytes unchanged when ResultsDir is empty
(TestClearOldToolResultsEmptyDirKeepsLegacyPlaceholder).
Impact: opt-in via Config.ResultsDir; the native adapter wires it to
<workDir>/.agentx/results. No behavior change for other hosts.
Refs: 2026-10-07-agent-stack-n2-plan WP1
Why: a ContractRequest without a workspace (the conformance minimal
case) resolved WorkDir to the process CWD and wrote .agentx transcripts
into the repo, dirtying the tree in CI and failing the build step's
worktree check.
Evidence: GOWORK=off go vet + go test -count=1 ./... green;
TestContractEmptyWorkspaceKeepsCWDClean pins the fixture bytes;
the adapters/native tree no longer drifts after a suite run.
Impact: requests with an explicit workspace are unchanged; empty
workspace now lands in a disposable temp dir.
Refs: Agent-System-Dev#242 CI failure (run 1144)
Why: the Dev combination check requires every nested agent-intent pin
to equal the Dev top-level pin (343b1e6, I2 increments 1-2 on intent
main).
Evidence: tree-only pin move; agent-native code does not consume the
new ports.
Impact: none.
Refs: I2 increment 3 cascade
Why: Dev moved its agent-intent pin to 2554b50 (PRs #6/#7);
check-pins requires the same combination in the nested copy
(gitlink only - no go.mod reference since D1).
Evidence: 2554b50 is the #7 merge on agent-intent main; native
suite runs next.
Impact: Nested pin only.