Skip to content

Conversation

@yujonglee
Copy link
Contributor

No description provided.

@coderabbitai
Copy link

coderabbitai bot commented Oct 27, 2025

📝 Walkthrough

Walkthrough

Moves chat interactive and trigger elements into React portals with fixed positioning and higher z-index; adds tooltip/disabled styling for floating controls; refactors transcript viewer to segment-based rendering with auto-scroll and a new segmentation API and tests; simplifies seed transcript generation; adjusts API path prefixes in client/server; removes an unused banner in auth.

Changes

Cohort / File(s) Summary
Chat UI Portal Refactor
apps/desktop/src/components/chat/interactive.tsx, apps/desktop/src/components/chat/trigger.tsx
Render interactive container and trigger button via createPortal(..., document.body); change positioning from absolute to fixed, increase stacking context (z-10z-[100]), and add layout/transition utility classes to trigger.
Floating Button UI
apps/desktop/src/components/main/body/sessions/floating/generate.tsx, apps/desktop/src/components/main/body/sessions/floating/index.tsx, apps/desktop/src/components/main/body/sessions/floating/shared.tsx
Add conditional tooltip when language model is unconfigured; make Regen button disabled when no model; raise floating container z-index to z-50; add disabled-state styles to Button className.
Note Input Styling
apps/desktop/src/components/main/body/sessions/note-input/index.tsx
Container overflow behavior made conditional on active tab (transcriptoverflow-hidden, else overflow-auto) via cn-based class list.
Transcript Viewer — Rendering & Auto-scroll
apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/index.tsx
Replace per-channel rendering with segment-based rendering using useSegments; render segments via a Segment component; integrate useAutoScroll for automatic scrolling on updates.
Transcript Segmentation API & Tests
apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.ts, apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.test.ts
Add segmentation pipeline: useSegments, splitIntoSegments, groupIntoTurns, buildSegments, and Segment type; introduce scoring-based split logic and grouping into turns; expand/replace tests to validate pipeline functions and edge cases.
Auth UI Cleanup
apps/desktop/src/components/main/sidebar/profile/auth.tsx
Remove local isBannerDismissed state and inline TryProBanner rendering; replace with direct Sign in button; keep an unused TryProBanner function annotated with @ts-expect-error.
Seed Transcript Simplification
apps/desktop/src/devtool/seed/shared/transcript.ts
Replace complex multi-turn/channel sentence generation with deterministic generateSentence-based assembly; produce fixed two-channel transcripts with simplified timing progression.
API Path Changes (client)
crates/am/src/client.rs
Remove /v1 prefix from several client endpoints: /status, /init, /reset, /unload, /shutdown.
API Path Changes (server config)
plugins/local-stt/src/server/external.rs
Add /v1 prefix to constructed external STT server base URL (http://localhost:<port>/v1).
Web app scripts
apps/web/package.json
Prepend pnpm -F @hypr/web build to the typecheck script.

Sequence Diagram(s)

sequenceDiagram
    participant Viewer as TranscriptViewer (Component)
    participant Hook as useSegments (Hook)
    participant Splitter as splitIntoSegments (Logic)
    participant Grouper as groupIntoTurns (Logic)
    participant Builder as buildSegments (Logic)
    participant SegmentComp as Segment (Component)
    participant AutoScroll as useAutoScroll (Hook)

    Note over Viewer,AutoScroll: Segment-based transcript rendering (new)
    Viewer->>Hook: request segments(sessionId)
    Hook->>Splitter: split words into candidate groups
    Splitter-->>Hook: word groups
    Hook->>Grouper: group words by channel into turns
    Grouper-->>Hook: segments [{channel, words}, ...]
    Hook->>Builder: build final segments (merge finals + partials)
    Builder-->>Hook: Segment[]
    Hook-->>Viewer: return Segment[]
    Viewer->>SegmentComp: render each Segment
    Viewer->>AutoScroll: register container & deps
    AutoScroll-->>Viewer: scroll on updates
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay extra attention to:
    • segment.ts and segment.test.ts — new segmentation API, scoring/splitting heuristics, and exported types/functions.
    • seed/shared/transcript.ts — verify deterministic timing/channel semantics and any assumptions used elsewhere.
    • Portal changes in chat components — confirm event propagation, focus handling, and positioning across OS windows/containers.

Possibly related PRs

  • Got enhancing working in desktop2 #1596 — Modifies apps/desktop/src/components/main/body/sessions/floating/generate.tsx (Generate button/session scope); likely related to the Regen button tooltip and floating control changes.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning No pull request description was provided by the author. The description field is empty, meaning it does not describe any part of the changeset or provide context for the numerous modifications across multiple files and components. According to the pass criterion, the description should be "related in some way to the changeset," which an empty description cannot satisfy.
Docstring Coverage ⚠️ Warning Docstring coverage is 3.70% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "Transcript viewer final" directly relates to a significant portion of the changeset, specifically the major refactoring of the transcript viewer component with new segmentation API pipeline (segment.ts, segment.test.ts, viewer/index.tsx). However, the PR includes numerous additional changes beyond the transcript viewer, such as portal rendering updates in interactive and trigger components, z-index improvements for floating elements, API endpoint modifications in Rust code, package.json script updates, and more. The title captures an important part of the work but does not reflect the full scope of changes in the PR.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch transcript-viewer-final

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 580d1e2 and 0b619d3.

📒 Files selected for processing (2)
  • apps/desktop/src/devtool/seed/shared/transcript.ts (2 hunks)
  • apps/web/package.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/simple.mdc)

