From 2445484574cb767b90f682daaf3591966c8f68c0 Mon Sep 17 00:00:00 2001 From: Mohid Makhdoomi Date: Sun, 31 May 2026 16:26:53 -0400 Subject: [PATCH 01/11] chore(porch): bugfix-905 init bugfix --- .../status.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml diff --git a/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml b/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml new file mode 100644 index 000000000..efd4b0547 --- /dev/null +++ b/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml @@ -0,0 +1,14 @@ +id: bugfix-905 +title: investigate-flaky-session-mana +protocol: bugfix +phase: investigate +plan_phases: [] +current_plan_phase: null +gates: + pr: + status: pending +iteration: 1 +build_complete: false +history: [] +started_at: '2026-05-31T20:26:53.743Z' +updated_at: '2026-05-31T20:26:53.743Z' From c9950538b85ea0c07f902577456069400c28c35d Mon Sep 17 00:00:00 2001 From: Mohid Makhdoomi Date: Sun, 31 May 2026 16:36:37 -0400 Subject: [PATCH 02/11] [Bugfix #905] Fix: replay EXIT frame to clients that connect after PTY exit Fast-exiting commands (e.g. `exit 1`) could finish before SessionManager connected its client. The shellper broadcast the EXIT frame only to clients connected at exit time, so the late-connecting client never learned the session ended and hung until the 15s test timeout. WSL/slow disk widened the race, which is why the session-manager integration tests timed out locally while passing (when not skipped) elsewhere. Retain exit info after the PTY exits and replay an EXIT frame to any client that connects post-exit (during the HELLO/WELCOME handshake). Adds a regression test that exits the PTY before connecting and asserts the client still receives an EXIT frame. Co-Authored-By: Claude Opus 4.7 --- codev/state/bugfix-905_thread.md | 48 +++++++++++++++++++ .../__tests__/shellper-process.test.ts | 33 +++++++++++++ .../codev/src/terminal/shellper-process.ts | 20 +++++++- 3 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 codev/state/bugfix-905_thread.md diff --git a/codev/state/bugfix-905_thread.md b/codev/state/bugfix-905_thread.md new file mode 100644 index 000000000..c8e77a625 --- /dev/null +++ b/codev/state/bugfix-905_thread.md @@ -0,0 +1,48 @@ +# bugfix-905: Investigate flaky session-manager integration tests + +## Investigate phase + +### Findings so far +- 3 affected tests in `packages/codev/src/terminal/__tests__/session-manager.test.ts`: + - `respects maxRestarts limit` (~1020) + - `logs session exit without stderr tail (stderr goes to file)` (~1724) + - `no stderr tail logged for file-based stderr (Bugfix #324)` (~1834) +- All integration tests spawn a real shellper via `dist/terminal/shellper-main.js` + (resolved relative to the test file: `../../../dist/terminal/shellper-main.js`). +- **Original `skipIf(CI)` intent** (commit fd012108e, Spec 0104): skipped in CI because + node-pty native module resolution fails in child processes on GitHub Actions. Expected + to run locally. + +### Leading hypothesis +The default `pnpm test` (`vitest`) does NOT build `dist/` first (only `test:e2e`/`test:e2e:cli` +run `pnpm build`). In a fresh worktree `dist/terminal/shellper-main.js` is absent, so spawning +the shellper fails / never emits `session-exit` → 15s test timeout. Root cause = missing build +artifact dependency, not a deadlock in the code under test. + +Verifying: reproduce timeout w/o dist, then build dist and re-run. + +### ROOT CAUSE (confirmed) — not missing dist +- Without dist: tests fail fast (~120ms) with "Invalid shellper info JSON" (spawn can't find script). +- With dist built: the 3 tests genuinely time out at 15s each (45.98s total). Real bug, env-amplified. +- node-pty itself works fine locally (direct spawn test passes). +- **The bug**: `ShellperProcess` broadcasts the EXIT frame only to clients connected + *at exit time* (`shellper-process.ts` pty.onExit → broadcast). `handleHello` sent + WELCOME + REPLAY but never an EXIT frame. Fast-exiting commands (`exit 1`/`exit 0`) + finish before `SessionManager.createSession` connects its client (spawn → read info → + waitForSocket → connect), so the EXIT broadcast reaches nobody and the client hangs + → `session-exit`/`session-error` never fires → 15s timeout. WSL/slow disk widens the race. +- Why local-only & flaky: CI skipped these (node-pty child-proc resolution); locally they + were racy and lost the race on slow filesystems. + +### FIX (`shellper-process.ts`) +- Retain `exitInfo` when the PTY exits; reset on (re)spawn. +- In `handleHello`, after WELCOME+REPLAY, if already exited, replay the EXIT frame to the + late-connecting client. No double-send (broadcast only hits already-connected clients). +- Regression test in `shellper-process.test.ts`: exit BEFORE connect, assert client still + gets EXIT frame. +- Kept `skipIf(CI)` — node-pty-on-CI rationale is independent of this race and still valid. + +### Results +- 3 affected tests: 45.98s timeout → all pass in <2s. +- Full shellper-process + session-manager suites: 114 passed, 0 failed (18.72s). + diff --git a/packages/codev/src/terminal/__tests__/shellper-process.test.ts b/packages/codev/src/terminal/__tests__/shellper-process.test.ts index edcc84724..7f8d2967d 100644 --- a/packages/codev/src/terminal/__tests__/shellper-process.test.ts +++ b/packages/codev/src/terminal/__tests__/shellper-process.test.ts @@ -387,6 +387,39 @@ describe('ShellperProcess', () => { mockPty.simulateExit(1); expect(shellper.hasExited).toBe(true); }); + + it('replays EXIT frame to a client that connects after the PTY already exited (Bugfix #905)', async () => { + shellper = new ShellperProcess(createMockPty, socketPath); + await shellper.start('/bin/bash', [], '/tmp', {}, 80, 24); + + // PTY exits BEFORE any client connects — the original EXIT broadcast + // reaches nobody. A late-connecting client must still be told. + mockPty.simulateExit(1); + expect(shellper.hasExited).toBe(true); + + const socket = net.createConnection(socketPath); + const parser = createFrameParser(); + socket.pipe(parser); + + const framesPromise = collectFramesFor(parser, 300); + await new Promise((resolve, reject) => { + socket.on('error', reject); + socket.on('connect', () => { + socket.write(encodeHello({ version: PROTOCOL_VERSION, clientType: 'tower' })); + resolve(); + }); + }); + + const frames = await framesPromise; + const exitFrame = frames.find((f) => f.type === FrameType.EXIT); + expect(exitFrame).toBeDefined(); + if (exitFrame) { + const msg = parseJsonPayload(exitFrame.payload); + expect(msg.code).toBe(1); + } + + socket.destroy(); + }); }); describe('SPAWN handling', () => { diff --git a/packages/codev/src/terminal/shellper-process.ts b/packages/codev/src/terminal/shellper-process.ts index e1b343455..089c39696 100644 --- a/packages/codev/src/terminal/shellper-process.ts +++ b/packages/codev/src/terminal/shellper-process.ts @@ -86,6 +86,12 @@ export class ShellperProcess extends EventEmitter { // shellper that has emitted nothing yet still reports a sane value. private lastDataAt: number = Date.now(); private exited = false; + // Exit info retained after the PTY exits so clients that connect *after* + // exit still learn the session ended. Without this, a fast-exiting command + // (e.g. `exit 1`) can finish before the manager connects its client, the + // EXIT broadcast reaches nobody, and the client hangs forever waiting for an + // EXIT frame that already went out (Bugfix #905). + private exitInfo: { code: number; signal: string | null } | null = null; constructor( private readonly ptyFactory: () => IShellperPty, @@ -125,6 +131,7 @@ export class ShellperProcess extends EventEmitter { rows: number, ): void { this.exited = false; + this.exitInfo = null; const pty = this.ptyFactory(); this.pty = pty; pty.spawn(command, args, { @@ -155,10 +162,11 @@ export class ShellperProcess extends EventEmitter { this.log(`PTY exited: code=${exitInfo.exitCode}, signal=${exitInfo.signal ?? null}`); this.exited = true; - const exitFrame = encodeExit({ + this.exitInfo = { code: exitInfo.exitCode, signal: exitInfo.signal != null ? String(exitInfo.signal) : null, - }); + }; + const exitFrame = encodeExit(this.exitInfo); this.broadcast(exitFrame); @@ -375,6 +383,14 @@ export class ShellperProcess extends EventEmitter { socket.write(encodeReplay(replayData)); } + // If the PTY already exited before this client connected, the original + // EXIT broadcast missed it. Replay the retained EXIT frame so the client + // doesn't hang waiting for an event that already fired (Bugfix #905). + if (this.exited && this.exitInfo) { + socket.write(encodeExit(this.exitInfo)); + this.log(`EXIT replayed to late connection ${connectionId}: code=${this.exitInfo.code}`); + } + return connectionId; } From 772f25b7bd124ec077ffc6a9ecb6b3d0e92b0cd8 Mon Sep 17 00:00:00 2001 From: Mohid Makhdoomi Date: Sun, 31 May 2026 16:36:41 -0400 Subject: [PATCH 03/11] chore(porch): bugfix-905 fix phase-transition --- .../bugfix-905-investigate-flaky-session-mana/status.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml b/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml index efd4b0547..678e26769 100644 --- a/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml +++ b/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml @@ -1,7 +1,7 @@ id: bugfix-905 title: investigate-flaky-session-mana protocol: bugfix -phase: investigate +phase: fix plan_phases: [] current_plan_phase: null gates: @@ -11,4 +11,4 @@ iteration: 1 build_complete: false history: [] started_at: '2026-05-31T20:26:53.743Z' -updated_at: '2026-05-31T20:26:53.743Z' +updated_at: '2026-05-31T20:36:41.839Z' From c4a9530c2501a14623a702faaa7017e4c982846c Mon Sep 17 00:00:00 2001 From: Mohid Makhdoomi Date: Sun, 31 May 2026 16:38:00 -0400 Subject: [PATCH 04/11] chore(porch): bugfix-905 pr phase-transition --- .../bugfix-905-investigate-flaky-session-mana/status.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml b/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml index 678e26769..508f605bc 100644 --- a/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml +++ b/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml @@ -1,7 +1,7 @@ id: bugfix-905 title: investigate-flaky-session-mana protocol: bugfix -phase: fix +phase: pr plan_phases: [] current_plan_phase: null gates: @@ -11,4 +11,4 @@ iteration: 1 build_complete: false history: [] started_at: '2026-05-31T20:26:53.743Z' -updated_at: '2026-05-31T20:36:41.839Z' +updated_at: '2026-05-31T20:38:00.628Z' From 7200008f76f38c54f7bad0ce6c14a276f7b29817 Mon Sep 17 00:00:00 2001 From: Mohid Makhdoomi Date: Sun, 31 May 2026 20:02:25 -0400 Subject: [PATCH 05/11] chore(porch): bugfix-905 pr gate-requested --- .../bugfix-905-investigate-flaky-session-mana/status.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml b/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml index 508f605bc..9c18b5d1e 100644 --- a/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml +++ b/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml @@ -7,8 +7,10 @@ current_plan_phase: null gates: pr: status: pending + requested_at: '2026-06-01T00:02:25.837Z' iteration: 1 build_complete: false history: [] started_at: '2026-05-31T20:26:53.743Z' -updated_at: '2026-05-31T20:38:00.628Z' +updated_at: '2026-06-01T00:02:25.837Z' +pr_ready_for_human: true From 4a939f9ec847784286f62fa780829f23d3261cff Mon Sep 17 00:00:00 2001 From: Mohid Makhdoomi Date: Sun, 31 May 2026 20:02:56 -0400 Subject: [PATCH 06/11] [Bugfix #905] docs: update builder thread with PR/CMAP outcome Co-Authored-By: Claude Opus 4.7 --- codev/state/bugfix-905_thread.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/codev/state/bugfix-905_thread.md b/codev/state/bugfix-905_thread.md index c8e77a625..7e0174c8b 100644 --- a/codev/state/bugfix-905_thread.md +++ b/codev/state/bugfix-905_thread.md @@ -45,4 +45,13 @@ Verifying: reproduce timeout w/o dist, then build dist and re-run. ### Results - 3 affected tests: 45.98s timeout → all pass in <2s. - Full shellper-process + session-manager suites: 114 passed, 0 failed (18.72s). +- After clean `pnpm install && pnpm build`: full unit suite 152 files / 3211 passed, 13 skipped, 0 failed. + +## PR phase +- PR #953 → cluesmith/codev (cross-fork from mohidmakhdoomi:builder/bugfix-905). + Note: `origin` has split URLs (fetch=cluesmith, push=mohidmakhdoomi fork); branch lives on the fork. +- CMAP-3 (--issue 905): Gemini APPROVE (HIGH), Codex APPROVE (MEDIUM, couldn't re-run vitest in RO sandbox). + Claude lane hit a usage limit (rate-limited, not a finding). No REQUEST_CHANGES. +- porch: investigate → fix → pr done; **PR gate requested — WAITING FOR HUMAN APPROVAL** + (`porch approve bugfix-905 pr`). From 4b58faac75dc9c20d4ec623eeb5c333eab395a4a Mon Sep 17 00:00:00 2001 From: Mohid Makhdoomi Date: Sun, 31 May 2026 20:11:28 -0400 Subject: [PATCH 07/11] [Bugfix #905] Fix: short-circuit waitForTerminalExit for already-exited sessions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The EXIT-replay fix made shellper exits propagate before teardown attaches its once('exit') listener. waitForTerminalExit attached the listener after the event had already fired, so an already-exited session waited out the full 5s safety timeout — A-then-B sequential teardown (3 terminals) overran the send-integration e2e afterAll 10s budget in CI. Short-circuit on session.status === 'exited' before attaching the listener. Exports waitForTerminalExit and adds focused unit tests (already-exited resolves immediately without attaching the listener; missing session resolves; running session still resolves on the exit event). Co-Authored-By: Claude Opus 4.7 --- .../__tests__/tower-instances.test.ts | 47 +++++++++++++++++++ .../src/agent-farm/servers/tower-instances.ts | 10 +++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/packages/codev/src/agent-farm/__tests__/tower-instances.test.ts b/packages/codev/src/agent-farm/__tests__/tower-instances.test.ts index 755dac636..50b852a89 100644 --- a/packages/codev/src/agent-farm/__tests__/tower-instances.test.ts +++ b/packages/codev/src/agent-farm/__tests__/tower-instances.test.ts @@ -21,6 +21,7 @@ import { killTerminalWithShellper, stopInstance, removeArchitect, + waitForTerminalExit, type InstanceDeps, } from '../servers/tower-instances.js'; @@ -126,6 +127,52 @@ describe('tower-instances', () => { }); }); + // ========================================================================= + // waitForTerminalExit + // ========================================================================= + + describe('waitForTerminalExit', () => { + it('resolves immediately when the session has already exited (Bugfix #905 regression)', async () => { + // Bugfix #905 made shellper exits propagate before teardown attaches its + // once('exit') listener. A session that already fired 'exit' must NOT wait + // out the 5s safety timeout — it should short-circuit on status. + const once = vi.fn(); + const manager = { + getSession: vi.fn().mockReturnValue({ status: 'exited', once }), + } as unknown as Parameters[0]; + + await expect(waitForTerminalExit(manager, 'term-1', 5000)).resolves.toBeUndefined(); + // Must not even attach the listener for an already-exited session. + expect(once).not.toHaveBeenCalled(); + }); + + it('resolves immediately when the session is missing', async () => { + const manager = { + getSession: vi.fn().mockReturnValue(undefined), + } as unknown as Parameters[0]; + + await expect(waitForTerminalExit(manager, 'gone', 5000)).resolves.toBeUndefined(); + }); + + it('waits for the exit event on a still-running session', async () => { + let exitHandler: (() => void) | null = null; + const manager = { + getSession: vi.fn().mockReturnValue({ + status: 'running', + once: (event: string, cb: () => void) => { + if (event === 'exit') exitHandler = cb; + }, + }), + } as unknown as Parameters[0]; + + const promise = waitForTerminalExit(manager, 'term-2', 5000); + expect(exitHandler).toBeTypeOf('function'); + // Fire the event the listener is waiting for. + exitHandler!(); + await expect(promise).resolves.toBeUndefined(); + }); + }); + // ========================================================================= // registerKnownWorkspace // ========================================================================= diff --git a/packages/codev/src/agent-farm/servers/tower-instances.ts b/packages/codev/src/agent-farm/servers/tower-instances.ts index 15f43bb62..b6dab2837 100644 --- a/packages/codev/src/agent-farm/servers/tower-instances.ts +++ b/packages/codev/src/agent-farm/servers/tower-instances.ts @@ -120,7 +120,7 @@ export function isIntentionallyStopping(workspacePath: string): boolean { * because the session was already gone), the promise still resolves so we * don't block the stop indefinitely. */ -function waitForTerminalExit(manager: TerminalManager, terminalId: string, timeoutMs = 5000): Promise { +export function waitForTerminalExit(manager: TerminalManager, terminalId: string, timeoutMs = 5000): Promise { const session = manager.getSession(terminalId); // Defensive: if the session is gone or doesn't look like an EventEmitter // (e.g. a test stub), there's nothing to wait for — resolve immediately so @@ -128,6 +128,14 @@ function waitForTerminalExit(manager: TerminalManager, terminalId: string, timeo if (!session || typeof (session as { once?: unknown }).once !== 'function') { return Promise.resolve(); } + // The session may have already exited before we attach the listener below. + // `once('exit')` only catches *future* emissions, so a session that already + // fired 'exit' would otherwise wait out the full safety timeout. Bugfix #905 + // made shellper exits propagate earlier (EXIT is now replayed to clients that + // connect after the PTY exits), which surfaced this: short-circuit instead. + if ((session as { status?: string }).status === 'exited') { + return Promise.resolve(); + } return new Promise((resolve) => { let settled = false; const finish = () => { From 03911f557699c6a33dabb6b31adf915e36944efb Mon Sep 17 00:00:00 2001 From: Mohid Makhdoomi Date: Sun, 31 May 2026 20:11:46 -0400 Subject: [PATCH 08/11] [Bugfix #905] docs: thread update for CI regression fix Co-Authored-By: Claude Opus 4.7 --- codev/state/bugfix-905_thread.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/codev/state/bugfix-905_thread.md b/codev/state/bugfix-905_thread.md index 7e0174c8b..487e8e6f3 100644 --- a/codev/state/bugfix-905_thread.md +++ b/codev/state/bugfix-905_thread.md @@ -52,6 +52,18 @@ Verifying: reproduce timeout w/o dist, then build dist and re-run. Note: `origin` has split URLs (fetch=cluesmith, push=mohidmakhdoomi fork); branch lives on the fork. - CMAP-3 (--issue 905): Gemini APPROVE (HIGH), Codex APPROVE (MEDIUM, couldn't re-run vitest in RO sandbox). Claude lane hit a usage limit (rate-limited, not a finding). No REQUEST_CHANGES. -- porch: investigate → fix → pr done; **PR gate requested — WAITING FOR HUMAN APPROVAL** - (`porch approve bugfix-905 pr`). +- porch: investigate → fix → pr done; PR gate requested. + +## CI regression follow-up (architect-flagged) +- Tower Integration Tests job went red: `send-integration.e2e.test.ts` afterAll (10s) timed out. +- Cause: the EXIT-replay fix makes shellper exits propagate *earlier*. `waitForTerminalExit` + (`tower-instances.ts:123`) attached `once('exit')` *after* the event had already fired, so an + already-exited session waited out the full 5s safety timeout × N terminals (A then B ≈ 10s). +- Fix: short-circuit `waitForTerminalExit` when `session.status === 'exited'` before attaching the + listener. Exported the fn + added 3 focused unit tests in `tower-instances.test.ts`. +- Could NOT reproduce the e2e locally: `registerTerminal` returns 500 in this sandbox during + `beforeAll` (real-shellper spawn fails — same node-pty-in-child-process limitation that gates + these CI-tier tests). My change only touches teardown, so it can't cause a beforeAll 500. +- Verified: full `pnpm build` + full unit suite green (152 files / 3214 passed, +3 new, 0 failed). + Pushed for CI to verify the Tower Integration Tests job. **Do NOT merge until CI green + re-approval.** From e5742af5f3070f8685768d60c883737f31ea4342 Mon Sep 17 00:00:00 2001 From: Mohid Makhdoomi Date: Sun, 31 May 2026 20:14:32 -0400 Subject: [PATCH 09/11] =?UTF-8?q?[Bugfix=20#905]=20docs:=20thread=20update?= =?UTF-8?q?=20=E2=80=94=20all=20CI=20green?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- codev/state/bugfix-905_thread.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/codev/state/bugfix-905_thread.md b/codev/state/bugfix-905_thread.md index 487e8e6f3..3c733bca2 100644 --- a/codev/state/bugfix-905_thread.md +++ b/codev/state/bugfix-905_thread.md @@ -66,4 +66,7 @@ Verifying: reproduce timeout w/o dist, then build dist and re-run. these CI-tier tests). My change only touches teardown, so it can't cause a beforeAll 500. - Verified: full `pnpm build` + full unit suite green (152 files / 3214 passed, +3 new, 0 failed). Pushed for CI to verify the Tower Integration Tests job. **Do NOT merge until CI green + re-approval.** +- **CI RESULT: all 6 checks GREEN** — Tower Integration Tests (the formerly-red job), Unit Tests, + CLI Tests (ubuntu + macos), CLI Integration Tests, Package Install Verification all pass. + Holding at the pr gate awaiting architect re-approval. Not merging. From 220e2feb6d4caf77041bfa59a5c1dc0ab0390346 Mon Sep 17 00:00:00 2001 From: Mohid Makhdoomi Date: Sun, 31 May 2026 20:25:20 -0400 Subject: [PATCH 10/11] chore(porch): bugfix-905 pr gate-approved --- .../bugfix-905-investigate-flaky-session-mana/status.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml b/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml index 9c18b5d1e..63c18dbfa 100644 --- a/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml +++ b/codev/projects/bugfix-905-investigate-flaky-session-mana/status.yaml @@ -6,11 +6,12 @@ plan_phases: [] current_plan_phase: null gates: pr: - status: pending + status: approved requested_at: '2026-06-01T00:02:25.837Z' + approved_at: '2026-06-01T00:25:20.957Z' iteration: 1 build_complete: false history: [] started_at: '2026-05-31T20:26:53.743Z' -updated_at: '2026-06-01T00:02:25.837Z' -pr_ready_for_human: true +updated_at: '2026-06-01T00:25:20.958Z' +pr_ready_for_human: false From 8dd77ceed4ba69e768f3509df7b21d157cd1af1f Mon Sep 17 00:00:00 2001 From: Mohid Makhdoomi Date: Sun, 31 May 2026 20:28:42 -0400 Subject: [PATCH 11/11] =?UTF-8?q?[Bugfix=20#905]=20docs:=20thread=20update?= =?UTF-8?q?=20=E2=80=94=20HOLD=20at=20pr=20gate=20(branch-protection=20blo?= =?UTF-8?q?cker)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- codev/state/bugfix-905_thread.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/codev/state/bugfix-905_thread.md b/codev/state/bugfix-905_thread.md index 3c733bca2..143818aa8 100644 --- a/codev/state/bugfix-905_thread.md +++ b/codev/state/bugfix-905_thread.md @@ -70,3 +70,10 @@ Verifying: reproduce timeout w/o dist, then build dist and re-run. CLI Tests (ubuntu + macos), CLI Integration Tests, Package Install Verification all pass. Holding at the pr gate awaiting architect re-approval. Not merging. +## Final state: HOLD (architect decision 2026-06-01) +- pr gate human-approved; consult 2-0 APPROVE (Gemini+Codex HIGH); all 6 CI checks green; MERGEABLE. +- Merge BLOCKED by GitHub branch protection: `reviewDecision=REVIEW_REQUIRED`, 0 formal reviews. + Single-account repo can't self-approve, so the required review can't be satisfied right now. +- Architect decision: **leave PR #953 OPEN, do NOT merge, do NOT use --admin.** Stand by at pr gate; + revisit once a reviewer account / branch-protection config is sorted. Work itself is complete & green. +