Skip to content

fix(viewer): handle sessions missing ids#366

Open
honor2030 wants to merge 2 commits into
rohitg00:mainfrom
honor2030:fix/viewer-missing-session-id
Open

fix(viewer): handle sessions missing ids#366
honor2030 wants to merge 2 commits into
rohitg00:mainfrom
honor2030:fix/viewer-missing-session-id

Conversation

@honor2030
Copy link
Copy Markdown

@honor2030 honor2030 commented May 14, 2026

Summary

  • Add shared viewer helpers for missing/null session IDs so malformed session payloads render as Unknown session / missing id instead of throwing.
  • Disable session actions/options that require an ID when a session record has no usable ID, avoiding undefined action payloads.
  • Add regression coverage for dashboard, timeline, and sessions rendering when sessions are missing IDs.

Red / Green

  • RED: PATH=/opt/homebrew/bin:$PATH npm test -- test/viewer-session-id.test.ts --reporter=verbose failed before the implementation with TypeError.
  • GREEN: PATH=/opt/homebrew/bin:$PATH npm test -- test/viewer-session-id.test.ts test/viewer-security.test.ts --reporter=verbose — 2 files / 4 tests passed.
  • GREEN: PATH=/opt/homebrew/bin:$PATH npm run build — passed.
  • GREEN: PATH=/opt/homebrew/bin:$PATH npm test -- --reporter=dot — 84 files / 905 tests passed.

Closes #340
Closes #347

Summary by CodeRabbit

  • New Features

    • Introduced normalized session identification and display helpers with graceful fallbacks (shows "Unknown session" / "missing id" when needed).
    • Updated Dashboard, Timeline, Activity, Sessions list, Session detail, and Replay selector to use normalized session labels/IDs, disable actions for sessions lacking IDs, and select the first valid session by default.
  • Tests

    • Added tests ensuring views render and handle sessions with missing IDs without throwing.

Review Change Stack

@vercel
Copy link
Copy Markdown

vercel Bot commented May 14, 2026

@honor2030 is attempting to deploy a commit to the rohitg00's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 357ddcc6-a006-4fef-8202-1fe0075a062e

📥 Commits

Reviewing files that changed from the base of the PR and between b3d4c3a and 0eb640a.

📒 Files selected for processing (2)
  • src/viewer/index.html
  • test/viewer-session-id.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/viewer-session-id.test.ts
  • src/viewer/index.html

📝 Walkthrough

Walkthrough

This PR adds helper functions to derive normalized session ids and labels when raw session.id may be missing, then updates all session-facing UI surfaces (Dashboard, Timeline, Activity, Sessions list, Session detail, and Replay selector) to use those derived values; includes Vitest sandbox tests for missing-id cases.

Changes

Session ID Resilience

Layer / File(s) Summary
Session ID derivation helpers
src/viewer/index.html
New helper functions (sessionId, shortSessionId, sessionDisplayName, sessionLabel) normalize session identifiers and display names, explicitly handling missing/undefined id fields.
Dashboard, Timeline, and Replay selectors
src/viewer/index.html
Dashboard Recent Sessions now uses sessionDisplayName(); Timeline initial selection and dropdown options use derived sessionId()/sessionLabel() and disable missing-id options; Replay dropdown uses derived ids/labels and disables missing-id options.
Activity loading and Sessions list rendering
src/viewer/index.html
Activity requests filter recent sessions by derived sessionId() and use it for observations; Sessions list rows use derived sessionId() for selection/data attributes, sessionDisplayName() for display, and shortSessionId() with a missing-id fallback in metadata.
Session detail lookup and actions
src/viewer/index.html
Session detail lookup matches by derived sessionId(), clears panel early when id is missing, fetches observations by derived id, shows derived id in metadata with a "missing id" fallback, and conditionally renders/disables End Session and Summarize controls based on derived id and activity.
Test suite for session ID resilience
test/viewer-session-id.test.ts
Adds a VM sandbox harness and Vitest tests that assert Dashboard, Timeline toolbar, and Sessions views do not throw when sessions lack ids and that rendered HTML contains "Unknown session".

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 When IDs go missing, no slice shall we try,
Helpers hop in where the raw fields are dry,
Dashboard to replay, the labels stay wise,
Unknown session shows, no more surprise,
A cheerful rabbit guards the viewer’s sky.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding handling for sessions with missing IDs, which directly addresses the core issue in the changeset.
Linked Issues check ✅ Passed The PR implements all requirements from #340 and #347: adds session ID helper utilities to prevent crashes when id is undefined, disables actions requiring IDs, and provides regression test coverage for dashboard/timeline/sessions rendering with missing IDs.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the session ID handling issues described in #340 and #347; no unrelated modifications are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
test/viewer-session-id.test.ts (1)

97-100: 💤 Low value

The auto-start regex pattern is fragile and tightly coupled to script output format.

This pattern will break if function names, order, whitespace, or additional auto-start calls change in the viewer script. Consider extracting the expected pattern as a named constant with a comment explaining the dependency, or use a more flexible approach like multiple small replacements for each function call.