After a substantial amount of TypeScript changes, run pnpm -r typecheck

Files:

  • apps/desktop/src/devtool/seed/shared/transcript.ts
🧠 Learnings (1)
📚 Learning: 2025-10-26T00:28:22.016Z
Learnt from: CR
PR: fastrepl/hyprnote#0
File: .cursor/rules/simple.mdc:0-0
Timestamp: 2025-10-26T00:28:22.016Z
Learning: Applies to **/*.{ts,tsx} : After a substantial amount of TypeScript changes, run `pnpm -r typecheck`

Applied to files:

  • apps/web/package.json
🧬 Code graph analysis (1)
apps/desktop/src/devtool/seed/shared/transcript.ts (3)
packages/db/src/schema.ts (1)
  • words (127-138)
apps/desktop/src/store/tinybase/persisted.ts (1)
  • Word (124-124)
apps/desktop/src/utils/index.ts (1)
  • DEFAULT_USER_ID (6-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: ci (macos, macos-14)
🔇 Additional comments (4)
apps/web/package.json (1)

10-10: Verify the build step is necessary for typecheck.

Adding pnpm -F @hypr/web build to the typecheck script ensures the build artifacts are current before type checking. However, this has performance implications: the build will now run on every typecheck invocation during development.

Consider whether:

  1. The build actually generates type definitions or other artifacts that typecheck depends on
  2. The performance cost is acceptable for the dev workflow (especially in tight feedback loops)
  3. An incremental build caching strategy is in place to minimize overhead

If the build is necessary, consider documenting why in a code comment or ADR to help future maintainers understand the dependency. If the build is only needed before running tests or CI, consider moving this check to those contexts instead.

apps/desktop/src/devtool/seed/shared/transcript.ts (3)

6-23: LGTM! Helper functions are well-designed.

The utility functions are clear, concise, and correctly typed. The durationForWord calculation provides realistic speech timing variation based on word length.


25-73: LGTM! Sentence generation logic produces natural variation.

The generateSentence function creates realistic sentence structures with appropriate use of starters, bridges, and weighted length distributions. The 30/70 split between short and long sentences, combined with conditional starters and bridges, will generate natural-sounding transcripts.


75-145: All TypeScript types verified and consistent.

The function's word object structure matches the Word type exactly and is consistent with existing usage in builders.ts (lines 256-264). All faker method calls are valid, helper functions properly typed, and imports resolve correctly.

Though pnpm -r typecheck couldn't execute in the sandbox environment (expected limitation), manual cross-verification confirms no type issues exist in this code.


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

@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: 4

🧹 Nitpick comments (12)
apps/desktop/src/components/main/sidebar/profile/auth.tsx (1)

115-175: Consider removing unused code or deferring to a future PR.

The TryProBanner function is currently unused and marked with a broad @ts-expect-error annotation. Consider:

  • Removing it until actually needed, or
  • If keeping for near-term use, replace @ts-expect-error with a more specific @ts-expect-error [reason] or track implementation in an issue

Unused code with error suppression can hide type issues and creates maintenance overhead.

apps/desktop/src/devtool/seed/shared/transcript.ts (2)

25-74: Hoist static word lists to module scope to avoid per-call allocations.

Move starters/bridges out of generateSentence() and reuse them. Tiny perf win and cleaner.

Example:

// top-level
const STARTERS = ["yeah","so","honestly","right","okay","look","listen","alright"] as const;
const BRIDGES = ["you know","I mean","kind of","sort of","at the moment","for example","basically","on our side"] as const;

// inside generateSentence()
if (faker.datatype.boolean({ probability: 0.5 })) {
  appendPhrase(sentenceWords, faker.helpers.arrayElement(STARTERS));
}
...
appendPhrase(sentenceWords, faker.helpers.arrayElement(BRIDGES));

75-82: Optional: allow deterministic seeds for repeatable transcripts.

Add an optional seed param and call faker.seed(seed) at the start. Helpful for debugging/tests.

Example:

export const generateTranscript = (seed?: number) => {
  if (seed != null) faker.seed(seed);
  // ...
};
apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.test.ts (3)

7-28: buildSegments tests: solid coverage of merge+turns

Happy path looks good. Consider adding a case with >2 channel alternations (e.g., 0→1→0→1→0) to ensure turn boundaries remain stable with more interleaving.


153-254: groupIntoTurns: tie-breaking and zero-length words

Consider tests for:

  • Ties: two words with identical start_ms on different channels.
  • Zero-length or overlapping words to confirm the sort + grouping still produce intended turns.

56-151: Add three recommended test cases for mergeWordsByChannel function

The test file is missing three important edge case tests:

  1. Equal start_ms across channels — Verify deterministic ordering when words from different channels have identical start times. Current sorting happens per-channel only; this tests stability when merging across channels in groupIntoTurns.

  2. Boundary adjacency — Add test where one word's end_ms equals the next word's start_ms (e.g., word A ends at 300ms, word B starts at 300ms). This validates handling of continuous/adjacent timing.

  3. Multi-key partial words with channel mismatch — Expand the existing single-key test ("uses word.channel property...") to use multiple partial word keys where some keys don't match their contained words' channel values, confirming robust channel-over-key priority.

These tests ensure the function's sorting and channel assignment logic handles edge cases correctly before reaching downstream consumers like groupIntoTurns and buildSegments.

apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/index.tsx (1)

25-27: Use stable keys for segments

Index keys can mis-associate on insertion/reordering. Prefer a timestamp‑based key derived from first/last word.

-        (segment, i) => <Segment key={i} segment={segment} />,
+        (segment) => {
+          const first = segment.words[0];
+          const last = segment.words[segment.words.length - 1] ?? first;
+          const stableKey = `${segment.channel}:${first?.start_ms ?? 0}-${last?.end_ms ?? 0}`;
+          return <Segment key={stableKey} segment={segment} />;
+        },
apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.ts (5)

71-77: Transcript selection may be non-deterministic

Picking transcriptIds?.[0] could select an older transcript if index order changes. Consider selecting the most recent or explicit active transcript.

If “transcriptBySession” isn’t time‑sorted, adjust:

-  const transcriptId = transcriptIds?.[0];
+  const transcriptId = transcriptIds?.[transcriptIds.length - 1]; // most recent

Verify index ordering before applying.


115-117: Sentence boundary heuristic: include common non‑ASCII punctuation

Support “。” “! ” “?” “…” to improve multi‑language segmentation.

-function isSentenceEnding(text: string): boolean {
-  return /[.!?]$/.test(text.trim());
-}
+function isSentenceEnding(text: string): boolean {
+  // ASCII . ! ? and common CJK/ellipsis sentence terminators
+  return /[.!?…。!?]$/.test(text.trim());
+}

137-141: Defensive ordering for splitIntoSegments

The function assumes chronological input. Either assert or sort defensively to avoid pathological splits with unsorted input.

 export function splitIntoSegments(
   words: MaybePartialWord[],
   options: SplitOptions = {},
 ): MaybePartialWord[][] {
   const { maxWordsPerSegment = 30, minGapMs = 2000 } = options;
+  // Ensure chronological order
+  const sorted = words.length > 1 && words[0].start_ms > words[1].start_ms
+    ? [...words].sort((a, b) => a.start_ms - b.start_ms)
+    : words;
 
-  if (words.length === 0) {
+  if (sorted.length === 0) {
     return [];
   }
 
-  if (words.length === 1) {
-    return [words];
+  if (sorted.length === 1) {
+    return [sorted];
   }
 
-  const segments: MaybePartialWord[][] = [];
-  let currentSegment: MaybePartialWord[] = [words[0]];
+  const segments: MaybePartialWord[][] = [];
+  let currentSegment: MaybePartialWord[] = [sorted[0]];
 
-  for (let i = 1; i < words.length; i++) {
-    const prevWord = words[i - 1];
-    const currentWord = words[i];
+  for (let i = 1; i < sorted.length; i++) {
+    const prevWord = sorted[i - 1];
+    const currentWord = sorted[i];

250-255: Consider splitting long turns into readable segments

buildSegments currently returns channel turns only. For long monologues, UI may show very large blocks. Optionally split each turn by time/size.

 export function buildSegments(
   finalWords: Record<string, persisted.Word>,
   partialWords: Record<number, Array<{ text: string; start_ms: number; end_ms: number; channel: number }>>,
 ): Segment[] {
-  return groupIntoTurns(mergeWordsByChannel(finalWords, partialWords));
+  const turns = groupIntoTurns(mergeWordsByChannel(finalWords, partialWords));
+  // Split each turn into sub‑segments for readability
+  const segmented: Segment[] = [];
+  for (const turn of turns) {
+    const pieces = splitIntoSegments(turn.words);
+    for (const words of pieces) {
+      segmented.push({ channel: turn.channel, words });
+    }
+  }
+  return segmented;
 }

100-108: Memoized useSegments: good shape

Hook composes final/partial words cleanly. If you adopt turn splitting, the memoization boundaries remain valid.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0e49e37 and 580d1e2.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • apps/desktop/src/components/chat/interactive.tsx (3 hunks)
  • apps/desktop/src/components/chat/trigger.tsx (2 hunks)
  • apps/desktop/src/components/main/body/sessions/floating/generate.tsx (1 hunks)
  • apps/desktop/src/components/main/body/sessions/floating/index.tsx (1 hunks)
  • apps/desktop/src/components/main/body/sessions/floating/shared.tsx (1 hunks)
  • apps/desktop/src/components/main/body/sessions/note-input/index.tsx (1 hunks)
  • apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/index.tsx (1 hunks)
  • apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.test.ts (6 hunks)
  • apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.ts (1 hunks)
  • apps/desktop/src/components/main/sidebar/profile/auth.tsx (1 hunks)
  • apps/desktop/src/devtool/seed/shared/transcript.ts (2 hunks)
  • crates/am/src/client.rs (5 hunks)
  • plugins/local-stt/src/server/external.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/simple.mdc)

After a substantial amount of TypeScript changes, run pnpm -r typecheck

Files:

  • apps/desktop/src/components/main/body/sessions/floating/index.tsx
  • apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/index.tsx
  • apps/desktop/src/components/main/body/sessions/note-input/index.tsx
  • apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.test.ts
  • apps/desktop/src/devtool/seed/shared/transcript.ts
  • apps/desktop/src/components/chat/interactive.tsx
  • apps/desktop/src/components/main/body/sessions/floating/generate.tsx
  • apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.ts
  • apps/desktop/src/components/main/body/sessions/floating/shared.tsx
  • apps/desktop/src/components/main/sidebar/profile/auth.tsx
  • apps/desktop/src/components/chat/trigger.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/simple.mdc)

**/*.{tsx,jsx}: When many classNames have conditional logic in React components, use cn from @hypr/utils
When using cn, always pass an array of class segments
When using cn, split entries by logical grouping for readability
Use motion/react instead of framer-motion

