Skip to content

06 — CX.33 source-document explorer option scan

06 — CX.33 source-document explorer option scan

Section titled “06 — CX.33 source-document explorer option scan”

Status: Findings (S232 Wave 1B). Foreground investigation per 09-decision-graph-feedback-actions.md §3 (“Platform UI Source-document explorer — investigate options”) and 0.9-context.md §7.5 (“3rd-party tool for source-document explorer (TBD which)”) + Liam’s golden-source-update crossover ask.

Audit date: 12/05/2026 Branch: content-items-investigation Scope: evaluate browse / preview / (optional) edit-back surface for binary golden-source documents (DOCX, PDF, XLSX, MD) held in Supabase Storage. Not the content_items editor — Tiptap+Yjs already covers that per 0.9-edit-flow-investigation.md §6.1 + §9.8.


  • The KH stack already ships every primitive an explorer needs for the markdown + DOCX + PDF paths: Tiptap 3.22 (read + edit), mammoth 1.11 (DOCX → HTML), react-pdf 10.4 + @react-pdf/renderer 4.5 (PDF preview, used in components/reader/pdf-viewer.tsx), docx 9.6 + exceljs 4.4 (write-back for DOCX and XLSX), turndown 7.2 + turndown-plugin-gfm (HTML → markdown). yjs 13.6 + y-prosemirror 1.3 are installed but the collaboration extension isn’t yet wired to a live Y.Doc.
  • No file in lib/, components/, app/ imports @tiptap/extension-collaboration or y-prosemirror as a Tiptap extension — these deps are queued for the §9.8 enable, not active. Source-doc-history UI also has no consumer of a “preview the binary” affordance yet — only diff + history list.
  • Primary recommendation for the v1 explorer: a per-mime-type viewer surface that reuses the in-stack components, mounted from a new app/documents/[id] index page (not the existing [id]/diff sub-route).
    • Markdown → Tiptap (existing ContentEditor in components/item-detail/content-editor.tsx, with readOnly=true for preview, editable for golden-source edit).
    • DOCX → mammoth.convertToHtml + Turndown → mount in Tiptap; edit-back via Tiptap getMarkdown() → optional server-side DOCX regen (see §6).
    • PDF → existing PdfViewer / PdfReaderView (read-only — PDF round-trip is out of scope; flag at UI).
    • XLSX → defer past v1 (form-data shape: handle via structured form UI per 09 §1 Q3.5, not a binary viewer).
  • Secondary recommendation (fallback if Tiptap-as-DOCX-viewer surface proves insufficient): docx-preview as a read-only DOCX renderer (preserves layout fidelity better than mammoth+Tiptap), paired with the existing Tiptap surface for edit-mode. Adds ~150-200 KB minified.
  • Golden-source-update crossover (Liam’s specific ask): the chosen surface handles markdown trivially (Tiptap → write to Storage at storage_path). DOCX round-trip via mammoth-in / Tiptap-edit / docx library-out is feasible but lossy on complex formatting; gates on Wave 1B-2’s Q&A write-back decision. PDF round-trip is out of scope. XLSX edit-back uses the structured form UI path (not a viewer). The explorer’s surface and the edit-flow UC1/UC4/UC6 candidates already converge on Tiptap+Yjs — the explorer is a binary-source viewer that hands off to the same editor for markdown.
  • Net new dependencies if primary recommendation taken: zero. All capability exists in stack; secondary adds docx-preview only if explicit DOCX fidelity is required.

2. What’s already in stack (verified versions, 12/05/2026)

