Repository navigation
fix(reasoning): re-send without the id when the upstream cannot find a stripped reasoning item - #252
Merged
Merged
Conversation
…a stripped reasoning item Reasoning recovery deletes encrypted_content from reasoning items and keeps the item with its id. An upstream may take such an item for a reference to one it stores, and answers `Item with id '<id>' not found` when it has none (HTTP 404 from api.openai.com). In production on 2026-10-06 one conversation ended this way 59 times: 56 first sends that had been stripped from the 24h memory and 3 stripped retries, all naming one id of the form rs_ + 32 hex. Ids minted by OpenAI were accepted when left behind in the same way. When the upstream's error message names an item this attempt stripped, the request is now re-sent once on the same account with the id removed from the items the attempt stripped; the items and every other field stay. This is the remedy the Codex OAuth path already applies to every reasoning item. - Trigger: an answer with a status >= 400 other than 401/402/403/407/429 whose message names, as not found, the id of a reasoning item that this attempt stripped and that was sent with that id and without ciphertext. An item without a summary keeps its id, because the upstream refuses it without one. - It is separate from the stripped retry and does not spend it: an account sees at most three POSTs (first send, stripped retry, id repair). A strip made after the repair removes the id together with the ciphertext. - Nothing is remembered. Each request that meets the answer repairs again. - Native Responses, passthrough and Responses-shaped bodies on the Chat Completions endpoint. The repaired answer has no account-health effect. - The wire-to-clean projection accepts the id deletion and nothing else new. - Ops: recovery action `retry_without_item_ids`; the continuation diagnostic gains `recovery.item_ids_removed`. Whether api.openai.com accepts a reasoning item with neither id nor ciphertext was not verified against the real upstream. If it does not, the repaired request ends with that answer instead of the 404. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… retry's record Follow-up to the id repair, from review. - Deleting a field from the stripped reasoning items edited the whole body once per item, in the strip, in the repair and again in the projection. At the sizes seen in production (hundreds of items, megabytes) that is hundreds of milliseconds to seconds of CPU per request. The items are now edited on their own and the body is written once; the per-item lookups read the input array once. The bytes are those of the one-by-one deletion, which is kept as the fallback and as the oracle of the new equivalence test. - The repair no longer resets the record of the stripped retry (retryDispatched, diagnosticState): the continuation diagnostic goes on describing the stripped retry, as the handbook says. - The repaired answer's status and request id are recorded with its own event and are not left in the state, which matters for the Chat Completions path that does not observe each response. - Handbook: the bound of three POSTs is per forwarding attempt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HTExplicit
added a commit
that referenced
this pull request
Oct 7, 2026
The deployment path still carried retired acceptance, rollback, resource-request and plugin-era controls, while console typography needed to be brought up to date with the current upstream style. This integrates the remaining authorized takeover work after the reasoning repair in #252. - Integrates #253, #254, #255 and #222 while retaining their commit ancestry. Removes stale release scaffolding and deployment template settings; preserves every existing migration SQL file. - Production Deploy accepts only `release_tag` and `confirmation=DEPLOY`, sends `deploy <immutable-image>`, and retains standard OCI provenance and fixed SSH/environment controls. Both automation callers and historical-run deduplication match it. - Migration 274 deletes only validated, soft-deleted release-acceptance keys and their usage/dedup rows, removes the two acceptance columns, and leaves ordinary keys and diagnostic logs. The matching application no longer reads those columns. Older images cannot be deployed after 274; failures require a forward fix. - Uses upstream system fonts, sizes and readable semantic text colors without dropping table columns. Fixes the TLS empty-state color and whole-badge/word wrapping, and normalizes the audit helper's LF bytes without semantic changes. - Removes the image-side skill-registry directory after the host mount and retired runtime configuration were removed. Validation: reuse the component branches' directly affected tests and source-identical UI matrix; normal required checks run on this final integration tree. The only integration conflicts were the migration CI selector and retired documentation/notices; the resolved selector retains the new PostgreSQL migration fixture and live migration tests. All existing migration SQL is unchanged. Entry-point Bash syntax and diff checks pass. The simplified host tool has completed a successful unchanged-image `.12` redeploy, preserving environment/resources and other containers. Host config retirement also passed with a new complete backup retained. UI localhost fake-data validation sampled 7,728 normal text/input/placeholder elements across 36 after states, with no sample below 4.5:1; account tables fit at 1280/1440/1920 in both languages/themes. Before screenshots block external fonts and show their fallback stack. No real model call or live upstream ID-less-item acceptance test was performed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reasoning recovery strips rejected ciphertext but keeps the reasoning item and its ID. Some upstreams then treat that ID as a reference to a stored item and reject the request with
Item with id '…' not found. This change repairs that specific response once on the same account by removing IDs only from reasoning items whose ciphertext this forwarding attempt actually stripped. Items, summaries and other fields remain intact.Validation on the final patch uses unit-tagged service tests: the previously interrupted
TestOpenAIReasoningRecoveryRepairIsRecordedWithItsOwnAnswer; unsent repair diagnostics after cached pre-stripping and after a stripped retry, including prior account/cipher failures; and directly affected single-repair, stripped-retry availability, exact sent-body, account mismatch and account-failure classification cases. Formatting and diff whitespace checks pass. The normal required PR checks validate this new head separately.No real model calls were made. Acceptance by api.openai.com of reasoning items without ID or ciphertext remains unverified; a rejected repair ends with that upstream response, and subsequent requests retain their normal first-send behavior.