Files:

  • apps/desktop/src/components/main/body/sessions/floating/index.tsx
  • apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/index.tsx
  • apps/desktop/src/components/main/body/sessions/note-input/index.tsx
  • apps/desktop/src/components/chat/interactive.tsx
  • apps/desktop/src/components/main/body/sessions/floating/generate.tsx
  • apps/desktop/src/components/main/body/sessions/floating/shared.tsx
  • apps/desktop/src/components/main/sidebar/profile/auth.tsx
  • apps/desktop/src/components/chat/trigger.tsx
🧬 Code graph analysis (6)
apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/index.tsx (1)
apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.ts (2)
  • useSegments (100-108)
  • Segment (207-210)
apps/desktop/src/components/main/body/sessions/note-input/index.tsx (1)
packages/utils/src/cn.ts (1)
  • cn (20-22)
apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.test.ts (2)
apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/test-utils.ts (1)
  • word (66-81)
apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.ts (4)
  • buildSegments (250-255)
  • mergeWordsByChannel (11-51)
  • groupIntoTurns (212-248)
  • splitIntoSegments (137-205)
apps/desktop/src/devtool/seed/shared/transcript.ts (3)
packages/db/src/schema.ts (1)
  • words (127-138)
apps/desktop/src/store/tinybase/persisted.ts (1)
  • Word (124-124)
