@bitkyc08/opencodex 2.82.0 → 2.83.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/gui/dist/assets/{App-Ds_qL7o8.js → App-Ba8uG696.js} +4 -4
  2. package/gui/dist/assets/{Tray-BqHF5Trd.js → Tray-IImbNPRy.js} +1 -1
  3. package/gui/dist/assets/{index-D3FBCNiP.js → index-BHRZdJuv.js} +12 -12
  4. package/gui/dist/assets/{quota-summary-DTBC8n7-.js → quota-summary-DiJO6sYY.js} +1 -1
  5. package/gui/dist/index.html +1 -1
  6. package/package.json +1 -1
  7. package/src/adapters/cursor/catalog.ts +2 -2
  8. package/src/adapters/cursor/effort-map.ts +1 -1
  9. package/src/adapters/devin/live-models.ts +2 -2
  10. package/src/adapters/google-truncation.ts +22 -0
  11. package/src/adapters/google.ts +7 -3
  12. package/src/adapters/ollama-native.ts +18 -14
  13. package/src/adapters/openai-responses/passthrough.ts +2 -0
  14. package/src/adapters/openai-responses/plaintext-reasoning-notice.ts +85 -0
  15. package/src/adapters/openai-responses/reasoning.ts +11 -1
  16. package/src/bridge/errors.ts +7 -1
  17. package/src/claude/context-windows.ts +3 -3
  18. package/src/claude/desktop-picker.ts +1 -1
  19. package/src/cli/account-auth.ts +20 -12
  20. package/src/cli/resolve.ts +1 -1
  21. package/src/clients/config-export/model-metadata.ts +16 -0
  22. package/src/clients/config-export/zcode-store.ts +46 -11
  23. package/src/clients/config-export/zcode.ts +3 -5
  24. package/src/clients/config-export.ts +1 -1
  25. package/src/codex/auth-api/pool-mode-gate.ts +4 -5
  26. package/src/codex/auth-context.ts +8 -3
  27. package/src/codex/catalog/native-models.ts +1 -1
  28. package/src/codex/catalog/provider-models.ts +25 -0
  29. package/src/codex/desktop-app/darwin.ts +1 -1
  30. package/src/codex/desktop-app/handoff.ts +1 -1
  31. package/src/codex/desktop-app/linux.ts +1 -1
  32. package/src/codex/desktop-app/lock.ts +1 -1
  33. package/src/codex/desktop-app/types.ts +1 -1
  34. package/src/codex/desktop-app/windows.ts +1 -1
  35. package/src/codex/desktop-app-restart.ts +1 -1
  36. package/src/codex/main-account.ts +6 -7
  37. package/src/generated/compatibility-version.json +91 -75
  38. package/src/grok/inject.ts +245 -221
  39. package/src/grok/reset-coupon-ledger.ts +223 -57
  40. package/src/grok/reset-coupons.ts +13 -6
  41. package/src/integrations/cursor-detect.ts +1 -1
  42. package/src/lib/errors.ts +25 -0
  43. package/src/lib/redact.ts +2 -2
  44. package/src/oauth/index.ts +1 -1
  45. package/src/oauth/meta-muse-device.ts +1 -1
  46. package/src/oauth/types.ts +1 -1
  47. package/src/providers/anthropic-fast.ts +1 -1
  48. package/src/providers/anthropic-reset-grant-ledger.ts +1 -1
  49. package/src/providers/devin-cli-authmode-migration.ts +1 -1
  50. package/src/providers/devin-provider-merge-migration.ts +1 -1
  51. package/src/providers/github-copilot-auto.ts +169 -0
  52. package/src/providers/model-presets.ts +1 -1
  53. package/src/providers/muse-subscription-usage.ts +1 -1
  54. package/src/providers/registry/entries-core.ts +6 -6
  55. package/src/providers/registry/entries-extended.ts +4 -0
  56. package/src/providers/registry/model-seeds.ts +3 -3
  57. package/src/providers/xai-fast-model.ts +1 -1
  58. package/src/server/inbound-body-admission.ts +24 -7
  59. package/src/server/index/link-listener.ts +30 -17
  60. package/src/server/index/serve-options.ts +8 -2
  61. package/src/server/index.ts +1 -1
  62. package/src/server/lifecycle.ts +31 -4
  63. package/src/server/management/grok-coupon-routes.ts +277 -52
  64. package/src/server/management/link-routes.ts +42 -20
  65. package/src/server/management/route-registry.ts +2 -2
  66. package/src/server/relay-eager.ts +2 -0
  67. package/src/server/relay.ts +18 -7
  68. package/src/server/request-log-failure-attribution.ts +3 -0
  69. package/src/server/request-log-terminal-status.ts +186 -0
  70. package/src/server/request-log.ts +15 -118
  71. package/src/server/responses/adapter-continuation.ts +9 -1
  72. package/src/server/responses/adapter-dispatch.ts +65 -6
  73. package/src/server/responses/compact.ts +3 -2
  74. package/src/server/responses/core-opaque-recovery.ts +5 -5
  75. package/src/server/responses/core.ts +6 -6
  76. package/src/server/responses/empty-completion-guard.ts +18 -2
  77. package/src/server/responses/jev-model-invoke.ts +1 -1
  78. package/src/server/responses/passthrough-dispatch.ts +115 -60
  79. package/src/server/responses/passthrough-execution.ts +3 -3
  80. package/src/server/responses/request-transport.ts +125 -5
  81. package/src/server/responses/run-turn-execution.ts +13 -5
  82. package/src/server/responses/sidecar-execution.ts +5 -0
  83. package/src/server/responses/spend-storage-error.ts +33 -0
  84. package/src/types/request.ts +5 -0
  85. package/src/usage/expected-prices.ts +1 -1
