Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
5118a9d
fix(codex): refresh bundled catalogs without synchronous request probes
mashfromband Oct 8, 2026
a3b725a
fix(codex): isolate caller cancellation from shared catalog refreshes
mashfromband Oct 8, 2026
b3a5341
test(codex): check mutation isolation without an empty catch
mashfromband Oct 8, 2026
76dc4fb
test(codex): retain write-boundary guard with observed catalog input
mashfromband Oct 8, 2026
60fa182
Merge latest dev into catalog liveness fix and preserve runtime contr…
mashfromband Oct 8, 2026
5df82f8
fix(catalog): keep observed effort diagnostics nonblocking and test p…
mashfromband Oct 8, 2026
c54cf43
test: synchronize policy edits with worker load and own catalog fixtures
mashfromband Oct 8, 2026
9c5ddfe
fix: retain Windows ACL ownership across complete hardening flights
mashfromband Oct 8, 2026
b278ef8
style: format Windows ACL lifetime contract assertions
mashfromband Oct 8, 2026
df8276c
fix(runtime): dispose translator budgets on unread client abort
mashfromband Oct 8, 2026
9b93361
fix(runtime): preserve rendered cancellation envelopes
mashfromband Oct 8, 2026
8899dd5
fix(runtime): preserve terminal responses while releasing aborted bud…
mashfromband Oct 8, 2026
786e028
Merge remote-tracking branch 'origin/dev' into agent/agent-todo-1936-…
mashfromband Oct 8, 2026
9149843
fix(windows): retain both named and physical removal ownership
mashfromband Oct 9, 2026
39663ff
fix(test): preserve file IDs and settle Windows fixture owners
mashfromband Oct 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/workflows/catalog-async-contracts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Catalog async contracts

