Promote DomRange and Structural selector types for non-PDF anchoring
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 9s

Define real DomRangeSelector, StructuralSelector, StructureMap, and
containerPath fields so evidence-anchor can implement HTML/Markdown
selector creation and resolution. Update SharedContracts.md with field
shapes and DomSelectionCapture payload.
This commit is contained in:
tegwick 2026-07-09 09:18:42 +02:00
parent 67a3d82dfa
commit 86d10e7e90
3 changed files with 111 additions and 12 deletions

View file

@ -6,6 +6,7 @@
*/ */
import type { DocumentId, RepresentationId } from "./ids"; import type { DocumentId, RepresentationId } from "./ids";
import type { DomNodePath, StructuralPathSegment } from "./selector";
/** /**
* The kind of normalized view derived from a source document. * The kind of normalized view derived from a source document.
@ -56,10 +57,23 @@ export interface PageOffsetRange {
export type OffsetMap = readonly PageOffsetRange[]; export type OffsetMap = readonly PageOffsetRange[];
/** /**
* Reserved for `StructuralSelector` (heading/section/AST path). * Maps canonical-text offset ranges to structural paths for non-paginated
* Not implementable in MVP type is `never` to enforce that at compile time. * representations (`html-dom`, `markdown-rendered`).
*
* Entries are sorted by `globalStart`, are non-overlapping, and together
* cover `[0, canonicalText.length)`.
*/ */
export type StructureMap = never; export interface StructureRange {
/** Inclusive canonical-text offset where this block begins. */
readonly globalStart: number;
/** Exclusive canonical-text offset where this block ends. */
readonly globalEnd: number;
readonly path: readonly StructuralPathSegment[];
/** DOM path to the block's text container, when captured from a viewer. */
readonly containerPath?: DomNodePath;
}
export type StructureMap = readonly StructureRange[];
/** A source document known to the system. */ /** A source document known to the system. */
export interface Document { export interface Document {

View file

@ -7,9 +7,8 @@
* *
* The MVP implements the four PDF-relevant variants * The MVP implements the four PDF-relevant variants
* (`TextQuoteSelector`, `TextPositionSelector`, `PdfRectSelector`, * (`TextQuoteSelector`, `TextPositionSelector`, `PdfRectSelector`,
* `PdfPageTextSelector`). The other three kinds (DOM, structural, fragment) * `PdfPageTextSelector`) plus DOM/structural selectors for HTML/Markdown.
* are reserved as `never`-typed stubs so adding them later is a localised * `FragmentSelector` remains a `never`-typed stub.
* change.
*/ */
/** Exact quote with optional surrounding context (W3C-aligned). */ /** Exact quote with optional surrounding context (W3C-aligned). */
@ -54,11 +53,41 @@ export interface PdfPageTextSelector {
readonly end: number; readonly end: number;
} }
/** Reserved for HTML/Markdown viewer adapters. Not implementable in MVP. */ /**
export type DomRangeSelector = never; * Child-index path from the document root to a text container node.
* Each entry is the 0-based index among `childNodes` at that level.
*/
export type DomNodePath = readonly number[];
/** Reserved for heading/section/AST-path locators. Not implementable in MVP. */ /** DOM range for rendered HTML/Markdown (W3C Range-aligned). */
export type StructuralSelector = never; export interface DomRangeSelector {
readonly type: "DomRangeSelector";
readonly startPath: DomNodePath;
readonly startOffset: number;
readonly endPath: DomNodePath;
readonly endOffset: number;
}
/** One segment of a structural path (heading, section, or block). */
export interface StructuralPathSegment {
readonly kind: "heading" | "section" | "block";
/** 0-based index among siblings of the same kind at this level. */
readonly index: number;
/** Heading level (16) when `kind` is `heading`. */
readonly level?: number;
/** Snapshot of heading/section label text when known. */
readonly label?: string;
}
/** Structural locator for re-render-stable anchoring in HTML/Markdown. */
export interface StructuralSelector {
readonly type: "StructuralSelector";
readonly path: readonly StructuralPathSegment[];
/** Inclusive start offset within the resolved block's canonical text. */
readonly startOffset: number;
/** Exclusive end offset within the resolved block's canonical text. */
readonly endOffset: number;
}
/** Reserved for exported deep-link fragments. Not implementable in MVP. */ /** Reserved for exported deep-link fragments. Not implementable in MVP. */
export type FragmentSelector = never; export type FragmentSelector = never;

View file

@ -148,6 +148,38 @@ StructuralSelector heading/section/AST path
FragmentSelector exported fragment / deep link (export-only) FragmentSelector exported fragment / deep link (export-only)
``` ```
Field shapes (non-PDF selectors, EANCH-WP-0003):
```ts
type DomNodePath = readonly number[]; // child-index path from document root
interface DomRangeSelector {
type: "DomRangeSelector";
startPath: DomNodePath;
startOffset: number;
endPath: DomNodePath;
endOffset: number;
}
interface StructuralPathSegment {
kind: "heading" | "section" | "block";
index: number;
level?: number; // headings only
label?: string;
}
interface StructuralSelector {
type: "StructuralSelector";
path: readonly StructuralPathSegment[];
startOffset: number;
endOffset: number;
}
```
`StructureMap` on `DocumentRepresentation` maps canonical-text spans to
structural paths (sorted, non-overlapping). Ingest pipelines may omit it;
viewer adapters populate it at selection time.
**Selector redundancy rule:** when an annotation is created, the system stores **Selector redundancy rule:** when an annotation is created, the system stores
*all selector types that are available* for that document representation, not *all selector types that are available* for that document representation, not
just one. Resolution tries them in order of expected confidence and stops at just one. Resolution tries them in order of expected confidence and stops at
@ -218,8 +250,32 @@ interface DocumentViewerAdapter {
} }
``` ```
MVP delivers a single `PDFViewerAdapter`. HTML and Markdown adapters are MVP delivers a single `PDFViewerAdapter`. HTML and Markdown adapters ship in
deferred. `evidence-anchor/dom`.
`SelectionCapture` is a discriminated union:
```ts
interface PdfSelectionCapture {
kind: "pdf";
text: string;
page: number;
rects: readonly NormalizedRect[];
boundingRect?: NormalizedRect;
}
interface DomSelectionCapture {
kind: "dom";
text: string;
startPath: DomNodePath;
startOffset: number;
endPath: DomNodePath;
endOffset: number;
structuralPath?: readonly StructuralPathSegment[];
}
type SelectionCapture = PdfSelectionCapture | DomSelectionCapture;
```
--- ---