Section titled “2. What’s already in stack (verified versions, 12/05/2026)”
CapabilityPackageVersionActive consumerNotes
Rich-text editor (markdown)@tiptap/react + @tiptap/starter-kit + @tiptap/markdown3.22.0components/item-detail/content-editor.tsx:42-58 (buildExtensions)Markdown-in/markdown-out via editor.getMarkdown(). Used in Q&A answer display, response editor, bid context, item detail.
Tiptap collab plumbing@tiptap/extension-collaboration, yjs, y-prosemirror3.22 / 13.6 / 1.3None — installed but no Y.Doc wiring yetPer 0.9-edit-flow-investigation.md §9.8: “REUSE — one plugin enable away.”
PDF previewreact-pdf + @react-pdf/renderer10.4.1 / 4.5.1components/reader/pdf-viewer.tsx:4, components/reader/pdf-reader-view.tsx:4Already supports filePath → signed-URL → <Document><Page/></Document>. Includes page nav, zoom, fit-width, keyboard navigation.
PDF text extractionunpdf1.4.0lib/extraction/pdf.ts (used by app/api/upload/route.ts:467)Server-side; not a viewer.
DOCX → HTMLmammoth1.11.0app/api/upload/route.ts:13, lib/bid-library-ingest/docx-to-markdown.ts:12, lib/ai/extract-questions.ts:231, lib/bid-library-ingest/extract-qa-pairs.ts:475, app/api/bids/[id]/questions/extract/route.ts:241Verified two-step convertToHtml → Turndown pattern in use (per CLAUDE.md gotcha — convertToMarkdown drops tables).
HTML → markdownturndown + turndown-plugin-gfm7.2.4 / 1.0.2lib/bid-library-ingest/docx-to-markdown.ts:13-14Same pipeline above.
DOCX writer (round-trip-out)docx9.6.0lib/bid/bid-export-docx.ts:10-22Generates .docx from in-memory structure via Packer.toBuffer(). Server-side.
XLSX read/writeexceljs4.4.0lib/bid/bid-export-xlsx.ts:10Existing server-side write path; same package handles read.
Storage bucketSupabase Storage documents bucketn/aapp/api/upload/route.ts:375 (insert), components/reader/pdf-viewer.tsx:63-65 (signed URL read)storage_path column on source_documents points here.
source_documents row + history UIKH scheman/acomponents/source-document/source-document-info.tsx, source-document-history.tsxHistory timeline + version-chain link exist; no preview-the-binary affordance currently surfaced (gap CX.33 fills).

Interpretation: the explorer is a UI-assembly job over existing primitives, not a tool-selection job. The “TBD which third-party tool” framing in 0.9-context.md §7.5 overstates the gap — all read-side primitives are already deployed.


Scoring scale: yes / partial / no / n/a. “In-stack” means already in package.json with at least one active consumer.

3.1 Tiptap viewer (read-only) — already in stack

Section titled “3.1 Tiptap viewer (read-only) — already in stack”
AxisResult
1. Markdown previewyesContentEditor readOnly={true} (line 78 of content-editor.tsx) renders markdown via the existing extension set.
2. DOCX previewpartial — needs mammoth.convertToHtml → Turndown → Tiptap (see §3.5). Loses page layout, headers/footers, comments, tracked changes (though has_tracked_changes() detection exists at scripts/docx_utils.py).
3. PDF previewno — PDF is not a markdown shape.
4. XLSX previewno — table semantics drop; Tiptap’s table extensions are GFM-shaped, not spreadsheet-shaped.
5. Edit-back capabilityyes for markdown (native getMarkdown()); partial for DOCX (round-trip via docx library — lossy on complex formatting); no for PDF / XLSX.
6. Tiptap+Yjs integrationyes — same editor instance; collab extension is the §9.8 enable.
7. Workspace_id scopingyes — access control attaches at the source_documents row + Storage signed-URL layer (existing pattern at components/reader/pdf-viewer.tsx:63-65).
8. Golden-source updateyes (markdown), partial (DOCX), no (PDF/XLSX). Markdown writes back to Storage at storage_path; DOCX requires regen step.
9. Bundle impact0 KB — already shipped.
10. LicenceMIT (Tiptap), MIT (mammoth), MIT (Turndown).

3.2 ProseMirror viewer (raw, no Tiptap wrapper)

Section titled “3.2 ProseMirror viewer (raw, no Tiptap wrapper)”
AxisResult
1. Markdown previewyes but requires re-implementing the markdown serialiser Tiptap already provides.
2-4. DOCX / PDF / XLSXno — same constraint as Tiptap; no shape advantage.
5. Edit-backyes for markdown (more work than Tiptap to wire).
6. Tiptap+Yjs integrationn/a — Tiptap IS the ProseMirror wrapper. Using raw ProseMirror means dropping the existing buildExtensions pipeline and re-implementing schema parity.
7-10. Workspace / golden-source / bundle / licenceIdentical to Tiptap (smaller bundle by ~20 KB; not material). MIT.

Verdict: strictly worse than Tiptap — same capability surface, more bespoke code. Discount.

