Skip to content

Preserve manual pane names and launch the default agent on repository add - #551

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

tbrownio wants to merge 15 commits into
mainfrom
workspace-entry-sidebar

Conversation

@tbrownio

@tbrownio tbrownio commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Manually named Panes should keep their labels as work progresses. This addresses the reported PR/commit label replacement and the workspace-entry brief: give users a display-only rename action, open a default agent when adding a repository, and make sidebar selection easier to distinguish from agent status.

Behavior

A Pane is a workspace; its display name is separate from its Git branch and worktree path. Right-click a Pane in the expanded sidebar, compact sidebar, or the pinned section in either mode → Rename → enter Human label → Save. The visible name becomes Human label; branch and directory remain unchanged. Blank input is rejected, Escape cancels, and duplicate labels are allowed.

The rename writes both the name and a persistent name_manually_set flag. Reloading sessions or reopening SQLite preserves both. A late AI-generated name cannot replace an explicit name, even when the user deliberately chooses the original fallback text. PR titles and commit statistics remain metadata. The active main-repository Pane is stored both in the sidebar list and as the current selection; both now update together, avoiding a stale sidebar label.

Adding a repository through the desktop dialog discloses the configured default agent and command. Creating the repository authorizes that launch with the existing permissive preset and no initial prompt. The repository is saved before main validates the disclosed agent, platform, and executable. Main then creates one agent tab, waits until its process is alive and the command has been sent, and writes a success receipt. An agent showing its own login/trust screen counts as live; authentication is not checked. Concurrent requests share one attempt. Navigation, tab closure, or app restart does not initiate another automatic launch: only the create-repository request triggers it. Failed attempts are remembered for the current process; after restart, reopening an existing repository does not call that creation path.

With no configured agent, no agent is launched. The ordinary project-opening path may still create a shell terminal; this differs from the brief’s zero-terminal blank state and needs owner acceptance.

If executable validation or launch fails, the saved repository remains available. Cleanup removes the provisional agent tab, leaves Explorer/Diff, and displays a non-blocking notice with Open agent and Dismiss. The manual button uses normal panel creation; automatic retry is disabled. Executable validation can take about five seconds, followed by a 45-second launch deadline. Deleting the project cancels an in-flight launch, and late completion cannot leave an orphan terminal.

Sidebar rows use neutral hover/selected surfaces and a compact accessible status badge. This also includes softer navigation text, right-aligned Git statistics with hover/focus row actions, and a simpler hover card with branch, activity, PR state/title and a GitHub link. Settings copy explains the default-agent use; the unused PR-title auto-rename setting is removed.

Integration and review

Current main was merged into this branch, preserving its existing createDefaultTerminalOnCreate contract and external-worktree labels. An independent integration reviewer found no must-fix issues. GitHub marks all 10 existing review threads resolved; that does not settle the product decisions listed below.

#573 remains open and is not superseded: its double-click inline editor is a separate affordance. Its relevant dual-copy store fix is also included here; its inline UI is not imported. The broader launch and sidebar changes remain specific to #551.

Visual overview

The existing diagram shows the original and proposed launch flow. It is historical design evidence, not a screenshot of the current head.

Before and after: repository entry and one-shot agent launch

Historical rename UI, from the earlier mock-browser QA:

Expanded context-menu rename
Rename dialog

Current QA media is local only; the images above document the earlier implementation.

Validation

Browser-tested commit: 71cc03240237cc6972fca118b9838344ad6794a6. Product/unit/build checks ran on 2ae78b37; the later commit only corrects the hover sequence in the browser regression.

  • Real SQLite reopen and reloading sessions from storage preserve the manual name and provenance through changed PR/commit metadata; a subsequent explicit rename still works.
  • Late AI-name regression preserves a manually chosen fallback-identical label.
  • Store regression updates both copies of an active main-repository Pane while preserving terminal output.
  • Main regression coverage exercises rename IPC, concurrent launch attempts, success receipts and failures, project deletion, terminal cleanup and RunPane integration.
  • Frontend unit suite: 34 files, 335 tests passed. Main/frontend builds and theme-contrast checks passed. Final lint/typecheck pass; main regression coverage totals 190 passing tests across 9 files.

