# 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`). See `ADR-0006` and `SharedContracts.md` §8. - **May depend on:** `citation-engine` only (DependencyMap §4). Nothing from `binder/`, `source/`, or `work/` may flow back into it. See `SCOPE.md` for the boundary and `INTENT.md` for the long-range intent. ## Status: extracted; umbrella consumes this package The anchor slice has been extracted from the umbrella and now lives here. `citation-evidence` consumes it as `@citation-evidence/evidence-anchor` (`link:../evidence-anchor`); its former `src/anchor/` directory is gone and the `@anchor` alias is retired. Shared-contract changes still happen in the umbrella (`citation-evidence/wiki/`), not here. EANCH-WP-0002 and EANCH-WP-0003 delivered stale/orphan/fuzzy resolution, `PdfViewerAdapter`, and HTML/Markdown selectors plus `evidence-anchor/dom`. Remaining work (FragmentSelector, umbrella viewer wiring) is tracked in `workplans/`. ## 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) ```text src/ index.ts public entrypoint — full barrel (core + pdf) 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, fuzzy, orphan helpers create.ts selector creation (PDF + DOM branches) resolve.ts resolution ladder + stale/fuzzy recovery fuzzy.ts / orphan.ts / dom-path.ts *.test.ts pdf/ PDF adapter boundary index.ts subpath entry `evidence-anchor/pdf` pdf-viewer-adapter-spike.tsx PdfViewerAdapter (+ PdfSpikeViewer alias) pdf-selector-math.ts / scroll-job.ts / *.css dom/ HTML/Markdown adapter boundary index.ts subpath entry `evidence-anchor/dom` html-viewer-adapter.tsx HtmlViewerAdapter dom-path.ts Range ↔ DomNodePath serialization ``` Boundary rules for the layout (enforced by `eslint.config.js`): - viewer-library imports (`pdfjs-dist`, `react`, `react-pdf-highlighter-plus`) are confined to `src/pdf/` — the pure zone (`src/selectors/**`, `src/types.ts`) may not import them; - `src/selectors/` is pure and depends only on `citation-engine` shared types; - the **root** entrypoint (`evidence-anchor`) is the full barrel — selector creation/resolution, the adapter types/contract, and the PDF adapter — so consumers resolve every anchor symbol (and their test `vi.mock(...)` calls) from a single specifier, matching the umbrella's prior `@anchor/index`; - focused subpath entries: **`evidence-anchor/pdf`** (PDF adapter) and **`evidence-anchor/dom`** (HTML/Markdown adapter). The root barrel re-exports both for consumers that want a single import path. ## Public API (target surface) ```ts import { createSelectors, resolveSelectors, type DocumentViewerAdapter, type AnchorResolution, } from "@citation-evidence/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.