AxisResult
1. Markdown previewno.
2. DOCX previewno.
3. PDF previewyes — production-deployed at components/reader/pdf-viewer.tsx (Dialog + toolbar + nav + zoom + keyboard) and pdf-reader-view.tsx (inline variant). Already reads from Supabase Storage signed URLs.
4. XLSX previewno.
5. Edit-backnoreact-pdf is render-only. Form-field PDFs aren’t in scope per the corpus shape.
6. Tiptap+Yjs integrationn/a.
7. Workspace_id scopingyes — signed-URL pattern verified at line 63-65.
8. Golden-source updateno — flag as one-way preview.
9. Bundle impact0 KB — already shipped.
10. LicenceMIT.
AxisResult
1. Markdown previewno.
2. DOCX previewyes — renders .docx natively in-browser, preserving styles, headers/footers, footnotes, images. Higher fidelity than mammoth+Tiptap.
3. PDF previewno.
4. XLSX previewno.
5. Edit-backno — render-only. Edit-back stays in Tiptap (so this is paired with §3.5, not replacement).
6. Tiptap+Yjs integrationn/a — separate surface.
7. Workspace_id scopingyes — signed-URL → ArrayBuffer pattern works identically to react-pdf.
8. Golden-source updateno on the preview path — edit-back delegates to the Tiptap surface.
9. Bundle impact~150-200 KB minified (pulls in jszip + DOM rendering).
10. LicenceApache 2.0.

3.5 mammoth.js → Tiptap (composed) — already in stack

Section titled “3.5 mammoth.js → Tiptap (composed) — already in stack”

This is the production-realistic markdown-as-canonical pathway: mammoth.convertToHtml → Turndown → Tiptap mount. Identical pipeline to lib/bid-library-ingest/docx-to-markdown.ts:38-44 (docxBufferToMarkdown). KH already normalises DOCX uploads to markdown at ingest time (app/api/upload/route.ts:476-477), so this is internally-consistent with the rest of the platform.

AxisResult
1. Markdown previewyes — Tiptap handles.
2. DOCX previewyes, as markdown — meaningful loss of formatting fidelity (tables preserved per CLAUDE.md gotcha + GFM plugin; headers/footers / page-layout / comments / tracked-changes / footnotes degrade).
3. PDF previewno.
4. XLSX previewno.
5. Edit-backyes (markdown-canonical) — Tiptap edit → getMarkdown() → write to Storage. For golden-source DOCX edit-back: add server-side step to convert markdown → DOCX via existing docx 9.6 package (the inverse of bid-export-docx.ts). Round-trip is lossy by design (markdown is the canonical layer).
6. Tiptap+Yjs integrationyes — same editor; collab via §9.8 enable.
7. Workspace_id scopingyes.
8. Golden-source updatepartial-yes — see §6.
9. Bundle impact0 KB — already shipped. Server-side conversion runs in existing upload-route environment.
10. LicenceMIT (Tiptap), MIT (mammoth), MIT (Turndown), MIT (docx writer).
AxisResult
1. Markdown previewpartial — has a markdown plugin but maturity lower than Tiptap’s.
2-4. DOCX / PDF / XLSXno — no first-party plugins.
5. Edit-backyes for markdown (after wiring).
6. Tiptap+Yjs integrationn/a — different framework. Lexical has its own Yjs adapter (@lexical/yjs) but doesn’t reuse the existing @tiptap/extension-collaboration plumbing.
7. Workspace_id scopingyes (storage-layer concern, framework-agnostic).
8. Golden-source updateSame as Tiptap shape, but reimplemented.
9. Bundle impact~100-150 KB.
10. LicenceMIT.

Verdict: discounting per 0.9-context.md §8 anti-pattern (“don’t fall into ‘extend the existing infrastructure’ trap” cuts both ways — also “don’t introduce a new framework where existing one suffices”). Lexical adds zero capability over Tiptap for KH’s markdown-canonical model.

AxisResult
1. Markdown previewno.
2. DOCX previewno.
3. PDF previewyes — Adobe-hosted; supports annotation, form-fill, comments.
4. XLSX previewno.
5. Edit-backpartial — Adobe-hosted annotation layer, not raw PDF mutation.
6. Tiptap+Yjs integrationn/a.
7. Workspace_id scopingpartial — requires Adobe-hosted credential per workspace; introduces an external dependency on document URLs reachable by Adobe’s servers.
8. Golden-source updateno (annotation overlays, not source mutation).
9. Bundle impactSmall JS shim (~30 KB); load deferred to Adobe-hosted iframe.
10. LicenceProprietary — free tier with attribution; commercial use needs Adobe terms.

