[WRONG BRANCH] release: promote verified 2.52.0-preview.20260911 product tree to preview - #4273
Conversation
… the account short slot The response-header quota path had no model context, so on a Spark-model response the upstream model-specific 5h limit (codex_bengalfox) was stored as the account-level shortPercent tuple. One pool account then displayed a 5h quota bar its identically-limited Pro peers did not have, and account-policy readers (main-account hard lock, five-hour auto-refresh) consumed a model-specific window. parseUpstreamQuotaHeaders and applyAccountQuotaFromUpstreamHeaders now take an optional routed-model hint; on Spark-family models the sub-day primary window is filed under customWindows with the same label the WHAM parser uses, merged label-wise so the WHAM-recorded Spark weekly window survives (#4007 retention intact). All HTTP and WebSocket header write paths pass route.modelId. Genuine account-level 5h windows on non-Spark models are unchanged, and warmup callers (non-Spark default models) keep legacy behavior. Regression coverage in tests/codex-integration/codex-quota-parser-parity.test.ts. Closes #4122
fix(codex): attribute Spark 5h header windows to the model limit, not the account short slot
The 260909_spark_short_quota_attribution unit was committed into the product PR #4128 instead of being kept out of it. That PR merged (b214258, merge commit 91db6c2) and issue #4122 closed, so the unit is terminal and belongs in _fin per the devlog convention in AGENTS.md: _plan holds units still open, _fin holds units with a recorded terminal outcome. Adds 090_closeout.md with the merged SHAs, the exact-head CI result, and the two consequences the plan already declared out of scope (stale cached short* tuples expiring via the six-hour hydration TTL, and Spark-routed requests no longer preemptively avoiding a Spark-saturated account). Docs only. No file under src/, tests/, gui/, or scripts/ is touched.
SECURITY.md described how to file a report but not what to do after one is filed and quiet. Reporters had no stated route for a stalled private thread, no statement of what a public issue may contain in that situation, and no way to tell an acknowledgment apart from completed triage. Adds a public-or-private routing test, a follow-up section that keeps coordination in the private advisory thread and limits a public issue to coordination with no vulnerability detail or advisory identifiers, and an explicit statement that receipt is not triage and that a landed public patch does not close the corresponding private report. States plainly that no first-response target is published; review stays best-effort. README's security pointer carries the same three facts. Closes #4073
The new paragraph claimed the 90-second prelude deadline is not configurable through connectTimeoutMs. The constant is not tunable, but the effective wait is: core.ts passes connectTimeoutMs (default 200s) as the header-timeout budget to fetchWithHeaderTimeout, which aborts the combined signal the WS exchange runs under, and codex-ws-exchange.ts cancels an already-sent create on that abort before the prelude timer fires. An operator who lowers connectTimeoutMs below 90 seconds keeps the shorter deadline, so state it as the shorter of the two. Addresses the Codex review finding on this PR.
…ance fix(codex): report operator-owned root routing truthfully
…tches A live Codex thread switched from a native ChatGPT model to a routed provider replays the backend-minted encrypted agent message on every later turn. That turn is not a thread spawn, so the direct recovery gate skipped it and the thread was permanently unusable on that provider, with no recovery attempt and no recovery_reason on the error. Drop the threadSpawn conjunct from the direct gate only. The trust boundary is recoveryAdmission() -- Codex originator, live native ChatGPT bearer, matching chatgpt-account-id, no inbound API key -- which is unchanged. The cache restore lives inside the same if, so a mid-thread turn can now reuse a plaintext this proxy already paid for. The combo gate keeps its spawn requirement. Closes #4089
…e visibility The first draft said a defect 'plainly visible in code that is already published' could go to a public issue. opencodex is source-available, so that reading covers nearly every finding, and it contradicted the same file's rule that undisclosed vulnerabilities never start as public issues. The test is now whether the weakness is already public — fix shipped, or already described in a published advisory, issue, or pull request — with an explicit statement that being findable in the source is not disclosure.
Docs-only devlog move. Exact-head CI at e3a4f0a: 12 success, 10 skipped by path filters, only the CodeRabbit review bot outstanding. Merged by the maintainer under the dev integration policy in MAINTAINERS.md.
The proxy has stamped a stable non-PII account label on every request row and every attempt for a long time (main, p<hex6> for Codex pool accounts, o<hex6> for other OAuth providers), but nothing could read it back. An operator running several accounts behind one provider had to grep usage.jsonl to answer "which account served this request", which is the first diagnostic question for a quota or cache anomaly. /api/logs now accepts ?account=<label>, matching failover attempts the same way ?provider and ?model already do, so a request is findable by the account that finally served it as well as the one that first refused it. ocx logs gains the matching --account flag and prints acct=<label> in human output, so a filtered result can be told apart from an empty one. No new field is persisted and no new identifier is derived: this reads back the label already written by sealRequestAttemptIdentity. Closes #4057
…ing MissingSessionID OpenCode closed the keyless Zen tier to its own client. A request without an x-opencode-session header is refused with error type MissingSessionID and "OpenCode's free tier can only be used in OpenCode", so every opencode-free request now fails and the user saw that raw upstream string with no indication of what happened or what to do instead. Presence of the header is the entire gate, so the proxy could pass it by minting a value. It does not: a fabricated session id plus a versioned opencode/<version> User-Agent is a claim to be the OpenCode client, and OpenCode publishes no third-party integration contract for this keyless tier, so a 200 obtained that way is a bypassed admission check rather than permission. Report the restriction instead. The Zen guidance module gains a free-tier enrichment that replaces the passthrough with the reason and the supported keyed opencode-zen route. It is scoped to Zen destinations and to this error, and is idempotent so layered enrichment cannot append it twice. Wired on both surfaces that render upstream errors: the native Chat path, where the issue reproduces, and the Responses path, whose existing single call site now goes through a composed entry point that leaves the 429 guidance unchanged. The opencode-free registry note and the providers guide document the gate, the refusal to impersonate, and the keyed alternative. Closes #4121
MAX_DECOMPRESSED_BODY_BYTES was hard-coded at 256 MiB, and on the 922k-token opt-in window a session's serialized history crosses it. The request that crosses it is Codex's own remote-compaction request, so the session 413s on the one operation that would have shrunk it and cannot recover. Adds the opt-in `maxInboundBodyBytes`, shaped like `maxUpstreamBodyBytes`: omitted or 0 keeps today's 256 MiB. Every reader resolves through resolveInboundBodyLimitBytes(), which clamps to [1 MiB, 512 MiB]. The ceiling is mandatory rather than advisory: readBoundedJsonRequestBody materializes the body several times over, so peak memory is a multiple of whatever is admitted and an unbounded inbound cap would be a memory exhaustion lever. The schema keeps the outbound guard's `.catch(undefined)` degradation, which is exactly why the bound cannot live there. Bun's listener rejects an oversized body before fetch() runs, so maxRequestBodySize is now resolved from config at bind time instead of being pinned to the default; an out-of-range value is clamped with one startup warning. Also separates the two 413s a client can now see on this surface. #4112 gives an upstream size refusal `context_length_exceeded`; a local admission refusal now answers `inbound_body_too_large` with a message that names OpenCodex as the refuser, the observed and configured sizes, and the config key that moves the limit. The diagnostic inherits the thrown error's rule about keeping non-finite and untyped values out of the text.
The reference page and the sub-agent surface guide framed agentTaskRecovery as spawn-only. It now also covers a live thread switched from a native ChatGPT model to a routed one. Combo recovery is still spawn-only, so say that explicitly in each locale rather than leaving the distinction implicit.
…sal shape Bun answers 413 and stops reading while the client is still uploading, so the write side can surface the refusal as a transport error rather than a response. Accept either shape for the refusal, and pair it with the admitted case at the same body size so the assertion stays non-vacuous: the old listener, pinned to MAX_DECOMPRESSED_BODY_BYTES, admitted this body under every configuration.
… locales The English providers guide now says the keyless tier is closed, while ko, ja, zh-cn, zh-tw, fr, ru and tr still told readers it works without a key. Each locale gets the same two paragraphs in its own register, keeping the identifiers, the quoted upstream message and both URLs verbatim.
…he rendered page `skills/ocx/references/01_management_surface.md` is generated from `CAPABILITIES` in `src/cli/capabilities.ts`, and `tests/ci-workflows/skill-ocx.test.ts` compares the committed file against a fresh render byte for byte. The previous commit edited the rendered page by hand, so the two disagreed. Declare the flag at its source instead: the logs capability now carries `--account` between `--conversation` and `--status`, its summary names the new filter, and a detail line documents the `acct=<label>` column next to the existing `conv=<id>` one. The rendered page is unchanged from the previous commit apart from that detail line, which is what the registry now emits.
…m, and guard fallback
…grant A Codex pool credential whose OAuth grant was revoked upstream kept lastCodexValidationStatus: "ok" in codex-accounts.json and was reported as healthy for as long as the install lived, while every request using it 401'd. guardianSweep's pool branch already classified the failure -- it computed `permanent` for a revoked/expired TokenRefreshError -- but spent it only on widening an in-memory backoff delay. The persisted-verdict branch next to it required `needsWarmup`, which is false in the default configuration, and additionally excluded every TokenRefreshError, so the one class of failure that proves the credential is dead was the one class that never reached the record. Persist that verdict instead, independently of needsWarmup, and add a lastCodexValidationTerminal marker so a dead grant is distinguishable from a transient warmup failure. The write is fenced on the generation the sweep actually observed, so a credential replaced mid-refresh is never branded by the previous credential's failure. The marker clears itself in both directions that disprove it: markCodexAccountValidated clears it explicitly, and every credential write drops it because the record is rebuilt from preservedValidationMetadata, which deliberately omits it. A refresh that succeeds disproves "the grant was revoked", so one spurious invalid_grant cannot brand a live account dead forever. On the read side, projectCodexAccountHealth now reads that verdict and reports reauth_required/refresh_failed -- the accurate statement, since only a re-login recovers a revoked grant, and the existing union member already carries the Codex reauth action. collectLocalCodexEntries is folded onto the same projector rather than keeping its inlined copy, which is how the CLI would otherwise have kept reporting the account healthy after the dashboard stopped. Background warmup stays opt-in; no default-on probe is introduced. Closes #4120
Diff-level roadmap for the three-layer chain (#4120 -> #3848 -> #3777), with the wp1 design decisions recorded: why the terminal marker is an extra optional key rather than a new status value, why it clears itself on every credential write, why the generation fence declines rather than clobbers, and why the dashboard fix is a server-side projection onto the existing reauth_required member.
fix(responses): classify non-streaming provider input overflow
CodeRabbit flagged that the ja and zh-cn pages disagreed about when combo recovery runs. The runtime has two triggers: no payload-eligible target is initially selectable (core.ts:2753), and native attempts are exhausted with no eligible target left (core.ts:3054-3060). The English reference page named only the first, while the sub-agent surface guide and the fr/zh pages named both, so the English page and the ja/ko/tr/ru pages were the ones out of step.
…up-4073 Closes #4073. Exact-head CI at cf967c3: Cross-platform CI success, enforce-target success x3, PR hygiene success x2, PR Labeler success x2, React Doctor success; the two cancelled runs are superseded duplicates at the same SHA and only the CodeRabbit review bot is outstanding. Documentation only: SECURITY.md plus locale mirrors, no response SLA published. Merged by the maintainer under the dev integration policy in MAINTAINERS.md.
…ntact around the bridge
fix(responses): allow 90 seconds for Codex WebSocket response prelude
…-envelope fix(google): restore AI Studio model discovery
…an unselectable one CodeRabbit review on #4257: the exempt default must survive only when the surviving ladder advertises it; an orphaned ultra default is repaired down without naming the rung in the clamp diagnostic. Also folds the three doc-coherence findings into the devlog unit and docs-site.
fix(codex): emit max/ultra efforts unconditionally and expire stale clamp diagnostics
The Responses preset shipped a two-model roster read off the models.json sample on BigModel's Codex page. That sample is a starter catalog, not the endpoint's roster, and taking it for the latter left Flash off a subscription that sells it. Three upstream pages disagree with the old reading, all checked 2026-09-11: - coding-plan/latest-model.md pins Codex to https://open.bigmodel.cn/api/v1 -- this preset's exact baseUrl -- and states GLM Coding Plan supports GLM-5.3 and GLM-5.3-Flash for every tier, then treats glm-5.3-flash as an already-callable id in that tool. - coding-plan/overview.md states GLM-5-Turbo calls are auto-switched to GLM-5.3-Flash. The preset already lists glm-5-turbo, so it was already reaching Flash on this endpoint under another name. - guide/models/vlm/glm-5.3-flash.md gives native multimodal input, a 1M window, and text parameters "consistent with GLM-5.3". Flash is seeded into the roster and all five sibling per-model maps. Its context tracks the 5.3 sibling on this row (1_048_576) rather than the Chat row's 1_000_000: both are documented as "1M", and this preset expresses that family's 1M the way BigModel's own Codex declaration does, so one preset does not claim two sizes for one documented window. Flash declares ["text", "image"]. It is the only row here that can actually see an image; the other two are text-only upstream and get image back from the vision sidecar at catalog-build time. Declaring Flash text-only would push a native VLM's pictures through a describe-it-first detour and hand the model prose about an image it could have read -- the defect ZAI_GLM_5X_SIDECAR_VISION_MODELS already exists to prevent on the Chat rows. The oracle moves in this same commit, because a test asserting the old roster is not evidence for the new one, it is the thing being changed. It previously locked models to two entries and asserted glm-5.3-flash was absent from the export. It now pins the three-model contract, Flash's exported window, ladder (low/high/max plus the compatibility ultra tier), default effort and native image modality, and keeps asserting the part no document supports: there is still no HTTP /models contract here, so liveModels and apiKeyValidation must not drift. Closes #4201
… describes The preset now seeds glm-5.3-flash, and both pages still said it did not. The guide went further and told the reader why it was excluded, which stops being staleness and becomes a false statement the moment this lands. The modality note is split rather than rewritten: 5.3 and Turbo still reach images through the vision sidecar, while Flash declares native text and image input, so the page should not describe one mechanism for all three rows.
provider: seed GLM-5.3-Flash on the BigModel Responses preset
Two surfaces changed because one pooled account stopped being usable, and neither said so. The reporter in #4212 lost astra and sol through the proxy, found the proxy worked with ocx turned off, and concluded OpenCodex had broken. The real cause was a single account stuck on a failed credential refresh, which they eventually found themselves and then asked to be told about. The request-time refusal now names the account. refreshPoolForwardAuth and refreshPoolCompactContext both caught a non-terminal refresh failure and returned "Codex credential refresh did not complete; retry this request", which describes a transient server problem. It stays a retryable 503 and stays non-quarantining, because the refresh genuinely may succeed and a token-endpoint 5xx must not retire a healthy account (#2887). What it gains is the account and the exit: when retrying stops helping, that account has to be signed in again. The two call sites now share one helper, so the regular and compact contracts on this endpoint cannot drift the way they already had -- compact takes no RouteResult and so could not reach the public selector at all until its caller started passing it. The refusal says "sign in to that account again" rather than the more natural "needs reauthentication", and that is load-bearing. classifyError runs isAuthenticationMessage before it reaches the status === 503 arm, and that check is status-blind on the bare substring "authentication", which "reauthentication" contains. The friendlier wording reclassifies the body to authentication_error / invalid_api_key while the HTTP status stays 503, and Codex applies retry-after backoff only for server_is_overloaded -- so it would have quietly disabled the retry this refusal exists to ask for. A test pins the wording, not just the resulting code, because the next person to improve this sentence will not know. The name is a public account selector when the request carried one, otherwise the durable p-prefixed log label. Never the raw pool id and never the email: those are the identifiers responses-compaction-routing.test.ts and codex-auth-context.test.ts already assert must not reach an operator-facing surface, and an error body travels further than a log line. When neither resolves, the sentence degrades to "the selected Codex pool account" rather than naming something opaque. The catalog drop now explains itself. A gated native model that no usable account backs is omitted from the catalog -- there is no row, so nothing downstream could attach a reason to it, and no later surface can tell "never entitled" apart from "the account broke this morning". The suppression site now says which accounts are stuck while the entitlement snapshot that produced the omission is still in scope. That explanation is deliberately narrow, in two ways. It is produced only when an account needs reauthentication, because being unentitled is the default state of most installations and explaining that on every sync would bury the case an operator can act on. And it considers only accounts that could have served the model in question: an account upstream positively denied is not the reason the model is missing, so naming it would send the operator to repair a credential that was never going to help. An unconfirmed roster stays a candidate, because that is exactly what a credential stuck on a failed refresh looks like. Catalog bytes are unchanged. The suppressed slugs are still suppressed, so the existing oracles that assert gated slugs stay absent from the written catalog keep asserting exactly that. Closes #4212
…attribution pool: name the account when a refresh fails or its models vanish
A connected client reported healthy while the installed Codex CLI exited before its first request, because the catalog on disk used a reasoning level that CLI does not know. Connection state proved the hub and the credential; it never proved the selected local runtime could consume what was written. The write-time gate cannot answer this. It runs once, on bytes about to be written, so it says nothing about a catalog that predates it, one written while the runtime ladder was unverified, or a runtime swapped afterwards. inspectClientCatalogReadiness assesses the installed file, and ocx connect status, ocx status --json and ocx connect now report the verdict. Only "ready" means ready; an unobservable runtime stays "unverified" rather than becoming an incompatibility, which is the line the write-time gate already refuses to cross. The probe runs only for a connected client, so no other install pays a Codex process for it. Closes #4207
Four things an independent read of the diff found. A diagnostics command should not start writing runtime selection state: the default observer now resolves the runtime without persisting and hands that command to the catalog read, which also avoids a second probe on a path that had already resolved it. The ocx connect decision moves into a pure connectCompletionReport, so the fail-closed exit is exercised without a hub. It prints the verdict first and withholds "Connected to" when it fails, because a caller grepping that phrase would otherwise read a broken catalog as success. A Claude-only connection is told about an old Codex CLI but not failed by it, since nothing in that connection launches Codex. connectClient now receives the same observer, so the write-time gate and the readiness check cannot disagree about the ladder inside one command. An installed catalog that is not JSON gets its own sentence instead of the gate's "downloaded" wording, and the subprocess fixture takes the same spawn budget the neighbouring client fixtures use.
The previous commit only forwarded catalogCompatibility when a test had injected it, so an ordinary ocx connect still let assertClientCatalogCompatible fall back to its own default -- which persists runtime selection state and runs a second probe. One command could then act on two separately observed ladders, and the comment claiming otherwise was false. Both checks now build the observer through one helper.
collectClientConnectionStatus observes the local ladder for a connected client, and observing it spawns codex debug models under a 45s budget. That is the point on ocx status and ocx connect status. config show is a different caller: it reads state, reason and token to answer whether the hub link is real, and it arrived on dev after this branch forked, so nothing here had declined the probe on its behalf. Declining it explicitly keeps a read-only config dump from turning into a runtime probe - the same reasoning the readiness check already applies when it refuses to persist runtime selection state.
client: report local Codex readiness instead of bare connected state
Round one fixed the English remote hub guide and left the seven translated copies telling their readers to run the line that fails. Each locale still ran a nested `ocx config set hub.<field>` straight after `ocx config set runtimeRole hub`, but `runtimeRole` does not create the object and the CLI refuses to create a missing parent, so the guide's own next line died with `config parent path not found: hub`. Each locale also still offered `--allow-insecure-http`, which `ocx connect` rejects as an unknown argument, and none of them documented the data plane at all. Every locale now creates `hub` and `remoteGui` first, offers the whole-object alternative with its replace-not-merge warning, and carries the section that gives the data listener TLS: the macOS constraint that Serve proxies only to 127.0.0.1, the loopback forwarder, the split data and `--management-url` origins, and the quiet trap where a loopback-bound listener behind a TLS frontend answers 403 `origin_rejected` on `/v1/catalog` while `/readyz` still returns 200. The locales say a mistyped key is rejected at write time with a `schema_invalid` error, without pinning the literal error shape. That is deliberate: the English guide at docs-site/src/content/docs/guides/remote-hub.md:110 says the shape is `schema_invalid: hub.<field>`, but `remoteGuiConfigError` in src/config.ts only produces the dotted form when the Zod issue carries a path. An unrecognized key has an empty path, so a typo actually reports `schema_invalid: hub`. Correcting the English source is outside this change's scope, and a translation should not quietly assert a different error shape than the source it translates, so the locales state only what is true of both. tests/ci-workflows/docs-remote-hub-claims.test.ts only read the English guide, which is why this drift went unenforced. It now runs the language-independent assertions over all eight files, English included, pinning commands and literal error codes rather than prose a translator is meant to rewrite. The replace-not-merge check bounds its window on the next heading of any level and requires the warning to name `hub.managementIngress`; bounding on `##` alone and accepting any bold let the following subsection satisfy it, which made the assertion decorative in five of the eight files. Closes #4200
docs(i18n): make the remote hub guide runnable in every locale
…not a bad key The 2.51.0 candidate reworded the retryable main-account refusal to end with 'the main Codex account needs reauthentication'. classifyError runs isAuthenticationMessage before it reaches the status === 503 arm, and that check is status-blind on the bare substring 'authentication', which 'reauthentication' contains. The body was served as authentication_error / invalid_api_key while still returning 503. Codex keys retry-after backoff on server_is_overloaded, so a transient token refresh started reading to the client as a bad API key and it stopped retrying. On 2.50.0 the same failure classified as server_error / server_is_overloaded. The pool counterpart in core.ts documents this exact trap and words itself around it; the main path walked into it anyway. It now uses the same construction: sign in to the main Codex account again. The old test asserted only the 503 and the word 'reauthentication', which is why the reclassification shipped unnoticed. The added test asserts error.type and error.code, and that the message carries no 'authentication' substring at all - the substring is the thing that reclassifies, not the phrasing.
…ssification fix(responses): keep the retryable main-refresh refusal an overload, not a bad key
…view # Conflicts: # package.json
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
✅ Deterministic PR hygiene checks passed. |
|
Important Review skippedToo many files! This PR contains 1238 files, which is 938 over the limit of 300. To get a review, reduce the PR to 300 files or fewer by splitting it into smaller PRs or changing its base branch. Usage-priced reviews support at most 300 files. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: ⛔ Files ignored due to path filters (40)
📒 Files selected for processing (1238)
You can disable this status message by setting the |
⏳ DRAFT
What to do
Its title has been prefixed with |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c1af92596a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const prompt = discoveredPricingRate(pricing.prompt ?? pricing.input); | ||
| const completion = discoveredPricingRate(pricing.completion ?? pricing.output); | ||
| if (prompt === undefined || completion === undefined) return "unknown"; | ||
| return prompt === 0 && completion === 0 ? "free" : "paid"; |
There was a problem hiding this comment.
Treat auxiliary charges as paid in the free filter
When a provider publishes zero prompt/completion rates but a positive auxiliary rate such as request, image, or web_search, this returns free. Both the CLI and dashboard trust pricingStatus for their Free-only filters, so users can select a model explicitly presented as free and still incur per-request or tool charges. Inspect the additional published charge dimensions before returning free, treating any positive recognized rate as paid.
Useful? React with 👍 / 👎.
| if (terminalType === "response.failed" || terminalType === "response.incomplete") { | ||
| return { kind: "end", searches: [] }; |
There was a problem hiding this comment.
Close bridge search cells before forwarding failure
When the opt-in passthrough bridge receives a web_search call followed by response.failed or response.incomplete, this discards this.searches and takes the ordinary end path. The caller therefore forwards the terminal without emitting searchEndFrames, leaving Codex's opened “Searching the web” cell spinning under the failed turn. Close each intercepted search cell before emitting the upstream failure terminal, as the explicit kind === "fail" path already does.
Useful? React with 👍 / 👎.
리뷰 · 우선순위 76 / 80이 PR은 새 기능을 더하는 작업이 아닙니다. 이미 지금 왜 버전이
게이트 쪽은 이전 preview 승격(#4010 2.48, #3928 2.47, #4116 2.49 등)과 같은 패턴입니다. 한 가지 빠진 점은 #4271과 같습니다. 본문은 여섯 레인 회귀 감사 증거를 경로 base= 메인테이너의 판단이 필요한 지점
너의 추천 이 댓글은 grok-bot이 작성했습니다 |
Summary
Promotes the same audited 2.51.0 product tree to
preview, published as2.52.0-preview.20260911.This is the identical freeze the stable promotion uses —
42fcf9a0a6de7930a3f69b5c0d6917acaca1a7ea.git diff 42fcf9a0a HEADis exactly one line:Nothing else differs. The preview channel gets the same bytes the stable channel does, from the same regression audit, which is the point of cutting both from one freeze rather than auditing twice.
previewmoves2.49.0-preview.20260909to2.52.0-preview.20260911.Why 2.52.0-preview and not 2.51.1-preview
nextPreviewReleaseoffers both from the current tag state.2.52.0-preview.20260911is the right one becausedevis already at 2.52.0 — the pre-move in #4270 put it there so 2.51.0 could publish — so this previews the coredevis actually becoming.This closes the 2.51.x patch line, per
MAINTAINERS.md: oncevX.Y.0-preview.*is tagged, a fix ships as part ofX.Y.0, not asX.(Y-1).(Z+1). A post-2.51.0 fix will ship as 2.52.0. That consequence is already implied bydevsitting at 2.52.0; naming it here so it is a decision on the record rather than a side effect.No
devpre-move is needed for this cut.release.ymlrequiresdevto outrank the released version, and 2.52.0 outranks 2.52.0-preview.20260911 because a prerelease sorts below its release — the caseMAINTAINERS.mddescribes as "no move is needed".Verification
The audit behind this tree is the one recorded for 2.51.0: six independent read-only
xai/grok-4.6lanes over all 97 changed product paths, coverage proven mechanically with zero unowned, five NO-BLOCKER and one blocker that was reproduced and fixed in #4269 rather than waived. Full detail, including the eight-clause blocker definition and 23 non-blocking dispositions:devlog/_plan/260911_251_regression_audit_release/.Because this tree is byte-identical to the stable promotion apart from the version string, the audit transfers without a re-run.
The authoritative gate is the push-event
ci.ymlandservice-lifecycle.ymlon this PR's merge commit, whichrelease.ymlindependently requires before it will publish.Checklist