closed accidental test PR - #14
Closed
Wibias wants to merge 164 commits into
Closed
Conversation
codex-rs 0.147.x desktop voice (thread/realtime/start, standalone WebSocket transport) connects directly to /v1/realtime?intent=quicksilver&model= (V1), /v1/realtime?model= (RealtimeV2), or /v1/live?model= (Frameless) with no call_id. The proxy only recognized call-create POSTs and keyed sideband joins, so these upgrades fell through to the /v1/* guard and clients saw 'failed to connect realtime websocket: HTTP error: 404'. - parseLiveSidebandTarget: accept standalone /v1/realtime and /v1/live upgrade targets (present-but-invalid call_id stays a rejected join) - buildLiveSidebandUpstreamWsUrl: map standalone targets onto the canonical realtime root, preserving the client query verbatim - sanitizeStandaloneRealtimeQuery: drop credential-shaped query params (access_token/api_key/token/key/...) before upstream relay - loopback listener allowlist: admit the two standalone paths for WebSocket upgrades so a directly-spawned codex app-server keeps voice - tests: parser/builder/query-policy units, standalone e2e relays for both paths, auth/origin guard pins, loopback admission pins Plan: devlog/_plan/260812_realtime_standalone_ws/000_plan.md
…AVAS
Upstream codex-rs RealtimeCallClient posts Frameless API-shape
call-create to {base}/live with no AVAS query (realtime_call.rs); only
the realtime/calls inbound shape maps to the legacy keyed AVAS endpoint.
The keyed branch previously sent every inbound path to
/v1/realtime/calls?intent=quicksilver&architecture=avas, misrouting
Frameless session bodies to an endpoint that validates them as v1.
…thinking ladder DeepSeek-V4-Pro-0813 GA (2026-08-13): the official model table marks the Responses API for deepseek-v4-pro, the /responses reference accepts both V4 ids, and the thinking-mode table is now identical for flash and pro (low->low, xhigh->high). Registry gains the Responses wire default + terminal repair for v4-pro, the Pro ladder regains low, and the metadata bundle effort maps match. Tests updated from the pinned pre-GA behavior.
* fix(codex): preserve account-scoped native model ids * fix(codex): isolate observed account-native model ids * docs(codex): call the row check plausibility, not provenance Review follow-up on top of @Yuxin-Qiao's commits. The behavior is kept; what changes is the claim made about it. hasNativeCatalogProvenance checked only field shape — base_instructions non-empty, comp_hash string-or-null, shell_type, a reasoning-levels array, model_messages an object. There is no signature, source identity, or server attestation, and models_cache.json is a user-owned file, so a complete hand-written row passes. I reproduced that directly before changing anything: a forged gpt-* row with those fields is accepted. Calling that provenance is the problem, not the acceptance itself. It grants nothing new — router.ts already routes any bare gpt-* id under an account selector regardless of the catalog, so the effect is that a poisoned row gets ADVERTISED through discovery, not that a new route or credential becomes reachable. And anyone who can rewrite that cache can already edit config.json or run ocx directly. So the predicate is renamed to say what it does, the two docs pages drop the provenance language, and a test pins the accepting behavior with the reasoning attached. A future reader who wants rejection needs a real provenance signal, not a longer list of fields to match. The existing minimal-row test is kept and retitled: filtering malformed rows is what this check is actually for. --------- Co-authored-by: bitkyc08-arch <bitkyc08@gmail.com>
…n#1529) Co-authored-by: Ingwannu <ingwannu@users.noreply.github.com>
* fix(provider): clamp Xiaomi MiMo public reasoning tiers * test(provider): record what the MiMo clamp does and does not govern Review follow-up on top of @Ingwannu's commit. The review flagged that a user reasoningEffortMap can lift a tier past the registry clamp, and that is true — I reproduced it: max resolves to max, not high. But it is the shipped contract, not an oversight. healMappedTiers treats a wire map as authoritative evidence of the tiers an upstream can emit and merges its Codex values into the ladder at lookup time. That is what lets a stale persisted ladder recover a newly documented tier without rewriting user config, and tests/reasoning-effort.test.ts pins it under 'stale reasoning-ladder self-heal'. I first tried making the clamp win. It broke two existing tests, because a mapped value like Kimi's is a legitimate non-Codex wire word, not a tier to compare against a ladder. Narrowing the clamp to Codex tiers only still fought healMappedTiers, so I reverted it: the right answer is that the registry clamp protects the DEFAULT route, and a user who writes a conflicting map has deliberately opted out. Two tests record that boundary — one for the default route where the clamp holds, one for the overriding map — so nobody later reads the clamp as an enforcement the code does not implement. --------- Co-authored-by: Ingwannu <ingwannu@users.noreply.github.com> Co-authored-by: bitkyc08-arch <bitkyc08@gmail.com>
* fix(claude): isolate native passthrough credentials * fix(server): align Anthropic listener policy --------- Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
…ts (lidge-jun#1471) Pins forwarded Codex credentials to the canonical ChatGPT host with a fail-closed path check, and stops the five credential-bearing sidecar fetches from following cross-origin redirects. Bun strips Authorization across origins but forwards nonstandard headers, so chatgpt-account-id, session_id and x-codex-turn-metadata would otherwise reach a redirect target. tests/credential-redirect-guard.test.ts pins both the sidecar family and the shared fetchWithHeaderTimeout helper. Co-authored-by: luvs01 <luvs01@users.noreply.github.com>
With the sidecar engaged, runWithWebSearch buffers every semantic adapter event of an iteration before scanning for web_search calls, so clients see nothing until the turn ends — 6-50s of silence, then the whole answer as one burst, on every routed-model turn (Codex sends the hosted web_search tool on every real turn). New config option webSearchSidecar.streamRoutedModelOutput (default false, behavior unchanged without opt-in): stream each iteration's leading text/thinking deltas live; the live window closes permanently at the first buffer-only event (tool calls above all), so web_search interception stays atomic, live events are exactly the first N passthrough entries, and the terminal replay skips them by count — nothing is delivered twice. Scanner semantics (thinking extraction, forced-answer output check) are unchanged. Verified: bun run test — 11197 pass / 0 fail (691 files); 4 new tests including a gated adapter proving live delivery mid-turn; tsc clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ient receipt Address review: both tests previously asserted only final frames, which a fully buffered implementation also produces. They now withhold the tool call until the test has observed the leading delta on the wire (buffered delivery deadlocks the gate), and the tool-boundary test additionally asserts wire order: prefix delta -> function_call item -> suffix delta. Docs: note that Kiro commentary streaming is independent of the new option; devlog: qualify the reasoning-first-model claim (their leading reasoning becomes visible too — that visibility is the point). Verified: bun run test tests/web-search.test.ts — 55 pass / 0 fail; tsc clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ad of releasing the gate The previous 5s guard called the adapter's release function on timeout, so a fully buffered implementation could still pass: the timer opens the gate, the terminal replay delivers the leading delta, and readUntil observes the replayed copy. The deadline now rejects the readUntil wait; the gate opens only after the client has genuinely observed the live delta. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oggle on the overview page GET/PUT /api/sidecar-settings now carry webSearch.streamRoutedModelOutput (boolean; false is the default and removes the key so config files stay minimal), and the web-search sidecar card on the Dashboard overview gains a "Stream answers live" switch so the option is discoverable without editing config.json. Strings added to all eight locales. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…notes Swept in by a bulk add; the follow-up devlog in 260812_websearch_sidecar_live_streaming stands on its own. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…webSearch shape Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…utedModelOutput Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rt durable persistence CodeRabbit round 4: the dashboard hint implied the whole turn streams — reworded in all eight locales to say leading text/reasoning streams until the model decides on a tool call, with the rest buffered for search interception. The sidecar-settings test now reloads the config from disk after each PUT and asserts the flag survives (true persists, false removes the key); the fixture gained a schema-valid provider because loadConfig() discards invalid files wholesale, which would have voided the reload assertions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
) Replaces credential-bearing live provider updates with an attested bodyless POST /api/providers/reload, binding a single-use capability to provider, method, exact path, nonce, PID, port and expiry, verified with timingSafeEqual. Also reports a reload the running proxy could not accept, so a CLI talking to a pre-attestation proxy no longer prints unconditional success while the live process keeps the previous credential. Co-authored-by: luvs01 <luvs01@users.noreply.github.com>
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Adds an experimental, config-only recovery path for native Codex v2 NEW_TASK messages whose payload is backend-encrypted. Disabled by default; when enabled it accepts only a native Codex ChatGPT credential from a loopback caller and sends it only to the compiled-in ChatGPT Codex endpoint, with redirect: error. Recovered plaintext is barred from the persisted continuation cache: recovery mutates the request input in place, so the body would otherwise have been written to responses-state.json with no TTL. Co-authored-by: soulbah <soulbah@users.noreply.github.com>
…-jun#1541 Also records the lidge-jun#1302 reproduction seen while running campaign CI: three spinning bun test processes, State R with wchan 0, growing epoll/eventfd counts, and an open SQLite journal — diagnosis only, the issue stays open.
CodeRabbit round 6: the live-window tests only covered text_delta, so a regression that buffers or drops thinking_delta would pass. The new gated test blocks the adapter until the client has observed the leading response.reasoning_summary_text.delta on the wire (rejecting 5s deadline), then asserts exactly-once delivery across the terminal replay. Requires reasoning.summary=auto in the request — without it the parser sets hideThinkingSummary and reasoning is never client-visible by design. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…attested reload call lidge-jun#1541 (fb4f2fe) added a seventh 'await convergeCodexCatalog()' to provider-routes.ts in the new attested credential-free provider-reload route, but the inventory contract still expected 6, leaving dev CI red for every open PR. Update the expected count and test title to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ntract-provider-reload test(codex-convergence): update route inventory for lidge-jun#1541's attested reload call
Independent review found a real hole in the retained-tail reuse that landed in 1d5c4dc. usageLogIdentityKey excludes size/mtime/ctime on purpose so appends can share work, which also means an in-place rewrite that keeps the inode is invisible to it. The file does not shrink, so the shrink check does not fire either, and the reader could return stale rows concatenated with bytes from the replacement content: first: aaa1,aaa2,aaa3 after: aaa1,aaa2,aaa3,bbb4 <- three rows no longer present in the file Carry a prefixDigest (SHA-256 over the last 4 KiB ending at the covered offset) on the snapshot and re-verify it before reusing or extending the retained rows. Any mismatch falls back to a full bounded read. The record-boundary check already masks this whenever a rewrite shifts row widths, which makes a naive regression test pass vacuously. The test therefore uses fixed-width request ids so a newline still lands exactly at the previously covered offset, and it was driven red against a disabled guard before being accepted. Also adds a bound test: once growth pushes the retained window start before the current bounded window, the reader must refuse to extend and read afresh, which is what keeps the retained set inside maxReadBytes rather than creeping toward the whole file.
The prefix digest only covered the trailing 4 KiB, so an in-place rewrite that altered earlier rows while leaving the final bytes byte-identical would still be reused. Digesting the entire prefix would re-read up to 64 MiB on every incremental call and give back most of what the retained tail saves. Take 8 evenly spaced 4 KiB probes across the prefix plus one anchored at the end, and mix the covered length into the digest: at most 32 KiB of work regardless of prefix size. Verified against a 20,000-row prefix with an equal-width rewrite of row 0 and the final probe window untouched -- the reader refuses the retained rows and falls back to a full read. This bounds rather than eliminates the adversarial case: a rewrite preserving both total length and every sampled span would pass. usage.jsonl is written only by appendUsageEntry, and the guard targets hand-edits, external compaction and restore-from-backup rather than a deliberate attack on a local ledger.
Independent review caught that the retained tail never engaged on any ledger larger than the read window -- which is every ledger this was written for. The refusal required the retained window to start at or after the current window, but once the file exceeds 64 MiB each append slides the window forward, so the check failed every time and the reader did a full reparse: 6 appends on an over-window file -> fullReads 7, tailReads 0, 37,254 lines The check was backwards. A retained window that starts EARLIER is a superset of the current window and already holds every row the window needs, so it is kept and a full read re-anchors only once the retained span reaches twice the window. That bounds retention while amortizing the full read over a window of growth: same 6 appends -> fullReads 1, tailReads 6, 6 lines 400 appends, 256 KiB window -> fullReads 6, tailReads 394, span within 2x Also replaces the sampled prefix digest with a full-prefix digest. Sampling covered 0.68% of a 4.8 MB prefix and 0.05% of a 64 MiB one, so an ordinary fixed-width in-place edit landed in a gap and stale rows were served; a rewritten row was demonstrated still being read from the retained set. Timestamps were considered and rejected as the cheap alternative because an append and a rewrite both move mtime and ctime forward. The full digest is a sequential scan of cached pages with no parsing or allocation: on the real 245 MB ledger, cold 67 ms then five reads in 8 ms and +1 MB. Both regression tests were driven red against the defective implementation before being accepted.
…o it Second review round found two more defects in the retained-tail reader. The caller received rows outside its own window. Keeping a retained window that starts before size-maxReadBytes returns rows a fresh bounded read would exclude, making maxReadBytes advisory rather than binding. The user-visible effect was worse than the contract break: when the oversized window re-anchored, visible history halved on a single poll of an append-only file, so dashboard totals swung ~2x between refreshes (rows oscillated 688..1376). Rows outside the window are now trimmed in place using recorded per-row byte lengths, so the result equals a fresh bounded read exactly at O(dropped) rather than a reparse. Verified against a fresh read on 60 consecutive rounds with 0 mismatches; row count across 900 polls is flat at 1330. The digest was also O(file) rather than O(window): hashing 0..covered twice per call is unbounded work while the read it replaces is capped at maxReadBytes, so it degraded with ledger growth and became SLOWER than a full read past roughly 1-2 GB. It now covers only truncatedPrefixBytes..covered -- exactly the span the retained rows were parsed from. Bytes before the retained start describe no retained row, so reading them proved nothing. Cost is now flat in ledger size: 0.07x of a full read at 245 MB, 1 GB and 2 GB alike (54/53/56 ms against 828/813/846 ms). Corrects a measurement in the previous devlog entry: the "8 ms on the 245 MB ledger" figure was taken after a reviewer agent had truncated the file to 4 MB. The table above is measured at true scale. The sawtooth regression test was driven red against a deliberately widened window before being accepted.
…window entryLengths recorded a length only for lines that parse, so malformed JSON, rows without a string requestId, and torn final writes had their bytes dropped. The window trim advances by summing those lengths, so it under-counted the real byte distance and consumed extra rows to reach the window start. This is the mirror image of the sawtooth fixed in the previous commit: instead of showing too much history it silently showed too little, and it never self-corrected. At one bad line per five over 600 polls a cached read returned 1313 rows starting at R000873 where a fresh read of the same window returned 1326 starting at R000860. Skipped bytes now fold into the next accepted row's recorded length, with a trailing remainder carried across the append boundary. A self-check backs it up: the recorded lengths plus that remainder must equal size minus truncatedPrefixBytes, or the retained rows are rejected and a full read runs. Two subtleties surfaced while proving this. String.split leaves a zero-byte trailing element after the final newline, which must not be charged a byte or every clean file fails the self-check. Deriving the offset from the kept span rather than accumulating double-counts the remainder. The regression test asserts tailReads, not just output: the self-check makes output correct either way, so without skipped-line accounting the reader merely degrades to a full read per poll. Verified red at tailReads 0.
A fourth review round on the shipped state found three more defects. Rows removed by the entry cap left the result without their bytes being accounted for, so the self-check failed and the incremental path shut off permanently once the cap was reached: 13 full reads and 0 tail reads across 12 appends. Output stayed correct, so only the read counters showed it. Fixing that exposed a design error. Folding capped bytes into truncatedPrefixBytes broke an existing test asserting that byte-window truncation and entry-count truncation are independent API signals. That test is right -- they are different facts and consumers see both. The accounting offset is now a separate internal field, rowsBeginAtBytes, and truncatedPrefixBytes keeps its API meaning. The digest is anchored to rowsBeginAtBytes at both write and verify; anchoring at one and checking the other is what made the capped case miss. Malformed-only appends were unbounded: once every retained row is trimmed and only an unparseable remainder is left, nothing advances the offset, so the retained span grew past maxReadBytes while the accounting still balanced. It now re-anchors with a full read. CRLF ledgers never used the incremental path at all. split(/\r?\n/) consumes two bytes but leaves no way to tell it did, so recorded lengths were one byte short per line and the self-check rejected every reuse. Splitting on "\n" keeps the \r inside the line where its byte is counted, and JSON.parse tolerates it. Before: 2 full reads, 0 tail. After: 1 full, 1 tail. All three regression tests were driven red against the defective code. Cost stays flat at 0.07x of a full read at 245 MB, 1 GB and 2 GB.
…tate Comparing truncatedPrefixBytes against a cold bounded read across all four truncation combinations -- none, byte window, entry cap, both -- surfaced two problems that single-scenario probes had missed. entriesTruncated was ORed with byte truncation on the incremental path, so a byte-truncated read reported that rows had been dropped when none had. It means entry-count truncation only; the route ORs the two signals itself. When both truncations apply, a cold read applies the entry cap across the whole window and reports byte truncation for the window boundary alone. An incremental read arrives at the cap by a different route and cannot reconstruct that ordering from retained state, so it now re-anchors rather than reporting a window a fresh read disagrees with. That branch is reachable in production rather than theoretical: rows on a real ledger average 118 bytes, so 500,000 of them occupy about 56 MiB and fit inside the 64 MiB window, which means the entry cap and the byte window can bind at the same time. Byte-window truncation is now advanced only by the window trim, tracked directly instead of derived from a difference that drifted as polls accumulated. All four states now match a cold read exactly on rows, first and last row, truncatedPrefixBytes, entriesDropped and entriesTruncated.
Eight commits were on dev, preview and main, but no running process had ever executed them: the proxy on :10100 was still the pre-fix binary at 6.68 GiB after 112 minutes. A green bench on a synthetic ledger is not proof for the machine that reported the problem. Restarted through the service's own lifecycle endpoint with the expected-pid header, which drained cleanly. Activation is proven by a store that only exists in this patch: the live memory API now reports usage_snapshot with one retained entry, which the pre-fix binary could not produce. RSS 6.68 GiB -> 0.9 GiB. Cold /api/usage 25.6 s -> 0.20 s. Three polls spaced 62 s apart to land past the summary-cache freshness window -- the case that previously forced a full reparse every minute -- cost 1 ms, 1 ms and 115 ms, with RSS moving 883 to 926 MB across the whole sequence instead of +680 MB per call. Tab-switch surfaces answer in 1-14 ms.
detectArtifactIoMode creates a .dirfd-probe-<pid> file, renames it, and unlinks it to decide whether dirfd-relative IO works. A process that dies between the rename and the unlink leaves an empty .dirfd-probe-<pid>.ok behind, and they accumulate in whatever directory the check ran from -- 84 of them, dating back to Aug 10, were sitting untracked in the repository root. They are machine-local scratch that must never be committed, and while they are untracked they also block the release preflight, which requires a clean tree. Ignoring them fixes both without deleting anything the user owns. The leak itself is worth fixing at the source, but that is a separate change to src/lab/artifacts/secure-fs.ts and not part of this work. Also adds the release plan for 2.14.2.
…s/add-turkish-translation
…, and troubleshooting pages
…windows memory table, and frontier strings
…lation docs: add Turkish (tr) localization to documentation site
* fix(pr-quality): break CodeRabbit review feedback loop in gate comment The readiness gate wrote a literal '@coderabbitai review' command into its status comment, and it rewrote an unchanged comment body on every wake. - Remove the inline CodeRabbit command from the ready notice. - Skip updateComment when the rebuilt body is unchanged. - Add regression tests for both behaviors. * test(pr-quality): cover unchanged CodeRabbit status wake * test(pr-quality): keep status-wake regression focused * test(pr-quality): cover legacy migration on no-op wake * test(pr-quality): reproduce stale gate comment body * fix(pr-quality): track gate comment body after writes * test(pr-quality): restore trust-boundary context * test(pr-quality): pin repeated failure comment target * test: fix gate body helper
|
⏳ DRAFT
What to do
This pull request was already a draft. Its draft status will be preserved after every issue above is resolved. |
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.
No description provided.