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
81 changes: 81 additions & 0 deletions devlog/_plan/260904_bug_backlog_closeout/000_research.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# 260904 bug backlog closeout — research

Goal: drive every bug-labeled OPEN issue and bug-labeled OPEN PR in lidge-jun/opencodex
to a terminal state (merged, superseded with attribution, or closed with rationale).

Session FSM: PABCD under an ACTIVE host goal (HOTL). Goalplan slug
`close-out-the-bug-backlog-of-lidge-jun-opencodex`.

## Board snapshot (captured at goal start, dev = 072df52eb)

### Bug-labeled open PRs (12)

| PR | Author | State | Base | Note |
|----|--------|-------|------|------|
| 3430 | ChickenBreast-ky | READY, all checks pass | dev | Closes #3428 |
| 3420 | ildunari | READY, all checks pass | dev | no Closes tag |
| 3405 | adtumk | READY, all checks pass | dev | Closes #3378 |
| 3403 | ianlyoo | READY, all checks pass | dev | Closes #3402 |
| 3401 | agentHits | READY, all checks pass | dev | Closes #3400 |
| 3432 | luvs01 | DRAFT | dev | lab file-URI privacy |
| 3407 | turin-dev | DRAFT, 33 behind | dev | integrations toggle |
| 3394 | kremnyi | DRAFT, 33 behind | dev | grok 4.6 responses |
| 3388 | zleo-ai | DRAFT, 44 behind | dev | grok sparse output |
| 3348 | RHODIZSECURITY | DRAFT, 33 behind | dev | 2338-line failover overhaul |
| 3332 | full999 | DRAFT, 66 behind | dev | claude combo capabilities |
| 3325 | luvs01 | DRAFT, checks FAIL | dev | workflow surface, unsponsored |

### Bug-labeled open issues (13)

Claimed by a PR: #3428 (3430), #3402 (3403), #3400 (3401), #3406 (3407).
Unclaimed: #3433, #3425, #3424, #3352.
needs-info: #3320, #3279, #3255, #3245, #1527.

## Verification constraint (user-stated, binding)

The local full suite is FORBIDDEN for this unit: no `bun run test`, no bare `bun test`.
Live GitHub CI (`gh pr checks`) is the authoritative verifier; CI already runs
Linux/Windows/macOS. At most one named focused test file may be run when a change
needs a local signal. This overrides the AGENTS.md PR-ready full-suite gate for
this session because the maintainer explicitly directed it.

## Attribution constraint

AGENTS.md `missing_coauthor_credit` and CREDITS.md: reimplementing, superseding,
carrying, or rebasing another author's PR REQUIRES a `Co-authored-by:` trailer
naming that author in a branch commit so it survives the squash. Prose credit is
not equivalent — GitHub reads the trailer, not the sentence.

## Repository permission

`gh api repos/lidge-jun/opencodex --jq .permissions` returns
`{"admin":true,"maintain":true,"pull":true,"push":true,"triage":true}`.
Squash-merge into dev is therefore available to this session. Branch rulesets
still require a reviewed PR; force-push and direct dev push remain refused.

## What "terminal" means for this unit (settled after plan audit round 2)

The plan auditor argued that only MERGED or CLOSED counts, and that a live PR or a
posted NEEDS_HUMAN is "deferred closure, not a terminal repository state." That is
rejected as the completion bar, deliberately, and the reason is recorded here so the
D-phase claim can be checked against a stated rule rather than a mood.

The goal contract this session was given names BLOCKED, NEEDS_HUMAN, UNSAFE, and NOOP
as terminal outcomes alongside DONE. Some items genuinely cannot reach CLOSED from
inside this session without lying or destroying information:

