Skip to content

fix: preview PDFs and slides inline with agent change requests - #438

Merged
devSejung merged 2 commits into
mainfrom
fix/platformclaw-document-preview-csp
Nov 2, 2026
Merged

devSejung merged 2 commits into
mainfrom
fix/platformclaw-document-preview-csp

Conversation

@devSejung

@devSejung devSejung commented Nov 2, 2026 •

Copy link
Copy Markdown
Owner

Closes #436

What Problem This Solves

Fixes an issue where employees opening PDF or PowerPoint attachments in Chrome saw a blocked-content page instead of their preview. Browser-native PDF frames also produced inconsistent controls and left no way to point at a document section when asking the agent for changes.

Why This Change Was Made

Use one app-owned PDF.js canvas viewer for PDFs and the existing LibreOffice-converted slide snapshots. Bundle the version-matched worker, character maps, fonts, WASM, ICC resources, and license with the UI. Keep the existing authenticated snapshot, ownership checks, VM/file bridge, and original download path.

The dependency owner needs a small, explicitly approved PDF.js 6.4.299 patch: operator-stream errors must reject rendering and public operator-list readers instead of reporting successful blank/partial output. An exact-version, patch-byte, lock-hash, and archive-integrity guard registers it separately from security advisory patches. Remove it when an upstream release passes the same failure/replay/cancellation regressions. Other upstream decoder and annotation recovery behavior is unchanged.

User Impact

  • Visible document cards open automatically; manually closing a preview keeps that source closed. Offscreen cards do not load document bytes or create workers.
  • One existing inline attachment box fits the document to its width. Page/slide navigation sits below the document, inside the same box. Contents is immediately left of the pencil-marked Request changes button. Zoom, fit, and optional Expand stay in Preview options.
  • Request changes explicitly enables selection. Clicking a text run or region opens a small adjacent input inside the preview; dragging selects a custom region. Enter instructions and send them to the owning conversation. PDF font-metric hit areas and bounded context crops do not claim native PowerPoint object selection or direct Office editing.
  • The existing outbox and Retry own admitted requests. Human composer drafts and attachments remain intact. Cancel, close, source replacement, and page changes retire stale selection work.
  • Region requests attach a bounded PNG crop; the reply references the original message. This does not provide native PowerPoint object editing or reattach the original document.
  • Korean users see all 39 new viewer messages localized, including Contents (목차), Request changes (수정 요청), and the adjacent input guidance. The existing PlatformClaw nativeTranslations merge owns this copy; canonical upstream locale adapters, generated memory, metadata, and CI isolation rules remain unchanged.
  • No Canvas configuration or reverse-proxy CSP relaxation is required. PDF scripting and interactive form/link layers are not installed; failures stay visible with the original download available.

Evidence

Rebased onto main at 318b75da5d4eb7defc95b6cf746449661251e3cc. Range-diff confirms the reviewed patch is unchanged; upstream composer diagnostics are preserved. Runtime proof was collected at the earlier 0c8281c637d370cd24b3e2cc5a1e1cabf9b13603 base, whose viewer/runtime source is unchanged by that rebase. Validation used task-owned Ubuntu 22.04 Docker containers, Node 24.18.0, pnpm 11.15.1, Chromium, rootless Docker Basic execution, and a real SSH assigned-VM fixture. Identity/history/chat-send endpoints use the standard controlled gateway fixture; asset CSP, media snapshots, conversion, PDF worker, browser selection, crop pixels, and download paths are real.

  • Reproduced the original Chrome blocked page through the employee asset handler before the fix, including an enforced frame-src violation.
  • 91 focused tests passed on the approved inline viewer/card/selection/binding/request/pane behavior. Unchanged packaging/performance/Vite/sidecar owners passed 55 tests, and existing chat-send ownership proof is retained. The final button/icon and Canvas test-adapter changes passed 22 affected tests and UI-test tsgo.
  • Browser proof: 10 tests passed on the document Docker/SSH, mapped bridge, rendering, and image-read lifecycle suites. Covers source deletion/reload, foreign-owner refusal, original downloads, default open/close, contents/navigation, real mouse clicks on painted text, adjacent inputs, region capture, desktop/mobile bounds, cancellation, and one correctly bound outbound request. Oversized scans visibly fail; public operator failures/replay reject and ordinary cancelled renders recover. Final button/icon placement is a presentation-only follow-up to that proof.
  • Final full node scripts/run-tsgo.mjs -b tsconfig.projects.json, node scripts/run-lint.mjs, pnpm check:import-cycles, pnpm build, formatting, and git diff --check: passed. After adding Korean copy, the affected UI typecheck, lint, UI build, keyless i18n baseline/verify, and 23 existing translation tests passed. The existing product-locale integration test confirms Korean viewer labels and interpolated page positions, English locale switching, and preservation of the generated base catalog. The raw-copy baseline is unchanged.
  • Fresh $autoreview, uncommitted candidate against the pinned base: scoped-clean through P2, no accepted/actionable findings.
  • OPENCLAW_CHECK_CHANGED_REMOTE_CHILD=1 node scripts/platformclaw-check.mjs --changed passed the PlatformClaw lane and upstream guards, then found a Canvas test mock type error. After fixing the narrow adapter, the failed full typecheck and remaining full lint/import-cycle stages passed individually; unchanged preceding guard results are reused. No skip flags or baseline relaxation were used. The original implementation matched across host/Linux; all 19 final CI-repair file hashes also match.

