Evidence anchoring, selector, resolution for citations.
Find a file
codex adbcae29e8
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
fix(workplans): adopt ADR-007 derived identifiers for unregistered records
These workplans exist only in the retired local hub. Their random pre-ADR-007
identifiers are refused by C-06 as stale references, so they cannot be
registered. Deriving from the canonical record id takes no identity from
anything: central does not hold them and the old ids die with the cache.

Records central already holds were deliberately left untouched.

Refs CUST-WP-0068-T06

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2583210@bnt-lap001
Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
2026-08-25 20:09:37 +02:00
.claude/rules chore(consistency): register follow-on workplans + retire ralph loop state 2026-07-09 01:37:11 +02:00
.forgejo/workflows Add Forgejo CI smoke workflow (enablement template) 2026-07-08 12:31:10 +02:00
registry Add registry/NO_CAPABILITIES.md (reuse-surface REUSE-WP-0017-T03) 2026-07-06 18:50:37 +02:00
src EANCH-WP-0004: HtmlViewer scroll parity and viewer-shell workplan 2026-07-09 09:58:41 +02:00
workplans fix(workplans): adopt ADR-007 derived identifiers for unregistered records 2026-08-25 20:09:37 +02:00
.custodian-brief.md chore(consistency): sync task status from DB [auto] 2026-08-25 19:49:44 +02:00
.gitignore EANCH-WP-0001 T03: extract pure selector creation + resolution core 2026-07-08 20:41:54 +02:00
.nvmrc EANCH-WP-0001 T02: bootstrap standalone TS package + test harness 2026-07-08 20:37:59 +02:00
.repo-classification.yaml Add .repo-classification.yaml (CUST-WP-0050 T11 agent first-pass) 2026-06-22 17:47:35 +02:00
AGENTS.md docs(agents): repoint remote State Hub URL to the in-cluster address 2026-08-25 00:20:55 +02:00
CLAUDE.md Normalize agent instructions and workplan frontmatter (STATE-WP-0067) 2026-06-22 23:16:24 +02:00
eslint.config.js EANCH-WP-0001 T04: extract PDF adapter + scroll/highlight helpers 2026-07-08 20:44:52 +02:00
INTENT.md Add MVP Coordination section: code lives in citation-evidence umbrella during MVP 2026-05-24 16:51:04 +02:00
LICENSE Adopt Target Revenue Source License V1C1 (org-wide preliminary rollout) 2026-07-30 00:06:34 +02:00
package.json Implement EANCH-WP-0002 and EANCH-WP-0003 anchor hardening and DOM selectors 2026-07-09 09:18:42 +02:00
pnpm-lock.yaml EANCH-WP-0001 T03: extract pure selector creation + resolution core 2026-07-08 20:41:54 +02:00
README.md Post WP-0002/0003 hygiene: update docs and archive finished workplans 2026-07-09 09:29:50 +02:00
SCOPE.md EANCH-WP-0004: HtmlViewer scroll parity and viewer-shell workplan 2026-07-09 09:58:41 +02:00
tsconfig.json EANCH-WP-0001 T02: bootstrap standalone TS package + test harness 2026-07-08 20:37:59 +02:00
vitest.config.ts EANCH-WP-0001 T02: bootstrap standalone TS package + test harness 2026-07-08 20:37:59 +02:00
WORK-RECORDS.md fix(workplans): adopt ADR-007 derived identifiers for unregistered records 2026-08-25 20:09:37 +02:00

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 behaviorcreateSelectors, 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)

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)

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.