Skip to content

perf: remove upload, playback, and page waterfalls - #67

Merged
bmdavis419 merged 3 commits into
mainfrom
agent/deep-performance-pass
Jul 24, 2026
Merged

perf: remove upload, playback, and page waterfalls#67
bmdavis419 merged 3 commits into
mainfrom
agent/deep-performance-pass

Conversation

@bmdavis419

@bmdavis419 bmdavis419 commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • start authorized Mux playback directly from the subscribed playback ID, lazy-load Original S3 playback, share the HLS runtime import, and use the server action only as fatal-error recovery
  • make Original URL expiry and source recovery race-safe across video/version navigation, including bounded refresh while Mux is still encoding
  • queue two files at a time while retaining four-way multipart concurrency, coalesce progress updates, show queued files immediately, and isolate upload progress from dashboard route rendering
  • eliminate redundant upload-action video reads while preserving member authorization and existing upload/resume safeguards
  • reduce dashboard read/subscription work: one comments subscription with linear threading, one paginated video-page execution, viewport-scoped presence capped at 40 videos, responsive thumbnail loading, and no speculative HLS work without a playback ID
  • move Clerk, Convex, and theme providers to the routes that need them; self-host Geist with font-display: swap; remove global Mux hints, remote font waterfalls, Video.js, and unused tooltip/dependency code
  • preload the homepage hero, remove redundant scroll work, and keep downloads click-time so signed URL actions are not spent speculatively

Validation

  • bun run format
  • bun run check
    • 73 unit tests
    • 39 Convex tests
    • app + Convex typechecks
    • ESLint + Prettier
  • git diff --check
  • read-only first-pass claude -p performance audit plus three clean independent final review passes

Per repository guidance, I did not run a dev server or production build.

Follow-up

Materialized comment-count and storage-accounting counters still deserve dedicated migrations/backfills. They are intentionally not mixed into this PR because storage accounting is billing-sensitive and both changes need deployment reconciliation, not compatibility guesses.

Note

Remove upload, playback, and page waterfalls by scoping providers per route and adding recovery-aware playback

  • Moves Clerk, Convex, and Theme providers from the root route into individual route components so each page only loads what it needs, eliminating cross-route initialization waterfalls.
  • Adds Mux playback recovery across the dashboard, watch, and share pages: the player tracks a sourceRevision, reports fatal HLS errors via onPlaybackIssue, and triggers structured retry/recovery flows with user-visible status banners.
  • Adds prefetchHlsRuntime and selectMuxPlaybackSource abstractions; Mux HLS URLs now cap at max_resolution=720p (previously min_resolution=720p).
  • Moves threaded comment construction client-side using a new threadComments helper, removing a server-side comments.getThreaded prewarm query.
  • Limits project presence queries to viewport-adjacent videos (up to 40) via a new useProjectPresenceViewport hook and a bounded videoPresence.listProjectOnlineCounts query.
  • Concurrent file uploads are now processed via a new createAsyncTaskQueue with concurrency 2; progress events are coalesced per animation frame via createFrameCoalescedPublisher.
  • Removes video.js, @radix-ui/react-tooltip, @stripe/stripe-js, and @tanstack/react-router-devtools from the dependency tree; switches fonts to local @fontsource-variable packages.
  • Risk: Behavioral change — Mux playback URLs now enforce a 720p maximum rather than minimum resolution, which will reduce quality for viewers previously served higher renditions.

Macroscope summarized 8d641f9.

Summary by CodeRabbit

  • New Features
    • Added automatic video playback recovery for shared/watch/dashboard with “Repairing playback…” and optional retry.
    • Improved original-quality playback loading and retry flows.
    • Video uploads now queue with limited concurrent processing and “Queued for upload...” feedback.
    • Enhanced project presence selection, thumbnail normalization, and watcher indicator visibility.
  • Bug Fixes
    • Improved initial scroll state and safer upload cancellation/failure handling.
    • Presence counts are now strictly scoped to requested video IDs (with bounds).
  • Style
    • Updated typography to variable Geist fonts and simplified video/tooltip UI.

@vercel

