You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
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
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.
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).
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.
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).
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.
The legacy v1 → v2 backfill on existing rows (lazy migration on next save is sufficient — same approach as backend).
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.
Background
There are two independent v1↔v2 compact-JSON formats in this codebase, with separate boundary modules:
Document.pawls_parse_file. Migrated end-to-end in Migrate codebase to v2 PAWLs as canonical format end-to-end #1488.Annotation.json. Backend is already v2 (Annotation.save()auto-compacts atopencontractserver/annotations/models.py:1145-1158; all readers use the format-agnosticiter_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:
frontend/src/components/annotator/types/annotations.tsServerTokenAnnotationconstructor callsexpandAnnotationJson— every incoming v2 is converted to v1 for the rendering layer.frontend/src/components/annotator/renderers/pdf/PDFPage.tsxannot.json[pageIndex].bounds(v1 shape).frontend/src/components/annotator/display/components/Selection.tsxannotation.json[pageNum - 1].boundsand.tokensJsons(v1 shape).frontend/src/components/annotator/renderers/pdf/PDF.tsxfor (const pageStr in annot.json)— iterates the v1 page-key dict.frontend/src/components/annotator/hooks/AnnotationHooks.tsxannotation.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 infrontend/src/utils/compactAnnotationJson.ts.Scope
ServerTokenAnnotation.jsonv2-canonical (CompactAnnotationJson). Stop callingexpandAnnotationJsonin the constructor; instead, normalize anything coming in (v1 from old fixtures, v2 from backend) to v2 viacompactAnnotationJsononce at the boundary.iterPageAnnotations(the existing format-agnostic accessor) for reads, or to read v2 shape directly (json.p[pageIndex].b, range-decodedt).Annotation.save()already accepts both v1 and v2 — but the frontend should send v2 for consistency.expandAnnotationJson, the v1 type aliases (MultipageAnnotationJson,SinglePageAnnotationJson), and v1 fixture shapes in tests. KeepcompactAnnotationJson(still needed at boundary for any v1 input still received from older fixtures).frontend/src/utils/__tests__/compactAnnotationJson.test.tsand any consumer tests to assert v2-in/v2-out. Component tests forSelection,PDFPage,PDFshould mount with v2 fixtures.Acceptance Criteria
ServerTokenAnnotation.jsonis typedCompactAnnotationJson(v2).annot.json[pageIndex].boundsorannot.json[pageIndex].tokensJsonsshape.expandAnnotationJsonandMultipageAnnotationJson/SinglePageAnnotationJsonare deleted fromfrontend/src/utils/compactAnnotationJson.tsandfrontend/src/components/types.ts.REQUEST_ADD_ANNOTATION/REQUEST_UPDATE_ANNOTATIONpayloads send v2 shape.Out of Scope
Annotation.jsonstorage (already v2).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.