Skip to content

feat(web): show machine + last-active in session detail header - #1244

Merged
tiann merged 4 commits into
tiann:mainfrom
heavygee:feat/session-header-machine-meta
Jul 30, 2026
Merged

feat(web): show machine + last-active in session detail header#1244
tiann merged 4 commits into
tiann:mainfrom
heavygee:feat/session-header-machine-meta

Conversation

@heavygee

@heavygee heavygee commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Show machine label and relative last-active age in the session detail header meta row (alongside flavor/model), so multi-machine estates keep that signal after leaving list filter chips.
  • Resolve machine names the same way as session-list chips: displayName → host → short machineId.
  • Treat detail-cache activeAt keep-alives as render-relevant (SessionHeader reads them) and tick relative age every minute.

Test plan

  • cd web && bun run test -- src/components/SessionHeader.test.tsx src/hooks/useSSE.test.ts (21 pass)
  • bun run typecheck:web
  • Open a session on a multi-machine hub; header shows machine: <label> and a relative age with absolute tooltip
  • Rename a machine in Settings; header label updates after machines query refresh
  • Session with only host / short id still shows a machine label
  • Active session age advances on keep-alive / minute tick

Fixes #1241

@github-actions github-actions Bot 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.

Findings

  • [Major] The new last-active field reads activeAt, but the session-detail SSE cache still discards activeAt-only heartbeats. Active sessions can therefore appear stale even while the hub receives fresh keep-alives. Evidence web/src/components/SessionHeader.tsx:150, related context web/src/hooks/useSSE.ts:66.
    Suggested fix:

    // Detail-session cache: activeAt now affects rendered output.
    for (const [key, value] of Object.entries(patch)) {
        if (current[key] !== value) return false
    }
  • [Minor] The relative label is memoized only from the stored timestamp and translator, so it never advances when an inactive session receives no further updates. Evidence web/src/components/SessionHeader.tsx:151.
    Suggested fix:

    const [relativeTimeTick, setRelativeTimeTick] = useState(0)
    useEffect(() => {
        const timer = window.setInterval(() => setRelativeTimeTick((tick) => tick + 1), 60_000)
        return () => window.clearInterval(timer)
    }, [])
    const ageLabel = useMemo(
        () => lastActiveAt > 0 ? formatRelativeTime(lastActiveAt, t) : null,
        [lastActiveAt, t, relativeTimeTick]
    )

Questions

  • None.

Summary

  • Review mode: initial
  • Two freshness defects found in the new last-active display. No other high-confidence correctness, security, data-loss, performance, or maintainability issues found in the full diff.

Testing

  • Not run (automation; PR code was not executed). Static coverage gap: update the detail-SSE heartbeat test and add a fake-timer rollover test for the header age.

HAPI Bot

Comment thread web/src/components/SessionHeader.tsx
Comment thread web/src/components/SessionHeader.tsx

@github-actions github-actions Bot 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.

Findings

  • None.

Questions

  • None.

Summary

  • Review mode: follow-up after new commits
  • No high-confidence correctness, security, regression, data-loss, performance, or maintainability issues found in the full latest diff. The prior activeAt cache and relative-time rollover findings are addressed at this head. Residual risk: multi-machine rename/fallback behavior remains primarily unit-tested rather than browser-integrated.

Testing

  • Not run locally (automation; PR code was not executed). GitHub test check passed for this head. Existing coverage now exercises detail-cache activeAt relevance, minute rollover, and machine-label fallback.

HAPI Bot

@heavygee
heavygee force-pushed the feat/session-header-machine-meta branch from a185115 to 2ae049c Compare July 30, 2026 01:57

@github-actions github-actions Bot 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.

Findings

  • None.

Questions

  • None.

Summary
Review mode: follow-up after new commits

  • No high-confidence correctness, security, regression, data-loss, performance, or maintainability issues found in the full latest diff.
  • Residual risk: live machine-rename refresh and fallback behavior remain unit-tested rather than browser-integrated.

Testing

  • Not run (automation; PR code was not executed).
  • GitHub test check was still in progress at review time.
  • Existing coverage exercises detail-cache activeAt relevance, minute rollover, machine-label fallback, and the extracted todo helper.

