--- id: EANCH-WP-0001 type: workplan title: "Bootstrap evidence-anchor and extract the current anchor slice from citation-evidence" domain: infotech repo: evidence-anchor status: finished owner: codex topic_slug: citation_evidence_mvp created: "2026-06-21" updated: "2026-07-08" state_hub_workstream_id: "69e30105-ace2-49b6-a1de-a509052854c1" spec_refs: - INTENT.md - README.md - SCOPE.md - ../citation-evidence/wiki/SharedContracts.md - ../citation-evidence/wiki/DependencyMap.md - ../citation-evidence/docs/decisions/ADR-0006-selector-ownership-split.md --- # EANCH-WP-0001 — Bootstrap And Extract Evidence Anchor ## Goal Turn `evidence-anchor` from an intent-only placeholder into the real home of the current anchor slice that already exists in `../citation-evidence/src/anchor/`, while keeping the extraction bounded enough to run safely under `/ralph-workplan`. This workplan is intentionally about **package bootstrap + code extraction + consumer cutover + verification**. It is not the place to invent the full next generation of anchor behavior. ## Ralph Loop Fit Recommended invocation once the repo is ready to execute: ```text /ralph-workplan workplans/EANCH-WP-0001-intent-placeholder.md --max-iterations 12 ``` Guardrails for the loop: - stop at extraction/cutover/verification; do not expand into open-ended feature design during the same loop - if stale detection, fuzzy recovery, or HTML/Markdown support turns into substantive new implementation work, register a follow-on workplan instead of growing this one in place - HEUREKA condition for this workplan is: extracted package exists, umbrella consumer is wired to it, verification is green, and the remaining gaps are registered as next work rather than left implicit ## Background And References Repo review on 2026-07-08 found that `evidence-anchor` is still docs-only: - local repo contents are `INTENT.md`, `README.md`, a template `SCOPE.md`, registry metadata, and this workplan - the concrete implementation currently lives in `../citation-evidence/src/anchor/` - that upstream slice already contains selector creation/resolution logic, PDF selector math, a PDF viewer adapter spike, scroll/highlight helpers, and unit tests - `../citation-engine` already exports the shared `Document`, `DocumentRepresentation`, `Selector`, `AnnotationResolutionStatus`, and `normalize()` surfaces the extracted code needs Relevant upstream files already reviewed: - `../citation-evidence/src/anchor/types.ts` - `../citation-evidence/src/anchor/selectors/create.ts` - `../citation-evidence/src/anchor/selectors/resolve.ts` - `../citation-evidence/src/anchor/pdf-selector-math.ts` - `../citation-evidence/src/anchor/pdf-viewer-adapter-spike.tsx` - `../citation-evidence/src/anchor/scroll-job.ts` - matching upstream tests under `../citation-evidence/src/anchor/` ## Non-Goals For This Ralph Slice - full HTML/Markdown selector implementation - a production-grade fuzzy re-anchoring system - new persistence, binder, source-ingest, or workspace-shell behavior - speculative architecture beyond what is needed to extract and verify the existing anchor slice - indefinite cross-repo cleanup without an explicit verification target ## Execution Order ```text T01 boundary + package shape -> T02 repo bootstrap -> T03 pure selector/resolution extraction -> T04 PDF adapter extraction -> T05 citation-evidence cutover -> T06 register remaining post-extraction gaps -> T07 verification + state-hub close-out ``` ## Task Breakdown ## T01 — Codify the repo boundary and initial package shape ```task id: EANCH-WP-0001-T01 priority: high status: done state_hub_task_id: "ef88ff6a-590f-4858-a674-33f84c1d6116" ``` Turn the repo from an intent bucket into a concrete extraction target. Scope: - finish `SCOPE.md` so it reflects the actual boundary described in `INTENT.md`, `SharedContracts.md`, and `ADR-0006` - update `README.md` so it no longer points only at upstream ownership, but states the package/API shape this repo is preparing to expose - document the initial module layout for the first extracted version (`selectors`, `resolver`, `pdf`, `highlight`, `tests`, public entrypoints) - record what explicitly stays out of scope for this phase: persistence, binder/work semantics, ingestion, and umbrella app shell Acceptance: - `SCOPE.md` is no longer a template; it names the extracted boundary, current maturity, relevant dependencies, and non-goals - `README.md` explains the package purpose, sibling-checkout install model, and public module layout expectations - the repo docs clearly distinguish: `citation-engine` owns shared selector types; `evidence-anchor` owns selector behavior and viewer contracts Deliverables: - finished `SCOPE.md` - extraction-oriented `README.md` - concise package shape documented in-repo Done when a fresh agent can open this repo and know exactly what should move here and what must stay elsewhere. ## T02 — Bootstrap the local TypeScript package and test harness ```task id: EANCH-WP-0001-T02 status: done priority: high depends_on: [T01] state_hub_task_id: "59c07bc6-7a80-4f58-b1cf-ee2f0c26e8ed" ``` Create the minimum package scaffolding needed to host extracted code. Scope: - add `package.json`, `tsconfig.json`, lint/test scripts, and a test runner consistent with sibling repos - define public exports for the package and for any subpath exports that need to stay stable during cutover - wire imports to `@citation-evidence/engine/shared` instead of local `@shared/*` aliases from the umbrella repo - ensure the repo can typecheck and run tests without importing `citation-evidence` internals Acceptance: - the scaffold matches the existing `citation-engine` conventions closely enough that extraction is mostly file movement plus import rewrites - `pnpm test`, `pnpm typecheck`, and `pnpm lint` exist as local scripts - the package exposes a stable public entrypoint and any necessary subpath exports for the adapter slice Deliverables: - `package.json` - `tsconfig.json` - test/lint config files - any required ignore / Node version files Done when this repo can host the extracted code as a standalone TypeScript package with only `citation-engine` as a shared-type dependency. ## T03 — Extract pure selector creation and resolution logic ```task id: EANCH-WP-0001-T03 status: done priority: critical depends_on: [T02] state_hub_task_id: "d7bff928-a022-4cc4-a151-950ffaaf622b" ``` Move the non-UI anchoring behavior out of `../citation-evidence/src/anchor/`. Scope: - extract and adapt: `types.ts`, `selectors/create.ts`, `selectors/resolve.ts`, `selectors/index.ts`, `index.ts`, and `pdf-selector-math.ts` - port the matching unit tests: `selectors/create.test.ts`, `selectors/resolve.test.ts`, and `pdf-selector-math.test.ts` - keep the selector-ownership split intact: selector data shapes remain in `citation-engine`, selector behavior lives here - preserve the current exact-match confidence ladder and selector redundancy rules from `SharedContracts.md` Acceptance: - the extracted pure modules compile against `@citation-evidence/engine/shared` imports, not umbrella-only aliases - the three upstream unit-test groups pass locally in this repo - no UI/viewer package dependencies are required for this task Deliverables: - extracted core source files under `src/` - ported unit tests for selector creation, selector resolution, and PDF selector math - local exports wired through the package entrypoint Done when the pure anchor modules pass locally in this repo and no longer depend on the umbrella repo folder structure. ## T04 — Extract the PDF viewer adapter and highlight/scroll helpers ```task id: EANCH-WP-0001-T04 status: done priority: high depends_on: [T03] state_hub_task_id: "1deca610-8502-44e5-90c7-43e355489f55" ``` Move the PDF-specific adapter surface into this repo without leaking viewer library types into engine/shared layers. Scope: - extract and adapt: `pdf-viewer-adapter-spike.tsx`, `scroll-job.ts`, `highlight-styles.css`, and `debug-textlayer.css` - decide explicitly whether the first local export remains an explicitly-named spike or is promoted to the initial `PDFViewerAdapter` - keep `react-pdf-highlighter-plus` and PDF.js imports confined to the adapter package boundary - port `scroll-job.test.ts` and add a local demo or harness that still proves select -> store selectors -> resolve -> scroll -> highlight Acceptance: - viewer-library imports exist only inside the adapter package boundary - the scroll/highlight helper test passes locally - a maintainer can identify the supported PDF adapter surface and its current non-goals from the repo without reading the umbrella repo Deliverables: - extracted adapter and helper files - local adapter export decision documented in code or README - at least one runnable or inspectable local harness path for the PDF adapter Done when the PDF adapter contract is owned here and the viewer-specific implementation remains behind `DocumentViewerAdapter`. ## T05 — Cut citation-evidence over to the extracted package ```task id: EANCH-WP-0001-T05 status: done priority: high depends_on: [T03, T04] state_hub_task_id: "2fd9bd62-5d79-49b5-aee7-45e0a37313ba" ``` Replace the umbrella repo's internal anchor slice with a dependency on this repo. > **RESOLVED (2026-07-08).** The parallel `evidence-source` extraction landed > (`citation-evidence@4ede979`), leaving `main` clean. The cutover was then > executed and verified: umbrella typecheck + 95 tests + production build all > green (`citation-evidence@d145148`). Package published as > `@citation-evidence/evidence-anchor` with `.`, `./selectors`, `./types`, and > `./pdf` exports; node-env consumers use the pure subpaths. Original blocker > context retained below. > > **BLOCKED (2026-07-08, ralph loop iteration).** Extraction T01–T04 are > complete, committed, and verified green in `evidence-anchor` (30 tests, > typecheck, lint). T05 was **not** attempted because the umbrella > (`../citation-evidence`) has **another session's uncommitted work in > progress on `main`** — a parallel `evidence-source` extraction: > `package.json` adds `@citation-evidence/evidence-source` (link), > `src/source/pdf/*` is deleted, and `tests/integration/anchor-source-roundtrip.test.ts` > is already modified — the same shared file this cutover must edit (it imports > both `@anchor/*` and the new source package). Forcing the anchor cutover into > that dirty tree would entangle the two extractions and likely commit a > non-building intermediate state. Needs human coordination: land/park the > source extraction first, or agree how the two cutovers share the roundtrip > test and `package.json`. The ralph loop was deactivated at this point. > > Cutover plan once unblocked (bounded — 4 import sites, all via `@anchor/index`): > add `"evidence-anchor": "link:../evidence-anchor"`; repoint > `PdfSelectionCapture` + `createSelectors` → `evidence-anchor`, and > `PdfSpikeViewer`/`StoredAnnotation` + `getHighlightClientRects` → > `evidence-anchor/pdf`; drop the `@anchor` tsconfig/vite alias; delete or thin > `src/anchor/`; run umbrella typecheck/test/build. Scope: - update `../citation-evidence` to consume `evidence-anchor` through a linked package dependency instead of `src/anchor/` as the source of truth - remove duplicate anchor logic from `citation-evidence` or reduce it to thin compatibility re-exports during transition - verify `citation-evidence` build/test flows still pass against the extracted package - update cross-repo docs so the ownership statement is no longer aspirational Acceptance: - `citation-evidence/package.json` points at `link:../evidence-anchor` (or the equivalent local consumer path actually chosen) - umbrella imports resolve through the extracted package instead of treating `src/anchor/` as the canonical implementation - `citation-evidence` build/test/typecheck remain green after the cutover Deliverables: - consumer dependency and import updates in `../citation-evidence` - any temporary compatibility shims reduced to thin re-exports only - updated ownership docs across the affected repos Done when `citation-evidence` builds and tests against this repo and `src/anchor/` is no longer the canonical home of anchor behavior. ## T06 — Register the post-extraction gaps instead of expanding the slice ```task id: EANCH-WP-0001-T06 status: done priority: medium depends_on: [T05] state_hub_task_id: "4e82ee7b-e813-441f-a41f-8f17a75fee57" ``` Current upstream code handles exact resolution plus PDF fallbacks, but it does not yet satisfy the entire intent promised in `INTENT.md`. Those gaps should be made explicit and queued, not silently folded into this extraction loop. Scope: - document the gap between the extracted MVP behavior and the broader `INTENT.md` target for: `stale`, orphaned annotations, fuzzy or recovery-oriented re-anchoring, and HTML/Markdown selectors - decide which gaps belong in one follow-on extraction-hardening workplan versus separate format-specific workplans - write the follow-on plan(s) or clearly register them in this workplan as explicit next slices Acceptance: - no major promised behavior remains as "implicit future work" - the next work after extraction is named concretely enough that another Ralph loop can pick it up without re-discovery - the current workplan stays bounded: no new broad implementation starts here Deliverables: - follow-on workplan section or new workplan file(s) for gap closure - updated references in `README.md`/`SCOPE.md` if they previously implied those features already existed here Done when the extracted package ships with an honest, explicit map of the remaining anchor work instead of vague future intent. **Gap map (registered 2026-07-08):** the two follow-on workplans below cover everything `INTENT.md` promises beyond the extracted MVP slice. `SCOPE.md` already lists these under "Not in this extraction slice"; `README.md` points here. No promised behavior is left as implicit future work. - `workplans/EANCH-WP-0002-anchor-resolution-hardening.md` — stale/orphan semantics, fuzzy/recovery re-anchoring, and promoting `PdfSpikeViewer` to a production `PDFViewerAdapter` (existing PDF/text path). - `workplans/EANCH-WP-0003-non-pdf-selectors.md` — HTML/Markdown `DomRange` + `Structural` selectors and a non-PDF viewer adapter (new format track; starts with a `citation-engine` shared-type contract change). Both are `status: proposed` and will be registered in the hub by `fix-consistency` (C-06) during T07 — not by hand. ## T07 — Verification, sync, and close-out evidence ```task id: EANCH-WP-0001-T07 status: done priority: high depends_on: [T06] state_hub_task_id: "e88623a9-38d0-4aeb-a7d7-6ec78342d57b" ``` Close the loop with machine-verifiable evidence and State Hub hygiene. Scope: - run the local verification commands for `evidence-anchor` - run the affected verification commands for `citation-evidence` after cutover - update task/workplan status, run `fix-consistency`, and log the required progress note - ensure the repo capability note and brief remain truthful after extraction Acceptance: - `pnpm test`, `pnpm typecheck`, and `pnpm lint` are green in this repo - the relevant `citation-evidence` verification commands are green after consumer cutover - `fix-consistency` passes and the workplan can be moved from `active` to `finished` without status drift Deliverables: - verification evidence in commit history and/or progress note - synced State Hub task/workplan state - clean handoff for the next anchor follow-on workplan Done when the extraction is verified end-to-end and the workplan can retire cleanly under HEUREKA instead of stopping at "probably finished". **Verification (2026-07-08):** - `evidence-anchor`: `pnpm test` 30 passed (4 files), `typecheck` clean, `lint` clean. - `citation-evidence` (post-cutover, `d145148`): `pnpm typecheck` clean, `pnpm test` 95 passed (26 files), `pnpm build` succeeded. Commits: `08b3105` T01 · `0e93b68` T02 · `bd7f56c` T03 · `5b77dbd` T04 · `f32b500` T05 (umbrella `d145148`) · `0871f79` T06. Workplan frontmatter set to `finished`; follow-on gaps live in `EANCH-WP-0002` and `EANCH-WP-0003`.