QA verdict: partial. All 28 focused browser regressions pass on 71cc0324. Two visual journeys pass on the identical product code at 2ae78b37, covering rename/validation/hover card/narrow compact mode and agent disclosure/pending/failure/manual recovery. Ten screenshots and two videos are retained locally in /Users/tbrownio/.pane/closeout-2026-09-16/sidebar-evidence/; no new media was uploaded.

Marker: agent-e2e-551-20260916; dedicated port 4551; Electron APIs and agent outcomes are mocked. Real-agent/native restart and Windows/WSL checks remain manual. Product decisions are listed below. Detailed evidence and remaining checks. Hosted CI is green: Quality Checks + Smoke, macOS/Windows main suites, React Doctor and Socket. The wrapper matrix was path-filtered out. Full main suites: 1,037 passed / 2 skipped on macOS and Linux; 1,036 passed / 3 skipped on Windows. CI also passed 335 frontend tests, 47 preload routing cases and 29 functional smoke tests.

Remaining decisions and manual QA

  • Clear/reset semantics: blank names remain invalid under the approved brief. This PR supports changing a manual name, but no clear/reset-to-automatic action. Decide whether that should be a separate affordance before treating the “changes or clears” feedback as fully closed. Current code has no commit-subject auto-naming producer.
  • No configured agent: the defensive skip starts no agent; opening that project retains the pre-existing ordinary shell-terminal behavior. This is narrower than the brief's “blank with zero terminal panels” wording and still needs owner acceptance or a follow-up change.
  • Launch authorization: the flag plus disclosed agent is honored for authenticated projects:create callers, not restricted by transport to the desktop dialog. Clone/onboarding/RunPane registration do not send that flag. Confirm this authorization boundary.
  • Readiness: a live agent showing its own login/trust screen counts as a successful tab, as with normal manual launch. Confirm this behavior; the handshake does not verify authentication.
  • Native verification still needed: real-agent launch, navigation/tab-close/full-app-restart without relaunch, changing the configured default for a new repository, missing-binary failure, and Windows/WSL parity. Browser mocks and unit tests cover their local contracts, not those full native journeys.

Two additive SQLite columns are migrated at startup (name_manually_set, default_agent_launched_at). No new dependencies or release steps.

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) · 1 fixed · vs main

1 warning

src/components/AddProjectDialog.tsx

  • ⚠️ L21 Many related useState calls prefer-useReducer

Reviewed by React Doctor for commit 71cc032. 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
@parsakhaz

Copy link
Copy Markdown
Member

Additional customer evidence from a September 4 feedback call: the user explicitly prefers their manually assigned pane label, but reported that it does not always persist and can be replaced by the latest PR or commit label.

For this PR, the desired precedence is: an explicit user-assigned name remains authoritative until the user changes or clears it. Automatic PR/commit-derived labels should only act as a fallback when no custom name exists. A regression test covering refresh/restart and PR/commit updates would capture the reported failure mode.

@tbrownio tbrownio changed the title feat: sidebar pane rename, one-shot default agent launch, neutral row status Preserve manual pane names and launch the default agent on repository add Sep 16, 2026
@tbrownio

tbrownio commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

Closeout QA verdict: partial. Automated gates and the browser journeys pass; native agent/restart checks and the product decisions below remain open.

Tested browser commit: 71cc03240237cc6972fca118b9838344ad6794a6. Main integration and product changes were checked at 2ae78b37; the only later change moves the pointer off a clicked row before testing its tooltip. Main was merged without rewriting the existing PR history.

In response to parsakhaz’s naming feedback: a real SQLite close/reopen plus fresh SessionManager keeps Human label and its manual provenance. An actual UI rename is read back from the mock backend and used to initialize a fresh renderer; changed PR title and commit counts preserve the name in expanded/pinned/compact rows and the window title. A late AI-name result is ignored even when the explicit name equals the original fallback. The active-main-repository stale-sidebar bug also has a regression test. Current code has no commit-subject naming producer.