♻️ More maintainable approach
-  const scriptWithoutAutoStart = scriptMatch[1].replace(
-    /\n\s*loadTab\('dashboard'\);\n\s*connectWs\(\);\n\s*startDashboardAutoRefresh\(\);\s*$/,
-    "\n",
-  );
+  // Strip viewer auto-start calls that would interfere with test control
+  let scriptWithoutAutoStart = scriptMatch[1];
+  scriptWithoutAutoStart = scriptWithoutAutoStart.replace(/\bloadTab\s*\([^)]*\)\s*;?\s*/g, "");
+  scriptWithoutAutoStart = scriptWithoutAutoStart.replace(/\bconnectWs\s*\([^)]*\)\s*;?\s*/g, "");
+  scriptWithoutAutoStart = scriptWithoutAutoStart.replace(/\bstartDashboardAutoRefresh\s*\([^)]*\)\s*;?\s*/g, "");

This approach removes each function call independently, making it resilient to order changes and whitespace variations.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/viewer-session-id.test.ts` around lines 97 - 100, The current fragile
single-regex removal in scriptWithoutAutoStart tightly couples to exact
order/whitespace of loadTab('dashboard'); connectWs();
startDashboardAutoRefresh(); — replace it with a more resilient approach:
extract the expectation into a named constant (e.g., AUTO_START_CALLS_PATTERN)
and/or perform separate, small regex replacements that each target
loadTab\('dashboard'\)\s*;, connectWs\(\)\s*; and
startDashboardAutoRefresh\(\)\s*; independently (using flexible whitespace
flags) so order changes or extra whitespace won't break the test; update the
code that constructs scriptWithoutAutoStart to use these constants/replacements
and add a short comment explaining why this is necessary.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/viewer/index.html`:
- Around line 2586-2590: The selection mismatch comes from normalizing IDs with
sessionId(s) when rendering (used for data-session-id) but still comparing raw
x.id === state.sessions.selectedId when opening details; fix by using the same
normalization function for the detail lookup (i.e., compare sessionId(x) ===
state.sessions.selectedId) or otherwise convert both sides to the same canonical
string form before comparing so numeric/typed IDs match; update any logic that
sets or compares state.sessions.selectedId to consistently use sessionId(...)
(references: sessionId, state.sessions.selectedId, the detail lookup that
compares x.id, and the session rendering that uses data-session-id).
- Around line 2224-2227: The default timeline selection currently assigns
state.timeline.sessionId = sorted[0].id which uses the raw upstream id and can
be invalid; change the initialization to use the normalized sessionId helper (or
pick the first sorted entry whose sessionId(s) returns a non-empty value) and
assign that normalized id (or '' fallback) to state.timeline.sessionId so the
initial selected option matches the normalized/disabled logic used when
rendering options (see sessionId, sorted, sessionLabel, and
state.timeline.sessionId).

In `@test/viewer-session-id.test.ts`:
- Around line 41-57: The mock document's querySelectorAll currently returns []
which prevents the viewer script from attaching event listeners; update the mock
in test/viewer-session-id.test.ts so document.querySelectorAll(selector) returns
an array of appropriate mock elements for selectors used by the viewer (at least
'.tab-bar button', '.view', and 'input[type="checkbox"]'). Each returned mock
element should implement addEventListener, getAttribute/setAttribute, classList
toggle/contains (or className), and for checkbox inputs a checked property;
reuse the existing createElement/getElement behaviors to construct these mocks
so the forEach loops in the viewer script execute and event handlers can be
attached.

---

Nitpick comments:
In `@test/viewer-session-id.test.ts`:
- Around line 97-100: The current fragile single-regex removal in
scriptWithoutAutoStart tightly couples to exact order/whitespace of
loadTab('dashboard'); connectWs(); startDashboardAutoRefresh(); — replace it
with a more resilient approach: extract the expectation into a named constant
(e.g., AUTO_START_CALLS_PATTERN) and/or perform separate, small regex
replacements that each target loadTab\('dashboard'\)\s*;, connectWs\(\)\s*; and
startDashboardAutoRefresh\(\)\s*; independently (using flexible whitespace
flags) so order changes or extra whitespace won't break the test; update the
code that constructs scriptWithoutAutoStart to use these constants/replacements
and add a short comment explaining why this is necessary.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 15c16191-1c09-4467-a7a9-2bf8ead94fd8

📥 Commits

Reviewing files that changed from the base of the PR and between 8c3418c and b3d4c3a.

📒 Files selected for processing (2)
  • src/viewer/index.html
  • test/viewer-session-id.test.ts

Comment thread src/viewer/index.html
Comment thread src/viewer/index.html
Comment thread test/viewer-session-id.test.ts
@honor2030 honor2030 force-pushed the fix/viewer-missing-session-id branch from b3d4c3a to 0eb640a Compare May 15, 2026 06:46
@honor2030
Copy link
Copy Markdown
Author

Addressed the review feedback in the latest push (0eb640a):

  • Timeline default selection now picks the first session with a normalized, non-empty sessionId(...).
  • Session detail lookup now compares normalized IDs and uses the normalized ID for the observations request.
  • The viewer session-id regression test mock now returns tab/view/checkbox elements from querySelectorAll(...) and verifies tab switching still attaches/uses the mock DOM elements.

Verification:

  • git diff --check
  • npm test -- test/viewer-session-id.test.ts --reporter=verbose — 2/2 tests passed
  • npm run build — passed

Current checks after push: CodeRabbit is passing/skipped. Vercel is still blocked by repository deployment authorization, unrelated to this diff.

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

Labels

None yet

Projects

None yet

1 participant