Repository navigation
Merge stable OpenCodex v2.100.1 - #14
Merged
Merged
Conversation
…n#8313) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(vertex): support dashboard ADC configuration * fix(vertex): fence ambient credentials at dispatch * fix(vertex): address credential and setup review findings * fix(vertex): address final credential review * fix(vertex): address routing and discovery review * fix(vertex): preserve registry and catalog authority * fix(gui): satisfy Vertex form accessibility checks
…nder Advanced usage (lidge-jun#8006) * docs(readme): link GOAT up top, note official-API commercial use, move account pool under Advanced usage - Add a one-line 'Part of GOAT' link under the tagline. - Add a commercial-use note: GOAT's paid offerings use official provider APIs and agreements only. - Move the ChatGPT account pool section and its highlight bullet (with the provider-policy note intact) into a new Advanced usage section before Documentation. No content removed. - Resync all seven locale READMEs and refresh readme/i18n-manifest.json hashes. * docs: remove unverified commercial-use claim
* docs: plan automatic update parity * docs: clarify update roadmap and address review feedback * docs: pin update guard citations to inventory baseline * docs: align update guard citations with baseline
* fix(gui): show WorkBuddy credits in quota summary * fix(gui): represent unavailable WorkBuddy credits accurately * fix(gui): handle accumulated WorkBuddy credit precision * fix(gui): define WorkBuddy credit percentage rounding * fix(gui): omit inconsistent WorkBuddy credit ratios * fix(gui): round reported WorkBuddy balances precisely * fix(workbuddy): preserve decimal precision in credit sums * fix(workbuddy): preserve enterprise balance precision * fix(workbuddy): preserve exact quota balance decimals * fix(workbuddy): validate exact balances before rounding * fix(workbuddy): sum credit amounts before number conversion * fix(workbuddy): keep quota change within display scope Defer exact-decimal DTO preservation to lidge-jun#8324. Co-authored-by: Rafael Moreira Lima <rrmlima@gmail.com> --------- Co-authored-by: Rafael Moreira Lima <rrmlima@gmail.com>
… on Anthropic children (lidge-jun#7374) Preserve native Anthropic Messages requests across eligible failover combos, including replay commitment, accounting, and stream framing. Co-authored-by: Vadym O <bolein95@gmail.com>
* refactor(release): build channels from verified dev commits * fix(release): preserve recovery and bound evidence lookups * fix(ci): fetch release history for evidence tests
…n#8334) * fix(gui): show verified Claude account in overview * fix(gui): order account status refreshes by provider * fix(gui): keep account identity uncertain during logout * Fix OAuth status races across logout and targets * Fix OAuth account mutation status races * Fix OAuth account operation races and recovery * Fix OAuth cancellation account ownership * Fix account login cancellation and logout coordination * fix(gui): narrow OAuth login coordination * fix(gui): preserve explicit account removal failure path
* test(codex): diagnose native claim setup failures * fix(tests): preserve claim diagnostics and error behavior
Accept a single leading BOM in JSONC configuration while rejecting repeated BOMs before a rewrite. Co-authored-by: 정우철 <oocheol@naver.com>
Count supplementary Han consistently in shared and Kiro token estimates, including mixed-script input. Co-authored-by: 정우철 <oocheol@naver.com>
Stop processing sidecar frames after the first terminal event, regardless of network chunk boundaries. Co-authored-by: 정우철 <oocheol@naver.com>
Prefer valid titles from completed sidecar citations while retaining safe streamed fallbacks. Co-authored-by: 정우철 <oocheol@naver.com>
…compare Lab file identity with bigint stat (lidge-jun#8035) * fix: compare Lab file identity with bigint stat NTFS file IDs can exceed 2^53, where adjacent IDs are equal as JS numbers. Take dev/ino from bigint stats in the Lab mutation lock, private-file stage cleanup, private reads, artifact and scratch directory checks. * test: select Lab injected stat targets by canonical path * fix: bind Lab lock release to the checked directory Release, stale reclaim and failed-acquisition cleanup move the canonical lock to a unique detached name first and remove it only when the moved directory has the checked identity and the caller's owner or reclaim token; any other directory is restored or left detached. * fix: release the Lab lock without moving a directory it does not own Release and failed-acquisition cleanup move only their own owner record and remove the lock directory only while empty; detached cleanup skips a live owner; an acquisition whose fresh directory vanishes retries. * fix: serialize Lab public-evidence mutation with an OS-held SQLite lock Replace the directory lock and its stale-owner reclaim with a BEGIN IMMEDIATE transaction on lab/public-evidence-mutation.sqlite, released by the OS when the handle closes. Older builds' live directory locks are still honoured and never moved or removed. * fix: bind the Lab lock file to the inspected file and keep live detached locks Create the lock database exclusively with mode 0600, re-prove its identity after locking, and skip older builds' detached copies that still record a live owner. * fix: skip Lab lock bookkeeping names in community cache scans * fix(lab): preserve distinct recovery stages --------- Co-authored-by: JUN <243035832+lidge-jun@users.noreply.github.com>
…lidge-jun#8152) A failover combo whose native Codex target answered a zero-output 503 server_is_overloaded after Codex WebSocket metadata frames (codex.rate_limits / codex.response.metadata) never moved to its next target: the combo stream preflight treated those frames as output and committed the child. They are now non-committing control frames, so the overload fails over and the declined child's metadata never reaches the client. Closes lidge-jun#8107 Co-authored-by: Ingwannu <ingwannu@users.noreply.github.com>
* ci: add targeted Windows native claim diagnostic lane * fix: retain Windows claim diagnostic evidence * Preserve claim diagnostics across child timeouts * test: assert timeout without platform exit-code assumptions * ci: remove unmerged evidence policy fingerprint
…n#8294) * docs: plan automatic update parity * Extract offline minisign verification primitives * Generate proposed update trust root from pinned key * Define signed update candidate identities * Add bounded unverified update JSON parser * Bound aggregate update JSON allocations * Compare signed update versions exactly * Verify offline update signature thresholds * Validate closed signed update document schemas * Bind generated update root digest into runtime * Authenticate the embedded update trust root * Snapshot update root bytes before verification * Verify signed releases and select bound targets * Check signed update comment versions * Add Node update primitive interoperability harness * Separate root transition and release evidence * Verify signed update artifact evidence * Cover artifact delegation and byte mismatches * Clarify signed root transition envelope contract * Bind update metadata evidence to signed targets * Cover signed metadata binding failures * Verify root transition signer unions * Exercise transition envelope in runtime harness * Exercise signed transition evidence across runtimes * Expose root transition envelope parser * Allow bounded generated update asset names * Exercise signed supply chain on Node 18 * Check schema byte caps across runtimes * Check root expiry across supported runtimes * Test schema field limits across runtimes * Exercise malformed Unicode across runtimes * Prove malformed Unicode rejection is observable * Bind verifier keys and parser input snapshots * Exercise full root thresholds on Node 18 * Exercise signed version and legacy adapter parity * Exercise signed evidence for every target tuple * Verify evidence across supported channels * Expose detached signed supply evidence snapshots * Verify all evidence snapshot bindings * Add unverified checkpoint payload codec * Bound checkpoint descriptor capture * Protect checkpoint encoder collection limits
…e usage dashboard (lidge-jun#8293) * docs(devlog): plan opt-in telemetry and the opencodex.me usage dashboard Roadmap unit for a six-layer stack: client telemetry core, GUI consent popup, Cloudflare Worker collector, telemetry guide, and the public /dashboard page. Docs only. * docs(devlog): record PR review round 1 decisions for the telemetry stack * docs(devlog): plan the env opt-out marker, privacy statement files, and the open SignPath condition - 000: the no-backfill rule covers env opt-out days and the disclosure day; the privacy statement changes in layer 2. - 040: lists every file that carries the published privacy statement (README, seven translations, both code-signing pages, SPONSORS.md) and says they land in layer 2. - 060: D2 adds the envOptOutActiveSince marker for a proxy that runs opted out for days; records SignPath's install-time condition verbatim as an open owner decision instead of assuming first-run disclosure satisfies it. * docs(devlog): record the owner's SignPath decision (D21) and the Windows installer layer
…-4) (lidge-jun#7495) * docs(devlog): design Child-to-Home account move over Remote Link (OCX-4) * docs(devlog): correct OCX-4 link admission facts and tense Name the existing child-parity report as the third link admission predicate, describe the account-offer route as a fourth, scope validation-pending imports to Orca, and use future tense for routes and features that are not built.
Show Claude CLI subscription quota from the latest recorded account observation, including consistent active and passive reports. Co-authored-by: Sayo <82053242+wtfsayo@users.noreply.github.com>
…offline journal (lidge-jun#8237) * docs(devlog): add docs-first roadmap and PRDs for ocx-child ephemeral link * feat(link): add ephemeral-child contract helpers and golden conformance suite * feat(ocx-child): add standalone lightweight Rust Child link relay and offline journal * feat(link): integrate ephemeral ocx-child discovery, enrollment, and sync fan-out * docs(link): document ephemeral ocx-child in structure SSOT and docs-site * fix(ocx-child): persist write-ahead journal, track multiline TOML, and restore user features * fix(link): harden ocx-child Windows ACLs, strict wire/settings bounds, and discovery precedence * fix(link): preserve interrupted-sync digests, rollback failed reattach, and align locale/conformance parity * fix(link): fail fast on unreadable attach snapshots, preserve feature comments, and clarify lifecycle docs * fix(link): verify restored credentials before relay restart and clarify fan-out restart docs * style(ocx-child): remove trailing whitespace * fix(ocx-child): preserve recovery and verify shutdown * fix(ocx-child): harden recovery identity and shutdown * fix(ocx-child): preserve local state during detach and sync * test(ocx-child): add env-gated test barrier and shared mock Home harness Process-level lifecycle regressions need to pause a real ocx-child at a named point. test_hooks::barrier is a no-op unless both OCX_CHILD_TEST_BARRIER_DIR and OCX_CHILD_TEST_BARRIERS are set; spawned serve children never inherit those variables. The mock Home and binary runners move into tests/common so new test files can share them; the mock gains parity stall/trickle modes. * fix(ocx-child): serialize and own the shared CODEX_HOME The lifecycle lock and journal live under OPENCODEX_HOME/child while config.toml, the catalog and models_cache.json live in CODEX_HOME. Two ocx-child installs with different OPENCODEX_HOMEs and one CODEX_HOME took independent locks and could attach, sync and detach the same files with incompatible journals. Every writing lifecycle command now also locks a fixed .ocx-child.lock inside the canonical CODEX_HOME (never deleted) and checks a durable ownership record (.ocx-child-owner.json: owner id, canonical OPENCODEX_HOME, directory identities, phase; no secrets). Lock order is lifecycle lock, CODEX_HOME lock, daemon start gate. A foreign, corrupt or unreadable record refuses without mutation and names the recovery step; ownership is never taken over by PID or timeout. Detach releases ownership last, after a durable cleanup-complete phase, so any crash is resumable. Journal application and offline detach take the guard as a parameter. Regression: tests/lifecycle_guards.rs runs two real processes against one CODEX_HOME with a barrier inside the protected section. * style(ocx-child): format lifecycle assertion message * fix(ocx-child): recheck home identity around every restoration step Immediate rollback, crash recovery and offline detach verified the home directory identity once and then wrote and removed files by path name. If a home was replaced after that check, restoration kept writing into the new directory and could delete its recovery records. Every restoration write, rename and removal now goes through CodexHomeGuard::restore_step, which re-verifies both captured home identities immediately before and after the call while the CODEX_HOME lock is held. A mismatch stops restoration, keeps every recovery record (rollback snapshot, journal, key, ownership record) and reports a recovery error. The rollback snapshot and journal are removed only by a step whose checks passed. Regression: tests/lifecycle_guards.rs pauses detach between verification and the write, replaces CODEX_HOME with a directory of sentinel files, and checks the sentinels, the original directory and the records. * fix(ocx-child): commit a daemon generation before it serves spawn_detached_serve started the relay, the parent waited for /healthz and then recorded the PID; attach removed its rollback record later. If the parent died after handing over the secret, the child kept serving, including after recovery restored files or after another generation was committed. Each start now records a random daemonGeneration in state before the spawn and passes it with the secret on stdin, which stays open. Inside the start gate the child requires state.daemonGeneration to match, and until it reads "commit <generation>" it answers only /healthz and posts no parity reports. EOF or any other line before the commit makes it exit without serving. The parent commits only after the state naming the generation and PID is durable and, for attach, after the rollback record is removed. Restart, sync rollover and rollback's prior-relay restart use the same rule. An operator-run serve --foreground is unchanged and is refused while an attach rollback is pending. Regression: tests/lifecycle_guards.rs kills the real attach parent at a barrier before the commit, and starts a daemon with stale and superseded generations. * fix(ocx-child): let shutdown end in-flight parity work and a busy pool The relay joined its parity thread on shutdown, but an in-flight parity request had only per-read socket timeouts (5 s/15 s), so a stalled or trickling Home kept it alive well past stop_owned_daemon's 3-second wait and detach reported that the daemon did not stop. Separately, the accept loop blocked on the worker semaphore when all 32 workers were busy, so the shutdown connection was never accepted. One-shot Home calls now carry a whole-request deadline (60 s for lifecycle fetches, 10 s for parity) enforced per read. The parity thread registers its socket in a CancelSlot; shutdown cancels the slot under the same mutex and shuts the socket down, and serve exits only after the thread ends. When the pool is full, a connection gets a short-lived control thread (capped at 256) that answers only /healthz and the authenticated shutdown with 1-second timeouts. Regression: tests/lifecycle_guards.rs runs detach against a Home that stalls or trickles the parity response and against a relay whose workers are all blocked, and checks the time budget and that the process is gone. * test(ocx-child): cover removal of an unchanged injected web_search on detach * docs(link): state the single-owner CODEX_HOME rule for ocx-child * fix(ocx-child): let Home catalog slugs win in models_cache sync after outside edits A sync after any outside edit to models_cache.json rebuilt the cache by swapping injected Home entries back to their pre-attach versions, then rejected each restored entry because it differed from the Home catalog entry with the same slug. Every later sync failed with client_models_cache_conflict until detach and re-attach. A Codex rewrite that re-serialized a Home entry hit the same path. Injected catalog slugs are now Child-owned by slug: sync writes the Home version and keeps entries with other slugs, and the detach snapshot keeps the pre-attach version or drops the slug. * fix(ocx-child): commit a rollback-restarted relay after removing the record Attach rollback restarted the prior relay and committed it before it removed the rollback record, so the relay could serve while recovery might still restore files underneath it. The restart now commits only after the record is removed; an uncommitted relay is dropped and exits if the removal fails. The structure doc names this ordering. * fix(ocx-child): bound each control-mode request head with a deadline A control connection, accepted while every worker is busy, had only a 1-second per-read timeout, so a sender writing one byte per second held its slot indefinitely and 256 such senders kept the authenticated shutdown from being handled. Control mode now reads through the existing DeadlineStream with a 2-second deadline that covers the whole exchange, including the shutdown proof frame. The code comment and structure text now state the bound and the connection cap precisely. * fix(ocx-child): cap the cancellable parity connect at one second The parity socket can be registered for cancellation only after it connects, and that connect could take up to the 5-second auth timeout, longer than the 3-second wait stop_owned_daemon gives a relay to exit. A request that carries a CancelSlot now connects with a 1-second bound; one-shot lifecycle fetches keep the 5-second bound. * fix(ocx-child): keep both catalogs in the backup across the cache write sync replaced the catalog backup with the new catalog before it wrote models_cache.json. An I/O error or crash between the two left a cache of previous-catalog entries next to a backup naming only the new catalog, so the next reconcile kept those previous Home entries as local ones and detach restored them into the native cache. Before the cache write the backup now names the slugs of both catalogs; after it, the new catalog alone. The regression interrupts a sync with JournalWriteFault::AfterCatalogWrite and checks detach, directly and after a retried sync. * fix(ocx-child): remove the padding inside the relay restart hint A source line wrap had put about 20 spaces between "run" and "ocx-child restart" in the message attach prints when its relay does not start. * fix(ocx-child): compile the test barrier out of release builds test_hooks::barrier read two environment variables on every lifecycle path and the env names were linked into the release binary. The barrier, its env constants, and the env stripping for a spawned relay now exist only with debug_assertions, the profile cargo test builds the binary with; a release build compiles them to no-ops. * fix(ocx-child): open lock files without following links FileLock checked the path with reject_symlink and then opened it with create(true), so a symlink swapped in between made the open follow it and create the link target. The open now uses O_NOFOLLOW on Unix, with the value libc defines for each target, and FILE_FLAG_OPEN_REPARSE_POINT on Windows, and refuses anything that is not a plain file. On Windows an existing lock file is verified to carry the owner-only DACL instead of being accepted unchecked. A debug-only barrier between the check and the open lets the regression swap in the symlink. * fix(ocx-child): wipe the shutdown secret and token-bearing request heads The shutdown secret was a plain String in ChildStateV1, so every state read, clone, and drop left a copy in memory and Debug printed it. It is now a SecretString that is wiped on drop, serialized as the same plain string, and redacted from Debug; load_live_creds no longer hands out a copy nobody used, and the rollback records no longer wipe it by hand. The daemon start line and the relay and lifecycle request heads that carry the link token are built once at their final size into SecretBytes, and state.json bytes are wiped after a read or write. * docs(link): state Child sync serialization and the restore window precisely The lifecycle reference said a second ocx sync fails fast on any Child. That holds for a full ocx Child; on ocx-child only the --expect-link form the Home's fan-out runs exits 5 with pending_operation, and a plain ocx-child sync waits for the first apply. The structure note now names who can act in the restore window, and the ocx-child status ledger no longer carries stale test counts or a stale wp5 summary. * test(link): find the ocx-child binary under CARGO_TARGET_DIR The e2e test built ocx-child with cargo but always looked for the binary under native/ocx-child/target, so a run with CARGO_TARGET_DIR set failed with ENOENT. It now resolves the target directory the way cargo does. * fix(ocx-child): stop printing the link key id after attach The attach success line named the link key identifier. Keep identifiers out of console output, matching the repository privacy rule; the regression asserts attach output never contains the key id.
…idge-jun#8364) * fix(gui): show Claude account email when privacy.maskEmails is false (lidge-jun#8286) Add an accountLabel to the OAuth account roster that follows privacy.maskEmails: the validated masked identity by default, the stored email when the operator sets the flag to false. Dashboard rows, Overview, reset dialogs and remove confirmations prefer it over the always-masked maskedLabel, which tray surfaces keep reading unchanged. * fix: reject format characters in unmasked account labels and clarify scope (lidge-jun#8286) Address review notes: omit bidi/zero-width format characters from the unmasked label, cover the unmasked filter and a string "false" config in tests, and document that all OAuth account labels follow privacy.maskEmails while desktop trays stay masked. --------- Co-authored-by: OpenCodex Lane (cpa) <cpa@localhost>
…ract (lidge-jun#8336) (lidge-jun#8366) The expected Git Bash PATH entries were rebuilt with the same win32.dirname/win32.join calls as releaseShellPath, so a wrong path operation in the helper could be mirrored by the assertion. Assert literal Windows paths instead. Co-authored-by: OpenCodex Lane (cpa) <cpa@localhost>
…dge-jun#8330) (lidge-jun#8367) The release helper ran gh run watch through the captured command runner, so the operator saw only the run ID. Stream the watch's stdout (progress and final job states) and print the run URL; stderr stays captured and unprinted, and a failed run still fails the helper. Co-authored-by: OpenCodex Lane (cpa) <cpa@localhost>
…idge-jun#8346) * docs(release): describe history reconciliation and attested resume structure/ops/docs-and-release.md and structure/ops/cross-platform-ci.md still said the release workflow refuses resume and fails closed whenever npm history exists. Describe what lidge-jun#8328 implements instead: channel-floor history reconciliation, the operator-attested resume with its explicit version and source inputs, the checks that refuse it, and the rule that a resume never republishes npm. Closes lidge-jun#8329 * docs(release): correct legacy floor and resume tag/release checks For the two fixed 2.99.0 legacy floors, collectPublicationHistory replaces the containment check with the fixed-SHA, baseline-ancestry and version-only tree checks in verifyLegacyTreeEvidence. On resume, release-resume.cjs only checks a tag or release that already exists, and publish creates whichever is missing. The npm history read is not an authenticated GitHub request. * docs(release): name dispatch inputs, align the contributing guide, guard stale release text (lidge-jun#8329) Maintainer fix-forward: list the release dispatch inputs and note that scripts/release.ts never dispatches a resume, replace the hosted contributing guide's 'reconciliation outstanding' wording, and add a contract test that requires every dispatch input and recovery gate script in the Release workflow section and rejects the stale refusal text in all three docs. --------- Co-authored-by: lidge-jun <lidge-jun@users.noreply.github.com>
Preserve supported image inputs in Claude CLI replay and refuse image forms that cannot be represented safely. Co-authored-by: Nick Davis <inbox@nickdavis.io>
…nd #remote UX (lidge-jun#8255) * docs(devlog): add docs-first roadmap and PRDs for ocx-child ephemeral link * feat(link): add ephemeral-child contract helpers and golden conformance suite * feat(ocx-child): add standalone lightweight Rust Child link relay and offline journal * feat(link): integrate ephemeral ocx-child discovery, enrollment, and sync fan-out * docs(link): document ephemeral ocx-child in structure SSOT and docs-site * fix(ocx-child): persist write-ahead journal, track multiline TOML, and restore user features * fix(link): harden ocx-child Windows ACLs, strict wire/settings bounds, and discovery precedence * fix(link): preserve interrupted-sync digests, rollback failed reattach, and align locale/conformance parity * fix(link): fail fast on unreadable attach snapshots, preserve feature comments, and clarify lifecycle docs * fix(link): verify restored credentials before relay restart and clarify fan-out restart docs * docs(devlog): add wp0 roadmap and PRDs for ocx-child plant UX * feat(link): add ocx-child --purge, conflict codes, and SSH plant foundations * feat(server): add bare-host SSH plant, rollback, childKind status, and DELETE --purge * feat(gui,cli): add #remote Ready-to-Plant, parity badges, and --purge UX across 11 locales * docs(link): document zero-preinstall SSH plant, --purge, and #remote UX * fix(link): populate PowerShell best-effort catch blocks for pr-hygiene * fix(link): preserve recovery binary on failed purge rollback and stabilize child.lock inode * test(link): stage compiled ocx-child with SHA256SUMS for bare-host E2E on CI * style(ocx-child): remove trailing whitespace * fix(ocx-child): preserve recovery and verify shutdown * fix(ocx-child): harden recovery identity and shutdown * fix(ocx-child): preserve local state during detach and sync * test(ocx-child): add env-gated test barrier and shared mock Home harness Process-level lifecycle regressions need to pause a real ocx-child at a named point. test_hooks::barrier is a no-op unless both OCX_CHILD_TEST_BARRIER_DIR and OCX_CHILD_TEST_BARRIERS are set; spawned serve children never inherit those variables. The mock Home and binary runners move into tests/common so new test files can share them; the mock gains parity stall/trickle modes. * fix(ocx-child): serialize and own the shared CODEX_HOME The lifecycle lock and journal live under OPENCODEX_HOME/child while config.toml, the catalog and models_cache.json live in CODEX_HOME. Two ocx-child installs with different OPENCODEX_HOMEs and one CODEX_HOME took independent locks and could attach, sync and detach the same files with incompatible journals. Every writing lifecycle command now also locks a fixed .ocx-child.lock inside the canonical CODEX_HOME (never deleted) and checks a durable ownership record (.ocx-child-owner.json: owner id, canonical OPENCODEX_HOME, directory identities, phase; no secrets). Lock order is lifecycle lock, CODEX_HOME lock, daemon start gate. A foreign, corrupt or unreadable record refuses without mutation and names the recovery step; ownership is never taken over by PID or timeout. Detach releases ownership last, after a durable cleanup-complete phase, so any crash is resumable. Journal application and offline detach take the guard as a parameter. Regression: tests/lifecycle_guards.rs runs two real processes against one CODEX_HOME with a barrier inside the protected section. * style(ocx-child): format lifecycle assertion message * fix(ocx-child): recheck home identity around every restoration step Immediate rollback, crash recovery and offline detach verified the home directory identity once and then wrote and removed files by path name. If a home was replaced after that check, restoration kept writing into the new directory and could delete its recovery records. Every restoration write, rename and removal now goes through CodexHomeGuard::restore_step, which re-verifies both captured home identities immediately before and after the call while the CODEX_HOME lock is held. A mismatch stops restoration, keeps every recovery record (rollback snapshot, journal, key, ownership record) and reports a recovery error. The rollback snapshot and journal are removed only by a step whose checks passed. Regression: tests/lifecycle_guards.rs pauses detach between verification and the write, replaces CODEX_HOME with a directory of sentinel files, and checks the sentinels, the original directory and the records. * fix(ocx-child): commit a daemon generation before it serves spawn_detached_serve started the relay, the parent waited for /healthz and then recorded the PID; attach removed its rollback record later. If the parent died after handing over the secret, the child kept serving, including after recovery restored files or after another generation was committed. Each start now records a random daemonGeneration in state before the spawn and passes it with the secret on stdin, which stays open. Inside the start gate the child requires state.daemonGeneration to match, and until it reads "commit <generation>" it answers only /healthz and posts no parity reports. EOF or any other line before the commit makes it exit without serving. The parent commits only after the state naming the generation and PID is durable and, for attach, after the rollback record is removed. Restart, sync rollover and rollback's prior-relay restart use the same rule. An operator-run serve --foreground is unchanged and is refused while an attach rollback is pending. Regression: tests/lifecycle_guards.rs kills the real attach parent at a barrier before the commit, and starts a daemon with stale and superseded generations. * fix(ocx-child): let shutdown end in-flight parity work and a busy pool The relay joined its parity thread on shutdown, but an in-flight parity request had only per-read socket timeouts (5 s/15 s), so a stalled or trickling Home kept it alive well past stop_owned_daemon's 3-second wait and detach reported that the daemon did not stop. Separately, the accept loop blocked on the worker semaphore when all 32 workers were busy, so the shutdown connection was never accepted. One-shot Home calls now carry a whole-request deadline (60 s for lifecycle fetches, 10 s for parity) enforced per read. The parity thread registers its socket in a CancelSlot; shutdown cancels the slot under the same mutex and shuts the socket down, and serve exits only after the thread ends. When the pool is full, a connection gets a short-lived control thread (capped at 256) that answers only /healthz and the authenticated shutdown with 1-second timeouts. Regression: tests/lifecycle_guards.rs runs detach against a Home that stalls or trickles the parity response and against a relay whose workers are all blocked, and checks the time budget and that the process is gone. * test(ocx-child): cover removal of an unchanged injected web_search on detach * docs(link): state the single-owner CODEX_HOME rule for ocx-child * fix(link): refuse to plant ocx-child when the Child cannot verify its SHA-256 The POSIX plant script skipped the digest check when neither sha256sum nor shasum existed and then ran the binary after a size check alone. It now also accepts openssl dgst, and with no hash tool it exits 3 before the binary is installed or executed, printing ocx-plant-error:hash_tool_unavailable. Home maps that marker to 502 remote_plant_failed with hint hash_tool_unavailable. The Windows plant already streams SHA-256 before running the binary. * fix(ocx-child): let Home catalog slugs win in models_cache sync after outside edits A sync after any outside edit to models_cache.json rebuilt the cache by swapping injected Home entries back to their pre-attach versions, then rejected each restored entry because it differed from the Home catalog entry with the same slug. Every later sync failed with client_models_cache_conflict until detach and re-attach. A Codex rewrite that re-serialized a Home entry hit the same path. Injected catalog slugs are now Child-owned by slug: sync writes the Home version and keeps entries with other slugs, and the detach snapshot keeps the pre-attach version or drops the slug. * test(link): give the bare-host plant E2E a SHA-256 tool The plant script now refuses to install a binary it cannot hash, and the E2E's bare host exposed only sh and core utilities, so it had been planting without any digest check. Link the first available sha256sum, shasum, or openssl into the host's private PATH. * fix(link): purge through the managed planted ocx-child and report a purge that did not happen DELETE /api/link/:id {purge:true} ran `disconnect --purge` through the generic candidate resolver, so a ~/.local/bin/ocx-child could answer first; it is outside the managed directory, so it exited 0 with purged:false and Home reported success. The purge was also dropped silently for links whose record had no childKind. Home now runs the planted binary at the managed path explicitly (remoteManagedPurgeDisconnectArgv, POSIX and Windows) with --json and requires its "purged": true report. A missing managed binary (managed_child_missing) or a report without the removal (purge_incomplete) is 502 remote_disconnect_failed and the link record is kept. A record without childKind is inspected first; a full install answers 409 purge_unsupported instead of a silent plain disconnect. * fix(ocx-child): commit a rollback-restarted relay after removing the record Attach rollback restarted the prior relay and committed it before it removed the rollback record, so the relay could serve while recovery might still restore files underneath it. The restart now commits only after the record is removed; an uncommitted relay is dropped and exits if the removal fails. The structure doc names this ordering. * fix(ocx-child): bound each control-mode request head with a deadline A control connection, accepted while every worker is busy, had only a 1-second per-read timeout, so a sender writing one byte per second held its slot indefinitely and 256 such senders kept the authenticated shutdown from being handled. Control mode now reads through the existing DeadlineStream with a 2-second deadline that covers the whole exchange, including the shutdown proof frame. The code comment and structure text now state the bound and the connection cap precisely. * fix(ocx-child): cap the cancellable parity connect at one second The parity socket can be registered for cancellation only after it connects, and that connect could take up to the 5-second auth timeout, longer than the 3-second wait stop_owned_daemon gives a relay to exit. A request that carries a CancelSlot now connects with a 1-second bound; one-shot lifecycle fetches keep the 5-second bound. * fix(ocx-child): stop re-permissioning existing OPENCODEX_HOME when taking the lifecycle lock Moving the lifecycle lock to $OPENCODEX_HOME/child.lock made every FileLock acquisition call ensure_private_dir on OPENCODEX_HOME: attach, sync, restart, and detach chmodded a shared home to 0700 on POSIX and, on Windows, applied a protected owner-only DACL with inheritable ACEs that propagated into a co-installed full OpenCodex tree, all before the full-ocx conflict check. FileLock now decides through lock_parent_action: a missing parent is created private by create_private_dir_if_missing (0700, or a hardened DACL only on a directory this call created), an existing parent is used as it is, and a symlink or non-directory is refused. The lock file itself is still created 0600 / owner-only on the file alone. CODEX_HOME keeps using lidge-jun#8237's acquire_in_existing_dir, which never touched its mode. * fix(link): treat an empty OPENCODEX_HOME as unset when looking up cached ocx-child artifacts OPENCODEX_HOME= made the cache lookup join(, cache, ...), a path relative to the server's working directory. An empty or blank value now falls back to ~/.opencodex, as ocx-child does. structure/remote-link.md also records that childKind joined the strict link record keys, so a downgraded Home rejects a links.json that carries it (the same trade-off as remotePlatform). * fix(ocx-child): keep both catalogs in the backup across the cache write sync replaced the catalog backup with the new catalog before it wrote models_cache.json. An I/O error or crash between the two left a cache of previous-catalog entries next to a backup naming only the new catalog, so the next reconcile kept those previous Home entries as local ones and detach restored them into the native cache. Before the cache write the backup now names the slugs of both catalogs; after it, the new catalog alone. The regression interrupts a sync with JournalWriteFault::AfterCatalogWrite and checks detach, directly and after a retried sync. * fix(ocx-child): remove the padding inside the relay restart hint A source line wrap had put about 20 spaces between "run" and "ocx-child restart" in the message attach prints when its relay does not start. * fix(ocx-child): compile the test barrier out of release builds test_hooks::barrier read two environment variables on every lifecycle path and the env names were linked into the release binary. The barrier, its env constants, and the env stripping for a spawned relay now exist only with debug_assertions, the profile cargo test builds the binary with; a release build compiles them to no-ops. * docs(link): say where a plantable ocx-child build must come from today The guide claimed a bare SSH host works out of the box, but resolveChildBinarySource only finds a build in OPENCODEX_CHILD_BIN_DIR, native-bin/ sidecars (no package ships them), a source checkout's own cargo release build, or a SHA256SUMS-verified $OPENCODEX_HOME/cache/ocx-child/<version>/ (nothing fills it). A packaged npm or desktop Home therefore reports plantable:false with artifact_not_found. The English guide and structure now list those sources in order, state that packaged installs need one of them, and describe the Child's hash tool requirement. When the probe reports artifact_not_found, the CLI, the remote_plant_unavailable message (plantUnavailableGuidance), and the #remote sheet (link.plant.artifactHelp in all 11 locales) name the file and the directories Home reads. * fix(ocx-child): open lock files without following links FileLock checked the path with reject_symlink and then opened it with create(true), so a symlink swapped in between made the open follow it and create the link target. The open now uses O_NOFOLLOW on Unix, with the value libc defines for each target, and FILE_FLAG_OPEN_REPARSE_POINT on Windows, and refuses anything that is not a plain file. On Windows an existing lock file is verified to carry the owner-only DACL instead of being accepted unchecked. A debug-only barrier between the check and the open lets the regression swap in the symlink. * fix(ocx-child): wipe the shutdown secret and token-bearing request heads The shutdown secret was a plain String in ChildStateV1, so every state read, clone, and drop left a copy in memory and Debug printed it. It is now a SecretString that is wiped on drop, serialized as the same plain string, and redacted from Debug; load_live_creds no longer hands out a copy nobody used, and the rollback records no longer wipe it by hand. The daemon start line and the relay and lifecycle request heads that carry the link token are built once at their final size into SecretBytes, and state.json bytes are wiped after a read or write. * docs(link): state Child sync serialization and the restore window precisely The lifecycle reference said a second ocx sync fails fast on any Child. That holds for a full ocx Child; on ocx-child only the --expect-link form the Home's fan-out runs exits 5 with pending_operation, and a plain ocx-child sync waits for the first apply. The structure note now names who can act in the restore window, and the ocx-child status ledger no longer carries stale test counts or a stale wp5 summary. * test(link): find the ocx-child binary under CARGO_TARGET_DIR The e2e test built ocx-child with cargo but always looked for the binary under native/ocx-child/target, so a run with CARGO_TARGET_DIR set failed with ENOENT. It now resolves the target directory the way cargo does. * fix(ocx-child): stop printing the link key id after attach The attach success line named the link key identifier. Keep identifiers out of console output, matching the repository privacy rule; the regression asserts attach output never contains the key id. * fix(link): keep an unrunnable planted ocx-child while any recovery record exists The enrollment-rollback purge deletes a planted ocx-child that cannot run unless recovery evidence remains, but it only looked for child/state.json and codex-journal.json. An attach interrupted before state.json exists leaves only attach-rollback.json and the CODEX_HOME ownership record (.ocx-child-owner.json); the purge then deleted the one binary that could roll that attach back and reported success. Both the POSIX and the Windows purge now treat the attach rollback snapshot and the ownership record (under CODEX_HOME, defaulting to ~/.codex like ocx-child) as recovery evidence, keep the binary, name the record on stderr, and exit non-zero so Home reports a residual. * fix(gui): explain a refused --purge on a full install in the #remote sheet DELETE /api/link/:id with { "purge": true } answers 409 purge_unsupported when the Child turns out to run a full OpenCodex install, but the GUI had no mapping for that code and showed the generic "could not be completed" text. Map it to a message in all eleven locales that says there is no planted binary to delete and to disconnect without deleting it. The route-owner scrape now also reads the codes purgeDisconnectRemote returns, because the DELETE route forwards them as a variable.
Reconcile streamed sidecar text snapshots by compatible part identity while preserving output order and bounded processing. Co-authored-by: 정우철 <oocheol@naver.com>
…alling it foreign (lidge-jun#8439) * fix(usage): wait for a concurrently created filter index instead of calling it foreign * fix(usage): recheck a stale filter index schema under the lock and document the open contract * test(usage): release the still-creating lock from the reader's busy back-off, not a timer * docs(usage): state the four-attempt busy bound the reviewer measured
…process already has (lidge-jun#8441) * test(clients): give each Desktop lifecycle case the budget its child process already has * test(clients): give the sibling runEvalChild cases the same child-process budget * test(clients): stop the Desktop lifecycle sync fixture from probing the host Codex CLI
Refresh the documentation landing page, navigation and theme while preserving routes and keyboard access. Keep the responsive header usable across locales, short viewports and reduced-motion preferences. Co-authored-by: 이완우 <theguide123456789@gmail.com>
…target (lidge-jun#8438) * fix(gui): scope provider drafts to their dashboard target Provider Settings and the raw JSON editor kept one draft per provider name, while the Providers page can outlive an apiBase change. A same-name provider on the next target could inherit the old draft, or the old draft could be saved through the new target's callback. Keep drafts and their saved baselines in an in-memory store keyed by target and provider. The form remounts per target, config is bound to the target that answered it, and a save completion is fenced to the target that started it. Returning to a target restores its draft; if its saved values moved, the UI asks for an explicit keep-draft or use-saved choice instead of silently overwriting either side. Nothing is written to browser storage. Adds the target label and conflict banner to both Settings and JSON, with translations, docs and regression tests. * fix(gui): rebase provider drafts onto the latest target state Keep-draft now applies only the user's delta to the latest saved config: Settings patches changed fields only, and the JSON editor performs a three-way merge that preserves unrelated providers and fields and reports same-field, deletion and rename conflicts explicitly. Restore returns to the latest saved values, and a no-op save never sends an identical baseline/next pair. Fence the logical dashboard target (hub origin plus machine key id) across config, drafts, OAuth status, account rosters and login/logout completions, so a relay re-pair cannot reuse the previous hub's state. An old target's save completion can no longer advance the shared config request sequence and strand the new target in loading. Clear parked drafts on a confirmed provider removal and on leave-dialog discard, keep edits typed while a save is in flight, and sync the endpoint picker when saved values move. * docs: record audited provider draft target plan (lidge-jun#8325) * feat(gui): bind provider drafts to stable targets and relay saves Stable logical identity is hub origin plus link id (not API-key rotation), with App discovery coalesced across session/focus/mismatch events and the draft owner kept above remounts. Draft entries use a mount owner CAS so a stale save completion cannot write or clear a newer instance; discard, removal and A-B-A retain only same-instance newer edits. Settings and JSON now merge only the user delta into the latest observed saved values: deep pacing subfield merge, partial JSON merge with edit-to-resolve conflicts, latest-value Restore, numeric bounds, and a no-op save that never sends identical baseline/next. Endpoint choice is synced when saved values move. The machine listener advertises expected-target-v1 and the hub relay validates a bounded canonical expected origin against the same immutable forwarding snapshot before reading the body, strips the field, and keeps legacy absent-field behavior with an explicit preflight notice. GUI mutations capture their target before auth and refuse a changed target. Usage, preset, Dashboard and Codex-pool caches carry the logical identity. * test(gui): keep API-key rotation outside logical target identity * fix(gui): keep prototype keys as data and strip composite labels * fix(gui): fence every mutation transport and add target transport witnesses * test(gui): configure the captured target in CRUD transport tests * fix(gui): retain login cancellation capture and add lifecycle witnesses * test(gui): exercise own-key merge through the object path * fix(gui): capture manual-code and Kiro profile mutations * fix(gui): fence remaining provider mutations and target-scoped UI state * test(gui): prove panel and OAuth target capture isolation * fix(gui): keep provider actions on the target they were captured on An embedded component supplies its own apiBase. While the dashboard has no discovered topology that base is the target; discovery still wins, so a caller cannot retarget a configured relay. Unknown relay capability strings read as legacy instead of failing discovery. OAuth cancellation now always uses the capture the login started with, and fails closed when it is gone, so a timeout or rejection from the old target cannot cancel a login on the new target. Logout failures are guarded before any notice. Codex pool mutations fence every post-await write by the captured generation and the rendered base, including pending reconciliation refs. target_changed responses render the localized target message. * test(gui): prove target capture, cancellation and completion fencing Cover the embedded standalone base contract and its discovery boundary, an unknown relay capability reading as legacy, and the expected-target header surviving a 401 retry. Add deferred-completion witnesses for a switch and a pause accepted on the old target, plus OAuth cancel and logout settlement after a target change. The pin-release source assertion follows the present-checked confirmation row. * docs(structure): record the embedded target and legacy capability contract The dashboard provider row now states that an embedded apiBase is authoritative only before discovery, that a configured relay wins, and that an unrecognized relay capability reads as legacy. * test(gui): make the target-change witnesses discriminate The OAuth cancel witness now runs on a relay target so the live capture differs from the login capture, and it passes stable setters so the pagehide effect does not rerun on every render. The pause witness gates the completion follow-up load, which had been correcting the stale write before the assertion. * fix(gui): send pool settings through the captured target The global auto-switch threshold and the Claude account-pool settings still used a bare fetch, so a relay request carried no expected target and a completion could apply after a switch. Both now capture at the action, send through targetFetch and check the capture before applying. The Claude pool keeps its existing apiBase/provider request guard. * fix(gui): own the target at the form and dialog boundary Settings computed a patch and let the update callback capture the live target, so a module target change without a re-render sent the save to the new hub. The form now owns a render capture and passes it through a typed onUpdateProvider(name, patch, capture); the detail pane injects it into every child call and the CRUD hook owns its own for remove, disable and default. A render-owned capture may still reach its own target, where the relay refuses the stale expected target; completions stay fenced by the strict check. A remove confirmation captures at open and refuses after a target change. Key remove, add and alias guard their completions; the add-key form and the Add Provider completion do not survive a switch. Kiro polls with the session capture and ends when it is stale. CodexSet threads the logical target. * test(gui): keep the remove confirmation across the target change The witness now re-renders the same hook instance on B and back to A, so the pending confirmation is exercised instead of a remount. A refusal keeps the pending capture until a delete succeeds, so an A-B-A confirm still refuses. * docs: record capture ownership at the form and dialog boundary The acceptance plan and the dashboard structure note now state that the form owns the capture, the typed update callback carries it, and a remove or mode confirmation keeps the capture from when it opened. * test(gui): follow the Codex Set route's new target prop Codex Set now receives the logical target so its account pool is scoped like Providers. The source assertion follows that contract; the route is unchanged. * fix(gui): refuse every stale capture before fetch Restore the audited contract: a stale capture is refused before authentication or fetch regardless of who created it. The render-owned capture changes the capture point, not the fence; the permission exception is removed. The detail pane forwards a caller capture (capture ?? updateCapture) instead of replacing the form's. An empty targetKey falls back to apiBase so embedded surfaces do not share one identity. The relay capability is read from the live target after the identity check, so a same-identity downgrade uses the fresh legacy preflight and a downgrade with a target change refuses before fetch. * docs: correct the render-capture contract in the acceptance plan The render-owned capture changes only where the capture is created. Every stale capture is refused before authentication or fetch; the relay capability is read from the live target after the identity check. This corrects an implementation drift from plan revision 4 without changing the architecture. * fix(gui): own the target in every provider capture owner The account, OAuth, Kiro, Codex pool, auto-switch and Anthropic pool hooks created their capture inside the action, so a module target change that had not re-rendered the surface captured the live new target and the strict transport guard accepted it. Each hook now creates the capture at render with useRenderTargetCapture and carries it through loads, actions and completions. The logical target is threaded through ProviderAuthPanel, the Kiro dialog, the Anthropic pool card and CodexAccountPool. The leave dialog captures its target when it opens, closes on a target change, and uses the form's owner-checked discard. A parameterized render-gap suite covers every capture owner. * fix(gui): keep the render capture server-render safe Server-rendered surfaces have no window or session. The capture hook now returns an inert capture there instead of reading the location. The plan records the render-owned capture owners and the leave-dialog boundary. * fix(gui): adopt saved provider settings without lint suppressions The Settings form reset wrote state from a useEffect, which the React Compiler lint rejects as EffectSetState. The PR silenced it with an eslint-disable for react-hooks/set-state-in-effect and an oxlint-disable for react/react-compiler on the effect, plus an exhaustive-deps disable for the render-local applyDraft. Those added suppressions fail the deterministic PR hygiene gate (new_suppression), and react-doctor reports the same flow as no-adjust-state-on-prop-change and no-effect-chain. Adopt saved values while rendering instead, the React pattern for a prop-driven reset: a clean form follows the saved item in the commit that delivers it, and a dirty draft keeps what the user typed so the conflict banner can ask which side wins. Account mode uses the same pattern, kept separate so a mode PATCH refresh cannot reset an in-progress draft. The draft-store owner token becomes a lazily initialised state value instead of useRef(Symbol(...)), which rebuilt the symbol on every render and read a ref during render. The preset read no longer needs its dependency suppressions because it already reads the current base URL through a ref. Verification: gui oxlint, tsc -b, root typecheck, structure:check, file-size and repo-hygiene guards, privacy scan, pr-hygiene helper on the PR diff (no failures), and the provider settings/draft/pacing suites. * fix(gui): clear the remaining react-doctor findings on the target-scope PR The React Doctor PR gate runs react-doctor@0.9.11 with `--blocking warning` over the changed files. After the Settings reset fix, 48 findings remained across the target-scope surfaces and their tests. Each one is fixed at its source; no rule, threshold, baseline, or suppression changed. - App.tsx: the target-discovery effect paired its listeners in a `for...of` loop, which the cleanup analyzer cannot follow. The same three events are now registered and released explicitly, keeping `discovery.dispose()` first. - useCodexAccountPool: the target reset clears rows while rendering, so the new target never paints the previous target's accounts; the generation guard and the loaded/initial-load refs still move in the effect, because in-flight loads read them. `captureIsCurrent` becomes a stable `useCallback` over the apiBase ref, so the eight action callbacks can list it instead of closing over a render-local function. - useProviderAccountPools: the bounded roster read moves to a module helper. A `try`/`finally` inside the memoized callback makes the compiler lose its dependency inference and report the capture the read uses as an extra dependency; the callback is now a plain delegation. - use-providers-fetch: the post-read supersede check becomes a named predicate. It is only meaningful after the read settles, and naming it says so. - Test harnesses publish hook results from a layout effect instead of writing them to module bindings during render, which the compiler rejects. Assertions and the values they read are unchanged; the crud harness drops the ready flag that existed only to force a second render, and the transport test now uses the capture it takes, which is what its name claims. Verification: react-doctor 0.9.11 over all 75 changed gui files reports 0 errors and 0 warnings (exit 0); gui oxlint and `tsc -b` pass; root typecheck, structure:check, file-size and repo-hygiene guards, and privacy scan pass; the affected gui suites pass; the PR hygiene helper reports no failures. * fix(gui): bind Codex login and reauth flows to their logical target A relay keeps one apiBase across a re-pair, so the Codex add-account OAuth and native-main device reauth hooks could send A's flow id, device code or cancel to B after a target change. Each flow now stores the render capture it started on, sends every start, status, manual-code and cancel request through targetFetch, and applies a completion only while that capture is still current. The modal, pool frame, Providers modal and Codex Set Multi-auth panel are keyed by the logical target and close or reset target-scoped state when it changes. Also fences the pool's quota-activation PUT and read-back with the same capture, and shows the existing legacy-preflight notice in Codex Set through a shared hook instead of duplicating the listener. * fix(gui): clear react-doctor findings on the auth target-capture delta Reset the visible main-reauth state at the prop boundary instead of inside the target-change effect, while the effect keeps retiring the original flow on its own capture. Publish the test hook/state globals from layout effects and bind the OAuth callbacks through a stable local so the pinned react-doctor scan reports no new diagnostics. * fix(gui): fence late account-pool reads on their captured target dd130 cleared the previous target's rows while rendering but left the generation bump in a passive effect, so a read issued for A that settled between B's commit and that flush still matched the generation and repainted A's rows, active id and ready state under B. The relay re-pair (same apiBase, hub-a -> hub-b) is the case that exposed it. Every apply, catch, settle and counter write now checks the captured target as well as the generation, and a load whose render no longer owns the target does not start. The render identity is published from a layout effect because the continuation runs after the layout phase and before passive effects. Verification: the reviewer's held-read repro is red on ef6cdf6 and green here; the new gui regression releases A from B's layout phase and asserts B's rows, active id, load state and first-attempt flag. gui pool and target suites 126 + 67 pass; gui oxlint 0/0; gui build passes; root typecheck, privacy scan, structure:check, repo-hygiene and file-size guards pass; react-doctor 0.9.11 over base c81be32 reports no changed-scope issues and full scope stays at the base's 79 pre-existing findings. * fix(gui): scope the account-pool in-flight counter to its reset The counter fence compared the seed key, which cannot tell A -> B -> A apart: the first A read's increment was discarded by the render-phase clear, yet its completion still matched the key and decremented the second A read's count, so refreshing went false while that read was still held. Tag each load with the reset epoch the clear advances, publish it from the same layout effect as the seed key, and release an increment only under the epoch that took it. A read superseded by a newer read on the same target keeps its own epoch and still releases its count, so the fence cannot be loadIsCurrent alone. The validation pause lease is unchanged: it is a Set, so its own finally's delete is idempotent and pauseCount is read from the live set. An old target's lease can still hold the new target's poll for the rest of its budget; that is pre-existing and outside this fix. Verification: the reviewer's ABA probe is red on 2702695 and green here; the new gui tests cover the ABA counter (red before this commit) and the same-target overlap release. gui pool and target suites 195 pass; gui oxlint 0/0; gui build passes; root typecheck, privacy scan, structure:check, repo-hygiene and file-size guards pass; react-doctor 0.9.11 changed scope over base c81be32 reports no issues. * fix(gui): reset the account pool's target-owned refs on a target change The render-phase clear emptied the rows but left two refs from the old target: a pending switch's reconciliation marker and the last /active payload. On the new target the marker spent its one stale-read allowance on the first /active answer, so the active id stayed empty until the next poll and the main account could look active. The payload seeded the old target's threshold and strategy into the new surface through readLastThreshold and readLastActive. Clear both in the layout effect that publishes the render identity, ahead of the new target's initial load and of any stale continuation, and key the last payload by the target that answered so a descendant reading before that effect still cannot see the old one. Verification: both new gui tests are red on d53fc13 (active id null instead of b6; readLastActive returns a7's payload) and green here; gui pool and target suites 197 pass, strategy and auto-switch consumers 92 pass; gui oxlint 0/0; gui build passes; root typecheck, privacy scan, structure:check, repo-hygiene and file-size guards pass; react-doctor 0.9.11 changed scope over base c81be32 reports no issues. * fix(gui): scope the account pool's mutation gates to their target The gates were process-wide: a switch, pause, order, auto-switch or credits write still held its ref across a relay re-pair, so the new target's action came back "busy" and the new target painted the old one's spinner. The release also compared the account id, which cannot tell two targets apart when they share one. Each gate now holds a MutationLease tagged with the target epoch. An action whose render predates the current epoch, or whose capture is stale, refuses before it touches the gate; a lease from another epoch does not block the new target; and only the exact lease that took the gate may release it. The target transition clears the visible busy state, so the new target starts idle. Verification: seven parameterized gui tests (switch, pause, priority, auto-switch, per-account credits, global credits, pause-exhausted) use the same account id on both targets, are red on ba8990b with the old target's busy value painted on the new one, and green here; each also asserts the same-target gate still answers "busy" and that the old target's completion leaves the new target's gate held. gui pool and target suites 258 pass; gui oxlint 0/0; gui build passes; root typecheck, privacy scan, structure:check, repo-hygiene and file-size guards pass; react-doctor 0.9.11 changed scope over base c81be32 reports no issues. * fix(gui): key a render capture by its request base, not only the logical target useRenderTargetCapture memoized on targetKey whenever one was supplied. A relay that re-pairs to the same hub keeps that key (the hub origin) while the request base and transport move from <machine>/api/machine/hub-relay to the hub itself, so the surface kept the relay capture and every targetFetch refused it until a remount. Include apiBase in the memo identity. The logical key still names the capture and the draft store, so a same-hub transport change does not discard a draft, and a module target change with unchanged props still keeps the old capture and sends nothing. Verification: the new relay-to-direct test is red on 8848ba5 (the old relay base is returned) and green here; the no-prop-change test holds the old capture and targetFetch answers 409 with zero requests in both. Focused capture, pool and target suites 298 pass; gui oxlint 0/0; gui build passes; root typecheck, privacy scan, structure:check, repo-hygiene and file-size guards pass; react-doctor 0.9.11 changed scope over base c81be32 reports no issues. * fix(gui): localize target_changed and drop stale pool action toasts Two generic paths still surfaced the raw wire token: the provider CRUD error helper and the key, alias and login callers read data.error directly, so a relay 409 showed "target_changed" instead of the localized copy. They now share errorMessageFrom, which maps that one token and passes every other code or message through unchanged. The pool's alias and remove handlers also reported a stale refusal as a failure toast on the new target. They now drop busy and stale the way pause, order, threshold and credits already do. The controller still returns stale before it reloads, so the new target's rows are untouched. Verification: the three pool caller tests show "target_changed" on abd4109 and the localized copy here; the alias and removal component tests show their failure toasts on abd4109 and none here, with the read count unchanged across the old write's completion. Focused suites 241 pass; full gui suite 4343 pass, 0 fail; gui oxlint 0/0; gui build passes; root typecheck, privacy scan, structure:check, repo-hygiene and file-size guards pass; react-doctor 0.9.11 changed scope over base c81be32 reports no issues. * fix(gui): fence provider pool reads on their captured target The provider pool updated serverRef in a passive effect and cleared the previous target's rows in a deferred microtask, so a roster, key or quota read issued for A that settled between B's commit and that flush still matched the generation and repainted A's emails, key labels and quota under B. accountSets and keyPools were also returned ungated, so the old target's rows could paint for a frame even without a late completion. Publish the render's target from a layout effect, require the captured target on every read, roster, quota, apply, catch and completion predicate, and clear the target-owned rows while rendering so the new target never paints the previous one. Same-target singleflight and the false obsolete result are unchanged. Verification: the reviewer's held-read probes are red on b244ed8 and green here; the new gui regression covers account and key late reads, held reads on the new target, an ABA round trip, late quota, late failure and a late account switch. * test(gui): wait for the target-change passive flush, not a timer The held-read-on-the-new-target case started the new target's read after a setTimeout(0). When the target-change passive cleanup had not flushed yet, that cleanup bumped the generation under the in-flight read, so a legitimate new-target query returned false. The same timer also made the P2 release window depend on scheduler order. Wait for the commit's passive effect itself: the probe's effect is declared after the hook, so its resolution is the barrier after the hook's cleanup and setup. The mount path no longer needs a timer either.
…stop churning the config directory (lidge-jun#8442) * fix(usage): keep the filter index's WAL sidecars so filtered queries stop churning the config directory * fix(usage): keep WAL sidecars only for this projection and truncate the kept WAL on close * fix(usage): checkpoint the kept WAL with TRUNCATE before the writer closes * fix(usage): register kept WAL sidecars beside a projection built before they persisted * fix(usage): keep checking sidecar ownership until both sidecars exist * fix(usage): register a crash-left projection file with its kept sidecars
…ds (lidge-jun#8459) * test(usage): name the input that moved when the warm aggregate rebuilds * test(usage): report the previous stage's recorded base and the filtered reads
…hem on failure (lidge-jun#8458) * test(rust): derive toolchain homes from the rustup proxy and report them on failure * test(rust): derive each unset toolchain home independently and report the default toolchain
…-jun#8463) * ci: refresh the Windows shard durations from batch 42694893702 * ci: pin the refreshed Windows duration table in the release evidence policy Appends a ci policy entry identical to the latest one except for the new scripts/ci/test-durations.windows.tsv blob, keeping earlier entries so historical revisions still verify.
…dows ChangeTime move (lidge-jun#8462) * test(usage): settle the per-write config ACL harden before recording the warm base * test(usage): read the warm base after the stage's work and name a Windows ChangeTime move The settle added before the refreshed aggregate drained no registered work: every config-directory harden it targets fires at startup and is already flushed there, and the per-save directory harden is synchronous inside the write. The batch payload only shows usage.jsonl's ChangeTime alone moving after refreshedAggregate recorded its revision. Read the base the next stage compares against after all of the stage's work. If that read is not warm, accept it only on Windows, only as a rebuild whose revision differs in ChangeTime alone with overlay version and time zone unchanged, and log the ChangeTime after each step so the next batch names the mover. * test(usage): require the tolerated Windows rebuild to show a ChangeTime move A rebuild whose revision is identical to the refreshed one, such as a discarded retained aggregate, no longer passes as a Windows ChangeTime move.
…dge-jun#8465) macos 3/4 hit its 20-minute limit in dev batch 42721779341 because the shared table was read from Ubuntu logs only. Refresh it from the passing test N/5 and macos N/4 jobs of run 42694893702, as the durations tool prescribes, and pin the new table in the release evidence policy.
… rows (lidge-jun#8466) * feat(anthropic): add Claude Fable 5.2 pricing, fast mode and provider rows Anthropic released Claude Fable 5.2 (claude-fable-5-2) on 2026-11-09. Without static rows the picker showed it with no price, max output or effort ladder, and its fast mode was not offered. - Anthropic seed: 1M context, 128K output, low..max effort, text+image input. - Fast mode: claude-fable-5-2 joins the anthropic-speed allowlist (Fable 5 and 5.1 still reject speed) with the 2x, response-confirmed priority price rule (16 / 80). - Price overlays at 8 / 40 / 0.20 cache read (0.025x) / 10 cache write for anthropic, anthropic-apikey, cursor (Cursor model page), devin and devin-cli (Devin model page). - Metadata snapshot + regenerated table: anthropic; Bedrock anthropic./global. (list) and us. (1.1x); openrouter (and its repriced fable-latest alias); source rows for github-copilot, kilo, vercel (+fast), venice and opencode-zen. - Opper pool and Devin static seeds; docs list Fable 5.2 among Anthropic Fast models. Cursor gets a price overlay only: its wire ids are not on the live roster yet, so no preemptive capability row. Sources: platform.claude.com Fable 5.2 overview, what's-new and pricing; cursor.com, docs.github.com, opper.ai and docs.devin.ai model pages; OpenRouter, Vercel, Kilo, Venice and models.dev APIs. Plan and audit: devlog/_plan/261110_fable_5_2_catalog/. * fix(usage): price Kilo fable-latest and Vercel Fable 5.2 fast; move Fable 5.2 pricing test to a sibling Kilo and Vercel are not generated metadata bundles, so their snapshot rows never reach the resolver; explicit overlays price both ids. The Fable 5.2 pricing cases move to tests/usage/usage-fable-5-2-pricing.test.ts so usage-cost.test.ts stays under the 2000-line ratchet, and the client-export roster now expects the Fable 5.2 fast selector. * docs(devlog): record Fable 5.2 catalog unit outcome * docs(providers): list the Fable 5.2 confirmed-fast rate
…-jun#8467) npm read the bare npm-artifact/package.tgz spec as a GitHub shorthand and ran git ls-remote, so the first dev-line publication (run 42763073267) failed before publishing anything.
…line (lidge-jun#8468) * fix(release): start the 2.100.0 changelog at the reviewed legacy baseline v2.99.0 was tagged on the retired main line, so the changelog fell back to the newest reachable stable, v2.42.0: a 4,960-commit range that exhausted the GitHub API and would exceed the 125,000-character release body. The reviewed legacy mapping in release-history.cjs now admits v2.99.0 and starts the range at its dev baseline. * fix(release): keep generated notes and the compare link inside the legacy range
…idge-jun#8469) * fix(anthropic): rank Fable accounts by its share of the weekly limit Claude's usage endpoint now reports weekly_scoped_shares, naming by raw limits index the share of the weekly limit a scoped family may consume (Fable: "up to 50% of your weekly limit"). The Fable window now carries it as weeklyAllowancePercent, and lowest-usage pool ranking restates Fable on the weekly scale, so an account at 60% Fable with 20 weekly points left no longer outranks one with 30. Auto-switch thresholds, exhaustion and route headroom keep their existing meaning. * fix(anthropic): keep five-hour ranking order for fresh Fable seats Five-hour pool ranking has no five-hour tie-break, so the weekly-scale Fable figure (50 for a fresh seat) masked every lower five-hour reading. Apply the conversion only under the weekly and max-utilization windows. * fix(anthropic): carry the weekly allowance only onto header readings A usage probe that reports no share is itself the current reading, so the merge must not restore the previous allowance onto it.
lidge-jun#8433) * fix(responses): reject malformed retained compact input * test: strengthen malformed compact envelope regression coverage * test: strengthen malformed compact envelope regression coverage * test: strengthen malformed compact envelope regression coverage * fix(responses): reject malformed retained compact input before credential refresh Co-Authored-By: Epinephrine <luvs01@hanmail.net> * docs: clarify malformed compact input in translated references * docs(responses): document retained envelope helpers Co-Authored-By: Epinephrine <luvs01@hanmail.net> * docs(responses): document the compact route entrypoint Co-Authored-By: Epinephrine <luvs01@hanmail.net> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…omain (lidge-jun#8472) The zone route needed an existing proxied DNS record for telemetry.opencodex.me, which does not exist, so a deploy left the hostname unresolvable and every client request failed. A Custom Domain creates the record and certificate on deploy.
…n#8401) * fix(sidecars): preserve identities across partial snapshots * fix(sidecars): update lookup only for newly learned indexes
…rences (lidge-jun#8434) Bound Mistral image pruning bookkeeping and replace malformed image references before dispatch. Co-authored-by: Epinephrine <luvs01@hanmail.net>
…arry of lidge-jun#8084) (lidge-jun#8473) * fix(kiro): request Identity Center profiles within the AWS page limit ListAvailableProfiles rejects maxResults above 10 with a 400 in every region, so every Identity Center login failed after AWS approved it. The test mock accepted any request; it now rejects an oversized page too. * fix(kiro): list Identity Center profiles without maxResults Maintainer follow-up to the carried fix from lidge-jun#8084. AWS rejects maxResults above 10 (400 ValidationException, observed in lidge-jun#8084), and another Kiro client reports 400 REQUEST_BODY_INVALID for any maxResults while an empty body works (Quorinex/Kiro-Go#164). Sending no page size and paginating with nextToken, as the code already does, works under both observations. The fixture now rejects any maxResults, so dev's 50 and a fixed 10 both fail the discovery tests. Co-authored-by: Mushikingh <164845020+mushikingh@users.noreply.github.com> * test(kiro): pin successful IAM profile pagination Page two must carry only nextToken (no maxResults) and both pages must be merged. Fails if maxResults returns on the continuation or nextToken is dropped; the existing tests covered only the first page and cycle rejection. Co-authored-by: Mushikingh <164845020+mushikingh@users.noreply.github.com> --------- Co-authored-by: Mushikingh <164845020+mushikingh@users.noreply.github.com> Co-authored-by: lidge-jun <lidge-jun@users.noreply.github.com>
… wait (lidge-jun#8422) Revalidate ownership after a spent publication wait and avoid caching a wait under a changed identity. Co-authored-by: Epinephrine <luvs01@hanmail.net>
…-jun#8083) * fix(venice): upscale inline images below the 64px minimum edge * fix(venice): bound and cancel minimum-edge upscales; keep openai-chat under its cap Maintainer carry on top of the contributor's Venice fix: - Move the image-preparation decision into prepareOpenAIChatImages (openai-chat-images.ts) so src/adapters/openai-chat.ts stays under its 822-line file-size cap; the registry lookup now runs once per adapter, not per request. - Upscales take the process-wide decode gate (enterImageDecode) shared with the other image normalizers, so concurrent Venice requests cannot each hold a decoded bitmap. - A cancellation during the last resize now rejects instead of building a request for a cancelled turn. - Two regression tests; both fail without this change. - Structure note: the aspect ratio is kept unless the 4096 clamp applies. Co-authored-by: tachyon6 <tachyon6@users.noreply.github.com> * docs(structure): state the Venice upscale aspect-ratio exception plainly Co-authored-by: tachyon6 <tachyon6@users.noreply.github.com> --------- Co-authored-by: lidge-jun <lidge-jun@users.noreply.github.com> Co-authored-by: tachyon6 <tachyon6@users.noreply.github.com>
…idge-jun#8474) Anthropic refuses claude-fable-5-2 below Claude Code 2.1.290 ("Claude Code 2.1.280 does not support this model"). The proxy-generated identity now presents 2.1.321 with @anthropic-ai/sdk 0.128.0 on runtime v26.12.1, the same baseline router-for-me/CLIProxyAPI#7392 measured for the identical 400.
Integrate the tagged stable release while retaining fork usage retention, transaction diagnostics, Hub entitlement querying, and signed releases. Reconcile dispatch and ledger contracts, preserve dependency pins, and align all version sources with the release tag for signed package binding. Split generated telemetry guidance to retain the chapter size contract. Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Codex Review Summary: ✅ CompletedThis 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. |
The stable update adds ocx-child sources to the package manifest. Include those files in the restricted Docker build context and package stage, and require them during archive verification to prevent incomplete releases. This ships source parity only; child execution still needs its expected prebuilt artifact. No compiler or package scripts run during packing. Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Keep the child source inventory contract in the existing release paragraph so the upstream structure documentation size guard remains satisfied. Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
00c02163e4352be5beb5633a3b6cc3b0be94ec8a) intocustom, preserving upstream ancestry, seven-day usage retention, transaction diagnostics, Hub entitlement versioning, and the signed numbered fork-release workflow.devupstream policy while retaining this fork'scustomtarget.Start review with runtime conflict resolutions and ledger compatibility, then the trusted CI branch selection and version-source correction. The fork archive now includes the upstream-declared ocx-child source files, with bounded inventory verification; this does not add automatic Rust compilation. The fork's numbered release workflow remains the release path; upstream's repository-specific release workflow is not used here.
Verification
git diff --checkis clean; upstream-owned whitespace was preserved unchanged. Merge signature and both parent identities were verified.Upstream GUI evidence from upstream PR #8471, using synthetic data; this is upstream evidence, not a new local rendering:
Checklist
Hosted policy readback:
customrequires PR integration but zero approvals and no status contexts. DCO reports inherited upstream commits without sign-offs; those commits are preserved. Cross-platform CI and PR target/hygiene workflows were already disabled and remain unchanged.