- INTENT.md: declare umbrella as the home for shared contracts; document umbrella-first MVP decision (code lives here until subsystems stabilize) - wiki/SharedContracts.md: vocabulary, state enums, relation types, selector taxonomy, event vocabulary, viewer adapter contract, canonical text normalization, rect-registry contract - wiki/DependencyMap.md: allowed dependency edges; folder layout + lint-rule strategy during umbrella-first phase - history/2026-05-24-initial-assessment.md: alignment review, technical risks, and the umbrella-first pivot rationale - workplans/CE-WP-0001..0004: four ralph-compatible workplans covering foundations, PDF review slice, form binding + visual guide, and citation card export — implementing PRD §20 end-to-end Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
8.8 KiB
id, type, title, domain, repo, repo_id, status, owner, created, updated, depends_on_workplan, spec_refs
| id | type | title | domain | repo | repo_id | status | owner | created | updated | depends_on_workplan | spec_refs | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CE-WP-0002 | workplan | PDF review slice — engine types, anchor, source, viewer, sidebar, click-to-reopen | citation_evidence | citation-evidence | a677c189-b4e2-4f2a-9e48-faa482c277e6 | todo | Bernd | 2026-05-24 | 2026-05-24 | CE-WP-0001 |
|
CE-WP-0002 — PDF Review Slice
The first vertical product slice. After this workplan, a user can:
- Open the app, see a collection of fixture PDFs.
- Open one PDF in a viewer.
- Select text, add a one-line comment, save as an evidence item.
- See the evidence item appear in a sidebar.
- Click the evidence item and have the PDF jump to and highlight the passage — even after a full page reload.
No forms, no Markdown/HTML, no recovery, no export. Those come later.
This workplan exercises the riskiest architectural assumption (PDF selector round-trip with viewer independence) on the simplest possible feature set.
Risk-driven order
T01 and T02 are the spike from the assessment: prove the
react-pdf-highlighter-plus integration can store and reload selectors
without leaking viewer types into engine code. If that breaks, the rest of
the workplan stops and a new ADR is required for ADR-0004 (PDF viewer choice).
Dependency Order
T01 (engine types: Document, Representation, Annotation, Selector, EvidenceItem)
└─ T02 (PDF viewer adapter spike — store + reload selectors as JSON)
└─ T03 (evidence-source: PDF ingest, fingerprint, canonical text)
└─ T04 (evidence-anchor: TextQuote + TextPosition resolution against representation)
└─ T05 (in-memory repositories + engine services)
└─ T06 (citation-work UI: collection list + viewer shell + sidebar)
└─ T07 (annotation create flow)
└─ T08 (click-to-reopen flow)
└─ T09 (end-to-end test of PRD scenario steps 1-4)
T01 — Engine types in src/shared/
id: CE-WP-0002-T01
priority: critical
status: todo
Translate the type definitions in wiki/SharedContracts.md §1 and §3 into
TypeScript under src/shared/:
src/shared/document.ts—Document,DocumentRepresentation,PageMap,OffsetMapsrc/shared/selector.ts—Selectordiscriminated union with at minimumTextQuoteSelector,TextPositionSelector,PdfRectSelector,PdfPageTextSelector. Other selector kinds defined asnever-typed stubs for now.src/shared/annotation.ts—Annotationwithselectors,quote,note,normalizeVersionsrc/shared/evidence.ts—EvidenceItem,EvidenceItem.statusenum per §2.2src/shared/ids.ts— branded ID types and anewId(prefix)helper
No services, no behavior. Pure data shapes + the ID helper.
Add JSDoc on each type pointing at the §-reference in
wiki/SharedContracts.md it implements.
T02 — PDF viewer adapter spike
id: CE-WP-0002-T02
priority: critical
status: todo
depends_on: [T01]
This is the architectural spike. Build a throwaway
src/anchor/pdf-viewer-adapter-spike.tsx that:
- Loads
fixtures/pdfs/simple.pdfusingreact-pdf-highlighter-plus(assumed; if a better library appears, document it in ADR-0004 before committing). - Lets the user select text and produces selectors per
T01shapes. - Serializes the selectors to a JSON blob in
localStorage. - On reload, reads the blob, asks the adapter to resolve, scrolls to the passage, and renders a highlight.
Success criteria:
- Reload-and-resolve works for all fixture PDFs.
- No PDF.js or
react-pdf-highlighter-plustypes appear in any file undersrc/shared/orsrc/engine/. - The adapter's public surface matches the contract in
wiki/SharedContracts.md§5.
If success criteria fail: stop. Write a short note in
docs/decisions/ADR-0004-pdf-viewer-library.md describing the failure mode
and proposed alternative. Do not proceed with T03+.
T03 — src/source/: PDF ingest, fingerprint, canonical text
id: CE-WP-0002-T03
priority: high
status: todo
depends_on: [T02]
Implement under src/source/pdf/:
ingest.ts—ingestPdf(file: File | Buffer): Promise<{ document: Document; representation: DocumentRepresentation }>fingerprint.ts— stable SHA-256 of bytesextract.ts— uses PDF.js to extract page text; runsnormalize()from T04 of WP-0001 over the canonical text; builds thePageMapandOffsetMapperDocument.DocumentRepresentation
Tests use the fixture corpus from CE-WP-0001-T05. For each fixture,
extracted canonical text must contain the manifest's known-good quote.
T04 — src/anchor/: TextQuote and TextPosition resolution
id: CE-WP-0002-T04
priority: high
status: todo
depends_on: [T01, T03]
Implement under src/anchor/:
selectors/create.ts— given aSelectionCapturefrom the adapter, build the maximal set of available selectors (alwaysTextQuoteSelectorwith prefix/suffix;TextPositionSelectorwhen the representation provides offsets; PDF rect/text selectors when on PDF)selectors/resolve.ts— implements the resolution strategy fromwiki/ArchitectureOverview.md§7 (try position, verify quote, fall back through quote+prefix/suffix, returnAnchorResolution)selectors/types.ts—AnchorResolution,SelectionCapture,ResolvedAnchorTarget
Fuzzy matching is out of scope here — return unresolved if exact+prefix/suffix
fails. Fuzzy is a later workplan.
Unit tests using fixtures: for each fixture+known-quote pair, create selectors then immediately resolve them; resolution must succeed with confidence ≥ 0.9.
T05 — In-memory repositories + engine services
id: CE-WP-0002-T05
priority: high
status: todo
depends_on: [T01]
Under src/engine/:
repos/in-memory.ts—Map-backed implementations ofDocumentRepository,AnnotationRepository,EvidenceItemRepositoryservices/documents.ts,services/annotations.ts,services/evidence.ts— thin orchestration layer that creates IDs, calls repos, and emits the events fromwiki/SharedContracts.md§4events/bus.ts— minimal pub/sub. Synchronous for MVP.
No persistence to disk yet. ADR-0005 (persistence) is still pending.
T06 — src/work/: collection list + viewer shell + sidebar
id: CE-WP-0002-T06
priority: high
status: todo
depends_on: [T02, T05]
Under src/work/ and src/app/:
src/app/App.tsx— three-pane layout per Architecture §12.1: collection list (left), viewer (centre), evidence sidebar (right)src/work/CollectionList.tsx— listsfixtures/pdfs/manifest.jsonentries; click to loadsrc/work/ViewerShell.tsx— hosts the viewer adapter from T02 wrapped cleanly; viewer adapter API is the only surfacework/usessrc/work/EvidenceSidebar.tsx— lists evidence items for the current document, shows quote + commentary + status
No styling beyond minimum legibility. CSS in Tailwind or vanilla — pick one, note in ADR-0001 if it wasn't already.
T07 — Annotation create flow
id: CE-WP-0002-T07
priority: high
status: todo
depends_on: [T04, T05, T06]
Wire selection → annotation → evidence item:
- User selects text in the viewer.
- A small toolbar appears with a comment input + Save button.
- On Save: adapter produces
SelectionCapture→ anchor createsSelector[]→ engine createsAnnotation→ engine createsEvidenceItemwith the commentary → sidebar updates.
Active state lives in a single React context for now; no Redux/Zustand.
T08 — Click-to-reopen flow
id: CE-WP-0002-T08
priority: critical
status: todo
depends_on: [T04, T06, T07]
Implement the round trip:
- User clicks an evidence item in the sidebar.
- Engine loads the annotation → anchor resolves selectors against the current representation → adapter scrolls to and highlights the target.
Critically, this must also work after a page reload. Persistence to
localStorage is acceptable for MVP (decide explicitly in
ADR-0005-persistence.md that we are deferring real persistence).
T09 — End-to-end test of PRD scenario steps 1-4
id: CE-WP-0002-T09
priority: high
status: todo
depends_on: [T07, T08]
Write a Playwright (or similar) E2E test that:
- Opens the app.
- Picks
simple.pdf. - Programmatically selects the known-good quote from the manifest.
- Saves an evidence item with a comment.
- Verifies the item appears in the sidebar.
- Reloads the page.
- Clicks the evidence item.
- Verifies the highlight is rendered on the expected page.
This is the contract for "MVP slice 1 works". If it passes, CE-WP-0003 may begin.