Ambiguous idempotency-store failures can occur after the account transaction commits. Scope durable recovery markers to the authenticated admin, retain the operation key across reloads, and recover only an already committed copy without rerunning active work.
Constraint: Generic idempotent handlers may legitimately remain active while a recovery lookup is attempted
Rejected: Reclaim or rerun an in-progress duplicate request | can execute account creation concurrently
Rejected: Recover by source account and key alone | allows another admin to observe the committed copy
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep ambiguous-response recovery read-only and bind durable operation markers to the authenticated actor
Tested: Full Go unit suite, go vet, server build, integration-test compilation; frontend lint, typecheck, 1,030 Vitest tests, and production build
Not-tested: Docker-backed PostgreSQL integration runtime because Docker is unavailable
Related: Wei-Shaw/sub2api#1379
Related: Wei-Shaw/sub2api#2928
Admins often need another account with the same provider and routing configuration. Duplicate on the server so credentials never return to the browser, preserve exact group priorities atomically, start the copy paused, and recover the same copy after ambiguous idempotency-store failures.
Constraint: Admin account responses redact credentials, so duplication must remain server-side
Constraint: OAuth and setup-token credentials rotate and must not be shared across account rows
Rejected: Copy raw account JSON to the clipboard | exposes credentials outside the server
Rejected: Duplicate rotating credentials | account-scoped refresh locks can race token rotation
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep copies paused, avoid automatic upstream probes, and exclude rotating credential types unless token ownership is redesigned
Tested: Targeted Go tests, Go vet, server build; frontend lint, typecheck, Vitest suite, production build; integration test compiled
Not-tested: Docker-backed PostgreSQL execution because Docker is unavailable
Related: Wei-Shaw/sub2api#1379
Related: Wei-Shaw/sub2api#2928
Three tests covering the CC→Responses→Anthropic finalize path:
- TestStreamingParallelToolUseNoGhostDelta: full end-to-end with two
parallel tool_calls, asserts every content_block_delta targets a
started block
- TestStreamingParallelToolUseSecondToolPackedArgsDone: focused test
where tool 1 streams deltas and tool 2 has packed .done args
- TestStreamingThreeParallelToolsAllPackedDone: three tools all with
packed .done, the most extreme case
All three fail on unfixed code (ghost deltas on wrong indices) and
pass after the fix.
resToAnthHandleFuncArgsDone used state.ContentBlockIndex directly
instead of looking up from OutputIndexToBlockIdx like
resToAnthHandleFuncArgsDelta does. When multiple tool_calls arrive
in parallel and arguments come as a packed .done (no prior delta),
the second+ tool would emit content_block_delta on an index that
was never content_block_start'ed, causing Claude Code to report
"Content block not found".
Fix: resolve block index from OutputIndexToBlockIdx, and skip the
delta if the block is already closed or the index doesn't match
the current open block.
Closes#4193
ChatGPT OAuth may normalize explicit image size controls to auto while returning smaller raster bytes. Decode final image headers so Images API metadata and tier billing reflect the actual output for both streaming and non-streaming OAuth responses.
Enrich openai.upstream_failover_switching structured logs with proxy
identity fields (proxy_id, proxy_name, proxy_host, proxy_port) so
operators can see which outbound proxy failed when switching accounts.
Matches the existing gateway.forward_failed / websocket_proxy_failed
logging pattern.
Add proxy_id/proxy_name/proxy_host/proxy_port fields to openai.websocket_proxy_failed so operators can identify which proxy failed without extra lookups. Matches the existing gateway.forward_failed logging pattern.
Add a toggleable group ID column in /admin/groups column settings.
It shows the group id (e.g. #1), is hidden by default for new and
existing admins via column-settings version migration, and remains
sortable against the existing backend sort_by=id support.