Repository navigation
v0.2.13 follow-ups: profit control as upstream, one reasoning recovery switch, retired settings and options deleted - #235
Merged
Merged
Conversation
Group profit control (upstream Wei-Shaw#4925) was switched off downstream by a compile-time kill switch, a 400 on any profit_* field in group create and update, and constant false/0/0 values in the API-key auth snapshot. The owner decided on 2026-10-03 that the feature is upstream's again: editable per group, off by default. - openai_profit_control.go, gateway_profit_control.go, group.go, admin_group_duplicate.go and handler/admin/group_handler.go are byte-identical to v0.2.13 again, and the profit-preview command with service/profit_preview.go is back. - The auth snapshot carries the stored group values. Its version becomes 28: version 27 entries hold the constants instead of the stored values, and the gate is built from the cached group without a database read, so they have to be reloaded. - The legacy selection failure summary counts profit vetoes again instead of counting a vetoed account as eligible. - Upstream's comments at the gate call sites are restored where the fork had shortened or dropped them. - Tests: upstream's profit tests replace the rewrites that pinned the switched-off state; profit_control_dormant_regression_test.go and TestGroupHandlerRejectsLegacyProfitControlWrites are removed; the simple-mode normalization tests send the profit fields again. No migration: the three columns come from 192, and the invalidation trigger function as last defined by 260 has the body of 193. A group that leaves profit control off gets no gate, so scheduling is unchanged for it. The profit code still differs from v0.2.13 only where a downstream contract wraps it: the runtime-breaker probe on selection results, the single repository read of the previous-response owner, Codex quality runs, the WebSocket local close error, the scheduler-based token count selection and the (bool, reason) eligibility helpers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ialogs The create and edit dialogs get upstream's editable section back: the switch, the minimum gross margin and the safety buffer in percent, and the validation before submit, with groupsProfitControl.ts, its spec, the profitControl texts of both locales and the request types. The read-only block of the edit dialog, its retiredProfitControl texts and the comment that called the fields deprecated are removed. The console theme needs no rule and no hook: the section has the markup of the peak-rate block above it, and its divider, checkbox, label, hint, field labels and inputs resolve to the same computed styles as their neighbours in light and dark. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The v0.2.13 review listed the profit control kill switch among the deviations kept. It now states the restoration, the files that are identical to upstream again, the auth snapshot version, why no migration is needed, what a group without a gate still sees differently (the snapshot reload and the two counters in the legacy selection summary), the profit lines that still differ inside downstream mechanisms and the checks that were run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… options
Invalid reasoning ciphertext recovery becomes one global switch on its own
page under 扩展功能; the two per-account options leave the account dialogs.
This is the frontend half: the backend for the endpoint below and the removal
of the per-account backend code follow separately.
- /admin/reasoning-recovery (sidebar: 扩展功能, after Codex 运行设置): one
switch with Reload and Save, no step-up. It reads and writes
GET/PUT /api/v1/admin/reasoning-recovery, body and answer
{"enabled": boolean}. No value is shown before one is loaded, and an answer
without a boolean counts as a failed request.
- Create, edit and bulk edit of an account no longer show or send
openai_chat_reasoning_replay_enabled and
openai_reasoning_signature_recovery_enabled. OpenAIReasoningPolicyFields,
utils/openaiReasoningPolicy, their specs and locale keys are deleted, and
buildOpenAIExtra starts from a plain copy again.
- oauthPassthroughDesc now names the global switch instead of the option that
used to sit below it.
- Console theme: the page takes the 系统提示词 rules through its own data-ui
hook; no new rule set.
- downstream-verify selects the new view spec in place of the two deleted
specs, which test_upstream_automation_contract requires to exist.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
openai_apikey_alpha_search_responses_bridge_enabled and openai_apikey_prompt_cache_key_normalization_enabled lost their gates and write fields on 2026-09-01 (cce166e). Since then the values were only loaded, shown in 系统设置 as 已弃用设置(只读,不生效) and written back unchanged on every save. They now go completely. - Frontend: the block, its state, the deprecated_settings field of the settings API type and its locale keys are removed, together with the alphaSearchMode* and promptCacheKeyMode* account locale keys that no component used and a stylesheet comment that named the block. - Backend: GET /admin/settings answers upstream's plain document again (no deprecated_settings); saving no longer carries the two values; the setting keys, their defaults, parse and update code, the audit comparison and the two never-read fields of OpenAIRefusalRecoveryRuntime are deleted. - Migration 266 deletes the two settings rows; an integration test restores them next to data that must stay and applies the migration twice. - Tests: the cases that only covered the two values are deleted. The ordinary API-key Alpha Search tests keep every assertion and lose the retired switch from their fixtures, so two are renamed after what they assert: TestForwardAlphaSearchOrdinaryAPIKeyUsesDirectAlphaSearchEndpoint and TestAlphaSearchOrdinaryAPIKeyToolErrorDoesNotSwitchAccounts. The handler fixture passes no settings service again, as before the switch existed. The account option openai_prompt_cache_key_mode and the PAT-only Alpha Search bridge are live and not touched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The v0.2.13 review was last written for the profit control follow-up alone. With the settings purge and the reasoning options change on the same tree, three of its statements were no longer true: the first start applies four migrations, not three (266 is new); two settings rows are deleted on upgrade; and the per-account reasoning options are not untouched. - Integration decisions: the deletion of the two retired API-key compatibility settings, and the frontend half of the reasoning options change, with what this tree still lacks (the endpoint and the removal of the per-account backend code) and the save error that follows for an account whose stored value is not a boolean. - Migrations: 266. - Validation: the checks run on the combined tree, why upstream-risk.json needs no regeneration, and an intro line that fits the follow-up bullets. - Release target: four migrations; no setting takes a new value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Upstream selects the account for the Codex models manifest with SelectAccountForModelWithExclusions, which installs no profit gate. The downstream handler selects through the scheduler, so the scheduler's defensive gate applied to the manifest as soon as a group enabled profit control: every account over the threshold was filtered, and a group with none left was answered with 503 "No available OpenAI accounts" where upstream serves the manifest. A veto after the slot would have ended as an empty 200, because this handler has no veto branch. CodexModels now marks its request context with WithOpenAIProfitControlSuppressed before the selection loop, as token counting does. No gate is installed for the request, so neither the filter nor the veto can occur there. TestCodexModelsIgnoresGroupProfitControl: a group with profit control on whose only account is over the threshold still gets its manifest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Reasoning options: create and bulk edit never send the two keys; the edit dialog no longer sets them but still sends them inside the stored extra it passes through. The lead sentence said that all three dialogs no longer send them, against its own sub-bullet. Name what the backend half has to remove for the pass-through to end; no strip code returns to the dialog. - Profit control inside downstream mechanisms: two differences from v0.2.13 were missing. The Codex models manifest selects through the scheduler under the handler's suppress marker, and a same-account retry gets a selection without a gate, so its check after the slot uses the request-level gate. - Validation: the settings purge and the reasoning options change share three files (the two admin/accounts.ts locale files and pages/settings-ops-public.css, in separate hunks); only profit control shares none with the others. List the checks run for the review fixes. - settings-ops-public.css: the hook table names the current SettingsView.vue lines of settings-dlg-foot (6386, 8035, 8088) and settings-list-box (7836). The removed deprecated-settings block moved them up by 27 lines, and three of the four numbers were 12 lines off before that. Comment only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner decisions after the preview of 2026-10-03. - The page has the switch and Save only. The Reload button, its locale key in both locales and its spec case are gone. The value is read once when the page is opened: load() no longer has a second caller, so the reset of the error before a read and the two guards that only a second read needed (loading while a draft exists) went with the button. - A failed read shows its error and no switch, with Save disabled, until the page is opened again. That is how the pages without a reload button behave (Codex 运行设置, 系统设置); no control was added for it. - Sidebar: the entry used the shield of 安全审计 and 操作日志. It now has RecoveryIcon, the turn-back arrow (Heroicons arrow-uturn-left), defined like the other inline icons and mapped for the console theme to the new Icon.vue name undo, whose Lucide glyph is undo-2 (verbatim from lucide-static 0.469.0). No other entry uses the icon, the path or the name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…again - The account-level Alpha Search and prompt_cache_key mode selectors left the dialogs long ago; three cases only asserted that their test ids are absent. The edit and bulk edit cases are deleted. The create case also checks that the Responses mode stays on auto when the Laxa base URL is typed instead of taken from the preset, which sets force_responses; that part stays under a name that says so. - admin.accounts.bulkEdit.noFieldsSelected lost its only assertion with the reasoning policy cases. A new bulk edit case selects the Responses routing field, changes the target to a platform that hides it and submits: nothing is sent and the message is shown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sync Two defects of the TypeSafe account dialogs that are upstream's (v0.2.13), fixed by owner decision of 2026-10-03. Wording. A TypeSafe account showed the generic API-key texts, which name Anthropic. The Base URL and API Key hints now come from the per-platform keys admin.accounts.typesafe.baseUrlHint / apiKeyHint (zh, en), through the baseUrlHint and apiKeyHint computeds that already serve OpenAI and Gemini. The edit dialog's placeholders are https://api.typesafe.ai and ts-..., the values the create dialog already had. Model sync. The create dialog started 同步上游支持的模型 after a create for every API-key account with a concrete mapping target. A TypeSafe account always has one (jev-latest), and System One has no model list, so every create ended with a 400 from the sync and the warning toast 同步上游模型失败. The button itself was decided by a platform set inside ModelWhitelistSelector, a second rule that knew no account type. utils/upstreamModelSync.ts now holds the one rule, supportsUpstreamModelSync(platform, type, credentials): the pairs that fetchUpstreamModelList and its request builders (service/upstream_models.go) accept before any upstream call, with the two that also depend on credentials (an Antigravity API-key account needs a base URL ending in /antigravity; a Gemini OAuth account with a project is Code Assist, which has no list). - Create dialog: the preview credentials exist, and the sync after a create starts, only where the rule holds. A preview also needs the API-key form, whose key authenticates it; a key left there no longer offers a preview in the OAuth and Bedrock sections. - Edit dialog: the model selectors get the account ID, and the Antigravity button shows, only where the rule holds for the saved account. - ModelWhitelistSelector offers the button for the target it is given; its platform set is gone. Bulk edit gives it no target, as before. Besides TypeSafe this ends three offers the backend answered with 400: the button for a Vertex service-account account, and the button and the sync after a create for an Antigravity API-key account whose base URL does not end in /antigravity. The backend is unchanged. The rule was compared with the backend by running both over the eleven platforms, the six account types and four credential variants: 264 cells, no difference. That comparison is not part of the repository. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A system prompt reaches an account only through the gateway that forwards its platform: the prompt service is called on the final body by GatewayService (Messages), OpenAIGatewayService (Responses, Chat Completions, Messages), GeminiMessagesCompatService and AntigravityGatewayService. A TypeSafe account is forwarded by ForwardSystemOne, which relays the request as it is, and System One has no system or instructions field. Still the binding endpoint wrote a binding to it, the account dialogs offered the control, and 系统提示词 counted it as inheriting the default (owner decision of 2026-10-03: do not offer it, and skip it in bulk). The rule is one list, service.SystemPromptPlatforms, the ten platforms those four gateways forward. An account on any other platform takes no binding. Backend - SetBindings (PUT /admin/system-prompts/bindings, used by the edit dialog, the row menu and the bulk bar alike) loads the selected accounts and writes only to those on the list. The others are skipped the way IDs that match no account already were: no error, and the answer counts the accounts written. - The usage counts of 系统提示词 are taken over the accounts on the list. - Migration 268 removes extra.system_prompt from every account on another platform, soft-deleted rows included. Such a value could exist (the endpoint wrote it whatever the platform, and 259 turned an old prompt_skills "off" into one), so it is removed once instead of being ignored in code. One UPDATE, a no-op when run again; no trigger writes another row for it. Frontend - takesSystemPrompt (utils/systemPromptBinding.ts) is the copy of the list. The account edit dialog and the row menu offer 系统提示词 only where it holds. - The bulk bar keeps its button: a selection is a list of IDs that can span pages. Its dialog now says that TypeSafe accounts are skipped, and reports the number actually updated. - The page texts no longer promise every platform: the description, the hint under the default prompt and the notes name the TypeSafe exception. Tests: SetBindings skips such accounts and writes nothing for a selection of them only; the edit dialog and the row menu offer the control for OpenAI and Antigravity accounts and not for a TypeSafe one. TestMigration268... (tag integration) is added next to the tests of 263 and 266 and, like them, needs a database: it was compiled here, not run. Not closed here: account create, bulk update, data import and duplicate store extra as given on every platform, so a direct API caller can still put the key on such an account. Nothing reads it there and no dialog sends it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The intro of 系统提示词 named the TypeSafe exception too. In the console theme that made the Chinese text wrap, with two characters left on a second line and the head's buttons pushed down (seen in the preview capture). The exception is stated right below it, under the default prompt and in the notes, so the intro only loses its "on every platform" claim: accounts that inherit the default receive it. Both locales. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The v0.2.13 review described the tree before the owner's preview of 2026-10-03. Several of its statements are no longer true, and three downstream differences from official were not written down. Corrected - 推理恢复 has the switch and Save, not Reload and Save; what a failed read leaves on the page; the entry's own sidebar icon. - The two TypeSafe defects of the account dialogs are no longer "upstream warts kept as they are"; only the missing badge colour is. - The open owner question about the binding selector of TypeSafe accounts is answered and removed. - The first start applies five migrations, not four (268 is new), and the release carries two downstream migrations besides the tail one. - System prompts for TypeSafe: not only "not applied". Recorded - TypeSafe in downstream account flows: the binding rule (service.SystemPromptPlatforms), what the endpoint, the counts, the dialogs and the page texts do with it, and what stays open to a direct API caller. - Deliberate downstream deviations: the TypeSafe wording of the dialogs, and the one rule for the upstream model sync with the set it mirrors and the offers it ends besides TypeSafe. - Migrations: 268. - Validation: the checks of this change and what was not run. gpt6-routing-and-prompts.md said that inheriting accounts use the site default on every platform; it now states the rule and the TypeSafe exception. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e a prompt The bulk bar offered 系统提示词 for every selection of 1 to 1000 accounts. For a selection of TypeSafe accounts only, one selected row included, the control had no effect: the binding request skips such an account. Its dialog showed no skip hint for a single account, stated 当前生效:站点默认 for the selection and ended with 已更新 0 个账号, while the row menu of the same account has no such entry (owner decision 5 of 2026-10-03). Bar - AccountsView gives the bar the selected rows the list holds (selAccounts, which selPlatforms and selTypes are now derived from). - The button is absent when every selected account is among them and none takes a prompt. A selection is a set of IDs that can also name accounts of other pages, of every result or of an import; such a selection keeps the button, and the request skips the accounts that take none. Dialog - The bar tells the dialog how many of the selected accounts it knows to take a prompt. The edit dialog and the row menu, which offer the binding only for such an account, pass nothing. - The skip hint no longer depends on the selection holding more than one account: it is shown whenever a selected account may be skipped, with its own wording for a single account the list has not loaded. A selection known to hold only accounts that take a prompt gets the plain count sentence again, and none for one account. - What the binding puts in effect is stated only when a selected account is known to take a prompt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SetBindings skips an account that can never receive a prompt and migration 268 removes the bindings such accounts already held, but three other paths still stored a given extra.system_prompt on any platform: - account creation (buildAccountForCreate), which data import and duplicate go through with a stored extra: an export holding a binding re-created it on a TypeSafe account; - bulk update (BulkUpdateAccounts), which merges the given keys into extra; - UpdateAccountExtra, which re-authorization reaches with the caller's extra. Only UpdateAccount protected the key. A binding stored that way could not be removed again: the dialogs hide the control for such an account and the endpoint skips it. So 268 was not final, and its header's "this release writes no binding to these accounts" was not true. The rule "an account outside SystemPromptPlatforms holds no binding" is now kept where extra is written: - account creation drops a given binding unless the platform takes a prompt; - bulk update and UpdateAccountExtra drop the key on every platform, like the other keys that enter through their own endpoint. On an existing account the binding endpoint is the only writer of the key; an account edit keeps the stored value, as before. The header of 268 now names these writers among the ways such a row came to hold a binding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The v0.2.13 review said two things about system prompt bindings that the review of the post-preview changes found false or left open. Corrected - The bulk bar does not keep its button for every selection: it offers 系统提示词 while the selection can hold an account that takes a prompt, and not when every selected account is loaded and none of them does. What the bulk dialog says about skipped accounts and about the effect is described as it is now. - "Not closed: account create, bulk update, data import and duplicate store extra as given ... no dialog sends it" is removed. The data import dialog did send it, and the three writers are closed: creation drops a given binding unless the platform takes a prompt, bulk update and UpdateAccountExtra write the key on no platform. - Migrations, 268: the writers that could leave such a binding are listed in full, and why the file is a single correction. Recorded - Validation: the checks of these fixes and what was not run. gpt6-routing-and-prompts.md states the same rule for the bulk bar, account creation and the two key-level writers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Chat-to-Responses behaves as official v0.2.13 again where replay was the fork's only difference: the request is the plain conversion of the client's messages, tool call ids are normalized by the Codex transform, and nothing is recorded from the response. Signature recovery stays on that path; it now rebuilds each attempt from the clean body like the native path does. Deleted: the replay engine and its recorder hooks in the Chat and Messages handlers, the replay rules, the batch half of the reasoning state cache (Redis keys, Lua branches, bounds, interface methods), the rejected-cipher callback that only replay used, the request builder variant that existed for replay preparation, ChatMessageResponsesInput, and the Chat cases of the live diagnostic harness. The harness and the CI gate are named for what they cover now: reasoning recovery. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Chat-to-Responses conversion always asks for reasoning.encrypted_content in `include`, so the assertion that the second request never contains the string "encrypted_content" failed. It now names what must not come back: the ciphertext the upstream returned in the first turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every lookup and every write of the rejection memory built its own Redis client, dialed, ran one script and closed the connection, so a request carrying reasoning ciphertext paid a TCP dial and a handshake on its way upstream. The dedicated client existed because the shared client does not apply a context deadline to socket I/O. The script now runs on the shared client through WithTimeout: the same connection pool, with the remaining I/O budget as read and write timeout. Waiting for a pooled connection, a new dial and a retry backoff end with the operation's context, and the shared options stay untouched. A Redis that stops answering still costs a request no more than its 100 ms budget, and the connection that timed out leaves the pool. An unreachable Redis now costs the remaining budget instead of failing at the first refused dial, because the pool retries the dial while the operation waits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signature recovery was switched per account through accounts.extra and read
again before every send and before the retry decision. It is now one settings
row, reasoning_recovery_config = {"enabled": <bool>}, enabled while no row is
stored, served like the system prompt configuration: an in-memory value that
a save replaces at once and a background refresh renews after 60 seconds, so
the forwarding path never queries the database. A forwarding attempt reads
the switch once, when its recovery state is created. A save and a refresh
are serialized, so a read that began before a save cannot publish the older
value after it. A failed read at startup stops the start; a failed refresh
keeps the value in use.
GET and PUT /api/v1/admin/reasoning-recovery read and save
{"enabled": <bool>} beside the system prompt endpoints: admin
authentication, no step-up, the save audited as
admin.reasoning_recovery.update.
Removed with the account option: both extra key constants and their getters,
the validation and preservation in the admin service, the handler checks and
the import merge that hid stored values, the bulk-edit target preflight, the
scheduler cache projection, and their tests.
Cleaned after the dispatch layer removal: the policy calls took a context
they never used and returned a nil error, so the unavailable-policy state,
its stop reason and those operands are gone, and nothing produces
policy_unavailable any more. The request-shape helpers of
plugin_codex_recovery.go live in openai_reasoning_recovery_policy.go, and the
rejection is parsed by the one policy function.
The recovery gate selects the tests of the switch and no longer names the
deleted scheduler projection tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Removes openai_chat_reasoning_replay_enabled and openai_reasoning_signature_recovery_enabled from accounts.extra. Nothing reads them: Chat reasoning replay is deleted and recovery has one global switch. A stored value is not carried over to that switch. Rows that hold neither key are not written, and a second run writes nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds the global switch, its endpoint, storage and read path to the current-state document, and names reasoning signature recovery where the v0.2.13 review listed the per-account reasoning policy switches, which no longer exist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rejection memory ran on the shared Redis client through WithTimeout. The shared client does not apply a context deadline to socket I/O, so each write and read got the remaining budget as a timeout of its own, counted from the moment it started: after a slow pool turn or dial, a stalled reply could hold a request for about twice its 100 ms budget. An unreachable Redis cost the whole budget, because the shared pool retries a refused dial with a backoff while the operation waits. The memory now runs on one long-lived client of its own, built with the gateway cache from the shared options. It applies the context deadline, so every write and read ends at the operation's deadline however long the connection took to acquire. It sends a command once and dials once, so a refused dial fails the operation at once. Connections are opened on demand and reused, so an operation still pays no dial, and a connection that timed out leaves this client's pool, not the shared one. The shared client's options are untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing produces policy_unavailable since recovery became a direct call: its producers went with the policy lookup. The continuation diagnostic allow-list still accepted it, which only served rows stored by earlier releases. The list now holds exactly the reasons recovery can emit; a stored row carrying the retired value reads as an empty reason, like any unknown value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The harness was the fork side of one sealed, dated study of Chat reasoning replay and signature recovery (run reasoning-replay-recovery-20260907). Its broker lives outside this repository: it runs one pinned binary once, a stored ledger refuses a second run, and it passes only when the Chat replay cases complete. With Chat replay deleted the remaining recovery cases cannot be launched by it under any name, the bootstrap still required the study's replay run id, and the harness gateway never read the global recovery switch. Deleted: the live test, its offline control test and its support file. The CI gate keeps the offline unit contracts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ReasoningFidelityGatewayForTest builds its gateway from a frozen settings snapshot but installed no ReasoningRecoveryService, so a harness gateway ran with recovery enabled whatever the snapshot stored. Before the switch became global the option came from the frozen account row. The helper now loads the switch from the same snapshot: a missing row keeps the enabled default, a stored "off" stays off, and an invalid row fails the bootstrap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Whether the dated live recovery diagnostic and its broker outside this repository are deleted or kept and aligned is not decided. Until it is, the harness stays as it was reviewed: the live test, its offline control test, its support file and the second command of the gate are back, and the frozen gateway helper they share with the fidelity harness has its previous wiring again. This undoes b0a6e85ea and 664eed548. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… cache The client the rejection memory runs on is built with the gateway cache, and nothing in the application closed it. The cache now releases it in Close, and application cleanup calls that before it closes the shared Redis client, which stays with its owner. The blocked-transport test took its snapshot of the shared options after the cache had been built, so it compared those options with themselves. It takes the snapshot first now: a constructor that edits the shared options in place fails it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nostics The backend neither produces nor accepts the stop reason policy_unavailable any more, so the Ops error detail keeps no text for it. The text was inline in the component; no locale key belonged to it. The text for "disabled" still described a per-account scope. Recovery has one global switch now: a forwarding attempt reports "disabled" when the switch is off, when the account type is not covered, or on a request path recovery does not cover (Messages, or a final request that is not /responses or /responses/compact). The text says that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FRONTEND_CRITICAL_VITEST still named src/features/cindy-group-split/__tests__/CindyGroupAuditDialog.spec.ts, which #206 deleted. Vitest ignores a file filter that matches nothing, so `make test-frontend-critical` selects the same specs as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The v0.2.13 review was written by the integration and extended by two follow-up branches, each describing its own tree: the frontend branch called the recovery backend "not in this tree", the backend branch knew no page, and both listed checks of trees that no longer exist. It now describes the one tree that ships as v0.2.13-codexrip.1. - Reasoning recovery is one entry: the global switch, its endpoint and page, the deleted Chat reasoning replay and per-account options, the rejected-cipher memory client, and the live diagnostic that stays as it is until the owner decides. - Migrations: the six files of this release in the order the runner applies them, the production path (read) and the new-database path (executed), migration 267, and what an older image reads after the three purges. - The profit control notes drop the Codex quality run, which #233 removed; the TypeSafe check in buildAccountForCreate is described as it stands after #233. - Validation states what was run on the assembled tree and what was not. - Release target lists what changes with the upgrade before an administrator acts. gpt6-models-and-prompts.md names the 推理恢复 page, the envelope and the 400 of the endpoint, and compact; it refers to migration 267 for the two removed keys instead of repeating their names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Four packages the follow-ups do not touch have tests that import the changed ones (accounttools/policy, codexruntime/profile, handler/quotaview, securityaudit). Their tests were type-checked on the assembled tree with the unit tag; the Validation section says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both headers named git 06e865f as the previous release and cited line numbers in it. 06e865f is v0.2.11-codexrip.8; the release before v0.2.13-codexrip.1 is v0.2.11-codexrip.9 (291d25e, #233), where the reader of the two account keys is service/plugin_codex_recovery.go:20-27 and the deprecated_settings block is handler/admin/setting_handler.go:513-519. The other cited lines are the same in both commits. Comment lines only; the statements are unchanged. The runner pins a file's checksum from its first application on, and the only database that applied these files was the disposable one of the validation run, so the headers are corrected before the release. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TestOpenAIReasoningRecoveryChatToolRoundKeepsNoReasoningState ended by checking that no gin context key contains "replay". The only such keys were set by openai_chat_reasoning_replay.go, which is deleted, so the loop asserted the absence of removed code. The test keeps its contract: the second turn is the plain conversion of the client's messages, without the first turn's ciphertext or reasoning id, and the reasoning state store is neither read nor written. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The zh hint of the switch said 被拒 reasoning next to 新推理, and the scope note kept the English Chat-only. They now say 被拒推理项, the term the English text and the downstream document use, and 只支持原生 Chat 的上游. The recovery line of the Ops continuation diagnostics was labelled 推理签名恢复 while the reason for "disabled" in the same panel says 推理恢复, the name of the page. The label is 推理恢复 too. The English texts already used one name and are unchanged. Text only. The owner has not previewed these strings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Release target names the stored data of the removed replay that the
upgrade does not delete: the batches the previous image wrote to Redis
under openai_reasoning_state:v1:{openai_reasoning_batches}:. No code of
this release names the prefix; every key carries the 24-hour expiry
the previous image set, so the last one is gone 24 hours after that
image stored its last batch.
- The live recovery diagnostic was described as kept as it was. Against
the previous release it is renamed from replay to recovery (files,
build tag, tests, environment variables, user agent) and has lost its
Chat half; the run id, the bootstrap contract and the recovery cases
are unchanged. Deleting it or aligning it with the broker stays the
owner's open decision.
- The upstream risk gate also runs on a manual dispatch for a pull
request number, not for sync/upstream-* branches only. It recomputes
from the commit the manifest records, so a dispatched run reproduces
the manifest and asks for the upstream-reviewed label.
- Validation lists the four changes made after its runs (the headers of
266 and 267, one assertion of the Chat tool round test, three zh
strings), what was run again and what was not: ESLint, vue-tsc and
vitest for the two frontend files, and an owner preview of the zh
texts written after 2026-10-03.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The harness was the fork side of one sealed study of Chat reasoning replay and signature recovery (run reasoning-replay-recovery-20260907). Its broker outside this repository ran one pinned binary once and passed only when the Chat replay cases completed; with Chat replay deleted it cannot run under any name. The owner decided on 2026-10-04 to delete the whole tool. Deleted: the live test, its offline control test, its support file and the second command of the gate script. The frozen gateway helper it shared with the reasoning fidelity harness now loads the recovery switch from the same frozen settings snapshot, so that harness sees a stored off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The hint and the scope note are the wording the owner approved in the preview of 2026-10-03. The review document records the deleted live diagnostic and what was run on the final tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HTExplicit
added a commit
that referenced
this pull request
Oct 4, 2026
…ion-repair diagnostics (#238) Owner decisions of 2026-10-04: the last dated one-shot diagnostics leave the repository. The reasoning replay/recovery diagnostic went with #235. Deleted: the reasoning fidelity diagnostic (four test files of service under the reasoning_fidelity build tag, 2,124 lines) and the continuation-repair diagnostic (two test files of handler under the continuation_repair_live build tag, 1,953 lines). No other file carried either tag, no workflow or script named them, and every production function they called has other callers, so no production code changes. Test-only files under build tags that no build uses: no runtime change and no release. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Ships together with the upstream v0.2.13 integration (#232) as
v0.2.13-codexrip.1. These are the follow-ups the owner decided on 2026-10-03..downstream/upstream-review-v0.2.13.mddescribes the resulting tree.What changes for administrators
profit_control_enabled,profit_min_margin,profit_safety_buffer), off by default. The compile-time kill switch, the 400 onprofit_*fields, the constants in the API-key auth snapshot and the read-only "retired" block are removed. The profit code and its tests are byte-identical to upstream v0.2.13; the Codex models manifest stays outside the gate, as upstream.GETandPUT /api/v1/admin/reasoning-recoverywith{"enabled": boolean}; stored as the settings rowreasoning_recovery_config, on while no row exists, read from memory on the forwarding path, saves audited./antigravitybase URL.policy_unavailableany more, and the text fordisablednames the switch.What changes for API users
profit_control_enabledis already true is gated from the first start.Removed
Chat reasoning replay: engine, recorder hooks, replay rules, the batch half of the reasoning state cache.
The two per-account reasoning options: stored keys, validation, import merge, bulk-edit preflight, scheduler cache projection, UI component, specs, locale keys.
The retired settings
openai_apikey_alpha_search_responses_bridge_enabledandopenai_apikey_prompt_cache_key_normalization_enabled: code, thedeprecated_settingsfield ofGET /admin/settings, the UI block, the stored rows.The profit control kill switch and its "dormant" tests.
The stop reason
policy_unavailable.CI:
.github/scripts/test_reasoning_replay.shis nowtest_reasoning_recovery.sh; a spec deleted in fix: rework connection tests, context capacity, system prompts, Cindy and UI foundation #206 left the Makefile critical list.The dated live reasoning diagnostic (owner decision of 2026-10-04): the live test, its offline control test, its support file and the second command of the gate script. Its broker scripts outside this repository are deleted as well; the study's ledger on the server is not touched.
Migrations
On a database that already ran
v0.2.11-codexrip.9, the first start applies six files in this order: the two upstream 241 files and 265 (already on main with #232), then the three of this PR:266_purge_retired_openai_apikey_compat_settings.sql: deletes the two retired settings rows.267_purge_account_reasoning_options.sql: removes the two per-account reasoning option keys fromaccounts.extra; a stored value is not carried over to the global switch.268_purge_system_prompt_bindings_without_insertion_point.sql: removesextra.system_promptfrom accounts on a platform without an insertion point.Each is a single statement with lock and statement timeouts and a no-op when run again. None has a down path; an older image would treat every account as default-on for replay and recovery.
Verification
Run on this branch:
go build ./...(windows);go vetwith theunitand theintegrationtag on the 14 touched packages and withuniton the 4 packages whose tests import them;gofmt -lempty for the 102 changed Go files;golangci-lint2.13 with 0 issues on the 14 packages.120 Go tests by name with the
unittag in ten packages, all passing: upstream's profit tests (43 inservice, 10 inhandler, 2 inhandler/dto, 3 incmd/profit-preview), the settings tests the purge changed, the system prompt binding tests, the recovery route and audit tests,TestAPIContracts, both TypeSafe migration tests..github/scripts/test_reasoning_recovery.shas CI runs it: 60 tests.Migrations 266, 267 and 268: their integration tests pass against a disposable local PostgreSQL 18.1 after the harness applied all 349 migration files to the empty database.
Frontend:
vue-tsc --noEmit; ESLint on the 48 changed files; vitest for 13 spec files with 279 tests (the 11 changed specs, locale key completeness, the diagnostics component). These ran against a local dependency tree with axios 1.18.1 and dompurify 3.3.1, while the lockfile pins 1.20.0 and 3.4.14.test_upstream_automation_contract.py,test_upstream_risk.py,test_release_preflight.py.After the last changes (live diagnostic deleted, the frozen harness helper loads the recovery switch, two zh texts back to the approved wording):
go build ./...,go vetonservicewith theunitand thereasoning_fidelitytag, the gate script, the two offline fidelity tests,vue-tsc --noEmit, ESLint on the two changed frontend files and vitest for six files with 20 tests.Production, read only through the admin API on 2026-10-04: all 12 groups hold the profit defaults (off, 0, 0); none of the 862 accounts holds either reasoning option key or a system prompt binding, so 267 and 268 change no row there; both retired settings rows exist and 266 deletes them.
Not run locally: the full unit, integration, race and e2e suites, the linux build and the candidate image, whole-project ESLint and the production frontend build, the production migration path against a database in the state of
v0.2.11-codexrip.9, a browser preview of the assembled tree, and real model calls.🤖 Generated with Claude Code