Skip to content

Drop v1 annotation JSON support on frontend; consume v2 directly #1491

@JSv4

Description

@JSv4

Background

There are two independent v1↔v2 compact-JSON formats in this codebase, with separate boundary modules:

  1. PAWLs (doc-level token positions)Document.pawls_parse_file. Migrated end-to-end in Migrate codebase to v2 PAWLs as canonical format end-to-end #1488.
  2. Annotation JSON (per-annotation token refs + page bounds)Annotation.json. Backend is already v2 (Annotation.save() auto-compacts at opencontractserver/annotations/models.py:1145-1158; all readers use the format-agnostic iter_page_annotations). Frontend is still v1-internal, even though the wire it receives from the backend is v2.

This issue tracks dropping v1 from the frontend so the on-the-wire and in-memory shapes are both v2.

Current State (Frontend)

The frontend rehydrates incoming v2 back to v1 on construction, so every consumer downstream reads v1:

File Line What it does today
frontend/src/components/annotator/types/annotations.ts 150-160 ServerTokenAnnotation constructor calls expandAnnotationJson — every incoming v2 is converted to v1 for the rendering layer.
frontend/src/components/annotator/renderers/pdf/PDFPage.tsx 370, 496 Reads annot.json[pageIndex].bounds (v1 shape).
frontend/src/components/annotator/display/components/Selection.tsx 210, 397, 404 Reads annotation.json[pageNum - 1].bounds and .tokensJsons (v1 shape).
frontend/src/components/annotator/renderers/pdf/PDF.tsx 193-195 for (const pageStr in annot.json) — iterates the v1 page-key dict.
frontend/src/components/annotator/hooks/AnnotationHooks.tsx 250, 348 Sends annotation.json (currently v1) to the backend on create/update. (Harmless — backend auto-compacts — but reinforces v1 internally.)

The v1 shape (MultipageAnnotationJson) and the v2 shape (CompactAnnotationJson) both live in frontend/src/utils/compactAnnotationJson.ts.

Scope

  1. Make ServerTokenAnnotation.json v2-canonical (CompactAnnotationJson). Stop calling expandAnnotationJson in the constructor; instead, normalize anything coming in (v1 from old fixtures, v2 from backend) to v2 via compactAnnotationJson once at the boundary.
  2. Refactor the 5 consumers above to use iterPageAnnotations (the existing format-agnostic accessor) for reads, or to read v2 shape directly (json.p[pageIndex].b, range-decoded t).
  3. Annotation mutations send v2 to backend. No backend change needed — Annotation.save() already accepts both v1 and v2 — but the frontend should send v2 for consistency.
  4. Delete v1-only code paths: remove expandAnnotationJson, the v1 type aliases (MultipageAnnotationJson, SinglePageAnnotationJson), and v1 fixture shapes in tests. Keep compactAnnotationJson (still needed at boundary for any v1 input still received from older fixtures).
  5. Tests: update frontend/src/utils/__tests__/compactAnnotationJson.test.ts and any consumer tests to assert v2-in/v2-out. Component tests for Selection, PDFPage, PDF should mount with v2 fixtures.

Acceptance Criteria

  • ServerTokenAnnotation.json is typed CompactAnnotationJson (v2).
  • No frontend call site reads annot.json[pageIndex].bounds or annot.json[pageIndex].tokensJsons shape.
  • expandAnnotationJson and MultipageAnnotationJson / SinglePageAnnotationJson are deleted from frontend/src/utils/compactAnnotationJson.ts and frontend/src/components/types.ts.
  • REQUEST_ADD_ANNOTATION / REQUEST_UPDATE_ANNOTATION payloads send v2 shape.
  • Existing component tests pass; updated where the v1 → v2 shape change is observable.

Out of Scope

Context

Surfaced when reviewing #1488. This is a follow-on migration of analogous shape (the annotation JSON sibling of PAWLs) — same boundary-layer pattern, different format, separate scope.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions