Skip to content

CPLAT-11459: daily/artifact-centric view (day → project → session) + startup stall fix - #155

Merged
gavin-jeong merged 1 commit into
masterfrom
CPLAT-11459-daily-view
Aug 13, 2026
Merged

gavin-jeong merged 1 commit into
masterfrom
CPLAT-11459-daily-view

Conversation

@gavin-jeong

Copy link
Copy Markdown
Collaborator

JIRA: https://sendbird.atlassian.net/browse/CPLAT-11459

Summary

Adds a daily / artifact-centric view to the session browser: a day → project → session tree whose preview answers "what came out of this day?" rather than showing conversation text. D toggles it from the project browser; each view keeps its own preview mode, and the cursor follows across the swap.

The existing browser answers "which sessions exist". It does not answer "what did I actually produce today" — the PRs, Jira issues, published artifacts, and plans a day's work left behind, with a path back to the conversation turn that produced each one.

What it does

  • Groups sessions by the calendar day of their last activity, newest first. A session that spanned several days appears once, under the day it was last active.
  • Nests day → project → session, each tier aggregating what it needs: output rollup badges on day rows, lifecycle + message counts on project rows.
  • The preview is a "Produced (N)" digest — never conversation text. Duplicate outputs across sessions collapse into one row anchored to the session that produced it first.
  • Enter jumps to the conversation turn where that output first appeared · o opens it externally (URL → path) · y copies.
  • Fold state is day-scoped, so folding a repo under one day does not fold it under every other day.

Startup: 2726ms → 227ms to first frame

NewApp was spending 2.46s in cleanupStaleRemoteSessions(), which pings every saved remote session synchronously. One saved remote whose SSH host is unreachable costs the full ConnectTimeout before ccx paints anything.

It now runs as a command dispatched from Init(). Batched commands run concurrently, so the sweep overlaps the session scan and costs nothing on screen; a remotesCleanedMsg handler drops the virtual row only when the remote actually vanished.

before after
NewApp 2648ms 85ms
to first frame 2726ms 227ms

Separately, tmux.HasClaude read the full ps -e table once per pane. One memoized process-tree snapshot (2s TTL) + BFS replaces it:

before after
CurrentWindowClaudes 219ms 106ms cold / 0s warm
claudesInWindow 185ms 55ms
resize 305ms 146ms

Design gap closed: first-occurrence message UUID

session.SessionRef recorded FirstSeen (a timestamp) but not the uuid of the entry where the ref first appeared — so a PR/Jira row had no jump target at all.

Adds SessionRef.FirstSeenUUID, populated in both extraction paths (the raw-line scanner via a new lineUUID(), and ExtractSessionRefs via entries[i].UUID) and carried through ResolveRef's cache merge at both getCachedRef sites.

That last part matters: the resolve cache is keyed by URL and shared process-wide, so the same PR seen in two sessions would otherwise serve session B's uuid to session A. Reverting it fails with got "sessionA-entry", want "sessionB-entry".

Gob compatibility with pre-upgrade caches is pinned by a test — gob matches by field name, so an old .ccx-cache.gob decodes with FirstSeenUUID="". Worth pinning because loadCache returns an empty cache on any decode error: a break would silently cost every user a full rescan.

Correctness bugs fixed along the way

panic prompt[:maxW-3]slice bounds out of range [:-1] at narrow list widths (reproduced at width 11), crashing the whole render
CJK corruption project names and prompts were byte-sliced against a cell budget, cutting mid-rune and computing the wrong width; now runewidth-based
phantom shortcuts on a day row the pane always renders the outputs digest, yet 19 still fired preview-mode switches and the hint listed all ten. Suppressed for those rows only — plain project rows in the non-daily browser keep them, since selectedSession() falls back to a real session there
frozen highlight the cursor highlight never moved on day-scoped project rows (re-render branch only handled day rows)
silent copy y copied nothing for path-only outputs (plan files), reporting "No URL for this output"
wrong glyph a day's last project always drew ├─projectItem had no treeLast field
cursor lost on rebuild aggregate rows were re-found via their newest session, so the 3s live tick moved the anchor on an active day and dropped the cursor into a child row. Now matched on their own identity (dayKey, dayKey+path)
toggle stranded the cursor when the destination row sat inside a folded parent, the restore only searched VisibleItems() and fell through. The destination is now built fully expanded and the target's real ancestor chain is walked, so a new grouping mode gets this for free — and only those ancestors are unfolded, since fold state is persisted and a blanket expand would follow the user into the next launch