HAPI Bot

heavygee added a commit to heavygee/hapi that referenced this pull request Jul 30, 2026
… meta

Co-authored-by: Cursor <cursoragent@cursor.com>
@heavygee

Copy link
Copy Markdown
Collaborator Author

Remat re-thin (Meta P0)

Tip force-pushed for soup remat onto intermediate 7ef4226a3 (rich-composer merge):

  • 77f2e8f09 — SessionHeader machine + last-active (kept LinkPr / soup header bits)
  • ba35a52c0 — activeAt keep-alive + 60s relative-age tick

Did not touch SessionList.tsx / sessionRowHelpers.ts (already on remat base; bindings verify OK).

merge-tree vs 7ef4226a3: clean.

Note: tip ancestry is temporarily the remat intermediate (not upstream/main) so remat only applies these 2 commits. After Meta remat lands I will re-thin back onto upstream/main for this PR's reviewable diff.

@heavygee
heavygee force-pushed the feat/session-header-machine-meta branch from 2ae049c to ba35a52 Compare July 30, 2026 02:22
@heavygee

Copy link
Copy Markdown
Collaborator Author

Remat re-thin (temporary tip)

Soup remat needed tip on exact intermediate 7ef4226a3 (not upstream/main).

Force-pushed feat/session-header-machine-metaba35a52c0c5c744d621cebb5048124965e9dfb7b.

Product delta vs that base is header + useSSE + locales only (no SessionList / helpers churn). Meta rematting now.

Note: this tip has soup ancestry (garden paths in range). After remat is green I will re-thin back onto upstream/main so this PR stays reviewable / cold-review-clean again.

@github-actions github-actions Bot 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.

Findings

  • [Blocker] The force-push imported the integration-soup branch and made the PR unmergeable — the previously reviewed head differed from main in 9 files, while this head now changes 450 files / +47,857 lines, including unrelated Overseer, runner-upgrade, Garden, import, and media work (.github/workflows/overseer-replay.yml:1). The resulting mixed tree also fails TypeScript compilation at web/src/components/AssistantChat/HappyThread.tsx:1013, web/src/router.tsx:722, and multiple other locations. Rebuild this PR from origin/main with only its four clean feature commits.
    Suggested fix:

    git fetch origin main
    git switch -c pr-1244-clean origin/main
    git cherry-pick 82fb3267 68aab89c b50205f3 2ae049c9
    

Questions

  • None.

Summary
Review mode: follow-up after new commits

  • Blocked: current head has unrelated branch ancestry and does not typecheck. Restore the clean PR history before another review.

Testing

  • Not run (automation; PR code was not executed).
  • GitHub test check failed during bun typecheck; representative errors: nonexistent props.outlineTitle, undefined projectCount, missing exports, and missing modules.

HAPI Bot

Comment thread .github/workflows/overseer-replay.yml Outdated
heavygee and others added 2 commits July 30, 2026 02:32
Multi-machine estates lose the machine signal after leaving list filter
chips; surface machine label + relative age in SessionHeader meta row.
Fixes tiann#1241.

Co-authored-by: Cursor <cursoragent@cursor.com>
Treat detail-cache activeAt keep-alives as render-relevant now that the
header reads them, and tick relative age every minute so labels advance
without a session prop change.

Co-authored-by: Cursor <cursoragent@cursor.com>
@heavygee
heavygee force-pushed the feat/session-header-machine-meta branch from ba35a52 to 4f3de28 Compare July 30, 2026 02:32
@heavygee

Copy link
Copy Markdown
Collaborator Author

Re-thinned onto upstream/main (post-remat)

Soup remat green with prior tip ba35a52c0. Restored reviewable ancestry:

  • tip: 4f3de28e1982cea5d01a3a798a0ae1742a90bcbe
  • base: upstream/main (36eedc870)
  • commits: 1a088978d (feat) + 4f3de28e1 (age keep-alive/tick)
  • diff: 6 files (SessionHeader + useSSE + locales) — no SessionList / sessionRowHelpers (soup already owns helpers; keeping them out of this tip avoids remat add/add on the next rebuild)

Cold review of full PR diff: no Blocker/Major. Prior bot freshness findings remain addressed.

