Client or integration
Claude Code (Claude Desktop Code surface)
Area
Provider adapter
Summary
On OpenCode Go's deepseek-v4.1-flash Chat route, appending a chronological Claude system reminder still rewrites the leading outbound system message. The generic Chat serializer collects text-only developer messages into that leading message, undoing the chronological representation introduced by #4161. This changes the reusable prompt prefix even when the existing conversation is unchanged.
This is the Chat-outbound follow-up explicitly left out of scope in #4161, which closed #4148. Proposed narrow fix: #4438.
Reproduction
-
Use the canonical OpenCode Go destination (https://opencode.ai/zen/go/v1), Chat adapter, and model deepseek-v4.1-flash.
-
Translate a synthetic Claude request through anthropicToResponsesBody → parseRequest → createOpenAIChatAdapter(...).buildRequest(...):
{
"model": "deepseek-v4.1-flash",
"system": "Stable project instructions.",
"max_tokens": 100,
"messages": [
{"role": "user", "content": "Inspect the synthetic project."},
{"role": "assistant", "content": "First result."},
{"role": "system", "content": "Synthetic reminder A."}
]
}
-
Append an assistant turn, a user continuation, and another system reminder B; build the second outbound request.
-
Compare the old-length prefix of the second outbound messages array with the first array. Before the fix, reminder B joins the leading system content and the comparison fails. Expected on this compatible route: the prior serialized messages remain unchanged and the new reminder stays in its chronological position, while pending tool calls/results remain adjacent.
The offline regression in #4438 exercises the actual translation/parser/adapter chain with stabilizePromptCache both false and true. It requires no credentials or model requests. The new suite produced 5 failures on the unmodified base and 15 passes with the patch, including destination/model boundaries and pending-tool behavior.
Version
Observed locally on OpenCodex 2.52.0, Bun 1.4.2. PR base: dcd13b4358befaae0fdca845a8219103943faca0; proposed head: e7bfb08b2823647b09d501692f759193a19d2299.
Operating system
Windows 11, build 26200.
Provider and model
OpenCode Go / deepseek-v4.1-flash, High effort. Live observation includes input growing to 409,130 tokens; it does not validate the full advertised 1M window.
Observed cache behavior
Snapshot through 2026-09-12 22:07:56 UTC, about 2h23m after the local chronological patch became active:
- Same long-session cohort: 9.17% before (16 measured later requests), 99.05% after (194).
- Both patched cohorts combined: 99.06% over 202 measured later requests; latest 50: 99.88%; latest 20: 99.92%.
- Four measured requests were below 90%, retained in those totals. One reset coincided with input shrinking from 214,155 to 36,948 tokens; another followed about 33 minutes without a successful request in that cohort and recovered on the next success. Compaction/cache expiry are possible explanations, not established causes.
Ratios are sum(cached input)/sum(input) from reported upstream usage; input already includes cached tokens. The first successful request per phase/session/effort is excluded as a cold-start approximation, and eligible requests require at least 1,024 input tokens. Failed requests and missing/estimated usage are not counted as cache measurements. The whole patch window contains 218 requests: 204 HTTP 200, 2 client cancellations (499), 12 connection failures (502), and no 400/422. Connection failures are disclosed separately; this issue does not propose a 502 fix.
This is an uncontrolled within-session observation, not a general cache guarantee. The live local endpoint predicate differs from the PR's registry-based predicate, whose boundary is tested offline. The opt-in trailing-notice stabilization setting stayed enabled during the live patch window; the new offline tests cover both setting values.
Related work / duplicate check
Searched open/closed issues and PRs for cache, DeepSeek, system, hoist and chronological terminology. No other PR implementing this specific residual fix was found; #4438 already exists and is reused. It remains draft because broader local test:changed validation is unresolved, as detailed in its body.
Checks
Client or integration
Claude Code (Claude Desktop Code surface)
Area
Provider adapter
Summary
On OpenCode Go's
deepseek-v4.1-flashChat route, appending a chronological Claude system reminder still rewrites the leading outbound system message. The generic Chat serializer collects text-onlydevelopermessages into that leading message, undoing the chronological representation introduced by #4161. This changes the reusable prompt prefix even when the existing conversation is unchanged.This is the Chat-outbound follow-up explicitly left out of scope in #4161, which closed #4148. Proposed narrow fix: #4438.
Reproduction
Use the canonical OpenCode Go destination (
https://opencode.ai/zen/go/v1), Chat adapter, and modeldeepseek-v4.1-flash.Translate a synthetic Claude request through
anthropicToResponsesBody→parseRequest→createOpenAIChatAdapter(...).buildRequest(...):{ "model": "deepseek-v4.1-flash", "system": "Stable project instructions.", "max_tokens": 100, "messages": [ {"role": "user", "content": "Inspect the synthetic project."}, {"role": "assistant", "content": "First result."}, {"role": "system", "content": "Synthetic reminder A."} ] }Append an assistant turn, a user continuation, and another system reminder B; build the second outbound request.
Compare the old-length prefix of the second outbound
messagesarray with the first array. Before the fix, reminder B joins the leading system content and the comparison fails. Expected on this compatible route: the prior serialized messages remain unchanged and the new reminder stays in its chronological position, while pending tool calls/results remain adjacent.The offline regression in #4438 exercises the actual translation/parser/adapter chain with
stabilizePromptCacheboth false and true. It requires no credentials or model requests. The new suite produced 5 failures on the unmodified base and 15 passes with the patch, including destination/model boundaries and pending-tool behavior.Version
Observed locally on OpenCodex 2.52.0, Bun 1.4.2. PR base:
dcd13b4358befaae0fdca845a8219103943faca0; proposed head:e7bfb08b2823647b09d501692f759193a19d2299.Operating system
Windows 11, build 26200.
Provider and model
OpenCode Go /
deepseek-v4.1-flash, High effort. Live observation includes input growing to 409,130 tokens; it does not validate the full advertised 1M window.Observed cache behavior
Snapshot through 2026-09-12 22:07:56 UTC, about 2h23m after the local chronological patch became active:
Ratios are
sum(cached input)/sum(input)from reported upstream usage; input already includes cached tokens. The first successful request per phase/session/effort is excluded as a cold-start approximation, and eligible requests require at least 1,024 input tokens. Failed requests and missing/estimated usage are not counted as cache measurements. The whole patch window contains 218 requests: 204 HTTP 200, 2 client cancellations (499), 12 connection failures (502), and no 400/422. Connection failures are disclosed separately; this issue does not propose a 502 fix.This is an uncontrolled within-session observation, not a general cache guarantee. The live local endpoint predicate differs from the PR's registry-based predicate, whose boundary is tested offline. The opt-in trailing-notice stabilization setting stayed enabled during the live patch window; the new offline tests cover both setting values.
Related work / duplicate check
Searched open/closed issues and PRs for cache, DeepSeek, system, hoist and chronological terminology. No other PR implementing this specific residual fix was found; #4438 already exists and is reused. It remains draft because broader local
test:changedvalidation is unresolved, as detailed in its body.Checks