vercel Bot commented Jul 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lawn Ready Ready Preview, Comment Jul 24, 2026 1:18am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The pull request updates playback recovery, concurrent uploads, dashboard presence and comment data handling, route-level Clerk/Convex providers, resource hints, variable fonts, navigation behavior, shared UI, and related tests and dependencies.

Changes

Playback recovery

Layer / File(s) Summary
Mux playback contracts and player runtime
src/lib/muxPlayback.ts, src/lib/dashboardPlaybackSource.ts, src/components/video-player/VideoPlayer.tsx, src/lib/*Playback.test.ts
Adds structured Mux recovery sources, cached HLS runtime loading, source revisions, fatal HLS error reporting, and selector tests.
Dashboard playback
app/routes/dashboard/-video.tsx
Separates Mux recovery from Original playback preparation with structured retries, errors, quality handling, and status UI.
Watch and share playback
app/routes/-watch.tsx, app/routes/-share.tsx
Adds request-matched playback recovery, stale-response protection, repair banners, and retry controls.

Upload pipeline

Layer / File(s) Summary
Queued upload utilities
src/lib/videoUpload.ts, src/lib/videoUpload.test.ts
Adds bounded async task queues, frame-coalesced progress updates, and cancellation checks.
Upload manager and dashboard boundary
app/routes/dashboard/-useVideoUploadManager.ts, app/routes/dashboard/-layout.tsx, src/lib/dashboardUploadContext.tsx
Moves uploads to concurrent queue processing and consolidates drag, project selection, progress, cancellation, and retry behavior.
Upload actions and status UI
convex/videoActions.ts, src/components/upload/UploadProgress.tsx
Reuses authorized video lookups across upload actions and displays pending uploads as queued.

Dashboard data and presence

Layer / File(s) Summary
Comments and project loading
app/routes/dashboard/-video.data.ts, convex/comments.ts, app/routes/dashboard/-project.data.ts, src/components/comments/CommentList.tsx
Threads flat comments on the client, removes the threaded essential query, and removes project video-list prewarming.
Viewport presence and thumbnails
app/routes/dashboard/-project.tsx, app/routes/dashboard/-routeDataContracts.test.ts
Selects nearby video cards for presence queries, normalizes public Mux thumbnails, and adjusts image loading and watcher-count rendering.
Presence query contract
convex/videoPresence.ts, convex/videoPresence.vitest.ts
Bounds requested video IDs, validates project ownership, and tests counts, heartbeats, limits, and authorization.

Application infrastructure

Layer / File(s) Summary
Providers and route resources
src/lib/clerk.tsx, src/lib/convex.tsx, src/lib/seo.ts, app/routes/{dashboard,invite,share,watch,sign-in,sign-up}*
Adds Clerk client and Clerk-Convex wrappers and appends Convex/Mux connection hints to route heads.
Root layout and assets
app/routes/__root.tsx, app/routes/index.tsx, app/app.css, package.json
Simplifies root provider composition, adds variable Geist fonts and resource hints, updates font utilities, and removes obsolete packages and Video.js CSS.
Navigation and shared UI
app/routes/-home.tsx, app/routes/mono.tsx, src/components/MarketingNav.tsx, src/components/ui/tooltip.tsx
Simplifies login navigation, initializes scroll state immediately, removes navigation scroll tracking, and removes tooltip implementation exports.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • pingdotgg/lawn#33: Overlaps with the queued, resumable, and concurrent upload pipeline changes.
  • pingdotgg/lawn#49: Overlaps with playback issue reporting across the player, watch, share, and dashboard flows.
  • pingdotgg/lawn#66: Overlaps with dashboard Mux and Original playback source selection and recovery.
🚥 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
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title concisely captures the main performance focus across uploads, playback, and page loading.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/deep-performance-pass

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

Comment thread app/routes/dashboard/-layout.tsx
Comment thread src/lib/muxPlayback.ts

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/routes/dashboard/-useVideoUploadManager.ts (1)

391-405: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep “Dismiss” non-destructive for retryable processing failures.

When canRetryProcessing is true, the upload has completed and its object was preserved for retry. This handler currently calls abortVideoUpload, deleting that object even though the error-state button is labeled “Dismiss”. Remove only the local item in this case, or expose a separately labeled destructive action.

Proposed fix
 const cancelUpload = useCallback(
   (uploadId: string) => {
     const upload = uploadsRef.current.find((item) => item.id === uploadId);
+    if (upload?.canRetryProcessing) {
+      updateUploads((prev) => prev.filter((item) => item.id !== uploadId));
+      return;
+    }
+
     if (upload?.abortController) {
       upload.abortController.abort();
     }
🤖 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 `@app/routes/dashboard/-useVideoUploadManager.ts` around lines 391 - 405,
Update cancelUpload so that when an upload has canRetryProcessing enabled, it
only removes the local upload entry and does not call abortVideoUpload; retain
the existing destructive abort behavior for uploads that are not retryable
processing failures.
🧹 Nitpick comments (1)
app/routes/dashboard/-video.tsx (1)

1301-1363: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Apply the playback recovery design consistently.

The new recovery surfaces bypass the required palette and primary-UI treatment.

  • app/routes/dashboard/-video.tsx#L1301-L1363: replace dark brown banners with cream, near-black text, and 2px borders.
  • app/routes/-watch.tsx#L397-L411: apply the same compliant status-banner treatment.
  • app/routes/-share.tsx#L439-L483: update the banner and remove the fallback’s rounded corners and shadow.

As per coding guidelines, primary UI uses #f0f0e8, #1a1a1a, strong 2px borders, square edges, and no shadows.

🤖 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 `@app/routes/dashboard/-video.tsx` around lines 1301 - 1363, Apply the
compliant primary-UI treatment to the recovery banners in
app/routes/dashboard/-video.tsx lines 1301-1363, app/routes/-watch.tsx lines
397-411, and app/routes/-share.tsx lines 439-483: use `#f0f0e8` backgrounds,
`#1a1a1a` text, strong 2px borders, square edges, and no shadows. In the share
fallback, specifically remove rounded corners and shadow while preserving its
existing recovery behavior.

Source: Coding guidelines

🤖 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 `@app/app.css`:
- Line 125: Update the --font-serif custom property in app.css to use lowercase
georgia, and make the same casing change for its repeated occurrence. Preserve
the existing serif fallback.

In `@app/routes/-share.tsx`:
- Around line 159-167: The automatic grant flow in the useEffect must recover
when acquireGrant resolves unsuccessfully instead of permanently relying on
hasAttemptedAutoGrant. Track the access error and expose a retry action or
bounded backoff that reattempts acquireGrant, keeping the user in the grant flow
rather than showing “Video not available” after transient or rate-limit
failures.

In `@app/routes/dashboard/-layout.tsx`:
- Around line 293-305: Update the fixed upload list container rendered when
uploads.length > 0 to constrain its height to the viewport and enable vertical
scrolling, while preserving its existing positioning, spacing, and responsive
width classes. Ensure all DashboardUploadProgressItem controls remain reachable
when many uploads are present.

In `@app/routes/dashboard/-project.tsx`:
- Around line 148-180: Move the assignments to scopeKeyRef.current and
recomputeSelectionRef.current out of the render body and into an effect that
runs after commit. Keep recomputeSelection using the refs for the latest
committed scope and callback, ensuring discarded concurrent renders cannot
affect pending animation-frame work.

---

Outside diff comments:
In `@app/routes/dashboard/-useVideoUploadManager.ts`:
- Around line 391-405: Update cancelUpload so that when an upload has
canRetryProcessing enabled, it only removes the local upload entry and does not
call abortVideoUpload; retain the existing destructive abort behavior for
uploads that are not retryable processing failures.

---

Nitpick comments:
In `@app/routes/dashboard/-video.tsx`:
- Around line 1301-1363: Apply the compliant primary-UI treatment to the
recovery banners in app/routes/dashboard/-video.tsx lines 1301-1363,
app/routes/-watch.tsx lines 397-411, and app/routes/-share.tsx lines 439-483:
use `#f0f0e8` backgrounds, `#1a1a1a` text, strong 2px borders, square edges, and no
shadows. In the share fallback, specifically remove rounded corners and shadow
while preserving its existing recovery behavior.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a24c2167-3bf4-4e91-a6e0-fc2062e404f6

📥 Commits

Reviewing files that changed from the base of the PR and between fc6b979 and 2bffb78.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (44)
  • app/app.css
  • app/routes/-home.tsx
  • app/routes/-share.tsx
  • app/routes/-watch.tsx
  • app/routes/__root.tsx
  • app/routes/dashboard/$teamSlug.$projectId.tsx
  • app/routes/dashboard/-layout.tsx
  • app/routes/dashboard/-project.data.ts
  • app/routes/dashboard/-project.tsx
  • app/routes/dashboard/-routeDataContracts.test.ts
  • app/routes/dashboard/-useVideoUploadManager.ts
  • app/routes/dashboard/-video.data.ts
  • app/routes/dashboard/-video.tsx
  • app/routes/dashboard/route.tsx
  • app/routes/index.tsx
  • app/routes/invite.$token.tsx
  • app/routes/mono.tsx
  • app/routes/share.$token.tsx
  • app/routes/sign-in.$.tsx
  • app/routes/sign-in.tsx
  • app/routes/sign-up.$.tsx
  • app/routes/sign-up.tsx
  • app/routes/watch.$publicId.tsx
  • convex/comments.ts
  • convex/videoActions.ts
  • convex/videoPresence.ts
  • convex/videoPresence.vitest.ts
  • package.json
  • src/components/MarketingNav.tsx
  • src/components/comments/CommentList.tsx
  • src/components/ui/tooltip.tsx
  • src/components/upload/UploadProgress.tsx
  • src/components/video-player/VideoPlayer.tsx
  • src/lib/clerk.tsx
  • src/lib/convex.tsx
  • src/lib/dashboardPlaybackSource.test.ts
  • src/lib/dashboardPlaybackSource.ts
  • src/lib/dashboardUploadContext.tsx
  • src/lib/muxPlayback.test.ts
  • src/lib/muxPlayback.ts
  • src/lib/muxPlaybackServerContract.test.ts
  • src/lib/seo.ts
  • src/lib/videoUpload.test.ts
  • src/lib/videoUpload.ts
💤 Files with no reviewable changes (2)
  • src/components/ui/tooltip.tsx
  • src/lib/dashboardUploadContext.tsx

Comment thread app/app.css
--font-serif: "Instrument Serif", Georgia, serif;
--font-sans: "Geist Variable", system-ui, -apple-system, sans-serif;
--font-mono: "Geist Mono Variable", ui-monospace, monospace;
--font-serif: Georgia, serif;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use lowercase georgia to satisfy Stylelint.

Line 125 fails value-keyword-case; line 299 repeats the same value.

Proposed fix
-  --font-serif: Georgia, serif;
+  --font-serif: georgia, serif;
...
-  font-family: Georgia, serif;
+  font-family: georgia, serif;

Also applies to: 299-299

🧰 Tools
🪛 Stylelint (17.14.0)

[error] 125-125: Expected "Georgia" to be "georgia" (value-keyword-case)

(value-keyword-case)

🤖 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 `@app/app.css` at line 125, Update the --font-serif custom property in app.css
to use lowercase georgia, and make the same casing change for its repeated
occurrence. Preserve the existing serif fallback.

Source: Linters/SAST tools

Comment thread app/routes/-share.tsx
Comment thread app/routes/dashboard/-layout.tsx
Comment thread app/routes/dashboard/-project.tsx Outdated
listProjectOnlineCounts threw FORBIDDEN when any subscribed video was
deleted or moved out of the project, which Convex useQuery rethrows in
render — one teammate deleting a video crashed every open dashboard for
that project to the root error page. Skip those videos instead (the
client already tolerates missing count entries), and make videoIds
optional so clients deployed before the argument existed keep a live
subscription through the rollout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bmdavis419
bmdavis419 merged commit a0765c6 into main Jul 24, 2026
4 checks passed
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.

1 participant