Hard-reload dogfood if Workbox sticks on pre-remat assets (index-Cpc5HVzO.js is current).

@github-actions github-actions Bot 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.

Findings

  • [Major] Every keep-alive now rerenders the full session-detail tree - the hub emits a changed activeAt about every 10 seconds, and this change makes each heartbeat replace the cached Session object. Both session-page query subscribers rerender, followed by SessionChat and the unmemoized HappyThread, even though the header label changes only at minute boundaries. Evidence: web/src/hooks/useSSE.ts:63; related context hub/src/sync/sessionCache.ts:293, web/src/hooks/useSSE.ts:426, web/src/router.tsx:704, web/src/components/SessionChat.tsx:447.
    Suggested fix:
    if (
        key === 'activeAt'
        && typeof value === 'number'
        && Math.abs(value - session.activeAt) < 60_000
    ) {
        continue
    }

Questions

  • None.

Summary

  • Review mode: follow-up after new commits
  • One major performance regression remains: sub-minute heartbeats invalidate and rerender the entire active chat view.

Testing

  • Not run (automation; PR code was not executed).
  • GitHub test check was pending at review time.
  • Add coverage showing sub-minute activeAt movement is ignored while a minute-boundary update remains render-relevant.

HAPI Bot

Comment thread web/src/hooks/useSSE.ts Outdated
heavygee and others added 2 commits July 30, 2026 09:41
Relative age only changes at 60s boundaries; accepting every ~10s
heartbeat replaced the Session object and re-rendered the chat tree
for no visible header change.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@heavygee

Copy link
Copy Markdown
Collaborator Author

Babysit update (2cc03a2c7)

Threads (was 2 open) — cleared

  1. Outdated Blocker (soup dump / overseer-replay.yml) — already fixed by re-thin onto upstream/main; replied + resolved.
  2. Major (sub-minute activeAt thrash) — fixed in 72ba9940c: isRenderIrrelevantSessionPatch skips |delta| < 60_000, accepts ≥60s. Tests cover both. Replied + resolved.

Unresolved review threads: 0

Verification

  • cd web && bun run test -- src/hooks/useSSE.test.ts src/components/SessionHeader.test.tsx22 pass
  • GitHub testgreen on tip
  • Local cold review of full PR diff (upstream/main...HEAD): no Blocker/Major remaining

Codex pr-review — infra flake (not code)

Three attempts on this tip failed with stream disconnected before completion / reconnect 10/10 (runs 30531683029 ×2, 30532457136). No new HAPI Bot review posted for 72ba9940c / 2cc03a2c7, so hapi-pr-status still shows the stale Major from 4f3de28e.

That Major is already implemented. Needs a successful Codex pass (or @tiann merge with the failing advisory check) to clear the status chip.

Diff tip: 6 files, product-only (SessionHeader + useSSE + locales).

@github-actions github-actions Bot 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.

Findings

  • None.

Questions

  • None.

Summary

  • Review mode: follow-up after new commits
  • No reportable issues found in the latest full diff. The prior major keep-alive rerender finding is resolved at this head.
  • Residual testing gap: the SessionHeader component tests pass api={null}, so live machine-query/display-name refresh behavior is not exercised; label precedence, host fallback, relative-age ticking, and SSE threshold logic have direct coverage.

Testing

  • Not run (automation; PR content was not executed).
  • GitHub test check: passed.

HAPI Bot

heavygee added a commit to heavygee/hapi that referenced this pull request Jul 30, 2026


Co-authored-by: Cursor <cursoragent@cursor.com>
heavygee added a commit to heavygee/hapi that referenced this pull request Jul 30, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
heavygee added a commit to heavygee/hapi that referenced this pull request Jul 30, 2026
…oted

Co-authored-by: Cursor <cursoragent@cursor.com>
heavygee added a commit to heavygee/hapi that referenced this pull request Jul 30, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
@tiann
tiann merged commit f8934d8 into tiann:main Jul 30, 2026
2 of 3 checks passed
@heavygee
heavygee deleted the feat/session-header-machine-meta branch July 30, 2026 15:28
heavygee added a commit to heavygee/hapi that referenced this pull request Jul 30, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
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.

feat(web): show machine + last-active in session detail header

2 participants