apps/desktop/src/utils/index.ts (1)
  • DEFAULT_USER_ID (6-6)
apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.ts (1)
apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/test-utils.ts (1)
  • word (66-81)
apps/desktop/src/components/chat/trigger.tsx (1)
packages/utils/src/cn.ts (1)
  • cn (20-22)
🔇 Additional comments (13)
apps/desktop/src/components/main/body/sessions/note-input/index.tsx (1)

32-39: LGTM! Clean implementation following coding guidelines.

The dynamic className computation using cn correctly follows the coding guidelines: array syntax, logical grouping (layout → spacing → conditional overflow), and clear conditional logic for transcript vs. editor tabs.

apps/desktop/src/components/main/body/sessions/floating/shared.tsx (1)

31-31: LGTM! Disabled state styling improves UX.

The explicit disabled state styling ensures disabled buttons remain clearly visible with full opacity and a distinct neutral background, providing better visual feedback than the default disabled appearance.

apps/desktop/src/components/main/body/sessions/floating/index.tsx (1)

42-42: LGTM! Appropriate z-index for floating UI.

The z-50 value elevates the floating button container above standard content while remaining below portaled elements (which use z-[100]), establishing a clear stacking hierarchy.

apps/desktop/src/components/main/body/sessions/floating/generate.tsx (1)