Verdict: discounting. Strictly inferior to react-pdf for KH’s needs (no annotation requirement surfaced in 09-decision-graph-feedback-actions.md), and introduces an external-services dependency that conflicts with the “binary stays in Supabase Storage” assumption.

Functionally equivalent surface to Tiptap with weaker ecosystem and no first-party Yjs. Discount on same grounds as Lexical.


4.1 Primary: per-mime-type viewer composed from in-stack primitives

Section titled “4.1 Primary: per-mime-type viewer composed from in-stack primitives”

Route: new app/documents/[id]/page.tsx (today the only [id]/ content is /diff/).

Behaviour by MIME type (taken from source_documents.mime_type):

MIMEComponentMode
text/markdown, text/plainContentEditor (existing components/item-detail/content-editor.tsx)readOnly toggle. Edit → onSave writes to Storage at storage_path.
application/vnd.openxmlformats-officedocument.wordprocessingml.document (DOCX)server-side mammoth.convertToHtml → Turndown → ContentEditorreadOnly for preview; edit-mode persists markdown; optional DOCX regen via docx 9.6 on save (gates on §6).
application/pdfPdfReaderView (existing components/reader/pdf-reader-view.tsx)read-only. Banner reads “PDF source — preview only. Edit-back not supported (extract Q&A pairs or re-upload a revised binary).”
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet (XLSX)defer past v1 — render an “Open in spreadsheet form UI” affordance pointing at the structured-form path (Wave 1B-3 forms / coverage).

Workspace_id scoping: the page is gated on source_documents.workspace_id lookup with the existing role-based RLS; signed-URL pattern from pdf-viewer.tsx:63-65 reused. No new access-control surface needed.

Existing infrastructure reused:

  • source_documents.storage_path → Supabase Storage documents bucket (already wired).
  • source_documents.mime_type → drives component selection.
  • source_documents.workspace_id → drives RLS (per Option α in finding 01 §1).
  • Tiptap + Yjs collab via §9.8 enable (deferred to v1.1 per 0.9-edit-flow-investigation.md §6.1 Q4 ratification).
  • Existing SourceDocumentInfo (components/source-document/source-document-info.tsx) and SourceDocumentHistory sidebar.
  • Existing diff UI at app/documents/[id]/diff/page.tsx linked from the new page (the explorer page becomes the index that the diff page hangs off).

Justifications:

  1. Reuse over introduction (0.9-context.md §8): every read-side primitive is already shipped and has at least one prod consumer. Adding a framework or new viewer is unjustified spend.
  2. Markdown-first ingestion (per 0.9-context.md §7.2): KH normalises DOCX to markdown at ingest. Surfacing a markdown view of the source is internally-consistent and trivially round-trippable.
  3. Convergence with edit-flow §6.1 Candidate A: the explorer’s edit mode IS the UC1 / UC4 / UC6 in-platform-edit surface. Two affordances, one editor.
  4. Per-MIME selection rather than “one viewer for everything” is the only honest answer — DOCX / PDF / XLSX have genuinely different semantics, and pretending otherwise produces a worse UX.

4.2 Secondary: add docx-preview ONLY if mammoth+Tiptap loses critical fidelity

Section titled “4.2 Secondary: add docx-preview ONLY if mammoth+Tiptap loses critical fidelity”

Trigger: user-feedback during v1 that the markdown-flattened DOCX preview loses information the user needs to see (headers / footers / styling cues / footnote anchors). Most likely surfaced from the docs/client-documentation-base/binary/ corpus — particularly long-form prose docs with heavy formatting.

Shape: view-mode toggles between “Markdown view” (Tiptap, default) and “Original layout” (docx-preview read-only iframe / shadow-DOM mount). Edit always uses the Tiptap surface.

Cost: ~150-200 KB minified bundle on top of react-pdf’s existing ~80 KB. Apache 2.0.

Don’t install pre-emptively — recommendation is to wire the per-MIME page first, observe whether the markdown-view fidelity is sufficient, and add docx-preview only on confirmed gap. This matches the 0.9-context.md §7.1 principle of avoiding speculative dep additions.


5. Golden-source-update crossover (Liam’s specific ask)