Check Result and evidence
Required lint Exit 0; “Boundary decoder lint conformance checks passed”; zero advisory anti-slop findings; Knip clean
Workspace typecheck Exit 0 across frontend, main, mobile, wrapper and shared
Main regression tests 190 passing across 9 files after fixing the test fixture; includes real SQLite persistence, late AI naming, workspace entry, deletion, rename IPC, RunPane and terminal lifecycle
Hosted main suites On 71cc0324: macOS/Linux “1037 passed / 2 skipped”; Windows “1036 passed / 3 skipped”; each “109 passed / 1 skipped” files
Hosted quality/smoke Pass: 335 frontend tests, 47 preload routing cases and 29 functional smoke tests
Other hosted checks React Doctor and Socket pass; wrapper matrix skipped by path filter
Frontend unit suite “Test Files 34 passed (34)”; “Tests 335 passed (335)”
Builds Main and frontend exit 0; sandboxed preload verified; production React Scan verification passed
Theme contrast Every gated theme reports “148/148 checks pass”
Focused browser regression “28 passed (13.4s)” on dedicated port 4551: add-repository, sidebar-compact, sidebar-pane-actions, window-title-bar
Visual browser QA “2 passed (5.3s)”: rename/blank validation/hover card/narrow compact mode and disclosed launch/pending/failure/manual recovery
Independent review No must-fix findings in integrated code; separate zero-context prose review completed and applied
GitHub review threads 10 total, 0 unresolved; this is thread state, not acceptance of remaining decisions

Current QA files are local in /tmp/pr-551-qa/, with a durable local copy under /Users/tbrownio/.pane/closeout-2026-09-16/sidebar-evidence/:

  • 01-selected-row.png06-compact-narrow.png: selection, context menu, blank validation, filled rename, hover card, 900px compact layout.
  • 07-agent-disclosure.png10-manual-recovery.png: disclosed Codex command, disabled pending state, failure notice, manually created tab.
  • videos/sidebar-closeout.qa-rename-journey-chromium/video.webm (1.92 s).
  • videos/sidebar-closeout.qa-repository-failure-recovery-journey-chromium/video.webm (2.92 s).
  • Five-fps luminance scan found one initial white frame at 0.0 s before page rendering in the recovery video; no later near-white frame bands. This is a coarse scan, not proof against all layout shifts.
  • pr-assets-manifest.json contains hashes and intended publication filenames. No release assets were uploaded, as instructed. Existing historical PR images were downloaded and verified; they remain explicitly labeled historical.

Harness limits: Electron APIs, repository creation, PR metadata and agent launch are mocked in browser QA. The history panel’s “Unable to load commit history” and the manual-tab loading placeholder are mock limitations. SQLite tests use temporary databases that are closed and deleted. No real repository registration, agent process, external message or service data was created.

Created Marker System Disposition
Browser fixture state agent-e2e-551-20260916 Local mock only Discarded with browser contexts
Test databases/worktrees pane-manual-name-*, pane-creation-* Local temporary directories Removed by test teardown
Screenshots/videos/logs PR 551 Local evidence folder Retained for review; not published

Remaining decisions / checks:

  1. Blank names stay invalid under the approved brief. Changing a name is supported; a distinct clear/reset-to-automatic action is not. Decide that affordance before calling the “changes or clears” request fully closed.
  2. No-default-agent skip retains ordinary shell creation when the project opens, instead of the brief’s literal zero-terminal blank state; owner acceptance or a follow-up change is needed.
  3. Confirm that the disclosed launch flag authorizes all authenticated projects:create transports, and that an agent login/trust screen counts as a live tab.
  4. Real-agent launch, missing-binary behavior, navigation/tab-close/full native app restart without relaunch, a changed default on a new repository, and Windows/WSL parity remain manual. This run did not drive a real Electron agent session; mock and service-level evidence cannot substitute for it.

#573 is still open and only overlaps the rename affordance plus the shared-store defect. Its double-click editor remains separate; #551 is not superseded. All applicable CI checks are green. The dedicated Vite process was stopped and the worktree is clean. No merge, close, release or deployment was performed.

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.

2 participants