Skip to content

fix: liveness, session names, project identity, search ordering and load time (v1.6.0) - #69

Open
Mr-Godot wants to merge 3 commits into
mainfrom
fix/26-0802-rewind-bugfix-campaign
Open

fix: liveness, session names, project identity, search ordering and load time (v1.6.0)#69
Mr-Godot wants to merge 3 commits into
mainfrom
fix/26-0802-rewind-bugfix-campaign

Conversation

@Mr-Godot

@Mr-Godot Mr-Godot commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Fixes the issues that were blocking release, found by a 7-track investigation swarm with adversarial critics on each proposed fix.

What was actually wrong

Search returning 1 result was not a search bug. getCacheDir() ignored CLAUDE_HOME, so running npm run e2e pointed the scanner at fixtures but left every cache path aimed at the real ~/.claude-dashboard. It indexed the 3 fixture sessions and pruned all 443 real ones. Fixed at the code level via getDashboardDir(), plus a fail-fast guard in playwright.config.ts.

False "active" sessions came from inferring liveness by transcript mtime. Measured drift between mtime and the last real message reaches 174 days, and an external process touches these files hourly without appending. Liveness now comes from Claude Code's own process registry (~/.claude/sessions/*.json), gated on the recorded pid actually running. waiting (live but idle) is now distinct from working.

/rename showing agents-0a came from the registry's auto-derived placeholder names, and from that registry only existing while a process is alive. The whole tier is deleted; the durable name is the transcript's own title entry. Measured contribution of the removed tier: 163 duplicates, 1 wrong value, 15 junk, 0 unique correct values.

Slow loads were an uncached full re-parse of the ~1 GB corpus on every stats request, plus a 3s liveness poll that triggered a full scan of every session file.

Measured on the live corpus (411 sessions, ~1 GB)

before after (warm)
session scan 11.6s 140ms
stats 9.1s 9ms
search "rewind" 1 result 81 sessions, 120ms

Also fixed

  • Search ordering is newest-first; each session is represented by its most recent match so date and snippet agree; the limit counts sessions, not raw matches
  • Search failures are visible instead of collapsing into an empty result set; a rejected search no longer retries forever
  • Projects are identified by their recorded working directory rather than a lossy path encoding, so moving a folder no longer splits a project. Dead paths are flagged, not hidden, and their sessions stay listed and searchable
  • Launching a session whose folder no longer exists returns 409 with the missing path instead of silently spawning into a dead directory
  • Empty states render a real card; refreshing keeps previous rows; a stale saved filter no longer flashes "no matches"; an unset theme preference resolves to dark

Verification

  • 761 tests pass (up from 631), 44 files
  • typecheck clean, lint 0 errors (15 pre-existing warnings unchanged)
  • build green, client and SSR
  • Client bundle scanned post-build for node:fs, better-sqlite3, readdirSync, process.kill, os.homedir — zero hits
  • Every fs write target verified to resolve under .claude-dashboard; ~/.claude remains read-only, with a regression test spying on write calls during a full scan plus a liveness poll
  • No dependency changes

Known gaps

  • subagentFingerprint cost is asserted rather than measured (warm stats at 9ms suggests it is fine)
  • The plan's manual checks were not performed: Launch on a months-old session, and 10 consecutive searches against the dev server log

…butions, fix search ordering and silent failures

P1 lib/scanner/live-sessions.ts: read ~/.claude/sessions/*.json (pid + status),
   filter by process.kill(pid,0) liveness, memoized 1s. Read-only.
P2 active-detector: drop the mtime heuristic that marked months-dead sessions
   'working'. isActive stays true only for 'working' so waiting sessions do not
   bypass the hidden-project filter, readmit stubs, or pin the 5s poll.
   The 3s active poll no longer runs a full 454-file scan.
P3 stats-parser: cache per-session contributions keyed on a fingerprint that
   includes the subagent directory, killing the 11.1s re-parse per stats request.
   persistSummaryCache now skips the write when nothing changed.
P4 search: stop swallowing provider failures into an empty result, log the real
   driver error, coalesce concurrent refreshes, yield during indexing, and stop
   the retry storm on a rejected search query.
P5 search: order hits newest-first (ORDER BY ts DESC, sid tiebreak), make the
   representative row the most recent matching block so date and snippet agree,
   and apply the limit as a session count server-side.
…lation

G  liveness gaps: the 3s poll now applies the same busy-mtime rule as the scan,
   so a killed-while-busy session can no longer be flipped back to 'working'.
   Forced search refresh no longer no-ops behind an in-flight non-forced pass.
P6 names: drop the ~/.claude/sessions/*.json name tier entirely (it contributed
   163 duplicates, 1 wrong value, 15 derived junk names like 'agents-0a', and 0
   unique correct values). The durable name is the JSONL custom-title. Fixes
   firstUserMessage for string-typed content and skips injected turns.
   SUMMARY_CACHE_VERSION 4 -> 5 to evict poisoned entries.
P7 identity: resolve each project from its recorded cwd into a new realPath
   field (projectPath keeps its lookup meaning), disambiguate same-basename
   projects, flag dead paths instead of hiding them, and return 409 from the
   launch handler rather than spawning into a directory that no longer exists.
P8 UI: shared EmptyState, honest loading affordance that keeps previous rows,
   suppressed stale-filter flash, surfaced search index staleness, and an unset
   theme preference now resolves to dark in both the pre-paint script and the
   provider.

Also fixes a pre-existing data-loss bug: getCacheDir() ignored CLAUDE_HOME, so
the e2e suite wrote to the real ~/.claude-dashboard and pruned the live search
index to its 3 fixture sessions. All dashboard paths now derive from
getDashboardDir(), which honours CLAUDE_HOME.
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

PR Size Analysis

  • Total changes: 6956 lines
  • Additions: 6101 lines
  • Deletions: 855 lines
  • Size: size/large

This label helps reviewers prioritize PRs by size.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant