fix: stabilize session navigation ordering#367
Conversation
📝 WalkthroughWalkthroughSession timestamp calculation logic is extracted from inline implementation in ChangesSession Timestamp Extraction
Optional turnDiffs Parameter
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request refactors the session time calculation for the sidebar by introducing a new helper function, pawworkSidebarSessionTime, which prioritizes the timestamp of the latest user message over the session's creation time. This change is supported by new unit tests and integrated into the layout logic. Additionally, the PR updates deriveReviewArtifactFiles to safely handle undefined turnDiffs during session loading. The review feedback suggests improving the robustness of timestamp validation by using Number.isFinite instead of a simple type check to avoid potential issues with NaN or Infinity values.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/app/src/pages/layout/pawwork-session-source.test.ts (1)
152-185: ⚡ Quick winAdd a regression case for
NaNuser/session timestamps.These tests are solid; one more case for non-finite numbers would prevent ordering regressions from malformed numeric timestamps.
Suggested test addition
describe("pawworkSidebarSessionTime", () => { + test("falls back when user/session created timestamps are NaN", () => { + expect( + pawworkSidebarSessionTime( + { time: { created: Number.NaN } }, + [{ id: "msg_nan", role: "user", time: { created: Number.NaN } }], + ), + ).toBe(0) + })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/app/src/pages/layout/pawwork-session-source.test.ts` around lines 152 - 185, Add a regression test to pawwork-session-source.test that ensures pawworkSidebarSessionTime correctly handles non-finite numeric timestamps (e.g., NaN) by treating them as missing and falling back to the next valid source; specifically add a case where a session or user message has time.created: NaN (or Number.NaN) and assert the function returns the valid alternate timestamp (or 0 if none), referencing the pawworkSidebarSessionTime function and existing tests "ignores user messages without a valid created time" / "uses the session creation time..." as templates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/app/src/pages/layout/pawwork-session-source.ts`:
- Around line 64-72: In pawworkSidebarSessionTime, the current check uses typeof
created === "number" which allows NaN/Infinity; update the validation to use
Number.isFinite(created) when returning a message-created timestamp and also use
Number.isFinite(session.time?.created) for the session fallback so sorting
(e.g., b.created - a.created) never receives non-finite values; reference the
created local variable and session.time?.created in your changes to locate the
logic.
---
Nitpick comments:
In `@packages/app/src/pages/layout/pawwork-session-source.test.ts`:
- Around line 152-185: Add a regression test to pawwork-session-source.test that
ensures pawworkSidebarSessionTime correctly handles non-finite numeric
timestamps (e.g., NaN) by treating them as missing and falling back to the next
valid source; specifically add a case where a session or user message has
time.created: NaN (or Number.NaN) and assert the function returns the valid
alternate timestamp (or 0 if none), referencing the pawworkSidebarSessionTime
function and existing tests "ignores user messages without a valid created time"
/ "uses the session creation time..." as templates.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: b44cb2cd-c8b8-44dc-9bab-a2e60a859351
📒 Files selected for processing (5)
packages/app/src/pages/layout.tsxpackages/app/src/pages/layout/pawwork-session-source.test.tspackages/app/src/pages/layout/pawwork-session-source.tspackages/app/src/pages/session/use-session-review-state.test.tspackages/app/src/pages/session/use-session-review-state.ts
Root cause: - PawWork's sidebar row builder in `packages/app/src/pages/layout.tsx` still populated `created` from `session.time.created`. - `PawworkSidebar` used that same field for the relative time text, and `buildPawworkSessionSections` used it for time sorting. - PR #367 had already established the correct loaded-row contract in `pawworkSidebarSessionTime`: latest valid loaded user message time, otherwise session creation time. The PawWork session-window path simply had not been wired to that helper. Behavior change: - Sidebar rows that already have loaded message cache now use the latest valid user message `time.created` for both displayed relative time and row-level time sorting. - Rows with missing cache, assistant-only messages, invalid user timestamps, or no user messages still fall back to `session.time.created`. - The cache read uses `globalSync.child(directory, { bootstrap: false, pin: false })`, so it does not bootstrap or owner-pin child stores just to calculate sidebar timestamps. Scope boundary: - No backend API, database schema, persistence, desktop shell, packaging, permission, model harness, or visual layout changes. - The initial global session window is still selected by the existing created-time API window. The broader product/API change to fetch the first sidebar window by latest user message time is tracked separately in #473. - A lower-priority cache API follow-up for reading an existing child store without creating one is tracked in #475. - Broader layout.tsx controller extraction is tracked in #474 and intentionally kept out of this bug fix. Tests and verification: - Added `buildPawworkSidebarSessionRows` coverage for loaded user-message timestamps. - Added missing-message-cache fallback coverage for the row builder. - Existing helper tests continue to cover assistant-only caches and invalid timestamp fallback. - TDD red check: the focused app unit test failed before implementation because `buildPawworkSidebarSessionRows` did not exist. - Focused app tests: `bun --cwd packages/app test --preload ./happydom.ts ./src/pages/layout/pawwork-session-source.test.ts` -> 916 pass, 0 fail. - App typecheck: `bun --cwd packages/app typecheck` passed. - Workspace typecheck: `bun turbo typecheck` passed before review follow-up. - Diff check: `git diff --check` passed. - Desktop startup check: `bun run dev:desktop` built main/preload/renderer and started Electron, but an existing local PawWork dev instance using the shared dev profile blocked a full interactive sidebar click-through in this worktree. - PR checks were green before merge, including typecheck, unit-app, unit-desktop, unit-opencode, e2e-artifacts, CodeQL, and smoke-macos-arm64. Closes #470
Summary
Why
A newer build could throw
Cannot read properties of undefined (reading 'flatMap')when opening a session beforeturnDiffsarrived. The sidebar also usedsession.time.updatedas a fallback, which let assistant/background updates promote older conversations and made timestamps/order feel wrong. The helper keeps the ordering tied to user activity when available and avoids using update time as a fallback. Review also identified thatNaNorInfinitytimestamps could still reach the numeric sort key, so the helper now accepts only finite numbers.Related Issue
No linked issue. This came from local regression triage against real session logs.
Human Review Status
Pending. A human should make the final merge decision after reviewing the final diff and verification evidence.
Review Focus
Please focus on the fallback ordering contract in
pawworkSidebarSessionTime: use the latest valid loaded user message time, otherwise fall back tosession.time.created, neversession.time.updated, and never return non-finite numbers. Also check that treating missingturnDiffsas an empty list does not hide legitimate review files once data arrives.Risk Notes
Low. This changes sidebar ordering behavior and a loading-state fallback only. No persistence, dependency, migration, permissions, updater, or generated-file changes are included.
How To Verify
Screenshots or Recordings
Not captured. This is a behavior and loading-state fix with no visual layout or copy change.
Checklist
dev, and my PR title and commit messages use Conventional Commits in English