Draft two proposed workplans instead of expanding this slice: - EANCH-WP-0002 anchor-resolution-hardening (stale/orphan, fuzzy re-anchoring, promote PdfSpikeViewer to a production PDFViewerAdapter) - EANCH-WP-0003 non-pdf-selectors (HTML/Markdown DomRange+Structural, non-PDF viewer adapter; starts with a citation-engine shared-type contract change) Add an explicit gap map to WP-0001 T06. fix-consistency (C-06) will register both in the hub during T07. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
114 lines
3.7 KiB
Markdown
114 lines
3.7 KiB
Markdown
---
|
|
id: EANCH-WP-0002
|
|
type: workplan
|
|
title: "Anchor resolution hardening: stale/orphan semantics, fuzzy re-anchoring, production PDF adapter"
|
|
domain: infotech
|
|
repo: evidence-anchor
|
|
status: proposed
|
|
owner: codex
|
|
topic_slug: citation_evidence_mvp
|
|
created: "2026-07-08"
|
|
updated: "2026-07-08"
|
|
spec_refs:
|
|
- INTENT.md
|
|
- SCOPE.md
|
|
- ../citation-evidence/wiki/SharedContracts.md
|
|
- ../citation-evidence/wiki/ArchitectureOverview.md
|
|
---
|
|
|
|
# EANCH-WP-0002 — Anchor Resolution Hardening
|
|
|
|
## Goal
|
|
|
|
Close the resolution-quality gaps left open by the MVP extraction
|
|
(`EANCH-WP-0001`) on the **existing PDF/text path**. The extracted slice
|
|
resolves exact position/quote/PDF selectors with a fixed confidence ladder and
|
|
returns `resolved | ambiguous | unresolved`. `INTENT.md` promises more:
|
|
`stale` detection, orphaned-annotation handling, fuzzy/recovery re-anchoring,
|
|
and human-confirmation workflows for ambiguity. This workplan makes those real
|
|
without changing the shared selector *types* (those stay in `citation-engine`).
|
|
|
|
Non-goals: HTML/Markdown selectors (see `EANCH-WP-0003`); new persistence or
|
|
UI shell behavior.
|
|
|
|
## Background
|
|
|
|
Current extracted behavior (`src/selectors/resolve.ts`):
|
|
|
|
- confidence ladder 1.00 → 0.70 across TextPosition/TextQuote/PdfPageText/PdfRect
|
|
- multiple undisambiguated quote matches → `ambiguous` at 0.5
|
|
- nothing matches → `unresolved` at 0.0
|
|
- there is **no** `stale` path (the `AnnotationResolutionStatus` enum includes
|
|
`stale`, but resolve.ts never returns it) and **no** fuzzy matching
|
|
|
|
## Task Breakdown
|
|
|
|
## T01 — Stale vs. unresolved: distinguish "representation changed" from "never found"
|
|
|
|
```task
|
|
id: EANCH-WP-0002-T01
|
|
status: todo
|
|
priority: high
|
|
```
|
|
|
|
Return `stale` (not `unresolved`) when a previously-resolvable anchor no longer
|
|
matches because the representation's canonical text changed, while the stored
|
|
quote is still meaningful. Define the signal (e.g. position selector points
|
|
in-range but slice ≠ quote AND quote no longer found) and preserve the original
|
|
quote/context on the result. Add unit tests covering stale vs. unresolved.
|
|
|
|
## T02 — Orphaned-annotation detection surface
|
|
|
|
```task
|
|
id: EANCH-WP-0002-T02
|
|
status: todo
|
|
priority: medium
|
|
depends_on: [T01]
|
|
```
|
|
|
|
Give callers a way to identify annotations whose selectors can no longer be
|
|
placed at all (orphaned) versus stale-but-recoverable. Decide whether this is a
|
|
distinct status, a flag on `AnchorResolution`, or a helper. Keep the shared
|
|
enum unchanged unless a contract change is agreed in the umbrella wiki first.
|
|
|
|
## T03 — Fuzzy / recovery re-anchoring
|
|
|
|
```task
|
|
id: EANCH-WP-0002-T03
|
|
status: todo
|
|
priority: high
|
|
depends_on: [T01]
|
|
```
|
|
|
|
Add a fuzzy quote-matching fallback (bounded edit-distance / token overlap)
|
|
below the exact ladder, returning candidates at appropriately low confidence
|
|
with `ambiguous`/`stale` status. Must never silently emit a confident wrong
|
|
match (INTENT: "No Silent Misleading Match"). Add tests with lightly-edited
|
|
source text. Confirm the ladder's exact tiers are untouched above the fuzzy
|
|
floor.
|
|
|
|
## T04 — Promote the PDF spike to a production adapter
|
|
|
|
```task
|
|
id: EANCH-WP-0002-T04
|
|
status: todo
|
|
priority: medium
|
|
depends_on: [T03]
|
|
```
|
|
|
|
Turn `PdfSpikeViewer` into a supported `PDFViewerAdapter` that implements the
|
|
`DocumentViewerAdapter` contract cleanly (remove spike-only debug flags from the
|
|
public surface, or gate them), keep viewer libs behind `src/pdf/`, and keep the
|
|
umbrella green through the change. Update `evidence-anchor/pdf` exports and docs.
|
|
|
|
## T05 — Verification + close-out
|
|
|
|
```task
|
|
id: EANCH-WP-0002-T05
|
|
status: todo
|
|
priority: high
|
|
depends_on: [T02, T04]
|
|
```
|
|
|
|
`pnpm test`/`typecheck`/`lint` green here; umbrella typecheck/test/build green
|
|
after any contract-visible change; `fix-consistency` clean; progress note.
|