Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,9 @@ Independent reviewer handle `01a0e348-c775-7a50-b2e5-25d11a5efb92` first returne

Append the exact branch/PR, source and CI SHA, commands/results, issue disposition, and D conclusion for later phases without claiming an unrun suite.
- **wp1 resume, 2026-09-28:** A successor task picked up the lane from the stopped thread's handoff, whose content is folded here, and removed the transfer note. The Codex P1 on #6097 (scoped key could reach Pool credential resolution before the scope check) is fixed by filtering forward candidates by admission scope before `resolveFirstUsableOpenAiSidecar`; see `010_images.md` "wp1 re-entry". An independent sol reviewer re-audited the plan (PASS) and re-verified all eleven non-carried verdicts in `001_candidate_inventory.md` against `origin/dev` `24b2f39b77` (AGREE on all; deferred PR heads unchanged).
- **wp1 D, 2026-09-28:** PR [#6097](https://github.com/lidge-jun/opencodex/pull/6097) (carry of #5927, @rrmlima credited by trailer) rebased onto `6d64ea26a7`, head `362d3df88e`. Adds the scope-before-credential filter and the client-cancel lease release on top of the original carry. Evidence: fixture red-green (`010_images.md`), `test:changed` 2,619 pass / 1 skip / 0 fail at `ad40e8d46a` (same tree for our paths), sol security review PASS after one accepted and one rebutted pre-existing finding. Merge waits on exact-head CI.
- **wp2 D, 2026-09-28:** PR [#6112](https://github.com/lidge-jun/opencodex/pull/6112) (carry of #5497, @hulkbig credited by trailer), head `95c59fc8da` on `dev`, code only; its devlog lives with this unit. Evidence: 261/261 focused, red-green 10/27 → 27/27, sol review PASS. `test:changed` selected most of the suite and hit the local 900 s wrapper limit under seven-lane lock contention; the flagged files reran 348 pass / 3 environment-only launcher failures (a real proxy on port 10100). Merge waits on exact-head CI. Did not improve: local broad coverage for this PR is left to hosted CI.
- **wp3 D, 2026-09-28:** comments on #4213, #4143 and #3765; #2511, #3506 and #5270 keep their existing maintainer dispositions (see `030_issues.md`). Direction change: the #4213 trial-prompt cause turned out to be fixable, so `wp5` (`050_trial_nux.md`) implements it before the `wp4` closing receipts.
- **wp4 D, 2026-09-28:** five deferred-PR dispositions posted after an independent audit (`040_integration.md`).
- **wp5 D, 2026-09-28:** #4213 trial-prompt fix opened as #6117 (`050_trial_nux.md`); a Codex P2 (surrogate pair split at the cap) was fixed with a red-green case.
- **wp6 D, 2026-09-28:** merged to `dev`: #6097 → `468b954cc4` (exact-head CI run 36334532836 plus `enforce-target` success), #6112 → `773c24bbbb` (run 36339549490 plus `enforce-target` success), #6117 → `890eb6d660`. #6117's earlier head `36bd4f2847` passed run 36341789245; the coordinator then replaced per-PR CI with local union checks and one final `dev` run, so after rebasing onto `2115563ca6` for a test-layout registry overlap it merged on 114/114 focused tests plus typecheck, structure and privacy checks. Squash commits keep the co-author trailers for #5927 (@rrmlima) and #5497 (@hulkbig); both originals were closed with thanks and links. #4213 has a follow-up naming both fixes and stays open for user confirmation. Post-merge Cross-platform CI on the final `dev` is run once by the coordinator after all lanes; this lane did not dispatch it. Did not improve: the #3765, #4143, #3506, #5270 and #2511 issues remain open, waiting on reporter data or design decisions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Require CI on #6117's final head before completion

Do not treat the earlier 36bd4f2847 run and local focused checks as a substitute for required CI on the rebased #6117 head: the rebase changed the union to resolve a test-layout overlap, yet 890eb6d660 was merged before its required checks—or even the promised final dev run—completed. The lane therefore records a merge that bypassed the repository's exact-head gate; obtain successful required CI for the final head and do not mark this phase complete on older-head evidence.

AGENTS.md reference: AGENTS.md:L238-L240

Useful? React with 👍 / 👎.

Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,5 @@ Plan, confirmed against `src/server/images.ts:667-760` at `acc750effa`:
- Tests: the two local WIP cases (forbidden Pool → 403 with zero sends; allowed Pool+model → 200 with the Pool bearer). Add one more: a key allowed only for the keyed provider falls through to the keyed branch without Pool resolution.

Review dispositions on #6097: the Codex co-author finding is already satisfied by the genuine trailer on `acc750effa`; the squash message will repeat it as a standalone trailer. The CodeRabbit request to apply an RFC 6750 `b64token` pattern to the managed Pool bearer is declined: the Pool token is a stored credential the proxy never builds from request input, the header is assembled through `Headers.set`, and a stricter local pattern would only turn an upstream 401 into a local 500 without closing a reachable path.
\nSecurity re-review (sol reviewer) of `46515c2a2e` returned FAIL with two findings, both present on `origin/dev` before this PR. Accepted: a client cancel during the in-flight Images send returned 499 without releasing a selected Pool account's recovery probe lease; the 499 branch now releases it, with a red-green fixture. Rebutted for this PR and recorded as follow-up: `selectImagesProvider` (`src/providers/openai-sidecar.ts:263,301`, unchanged here) resolves the keyed provider's API-key reference before the keyed branch scope check. That is a local config/keychain read with no network send or account-state change, and moving it changes keyed selection and error precedence for every Images caller; it belongs in a separate hardening change.\n

Security re-review (sol reviewer) of `46515c2a2e` returned FAIL with two findings, both present on `origin/dev` before this PR. Accepted: a client cancel during the in-flight Images send returned 499 without releasing a selected Pool account's recovery probe lease; the 499 branch now releases it, with a red-green fixture. Rebutted for this PR and recorded as follow-up: `selectImagesProvider` (`src/providers/openai-sidecar.ts:263,301`, unchanged here) resolves the keyed provider's API-key reference before the keyed branch scope check. That is a local config/keychain read with no network send or account-state change, and moving it changes keyed selection and error precedence for every Images caller; it belongs in a separate hardening change.
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,19 @@ This is one PR and one atomic runtime contract. Do not split observation from co
## Verification

Run `bun test tests/routing/fastwire-response-authority.test.ts tests/routing/fastwire-observability.test.ts tests/providers/model-rename-migration.test.ts tests/providers/provider-config-validation.test.ts tests/usage/usage-cost.test.ts tests/usage/cost-cap-unknown-evidence.test.ts`; these direct paths exercise the changed route, config and cost contracts. Also run `bun run test:changed`, `bun run typecheck`, `bun run privacy:scan`, `bun run structure:check`, `git diff --check`, and the docs-site frozen-install/build required by `docs-site/AGENTS.md`. The test fixture has a fake relay; it is not live evidence of a particular provider's billing. Record the resource exception for the local full suite and rely on completed exact-head required CI before merge. The PR credits @hulkbig with a `Co-authored-by` trailer, targets latest `dev`, and gets an independent review of the full current-dev diff.

## wp2 P stale check (2026-09-28)

Previous D (wp1): #6097 head `ad40e8d46a` verified (focused 19/19, `test:changed` 2,619 pass / 1 skip / 0 fail, sol security PASS); merge waits on exact-head CI. Direction kept: carry #5497 next.

A sol explorer re-mapped PR #5497 head `1152e3c9fc21` onto `origin/dev` `24b2f39b77`. No hunk is obsolete; the old docs anchors moved. Findings that amend the change map above:

- `src/providers/fastwire.ts:398` already reads `context.responseTierAuthoritative !== false`; the carry only copies the defined flag into `AttemptTierOutcome` near line 341.
- Context conflicts only (newer `fastEnabled` neighbours): `src/config/schema/leaf-validators.ts:299`, `src/server/auth-cors.ts:975` (editor roster is exhaustive at 1104; classify `"editor"`), `src/usage/log.ts:658,680`, `src/providers/openai-tiers-destination.ts:26`, `src/server/responses/core-normalize.ts:20`.
- `src/providers/model-rename-fields.ts:18` needs the field as provider-scoped `"none"`; its role union is exhaustive at 141.
- None of the grown files is listed in `tests/fixtures/file-size-baseline.json`, so no ratchet cap applies. The new `tests/routing/fastwire-response-authority.test.ts` needs both layout registries.
- Docs: English `reference/configuration/providers.md` (field row near 207; section before FastWire migration near 568, after the newer root `auto_review_model` section at 552), zh-cn providers (87, 175), and the Codex guide (134). `structure/gui-and-management-api.md` lost the old usage paragraph; place the note near lines 223/231.

Existing-user contract: omission keeps legacy authoritative relay semantics; canonical ChatGPT forwarding stays observational even with `true`; `false` changes evidence and pricing only, never the outbound tier or a local unsupported-route downgrade.

Audit amendment (sol reviewer, NEAR-PASS): `serviceTierContextFromOutcome` in `src/usage/cost.ts:441` checks the `canonical === "priority" && confirmation === "confirmed"` branch before the raw echo, and `normalizeAttemptTierOutcome` (`src/usage/log.ts:635`) does not tie the new flag to `confirmation`. The carry therefore gates **both** branches on `responseTierAuthoritative !== false`, as #5497's cost diff does, and the fixture covers a persisted record whose flag is `false` while `confirmation` says `confirmed`. No GUI, dashboard, usage-summary or CLI consumer needs a change: they read the outcome through the shared cost path.
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,10 @@ The existing opt-in `maxUpstreamBodyBytes` checks the final serialized outbound
## Verification

For each posted comment, read it back from GitHub and confirm number, body, open/closed state and link. A current source/merged-commit link is needed for any claim of resolution. For #4213 and #4143, no local user's app configuration is changed. If the diagnostic records arrive during this phase, amend this doc, run a separate repair cycle if a bounded regression is feasible, and update the issue with verified evidence.

## wp3 result (2026-09-28)

- #4213: diagnostic comment posted ([issuecomment-5857691131](https://github.com/lidge-jun/opencodex/issues/4213#issuecomment-5857691131)). It separates image-tool gating (client side: plan, feature flag, auth mode, model input modalities) from a failed Images call, links #6097 for the Pool admission failure, and names the trial-prompt cause: the live roster's `availability_nux` is dropped by `parseAccountModels`, so native rows keep the pinned `null`. The fix is `wp5` (`050_trial_nux.md`). Stays open.
- #4143: current-build reproduction request posted ([issuecomment-5857853055](https://github.com/lidge-jun/opencodex/issues/4143#issuecomment-5857853055)); stays open.
- #3765: `OPENCODEX_CACHE_DEBUG=1` two-turn comparison request posted ([issuecomment-5857853190](https://github.com/lidge-jun/opencodex/issues/3765#issuecomment-5857853190)); stays open.
- #2511, #3506, #5270: no new comment. An independent sol audit found the drafts repeated or contradicted the existing maintainer comments, and the posting conditions above (no current scoped decision / new evidence / landed Qoder client integration) are not met. The existing maintainer comments remain the recorded disposition; all three stay open.
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,15 @@ Dependency: `wp3`. Recheck every candidate's latest head, base, review state, an
## Evidence and final report

Append the current PR number, head SHA, exact check run URL/attempt/conclusion, merge SHA, original-PR closure link, issue disposition links, commands/exit codes, and remaining limitations to `000_plan.md`. The final user report lists each assigned PR and issue, the two carried methods, dev CI result, test scope, risk, and overlap files. If a required check or branch protection is pending, keep the relevant PR open and state its exact status instead of claiming completion.

## wp4 result (2026-09-28)

Deferred PRs stay open with an English disposition naming the blocking contract and re-entry proof, checked by an independent sol audit (FAIL on three overstated claims, PASS after revision):

- #5995 keyless Zen — [comment](https://github.com/lidge-jun/opencodex/pull/5995#issuecomment-5857896648): client identity minting and injected tools without a published third-party contract; needs OpenCode permission, three-turn tool fixture, security review.
- #3282 Copilot context tier — [comment](https://github.com/lidge-jun/opencodex/pull/3282#issuecomment-5857896879): tier advertised for any configured model; needs per-model verified windows and `modelContextTiers`/`modelContextWindows` interaction on current `dev`.
- #6003 first-output failover — [comment](https://github.com/lidge-jun/opencodex/pull/6003#issuecomment-5857897106): unbounded body read before rule match; timer armed only after headers; needs bounded read, one pre-dispatch deadline, cancellation fixtures, client-visible signal if required.
- #4732 registry cache — [comment](https://github.com/lidge-jun/opencodex/pull/4732#issuecomment-5857897341): snapshot traversal predates `snapshot-select.ts`; needs router-only split with benchmark.
- #3741 Antigravity TLS — [comment](https://github.com/lidge-jun/opencodex/pull/3741#issuecomment-5857897561): transport chosen before the physical-send egress decision (an integration gap; `dev` still fails closed); needs egress integration fixtures, security review with #5083, full exact-head CI.

Closing the carried originals #5927 and #5497 and checking post-merge `dev` CI moved to `wp6`, because both depend on the replacement PRs merging.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Phase 5 — #4213 trial prompt: account-scoped model availability NUX

Previous D (wp2): #5497 carry is PR #6112 at `95c59fc8da` (focused 261/261, sol review PASS); merge waits on exact-head CI alongside #6097. Direction change with reason: #4213 was planned as diagnosis only (`030_issues.md`). A sol explorer traced a concrete, fixable proxy-side cause for the trial-prompt half, so this phase fixes it, and `wp3` keeps only the comment follow-up.

## Cause

The public Codex client shows a model availability prompt only when a model row carries `availability_nux: { message }` (`openai/codex` `18344a972`: `codex-rs/tui/src/app/startup_prompts.rs:250-266`; type `codex-rs/protocol/src/openai_models.rs:222-224,277`). Behind OpenCodex, Codex reads the catalog written to `model_catalog_json`. OpenCodex fetches each account's live ChatGPT roster, but `parseAccountModels` (`src/codex/model-entitlements.ts:641-667`) keeps only slugs and `available_access_programs`, and native rows come from the pinned template where `availability_nux` is `null` (`src/codex/data/upstream-models.json:71`). An account-specific "try this model" prompt therefore cannot reach the app while OpenCodex owns the catalog. The Desktop trial UI source is not public, so this is the strongest verified candidate, not a captured trace.

## Change map

| Path | Action | Before → after |
| --- | --- | --- |
| `src/codex/model-entitlements.ts` | MODIFY | `parseAccountModels` also returns `availabilityNuxByModel`: only rows it already keeps, only a plain object whose `message` is a non-empty string after trim, capped at 2,000 characters, stored as `{ message }` (no other fields). `CachedAccountModels` carries it; `CodexModelEntitlementSnapshot` gains optional `availabilityNuxByAccount`, populated only for confirmed rosters, mirroring `accessProgramsByAccount`. |
| `src/codex/catalog/access-programs.ts` | MODIFY | `applyNativeAccessPrograms` additionally projects the NUX onto **bare native rows of the main account only**, when that roster is confirmed and lists the slug: set `availability_nux` to the live `{ message }`, otherwise `null`. Combo rows, native alias rows and account-bound (selector) rows get `availability_nux` removed, so a Pool account's prompt never shows and one account's prompt is never duplicated. Routed/derived/Reserve stripping elsewhere stays untouched. |
| `tests/codex-integration/codex-native-availability-nux.test.ts` | NEW | Fixture roster through `resolveCodexModelEntitlements` with a fake fetcher (main row with NUX, Pool row with a different NUX, malformed shapes) and the projection over catalog rows. Register in both layout registries. |
| `structure/catalog.md` (or the owner that documents access-program projection) | MODIFY | Document the NUX projection next to the access-program projection. |
| `docs-site/src/content/docs/guides/codex-integration.md` | MODIFY | One sentence: OpenCodex forwards the main account's live model availability prompt on native rows. |

The online `GET /v1/models?client_version=` fallback does not project access programs today (`src/server/index/serve-options.ts:1071-1110`); it stays unchanged here, and the plan records that parity gap.

## Activation and observable checks

1. Main account's confirmed roster lists `gpt-6-astra` with `availability_nux: { message: "M" }` → bare native `gpt-6-astra` row carries exactly `{ message: "M" }`.
2. Same roster without the field, or with `null`, and a stale on-disk row carrying an old NUX → row ends with `null`.
3. Unconfirmed main roster (fetch failure) → `null`; never an old value.
4. A Pool account's roster carries a NUX for the same slug → no bare row and no account-bound row shows it.
5. Malformed NUX (string, array, missing/empty/non-string message, extra fields) → dropped or reduced to `{ message }`; roster confirmation and access programs unaffected.
6. Combo and native alias rows claiming the slug → no `availability_nux`.

## Verification

`bun test` on the new file plus `codex-forward-access-programs-writer`, `codex-model-entitlements-program-shape`, `codex-convergence-account-selectors`, `reserve-catalog`, `gpt6-native-rows`, layout and ratchet guards; `bun run typecheck`, `structure:check`, `privacy:scan`, `git diff --check`, docs-site build; `test:changed` in the `/private/tmp` checkout. Red-green on the new file. Independent review. Separate PR against `dev`, linked from #4213; the issue stays open until a user confirms the prompt on a current build.

## Audit amendment (sol reviewer, NEAR-PASS)

The account boundary, both writer call sites and the later catalog steps were confirmed. One blocker folded in: the new test also drives **both on-disk writers** (retained sync and convergence, following the pattern in `tests/codex-integration/codex-convergence-account-selectors.test.ts:343`) and asserts the *written catalog* for the main-account NUX, its removal on a later roster without it, Pool isolation, and alias/selector cleanup. Recorded limitations: the bare row follows the account in the Codex home OpenCodex manages, which is the App's login only when the App uses that home; convergence already republishes the catalog even when unchanged (`src/codex/convergence.ts:614`), which predates this change. `tests/codex-integration/codex-catalog.test.ts` sits 11 lines under its cap and is not touched.
Loading
Loading