diff --git a/docs/phase-6-reaudit-2026-06-29.md b/docs/phase-6-reaudit-2026-06-29.md
new file mode 100644
index 0000000000..e92314e82f
--- /dev/null
+++ b/docs/phase-6-reaudit-2026-06-29.md
@@ -0,0 +1,83 @@
+# Phase 6 Re-Audit - June 29, 2026
+
+## Scope
+
+This pass re-checked the remediation work after the M2 merge and live Supabase migration. It covered:
+
+- clinical answer and source-governance refusal paths,
+- private source access and signed URL ownership checks,
+- reindex mutation safety and M2 abandoned-generation recovery,
+- current indexing health,
+- lower-confidence remediation candidates,
+- broad DocumentViewer papercuts.
+
+The pass intentionally avoided dependency changes and unrelated local work.
+
+## Current Evidence
+
+Commands run during the pass:
+
+- `npm run check:supabase-project` - passed against project ref `sjrfecxgysukkwxsowpy`.
+- `npm run check:production-readiness` - passed. Warnings were limited to the expected local `.env.local` service-role marker and missing top-level `.env`.
+- `npm run reindex:health` - passed with 2065 indexed documents, 0 queued/processing/failed documents, 0 pending/processing/failed jobs, and 69334 chunks with retrieval synopsis.
+- `npm run reindex:cleanup-staged` - dry run passed with 0 eligible abandoned staged-generation documents and 0 artifact rows.
+- `npm run check:indexing` - passed with 2065/2065 documents indexed, 0 chunk-count mismatches, 0 mixed-generation documents, 0 duplicate content-hash groups, 0 chunks missing embeddings, and 0 actionable failed or stuck jobs.
+
+Recent release context before this branch:
+
+- PR #91 merged M2 atomic reindex recovery to `main`.
+- The live migration `20260629000000_abandoned_reindex_generation_recovery.sql` was applied.
+- `cleanup_abandoned_document_index_generations(uuid, integer, boolean)` exists in the live project; anon cannot execute it and service-role execution is available through the staged cleanup script.
+- The post-M2 dry run found no abandoned staged generations to clean.
+
+## Re-Audit Results
+
+### Clinical and Security-Sensitive Paths
+
+- `/api/answer` and `/api/answer/stream` still require authenticated users outside demo mode, apply rate limits, resolve scope before generation, and return an explicit safe refusal when source-governance warnings contain danger severity.
+- The refusal contract does not spread the original generated answer, sources, smart panel, or API plan into the response.
+- Document and image signed URL routes still require ownership-scoped document checks before returning private storage URLs.
+- Image and document retrieval paths continue filtering uncommitted index-generation metadata so staged reindex artifacts do not leak into normal viewer/search paths.
+- Single-document and bulk reindex routes still check ingestion mutation safety before mutating index artifacts.
+
+No confirmed clinical/security regression was found in this pass.
+
+### Lower-Confidence Batch
+
+No lower-confidence audit item was promoted to implementation without a reproducible failing behavior or a failing test. The remaining candidates should stay backlog-scoped until each has:
+
+- a concrete observed defect,
+- an owner,
+- acceptance criteria,
+- a focused regression test.
+
+### DocumentViewer Papercuts
+
+One low-risk papercut was implemented:
+
+- The indexed-source search hit controls now use compact icon controls with retained accessible names and `title` text. This reduces visual crowding in the tight source-passage toolbar without changing keyboard or screen-reader operation.
+
+Existing coverage confirmed these broader DocumentViewer behaviors are already represented in smoke tests:
+
+- mobile pinned evidence appears before the PDF preview,
+- viewer section anchors expose Evidence and PDF,
+- failed PDF preview exposes retry recovery,
+- private missing source states do not get stuck on loading copy,
+- full-document source search opens and advances between hits.
+
+Broad DocumentViewer restyling remains deferred. It should be a separate UX PR if new defects are reproduced through screenshots or user sessions.
+
+## Remaining Caveats
+
+- The local working tree includes an unrelated edit in `scripts/classify-documents.ts`; this pass does not include or modify it.
+- Production readiness still warns when local secret-bearing env files are present; this is expected for local verification and should not be committed.
+- RAG enrichment and deep-memory coverage are not at 100 percent, but the current indexing health checks do not classify that as a release blocker.
+
+## Follow-Up Acceptance Criteria
+
+Before closing future deferred items:
+
+- Add a failing test or screenshot evidence for each lower-confidence or broad viewer issue.
+- Keep clinical/source-governance changes paired with `npm run check:production-readiness`.
+- Keep DocumentViewer UI changes paired with the focused smoke path and `npm run verify:ui`.
+- Keep Supabase/indexing changes paired with `npm run check:supabase-project`, `npm run check:indexing`, and `npm run reindex:health`.
diff --git a/src/components/DocumentViewer.tsx b/src/components/DocumentViewer.tsx
index 453c688b09..b833d00509 100644
--- a/src/components/DocumentViewer.tsx
+++ b/src/components/DocumentViewer.tsx
@@ -861,19 +861,19 @@ function IndexedTextPanel({
diff --git a/tests/ui-smoke.spec.ts b/tests/ui-smoke.spec.ts
index de60718931..9f0774ad6d 100644
--- a/tests/ui-smoke.spec.ts
+++ b/tests/ui-smoke.spec.ts
@@ -1107,8 +1107,13 @@ test.describe("Clinical KB UI smoke coverage", () => {
await sourceSearch.fill("safety plan include");
const desktopTextPanel = page.getByTestId("desktop-chunk-indexed-text-panel");
await expect(desktopTextPanel.getByText("Hit 1 of 2").first()).toBeVisible();
- await expect(desktopTextPanel.getByRole("button", { name: "Next document search hit" })).toBeVisible();
- await desktopTextPanel.getByRole("button", { name: "Next document search hit" }).click();
+ const previousHit = desktopTextPanel.getByRole("button", { name: "Previous document search hit" });
+ const nextHit = desktopTextPanel.getByRole("button", { name: "Next document search hit" });
+ await expect(previousHit).toHaveAttribute("title", "Previous document search hit");
+ await expect(previousHit).toHaveText("");
+ await expect(nextHit).toHaveAttribute("title", "Next document search hit");
+ await expect(nextHit).toHaveText("");
+ await nextHit.click();
await expect(desktopTextPanel.getByText("Hit 2 of 2")).toBeVisible();
await expect(desktopTextPanel.locator("mark").filter({ hasText: "safety" }).first()).toBeVisible();
await expectNoPageHorizontalOverflow(page);