PR: #644: feat(documents): cut readers over to extraction views [Story-2488] by @pramaan-board-bot[bot]
View PR →

Story-2488: Text and Original now read Extraction Record views

The app no longer asks the legacy page-block endpoint to serve either document-reading lens. Text reads the Text view; shared paragraph anchors and Original geometry read the Anchor view. There is no dual read or fallback.

The request chain

Surface Generated client Browser proxy Upstream
Text lens useAppGetDocumentTextView /api/internal/documents/:id/views/text /app/documents/:id/views/text
Original geometry and paragraph anchors useAppGetDocumentAnchorView /api/internal/documents/:id/views/anchors /app/documents/:id/views/anchors

Both server gateway methods fetch unknown JSON and validate it with generated schemas before the browser receives it. The existing document-wide toBrowserRoute mapping covers both new paths.

Why Text uses both projections

Text View is the full current text projection. Anchor View carries the block boundaries, bounding boxes, confidence, character offsets, and opaque anchorId values needed to preserve the structured reading surface. The app combines them only when document id, extraction version, page count, exact ordered block bytes, and anchor uniqueness agree. Rendered row text is sliced from Text View; Anchor View supplies only structure and metadata. A mismatch shows the existing load error and never falls back to the old endpoint.

Matter-16 render oracle

Deep links stay PDF-authoritative

?page=N still scrolls and clamps against PDFJS page count. Anchor View supplies only the overlay geometry on the landed page, so a sparse extraction cannot incorrectly shorten the Original.

Local proof: generated Text/Anchor clients exist; focused gateway, adapter, routing, and viewer tests pass; TypeScript passes; the updated Machine Copy Storybook catalog builds successfully. Full lint/test/build and diff gates are recorded in the PR checks.
Runtime proof: the signed-in staging matter-16 click-through runs after this SHA deploys. CI and Storybook prove the contract and component boundary; they do not claim deployed UAT.

Files changed

60 file(s), +3918 / -70 lines

Path Role + -
openapi/app-api.jsonConfig+594-0
openapi/permission-map.jsonConfig+27-0
src/app/[locale]/(workspace)/matters/[matterId]/record/doc/[documentId]/layout.tsxApp route+15-9
src/app/[locale]/(workspace)/matters/[matterId]/record/doc/[documentId]/text/page.tsxApp route+18-3
src/app/api/internal/documents/[docId]/views/anchors/route.tsApp route+7-0
src/app/api/internal/documents/[docId]/views/text/route.tsApp route+7-0
src/components/documents/viewer/document-machine-copy-view.stories.tsxComponent+128-0
src/components/documents/viewer/document-machine-copy-view.tsxComponent+26-9
src/components/documents/viewer/document-machine-copy.stories.tsxComponent+25-14
src/components/documents/viewer/document-machine-copy.tsxComponent+7-2
src/components/documents/viewer/machine-copy-presentation.test.tsComponent+27-0
src/components/documents/viewer/machine-copy-presentation.tsComponent+18-4
src/components/documents/viewer/section-fixtures.tsComponent+51-17
src/components/documents/viewer/use-document-gutters.tsComponent+17-9
src/gen/client/appGetDocumentAnchorView.tsGenerated contract+63-0
src/gen/client/appGetDocumentModelView.tsGenerated contract+66-0
src/gen/client/appGetDocumentTextView.tsGenerated contract+63-0
src/gen/client/index.tsGenerated contract+3-0
src/gen/hooks/index.tsGenerated contract+24-0
src/gen/hooks/useAppGetDocumentAnchorView.tsGenerated contract+127-0
src/gen/hooks/useAppGetDocumentAnchorViewSuspense.tsGenerated contract+126-0
src/gen/hooks/useAppGetDocumentModelView.tsGenerated contract+133-0
src/gen/hooks/useAppGetDocumentModelViewSuspense.tsGenerated contract+136-0
src/gen/hooks/useAppGetDocumentTextView.tsGenerated contract+127-0
src/gen/hooks/useAppGetDocumentTextViewSuspense.tsGenerated contract+125-0
src/gen/index.tsGenerated contract+117-0
src/gen/schemas/anchorBlockView.jsonGenerated contract+90-0
src/gen/schemas/anchorBoundingBoxView.jsonGenerated contract+37-0
src/gen/schemas/anchorPageView.jsonGenerated contract+110-0
src/gen/schemas/anchorViewResponse.jsonGenerated contract+136-0
src/gen/schemas/modelViewBudgetProfile.jsonGenerated contract+7-0
src/gen/schemas/modelViewResponse.jsonGenerated contract+45-0
src/gen/schemas/textViewResponse.jsonGenerated contract+32-0
src/gen/types/AnchorBlockView.tsGenerated contract+55-0
src/gen/types/AnchorBoundingBoxView.tsGenerated contract+40-0
src/gen/types/AnchorPageView.tsGenerated contract+25-0
src/gen/types/AnchorViewResponse.tsGenerated contract+29-0
src/gen/types/AppGetDocumentAnchorView.tsGenerated contract+75-0
src/gen/types/AppGetDocumentModelView.tsGenerated contract+80-0
src/gen/types/AppGetDocumentTextView.tsGenerated contract+69-0
src/gen/types/ModelViewBudgetProfile.tsGenerated contract+13-0
src/gen/types/ModelViewResponse.tsGenerated contract+39-0
src/gen/types/TextViewResponse.tsGenerated contract+33-0
src/gen/types/index.tsGenerated contract+48-0
src/gen/zod/anchorBlockViewSchema.tsGenerated contract+46-0
src/gen/zod/anchorBoundingBoxViewSchema.tsGenerated contract+38-0
src/gen/zod/anchorPageViewSchema.tsGenerated contract+29-0
src/gen/zod/anchorViewResponseSchema.tsGenerated contract+32-0
src/gen/zod/appGetDocumentAnchorViewSchema.tsGenerated contract+96-0
src/gen/zod/appGetDocumentModelViewSchema.tsGenerated contract+100-0
src/gen/zod/appGetDocumentTextViewSchema.tsGenerated contract+88-0
src/gen/zod/index.tsGenerated contract+42-0
src/gen/zod/modelViewBudgetProfileSchema.tsGenerated contract+17-0
src/gen/zod/modelViewResponseSchema.tsGenerated contract+34-0
src/gen/zod/textViewResponseSchema.tsGenerated contract+29-0
src/lib/documents/gateway-views.test.tsLibrary+76-0
src/lib/documents/gateway.tsLibrary+50-3
src/lib/documents/view-adapter.test.tsLibrary+95-0
src/lib/documents/view-adapter.tsLibrary+79-0
tests/unit/lib/kubb-client.test.tsTest+27-0

Observability

The two HTTP routes reuse the existing instrumented document proxy/gateway boundary (automatic HTTP tracing). The view adapter is a pure in-process helper and is instrumentation-exempt under pramaan-docs ADR-124.