Testing

gofmt and go vet clean; full suite green with an isolated HOME. Every regression test was verified by reverting its fix and confirming the test fails — e.g. the Enter jump fails with cursor landed on entry "u1", want the first mention u2, exactly the reported symptom.

… stall fix

Adds a daily view to the session browser: a day → project → session tree
whose preview answers "what came out of this day?" rather than showing
conversation text. `D` toggles it from the project browser; each view keeps
its own preview mode, and the cursor follows across the swap.

The preview is a "Produced (N)" digest — PRs, Jira issues, artifacts, plans.
Enter jumps to the conversation turn where an output FIRST appeared, o opens
it externally, y copies it. Duplicate outputs across sessions collapse into
one row anchored to the session that produced it first.

Startup: 2726ms → 227ms to first frame. NewApp was spending 2.46s inside
cleanupStaleRemoteSessions(), which pings every saved remote synchronously —
one unreachable SSH host cost the full ConnectTimeout before anything painted.
It now runs as a command from Init(), concurrent with the scan. Separately,
tmux.HasClaude read the whole `ps -e` table once per pane; one memoized
process-tree snapshot replaces it (CurrentWindowClaudes 219ms → 106ms cold,
0s warm).

Closes a design gap behind the jump: SessionRef recorded FirstSeen but not
the uuid of the entry where a ref first appeared, so PR/Jira rows had no jump
target. Adds FirstSeenUUID, populated in both extraction paths and carried
through ResolveRef's cache merge — that cache is keyed by URL and shared
process-wide, so without it the same PR seen in two sessions serves session
B's uuid to session A. Gob compatibility with pre-upgrade caches is pinned by
a test: loadCache returns an EMPTY cache on decode error, so a break would
silently cost every user a full rescan.

Correctness fixes found along the way:
- panic: prompt[:maxW-3] crashed the render at narrow list widths (width 11)
- CJK: project names and prompts were byte-sliced against a cell budget,
  cutting mid-rune; now runewidth-based
- number keys 1-9 fired preview modes that cannot exist on a day row, and the
  hint line advertised all ten; suppressed for those rows only
- cursor highlight was frozen on day-scoped project rows (re-render branch
  only handled day rows)
- y copied nothing for path-only outputs (plan files)
- a day's last project always drew ├─ (projectItem had no treeLast)
- rebuild re-found aggregate rows via their newest session, so the live tick
  dropped the cursor into a child row on an active day
- toggling into a folded destination stranded the cursor; the destination is
  now built fully expanded and only the target's own ancestors are unfolded

JIRA: https://sendbird.atlassian.net/browse/CPLAT-11459
@upwind-code-us

upwind-code-us Bot commented Aug 13, 2026

Copy link
Copy Markdown

Upwind Upwind Code Scan - ✅ Proceed with Deployment

0 newly introduced vulnerabilities · 0 resolved · 2 total in this PR vs master

🔶 1 High | 🟢 1 Low

View full analysis in Upwind Console

Scan completed in 18s

Scan history (1 scan)
Commit Scanned at New Resolved Net
5f95382 < 2026-08-13 14:33 UTC 0 0 0

Last scanned: 5f95382 · 2026-08-13 14:33 UTC

@upwind-code-us

upwind-code-us Bot commented Aug 13, 2026

Copy link
Copy Markdown

Upwind Upwind IaC Scan - ✅ Proceed with Deployment

0 newly introduced misconfigurations · 0 resolved · 0 total in this PR vs main

View full analysis in Upwind Console →

Scan completed in 4s

Scan history (1 scan)
Commit Scanned at New Resolved Net
5f95382 < 2026-08-13 14:33 UTC 0 0 0

Last scanned: 5f95382 · 2026-08-13 14:33 UTC

@jinsekim jinsekim left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM!

@jinsekim jinsekim added the auto-review/approved Auto-approved by the Slack auto-reviewer bot label Aug 13, 2026
@gavin-jeong
gavin-jeong merged commit b13641e into master Aug 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto-review/approved Auto-approved by the Slack auto-reviewer bot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants