Move pdf-viewer-adapter-spike.tsx, scroll-job.ts (+test), highlight-styles.css and debug-textlayer.css into src/pdf/ (the adapter boundary). Rewrite the spike's @shared import to @citation-evidence/engine/shared and its ./types to ../types. Add src/css.d.ts so tsc accepts side-effect .css imports. Decisions: - adapter stays the explicitly-named PdfSpikeViewer spike; promotion to a production PDFViewerAdapter is registered as T06 follow-on work - viewer libs (pdfjs-dist, react, react-pdf-highlighter-plus) confined to src/pdf/ and exposed only via the evidence-anchor/pdf subpath; the root entrypoint stays pure. Boundary enforced by eslint no-restricted-imports. - ported unit suites (pdf-selector-math round-trip + scroll-job retry) serve as the inspectable harness for capture->selectors->resolve->scroll. Verified: pnpm test (30 passed), typecheck, lint all green. README layout updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.1 KiB
evidence-anchor
Selector creation, resolution, and the DocumentViewerAdapter contract that
every document viewer in the citation-evidence workspace implements. This repo
turns annotations from static marks into durable, reopenable source references.
- Owns: selector behavior —
createSelectors,resolveSelectors, PDF selector math, the viewer-adapter contract, and highlight/scroll helpers. - Does not own: selector type interfaces — those live in
citation-engine(shared/selector). SeeADR-0006andSharedContracts.md§8. - May depend on:
citation-engineonly (DependencyMap §4). Nothing frombinder/,source/, orwork/may flow back into it.
See SCOPE.md for the boundary and INTENT.md for the long-range intent.
Status: extracting from the umbrella
The concrete anchor slice currently lives upstream in
../citation-evidence/src/anchor/. Workplan
EANCH-WP-0001 moves it here as a standalone TypeScript package, wires the
umbrella to consume this package, and verifies the round-trip. Shared-contract
changes still happen in the umbrella (citation-evidence/wiki/), not here.
Install model
Sibling-checkout, linked-package model — this repo is checked out next to its
consumers and consumed via a local link (e.g. link:../evidence-anchor), not
published to a registry during MVP. Its only shared-type dependency is
citation-engine, imported through the engine's public shared entrypoint
(@citation-evidence/engine/shared) rather than umbrella-only @shared/*
aliases.
Package layout (initial extracted version)
src/
index.ts public entrypoint — pure surface only
types.ts adapter-side types: SelectionCapture,
ResolvedAnchorTarget, AnchorResolution,
HighlightRenderOptions, DocumentViewerAdapter
css.d.ts ambient decl for side-effect .css imports
selectors/ pure core — no viewer/UI deps
index.ts createSelectors, resolveSelectors, DEFAULT_CONTEXT_CHARS
create.ts selector creation from a captured selection
resolve.ts resolution + the exact-match confidence ladder
create.test.ts
resolve.test.ts
pdf/ adapter boundary — the only place viewer libs live
index.ts subpath entry `evidence-anchor/pdf`
pdf-selector-math.ts pure page + normalized-rect math (capture↔selectors)
pdf-selector-math.test.ts
pdf-viewer-adapter-spike.tsx concrete PDF adapter (PdfSpikeViewer)
scroll-job.ts retryable scroll-to-highlight helper
scroll-job.test.ts
highlight-styles.css highlight rendering styles
debug-textlayer.css optional text-layer debugging styles
Boundary rules for the layout (enforced by eslint.config.js):
- viewer-library imports (
pdfjs-dist,react,react-pdf-highlighter-plus) are confined tosrc/pdf/— the pure zone (src/selectors/**,src/types.ts) may not import them; src/selectors/is pure and depends only oncitation-engineshared types;- the root entrypoint (
evidence-anchor) exposes only the pure surface —createSelectors,resolveSelectors, the selector/resolution types, and theDocumentViewerAdaptercontract; - the concrete PDF adapter is reached through the
evidence-anchor/pdfsubpath, so pure consumers never pull PDF.js or React into their bundle. That adapter is still the explicitly-namedPdfSpikeViewerspike; promoting it to a productionPDFViewerAdapteris registered follow-on work (T06).
Public API (target surface)
import {
createSelectors,
resolveSelectors,
type DocumentViewerAdapter,
type AnchorResolution,
} from "evidence-anchor";
Resolution is explicit about uncertainty — AnchorResolution.status is one of
resolved / ambiguous / unresolved / stale with a 0..1 confidence, so a
caller can highlight, ask the user to confirm, or mark a citation stale rather
than silently highlight the wrong passage.