- #3255 asks for a product decision about matching official ChatGPT behavior. Closing it
to satisfy a counter would discard a legitimate request; inventing the product intent
would be worse.
- #3245, #3279, #1527 need evidence only the reporter has. Closing them before the
reporter answers converts a real bug into a silent one. `stale-needs-info.yml` exists
precisely because this project already decided how that timeout is owned.
- A workflow-surface change (#3325) requires maintainer sponsorship that admin rights do
not substitute for.

So the bar for this unit is: every item reaches a RECORDED terminal outcome, where
DONE means merged/closed and the non-DONE outcomes require (a) a named reason from the
goal contract, (b) evidence with file:line or a posted URL, and (c) a visible artifact on
the issue or PR itself. What is forbidden is the thing the auditor was right to attack:
an item left open with no posted artifact and no named outcome. Silence is not a
disposition. That distinction is the operative rule for wp3, wp5, and wp6.
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# wp2 — green merge train

Five bug PRs are review-ready with every check green. An independent Sol reviewer
read each diff against current dev. Results below; one is NOT safe to land.

## Merge set

### #3430 fix(server): allow image routes on loopback listener — @ChickenBreast-ky
SAFE-TO-MERGE. Adds exactly the two image POST paths to the loopback allowlist at
`src/server/index.ts:815`. The handler still applies API admission and origin checks
(`src/server/index.ts:1688-1692`), so the public listener stays credential-gated;
GET and sub-paths remain denied. Regression: `tests/loopback-listener-integration.test.ts:349`.
Closes #3428.

### #3420 fix(responses): preserve outputs missing call ids — @ildunari
SAFE-TO-MERGE. Repair is scoped to tool-output items with no nonempty `call_id` and a
representable output (`src/adapters/openai-responses.ts:995`); valid stateful outputs
pass unchanged and malformed ones fail closed. Regression:
`tests/openai-responses-passthrough.test.ts:2248`. No `Closes` tag — no issue to close.

### #3405 fix(opencode-go): satisfy provider wire contract — @adtumk
MERGE-WITH-NOTE. Destination matching is exact; session values are opaque hashes;
explicit headers win; config is not mutated. The PR body reports four full-suite
failures it attributes to the dev baseline, not to itself. Since this unit does not
run the local suite, the note is recorded rather than re-litigated: hosted CI on the
PR is green, which is this unit's authoritative verifier. Closes #3378.

### #3401 fix(cli): heal deleted cwd at launch — @agentHits
MERGE-WITH-NOTE. `isatty(0/1)` avoids Bun lazy stream construction
(`src/cli/star-prompt.ts:168`, `src/update/notify.ts:125`); both launchers recover to
`homedir()`. Test coverage is partial: `tests/update-notify.test.ts:139` proves the TTY
guard under an unlinked cwd but does not spawn a launcher subprocess. Accepted as a
follow-up, not a blocker. Closes #3400.

### #3403 fix(proxy): accept dotted ns.name tool echo — @ianlyoo
HOLD — do not merge in wp2. The reviewer found a dispatch-collision risk: dotted
aliases are inserted into `toolNsMap` at `src/server/responses/collaboration.ts:136-143`
with no collision detection. Tool names allow any non-control character
(`src/responses/namespace-tool-compat.ts` `isRepresentableName`), so
`{namespace:"a", name:"b.c"}` and `{namespace:"a.b", name:"c"}` both flatten to `a.b.c`;
the second silently overwrites the first, so a dotted provider echo can invoke the
wrong client tool. The undeclared-tool guard collapses both identities into one set
entry at `src/server/responses-undeclared-tool-guard.ts:98`. This sits on the
client-tool authorization boundary, so it is treated as a real blocker.

Disposition: keep #3403 open in wp2 and hand it to wp3 as a NAMED work item
(wp3 item "#3403 collision repair"). `maintainerCanModify` is true on
`ianlyoo:fix-dotted-tool-alias`, so wp3 pushes the collision fix onto the author's
branch, preserving @ianlyoo as PR author; if that push is refused, wp3 opens a
successor branch whose commit carries `Co-authored-by: Youngin (Ian) Lyoo`.
wp3 owns driving it to MERGED or CLOSED — a posted review alone does not discharge it.

## Merge order

`src/adapters/openai-responses.ts` is touched by both #3420 and #3405, in distant
hunks (~906-1141 vs ~1966-2008). Merge #3430 first (smallest, isolated), then #3420,
then #3405, refreshing between each so the second lands on the first's result.
Order: 3430 -> 3401 -> 3420 -> 3405.

## Accept criteria

- each merged PR reports `state=MERGED` with a `mergedAt` and a dev merge sha
- linked issues #3428, #3400, #3378 are CLOSED after their merge lands
- no local full-suite run; `gh pr checks` is the recorded evidence
- #3403 carries a posted review naming the collision with file:line
- #3403 is explicitly handed to wp3 as a named item, not left unowned

## Manual issue closing (audit residual)

`gh pr view --json closingIssuesReferences` returns EMPTY for all five PRs even though
the bodies contain `Closes #N`: GitHub only auto-closes when the PR merges into the
default branch (`main`), and these target `dev`. Every linked issue must therefore be
closed manually after its merge lands, quoting the dev merge sha.

## Merge mechanics (wp2 P-phase stale check, re-verified against the live repo)

Re-verified before executing: all four of #3430, #3401, #3420, #3405 report
`mergeable=MERGEABLE` with zero non-success checks. `mergeStateStatus=BLOCKED` is not a
CI failure — the `Protect dev` ruleset requires one approving review, and every PR sits
at `REVIEW_REQUIRED`.

Ruleset (`gh api repos/lidge-jun/opencodex/rules/branches/dev`):
`required_approving_review_count: 1`, `require_code_owner_review: true`,
`require_extra_approval_for_unattributed_changes: true`,
`allowed_merge_methods: ["merge", "squash"]` — rebase merges are off, so squash it is.

How the review requirement is satisfied: these are contributor PRs, so the maintainer
reviews and approves them normally. MAINTAINERS.md line 172 notes that the admin role
also holds a `pull_request` bypass, but a bypass is not the right instrument here —
"Authors do not approve their own pull requests" still governs, and the file requires
that any bypass use be RECORDED on the PR rather than inferred from a merge timestamp.
Since the maintainer is not the author of any of these four, an ordinary approving review
is both available and more honest, and it leaves the reasoning visible on the PR.
CODEOWNERS puts `@lidge-jun` on `/src/adapters/`, `/src/providers/`, `/src/codex/`,
`/src/server/`, and `/.github/`, so the same review satisfies code-owner sign-off.

Each approval carries the substantive finding from the independent review lane, so the
merge record shows what was checked — including the two MERGE-WITH-NOTE items (#3405's
claimed-baseline suite failures, #3401's partial launcher coverage).
107 changes: 107 additions & 0 deletions devlog/_plan/260904_bug_backlog_closeout/020_wp3_draft_pr_triage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# wp3 — draft bug PR triage

Seven draft bug PRs, reviewed by an independent Sol lane. Verdicts and the exact
blocking defect for each.

## #3432 @luvs01 — lab file URI privacy bypass — DRIVE-TO-GREEN
`src/lab/events/limits.ts:36` rejects standalone `file:` schemes, but ASCII tab/newline
inside the scheme normalizes to a valid file URL and evades `FILE_URI_RE`
(`"fi\nle:///..."` -> `file:///...`). Fix: strip/normalize URL whitespace before the
scheme test, add those regressions. Privacy-sensitive admission logic; not an auth path.
Comment on lines +6 to +10

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 Move the unshipped privacy-bypass analysis to scratch

This newly tracked section documents an unfixed file-URI privacy bypass and includes the exact whitespace-evasion input, so merging the commit publishes reproduction guidance while the referenced PR is still open. Remove this and the related open security triage from devlog/_plan/260904_bug_backlog_closeout/, keep it in .tmp/ until the fixes ship, and only then publish the closed outcome; repository policy explicitly prohibits tracking unreleased findings and bypass reasoning in devlog/.

AGENTS.md reference: AGENTS.md:L103-L110

Useful? React with 👍 / 👎.


## #3407 @turin-dev — integrations toggle truthfulness — DRIVE-TO-GREEN
PUT persists via `setCodexIntegrationEnabled` (`src/server/management/native-integration-routes.ts:309`)
but GET still feeds the stale startup `config` into `codexStatus`, and the UI trusts it
(`gui/src/pages/integrations/overview-clients.ts:239`), so the switch snaps back after a
live toggle. Also `gui/src/i18n/tr.ts:1523` mistranslates "resumable". Needs a
PUT-then-GET regression plus a rebase (33 behind).

## #3394 @kremnyi — Grok 4.6 Responses — DRIVE-TO-GREEN
Correct after three addressed review fixes. The `enforce-target` "failure" is a
cancelled run superseded by a higher-priority gate request, not a real failure.
Needs rebase + a fresh gate run + readiness boxes.

## #3388 @zleo-ai — Grok sparse terminal output — DRIVE-TO-GREEN
Opt-in, Grok-client-only snapshot reconstruction, fail-closed, well tested. 847 lines
but the production change is one coherent compatibility boundary. Needs rebase
(44 behind) and hosted CI evidence for its claimed-baseline failures.

## #3348 @RHODIZSECURITY — failover hardening — SUPERSEDE
2338 lines / 33 files / 8 commits spanning cooldown persistence, provider quota state,
API-key 401/429 rotation, lifecycle, stream preflight, policy fallback, and public
error contracts. Individual fixes are sound (hashed key identity at
`src/providers/key-failover.ts:88`, exhaustion normalization at
`src/server/responses/policy-fallback.ts:166`), but it changes multiple independent
invariants in one diff and still has a blocker: the duplicated target-incompatibility
matcher at `src/server/responses/core.ts:3936` omits the shared generic `tool_choice`
case, so some combo children abort instead of hopping. Security-review class (credentials,
401 handling, rotation, persistence). Split into a reviewable stack, every branch commit
carrying `Co-authored-by: RHODIZSECURITY`.

## #3332 @full999 — Claude combo capabilities + output budget — DRIVE-TO-GREEN
Output-budget handling at `src/adapters/anthropic.ts:904` is correct. Blocker: the
catalog fallback maps vendor `maxTokens` onto `maxInputTokens` at
`src/codex/catalog/provider-fetch.ts:907`, shrinking a 1M Claude input window to its
128k output ceiling. Fix the mapping to `maxOutputTokens`, assert the 1M window
survives, rebase (66 behind).

## #3325 @luvs01 — ignore fork PRs in dev bump guard — DRIVE-TO-GREEN (sponsorship)
The change is correct: an owner-qualified server-side `head` filter at
`.github/workflows/dev-version-bump.yml:129` stops a same-named fork branch from
satisfying the repository-owned idempotency guard. Both `hygiene` and `enforce-target`
fail for exactly one reason: `unsponsored_surface` — a workflow file needs maintainer
security review and the `maintainer-sponsored` label. This is a maintainer decision,
not a code defect.

## #3403 @ianlyoo — dotted ns.name tool echo — COLLISION REPAIR (carried from wp2)

Handed over by wp2. The PR is correct in intent and green on CI, but it inserts dotted
aliases into `toolNsMap` (`src/server/responses/collaboration.ts:136-143`) with no
collision detection. Independently verified: namespaces come straight from the inbound
Responses `tools` array — the schema accepts an arbitrary namespace object
(`src/responses/schema.ts:117`) and `parseRequest` copies any string namespace
(`src/responses/parser.ts:221`), while `isRepresentableName` rejects only control
characters (`src/responses/namespace-tool-compat.ts:34`). Dots are legal in both halves,
and the existing `NamespaceToolCollisionError` guard covers only the `ns__name` form.
So `{a, b.c}` and `{a.b, c}` both claim `a.b.c` and the later insertion wins, which can
dispatch a provider echo to the wrong client tool.

Repair: before registering a dotted alias, check whether it is already owned by a
different `{namespace, name}` identity; on conflict register neither dotted alias (fail
closed to the unambiguous `ns__name` form) rather than picking a winner. Same treatment
in `src/server/responses-undeclared-tool-guard.ts:98` so the guard never collapses two
identities into one grant.

The repair must satisfy three properties the auditor named, because a naive "skip the
second insertion" implementation would still be wrong:

1. ORDER-INDEPENDENT. Meeting the second owner must REMOVE or tombstone the first dotted
registration, not merely decline the second. Otherwise the winner depends on
declaration order in the caller's tools array, which is attacker-influenced.
2. OWNERSHIP INCLUDES ALL SPELLINGS. The conflict check compares against bare and
canonical `ns__name` wire names too, not only other dotted aliases — a dotted alias
that shadows an existing bare or canonical name is the same authorization confusion.
3. THE LEGITIMATE CASE SURVIVES. A uniquely owned dotted alias is still registered, so
the `default.apply_patch` echo that #3402 reported keeps working. Only ambiguous
spellings are suppressed, and both canonical forms always remain available.

Regression coverage in `tests/responses-undeclared-tool-guard.test.ts`: the existing
unique-dotted case must keep passing; add an ambiguous catalog asserted in BOTH
declaration orders (proving order-independence), and a dotted-versus-bare and
dotted-versus-canonical collision case, each asserting no cross-identity authorization.
Execution: push onto `ianlyoo:fix-dotted-tool-alias` (`maintainerCanModify` true) so
@ianlyoo stays the PR author; otherwise a successor PR with a `Co-authored-by` trailer.

## Accept criteria
Terminality follows the rule settled in `000_research.md` §"What terminal means".
- #3403 specifically must reach MERGED or CLOSED. Its blocker is a code defect this
session can fix and its author granted `maintainerCanModify`, so no external
dependency justifies leaving it live. wp2 already committed to that stronger bar and
wp3 inherits it verbatim.
- every other listed PR reaches MERGED, CLOSED, or a live PR whose ONLY remaining gate is
maintainer CI or a maintainer decision this session cannot make (sponsorship for a
workflow surface, product intent), with that gate named and its artifact posted.
- a posted review alone does NOT discharge an item; the reason must be a named terminal
outcome (BLOCKED / NEEDS_HUMAN / UNSAFE) with evidence, visible on the PR.
- any superseding branch carries a `Co-authored-by:` trailer for the original author
- workflow-surface changes get an explicit sponsorship decision recorded
Loading
Loading