The CI repair addresses three owning boundaries: renderers use a leaf document-change type contract rather than importing the stateful factory; Korean copy lives under the existing PlatformClaw native locale owner; every Vite test entrypoint, including the deferred source E2E server, registers the production PDF asset plugin. No optimizer retry, assertion relaxation, timeout increase, or guard/baseline change was introduced.

Repair validation in Ubuntu Docker: canonical generated-ownership checks 3 passed, request/pane/binding/locale checks 56 passed, actual Chromium project 203 passed, and the four previously failing source-server E2E files 15 passed. The exact failed core-test typecheck, UI typecheck, Madge (zero cycles), scoped lint, UI build, sidecar/performance checks, and fresh autoreview through P2 passed. The browser fixtures were run with the same English locale expected by CI; an initial run inheriting the task container's Korean locale was retained as a known fixture-language mismatch. Hosted CI is green for e429293413f36320fb63243767b8aa68eb3ba8dd: exact-head CI run. All six previously failing checks and the remaining PR checks passed; the exact-head watcher returned GREEN with zero pending checks.

The separately approved worker limit is 360 KiB gzip. Ordinary JavaScript remains capped at 215 KiB and startup at 326 KiB; their baseline is unchanged. Final UI measurements: startup 333,058 bytes gzip (325.3 KiB), largest ordinary chunk 178.2 KiB, worker 351.6 KiB; all limits pass and 828 precompressed sidecars verify. Workers remain included in total JavaScript and cannot enter startup HTML. Standard gzip compression is round-trip verified.

Sanitized desktop/mobile/contents/request screenshots and videos are retained outside Git. The existing CI UI evidence upload publishes the platformclaw-canvas/document-previews captures in its exact-head html-attachment-browser-proof-* artifact. No screenshots or runtime state are committed.

Net growth is 2,793 production lines, 3,513 tests lines, 31 documentation lines, 172 dependency/patch metadata lines. Production growth belongs to the shared renderer/worker lifecycle, bounded selection geometry, request lifecycle, current-owner outbox admission, and requested Korean copy; tests are counted separately. Selected text and crops are explicit user context rather than a global prompt addition. Protocol, config, and database schemas do not change.

@devSejung
devSejung marked this pull request as ready for review November 2, 2026 08:40
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Dependency Guard

This PR changes dependency-related files. Maintainers should confirm these changes are intentional.

Changed files:

  • patches/pdfjs-dist@6.4.299.patch
  • pnpm-lock.yaml
  • pnpm-workspace.yaml
  • ui/package.json

Maintainer follow-up:

  • Review whether the dependency changes are intentional.
  • Inspect resolved package deltas when lockfiles or workspace dependency policy changes are present.
  • Treat pnpm-lock.yaml and package-lock.json diffs as dependency security-review surfaces.
  • Run pnpm deps:changes:report -- --base-ref origin/main --markdown /tmp/dependency-changes.md --json /tmp/dependency-changes.json locally for detailed release-style evidence.

@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Dependency graph changes noted

This PR includes dependency graph changes. The dependency guard is informational because the PR author is a repository admin or a member of @openclaw/openclaw-secops.

  • Current SHA: e429293413f36320fb63243767b8aa68eb3ba8dd
  • Trusted actor: @devSejung
  • Trusted role: pull request author; repository admin

Security review is still recommended before merge when the dependency graph change is intentional.

@devSejung
devSejung merged commit 1bf9596 into main Nov 2, 2026
79 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: PDF and PowerPoint previews are blocked in employee web chat

1 participant