@@ -11,6 +11,7 @@
11
11
 
12
12
  import { jsonResponse } from "../auth-cors";
13
13
  import type { ManagementContext } from "./context";
14
+ import { ConfigMutationLockError } from "../../config/mutation-lock";
14
15
  import { isCodexResetCreditOperationId } from "../../codex/reset-credit-recovery";
15
16
  import { getValidAccessSnapshotForAccount } from "../../oauth";
16
17
  import { listAccounts, captureOAuthAccountSelection } from "../../oauth/store";
@@ -20,8 +21,12 @@ import {
20
21
  type GrokResetCoupon,
21
22
  } from "../../grok/reset-coupons";
22
23
  import {
24
+ getGrokResetCouponOperationAccountId,
25
+ markGrokResetCouponAttempt,
23
26
  openGrokResetCouponOperation,
24
27
  recordGrokResetCouponSettlement,
28
+ readGrokResetCouponTerminalReplay,
29
+ settleGrokResetCouponPreflightRefusal,
25
30
  type GrokResetCouponOperationRecord,
26
31
  } from "../../grok/reset-coupon-ledger";
27
32
 
@@ -41,6 +46,11 @@ export interface GrokConsumeCouponRequestBody {
41
46
  operationId?: string;
42
47
  }
43
48
 
