74 file(s), +5415 / -52 lines
| Path | Role | + | - |
|---|---|---|---|
| messages/en.json | Config | +71 | -2 |
| messages/hi.json | Config | +71 | -2 |
| openapi/app-api.json | Config | +381 | -0 |
| openapi/permission-map.json | Config | +51 | -0 |
| src/app/[locale]/(workspace)/matters/[matterId]/record/doc/[documentId]/insights/page.tsx | App route | +49 | -0 |
| src/app/[locale]/(workspace)/matters/[matterId]/record/doc/[documentId]/layout.tsx | App route | +9 | -0 |
| src/app/api/internal/documents/[docId]/annotations/[annotationId]/dismiss/route.ts | App route | +4 | -0 |
| src/app/api/internal/documents/[docId]/annotations/[annotationId]/keep/route.ts | App route | +4 | -0 |
| src/app/api/internal/documents/[docId]/annotations/route.ts | App route | +84 | -0 |
| src/app/api/internal/documents/[docId]/insight-brief/route.ts | App route | +5 | -0 |
| src/app/api/internal/matters/[matterId]/documents/[docId]/declared-side/route.ts | App route | +11 | -0 |
| src/app/api/internal/matters/[matterId]/documents/[docId]/home/route.ts | App route | +11 | -0 |
| src/components/documents/viewer/annotations-presentation.ts | Component | +120 | -0 |
| src/components/documents/viewer/details-presentation.ts | Component | +59 | -0 |
| src/components/documents/viewer/document-counsel-bar.stories.tsx | Component | +22 | -0 |
| src/components/documents/viewer/document-counsel-bar.tsx | Component | +96 | -0 |
| src/components/documents/viewer/document-details-sheet.stories.tsx | Component | +51 | -0 |
| src/components/documents/viewer/document-details-sheet.tsx | Component | +161 | -0 |
| src/components/documents/viewer/document-gutter-mark.tsx | Component | +60 | -0 |
| src/components/documents/viewer/document-insights-live.tsx | Component | +36 | -0 |
| src/components/documents/viewer/document-insights-view.stories.tsx | Component | +36 | -0 |
| src/components/documents/viewer/document-insights-view.tsx | Component | +174 | -0 |
| src/components/documents/viewer/document-original-pane.tsx | Component | +72 | -19 |
| src/components/documents/viewer/document-pdf-canvas.tsx | Component | +8 | -1 |
| src/components/documents/viewer/document-permalink-shell.stories.tsx | Component | +30 | -2 |
| src/components/documents/viewer/document-permalink-shell.tsx | Component | +77 | -23 |
| src/components/documents/viewer/document-reading-surface.tsx | Component | +152 | -0 |
| src/components/documents/viewer/document-reclassify-dialog.stories.tsx | Component | +36 | -0 |
| src/components/documents/viewer/document-reclassify-dialog.tsx | Component | +136 | -0 |
| src/components/documents/viewer/document-viewer-header.tsx | Component | +7 | -1 |
| src/components/documents/viewer/insights-fixtures.ts | Component | +147 | -0 |
| src/components/documents/viewer/insights-presentation.ts | Component | +97 | -0 |
| src/components/documents/viewer/insights-types.ts | Component | +51 | -0 |
| src/components/documents/viewer/use-document-annotations.ts | Component | +190 | -0 |
| src/components/documents/viewer/use-document-reclassify.ts | Component | +57 | -0 |
| src/gen/client/appGetDocumentInsightBrief.ts | Generated contract | +67 | -0 |
| src/gen/client/index.ts | Generated contract | +1 | -0 |
| src/gen/hooks/index.ts | Generated contract | +8 | -0 |
| src/gen/hooks/useAppGetDocumentInsightBrief.ts | Generated contract | +131 | -0 |
| src/gen/hooks/useAppGetDocumentInsightBriefSuspense.ts | Generated contract | +134 | -0 |
| src/gen/index.ts | Generated contract | +48 | -0 |
| src/gen/schemas/authorityCited.json | Generated contract | +111 | -0 |
| src/gen/schemas/builtFrom.json | Generated contract | +19 | -0 |
| src/gen/schemas/documentInsightBrief.json | Generated contract | +642 | -0 |
| src/gen/schemas/enrichmentStamp.json | Generated contract | +36 | -0 |
| src/gen/schemas/insightPin.json | Generated contract | +96 | -0 |
| src/gen/schemas/positionAdmission.json | Generated contract | +111 | -0 |
| src/gen/schemas/punchCard.json | Generated contract | +217 | -0 |
| src/gen/schemas/silence.json | Generated contract | +111 | -0 |
| src/gen/types/AppGetDocumentInsightBrief.ts | Generated contract | +70 | -0 |
| src/gen/types/AuthorityCited.ts | Generated contract | +24 | -0 |
| src/gen/types/BuiltFrom.ts | Generated contract | +18 | -0 |
| src/gen/types/DocumentInsightBrief.ts | Generated contract | +68 | -0 |
| src/gen/types/EnrichmentStamp.ts | Generated contract | +31 | -0 |
| src/gen/types/InsightPin.ts | Generated contract | +30 | -0 |
| src/gen/types/PositionAdmission.ts | Generated contract | +24 | -0 |
| src/gen/types/PunchCard.ts | Generated contract | +34 | -0 |
| src/gen/types/Silence.ts | Generated contract | +24 | -0 |
| src/gen/types/index.ts | Generated contract | +20 | -0 |
| src/gen/zod/appGetDocumentInsightBriefSchema.ts | Generated contract | +88 | -0 |
| src/gen/zod/authorityCitedSchema.ts | Generated contract | +29 | -0 |
| src/gen/zod/builtFromSchema.ts | Generated contract | +22 | -0 |
| src/gen/zod/documentInsightBriefSchema.ts | Generated contract | +90 | -0 |
| src/gen/zod/enrichmentStampSchema.ts | Generated contract | +27 | -0 |
| src/gen/zod/index.ts | Generated contract | +19 | -0 |
| src/gen/zod/insightPinSchema.ts | Generated contract | +36 | -0 |
| src/gen/zod/positionAdmissionSchema.ts | Generated contract | +27 | -0 |
| src/gen/zod/punchCardSchema.ts | Generated contract | +42 | -0 |
| src/gen/zod/silenceSchema.ts | Generated contract | +27 | -0 |
| src/lib/documents/annotation-resolve-helper.ts | Library | +55 | -0 |
| src/lib/documents/gateway.ts | Library | +144 | -0 |
| src/lib/documents/reclassify-route-helper.ts | Library | +84 | -0 |
| src/lib/kubb-client.ts | Library | +12 | -0 |
| src/lib/surface-registry/route-registry.ts | Library | +12 | -2 |
Every uploaded document becomes a conversation. This story ships the
Document Page per the Claude Design contract (cd-document-view-v2.dc.html)
and the desk RFD: a route-per-mode page whose Original view
is untouched paper you talk to (select → Counsel Control Bar → note, wired
live to the span-anchored notes substrate), whose
Insights view is "a briefing, not a brief" (THE READ +
accordions), and whose header carries the document's identity + a Details
card + Reclassify. Text is demoted to a machine-copy utility link.
The brief assumed the Original anchored notes to an existing
document_pages blocks read path with normalized bbox. That
path does not exist — the Text route reads one derived/text.txt
blob (no blocks, no bbox, no char/page map; CE-17 unmirrored), and the live
PDF rendered its text layer off. Founder ratified the honest path:
turn the pdfjs text layer on, anchor each note by
quote (byte-exact V-CITE) + pageNumber
(blockIndex = null = whole page), render page-level
gutter marks v1, and design the overlay/gutter/margin components to
upgrade to per-¶ when the blocks/bbox endpoint lands (an
optional blocks prop; absent = page-level). The blocks read-path
story is filed separately on pramaan-functions.
| CD state | Shipped |
|---|---|
| 4a/4b Header identity strip | Live header (serif title, type/side/REGISTERED chips, uploaded·size meta, Download · Copy permalink · Details). |
| 4d Details card | DocumentDetailsSheet — right-edge sheet: classification (type/side/home/tags), provenance (original file/uploaded), integrity (sha256 + copy, size, duplicate-of, legal hold, status). Real DTO data; missing field → "—". |
| 4e Reclassify | DocumentReclassifyDialog — two-question (whose · where), wired live to the new PATCH home / declared-side proxies; on save re-reads (router refresh). |
| 1a Original at rest | Clean paper — pdfjs canvas, left gutter lane, right margin. Nothing boxed at rest. |
| 1b Paragraph hover / selection | Text selection raises the DocumentCounselBar (Explain · What-this-means dimmed "wired next"; Note · Copy ¶-link live). No "Cite". |
| 1c/2b Margin notes + composing | Select → Note → inline composer in the margin; posts to the live annotations API. Card appears + page gets a gutter ● the instant you commit (optimistic). |
| 1a gutter ● index | DocumentGutterMark — page-level ● note mark with count (◐ insight / ⚠ contradiction kinds ready for when those land). |
| 3a Insights — THE READ | DocumentInsightsView — headline + punch cards (one quiet pin each) + accordions (facts/positions/authorities/silences/notes), closed by default, freshness stamp. |
| 3a Honest pending | The live Insights route renders the honest pending state — "Read pending, this document hasn't been read against the matter yet" — because Station 4 has not processed these docs. Never fabricated. |
| 1f Pin-click landing | A punch-card / accordion pin deep-links to Original ?page=N; the pane seeds that page on arrival. |
| Tabs | Original | Insights are sibling routes (route-per-mode); Text is a machine-copy utility link. pdfjs loads only on Original. |
GET/POST /api/internal/documents/[docId]/annotations + [annotationId]/keep|dismiss and the gateway methods (listAnnotations, createAnnotation, resolveAnnotation), HR-21 parsed at the boundary.useDocumentAnnotations — list (author resolved against the firm roster: real photo + name), useAppCreateDocumentAnnotation with onMutate prepend + rollback + onSettled invalidate. Posted note is instant.PATCH /api/internal/matters/[matterId]/documents/[docId]/{home,declared-side} + gateway setHome/setDeclaredSide + toBrowserRoute rules, mirroring the privilege proxy.matter.record.doc.insights agentSurface + pnpm gen:routes (40 surfaces). Presence key in both locales.Documents/Viewer/Insights → Pending — the live honest state.Documents/Viewer/Insights → FullRead — THE READ + punch cards + accordions (Order_S.17 fixture).Documents/Viewer/CounselBar → Default — the CCB verbs.Documents/Viewer/DetailsSheet → Default — the identity card.Documents/Viewer/Reclassify → Default — the two-question dialog.Documents/Viewer/DocumentPermalinkShell → OriginalActive · InsightsActive · TextActive — the tab chrome per route.pnpm typecheck — clean.pnpm lint — clean (changed files).pnpm test — 168 files / 1035 tests green.pnpm build — green; all six new routes compiled (insights page; annotations + keep/dismiss; home; declared-side).en + hi.
Live-data seams (honest, reported on the issue):
(1) Insights content — no read/facts-derived
endpoint exists (Station 4). The route renders the pending state; the full
layout is fixture-driven in Storybook and lights up when the read-brief
endpoint lands. (2) Per-¶ fidelity — the gutter/margin are
page-level until the document_pages blocks (text + bbox + kind per page)
read path ships; the components take an optional blocks prop to
upgrade with zero call-site changes. (3) Explain / What-this-means
route to the matter agent — present but dimmed ("wired next") pending the
Wave B app sender. The on-staging check is a real note on the Order_S.17 doc
(3ee1dc28, matter 13): select → Note → it persists and reloads, and the page
gets a gutter ●.