Section titled “5. Golden-source-update crossover (Liam’s specific ask)”

The explorer needs to enable “seamlessly updating underlying golden-source knowledge hub documents” per Liam’s note in 09-decision-graph-feedback-actions.md §3. Handling per MIME:

  • User clicks “Edit” on the explorer page.
  • ContentEditor mounts in editable mode against the markdown loaded from storage_path.
  • User edits → onSave writes the modified markdown back to Storage at the same storage_path (or to a new versioned path under finding 01 Option α slim-and-keep).
  • Cocoindex source binding observes the file change on next scan (per 0.9-edit-flow-investigation.md §6.1 Candidate A) — the same write-back primitive UC1 / UC4 / UC6 use.
  • content_items derived from the source re-flow through the pipeline; content_history records the edit via existing DB trigger.
  • Read path: mammoth.convertToHtml (server-side) → Turndown → markdown → Tiptap mount.
  • Edit path: Tiptap edit → getMarkdown().
  • Write-back path: TWO options:
    1. Markdown-canonical (recommended for v1): write the edited markdown back as a sidecar .md alongside the .docx (or replace the .docx storage_path with the .md if the workspace policy allows). The original DOCX becomes the “frozen original”; the markdown is the live editable surface. This matches 0.9-edit-flow-investigation.md §6.1.1 Q6 ratification (“Prompted on first edit; silent thereafter per record”).
    2. DOCX-canonical (deferred to v1.1): server-side regen via docx 9.6 package. Markdown → AST → DOCX-paragraph-tree → Packer.toBuffer() → upload to Storage. Lossy: lacks the original styles / templates / numbering / images bundled in the source DOCX. Not worth the implementation cost in v1 when the markdown-canonical sidecar covers the workflow.
  • The Q&A-write-back investigation (02-q29-q32-q111-q112-qa-write-back.md, Wave 1B-2) covers a structurally identical decision for Q&A pair sources. Whatever shape that lands with should be carried forward here.
  • PDFs are not round-trippable through markdown without information loss; even Adobe-grade tooling (PDF Embed API) only adds annotation overlays rather than mutating the binary.
  • Recommendation: the explorer renders PDFs read-only with a banner directing the user to either (a) re-upload a revised PDF (engages the UC7+UC10 binary re-upload flow per 0.9-edit-flow-investigation.md §6.7), or (b) extract Q&A pairs and edit those via the standard UC6 surface.

5.4 XLSX (form-data) — not a viewer concern

Section titled “5.4 XLSX (form-data) — not a viewer concern”
  • The cited example (Cloud Security Principles Checklist) is form-data per 09-decision-graph-feedback-actions.md §1 Q3.5: it’s a structured questionnaire, not free-form prose.
  • A spreadsheet viewer would be the wrong primitive — the user needs the form-fill UI from the Wave 1B-3 forms / coverage stream (docs/plans/phase-0-investigation/10-feedback-investigation-findings/ future doc), not a cell-grid.
  • The explorer’s XLSX affordance should be a one-line CTA: “Open in form view →” linking to the form-fill route once that work lands.

If the user edits a markdown source through the explorer, does cocoindex (when wired) re-extract the content_items downstream? Per 0.9-edit-flow-investigation.md §6.1 Candidate A:

  • Cocoindex source binding observes the file change on next scan.
  • Engine compares content-hash; mismatched → re-runs the binary-shape adapter for that source-key.
  • Resulting content_items are UPSERTed (not duplicated); content_history v2/v3 lands via existing DB trigger.
  • §6.1 Q3 ratification: cocoindex idempotency on equal-hash gates on S9 spike result — but the explorer’s edit path is the same path as UC1’s, so it inherits whatever resolution S9 produces.

Open question raised by this scan: does cocoindex re-extract on a user-initiated edit-back? Gates on Wave 1B-2’s resolution of the WP3 ledger query pattern (see 0.9-edit-flow-investigation.md §6.1 + Q3 / Q4 carry-forward).