49
+ // A recent attempt can still be in flight. Older attempts may be inspected,
50
+ // but a remaining token is not proof that the original request cannot land.
51
+ const GROK_COUPON_ATTEMPT_STALE_MS = 90_000;
52
+ const grokCouponInFlightAttempts = new Set<string>();
53
+
44
54
  function resolveTargetAccountId(requestedAccountId?: string): string {
45
55
  if (requestedAccountId && requestedAccountId.trim() !== "") {
46
56
  return requestedAccountId.trim();
@@ -130,6 +140,10 @@ export async function handleGrokCouponRoutes(ctx: ManagementContext): Promise<Re
130
140
 
131
141
  const { accountId: rawAccountId, tokenId: requestedTokenId, operationId } = body;
132
142
 
143
+ if (requestedTokenId !== undefined && (typeof requestedTokenId !== "string" || requestedTokenId.trim() === "")) {
144
+ return jsonResponse({ error: { code: "invalid_token_id", message: "tokenId must be a non-empty string" } }, 400, req, config);
145
+ }
146
+
133
147
  if (operationId !== undefined && !isCodexResetCreditOperationId(operationId)) {
134
148
  return jsonResponse(
135
149
  { error: { code: "invalid_operation_id", message: "operationId must be a valid UUIDv4" } },
@@ -139,9 +153,16 @@ export async function handleGrokCouponRoutes(ctx: ManagementContext): Promise<Re
139
153
  );
140
154
  }
141
155
 
156
+ let recordedAccountId: string | undefined;
157
+ if (rawAccountId === undefined && operationId !== undefined) {
158
+ try { recordedAccountId = getGrokResetCouponOperationAccountId(operationId); }
159
+ catch {
160
+ return jsonResponse({ error: { code: "ledger_unavailable", message: "Coupon ledger could not be read or locked; no redemption was attempted" } }, 503, req, config);
161
+ }
162
+ }
142
163
  let accountId: string;
143
164
  try {
144
- accountId = resolveTargetAccountId(rawAccountId);
165
+ accountId = resolveTargetAccountId(rawAccountId ?? recordedAccountId);
145
166
  } catch (err) {
146
167
  return jsonResponse(
147
168
  { error: { code: "no_account", message: err instanceof Error ? err.message : String(err) } },
@@ -165,26 +186,106 @@ export async function handleGrokCouponRoutes(ctx: ManagementContext): Promise<Re
165
186
 
166
187
  // Journaling and Idempotency settlement check
167
188
  const effectiveOpId = operationId ?? crypto.randomUUID();
168
- const opRecord = openGrokResetCouponOperation({
169
- accountId,
170
- tokenId: requestedTokenId,
171
- operationId: effectiveOpId,
172
- });
189
+ if (grokCouponInFlightAttempts.has(effectiveOpId)) return jsonResponse({ error: {
190
+ code: "attempt_in_progress", message: "This operation still has an active request; retry later",
191
+ } }, 409, req, config);
192
+ let opRecord: GrokResetCouponOperationRecord;
193
+ try {
194
+ opRecord = openGrokResetCouponOperation({ accountId, tokenId: requestedTokenId, operationId: effectiveOpId });
195
+ } catch {
196
+ return jsonResponse({ error: { code: "ledger_unavailable", message: "Coupon ledger could not be read or locked; no redemption was attempted" } }, 503, req, config);
197
+ }
198
+
199
+ let resolvedTokenId = requestedTokenId ?? opRecord.tokenId;
200
+ let resolvedTokenValidityEnd: number | undefined;
173
201
 
174
202
  if (opRecord.kind === "replay") {
175
- return jsonResponse(
176
- {
177
- code: opRecord.code,
178
- replayed: true,
179
- tokenId: opRecord.tokenId,
180
- settledAt: opRecord.settledAt,
181
- },
182
- 200,
183
- req,
184
- config,
185
- );
203
+ if (opRecord.code !== undefined) {
204
+ return jsonResponse(
205
+ {
206
+ code: opRecord.code,
207
+ replayed: true,
208
+ tokenId: opRecord.tokenId,
209
+ settledAt: opRecord.settledAt,
210
+ },
211
+ 200,
212
+ req,
213
+ config,
214
+ );
215
+ }
216
+ if (opRecord.tokenId === undefined) {
217
+ // Legacy opens may already have dispatched without recording a token.
218
+ return jsonResponse({ operationId: effectiveOpId, error: {
219
+ code: "attempt_unresolved", message: "The prior operation has no recorded token; preserve this operationId and do not create a replacement attempt",
220
+ } }, 409, req, config);
221
+ }
222
+ // "attempted" with no recorded outcome: the spend call fired (or the
223
+ // process died right after the mark) but nothing was settled. Never
224
+ // replay this as a success — reconcile against upstream instead. A
225
+ // Remaining-token availability cannot identify the original request's
226
+ // outcome, and a listed token cannot rule out delayed completion.
227
+ if (requestedTokenId !== undefined && requestedTokenId !== opRecord.tokenId) {
228
+ // The retry names a different coupon than the one marked: spending
229
+ // either of them would surprise the caller — refuse and let them
230
+ // retry with the recorded token and preserve the operationId.
231
+ return jsonResponse(
232
+ {
233
+ error: {
234
+ code: "operation_token_mismatch",
235
+ message: "Operation was attempted with a different coupon; preserve the operationId and retry with the recorded tokenId",
236
+ },
237
+ },
238
+ 409,
239
+ req,
240
+ config,
241
+ );
242
+ }
243
+ if (
244
+ opRecord.attemptedAt === undefined ||
245
+ Date.now() - opRecord.attemptedAt < GROK_COUPON_ATTEMPT_STALE_MS
246
+ ) {
247
+ // A fresh attempt may still be in flight in the original request —
248
+ // no additional upstream inspection is needed until that window ends.
249
+ // Older attempts are inspected without another redemption.
250
+ return jsonResponse(
251
+ { operationId: effectiveOpId,
252
+ error: {
253
+ code: "attempt_in_progress",
254
+ message: "A redemption attempt for this operation is recent and may still be running; retry later",
255
+ },
256
+ },
257
+ 409,
258
+ req,
259
+ config,
260
+ );
261
+ }
262
+ let remainingTokens: GrokResetCoupon[];
263
+ try {
264
+ const remaining = await getGrokRemainingResets({ accessToken: tokenSnapshot.accessToken });
265
+ remainingTokens = remaining.tokens;
266
+ } catch (err) {
267
+ return jsonResponse(
268
+ { operationId: effectiveOpId, error: { code: "attempt_reconcile_failed", message: err instanceof Error ? err.message : String(err) } },
269
+ 502,
270
+ req,
271
+ config,
272
+ );
273
+ }
274
+ // Availability cannot identify which request consumed a coupon. Even a
275
+ // missing, still-valid token does not confirm this operation succeeded.
276
+ const listed = remainingTokens.some((t) => t.tokenId === opRecord.tokenId);
277
+ return jsonResponse({ operationId: effectiveOpId, error: {
278
+ code: "attempt_unresolved",
279
+ message: listed
280
+ ? "The prior redemption may still complete; its listed coupon will not be redeemed again"
281
+ : "The coupon is no longer listed, but this operation's outcome is unconfirmed; no redemption will be repeated",
282
+ } }, 409, req, config);
186
283
  }
187
284
 
285
+ if (opRecord.kind === "token-mismatch") return jsonResponse({ error: {
286
+ code: "operation_token_mismatch", message: "Operation ID was previously registered with a different coupon",
287
+ } }, 409, req, config);
288
+
188
289
  if (opRecord.kind === "identity-mismatch") {
189
290
  return jsonResponse(
190
291
  {
@@ -213,16 +314,48 @@ export async function handleGrokCouponRoutes(ctx: ManagementContext): Promise<Re
213
314
  );
214
315
  }
215
316
 
216
- let resolvedTokenId = requestedTokenId;
217
- if (!resolvedTokenId) {
317
+ const settlePreflightRefusal = (code: string, tokenId?: string): Response | null => {
318
+ try {
319
+ const result = settleGrokResetCouponPreflightRefusal({
320
+ operationId: effectiveOpId, accountId, tokenId, code,
321
+ status: "failed", expectedStatus: "open",
322
+ });
323
+ if (result.kind === "recorded") return null;
324
+ if (result.kind === "replay") return jsonResponse({
325
+ code: result.code, replayed: true, tokenId: result.tokenId, settledAt: result.settledAt,
326
+ }, 200, req, config);
327
+ return jsonResponse({ error: {
328
+ code: "operation_state_changed",
329
+ message: "Another request changed this operation during inspection; retry the same operationId to read its durable state",
330
+ } }, 409, req, config);
331
+ } catch {
332
+ return jsonResponse({ error: {
333
+ code: "ledger_unavailable", message: "Coupon refusal could not be recorded; no redemption was attempted",
334
+ } }, 503, req, config);
335
+ }
336
+ };
337
+
338
+ {
339
+ // Always consult the upstream list: it resolves the token when the
340
+ // caller omits one, and — for an explicit tokenId — proves the coupon
341
+ // still exists. Captured validity remains journal metadata, never proof
342
+ // that this operation succeeded during a later reconciliation.
343
+ let tokens: GrokResetCoupon[];
218
344
  try {
219
345
  const remaining = await getGrokRemainingResets({ accessToken: tokenSnapshot.accessToken });
220
- if (!remaining.tokens || remaining.tokens.length === 0) {
221
- recordGrokResetCouponSettlement({
222
- operationId: effectiveOpId,
223
- code: "no_coupons_available",
224
- status: "failed",
225
- });
346
+ tokens = remaining.tokens ?? [];
347
+ } catch (err) {
348
+ return jsonResponse(
349
+ { error: { code: "fetch_resets_failed", message: err instanceof Error ? err.message : String(err) } },
350
+ 502,
351
+ req,
352
+ config,
353
+ );
354
+ }
355
+ if (!resolvedTokenId) {
356
+ if (tokens.length === 0) {
357
+ const changed = settlePreflightRefusal("no_coupons_available");
358
+ if (changed) return changed;
226
359
  return jsonResponse(
227
360
  { error: { code: "no_coupons_available", message: "No reset coupons available to redeem" } },
228
361
  400,
@@ -230,29 +363,131 @@ export async function handleGrokCouponRoutes(ctx: ManagementContext): Promise<Re
230
363
  config,
231
364
  );
232
365
  }
233
- resolvedTokenId = remaining.tokens[0].tokenId;
234
- } catch (err) {
366
+ resolvedTokenId = tokens[0].tokenId;
367
+ }
368
+ const match = tokens.find((t) => t.tokenId === resolvedTokenId);
369
+ if (!match) {
370
+ // The requested coupon is already consumed or expired upstream —
371
+ // redeeming it would only surface an upstream error.
372
+ const changed = settlePreflightRefusal("coupon_unavailable", resolvedTokenId);
373
+ if (changed) return changed;
235
374
  return jsonResponse(
236
- { error: { code: "fetch_resets_failed", message: err instanceof Error ? err.message : String(err) } },
237
- 502,
375
+ {
376
+ error: {
377
+ code: "coupon_unavailable",
378
+ message: "The requested reset coupon is no longer available upstream",
379
+ },
380
+ },
381
+ 409,
238
382
  req,
239
383
  config,
240
384
  );
241
385
  }
386
+ const parsedEnd = Date.parse(match.validityEnd);
387
+ if (!Number.isNaN(parsedEnd)) resolvedTokenValidityEnd = parsedEnd;
388
+ }
389
+
390
+ if (resolvedTokenId === undefined) {
391
+ // Unreachable: every path above either resolves a token or returns.
392
+ return jsonResponse(
393
+ { error: { code: "token_unresolved", message: "No reset coupon token could be resolved" } },
394
+ 500,
395
+ req,
396
+ config,
397
+ );
398
+ }
399
+
400
+ if (grokCouponInFlightAttempts.has(effectiveOpId)) {
401
+ // The original request holding this operation is still running in this
402
+ // process — its upstream spend has not concluded, so nothing may spend
403
+ // on this operationId again regardless of how stale the mark looks.
404
+ return jsonResponse(
405
+ {
406
+ error: {
407
+ code: "attempt_in_progress",
408
+ message: "A redemption attempt for this operation is still running; retry later",
409
+ },
410
+ },
411
+ 409,
412
+ req,
413
+ config,
414
+ );
242
415
  }
243
416
 
417
+ grokCouponInFlightAttempts.add(effectiveOpId);
244
418
  try {
245
- const redeemResult = await redeemGrokResetCoupon({
246
- accessToken: tokenSnapshot.accessToken,
247
- tokenId: resolvedTokenId,
248
- });
419
+ // Record the attempt BEFORE the spend call: a crash between redemption
420
+ // and settlement must still leave the operation non-open so a retry can
421
+ // never execute it again. The atomic claim admits exactly one contender;
422
+ // a failed mark write aborts here while nothing has been spent.
423
+ try {
424
+ const claimed = markGrokResetCouponAttempt(effectiveOpId, resolvedTokenId, undefined, undefined, resolvedTokenValidityEnd);
425
+ if (!claimed) {
426
+ // A concurrent request may already have reached a definitive outcome;
427
+ // replay it rather than holding the caller on a finished operation.
428
+ // A failed read proves nothing about the winner, so it stays uncertain:
429
+ // reporting a definitive error here would let the caller open a
430
+ // replacement operation while this one may already have spent.
431
+ let winner: ReturnType<typeof readGrokResetCouponTerminalReplay> = null;
432
+ try { winner = readGrokResetCouponTerminalReplay(effectiveOpId, accountId, resolvedTokenId); } catch { winner = null; }
433
+ if (winner) return jsonResponse({
434
+ code: winner.code, replayed: true, tokenId: winner.tokenId, settledAt: winner.settledAt,
435
+ }, 200, req, config);
436
+ return jsonResponse({ error: {
437
+ code: "attempt_in_progress", message: "Another request already claimed this operation; no redemption was attempted",
438
+ } }, 409, req, config);
439
+ }
440
+ } catch (err) {
441
+ return jsonResponse(
442
+ { error: { code: "attempt_mark_failed", message: err instanceof Error ? err.message : String(err) } },
443
+ 500,
444
+ req,
445
+ config,
446
+ );
447
+ }
249
448
 
250
- recordGrokResetCouponSettlement({
251
- operationId: effectiveOpId,
252
- tokenId: resolvedTokenId,
253
- code: "redeemed",
254
- status: "success",
255
- });
449
+ try {
450
+ await redeemGrokResetCoupon({
451
+ accessToken: tokenSnapshot.accessToken,
452
+ tokenId: resolvedTokenId,
453
+ });
454
+ } catch (err) {
455
+ // A transport error cannot prove that the irreversible request failed.
456
+ // Keep "attempted" so a later retry can inspect without dispatching again.
457
+ return jsonResponse(
458
+ { operationId: effectiveOpId, accountId, tokenId: resolvedTokenId, error: {
459
+ code: "attempt_unresolved",
460
+ message: "Redemption delivery is unconfirmed; reuse this operationId to inspect its state and do not create a replacement attempt",
461
+ } },
462
+ 502,
463
+ req,
464
+ config,
465
+ );
466
+ }
467
+
468
+ // A confirmed redemption remains successful even when settlement fails.
469
+ // The existing claim protects retries if settlement does not land.
470
+ let settlementRecorded = false;
471
+ for (let attempt = 0; attempt < 5; attempt += 1) {
472
+ try {
473
+ settlementRecorded = recordGrokResetCouponSettlement({
474
+ operationId: effectiveOpId,
475
+ accountId,
476
+ tokenId: resolvedTokenId,
477
+ code: "redeemed",
478
+ status: "success",
479
+ expectedStatus: "attempted",
480
+ });
481
+ break;
482
+ } catch (error) {
483
+ // Retry only transient acquisition contention, never an unsafe or
484
+ // unreadable ledger, a changed claim, or the upstream redemption.
485
+ const cause = error instanceof ConfigMutationLockError ? error.cause : undefined;
486
+ if (!cause || typeof cause !== "object" || !("code" in cause)
487
+ || cause.code !== "SQLITE_BUSY" || attempt === 4) break;
488
+ await Bun.sleep(20);
489
+ }
490
+ }
256
491
 
257
492
  return jsonResponse(
258
493
  {
@@ -262,24 +497,14 @@ export async function handleGrokCouponRoutes(ctx: ManagementContext): Promise<Re
262
497
  tokenId: resolvedTokenId,
263
498
  accountId,
264
499
  operationId: effectiveOpId,
500
+ settlementRecorded,
265
501
  },
266
502
  200,
267
503
  req,
268
504
  config,
269
505
  );
270
- } catch (err) {
271
- recordGrokResetCouponSettlement({
272
- operationId: effectiveOpId,
273
- tokenId: resolvedTokenId,
274
- code: "redeem_failed",
275
- status: "failed",
276
- });
277
- return jsonResponse(
278
- { error: { code: "redeem_failed", message: err instanceof Error ? err.message : String(err) } },
279
- 502,
280
- req,
281
- config,
282
- );
506
+ } finally {
507
+ grokCouponInFlightAttempts.delete(effectiveOpId);
283
508
  }
284
509
  }
285
510
 
@@ -14,6 +14,7 @@ import { projectLinkStatus, type LinkStatusDto } from "../../link/status-project
14
14
  import { isLinkPort } from "../../link/ports";
15
15
  import { joinHome, type ClientLinkJoinDeps } from "../../client/link-join";
16
16
  import { clientLinkTunnelStatus } from "../../client/link-tunnel";
17
+ import { withConfigMutationLockSync } from "../../config/mutation-lock";
17
18
  import type { ManagementContext } from "./context";
18
19
  import { readManagementJsonBodyOr } from "./body";
19
20
  import { issueApiKeyInProcess, revokeApiKeyInProcess, type IssuedApiKey } from "./oauth-account-routes";
@@ -228,10 +229,12 @@ async function compensateNewLink(ctx: ManagementContext, state: LinkRouteState,
228
229
  if (!revoked) {
229
230
  try { await state.supervisor.stopLink(record.id); } catch { /* retain the record and failure marker */ }
230
231
  try {
231
- const current = readStoreFor(ctx);
232
- if (!current.links.some(link => link.id === record.id)) {
233
- writeStoreFor(ctx, { ...current, links: [...current.links, record] });
234
- }
232
+ withConfigMutationLockSync(() => {
233
+ const current = readStoreFor(ctx);
234
+ if (!current.links.some(link => link.id === record.id)) {
235
+ writeStoreFor(ctx, { ...current, links: [...current.links, record] });
236
+ }
237
+ });
235
238
  } catch {
236
239
  // The in-memory marker still makes the residual visible when persistence is unavailable.
237
240
  }
@@ -239,11 +242,16 @@ async function compensateNewLink(ctx: ManagementContext, state: LinkRouteState,
239
242
  }
240
243
  try { await state.supervisor.stopLink(record.id); } catch { return compensationFailure(ctx, state, record, "stop"); }
241
244
  try {
242
- const current = readStoreFor(ctx);
243
- const next = { ...current, links: current.links.filter(link => link.id !== record.id) };
244
- if (next.links.length !== current.links.length) {
245
- writeStoreFor(ctx, next);
246
- }
245
+ // Read→filter→write stays one section of the shared mutation lock: a sibling
246
+ // route's create must not land between the read and the rename and vanish.
247
+ const next = withConfigMutationLockSync(() => {
248
+ const current = readStoreFor(ctx);
249
+ const filtered = { ...current, links: current.links.filter(link => link.id !== record.id) };
250
+ if (filtered.links.length !== current.links.length) {
251
+ writeStoreFor(ctx, filtered);
252
+ }
253
+ return filtered;
254
+ });
247
255
  clearCompensationFailed(record.id, compensationPath());
248
256
  state.compensationFailures?.delete(record.id);
249
257
  if (next.links.length === 0) await state.listener.close();
@@ -362,14 +370,20 @@ async function apply(ctx: ManagementContext, state: LinkRouteState): Promise<Res
362
370
  const record = { id, alias: body.alias, direction: "hub-initiated" as const, hostKeyFingerprint: confirmed.fingerprint, tunnelPort: remotePort, apiKeyId: issued.id, createdAt: new Date((ctx.deps.now ?? Date.now)()).toISOString() };
363
371
  let store: LinkStore;
364
372
  try {
365
- const current = readStoreFor(ctx);
366
- if (current.links.some(link => link.alias === body.alias && link.direction === "hub-initiated")) {
373
+ // Duplicate-check and append under one mutation-lock section: two writers
374
+ // racing this check could otherwise both pass it and append, losing one link.
375
+ const writeOutcome = withConfigMutationLockSync((): "dup" | "written" => {
376
+ const current = readStoreFor(ctx);
377
+ if (current.links.some(link => link.alias === body.alias && link.direction === "hub-initiated")) return "dup";
378
+ store = { ...current, links: [...current.links, record] };
379
+ writeStoreFor(ctx, store);
380
+ return "written";
381
+ });
382
+ if (writeOutcome === "dup") {
367
383
  const compensation = await compensateNewLink(ctx, state, record);
368
384
  if (compensation) return compensation;
369
385
  return fail("link_exists", "A link for this alias already exists.", 409);
370
386
  }
371
- store = { ...current, links: [...current.links, record] };
372
- writeStoreFor(ctx, store);
373
387
  await state.listener.ensureStarted();
374
388
  if (state.listener.status().state !== "listening") {
375
389
  const compensation = await compensateNewLink(ctx, state, record);
@@ -430,13 +444,18 @@ async function issue(ctx: ManagementContext): Promise<Response> {
430
444
  const record = { id, alias: body.alias, direction: "client-initiated" as const, hostKeyFingerprint: null, tunnelPort: body.tunnelPort, apiKeyId: issued.id, createdAt: new Date((ctx.deps.now ?? Date.now)()).toISOString() };
431
445
  let failureCode = "link_issue_failed";
432
446
  try {
433
- const current = readStoreFor(ctx);
434
- if (current.links.some(link => link.id === id)) throw new Error("link id collision");
435
- if (current.links.some(link => link.alias === body.alias && link.direction === "client-initiated")) {
447
+ // Same atomic duplicate-check+append as the hub-initiated branch.
448
+ const writeOutcome = withConfigMutationLockSync((): "dup" | "written" => {
449
+ const current = readStoreFor(ctx);
450
+ if (current.links.some(link => link.id === id)) throw new Error("link id collision");
451
+ if (current.links.some(link => link.alias === body.alias && link.direction === "client-initiated")) return "dup";
452
+ writeStoreFor(ctx, { ...current, links: [...current.links, record] });
453
+ return "written";
454
+ });
455
+ if (writeOutcome === "dup") {
436
456
  const compensation = await compensateNewLink(ctx, state, record);
437
457
  return compensation ?? fail("link_exists", "A link for this alias already exists.", 409);
438
458
  }
439
- writeStoreFor(ctx, { ...current, links: [...current.links, record] });
440
459
  await state.listener.ensureStarted();
441
460
  if (state.listener.status().state !== "listening") {
442
461
  failureCode = "listener_unavailable";
@@ -538,9 +557,12 @@ async function remove(ctx: ManagementContext, state: LinkRouteState, id: string)
538
557
  if (!revokeKeyIdempotent(ctx, record.apiKeyId)) return fail("key_revoke_failed", "The link key could not be revoked.", 502);
539
558
  let next: LinkStore;
540
559
  try {
541
- const latest = readStoreFor(ctx);
542
- next = { ...latest, links: latest.links.filter(link => link.id !== id) };
543
- if (next.links.length !== latest.links.length) writeStoreFor(ctx, next);
560
+ next = withConfigMutationLockSync(() => {
561
+ const latest = readStoreFor(ctx);
562
+ const filtered = { ...latest, links: latest.links.filter(link => link.id !== id) };
563
+ if (filtered.links.length !== latest.links.length) writeStoreFor(ctx, filtered);
564
+ return filtered;
565
+ });
544
566
  clearCompensationFailed(id, compensationPath());
545
567
  } catch { return fail("link_remove_failed", "The link record could not be removed.", 503); }
546
568
  state.compensationFailures?.delete(id);
@@ -361,8 +361,8 @@ export const MANAGEMENT_ROUTES: readonly ManagementRoute[] = [
361
361
  { method: "GET", path: "/api/protocols", module: "server/management/protocol-routes", mutates: false },
362
362
  { method: "POST", path: "/api/protocols/plan", module: "server/management/protocol-routes", mutates: false },
363
363
  { method: "PATCH", path: "/api/protocols/settings", module: "server/management/protocol-routes", mutates: true },
364
- { method: "GET", path: "/api/workflow-budget", module: "server/management/workflow-budget-routes", mutates: false, exempt: { reason: "deferred-verb", why: "Reading a root's live budget is owed a CLI verb -- an operator staring at a 429 is usually already in a terminal -- but the ledger is process memory with no local transport to read it through, so the verb has to be an HTTP call the CLI does not yet make.", owner: "260915_workflow_budget_window wfc", ownerDoc: "devlog/_plan/260915_workflow_budget_window/030_wfc_diff_plan.md" } },
365
- { method: "POST", path: "/api/workflow-budget/clear", module: "server/management/workflow-budget-routes", mutates: true, exempt: { reason: "deferred-verb", why: "Clearing one root is owed the same verb as the read above and for the same reason. It is deliberately not shipped as a verb in this work-phase: the read comes first, because an operator who cannot see which ceiling fired has no basis for deciding to forgive it.", owner: "260915_workflow_budget_window wfc", ownerDoc: "devlog/_plan/260915_workflow_budget_window/030_wfc_diff_plan.md" } },
364
+ { method: "GET", path: "/api/workflow-budget", module: "server/management/workflow-budget-routes", mutates: false, exempt: { reason: "deferred-verb", why: "Reading a root's live budget is owed a CLI verb -- an operator staring at a 429 is usually already in a terminal -- but the ledger is process memory with no local transport to read it through, so the verb has to be an HTTP call the CLI does not yet make.", owner: "260915_workflow_budget_window wfc", ownerDoc: "devlog/_fin/260915_workflow_budget_window/030_wfc_diff_plan.md" } },
365
+ { method: "POST", path: "/api/workflow-budget/clear", module: "server/management/workflow-budget-routes", mutates: true, exempt: { reason: "deferred-verb", why: "Clearing one root is owed the same verb as the read above and for the same reason. It is deliberately not shipped as a verb in this work-phase: the read comes first, because an operator who cannot see which ceiling fired has no basis for deciding to forgive it.", owner: "260915_workflow_budget_window wfc", ownerDoc: "devlog/_fin/260915_workflow_budget_window/030_wfc_diff_plan.md" } },
366
366
  // server/management/request-history-routes
367
367
  { method: "GET", path: "/api/request-history", module: "server/management/request-history-routes", mutates: false },
368
368
  // server/management/routing-analytics-routes
@@ -338,6 +338,8 @@ export function relaySseEagerBounded(
338
338
  upstreamError,
339
339
  terminalBoundary.upstreamRefusalCode(),
340
340
  opts?.maskCredential,
341
+ terminalBoundary.upstreamErrorType(),
342
+ terminalBoundary.upstreamErrorCode(),
341
343
  );
342
344
  queuedBytes += upstreamErrorFrame.byteLength + terminalSentinel.byteLength;
343
345
  try {
@@ -6,13 +6,14 @@ import {
6
6
  isCyberPolicyCode,
7
7
  isCyberPolicyMessage,
8
8
  isTerminalRefusalCode,
9
+ recognizedUpstreamError,
9
10
  safetyRefusalCodeFromMessage,
10
11
  terminalRefusalFallbackMessage,
11
12
  upstreamErrorMessageFromPayload,
12
13
  } from "../lib/errors";
13
14
  import { redactSecretString } from "../lib/redact";
14
15
  import { isTranslatorBudgetExceededError } from "../lib/translator-budget";
15
- import { carryReplayRefusal } from "../lib/upstream-retry";
16
+ import { carryReplayRefusal, isReplayRefusalResponse } from "../lib/upstream-retry";
16
17
  import { isUsageDebugEnabled } from "../usage/debug";
17
18
  import {
18
19
  addRequestLog,
@@ -168,25 +169,28 @@ export function failedTailFrame(encoder: TextEncoder, err: unknown, maskCredenti
168
169
  * classifies this terminal by `error.code` alone and retries everything outside
169
170
  * its fatal set (codex-rs/codex-api/src/sse/responses.rs:423-450), so stamping
170
171
  * `upstream_server_error` on a refusal delivered it as a retryable disconnect
171
- * and drove the reconnect loop in #5176. Without a refusal code the terminal is
172
- * unchanged: a genuine transport failure stays retryable, which is what it is.
172
+ * and drove the reconnect loop in #5176. Without a refusal code the terminal
173
+ * carries only recognized rate-limit/overload classes; unknown codes stay generic.
173
174
  */
174
175
  export function upstreamErrorTailFrame(
175
176
  encoder: TextEncoder,
176
177
  message: string,
177
178
  refusalCode?: string,
178
179
  maskCredential?: (text: string) => string,
180
+ errorType?: string,
181
+ errorCode?: string,
179
182
  ): Uint8Array {
180
183
  return encoder.encode(
181
- `event: response.failed\ndata: ${upstreamErrorFailedPayload(message, refusalCode, maskCredential)}\n\n`,
184
+ `event: response.failed\ndata: ${upstreamErrorFailedPayload(message, refusalCode, maskCredential, errorType, errorCode)}\n\n`,
182
185
  );
183
186
  }
184
187
 
185
- function upstreamErrorFailedPayload(message: string, refusalCode?: string, maskCredential?: (text: string) => string): string {
188
+ function upstreamErrorFailedPayload(message: string, refusalCode?: string, maskCredential?: (text: string) => string, errorType?: string, errorCode?: string): string {
186
189
  const diagnostic = redactSecretString(message);
190
+ const recognized = recognizedUpstreamError({ type: errorType, code: errorCode });
187
191
  const error = {
188
- type: refusalCode === undefined ? "upstream_error" : "invalid_request_error",
189
- code: refusalCode === undefined ? "upstream_server_error" : (maskCredential?.(refusalCode) ?? refusalCode),
192
+ type: refusalCode === undefined ? (recognized?.type ?? "upstream_error") : "invalid_request_error",
193
+ code: refusalCode === undefined ? (recognized?.code ?? "upstream_server_error") : (maskCredential?.(refusalCode) ?? refusalCode),
190
194
  message: (maskCredential?.(diagnostic) ?? diagnostic).slice(0, MAX_TAIL_ERROR_MESSAGE_CHARS),
191
195
  };
192
196
  return JSON.stringify({
@@ -549,6 +553,8 @@ export function relaySseWithFailedTail(
549
553
  upstreamError,
550
554
  terminalBoundary.upstreamRefusalCode(),
551
555
  opts?.maskCredential,
556
+ terminalBoundary.upstreamErrorType(),
557
+ terminalBoundary.upstreamErrorCode(),
552
558
  ));
553
559
  controller.enqueue(doneFrame(encoder));
554
560
  }
@@ -898,6 +904,11 @@ export function responseWithDeferredRequestLog(
898
904
  logCtx: RequestLogContext,
899
905
  addLog: (entry: RequestLogEntry) => void = addRequestLog,
900
906
  ): Response {
907
+ // A synthetic 429 is a transport verdict, not evidence that the provider declined the turn.
908
+ if (isReplayRefusalResponse(response)) {
909
+ logCtx.causeHint = "transport-ambiguous";
910
+ logCtx.terminalSource = "synthetic";
911
+ }
901
912
  const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
902
913
  if (isUsageDebugEnabled() && !logCtx.usageDebugContentType && contentType) {
903
914
  logCtx.usageDebugContentType = contentType;
@@ -21,6 +21,8 @@ export interface FinalRequestAttributionFacts {
21
21
  readonly closeReason?: "terminal" | "client_cancel" | "non_stream" | "body_stall" | "body_overflow" | undefined;
22
22
  readonly transportPhase?: "pre_headers" | "mid_stream" | "terminal_sse" | undefined;
23
23
  readonly terminalSource?: "upstream" | "synthetic" | undefined;
24
+ /** A failure cause proved by the transport's in-process verdict. */
25
+ readonly causeHint?: RequestFailureCause | undefined;
24
26
  /** The REQUEST's first-output observation, not the final attempt's. See below. */
25
27
  readonly outputObserved: boolean;
26
28
  readonly locallyAnswered: boolean;
@@ -53,6 +55,7 @@ export function attributeFinalRequest(facts: FinalRequestAttributionFacts): Stam
53
55
  ...(facts.closeReason ? { closeReason: facts.closeReason } : {}),
54
56
  ...(facts.transportPhase ? { transportPhase: facts.transportPhase } : {}),
55
57
  ...(facts.terminalSource ? { terminalSource: facts.terminalSource } : {}),
58
+ ...(facts.causeHint ? { causeHint: facts.causeHint } : {}),
56
59
  ...(facts.attempt?.streamAborted === true ? { streamAborted: true } : {}),
57
60
  outputObserved: facts.outputObserved,
58
61
  // The one fact that can raise a stage above `semantic-output`, and the reason it is counted