113-118: LGTM! Excellent UX improvement.

The conditional tooltip provides clear feedback when the language model is not configured, helping users understand why regeneration is unavailable. This aligns well with the existing guard in onRegenerate.

apps/desktop/src/components/chat/interactive.tsx (1)

3-3: LGTM! Correct portal implementation.

The portal-based rendering is properly implemented:

  • Content renders to document.body via createPortal
  • Fixed positioning with z-[100] ensures proper stacking above other UI elements
  • All existing resizable functionality is preserved

This aligns with the broader UI layering strategy seen in other components.

Also applies to: 20-23, 67-69

apps/desktop/src/components/chat/trigger.tsx (1)

1-1: LGTM! Correct portal implementation and proper cn usage.

The portal-based rendering follows the same pattern as interactive.tsx, with fixed positioning and z-[100] for proper stacking. The cn usage correctly follows the coding guidelines by using an array with logical grouping (positioning, sizing, styling, transitions).

Also applies to: 6-26

apps/desktop/src/components/main/sidebar/profile/auth.tsx (1)

105-112: LGTM! Cleaner authentication flow.

The simplified unauthenticated state removes banner complexity while maintaining the sign-in functionality through handleStartSignIn.

crates/am/src/client.rs (1)

26-26: LGTM! API versioning centralized in base URL.

All five endpoint paths have been consistently updated to remove the /v1 prefix. This refactoring centralizes the API version in the base_url parameter (as seen in plugins/local-stt/src/server/external.rs line 50), making it easier to manage versioning across the client.

The final URLs remain unchanged:

  • Previously: base_url + /v1/status
  • Now: base_url/v1 + /status

Also applies to: 41-41, 54-54, 65-65, 76-76

plugins/local-stt/src/server/external.rs (1)

50-51: All Client instantiations are consistent with the /v1 prefix in base URLs.

The comprehensive search confirms there is only one instantiation of hypr_am::Client::new() in the entire codebase, and it's the one under review at plugins/local-stt/src/server/external.rs:51. This instantiation correctly includes /v1 in the base URL on line 50 via format!("http://localhost:{}/v1", port).

The centralization of API versioning from individual endpoint paths to the base URL is complete and consistently applied.

apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/index.tsx (2)

20-23: cn usage LGTM

Array form and logical grouping follow guidelines. No action.


2-3: Correct the verification command for this workspace's turbo configuration

The suggested verification commands don't work in this workspace. The workspace uses Turbo for task orchestration and doesn't have a workspace-wide vitest task. To properly verify TypeScript changes in apps/desktop, use:

turbo run typecheck
pnpm -F @hypr/desktop test

Alternatively, from the apps/desktop directory:

pnpm typecheck
pnpm test

Likely an incorrect or invalid review comment.

apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.ts (1)

11-51: mergeWordsByChannel implementation looks correct

Merges, preserves isFinal, and per‑channel sorting are straightforward and efficient. Nice.

apps/desktop/src/components/main/body/sessions/note-input/transcript/viewer/segment.test.ts (1)

256-415: Add three test cases for edge cases and preconditions in splitIntoSegments

All three suggested tests are missing and valid:

  • Gap equality test (gap === 2000ms): Existing tests use gaps of 2900ms and 2500ms; no boundary test for exact minGapMs. Verifies ">=" behavior.
  • Unsorted input test: The implementation assumes sorted input but doesn't sort internally. This precondition should be verified to document expected behavior or catch silent failures.
  • Long unpunctuated run with small gaps: No test covers the fallback split logic when no sentence boundaries exist and gaps stay below minGapMs. Ensures maxWordsPerSegment limits are respected cleanly.

@yujonglee yujonglee merged commit 1dfea32 into main Oct 27, 2025
5 checks passed
@yujonglee yujonglee deleted the transcript-viewer-final branch October 27, 2025 10:45
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.

2 participants