2 Commits
Author SHA1 Message Date
forever ee7ab461c5 gateway tests: a Claude Code run a test keeps for the next turn ends with the test, so -count no longer gathers 11 fake Claude Code processes a round (#1060)
Six tests have their server keep a Claude Code run for a conversation's
next turn, which the bridge holds for idleLongest (an hour):
TestClaudeRunKeptForTheNextTurn, TestClaudeOneOffAskNotKept,
TestClaudeRunLetGoWhenTheConversationMovedOn and
TestClaudeRunKeptAcrossEffort (claude_subscription_test.go),
TestClaudeRunKeptAfterTheClientsOwnToolCall and
TestCodexThreadKeepsItsClaudeRunAcrossAMemoryCall. Nothing ended those
runs, so each test's fake Claude Code ran on until the test binary
exited, 11 more each round: under -race -count=50, gateway.test had 77
of them after about 8 rounds.

Each now ends its server's runs as the gateway does when it stops,
t.Cleanup(s.subscription.abortAll), like the tests that already keep
runs. fakeClaude, and TestClaudeRunKeptAcrossEffort's own fake, register
runsEndWithTest before New(), so it runs after the test's cleanups: it
fails the test when a run of that fake is still in its server's bridge
and not ended, and ends it. Like the park sweep, it counts a run killed
or exited, on its way out of the bridge, as ended.

Without the six abortAll cleanups the six tests fail:

    claude_subscription_foreign_test.go:19: Claude Code runs the test started, still going after it: 3
    --- FAIL: TestClaudeRunKeptAfterTheClientsOwnToolCall
    claude_subscription_test.go:148: Claude Code runs the test started, still going after it: 3
    --- FAIL: TestClaudeRunKeptForTheNextTurn
    claude_subscription_test.go:192: Claude Code runs the test started, still going after it: 1
    --- FAIL: TestClaudeOneOffAskNotKept
    claude_subscription_test.go:349: Claude Code runs the test started, still going after it: 2
    --- FAIL: TestClaudeRunLetGoWhenTheConversationMovedOn
    claude_subscription_test.go:571: Claude Code runs the test started, still going after it: 1
    --- FAIL: TestClaudeRunKeptAcrossEffort
    codex_developer_cache_test.go:73: Claude Code runs the test started, still going after it: 1
    --- FAIL: TestCodexThreadKeepsItsClaudeRunAcrossAMemoryCall

With them they pass.

The test binary's processes after each round of -count=3, each test run
alone with a probe that lists gateway.test's descendants after it: before,
3, 6, 9 (TestClaudeRunKeptForTheNextTurn,
TestClaudeRunKeptAfterTheClientsOwnToolCall), 2, 4, 6
(TestClaudeRunLetGoWhenTheConversationMovedOn) and 1, 2, 3 (the other
three); the six in one run 11, 22, 33. After, none for each. The
package's other tests, run the same way one by one, left none running
into their next round: in a first round the probe saw only the stand-ins
TestMain runs once (testenv.StandIns), and once a fake of
TestClaudeBridgeSafeguardContextUpdates that abortAll had just killed.
The 21 that need bun, which end their plugin host with plugin.Settle, and
the live Codex test were skipped here.

-race -count=20 of the six passes. gofmt -l, go vet ./..., go build ./...,
GOOS=linux go build -tags nogui ./..., GOOS=windows go build ./... and
go test -tags nogui ./... pass under a temp HOME with Go's caches pinned.
Tests only.
2026-10-07 05:59:51 +08:00
yetone 0cb6e13d91 gateway: a developer message Codex adds mid-thread stays where it is, so the thread's cached prefix does too (#502, Koohoko: after a memory request the next turn of the same session wrote the whole conversation to the cache again) — Codex adds a developer message to a thread where its context changed (a world-state or skills diff, a settings or model change, and so after its memory pipeline has run) and keeps it there in every later request, which leaves OpenAI's prefix as it was. parseResponses lifted every developer and system message, wherever it stood, into the system prompt, so on a translated route that turn's system changed: Anthropic's system comes before the messages, so the whole conversation was written to the cache again, and a Claude subscription's waiting Claude Code is found by its system (turnKey), so a new one was started and told the whole conversation in one message. Developer messages before the thread's first reply (Codex's initial context) are lifted as before; one after it now stays in place as a user message inside <system-reminder>, which the router's classifier already leaves out of the user's words. The memory request itself (another model, its own prompt, the same session) moves nothing in magpie: affinity is scoped by model or by a group's first words, the Claude bridge's runs by the conversation. TestCodexLaterDeveloperMessageKeepsTheSystem and TestCodexThreadKeepsItsClaudeRunAcrossAMemoryCall (a Codex thread on a Claude subscription, a memory call in the same session between, then a developer message: the same Claude Code goes on) fail without the change. No real vendor request was made. go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./internal/gateway/ ./internal/provider/ pass. 2026-10-02 13:00:22 +08:00