Skip to content

fix(web): host videos explain missing file access instead of offering a retry - #21088

Open
BGD-1DAY00 wants to merge 3 commits into
pingdotgg:mainfrom
BGD-1DAY00:fix/video-missing-file-access
Open

BGD-1DAY00 wants to merge 3 commits into
pingdotgg:mainfrom
BGD-1DAY00:fix/video-missing-file-access

Conversation

@BGD-1DAY00

@BGD-1DAY00 BGD-1DAY00 commented Oct 18, 2026 •

Copy link
Copy Markdown

Problem

On a connection without the filesystem:read grant, a host video in chat (![Demo](/abs/demo.mp4)) shows "Video unavailable · Demo" and a "Retry video" button. The client blocks the asset before it asks the server, so Retry can never succeed, and nothing says why. A host image in the same state already says "This connection cannot read host files. Pair again with a new link to view it." Fixes #21087.

Change

ChatMarkdownAssetImage works out the missing-file-access state once and passes the existing MISSING_FILE_ACCESS_MESSAGE to the video as well as the image. MediaVideoPlayer takes an optional unavailableDetail and shows it in its unavailable label, as ChatMarkdownMediaUnavailableLabel already does for images, and the label is marked data-thread-find-ignore like the image one. In that state the video gets no retry handler, so the button goes away. Pairing again grants the scope and the video loads as before.

Mobile had the same gap: ThreadMarkdownVideo now passes the same message, and the mobile tile shows "Video unavailable. ", the wording ThreadMarkdownImage uses. Its accessibility label carries the same text while it is unavailable, so screen readers announce the reason instead of "Play ". The mobile tile never had a retry.

Scope and approval

A small fix for an obvious bug, reported in #21087: the video branch dropped the reason its image sibling shows, and offered an action that cannot succeed. The web and mobile video paths, plus one test.

Verification

  • Found on a macOS desktop (0.1.1-nightly.20261017.3272) paired with a Linux server. The session had no filesystem:read, and the server trace showed no asset request for the video.
  • New browser test in ChatMarkdown.assets.browser.test.tsx: a host video on a connection without file access shows the message and no "Retry video". On main it fails with Video unavailable · DemoRetry video; with this change it passes. vp test run --project browser src/components/ChatMarkdown.assets.browser.test.tsx: 2 passed.
  • vp lint and vp fmt --check on the changed files, and tsc-rs --noEmit in apps/web and apps/mobile: clean (lint shows two existing warnings in LoadedMediaVideo, which this PR does not touch).
  • Dev web app (vp run dev, seeded with migrate-dev-db), with the browser paired by node apps/server/src/bin.ts pair --scope orchestration:read --scope orchestration:operate --scope terminal:operate --scope relay:read, on a thread whose prompt and reply both embed a host video:
Before After
Before: Video unavailable with a Retry video button After: Video unavailable with the missing file access message and no retry
  • Not checked: a packaged desktop build, and the mobile change on a device.

Claude Opus 5.5 via Claude Code, running in T3 Code.

🤖 Generated with Claude Code

… a retry

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-18T04:32:16.075161Z b2a0acb New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Oct 18, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at fe0a9fb

Macroscope's review found this PR approvable — This is a narrowly scoped web bug fix that improves the existing missing-file-access state for host videos and removes only the ineffective retry action in that state. Normal video behavior remains unchanged, and the new path has focused browser coverage.

You can add or adjust custom eligibility rules. Learn more.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe0a9fb8f6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

<ChatMarkdownVideo
src={src}
sourceFailed={assetUrl._tag === "Failure" && fallbackSrc === undefined}
unavailableDetail={missingFileAccess ? MISSING_FILE_ACCESS_MESSAGE : undefined}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Propagate the access explanation to mobile videos

On the mobile client, when a host video is viewed over a connection without filesystem:read, ThreadMarkdownVideo still turns the access failure into only unavailable (apps/mobile/src/features/threads/ThreadMarkdownVideo.tsx:20-42), and the mobile player hard-codes only “Video unavailable” (apps/mobile/src/components/MediaVideoPlayer.tsx:165-166). The access explanation added here is therefore still absent on a first-class client; pass the missing-access reason/detail through the mobile video path too.

AGENTS.md reference: AGENTS.md:L67-L70

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed, it is the same defect on mobile. Fixed in 08412b8: ThreadMarkdownVideo passes MISSING_FILE_ACCESS_MESSAGE when the asset failed with missing-file-access, and the mobile tile shows "Video unavailable. ", the same wording ThreadMarkdownImage uses. The tile has no retry, so nothing else changes. Checked with tsc-rs --noEmit and lint in apps/mobile; not run on a device.

<span className="inline-flex items-center gap-1.5">
<TriangleAlertIcon aria-hidden className="size-3.5 shrink-0" />
Video unavailable{label ? ` · ${label}` : ""}
{["Video unavailable", label, unavailableDetail].filter(Boolean).join(" · ")}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Exclude the generated detail from thread search

When an access-denied video appears before real message text containing a word from this new boilerplate (for example connection), thread find now assigns occurrence 0 to the generated status instead of the persisted message match. collectThreadFindRanges skips generated DOM only under [data-thread-find-ignore] (apps/web/src/components/chat/threadFindHighlights.ts:50-56), and the image fallback already sets that marker (ChatMarkdown.tsx:1352); mark this video label as ignored as well so local highlighting remains aligned with the server's persisted-text occurrence indexes.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch. Fixed in 08412b8: the video label now carries data-thread-find-ignore, matching ChatMarkdownMediaUnavailableLabel for images, so thread find skips the generated text.