Sketch (not binding on implementation):

  • Route: app/documents/[id]/page.tsx (the document [id] is source_documents.id).
  • Layout: main content area + right-rail metadata sidebar.
  • Main content: mounts <DocumentViewer mimeType={...} storagePath={...} editable={...} /> — a thin dispatcher that picks <MarkdownViewer /> / <DocxViewer /> / <PdfViewer /> / <XlsxFormCta />.
  • Sidebar: existing <SourceDocumentInfo /> (filename, version, file size, hash, uploaded by, created at) + <SourceDocumentHistory /> (version chain, if Option α retains it; see finding 01 §3.4).
  • Toolbar: view-only / edit mode toggle (subject to permission per 0.9-edit-flow-investigation.md §6.0.4); “Download original” link; “View diff vs previous” if parent_id set; “Re-upload as new version” CTA.
  • Edit-save flow:
    • Markdown: direct Storage update() at storage_path; cocoindex re-flow follows.
    • DOCX (v1 markdown-canonical): write sidecar .md; mark DOCX as “frozen original”.
  • Concurrent-edit handling: Yjs collab via §9.8 enable (deferred to v1.1 per 0.9-edit-flow-investigation.md §6.1 Q4).

This page is also the natural home for the existing app/documents/[id]/diff/page.tsx sub-route to hang off — the explorer page becomes the index (“you’re looking at v3 of policy-v2.docx — see v2-vs-v3 diff →“).


Adjacent areaImplication
Finding 01 Option α vs βA v1 explorer surface needs SOME row to dispatch from. If Option β (drop source_documents entirely) lands, the explorer dispatches from cocoindex source-key + Storage path lookups (more indirection; tolerable). Option α (slim-and-keep) is the cleaner host. Either way the explorer’s viability isn’t blocked.
Edit-flow §6.1 (UC1) Candidate AThe explorer’s “Edit” mode IS UC1’s write-back surface. No new architectural decision; this is the per-MIME UI face of the same write-back primitive.
§6.1.1 Q6 (binary source sidecar prompt)Liam’s ratification “Prompted on first edit; silent thereafter per record” applies directly. The explorer’s first DOCX edit triggers the prompt.
§9.8 Tiptap+Yjs enableConcurrent-user editing on the explorer page benefits from the same enable. Not a blocker for v1 read-mode.
Wave 1B-2 (Q&A write-back)The DOCX-canonical-vs-markdown-canonical decision recurs there for Q&A pair sources. Whatever shape lands should propagate here.
Wave 1B-3 (forms / coverage)The XLSX CTA depends on the forms-UI shape. Until that lands, the explorer’s XLSX path is a stub.
CX.33 → decision-graph statusMove to RESOLVED with implementation seed once this finding is reviewed: primary recommendation is “compose from in-stack primitives, no new deps required.”
0.9-context.md §7.5 “3rd-party tool TBD”The framing is partially obsolete — the third-party tools (react-pdf, mammoth, docx, Tiptap, exceljs) are already in stack. Update §7.5 to note “Composed from in-stack primitives per finding 06; docx-preview provisional if fidelity gap surfaces.”

QFor
OQ-CX33-ADoes cocoindex re-extract content_items on user-initiated edit-back through the explorer? — gates on WP3 ledger query pattern (0.9-edit-flow-investigation.md §6.1 Q3 / Q4 carry-forward).
OQ-CX33-BDOCX write-back canonical: markdown-sidecar (v1 recommendation) vs full DOCX regen via docx 9.6 (v1.1 candidate) — confirm against Wave 1B-2 Q&A write-back outcome.
OQ-CX33-CDoes the explorer page need a “preview only” affordance for non-editor users (per 0.9-edit-flow-investigation.md §6.0.4 role matrix), or does the existing readOnly toggle on ContentEditor cover it? Confirm with role-matrix walkthrough.
OQ-CX33-DXLSX explorer affordance — render a placeholder CTA in v1, or hide the explorer entirely for XLSX MIME until Wave 1B-3 lands? Recommendation: render a CTA so the user isn’t blocked from seeing the source row exists.
OQ-CX33-EIf source_documents retires under finding 01 Option β, what becomes the canonical “show me all extractions from this one upload” query the explorer needs? Cocoindex ops-DB query? Wave 1B-2’s q_a_extractions join? Resolve before implementation.
OQ-CX33-Fdocx-preview add-or-defer trigger — define what “critical fidelity loss” means concretely (specific corpus examples from docs/client-documentation-base/binary/) so the decision isn’t perpetually deferred.
OQ-CX33-GAnnotation / highlight overlay on PDF preview — out of scope for v1 per §3.7 discount of Adobe PDF Embed API, but reconfirm against any sector-intelligence read-mode requirements that may surface.

End of finding 06.