-
Notifications
You must be signed in to change notification settings - Fork 1.1k
docs(devlog): close the 260914 triage round-lane unit #4558
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| # 260914 — Triage round lanes: two merge rounds, four worktree lanes | ||
|
|
||
| Status: OPEN. Opened 2026-09-14 KST. Owner: main orchestration session | ||
| `01a09bc0-bb13-7393-8526-785a3aeacb91`, goalplan slug | ||
| `opencodex-2026-09-14-triage-delivery-loop-hotl-o`. | ||
|
|
||
| ## Objective | ||
|
|
||
| Land 9-11 pull requests into `dev` across two merge rounds, then close the issues | ||
| and pull requests those merges resolve or supersede. The input is the 2026-09-14 | ||
| triage of 64 open PRs and 60 open issues; this unit is the delivery half of it. | ||
|
|
||
| ## Why this shape | ||
|
|
||
| The triage queue mixes two kinds of work that cannot be orchestrated the same way. | ||
| PRs #4528, #4529, #4511 and #4512 belong to outside contributors: the work there is | ||
| verification and merge, and nothing can be stacked on a fork branch. The remaining | ||
| items — the #4515 follow-up, #4519, #4530 and #4516 — are ours to author, and only | ||
| those can carry a branch chain. Treating the whole queue as one stack is the failure | ||
| mode this unit exists to avoid. | ||
|
|
||
| Ordering inside a chain follows gate speed, not importance. #4519 is the highest | ||
| priority item in the triage and it sits at the TOP of its lane, because it needs an | ||
| independent security review that can stall for days. A stalled bottom layer freezes | ||
| everything above it; a stalled top layer costs nothing once its parent has landed. | ||
|
|
||
| ## Verified repository facts (2026-09-14) | ||
|
|
||
| These were read live and decide the merge mechanics. Refresh before acting on them. | ||
|
|
||
| - `dev` ruleset carries `deletion`, `non_fast_forward` and `pull_request` | ||
| (1 approval, code-owner review required). There is **no** required-status-check | ||
| rule and **no** strict up-to-date rule, so a `dev` move does not mechanically | ||
| invalidate another PR's checks. Batch merging disjoint PRs inside one CI | ||
| generation is therefore sound, and the residual risk is semantic, not textual. | ||
| - Cross-platform CI runs in 9-11 minutes (runs observed 2026-09-13T16:54-17:03 and | ||
| 17:12-17:23). | ||
| - Contributor fork PRs sit at `action_required`: their workflow runs have never | ||
| executed. #4528 and #4529 both show this. Approving those runs is the first | ||
| merge-track action, not the last. | ||
| - `src/web-search/passthrough-bridge.ts` holds both `resolveOllamaWebSearchEndpoint` | ||
| (119-243) and `sidecarSettingsForBridge` (689). The two lane-A layers collide in | ||
| one file, which is what makes lane A a real chain rather than two parallel PRs. | ||
|
|
||
| ## Lane map | ||
|
|
||
| Four `environment: worktree` threads. Write-sets are disjoint by construction; that | ||
| disjointness is what licenses the batch merge above. | ||
|
|
||
| | Lane | Orchestrator | Bottom layer | Top layer | Write set | | ||
| |---|---|---|---|---| | ||
| | L1 | `anthropic/claude-opus-5` high | sidecar backend/model agreement | #4519 endpoint destination policy | `src/web-search/`, `src/server/responses/core.ts` (~6290) | | ||
| | L2 | `kimi/k3[1m]` high | catalog parser preserves `supportsImages` | capability propagation + override precedence | `src/adapters/devin/`, `src/codex/catalog/provider-fetch.ts` | | ||
| | L3 | `anthropic/claude-opus-5` high | #4516 spare-budget argument restoration | budget/ordering regressions | `src/adapters/cursor/` | | ||
| | L4 | `kimi/k3[1m]` high | #4529 carry, version-skew refusal plus its unknown-version case | #4512 live-failure regressions | `src/cli/index.ts`, `src/cli/system-restart-client.ts`, `tests/cli/`, `tests/server/audio-dictation.test.ts` | | ||
|
|
||
| Lane A's top layer is security-gated. If it stalls past round 2, cut it loose from | ||
| the chain and re-base it directly on `dev` rather than holding the lane open. | ||
|
|
||
| L4 is not a tests-only lane. The #4529 carry writes `src/cli/index.ts` and | ||
| `src/cli/system-restart-client.ts`, so it carries the same structure obligation as | ||
| any other source change. Structure owners per lane: L1 `structure/runtime.md`; | ||
| L2 `structure/catalog.md` and `structure/adapters/registry.md`; L3 | ||
| `structure/runtime.md` and `structure/providers/cursor.md`; L4 the owner of | ||
| `src/cli/`. Each lane resolves its owner from `structure/INDEX.md` at its own P and | ||
| updates the doc in the same PR, because `bun run structure:check` fails on a doc | ||
| that no longer matches the tree. | ||
|
|
||
| ## Worker policy | ||
|
|
||
| Two surfaces, each doing what it is for. A **lane** needs its own branch, its own | ||
| CI and its own merge, so every lane is a `create_thread` task with | ||
| `environment: worktree`. A **worker inside a lane** is a bounded slice of that | ||
| lane's own tree, so it is a subagent, spawned by the lane thread into the lane's | ||
| worktree. Subagents belonging to different lanes cannot collide because the | ||
| worktrees differ. | ||
|
|
||
| Four lane threads: `anthropic/claude-opus-5` on L1 and L3, `kimi/k3[1m]` at high | ||
| effort on L2 and L4. Each lane loads `$codexclaw:cxc-loop` and runs its own scoped | ||
| PABCD cycle with its own goal and FSM, because a thread owns both. | ||
|
|
||
| Inside a lane, workers are `devin/swe-2` and `xai/grok-4.6` subagents at roughly | ||
| 2:3, with no cap on count. Both ids are accepted by `spawn_agent` even though | ||
| `devin/swe-2` is absent from the advertised override list in the tool description; | ||
| that omission was verified as a documentation gap on 2026-09-14, not a real | ||
| restriction. Only one subagent writes at a time, and no subagent runs a | ||
| branch-level git operation. | ||
|
|
||
| ## Proof policy | ||
|
|
||
| No local product suite, typecheck, build or install. Every PR body labels them | ||
| NOT RUN. The only proof is hosted Cross-platform CI at the exact head SHA, | ||
| dispatched explicitly with `gh workflow run ci.yml --ref <branch> -F lane=all`, | ||
| because a sync or rebase does not reliably queue it. Non-tip chain commits carry | ||
| `[skip ci]`. Pushes are `--no-verify` and fast-forward only; no shared branch is | ||
| force-pushed. Each round closes with one post-merge `dev` run as the joint proof | ||
| for that batch. | ||
|
|
||
| ## Work-phase map | ||
|
|
||
| | Phase | Outcome | Depends on | | ||
| |---|---|---| | ||
| | wp1 | This roadmap, at diff level, before any lane dispatch | — | | ||
| | wp2 | Round 1: lanes created, bottom-layer PRs, merge-track approvals, batch merge, post-merge dev CI | wp1 | | ||
| | wp3 | Round 2: top-layer PRs, retarget after parents land, batch merge, post-merge dev CI | wp2 | | ||
| | wp4 | Closure sweep: resolved issues closed with merge references, superseded PRs and issues closed with written reasons | wp3 | | ||
|
|
||
| Phase documents: `010_wp2_round1.md`, `020_wp3_round2.md`, `030_wp4_closure.md`. | ||
|
|
||
| ## Out of scope | ||
|
|
||
| #4022, #4259, #2562, #3283, #3742, #3738, #4020 and #4299; any account-pool | ||
| redesign; any Lab import into `src/router.ts`, `src/server/lifecycle.ts` or | ||
| `src/server/responses/core.ts`; security write-ups in any tracked directory | ||
| (scratch only, per AGENTS.md); rewriting another maintainer's branch; and the | ||
| uncommitted `src/codex/inject.ts` and `src/codex/sync.ts` changes observed in the | ||
| parent checkout, whose author was never identified. | ||
|
|
||
| ## Terminal outcomes | ||
|
|
||
| DONE needs 9 or more PRs merged, each with a CI run id at its merged SHA or an | ||
| explicitly recorded decision to merge without observing CI, both rounds closed with | ||
| a post-merge `dev` run, the named issues closed with merge references, and the | ||
| superseded set closed with written reasons. NEEDS_HUMAN is reserved for the | ||
| security review on #4519 and #4528. A heartbeat firing, a wait timeout or a | ||
| compaction is none of these. |
184 changes: 184 additions & 0 deletions
184
devlog/_fin/260914_triage_round_lanes/010_wp2_round1.md
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| # 010 — wp2: Round 1 | ||
|
|
||
| Bottom layers plus the clean half of the merge track. Target: five PRs merged into | ||
| `dev` in one CI generation, closed by a post-merge `dev` run. | ||
|
|
||
| Every source fact below was read live on 2026-09-14 by read-only recon agents. | ||
| Re-verify line numbers before editing; `dev` moves. | ||
|
|
||
| ## Round 1 contents | ||
|
|
||
| | # | Branch or PR | Owner | Deliverable | | ||
| |---|---|---|---| | ||
| | 1 | `codex/260914-l1-bridge-backend-model` | L1 | sidecar model bound to the bridge backend | | ||
| | 2 | `codex/260914-l2-devin-catalog-supports-images` | L2 | catalog parser preserves field 5 as true/false/unknown | | ||
| | 3 | `codex/260914-l3-cursor-spare-budget` | L3 | spare-budget restoration of recent invocations | | ||
| | 4 | #4511 (`maoxin1234:fix/vision-native-model-capabilities`) | main | merge as-is | | ||
| | 5 | #4512 (`maoxin1234:fix/audio-outcome-accounting`) | main | merge as-is | | ||
|
|
||
| ## L1 bottom — bridge backend/model agreement | ||
|
|
||
| File: `src/web-search/passthrough-bridge.ts`. | ||
|
|
||
| `sidecarSettingsForBridge` (677-705) takes `sidecar.model` from the global | ||
| `config.webSearchSidecar` blob without checking that the global backend equals the | ||
| bridge backend, and `core.ts:6290-6296` passes that blob whole. A global | ||
| `{backend:"openai", model:"gpt-5.6-luna"}` therefore reaches | ||
| `runAnthropicWebSearch` when a provider sets `webSearchBridge.backend: "anthropic"`. | ||
| Credentials do not leak — `resolvePassthroughWebSearchBridgeAuth` (155-181) | ||
| inspects only the named backend — so this is a model and settings defect, not a key | ||
| defect, and the PR body must say exactly that. | ||
|
|
||
| ```diff | ||
| - sidecar?: Pick<OcxWebSearchSidecarConfig, "model" | "reasoning" | "xSearch">; | ||
| + sidecar?: Pick<OcxWebSearchSidecarConfig, "backend" | "model" | "reasoning" | "xSearch">; | ||
|
|
||
| - const model = backend === "anthropic" ? sidecar.model ?? DEFAULT_ANTHROPIC_BRIDGE_MODEL | ||
| - : backend === "xai" ? sidecar.model ?? DEFAULT_XAI_BRIDGE_MODEL | ||
| - : backend === "gemini" ? sidecar.model ?? DEFAULT_GEMINI_BRIDGE_MODEL | ||
| - : sidecar.model ?? DEFAULT_OPENAI_BRIDGE_MODEL; | ||
| + const model = modelForBridgeBackend(backend, sidecar); | ||
| ``` | ||
|
|
||
| `modelForBridgeBackend` applies `sidecar.model` only when | ||
| `resolveSidecarBackend(sidecar.backend) === backend`, and otherwise returns the | ||
| backend default. Reuse `resolveSidecarBackend` from `src/web-search/index.ts`; do | ||
| not invent a second resolver. `planWebSearch` (index.ts:112-208) already pins the | ||
| backend first and is the precedent to follow. | ||
|
|
||
| Tests go in `tests/web-search/web-search-passthrough-bridge.test.ts`: a global | ||
| openai model with an anthropic bridge yields `claude-sonnet-5`; a matching backend | ||
| keeps the override; repeat the matrix for xai and gemini. Structure owner is | ||
| `structure/runtime.md`, hosted-search bridge contract at L238-247. | ||
|
|
||
| Destination policy stays out of this layer. That is L1 top. | ||
|
|
||
| ## L2 bottom — Devin catalog preserves supportsImages | ||
|
|
||
| File: `src/adapters/devin/cloud-direct/catalog.ts`. | ||
|
|
||
| `parseCatalogBuffer` (107-141) has arms for fields 1, 4, 18 and 22 and no default, | ||
| so `ClientModelConfig` field 5 is dropped by omission. `disabled` defaults to | ||
| `false` when absent; image support must not copy that pattern, because an absent | ||
| field has to stay unknown. That is the #1796 precedent, and Antigravity already | ||
| implements the tri-state at `src/providers/antigravity-models.ts`:587-592. | ||
|
|
||
| ```diff | ||
| export interface ModelCatalogEntry { | ||
| modelUid: string; label: string; disabled: boolean; contextWindow?: number; | ||
| + /** ClientModelConfig #5. Present true/false asserts; omitted means unknown. */ | ||
| + supportsImages?: boolean; | ||
| } | ||
| + let supportsImages: boolean | undefined; | ||
| } else if (sf.num === 4 && sf.wire === 0) { disabled = sf.value === 1n; | ||
| + } else if (sf.num === 5 && sf.wire === 0) { supportsImages = sf.value === 1n; | ||
| byUid.set(modelUid, { modelUid, label: label || modelUid, disabled, | ||
| ...(contextWindow > 0 ? { contextWindow } : {}), | ||
| + ...(supportsImages !== undefined ? { supportsImages } : {}), | ||
| }); | ||
| ``` | ||
|
|
||
| Extend the file-header schema comment with `#5 supportsImages bool` in the same | ||
| commit; the comment is the only schema documentation this parser has. | ||
|
|
||
| Test: extend `"the catalog parser reads the per-account context window"` in | ||
| `tests/providers/devin-adapter.test.ts` (300-323) with three cases built from | ||
| `encodeVarintField(5, 1)`, `encodeVarintField(5, 0)` and omission, asserting | ||
| `true`, `false` and `undefined`. Encoder helpers already exist at | ||
| `src/adapters/devin/cloud-direct/wire.ts`:54-63. | ||
|
|
||
| PR #4511 touches only `src/vision/eligibility.ts` and its test, so there is no file | ||
| overlap. Do not wait on it and do not restack into it. | ||
|
|
||
| Corrections returned by L2 after doing the work: `encodeVarintField` is at | ||
| `wire.ts`:63-65, not 54-63; `parseCatalogBuffer` spans 107-142; the file-header | ||
| schema comment omits field 18 as well as field 5, so the patch documents both and | ||
| carries per-field provenance instead of a blanket "verified against extension.js" | ||
| claim, because field 5 identity is corroborated from external ClientModelConfig | ||
| documentation rather than re-read from the vendor bundle. For this layer the only | ||
| structure owner that actually documents the Devin adapter in prose is | ||
| `structure/adapters/registry.md`; `structure/catalog.md` has no Devin mention and | ||
| owns the round-2 provider-fetch surface instead. | ||
|
|
||
| ## L3 bottom — Cursor spare-budget restoration | ||
|
|
||
| File: `src/adapters/cursor/protobuf-request.ts`. The per-call 2 KiB cap | ||
| (`CURSOR_INVOCATION_ARGUMENTS_BYTE_LIMIT`, line 84) is applied at envelope | ||
| construction in `toolCallArgumentsText` (937-967) and never revisited, even when | ||
| almost all of the 192-root and 512 KiB envelope is unused. A 4,693-byte successful | ||
| call loses its tail inside a 6,011-byte replay. | ||
|
|
||
| Insert a second pass after `selected` is assembled (near line 694) and before the | ||
| return. It spends only leftover aggregate bytes, newest `toolResult` first, skips | ||
| `outputElided` roots, and never evicts a retained root. It does not remove the cap: | ||
| admission still uses the 2 KiB prefix. | ||
|
|
||
| Two review-surviving details from recon: | ||
|
|
||
| - Gate on `echoToolResultInRoot && replayedCalls` rather than | ||
| `externalModel && replayedCalls`. Native `composer-2.5` echoes results into roots | ||
| but is not an external wire model, so the narrower gate would leave it capped. | ||
| - Use the callback form of `String.prototype.replace` so replacement patterns | ||
| appearing inside serialized arguments are not expanded by the replace call. | ||
|
|
||
| The two existing 600 KiB tests in | ||
| `tests/providers/cursor/cursor-tool-result-invocation.test.ts` stay unchanged and | ||
| must stay green: `"PROBE a huge argument must not evict the result output from root | ||
| replay"` (244) and `"the truncated invocation line stays within the declared | ||
| argument budget"` (261). They are the proof that the cap still bites under | ||
| pressure. | ||
|
|
||
| The PR body states that this claims nothing about #3506 causation. The four | ||
| rejected patches there were 1,648, 1,396, 1,670 and 1,900 bytes, all under the cap. | ||
|
|
||
| ## Merge track in round 1 | ||
|
|
||
| Every contributor PR has Cross-platform CI queued and stuck at `action_required`; | ||
| none has ever executed a job. Approving those runs is the first action of the | ||
| round, not the last. | ||
|
|
||
| - #4511 at `6d926244101cb6234b66634464007268a06b1d89`: no outstanding reviewer ask, | ||
| non-draft, readiness 4/4. Approve CI, wait for green, merge. | ||
| - #4512 at `0235ce604cb907185295e42b05754d11d11a0bb2`: non-draft, readiness 4/4, | ||
| one open CodeRabbit ask for live `handleExternalLive` regressions. Do not push a | ||
| carry commit onto that branch. The readiness gate binds to the exact head, so a | ||
| new push resets the checklist and re-drafts the PR. Merge as-is and deliver the | ||
| asked coverage as our own follow-up PR in round 2. | ||
| - #4528 (2/4) and #4529 (0/4) are drafts. Approve their CI in round 1 so round 2 | ||
| has real information, but plan them as carries rather than direct merges. | ||
|
|
||
| ## Merge and proof mechanics | ||
|
|
||
| Each lane pushes with `--no-verify`, fast-forward only. Non-tip chain commits carry | ||
| `[skip ci]`. For each PR, dispatch CI explicitly, because a sync or rebase does not | ||
| reliably queue it: | ||
|
|
||
| ```sh | ||
| gh workflow run ci.yml --ref <branch> -F lane=all | ||
| ``` | ||
|
|
||
| One ruleset term the batch argument has to respect: | ||
| `require_extra_approval_for_unattributed_changes` is true on `dev`. A carry that | ||
| replays another author's commits can therefore need an approval beyond the standard | ||
| one. The mitigation is to author each carry as our own commits with a | ||
| `Co-authored-by` trailer rather than cherry-picking the contributor's commits; the | ||
| trailer is what GitHub reads for credit, and the change stays attributed to the | ||
| pushing author for the ruleset. | ||
|
|
||
| Wait for that run at the exact head SHA, then merge. Because `dev` carries no | ||
| required-status-check rule and no strict up-to-date rule, the five PRs may merge | ||
| back to back inside one generation; their write-sets are disjoint, so the residual | ||
| risk is semantic rather than textual. Close the round with one post-merge `dev` | ||
| Cross-platform CI run and record its id. | ||
|
|
||
| Every PR body fills Summary, Verification and Checklist, and states plainly that | ||
| the local suite, typecheck, build and install were NOT RUN, naming the hosted run | ||
| id and SHA as the only proof. | ||
|
|
||
| One thing the lanes discovered that makes this policy stronger than intended: a | ||
| fresh lane worktree has no `node_modules`, so a focused `bun test` cannot execute | ||
| at all without `bun install`. Local focused runs are therefore impossible in a lane | ||
| rather than merely disallowed, and hosted CI is the only evidence that could exist. | ||
| The one check that runs without install is `bun run structure:check`, used for | ||
| debugging the doc gate and never cited as proof. | ||
|
|
||
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 28807
Reconcile the Round 1 count with the later records.
This document defines Round 1 as five PRs and omits
#4545.020_wp3_round2.mdsays Round 1 landed six PRs, and040_outcome.mdrecords#4545as a Round 1 merge. If#4545was added after this plan was written, record that scope change and update the target. Otherwise, correct one of the records. The count controls batch closure and CI proof.Also applies to: 11-17
🤖 Prompt for AI Agents