@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a3f7c17c-2aa8-4c99-8245-fab1367c1ecb
📥 Commits

Reviewing files that changed from the base of the PR and between 08412b8 and b2a0acb.

📒 Files selected for processing: 1
  • apps/mobile/src/components/MediaVideoPlayer.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.

📝 Walkthrough

Web and mobile media players can display a detail when media is unavailable. ChatMarkdown and ThreadMarkdownVideo pass the missing-file-access message when asset lookup fails for that reason. Web video fallback does not offer retry in this condition.

Changes: Media access feedback

Layer / File(s) Summary
Unavailable media detail
apps/web/src/components/media/MediaVideoPlayer.tsx, apps/mobile/src/components/MediaVideoPlayer.tsx, apps/web/src/components/ChatMarkdown.tsx, apps/mobile/src/features/threads/ThreadMarkdownVideo.tsx
The web and mobile media players accept an optional unavailable detail. ChatMarkdown and ThreadMarkdownVideo pass the missing-file-access message when asset lookup fails for that reason.
Asset access handling and test
apps/web/src/components/ChatMarkdown.tsx, apps/web/src/components/ChatMarkdown.assets.browser.test.tsx
When asset URL creation fails because file access is unavailable and no fallback URL exists, ChatMarkdown passes the missing-access message and omits video retry. The browser test checks the message and confirms that “Retry video” is absent.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to b2a0a

The change explains why host videos are unavailable when file access is denied, and the supplied summaries show retry remains available for other web asset failures. No actionable merge-blocking risk is identified.

Pre-merge checks: Passed 3 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Out of Scope Changes check Warning Issue #21087 targets apps/web. The pull request also changes apps/mobile/src/components/MediaVideoPlayer.tsx and apps/mobile/src/features/threads/ThreadMarkdownVideo.tsx. These changes implement… Remove the mobile changes from this pull request, or link a separate active issue that requires the mobile behavior.
Passed Passed checks: 3 passed
Check name Status Explanation
Linked Issues check Passed Issue #21087 requires a host video without filesystem:read to explain the missing access and avoid an ineffective retry. The web changes pass MISSING_FILE_ACCESS_MESSAGE to the video fallback, dis…
Description check Passed The description covers the problem, change, scope and approval rationale, verification results, UI evidence, and unverified areas. It also identifies the agent and harness used.
Title check Passed The title clearly and concisely describes the primary fix: host videos now explain missing file access instead of offering an unusable retry.
Full details: Linked Issues check

Explanation

Issue #21087 requires a host video without filesystem:read to explain the missing access and avoid an ineffective retry. The web changes pass MISSING_FILE_ACCESS_MESSAGE to the video fallback, display it in the unavailable label, and omit the retry handler for this state. The added browser test checks the message and the absence of Retry video.

Full details: Out of Scope Changes check

Explanation

Issue #21087 targets apps/web. The pull request also changes apps/mobile/src/components/MediaVideoPlayer.tsx and apps/mobile/src/features/threads/ThreadMarkdownVideo.tsx. These changes implement similar behavior, but the directly linked issue contains no mobile requirement. The mobile changes are therefore outside the linked issue scope.

Resolution

Remove the mobile changes from this pull request, or link a separate active issue that requires the mobile behavior.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

…skips the label

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Oct 18, 2026

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 08412b8820

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +168 to +170
{props.unavailableDetail
? `Video unavailable. ${props.unavailableDetail}`
: "Video unavailable"}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include failure detail in the mobile accessibility label

When a host video is blocked on iOS or Android with VoiceOver/TalkBack enabled, this new text is nested inside a Pressable whose explicit accessibilityLabel remains Play ${props.name} (line 148). The pressable is the accessible element and that label replaces its descendant text, so users hear only “Play Demo, disabled” and never the pairing explanation; set a failure-specific label including unavailableDetail when unavailable is true.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed. Fixed in b2a0acb: when the tile is unavailable its accessibilityLabel is now ". Video unavailable. ", built from the same text the tile shows, so VoiceOver and TalkBack read the explanation. A playable tile still announces "Play ". Checked with tsc-rs --noEmit and lint in apps/mobile; not run on a device.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b2a0acbd2c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +43 to +46
unavailableDetail={
"resource" in source && asset._tag === "Failure" && asset.reason === "missing-file-access"
? MISSING_FILE_ACCESS_MESSAGE
: undefined

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Pass missing-access detail through video preview modals

The embedded-tile follow-up now passes this detail, but fresh evidence is the normal host-video link path: a link such as [Demo](/tmp/demo.mp4) is routed by ThreadFeed.tsx:1793-1803 directly to VideoPreviewModal, bypassing this component. In that path VideoPreviewModal.tsx:36-54 collapses asset.reason to a boolean and VideoPreviewModal.ios.tsx:46-52 replaces it with a generic connection error, so Android still displays only “Video unavailable” and iOS tells the user to check the connection even though re-pairing is required; propagate missing-file-access through both modal implementations as well.

AGENTS.md reference: AGENTS.md:L67-L70

Useful? React with 👍 / 👎.

@juliusmarminge juliusmarminge self-assigned this Oct 18, 2026
@juliusmarminge

Copy link
Copy Markdown
Member

Taking over this one. I’ll reduce the tests to the useful coverage, update the implementation against current main, and verify it before publishing the changes.

This branch has not been deployed

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

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: A host video without file access shows "Video unavailable" and a Retry that cannot work

2 participants