From 3e917969c70b264eb765ac9ed53d241b2d1e0ce5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?=
Date: Thu, 16 Jul 2026 00:54:01 +0200
Subject: [PATCH] fix(documents): surface the read-by-AI provenance in the
detail view
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
v1.28.38 removed the purple AI-read glyph from the vault card (it looked
wrong there), but that glyph had been the only visible surface for the
'read by AI' provenance since v1.28.22 — the detail sheet's AI section
shows no status and collapses entirely under auto-read. Add a discreet
muted 'Read by AI' line under the document's uploaded-metadata in the
detail view (data-slot document-detail-ai-read), independent of the AI
section's collapse logic; reinstate documents.ai.statusAiRead in all six
locales. Card glyph stays removed. The e2e that asserted the card marker
now deep-links the document and asserts the detail-view line.
---
CHANGELOG.md | 3 +-
e2e/documents-ai.spec.ts | 30 +++++++------------
messages/de.json | 1 +
messages/en.json | 1 +
messages/es.json | 1 +
messages/fr.json | 1 +
messages/it.json | 1 +
messages/pl.json | 1 +
.../documents/document-detail-sheet.tsx | 16 ++++++++++
9 files changed, 35 insertions(+), 20 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a09d74550..3f7f113bf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,8 @@
## [1.28.38] — 2026-07-16 — Documents polish, waist reminders, bulk sharing
The document vault gets a round of overdue polish. The list cards drop a
-stray glyph and give the real filename its own line so it stops being cut
+stray glyph — the "read by AI" mark it carried moves into the document's
+detail view — and give the real filename its own line so it stops being cut
off; the detail view's close button is aligned correctly (a shared sheet
primitive was reserving space for a button it wasn't showing). The action
that opens a document in the coach now reads "Coach fragen".
diff --git a/e2e/documents-ai.spec.ts b/e2e/documents-ai.spec.ts
index ad33f54b7..1bb3b71d0 100644
--- a/e2e/documents-ai.spec.ts
+++ b/e2e/documents-ai.spec.ts
@@ -357,26 +357,18 @@ test.describe("document vault — AI assist + content search", () => {
page,
}) => {
// CONTENT_DOC_ID is seeded with source "vision" (an AI provider read it).
- // No mocks: the real list GET threads the provenance through. v1.28.22 —
- // the marker lives on the vault CARD's meta row (an inline glyph beside
- // date · size), not in the sheet. Surface the card through search (the
- // grid is virtualized, so a targeted card must be brought into view the
- // way a user would).
- await page.goto("/documents");
- await expect(
- page.getByRole("heading", { name: "Documents" }),
- ).toBeVisible();
- await page
- .getByRole("searchbox", { name: "Search documents" })
- .fill(CONTENT_BODY_WORD);
- await expect(
- page.getByRole("button", { name: "Open Radiology note" }),
- ).toBeVisible({ timeout: 10_000 });
+ // No mocks: the real detail GET threads the provenance through. v1.28.38 —
+ // the vault card no longer carries the AI-read glyph (it looked wrong on
+ // the card face); the provenance now lives as a calm muted meta line in the
+ // document DETAIL view. Deep-link straight to the document so the sheet
+ // opens deterministically (the vault grid is virtualized).
+ await page.goto(`/documents?doc=${CONTENT_DOC_ID}`);
+ const sheet = page.getByRole("dialog");
+ await expect(sheet).toBeVisible();
- const marker = page.locator(
- `[data-document-id="${CONTENT_DOC_ID}"] [data-slot="document-card-ai-read"]`,
- );
- await expect(marker.first()).toBeVisible();
+ const marker = sheet.locator('[data-slot="document-detail-ai-read"]');
+ await expect(marker).toBeVisible();
+ await expect(marker).toHaveText("Read by AI");
});
// ── (f) Text-mode refuses a non-image before any OCR/upload ──────────────
diff --git a/messages/de.json b/messages/de.json
index 88df9f595..b44c2efcb 100644
--- a/messages/de.json
+++ b/messages/de.json
@@ -8355,6 +8355,7 @@
"close": "Ausblenden"
},
"ai": {
+ "statusAiRead": "Von KI gelesen",
"readDone": "Die KI hat dein Dokument gelesen.",
"read": "Mit KI auslesen",
"reread": "Erneut lesen",
diff --git a/messages/en.json b/messages/en.json
index 59a6a1d01..312ee4ee7 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -8355,6 +8355,7 @@
"close": "Hide"
},
"ai": {
+ "statusAiRead": "Read by AI",
"readDone": "The AI read your document.",
"read": "Read with AI",
"reread": "Read again",
diff --git a/messages/es.json b/messages/es.json
index e7f7fd84e..d0a4e9700 100644
--- a/messages/es.json
+++ b/messages/es.json
@@ -8355,6 +8355,7 @@
"close": "Ocultar"
},
"ai": {
+ "statusAiRead": "Leído por IA",
"readDone": "La IA leyó tu documento.",
"read": "Leer con IA",
"reread": "Leer de nuevo",
diff --git a/messages/fr.json b/messages/fr.json
index b1f04b4e3..4e444d565 100644
--- a/messages/fr.json
+++ b/messages/fr.json
@@ -8355,6 +8355,7 @@
"close": "Masquer"
},
"ai": {
+ "statusAiRead": "Lu par l’IA",
"readDone": "L’IA a lu votre document.",
"read": "Lire avec l’IA",
"reread": "Relire",
diff --git a/messages/it.json b/messages/it.json
index 9c62d4510..42b207b9c 100644
--- a/messages/it.json
+++ b/messages/it.json
@@ -8355,6 +8355,7 @@
"close": "Nascondi"
},
"ai": {
+ "statusAiRead": "Letto dall’IA",
"readDone": "L’IA ha letto il tuo documento.",
"read": "Leggi con l’IA",
"reread": "Leggi di nuovo",
diff --git a/messages/pl.json b/messages/pl.json
index 392590bd1..8122f13f0 100644
--- a/messages/pl.json
+++ b/messages/pl.json
@@ -8355,6 +8355,7 @@
"close": "Ukryj"
},
"ai": {
+ "statusAiRead": "Odczytane przez AI",
"readDone": "AI odczytało Twój dokument.",
"read": "Odczytaj z AI",
"reread": "Odczytaj ponownie",
diff --git a/src/components/documents/document-detail-sheet.tsx b/src/components/documents/document-detail-sheet.tsx
index aa34664d4..48c3409b6 100644
--- a/src/components/documents/document-detail-sheet.tsx
+++ b/src/components/documents/document-detail-sheet.tsx
@@ -62,6 +62,7 @@ import { invalidateKeys, queryKeys } from "@/lib/query-keys";
import { cn } from "@/lib/utils";
import {
INBOUND_DOCUMENT_KINDS,
+ isAiReadSource,
type DocumentSuggestionDto,
type DocumentSummaryMode,
type InboundDocumentDetailDto,
@@ -420,6 +421,12 @@ export function DocumentDetailSheet({
const title = doc?.title ?? doc?.filename ?? t("documents.card.untitled");
const Icon = doc ? DOCUMENT_KIND_ICONS[doc.kind] : null;
const originalHref = doc ? `/api/documents/inbound/${doc.id}/original` : "#";
+ // AI-read provenance — surfaced here (the detail view) as calm muted meta
+ // since v1.28.38 dropped the vault-card glyph. Same condition the AI section
+ // uses: a content index exists AND its source is a provider vision/text read.
+ const aiRead = doc
+ ? doc.hasContentIndex && isAiReadSource(doc.contentIndexSource)
+ : false;
return (
<>
@@ -752,6 +759,15 @@ export function DocumentDetailSheet({
})}
{doc.filename ? ` · ${doc.filename}` : ""}
+
+ {aiRead ? (
+
+ {t("documents.ai.statusAiRead")}
+
+ ) : null}
) : null}