on:
push:
paths:
- src/**
- scripts/diagnostics/windows-version-control/**
- .github/actions/setup-project-bun/**
- .github/workflows/catalog-async-contracts.yml
- package.json
- bun.lock
pull_request:
paths:
- src/**
- scripts/diagnostics/windows-version-control/**
- .github/actions/setup-project-bun/**
- .github/workflows/catalog-async-contracts.yml
- package.json
- bun.lock
workflow_dispatch:

permissions:
contents: read

jobs:
contracts:
name: Catalog async contracts (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
- uses: ./.github/actions/setup-project-bun
with:
role: runtime
- uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master
with:
toolchain: stable
components: rustfmt, clippy
- name: Install repository dependencies
run: bun install --frozen-lockfile
- name: Check formatting
run: cargo fmt --manifest-path scripts/diagnostics/windows-version-control/Cargo.toml --check
- name: Check Rust contracts
run: cargo clippy --locked --manifest-path scripts/diagnostics/windows-version-control/Cargo.toml --all-targets -- -D warnings
- name: Run Bun-module contracts through the portable Rust fixture
run: cargo test --locked --manifest-path scripts/diagnostics/windows-version-control/Cargo.toml --test async_contracts -- --test-threads=4
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ gigabytes of RSS during long streaming sessions (reported as issue
[#314](https://github.com/lidge-jun/opencodex/issues/314)). This page explains
what is actually happening and what you can do about it, honestly.

## Model-list liveness

Model-list reads use the selected runtime's last confirmed bundled catalog while version and bundled-model checks refresh asynchronously. A cold or changed selection temporarily uses the existing catalog/cache or native fallback. Slow launchers and descendants holding stdout therefore do not block unrelated health checks in this path. This does not identify or fix every historical memory-growth or unresponsive-listener report in [#6671](https://github.com/lidge-jun/opencodex/issues/6671), and it does not add automatic request replay or service restart.

## Root cause: upstream Bun runtime issues

opencodex bundles the Bun runtime (currently **1.3.14**). The memory growth is
Expand Down
121 changes: 121 additions & 0 deletions scripts/diagnostics/windows-version-control/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions scripts/diagnostics/windows-version-control/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "ocx-version-control"
version = "0.1.0"
edition = "2024"
publish = false

[workspace]

[[bin]]
name = "ocx-catalog-fixture"
path = "src/fixture.rs"
test = false

[dependencies]
serde_json = "1"
windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_Security", "Win32_System_Threading", "Win32_System_ProcessStatus", "Win32_System_Diagnostics_ToolHelp", "Win32_System_Diagnostics_Debug", "Win32_System_JobObjects"] }
78 changes: 78 additions & 0 deletions scripts/diagnostics/windows-version-control/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Windows synchronous runtime-selection control

This optional Rust control exercises `GET /v1/models` in a separate Bun process
using the repository's unchanged `tests/helpers/native-main-owner-child.ts`.
It does not connect to a running proxy, install accounts, or replay turns.
It is a reproducer, not a runtime fix or proof of a historical production cause.

The child gets a cleared environment, synthetic homes, fixed fixture-only
authentication values, and an ephemeral loopback listener. It is configured
with no real credentials and one unavailable loopback provider. Other network
egress is not blocked or audited.

```powershell
cargo nextest run --locked --manifest-path scripts/diagnostics/windows-version-control/Cargo.toml --test-threads 10
cargo clippy --locked --manifest-path scripts/diagnostics/windows-version-control/Cargo.toml --all-targets -- -D warnings
cargo build --locked --release --manifest-path scripts/diagnostics/windows-version-control/Cargo.toml
& <target>/release/ocx-version-control.exe <absolute-bun.exe> <absolute-repo> <new-absolute-fixture-root> <absolute-node_modules> [cumulative|pipe] | Out-String
```

Use the shared Cargo gate and an isolated target directory where required by
your environment. Check the actual executable exit code after the output pipe.
The fixture root must not already exist. Bun must support `--no-env-file`,
`--no-orphans`, and CPU profiling. A startup/profile flag failure is not evidence
of the catalog stall. This control has only been executed on Windows.

The fake Codex executables initially return their version and bundled catalog
immediately. After a successful model-list warmup and a 16-second memo-expiry
wait, the controller arms the chosen mode and sends one model-list request:

- `cumulative`: three version candidates take 7.5 seconds each; the first two
return unrecognized versions and the last returns a valid version. This tests
accumulation across synchronous candidates rather than one overlong process.
- `pipe`: each version launcher prints a valid version, starts a 25-second
descendant inheriting stdout, and exits. This tests whether the per-candidate
timeout remains bounded while EOF is delayed. Different spellings of a path
and the bare fallback can resolve to the same executable; count the attempts
from `fake-events.jsonl`, not from the number of copied files.

The root starts suspended, is assigned to a kill-on-close Windows Job, and is
then resumed. Only this root and its descendants are terminated at cleanup.
The controller retains its process handle and creation time, checks initial
and final health identity, and measures two sequential 20-second health probes.
It records the failed I/O stage and error kind, without preserving the OS error
number. A read-stage failure does not establish that zero bytes arrived.
Two probes alone do not establish the exact beginning and end of a stall.

Private output includes `health-samples.jsonl`, `result.json`, synthetic child
stderr, `opencodex/fake-events.jsonl`, and `version.cpuprofile`.
The final result is written after successful shutdown, so inspect samples and
fake events even when the executable fails before publishing it. A successful
executable exit is not an automatic assertion that a long stall occurred:
inspect the actual health outcomes, model-list status, fake sequence, and CPU
call chain. Keep profiles and fixture artifacts private; publish bounded scalar
results and repository-relative function names instead.

To compare installed source with the repository fixture, use a separately owned
scratch mirror containing a byte-identical copy of the helper and package
metadata, with `src` and `node_modules` links to the desired installation.
The fixture must perform no writes to that installation. Links alone do not
enforce read-only access. Verify the profile's source module paths and source
hashes, and describe the fixture version and source version separately.
Remove only the mirror's own links during cleanup; never recurse into targets.

## Regression assertions

Pass --expect-responsive after the mode to expire both memos (61 seconds), observe health for 45 seconds during armed probes, and require matching 200 health, responsive model-list output, stable fixture model identities and successful fixture shutdown. --pin-change additionally writes a valid explicit selection during an armed version probe and requires its bytes to remain unchanged. The public list in this credential-free fixture contains its local provider row; model identity stability alone does not prove native bundled publication. The separate Rust-driven Bun contracts cover bundled source priority and publication.

The assertion cases use no real AI, accounts or production listener. A success verifies this isolated path, not the original production stall or a persistent leak. The descendants are finite-lived and contained in the root Job; this is not a test of arbitrary production orphan cleanup.

The module contracts run by default on Linux, macOS and Windows with a portable Rust fake Codex executable. Bun must be installed on PATH; OCX_CATALOG_TEST_BUN and OCX_CATALOG_TEST_REPO can override the executable and repository. Defaults resolve the Bun executable before clearing the child environment and derive the repository from Cargo's manifest location. No ignored tests or real credentials are required. The Windows-only synchronous liveness controller remains separate. The catalog-async-contracts workflow runs these real Bun-module contracts on affected pushes and pull requests as well as manual dispatch.

The removal-lifetime contract holds two successive injected normal Windows ACL commands before their outer deadlines fire. It verifies that the fixture removal barrier waits across both commands and the gap between them, the exact-path timeout indicator remains false, and the subtree guard clears after the whole harden settles. It exercises the existing Bun owner seams without real permissions or credentials.

The abort-lifetime contract uses synthetic response bodies whose cancellation remains pending. Both Responses and the shared HTTP finalizer release owned translator budgets on an already-aborted signal, a later abort, or explicit cancellation, while a live response retains its budget and successful EOF preserves bytes and response metadata.

Abort finalization changes accounting only; transports retain producer cancellation and terminal precedence. Prepared 200, 499 and 504 bodies remain unchanged. The alias-removal contract uses an owned junction or symlink to prove physical and alias roots wait for the same work, including a deleted temporary file, unreadable identity and a child name beginning with two dots; an unrelated sibling remains outside the guard.

The picker metadata contract injects two distinct full-width file IDs that round to the same number. It requires the pre-open/descriptor comparison to reject them before any credential-store access, using the existing Bun stat seams and synthetic public metadata.
Loading
Loading