Skip to content

fix: org chart resume button + name collision - #116

Merged
aterrylu merged 1 commit into
mainfrom
terry/orgchart-fixes
Apr 10, 2026
Merged

fix: org chart resume button + name collision#116
aterrylu merged 1 commit into
mainfrom
terry/orgchart-fixes

Conversation

@aterrylu

Copy link
Copy Markdown
Owner

Summary

Two bug fixes for the org chart sidebar pane, plus a parallel client-side fix caught during polish.

Bug 1: Resume button on stopped agent cards

Stopped/exited agents in the org chart only had a trash (remove) button. Now the hover overlay shows a green debug-start (Resume) button beside the trash, wired to the existing resumeSession store action (isAutonomosAgent: true), which calls POST /api/sessions/:id/resume (from #110) to restore the full spawn config from persisted state.

Only shown when !isRunning — running agents still get just the kill/remove button.

Bug 2: Name collision — both agents show as "online"

Killing an agent and spawning another with the same name made both appear running in the org chart. Two root causes in buildOrgChart():

  1. Node Map was keyed by lowercased name — the second session silently overwrote the first.
  2. The wire-up loop looked up the parent by name and pushed the same node object into parent.children once for each duplicate, so a child could appear multiple times under one parent.

Fix: Nodes are now keyed by claudeSessionId (unique). Sessions are first grouped by name, then chooseCanonical() picks one canonical session per name:

  • Prefer running sessions over exited ones
  • Break ties by newest persistedAt (most recently intended instance)
  • Falls back to newest exited if all duplicates are exited
  • Backward-compat: treats missing status field as "running" (pre-feat: persist exited sessions for resume #110 sessions)

OrgNode interface gains status + claudeSessionId so the frontend can distinguish live/exited directly from the chart data, no name lookup needed.

Bug 2.5 (caught by polish review): Client-side collision hazard

useAgentStatusByName in HierarchyPanel.tsx was keyed by lowercased name too — reintroducing the exact collision class the server fix eliminated, for activity state (currentTool, working/needs_input, etc.). Renamed to useAgentStatusById and keyed by claudeSessionId. AgentCard now looks up activity state by node.claudeSessionId.

Approach — canonical selection (design call)

For duplicate names, we pick one canonical session and hide the duplicates from the org chart entirely (Option A from the design discussion with @aterrylu):

  • Running wins over exited
  • Newest persistedAt wins among the preferred pool
  • Dropped duplicates are reachable via the sidebar "exited agents" toggle

A follow-up issue tracks adding a matching hide-exited toggle to the org chart itself — it has gnarly orphaned-children cases when an exited parent has running descendants, and was deemed out of scope for this PR.

Diagram

flowchart TB
    subgraph Before["Before (buggy)"]
        B1[sessions.json] --> B2["Map&lt;name, Node&gt;<br/>collision loses data"]
        B2 --> B3["parent.children.push(node)<br/>duplicates under parent"]
    end
    subgraph After["After"]
        A1[sessions.json] --> A2["Group by name<br/>Map&lt;name, Session[]&gt;"]
        A2 --> A3["chooseCanonical()<br/>running wins, newest wins"]
        A3 --> A4["Map&lt;claudeSessionId, Node&gt;<br/>unique identity"]
        A4 --> A5["Tree wired by<br/>canonical sessions only"]
    end
Loading

Test plan

  • 5 new regression tests in orgChart.test.ts covering: running-wins, newest-wins tiebreak, all-exited fallback, no-duplicate-under-parent, schema shape. Includes a startup sweep that removes stale orgchart-test-* entries to survive crashed test runs.
  • make check — 68/68 tests pass, Biome + TSC clean
  • Visual QA deferred to reviewer — dev server on this branch would share ~/.autonomos/sessions.json with prod (tracked as a separate follow-up), making local make dev QA unsafe while prod is up. Please eyeball on the live dashboard after pulling the branch:
    • Resume button appears on stopped agent cards in the org chart, hover works, click resumes the agent, card updates to running
    • Kill an agent, spawn a new one with the same name — only the running one shows as online in the org chart
    • Existing org chart features (drag to open pane, set_manager, etc.) still work

Follow-ups (separate PRs, not this one)

  1. Config dir isolation~/.autonomos/ is shared between prod :3100 and dev :3101; dev's resume sweep nearly cloned the running fleet during my QA attempt. Will ship as a stacked PR immediately after this one.
  2. Hide-exited toggle for org chart — needs careful handling of exited parents with running children. Recommend spawning a worker.
  3. handleRemove silent failure — confirm dialog stays open with no visible feedback if the backend rejects the remove. Pre-existing in the sidebar path too, out of scope here.
  4. Resume button loading feedback — currently just an opacity toggle. Swap for a spinner/pulse.
  5. isProduction detection via existsSync(dashboardDist) — breaks when tsc --build writes to dist/ without index.html. Needs an explicit flag or NODE_ENV check.
  6. Makefile tsx --env-file=X watch src/index.ts argument ordering — tsx parses watch as the script name. Works in main by accident. Reorder to tsx watch --env-file=X src/index.ts.

Files changed

  • packages/server/src/orgChart.tsbuildOrgChart() rewrite, chooseCanonical(), OrgNode schema
  • packages/server/src/__tests__/orgChart.test.tsnew, 5 regression tests
  • packages/dashboard/src/components/HierarchyPanel.tsx — Resume button, OrgNode type, useAgentStatusById rename + ID key, targetSession lookup
  • packages/dashboard/src/components/Codicon.tsxdebug-start icon added

🤖 Generated with Claude Code

@nox-0x nox-0x left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Solid fix. Name collision by keying nodes on claudeSessionId (unique) instead of lowercased name (collision-prone) is exactly right — the chooseCanonical() tiebreak logic (running > exited, newest persistedAt wins) is clean and well-tested. Resume button wiring is correct. Tests are thorough including the startup sweep for crashed-run cleanup. No blocking issues.

@aterrylu
aterrylu marked this pull request as ready for review April 10, 2026 11:13
Two fixes to the org chart sidebar pane:

1. Resume button on stopped agent cards — hover overlay now shows a
   green debug-start button alongside the trash button when the agent
   is not running. Wires to the existing resumeSession store action
   with isAutonomosAgent: true, which calls POST /api/sessions/:id/resume
   (added in #110) and restores the full spawn config (template,
   manager, cwd, autonomousMode) from persisted state.

2. Name collision — killing an agent and respawning with the same name
   no longer shows both as running. buildOrgChart() previously keyed
   its node Map by lowercased name, so the second session overwrote
   the first and the same node object was pushed into the parent's
   children array multiple times. Now keys nodes by claudeSessionId
   (unique), groups sessions by name, and picks one canonical session
   per name via chooseCanonical(): prefer running sessions, break ties
   by newest persistedAt. OrgNode interface gains status +
   claudeSessionId fields so the frontend can distinguish live/exited
   without a name-based lookup.

Also fixes a parallel client-side collision hazard: useAgentStatusByName
was keyed by lowercased name too, reintroducing the same bug for
activity state (currentTool, working status). Renamed to
useAgentStatusById and keyed by claudeSessionId.

Adds 5 regression tests covering collision scenarios.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@aterrylu
aterrylu force-pushed the terry/orgchart-fixes branch from 1947dbb to e577117 Compare April 10, 2026 11:28
@aterrylu
aterrylu enabled auto-merge (squash) April 10, 2026 11:28
@aterrylu
aterrylu merged commit a78a99b into main Apr 10, 2026
1 check passed
@aterrylu
aterrylu deleted the terry/orgchart-fixes branch April 10, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants