Skip to content

closed accidental test PR - #14

Closed
Wibias wants to merge 164 commits into
devfrom
codex/provider-discovery-recovery
Closed

closed accidental test PR#14
Wibias wants to merge 164 commits into
devfrom
codex/provider-discovery-recovery

Conversation

@Wibias

@Wibias Wibias commented Aug 13, 2026

Copy link
Copy Markdown
Owner

No description provided.

lidge-jun and others added 30 commits August 13, 2026 00:38
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
lidge-jun and others added 25 commits August 14, 2026 01:00
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.
…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
@Wibias Wibias closed this Aug 13, 2026
@github-actions github-actions Bot added the intake: hygiene-blocked Deterministic PR hygiene checks failed label Aug 13, 2026
@github-actions

Copy link
Copy Markdown

⚠️ Deterministic hygiene checks failed.

  • new_suppression — A new TypeScript, lint, formatter, or similar suppression was added. Fix the underlying issue or obtain suppression-approved. Paths: gui/src/components/CodexPoolStrategySetting.tsx, gui/src/components/provider-workspace/ProviderAuthPanel.tsx, gui/src/pages/Models.tsx, gui/src/use-app-route-state.ts.

@github-actions

Copy link
Copy Markdown

⏳ DRAFT

  • PR description needs work (empty). UI screenshot required. hygiene: new_suppression.

What to do

  • Add a real Summary and Test plan to the PR description.
  • Add a screenshot of the UI change to the PR description.
  • Fix new_suppression — A new TypeScript, lint, formatter, or similar suppression was added. Fix the underlying issue or obtain suppression-approved. Paths: gui/src/components/CodexPoolStrategySetting.tsx, gui/src/components/provider-workspace/ProviderAuthPanel.tsx, gui/src/pages/Models.tsx, gui/src/use-app-route-state.ts.

This pull request was already a draft. Its draft status will be preserved after every issue above is resolved.

@Wibias Wibias changed the title noop closed accidental test PR Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

intake: hygiene-blocked Deterministic PR hygiene checks failed

Projects

None yet

Development

Successfully merging this pull request may close these issues.