Skip to content

feat: sidebar pane rename, one-shot default agent launch, neutral row status - #551

Open
tbrownio wants to merge 12 commits into
mainfrom
workspace-entry-sidebar
Open

feat: sidebar pane rename, one-shot default agent launch, neutral row status#551
tbrownio wants to merge 12 commits into
mainfrom
workspace-entry-sidebar

Conversation

@tbrownio

@tbrownio tbrownio commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Three independent sidebar/workspace-entry changes. They share a theme — the sidebar behaved like a Git control, not a workspace navigator — but review them separately; nothing in one depends on another.

# Change Blast radius
1 Rename a Pane from any sidebar entry — changes only the display label Sidebar + rename IPC
2 Adding a repository starts your default agent in it exactly once, or opens blank with an Open agent notice Main process, new one-shot service
3 Expanded rows drop the coloured left accent bar; agent state shows through the status dot the compact rail already uses Styling only

Change 2 is the one to read closely: it is new main-process ownership of "first entry" with a receipt (a nullable projects.default_agent_launched_at timestamp meaning "the automatic tab was created"), a deadline, and a cleanup path.

1. Rename

Why. There was no way to give a Pane a human label without renaming its branch.

How. One main-process helper (renameSessionDisplayName) shared by the UI and the RunPane CLI: it trims, rejects blanks, writes sessions.name plus a new name_manually_set provenance bit, and emits the existing session-updated. The stored name is now the label everywhere; PR title/number stay metadata (tooltip, title-bar pill, diff header, #n). The automatic AI namer honours the provenance bit instead of comparing strings. The dormant "Auto-rename panes to pull request titles" setting is removed — nothing produced it.

Done means. Right-click → Rename works on all four Pane renderings (expanded row, expanded pinned copy, compact icon, compact pinned icon) and touches nothing but the label.

2. One-shot default-agent launch

Why. A freshly added repository opened onto an empty stage.

How. Launch is owned by main, not a React effect. projects:create accepts launchDefaultAgent: true plus disclosedAgent — sent only by the Add Repository dialog, and only when it actually rendered the disclosure — and runs launchDefaultAgentOnce:

  • once: single-flight per project, the result is memoised so nothing retries, and a durable receipt (projects.default_agent_launched_at) is written last;
  • validated first: main refuses a different agent than the one disclosed, then checks platform + executable through the existing agent doctor (the same check behind runpane agents doctor) before any panel exists;
  • owned session: the launch tells the session-created listener not to auto-create the plain shell Terminal every new session otherwise gets (main/src/events.ts), so a successful launch yields exactly one terminal — the agent's;
  • bounded: PTY spawn + readiness wait run under one 45 s deadline;
  • one cleanup path for any failure after the panel exists (deadline, spawn error, process exit, receipt write): kill PTY → delete panel (verified, with a DB fallback) → re-select Explorer → no receipt, leaving Explorer/Diff only. A terminal that registers after cleanup is destroyed by a late guard, and initializeTerminal re-checks its panel still exists after acquiring a spawn slot — a cleaned-up panel can never run the permissive command.

Done means. Adding a repo with a default agent configured yields one live agent tab that never duplicates across remount, navigation, restart, or tab close; a failed launch leaves the project with Explorer/Diff only plus a non-modal Open agent notice; no default agent means nothing is launched.

3. Neutral rows

Why. Expanded rows carried a second, full-height colour channel that duplicated the status dot and fought with selection/hover.

How. StatusAccentBar and both row animations are deleted; SessionStatusBadge (size sm) sits in a fixed trailing slot; selected/hover keep bg-surface-selected / hover:bg-surface-hover.

Done means. No accent bar or label animation remains and every agent state is still announced accessibly.

Whole PR, green across the board: pnpm lint, pnpm typecheck, main Vitest, pnpm theme:contrast, and the focused Playwright specs.

Three owner decisions to confirm before merge (full detail under Residual risks):

  1. An agent that starts and then shows its own login/trust screen counts as a live tab, not a failed launch — the handshake can't see authentication.
  2. The launch flag + disclosed agent is the authorisation for any authenticated projects:create caller (desktop, remote PWA, daemon), not just the desktop dialog.
  3. A failed automatic launch leaves Explorer/Diff only, while an ordinary new project (and the unreachable no-default skip) keeps the pre-existing auto-created shell Terminal — so AC9 is read as "no agent panel, no launch".

Visual overview

The launch is the flow-shaped change — before, nothing owned "first entry"; after, main runs a gate sequence with a receipt written last:

Before: Add Repository saves the project row, ProjectView mounts Explorer and Diff, and the stage stays empty. After: main process runs a one-shot gate sequence — receipt check, default agent, agent doctor, main session + panel, PTY spawn + readiness wait, receipt written last — with one cleanup path for any failure and a non-modal notice.

Before — the compact Pane menu offered only Pin and Archive (expanded rows had no context menu at all):

Before: compact sidebar right-click menu showing only Pin and Archive

After — from the QA drive (Electron-mock Playwright, night-owl theme unless noted):

After: expanded row right-click menu with Rename first, then Pin, Archive After: Rename pane dialog with the current name pre-selected

After: expanded row showing the renamed label with the status dot in the trailing slot and no accent bar After: Add Repository dialog disclosing that Codex (codex --yolo) will start

After: project opened with Explorer/Diff only and the non-modal notice with Open agent and Dismiss After: light theme, selected row on a neutral surface

Full galleries (five agent states × two modes, four themes × selected/hover/focus, narrow width, dialogs) are in the QA evidence comment.

User journeys

J1 — Rename a Pane from the sidebar. Right-click a Pane (expanded row, compact icon, or either pinned copy) → Rename → a small dialog with the current name selected → type Human label → Enter → the row, the compact tooltip, the pinned copy, and the window title all read Human label immediately; the branch, worktree folder, and PR badge are untouched. Blank input can't be saved; Escape/Cancel changes nothing.

J2 — Add a repository with a default agent configured. Sidebar → Add repository → name + path → the dialog says "Creating this repository will start Claude Code in it (claude --dangerously-skip-permissions). Close the tab at any time." → Create (button reads "Starting Claude Code…" while main validates and spawns) → the project opens with Explorer, Diff, and one live Claude Code tab already running. Navigate away and back, close the tab, restart Pane — no second tab ever appears.

J3 — Add a repository when the agent can't start. Same dialog → Create → main finds the agent binary missing (or the platform unsupported, or the process exits/never becomes ready) → the project still opens with Explorer and Diff only (no terminal tab at all) and a bottom notice: "Repository added, but Codex could not start. " and Open agent / Dismiss. Open agent creates the same agent tab through the normal +-menu path; nothing retries on its own.

J4–J6 are the paths with no new UI: J4 replay (second call, restart), J5 no default configured, J6 other project creators. The map shows where each one exits.

Flow map (Add Repository)

Add Repository → Create  (frontend/src/components/AddProjectDialog.tsx)
└─ projects:create { launchDefaultAgent: true }  (main/src/ipc/project.ts)
   └─ launchDefaultAgentOnce  (main/src/services/workspaceEntry.ts)
      ├─ receipt already set ──────────────► skipped (already-launched)   [J4]
      ├─ no preset for defaultOrchestratorAgent ► skipped (no-default) → ordinary new-project state   [J5]
      ├─ agent doctor: platform/executable ✗ ► failed (validation-failed) → notice   [J3]
      ├─ create panel → spawn PTY ✗ / exit / not ready within 30 s / 45 s overall deadline / receipt write ✗
      │     └─ cleanup: kill PTY, delete panel, re-select Explorer ► failed → notice   [J3]
      └─ ready ► receipt written ► launched → live tab   [J2]
Other creators (Clone from GitHub, onboarding, `runpane repos add`) never send the flag   [J6]
Journey Risk Manual test
J1 rename everywhere Important M1–M4
J2 launch once Must M5–M7
J3 failure → Explorer/Diff only + notice Must M8–M9
J4 replay/memo (second call, restart) Must M6
J5 no default → blank Important M10
J6 other creators excluded Must M11
Neutral rows / status badge Nice M12–M14

Gap flagged honestly: an agent that starts and then shows its own login/trust prompt is a live tab, not a failure — see Residual risks.

Verification

Every AC below is covered by automated tests except where it says Manual — those are AC6–AC8, whose end-to-end proof is the real-agent Manual items (M5–M9 and M11) a mock can't reach.

Rename (AC1–AC5)

  • AC1 Rename on expanded/compact/pinned rows — tests/sidebar-pane-actions.spec.ts (menu order Rename, Pin, Archive on all four renderings) → 14 passed. Driven again in the QA drive.
  • AC2 trim/blank/cancel/focus — same spec (' Human label ' → call ['regular','Human label']; blank disables Save; Escape makes no call) → passed.
  • AC3 only name + provenance written — main/src/ipc/session.rename.test.ts asserts updateSession(id, { name: 'Human label', name_manually_set: true }) and untouched worktree_name/worktree_path/base_branch → 4/4.
  • AC4 live propagation to row, compact label, pinned copy, document.title — same Playwright spec → passed.
  • AC5 manual label survives a PR-title refresh; PR title/number still in tooltip/metadata → same spec (emitGitStatusUpdated with a new prTitle) → passed.

Launch (AC6–AC11)

  • AC6 disclosure + single confirmation + one terminal — renderer half in tests/add-repository.spec.ts (5/5); main half in main/src/services/workspaceEntry.test.ts (23/23); real-agent end-to-end is Manual (M5).
  • AC7 exactly once — Vitest: two concurrent calls share one createPanel; a later call replays the identical memoised result; receipt asserted after readiness (call order). Real remount/restart is Manual (M6).
  • AC8 default sampled per call, receipt makes later defaults inert — Vitest (already-launched) + Manual (M7).
  • AC9 no default → zero panels, blank stage — Vitest (no-default, no createPanel) + Playwright (omitDefaultOrchestratorAgent).
  • AC10 validation/spawn/exit/timeout/receipt-write failures clean up, no receipt, no retry, notice with Open agent — Vitest (each failure path asserts deletePanel, a rejecting deletePanel falls back to DB removal, no updateProject, Explorer re-selected; main/src/events.test.ts proves the default Terminal is skipped only when autoCreateTerminal === false) + Playwright (notice → panels.createPanel with codex --yolo / agentType: 'codex'; Dismiss creates nothing).
  • AC11 only the flagged dialog path launches; exact panel state with no seeded input — Vitest static-import guard (only main/src/ipc/project.ts imports the service), exact initialState assertion, project.create.test.ts (flag absent/false → never invoked); Playwright: Clone from GitHub sends no flag.

Neutral rows (AC12–AC13)

  • AC12 no accent bar; neutral selected/hover/focus — Playwright (no .w-1 rail, no sidebar-active-label/status-working class, bg-surface-selected kept) + pnpm theme:contrast 148/148. Visual pass across themes in the QA drive.
  • AC13 blocked/working/done/idle/unknown announced in both modes — Playwright five-state matrix ([role=status][aria-label="Agent <state>"], expanded unknown → Agent status unknown, compact placeholder unchanged) → passed.

Suite-wide (AC14) and gates

  • AC14 pnpm lint (oxlint, ESLint, boundary conformance, Knip) ✓ · pnpm typecheck ✓ · pnpm --filter main exec vitest run 856 passed / 1 skipped ✓ · pnpm theme:contrast ✓ · pnpm --filter frontend build ✓ · focused Playwright 14 + 5 passed ✓.
  • Gates: plan review 3/3 passes (Codex + Claude lanes, all Must Fix folded); backend-verifier pass with quoted evidence; post-PR review 3/3 passes (dual lanes) plus one scoped review of the final orphan-PTY fix; QA drive results land below.

Manual tests

Fourteen items; the six Must ones need a real repository and a real agent binary.

Must (breaks data/auth/money if wrong):

  • [J2] M5 — With Default agent = Claude Code, add a real repository → dialog discloses the agent → one Claude Code tab starts next to Explorer/Diff; Create was the only confirmation. — left to human: needs a real Electron app + agent binary (renderer half driven: disclosure, busy state, single confirmation)
  • [J2/J4] M6 — Navigate away and back, close the agent tab, restart Pane, reopen the project → no second automatic tab, ever. — left to human: needs a real Electron window and app restart (single-flight/memo proven in Vitest)
  • [J4] M7 — Change the default agent afterwards → the existing project is unchanged; add another repository → the new default starts. — left to human: needs a real Electron app
  • [J3] M8 — Set the default to an agent not on PATH (or Cursor on Windows native) and add a repository → project opens with Explorer/Diff and no terminal tab, notice names the agent, no failed/placeholder tab. — renderer half driven with a mocked failure; left to human: the real missing-binary check
  • [J3] M9 — Open agent in that notice → one tab is created by the normal path; Dismiss creates nothing; neither navigation nor restart retries the launch. — Open agent / Dismiss driven; left to human: no-retry after app restart
  • [J6] M11 — Clone from GitHub, onboarding, and runpane repos add create projects with no automatic agent tab. — Clone from GitHub driven (no flag sent); left to human: onboarding and runpane repos add (proven by the static import guard in Vitest)

Important (user-facing behaviour):

  • [J1] M1 — Right-click an expanded row, its pinned copy, a compact icon, and a compact pinned icon → Rename is first, then Pin/Unpin, divider, Archive; ArrowDown/Enter reaches Rename from the keyboard and Escape returns focus to the row.
  • [J1] M2 — Rename to Human label → row, compact tooltip/aria-label, pinned copy, and window title show Human label; git branch --show-current and the worktree folder are unchanged. — label propagation driven; left to human: the Git-identity check needs a real worktree
  • [J1] M3 — Blank name: Save disabled and "Pane name cannot be blank"; Escape/Cancel leaves the old name; focus returns to the row.
  • [J1] M4 — On a Pane with a PR: renamed label stays after a git-status refresh; PR title/number still appear in the tooltip and title-bar pill.
  • [J5] M10 — (Defensive path; not reachable through settings) — leave to the Vitest/Playwright evidence above.

Nice (cosmetic):

  • M12 — No coloured left rail on expanded rows; selected vs hover vs focus ring are distinct in dark, light, high-contrast, and colorblind-safe themes at normal and narrow sidebar widths. — driven across night-owl, light, high-legibility, colorblind-safe + 900px; left to human: a pixel-level look in the real app
  • M13 — Blocked / working / done / idle dots render in expanded and compact rows; only the badge animates while working.
  • M14 — Settings → AI & Agents reads "Default agent — Used when Pane Chat opens a new global terminal and when a newly added repository opens its first terminal."; Worktrees & Git no longer shows "Auto-rename panes to pull request titles". — left to human: Settings screen not in the driven journeys

Areas not affected: worktree creation/archiving, terminal restore/resume, Pane Chat, PR metadata fetching, the remote PWA sidebar, project rename/delete.

QA results

QA drive (Electron-mock Playwright, 18 driven tests, 45 screenshots, 7 journey videos, axe clean on menu/rename/Add-Repository dialogs): 8 of 14 items executed and passed (M1–M4, M9, M10, M12, M13; several with a real-app half left to you as annotated), 6 left to the human (M5–M8 and M11 need a real Electron window / agent binary / restart; M14 is a Settings-copy read). No bug found. One pre-existing test-mock artifact disclosed (unmocked sessions.get logs a console error on project creation; not a product change). Cleanup: none created — all state lived in the in-memory mock. Proof with galleries and video links: see the QA evidence comment below.

Deploy notes

Nothing for an operator to do. Two additive nullable columns land through Pane's own startup migration.

  • Schema (local SQLite, per user) — two additive nullable columns, applied automatically by Pane's startup migration on first launch after update; no operator action.
    • ALTER TABLE sessions ADD COLUMN name_manually_set BOOLEAN DEFAULT 0main/src/database/migrations/add_session_name_provenance.sql, runtime check in main/src/database/database.ts.
    • ALTER TABLE projects ADD COLUMN default_agent_launched_at TEXTmain/src/database/migrations/add_project_default_agent_launch.sql, runtime check in main/src/database/database.ts.
    • staging/production: n/a (desktop app; no shared database). Downgrade-safe: older builds ignore unknown columns.
  • No new dependencies, env vars, secrets, CI, or one-time scripts.

Residual risks

The first two are the owner decisions from the Summary.

  • Owner decision 1 — authentication is not detectable at launch. The readiness handshake proves executable found, PTY spawned, command injected, and process alive (isCliReady); an agent that then shows its own login/trust screen is treated as a live tab, exactly like one opened from the + menu. Owner decision to confirm; tearing such tabs down would need per-agent output heuristics and a longer wait.
  • Owner decision 2 — launchDefaultAgent: true is honoured for any authenticated projects:create caller (desktop renderer, remote PWA, daemon clients) — the flag is the authorisation, not the transport. Pinned by main/src/ipc/project.create.test.ts.
  • Add Repository now blocks up to ~50 s in the worst case (5 s executable lookup + one 45 s deadline covering spawn-slot wait, PTY spawn, and readiness) behind a disabled "Starting …" button; hitting the deadline is a launch failure with the normal cleanup, so the dialog can always finish.
  • Owner decision 3 — the auto-created shell Terminal is only suppressed on an attempted launch. A brand-new project opened the ordinary way — including the defensive no-default skip — still gets the pre-existing auto-created shell Terminal (main/src/events.ts, unchanged by this PR; the no-default branch is unreachable through Settings because config normalises to Claude). Only an attempted automatic launch suppresses it, so after a failed launch the project has Explorer/Diff only — deliberate, so no failed/placeholder tab survives. AC9's "zero terminal panels" is therefore proven as "no agent panel, no launch" (Vitest); the Playwright "Open a terminal" stage is the mock's approximation. Owner decision to confirm.
  • Stale naming, no behaviour change. Sidebar.tsx still names its local state compactSessionMenu/openCompactSessionMenu (the CompactSessionMenu component itself is deleted) — naming only.

https://claude.ai/code/session_01A6ystbZhfNVGeSUc7x8DNm

Tyler Brown added 2 commits August 29, 2026 12:32
Add a shared Pane context menu (Rename, Pin/Unpin, Archive) to the
expanded, compact, and pinned sidebar entries, backed by a rename dialog
that trims input and rejects blanks. Renames go through one main-process
helper that writes only the display name plus a new name_manually_set
provenance bit, which the AI namer now respects; the stored name is the
label everywhere and PR titles stay metadata, so the dormant
auto-rename-to-PR-title setting is removed. Expanded rows lose the
coloured accent bar and label animation and show agent state through
SessionStatusBadge instead. Adds the DB columns both workstreams need
and extracts runAgentDoctor into a service module.

Claude-Session: https://claude.ai/code/session_01A6ystbZhfNVGeSUc7x8DNm
The interactive Add Repository dialog now discloses the configured
default agent and sends launchDefaultAgent: true; projects:create then
runs a main-owned, single-flight one-shot that validates platform and
executable, creates the main session and a terminal panel, spawns the
PTY, waits for CLI readiness, and only then writes a durable receipt.
Any failure destroys the panel, leaves the project blank, writes no
receipt, is memoised so nothing retries, and surfaces a non-modal
notice with a manual Open agent action. The default agent setting copy
now names both uses.

Claude-Session: https://claude.ai/code/session_01A6ystbZhfNVGeSUc7x8DNm
@github-actions

github-actions Bot commented Aug 29, 2026

Copy link
Copy Markdown

React Doctor found 1 new issue in 1 file · 1 warning · score 74 / 100 (Needs work) · 0 fixed · vs main

1 warning

src/components/AddProjectDialog.tsx

  • ⚠️ L21 Many related useState calls prefer-useReducer

Reviewed by React Doctor for commit 662b196. See inline comments for fixes.

Tyler Brown added 5 commits August 29, 2026 12:49
Suppress the default Terminal that session-created auto-creates when the
one-shot launch owns the session, so a launch yields exactly one agent
tab and a failed launch leaves none. Verify provisional-panel removal
with a retry and DB fallback and report any stale panel. Send the launch
flag only when the dialog actually disclosed the agent, ignore dialog
close while creating, and keep the failure notice if Open agent fails.
Make the Pane context menu keyboard-operable (focus, arrows, Home/End,
Escape restores the opener). Return raw rename errors only for the typed
validation error, fix the stale single-flight entry on skip paths, drop
the unused menu label field, and de-flake the Playwright text assertion.

Claude-Session: https://claude.ai/code/session_01A6ystbZhfNVGeSUc7x8DNm
Pre-allocate the agent panel id so a persist-then-reject createPanel is
still cleaned up, create the suppressed-terminal main session before the
agent doctor runs so every attempted launch that fails leaves Explorer
and Diff only, and bound the spawn plus readiness wait with one 45 s
deadline so Add Repository can never hang. Context-menu opener falls
back to the row element; Playwright covers the pinned expanded copy.

Claude-Session: https://claude.ai/code/session_01A6ystbZhfNVGeSUc7x8DNm
When the 45 s launch deadline fires while the terminal is still queued
for a spawn slot, the failure path now arms a late guard that destroys a
terminal registering after cleanup, and initializeTerminal revalidates
that its panel still exists after acquiring the slot and before spawning,
so a deleted panel never runs the permissive agent command. The dialog
also sends the agent it disclosed and main refuses to launch a different
one. Cleanup probes are guarded so a DB read cannot escape the catch.

Claude-Session: https://claude.ai/code/session_01A6ystbZhfNVGeSUc7x8DNm
An automatic launch now needs both the launch flag and the exact agent
the dialog disclosed; a request without a disclosed agent, or with a
different one, is skipped before any session or panel exists.

Claude-Session: https://claude.ai/code/session_01A6ystbZhfNVGeSUc7x8DNm
Whitespace only (git diff -w is empty); applied from the refactor pass.

Claude-Session: https://claude.ai/code/session_01A6ystbZhfNVGeSUc7x8DNm
Comment thread frontend/src/components/AddProjectDialog.tsx Outdated
Comment thread frontend/src/components/PaneContextMenu.tsx Outdated
Comment thread frontend/src/components/PaneContextMenu.tsx Outdated
Comment thread frontend/src/components/RenamePaneDialog.tsx Outdated
Comment thread frontend/src/components/RenamePaneDialog.tsx Outdated
@tbrownio

Copy link
Copy Markdown
Contributor Author

QA drive evidence — PR #551

Driver: the repo's own Playwright harness (Chromium + installElectronApiMock, pnpm electron-dev on port 4523), 18 driven tests, all passed; no Playwright MCP or real Electron window was available, so anything needing a real agent binary, restart, or Settings screen is listed under remaining for the human. Marker used in typed names: agent-e2e-20260829. Each caption says what to notice.

J1 — Rename from the sidebar (M1–M4, AC1/2/4/5) Pinned expanded row: menu opens with Rename first Expanded row: Rename · Pin · Archive order Dialog prefilled with the current name, text selected Blank name: Save disabled, 'Pane name cannot be blank' Saved: trimmed 'agent-e2e-20260829 Human label' in the row, status dot trailing, no accent bar Compact tooltip shows the new label Compact menu titled with the new label Compact pinned copy also renamed PR-bearing pane: PR title and #42 still in the tooltip After a git-status refresh with a new PR title the manual label is kept

📹 Journey video: J1-rename-propagation.webm (4.5 s; local scratchpad/qa/evidence/J1-rename-propagation.webm)

J2 — Add repository, launch once (M5 renderer half, AC6) Dialog default state Disclosure names Codex and `codex --yolo` 'Starting Codex…' busy state, Create and Cancel disabled Project view after a launched result — no notice

📹 Journey video: J2-launch-once.webm (3.2 s; local scratchpad/qa/evidence/J2-launch-once.webm)

J3 — Failed launch → notice → Open agent / Dismiss (M8 renderer half, M9, AC10) Explorer/Diff only, notice 'Repository added, but Codex could not start. Executable exited' Open agent: one panel-create request recorded, notice gone Dismiss: notice gone, zero panel-create requests

📹 Journey video: J3-failed-launch-open-agent.webm (1.1 s; local scratchpad/qa/evidence/J3-failed-launch-open-agent.webm)

J5 — No default agent (M10, AC9) and J6 — Clone from GitHub sends no flag (M11) No disclosure card; request carries no launchDefaultAgent Stage shows 'Open a terminal' (mock approximation — see owner decision 3)

📹 Journey video: J6-clone-from-github.webm (0.7 s; local scratchpad/qa/evidence/J6-clone-from-github.webm)

AC13 — five agent states, expanded and compact (M13) Expanded row: Agent blocked Expanded row: Agent working Expanded row: Agent idle Expanded row: Agent done Expanded row: Agent unknown Compact pane: Agent blocked Compact pane: Agent working Compact pane: Agent idle Compact pane: Agent done Compact pane: Agent unknown
AC12 — neutral selected / hover / focus across themes (M12) night-owl: selected row = neutral surface night-owl: hover row night-owl: focus ring distinct from selection light: selected row = neutral surface light: hover row light: focus ring distinct from selection high-legibility: selected row = neutral surface high-legibility: hover row high-legibility: focus ring distinct from selection colorblind-safe: selected row = neutral surface colorblind-safe: hover row colorblind-safe: focus ring distinct from selection 900 px viewport: selected row still neutral
Rubric 4 — axe scans (0 violations) Menu open Rename dialog open Add Repository dialog open

Other videos: J1-cancel-escape-pr-refresh.webm, J3-dismiss.webm, J5-no-default.webm. Playwright traces for all 18 tests are hosted as 551-test-results__*__trace.zip on the qa-assets prerelease.

Console (rubric 5): every journey asserted zero console errors after filtering one pre-existing mock artifact — the mock leaves sessions.get unimplemented, so [SessionStore] Failed to fetch session: main-N logs on any project creation (traced to tests/electronApiMock.ts Proxy fallback; not a product change). Recommend a follow-up mock sessions.get.

Passed automated

M1, M3, M4, M10, M13 in full; M2, M9, M12 for their renderer halves; AC1, AC2, AC4, AC5, AC6 (renderer), AC9 (mock approximation), AC10 (renderer), AC12, AC13.

Remaining for the human

  • M5–M7 — real agent starts once beside Explorer/Diff; no second tab across navigate/close/restart; default change is non-retroactive (needs a real Electron app + agent binary).
  • M8 — real missing-binary (or Cursor-on-Windows) case; M9 — no auto-retry after app restart.
  • M2git branch --show-current / worktree folder unchanged on a real worktree Pane.
  • M11 — onboarding and runpane repos add (structurally guarded by the Vitest import guard; not driven).
  • M12 — a pixel-level look in the real app; M14 — Settings copy read.
  • Owner decisions 1–3 in the PR body.

@tbrownio tbrownio left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Surviving Should-Fix / Nice-to-Have findings from the automated review + refactor passes (none block merge; details inline).

Comment thread main/src/services/workspaceEntry.ts Outdated
Comment thread main/src/services/workspaceEntry.ts Outdated
Comment thread frontend/src/components/ProjectSessionList.tsx Outdated
Comment thread frontend/src/components/Sidebar.tsx Outdated
Comment thread main/src/services/sessionManager.ts
@tbrownio

Copy link
Copy Markdown
Contributor Author

type: wrap-up-report
item: workspace-entry-sidebar
pr: #551

Wrap-Up Report — workspace-entry-sidebar

What was built

PR #551 (workspace-entry-sidebar, 7 commits on 169f8aa3/v2.4.87): three sidebar/workspace-entry behaviours from the approved brief.

  1. Rename from the sidebar, display-only. A shared Pane context menu (Rename · Pin/Unpin · Archive) on expanded, compact, and both pinned entries, keyboard-operable, opening a small rename dialog. One main-process helper serves the UI and the RunPane CLI: trims, rejects blanks, writes sessions.name plus a new name_manually_set provenance bit, emits the existing session-updated. The stored name is the label everywhere; PR title/number stay metadata; the AI namer honours the provenance bit; the inert "Auto-rename panes to pull request titles" setting is removed.

  2. One-shot default-agent launch on Add Repository. The dialog discloses the configured agent and command and sends launchDefaultAgent: true + disclosedAgent; projects:create runs launchDefaultAgentOnce:

    • single-flight, memoised (never retried);
    • validation before any panel exists (disclosure match, platform, executable via the existing agent doctor);
    • the main session created with the default shell Terminal suppressed;
    • PTY spawn + readiness under one 45 s deadline;
    • a durable receipt (projects.default_agent_launched_at) written last.

    Any failure after the panel exists takes one verified cleanup path and leaves Explorer/Diff only plus a non-modal notice with Open agent / Dismiss; a terminal that registers after cleanup is destroyed, and initializeTerminal refuses to spawn for a deleted panel.

  3. Neutral rows. StatusAccentBar and both row animations deleted; SessionStatusBadge in a fixed trailing slot (accessible unknown state added); selected/hover/focus on neutral surfaces.

Verification evidence

  • Main (Vitest): 871 passed / 1 skipped across 87 files at the final head, including the new session.rename (AC3), workspaceEntry (AC7/AC9/AC10/AC11 — single-flight, memo replay, every failure path incl. receipt-write and late-registration, exact initialState, static import guard), project.create (flag boundary incl. registry invocation), events (default Terminal suppressed only with autoCreateTerminal: false), and terminalPanelManager (deleted panel never spawns).
  • Renderer (Playwright, Electron mock): tests/sidebar-pane-actions.spec.ts + tests/sidebar-compact.spec.ts 14 passed; tests/add-repository.spec.ts 5 passed (AC1, AC2, AC4, AC5, AC6 renderer half, AC9 approximation, AC10 renderer half, AC11 clone dialog, AC12, AC13).
  • Gates: pnpm lint (oxlint, ESLint, boundary conformance, Knip) ✓ · pnpm typecheck ✓ · pnpm --filter frontend build ✓ · pnpm theme:contrast ✓ (AC14).
  • Backend-verifier (Step 3): pass on every command-shaped AC with quoted evidence; its two "fail" rows were the local compactSessionMenu variable names (naming only) and rubric items 5/6, which the QA drive then covered.
  • QA drive (Step 5): 18 driven tests, 45 screenshots, 7 journey videos, axe clean on menu / rename dialog / Add Repository dialog, zero console errors after one disclosed pre-existing mock artifact (sessions.get unmocked). No bug found. Evidence hosted on the qa-assets prerelease (551-*), galleries in the PR's QA comment.
  • Manual (AC6–AC8): not verified — need a real Electron app + agent binary; see Human action required.

Review outcome

  • Plan review: Must Fix 0 after pass 3/3 (dual lanes: Codex 9→4→1, Claude 5→4→3 across passes; all folded, cap reached with everything addressed).
  • Post-PR review: passes used 3/3 (dual lanes) + 2 scoped passes on the orphan-PTY / disclosure fixes; final state Must Fix: 0. Yield by pass — Codex 4 / 2 / 1, Claude 0 / 0 / 0 Must Fix (Claude found the hang and the AC9 semantics as Should Fix). Real defects caught post-PR: the session-created listener's double terminal, deletePanel rejection leaving a stale panel, launch flag without disclosure, non-keyboard menu, unbounded spawn wait, persist-then-reject panel, orphan PTY after the deadline, disclosure omitted → launch.
  • QA pass: 8 of 14 Manual items executed and passed (several with a real-app half left to the human), 6 left to the human, 0 QA findings.
  • Should Fix / Nice to Have deferred (as inline PR comments): the 200-line launchDefaultAgentOnce, the duplicated menu lifecycle between the two sidebars, unpruned memo maps, no rename length bound, compactSessionMenu naming.
  • refactor: applied 1 auto-fixable [S] (whitespace re-indent, git diff -w empty) · manual 2 below · adversary passes 0/3 (whitespace-only change verified by the Overseer directly) · refactor-deep's 2 "Critical" items restate owner decisions 1–2 and were not applied.
  • fresh-eyes: 3 passes (pass 3: no material change).

Human action required

  • ⛔ Decide (owner decisions recorded in the PR body — all three are already implemented as described; disagreeing means a follow-up change, and the manual tests can run after merge if you prefer):
    1. an agent that starts and then shows its own login/trust screen counts as a live tab, not a failed launch;
    2. the launch flag + disclosed agent authorises the launch for any authenticated projects:create caller (desktop, remote PWA, daemon);
    3. a failed automatic launch leaves Explorer/Diff only, while an ordinary new project keeps the pre-existing auto-created shell Terminal (AC9 read as "no agent panel, no launch").
  • ⛔ Manual tests left to you (real Electron app + agent binary): M5–M8, M9's restart half, M2's Git-identity check, M11's onboarding / runpane repos add halves, M12's pixel look, M14 Settings copy.
  • ✅ Blocks verification / QA (prerequisite): none.
  • ✅ You must do (deploy / external): none — no production surface; the two SQLite columns are additive, nullable, and self-applied by Pane's startup migration.
  • ✅ Done for you (applied in-run): implementation, 7 commits pushed over HTTPS, PR opened non-draft, 3+2 review passes with fixes landed, refactor whitespace commit, QA evidence hosted and embedded, survivors posted inline, awaiting-human-review label.

Residual risks / follow-ups

  • Authentication is invisible to the launch handshake (isCliReady is first-byte or a 10 s safety timer) — owner decision 1.
  • Any authenticated daemon client can trigger the permissive launch with the flag + disclosed agent — owner decision 2; a renderer-only channel would be the stricter alternative.
  • Add Repository can block up to ~50 s worst case behind a disabled button (bounded; hitting the deadline is a clean failure).
  • The default shell Terminal on ordinary new projects is pre-existing behaviour and unchanged; the no-default branch is unreachable through Settings.
  • tests/electronApiMock.ts lacks sessions.get, producing a console error on every project-creation flow in Playwright (pre-existing; recommend a mock sessions.get backed by mockSessions).
  • Refactor manual items (not applied): main/src/services/workspaceEntry.ts:27 — split launchDefaultAgentOnce into attempt / readiness / cleanup helpers [S]; frontend/src/components/ProjectSessionList.tsx:72 + frontend/src/components/Sidebar.tsx:197 — extract a shared usePaneContextMenu() hook [S].
  • Playwright MCP is not registered for Claude sub-agents on this machine; the QA drive used the repo's own Playwright harness (same driver, mock-backed). Real-Electron proof stays manual.

Dial record

zone: 1                # item; Overseer-escalated to effective 0 (permissive agent launch = trust boundary)
lanes: dual
passes: {plan: 3/3, post_pr: 3/3, post_pr_scoped_extra: 2}
findings: {plan: {pass1: {codex: 9, claude: 5}, later: {codex: 5, claude: 7}},
           post_pr: {pass1: {codex: 4, claude: 0}, later: {codex: 3, claude: 0}}}   # Must Fix counts; Claude lane raised 3+2+1 Should Fix
verifiers: {frontend: ran, qa_pass: ran}
qa_findings: 0
cleanup: {disposition: none_created, markers: [agent-e2e-20260829], registered: 0}
wall_clock: 2:13 (transcript first event 2026-08-29T18:24Z → wrap-up 20:37Z; single session, no resume)
deviations: "escalated 1→0: permissive agent auto-launch is a trust boundary; dual review lanes"
pr_size: {files_changed: 53, additions: 2412, deletions: 711}
tokens:
  codex: {total: 2546771, by_role: {implementer: 1111404, plan_reviewer: 354746, code_reviewer: 601036, code_researcher: 95070, backend_verifier: 66526, refactor_simple: 117464, refactor_deep: 200525}}
  claude_subagents: 949627   # plan-reviewer 362392, code-reviewer 373508, fresh-eyes 86776, frontend-verifier 126951 (harness usage summaries)
  overseer: 68782956         # transcript JSONL, dedup by message.id: input 23619 + cache_create 598829 + cache_read 67938206 + output 222302
  total: 72279354
spend_ratio: 23144.2         # tokens.total ÷ 3123 changed lines; cache reads dominate the overseer figure
agents:
  - {role: code-researcher, model: gpt-5.6-sol, effort: low, dispatches: 1, wall_clock: 2:09, tokens: 95070}
  - {role: plan-reviewer, model: gpt-5.6-sol, effort: medium, dispatches: 3, wall_clock: 8:43, tokens: 354746}
  - {role: plan-reviewer, model: claude-opus, effort: thinking, dispatches: 3, wall_clock: 20:42, tokens: 362392}
  - {role: implementer, model: gpt-5.6-sol, effort: medium, dispatches: 6, wall_clock: 38:27, tokens: 1111404}
  - {role: backend-verifier, model: gpt-5.6-sol, effort: low, dispatches: 1, wall_clock: 2:26, tokens: 66526}
  - {role: code-reviewer, model: gpt-5.6-sol, effort: medium, dispatches: 5, wall_clock: 12:14, tokens: 601036}
  - {role: code-reviewer, model: claude-opus, effort: thinking, dispatches: 3, wall_clock: 18:38, tokens: 373508}
  - {role: refactor-simple, model: gpt-5.6-sol, effort: medium, dispatches: 1, wall_clock: 1:55, tokens: 117464}
  - {role: refactor-deep, model: gpt-5.6-sol, effort: medium, dispatches: 1, wall_clock: 4:20, tokens: 200525}
  - {role: fresh-eyes, model: claude-opus, effort: thinking, dispatches: 2, wall_clock: 2:37, tokens: 86776}
  - {role: frontend-verifier, model: claude-sonnet, effort: thinking, dispatches: 1, wall_clock: 8:07, tokens: 126951}

Deltas vs plan

  • Added: main/src/events.ts + main/src/events.test.ts (default-Terminal suppression flag), main/src/services/terminalPanelManager.ts + test (deleted-panel spawn guard), frontend/src/components/settings/catalog.tsx (setting id removal), disclosedAgent on CreateProjectRequest and the disclosure-mismatch result — all from post-PR review rounds and recorded as plan deltas.
  • Dropped: the plan's withLock('workspace-entry-<id>') (single-flight map suffices) and the already-attempted result (memoised result is replayed instead).
  • Tracker: no Linear links on this item; handoff set empty. Merged-PR hygiene candidate TM-667unavailable (no Linear connector authenticated in this session).

@tbrownio tbrownio added the awaiting-human-review Run complete; awaiting human PR review label Aug 29, 2026
@tbrownio

Copy link
Copy Markdown
Contributor Author

type: postmortem
item: workspace-entry-sidebar
pr: #551
anchor: #551

Postmortem — workspace-entry-sidebar (ops-only)

Run operations (always)

Wall-clock 2:17 (UTC 2026-08-29 18:24:34 → 20:41:07, single session, no compaction). Human-idle inside the run: 0:00 — the transcript has exactly one genuine human message (the kickoff); every other user event is a tool result, task notification, or skill load. Stalls (turn-ends needing a nudge): none. Post-completion idle: n/a (postmortem posted at run end). Agent-active ≈ 100 % of span.

Gantt of the run: research → three parallel plan-review passes → one 17-minute implementer dispatch overlapped by diagram authoring → verifier, PR → three dual-lane review passes each followed by a resumed implementer fix round → two scoped reviews + refactor lanes → fresh-eyes, QA drive, wrap-up

Per-step timing table

Step / dispatch Start End Dur Tokens Est. cost Note
Step 0 preflight + load + brief.html 18:24 18:28 04:04 overseer gh/codex/pnpm probes, install no-op, intake artifact
code-researcher (Codex) 18:28 18:30 02:09 95,070 unknown (blended) ran while Overseer read anchors
Overseer anchor reading + plan.md 18:28 18:40 12:06 overseer serial with research (overlapped)
plan-reviewer pass 1 (Codex) 18:40 18:43 02:57 133,573 unknown parallel with Claude lane
plan-reviewer pass 1 (Claude) 18:40 18:48 07:22 144,459 unknown (no class split) 7:22 — the slower lane
plan revision 1 (Overseer) 18:48 18:52 04:37 overseer 14 MF folded
plan-reviewer pass 2 (Codex) 18:52 18:55 02:26 100,767 unknown parallel
plan-reviewer pass 2 (Claude) 18:53 18:59 06:27 104,699 unknown 6:27
plan revision 2 (Overseer) 18:59 19:02 02:37 overseer
plan-reviewer pass 3 (Codex) 19:02 19:05 03:20 120,406 unknown parallel
plan-reviewer pass 3 (Claude) 19:02 19:09 06:54 113,234 unknown 6:54
plan revision 3 + implementer launch 19:09 19:10 01:21 overseer cap reached
implementer (Codex, all 22 tasks) 19:10 19:27 17:05 400,698 unknown 17:05; diagram authored in parallel
Excalidraw diagram + hosting (Overseer) 19:11 19:20 08:41 overseer overlapped implementer
backend-verifier (Codex) 19:28 19:30 02:26 66,526 unknown 2:26
build gate + commits + push + PR open 19:30 19:34 03:06 overseer frontend build in background
code-reviewer pass 1 (Codex) 19:34 19:37 03:44 172,211 unknown 4 MF incl. events.ts double terminal
code-reviewer pass 1 (Claude) 19:34 19:41 07:03 140,096 unknown 0 MF / 3 SF
implementer fix round 1 (resume) 19:41 19:48 07:01 412,786 unknown 7:01
code-reviewer pass 2 (Codex) 19:49 19:52 02:38 134,187 unknown 2 new MF
code-reviewer pass 2 (Claude) 19:49 19:57 08:04 146,135 unknown 0 MF / 2 SF
implementer fix round 2 (resume) 19:58 20:05 07:03 103,336 unknown 7:03
code-reviewer pass 3 (Codex) 20:06 20:09 02:59 134,843 unknown 1 MF (orphan PTY)
code-reviewer pass 3 (Claude) 20:06 20:09 03:31 87,277 unknown 0 MF / 1 SF (same orphan PTY)
implementer fix round 3 (resume) 20:10 20:13 03:18 108,591 unknown 3:18
scoped code-reviewer 1 (Codex) 20:14 20:16 01:49 91,257 unknown 1 MF (disclosure omitted)
implementer fix round 4 (resume) 20:16 20:19 02:36 65,267 unknown 2:36
scoped code-reviewer 2 (Codex) 20:19 20:21 01:04 68,538 unknown clean
refactor-simple (Codex) 20:19 20:21 01:55 117,464 unknown parallel with scoped review
refactor-deep (Codex) 20:19 20:24 04:20 200,525 unknown 2 'Critical' = owner decisions
implementer refactor apply (whitespace) 20:24 20:26 01:24 20,726 unknown git diff -w empty
fresh-eyes PR body: Overseer + 2 agents 20:25 20:29 04:22 86,776 (agents) unknown pass 3 no change
frontend-verifier QA drive (Claude) 20:27 20:35 08:07 126,951 unknown 18 tests, 45 shots, 7 videos
QA hosting + body + evidence comment + inline comments 20:35 20:38 03:00 overseer 70 assets to qa-assets
wrap-up + fresh-eyes ×2 + label + notify 20:38 20:41 02:37 overseer

Aggregates (share of 2:17): Step 0 + research + plan writing 16 m (12 %) · plan-review loop 30 m (22 %) · implement 17 m (12 %) · verify + PR 6 m (4 %) · post-PR review + fix loop 46 m (34 %) · scoped/refactor 9 m (7 %) · fresh-eyes + QA drive + evidence 12 m (9 %) · wrap-up 3 m (2 %). Summed Overseer turnaround gaps between a report landing and the next dispatch: ≈ 14 m total, never more than ~4 m each (plan revisions were the largest). Human-idle 0.

Ranked stalls: none in-run. The longest productive waits were the implementer's first dispatch (17:05) and each Claude review lane (6–8 m per pass, consistently the slower lane by 3–5 m).

Per-phase pacing from commits (PDT): 12:32 feature commits ×2 → 12:49 fix 1 → 13:06 fix 2 → 13:14 fix 3 → 13:19 fix 4 → 13:26 whitespace refactor. Fix rounds every 8–17 m, each gated by a full dual-lane review pass.

Blocker inventory: AskUserQuestion gates 0 · rate-limit hits 0 · red gates 0 · environment notes 2 (no Playwright MCP registered for Claude sub-agents → QA drive used the repo's Playwright harness; the Claude reviewer's node ABI mismatched better-sqlite3, so it could not run three Vitest suites and read them instead — Codex lanes and the verifier ran them green).

Tokens & cost. Overseer (claude-fable-5, 1 h cache TTL): input 23,619 + output 222,302 + cache read 67,938,206 + cache write 598,829 → ≈ $91 (0.24 + 11.12 + 67.94 + 11.98). Claude sub-agents 949,627 (notification totals; per-class split not harvested → cost unknown). Codex 2,546,771 blended tokens used → cost unknown (no class split survives the blend). The overseer's cache reads are 94 % of raw volume: a 186-message turn loop over a ~370 k-token context.

The single change that would have cut the most time: the post-PR loop spent 46 m on three full dual-lane passes plus two scoped passes because the first implementer pass shipped a defect the plan could not have known about only by reading (events.ts auto-creates a Terminal on every session-created). A cheap, targeted "listener/side-effect sweep" in the code-researcher dispatch (grep every sessionManager.on(...) / panelManager event consumer touched by the plan) would have surfaced it at plan time, collapsing at least one review pass and one fix round (~15 m, ~700 k Codex tokens).

What we asked for

Owner-approved brief: display-only Pane rename from the sidebar; once-only default-agent launch on Add Repository with blank state on skip/failure; neutral sidebar rows with the status badge instead of the accent bar. Zone 1, escalated to effective 0.

Outcome vs intended

On-target as far as the run can tell — every AC has automated or QA-drive evidence except the real-agent manual items (AC6–AC8) and three owner decisions recorded in the PR. The outcome half of this postmortem runs after PR review.

Why the gap happened

Omitted — operations-only.

What to change so it doesn't recur

  1. claude/agents/code-researcher.md (dcouple/orchestra) — add to Method step 2: "For every event the plan will emit or listen to (emit('…'), .on('…')), enumerate all existing listeners and their side effects with path:line; a listener that creates, deletes, or launches something is a load-bearing finding." Evidence: main/src/events.ts:64-75 was missed by the researcher and by three plan-review passes; it cost one review pass + one fix round.
  2. claude/skills/do/SKILL.md — Step 1, plan-review dispatch: when the item touches process/PTY lifecycle, instruct reviewers to trace the full lifecycle including deadline/cancellation paths ("what happens if the awaited call completes after the caller gave up?"). The orphan-PTY-after-deadline defect (pass 3 + scoped pass) is the generic "late completion after cancellation" class; naming it in the dispatch would have caught it in pass 2 when the deadline was introduced.
  3. references/zones.md — data point, no edit proposed yet: at effective zone 0 the Claude review lane found 0 Must Fix in all three post-PR passes (its findings were Should Fix that Codex escalated or duplicated), while costing 373 k tokens; the Codex lane found every Must Fix. Two more runs like this would justify making the second lane plan-review-only at zone 0 for single-phase items.
  4. references/notify.md / claude/skills/do/SKILL.md Step 0 — preflight should probe for a registered Playwright MCP server (claude mcp list) when the item is browser-required and say explicitly which driver the QA drive will use; this run discovered the gap at preflight but only by reading the agent charter.

Dial record & right-sizing

zone: 1                # item; Overseer-escalated to effective 0 (permissive agent launch = trust boundary)
lanes: dual
passes: {plan: 3/3, post_pr: 3/3, post_pr_scoped_extra: 2}
findings: {plan: {pass1: {codex: 9, claude: 5}, later: {codex: 5, claude: 7}},
           post_pr: {pass1: {codex: 4, claude: 0}, later: {codex: 3, claude: 0}}}   # Must Fix counts; Claude lane raised 3+2+1 Should Fix
verifiers: {frontend: ran, qa_pass: ran}
qa_findings: 0
cleanup: {disposition: none_created, markers: [agent-e2e-20260829], registered: 0}
wall_clock: 2:13 (transcript first event 2026-08-29T18:24Z → wrap-up 20:37Z; single session, no resume)
deviations: "escalated 1→0: permissive agent auto-launch is a trust boundary; dual review lanes"
pr_size: {files_changed: 53, additions: 2412, deletions: 711}
tokens:
  codex: {total: 2546771, by_role: {implementer: 1111404, plan_reviewer: 354746, code_reviewer: 601036, code_researcher: 95070, backend_verifier: 66526, refactor_simple: 117464, refactor_deep: 200525}}
  claude_subagents: 949627   # plan-reviewer 362392, code-reviewer 373508, fresh-eyes 86776, frontend-verifier 126951 (harness usage summaries)
  overseer: 68782956         # transcript JSONL, dedup by message.id: input 23619 + cache_create 598829 + cache_read 67938206 + output 222302
  total: 72279354
spend_ratio: 23144.2         # tokens.total ÷ 3123 changed lines; cache reads dominate the overseer figure
agents:
  - {role: code-researcher, model: gpt-5.6-sol, effort: low, dispatches: 1, wall_clock: 2:09, tokens: 95070}
  - {role: plan-reviewer, model: gpt-5.6-sol, effort: medium, dispatches: 3, wall_clock: 8:43, tokens: 354746}
  - {role: plan-reviewer, model: claude-opus, effort: thinking, dispatches: 3, wall_clock: 20:42, tokens: 362392}
  - {role: implementer, model: gpt-5.6-sol, effort: medium, dispatches: 6, wall_clock: 38:27, tokens: 1111404}
  - {role: backend-verifier, model: gpt-5.6-sol, effort: low, dispatches: 1, wall_clock: 2:26, tokens: 66526}
  - {role: code-reviewer, model: gpt-5.6-sol, effort: medium, dispatches: 5, wall_clock: 12:14, tokens: 601036}
  - {role: code-reviewer, model: claude-opus, effort: thinking, dispatches: 3, wall_clock: 18:38, tokens: 373508}
  - {role: refactor-simple, model: gpt-5.6-sol, effort: medium, dispatches: 1, wall_clock: 1:55, tokens: 117464}
  - {role: refactor-deep, model: gpt-5.6-sol, effort: medium, dispatches: 1, wall_clock: 4:20, tokens: 200525}
  - {role: fresh-eyes, model: claude-opus, effort: thinking, dispatches: 2, wall_clock: 2:37, tokens: 86776}
  - {role: frontend-verifier, model: claude-sonnet, effort: thinking, dispatches: 1, wall_clock: 8:07, tokens: 126951}

Judgment: review effort slightly overdone — right-sized on the Codex lane, overdone on the Claude diff-review lane. Plan review (3 passes, both lanes) paid for itself: 14 Must Fix folded before code. Post-PR: Codex passes 1–3 found 4/2/1 Must Fix (all real; pass 3's orphan PTY was security-relevant), so the cap was earned; the Claude diff lane caught 0 Must Fix across three passes for 373 k tokens — the single dial that would have changed it is review_lanes: single for the post-PR loop at this zone (keep dual for plan review).

Acceptance

Still awaiting review (operations-only postmortem).

System changes

  • PR comment: (filled after posting)
  • Work item: local-only intake artifact (no tracker) — no second anchor.
  • Proposals 1–4 above: pending human verdict; nothing applied.

Tyler Brown added 3 commits August 29, 2026 14:07
Make the AC11 import-guard test separator-agnostic so it passes on
windows-2022. Drop the React Doctor prop-change effects by keying the
context-menu body, rename dialog body, and dialog error state instead.
Extract the duplicated sidebar menu/rename/focus lifecycle into
usePaneContextMenu, split launchDefaultAgentOnce into attempt, readiness,
and cleanup helpers, and forget a project's launch memo when the project
is deleted.

Claude-Session: https://claude.ai/code/session_01A6ystbZhfNVGeSUc7x8DNm
…eted

Each launch attempt carries an AbortController; projects:delete aborts it
before teardown and forgets the memo regardless of the delete result. The
attempt re-checks cancellation and the project row before every stage,
runs the normal provisional-panel cleanup, and never writes a receipt
after cancellation. Rejected attempts are memoised as a failed result,
and the rename dialog selects its prefilled text once.

Claude-Session: https://claude.ai/code/session_01A6ystbZhfNVGeSUc7x8DNm
@tbrownio

Copy link
Copy Markdown
Contributor Author

Final readiness evidence — 1e48beac

Branch contains current origin/main (no drift); only change since aa3babb is committing the brief (briefs/workspace-entry-sidebar.md), matching the convention from #512.

Review threads: 10 total, 0 unresolved. CI on aa3babb: all checks green (main tests on macOS/Ubuntu/Windows, Quality + Smoke, 12× Runpane wrapper matrix, Socket, React Doctor — 1 pre-existing-style warning, prefer-useReducer in AddProjectDialog.tsx, advisory).

Local, Node 22, this worktree:

  • pnpm lint → exit 0 (Oxlint/Knip blocking clean, 0 advisory findings)
  • pnpm typecheck → exit 0 (all four packages)
  • main Vitest (vitest run) → 88 files, 876 passed / 1 skipped
  • pnpm theme:contrast → 148/148 checks pass
  • Focused Playwright (add-repository, sidebar-compact, sidebar-pane-actions) on PLAYWRIGHT_PORT=452319 passed

Note for anyone rerunning locally: with the default port 4521 and reuseExistingServer, Playwright silently reused the main checkout's Vite server and 7 specs failed against main's UI (no Rename menu item, no launch notice). Set PLAYWRIGHT_PORT to a free port when another Pane dev server is running — not a code issue.

Ready for owner review/merge; no open decisions.

Sidebar rows and headers now use the navigation text family instead of body
text-primary, and the dark/light navigation-primary tokens sit a step below
body text so the rail reads as navigation. The pane hover card drops the PR
body, status prose, and 10px type for a compact card: name, branch, last
activity, PR number + state pill + diff size, title, and a View on GitHub
link.

Claude-Session: https://claude.ai/code/session_01LfUbWdfJ7xSx8a3TPq4XWC
@tbrownio

Copy link
Copy Markdown
Contributor Author

Follow-up — sidebar contrast + hover card (662b1963)

Contrast. Root cause: sidebar rows/headers used body text-text-primary (rgb 230/237/243 dark, 31/35/40 light) while the dedicated --color-text-navigation-* family already existed and went unused. Rows, section headers, and the rail now use the navigation family, and the dark/light navigation-primary tokens sit one step below body text (dark 200→188/196/205, light 31→58/64/71 — still ≥8:1 on the rail). Other themes override these tokens themselves, so only dark/light shift. pnpm theme:contrast 148/148, themeContrast.test.ts green.

Hover card. Rebuilt SessionDetailTooltip after Superset's card: name (+⌘N), BRANCH, last activity, then #n + state pill (reuses the title-bar Badge + paneTitle state mapping) + diff size, 2-line PR title, and a View on GitHub button (openExternal). Dropped the PR body markdown, status prose, created date, and 10px type. Tooltip gained contentClassName for the wider padding.

dark light

Checks: typecheck 0 errors, pnpm lint 0, frontend Vitest 30 files / 298 passed, focused Playwright (add-repository, sidebar-compact, sidebar-pane-actions, window-title-bar) 26/26 after fixing the pill label to "Open" (the spec pins the capitalised text).

The archive and pin buttons were transparent but still occupied their slots,
so every idle row reserved 48px to the right of its git stats. They now sit
left of the stats and collapse to zero width until the row is hovered or
focused, which leaves the stats on the row's right edge and gives the pane
name that width at rest. A pinned pane keeps its pin visible.

Claude-Session: https://claude.ai/code/session_01LfUbWdfJ7xSx8a3TPq4XWC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-human-review Run complete; awaiting human PR review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant