/** * Evidence Graph layout (PRD §9/§33): the pure deterministic geometry layer * that maps the folded `EvidenceGraph` (+ researcher-declared Eureka records) * onto a temporal research worktree — research-line bands on the y axis, time * on the x axis, circular nodes, and routed SVG paths. * * Model B (the north-star reading): a research line is a band, a claim is a * branch rail whose head carries the terminal status, a declaration event is * a bead on the rail, cross-claim edges are merge curves, retractions are * revert loops, and Eureka declarations are emphasized markers on the line * header — never inferred, only declared (§107/§108). External sources (lit/ * exp/run) surface as open-circle origins at the inflow start, not as a * parallel node soup; the full entity graph lives in the audit layer. * * Determinism contract: same input ⇒ byte-identical layout. No clocks, no * randomness, no DOM, no React, no locale — executable in Vitest (§33.1). * @module dsh-client-ui-mimir/client/evidence-graph-layout */ import type { EvidenceConflict, EvidenceGraphEdge, EvidenceTimelineGroup } from 'dsh-mimir/types'; /** * The minimal fold-product shape the layout consumes. `dsh-mimir/types` does * not re-export the composed `EvidenceGraph` itself, and the layout must not * import controller slices (§112) — so it takes the smallest structural * slice it needs: the timeline, the edges, and the conflicts. */ export interface EvidenceGraphLayoutInput { readonly timeline: readonly EvidenceTimelineGroup[]; readonly edges: readonly EvidenceGraphEdge[]; readonly conflicts: readonly EvidenceConflict[]; } /** * Stable geometry constants for the research-map renderer (§35): one frozen * config, no scattered magic numbers in the renderer. */ export declare const EVIDENCE_GRAPH_LAYOUT_DEFAULTS: Readonly<{ /** Left gutter for the line band label + claim rail labels. */ plotLeft: 248; /** Top padding hosting the time-axis labels. */ topPad: 46; /** One research-line band's header row (line label + eureka markers). */ bandHeader: 34; /** One claim rail's height. */ laneHeight: 48; /** Trailing space for the claim head node + its status tag. */ tailWidth: 132; /** Canvas floor width; the derived width only grows from here. */ minWidth: 960; /** Minimum horizontal separation between beads on the time axis (§114). */ minNodeGap: 30; /** Same-timestamp vertical stack step within one rail (§39). */ nodeStackStep: 18; /** Maximum symmetric same-timestamp stack slots (0, ±1, ±2). */ nodeStackLimit: 2; /** Radius hierarchy (§7.2). */ nodeMinRadius: 6; nodeImportantRadius: 8; nodeMilestoneRadius: 10; nodeEurekaRadius: 8; /** Transparent interaction hit target radius (≥28px diameter). */ nodeHitRadius: 14; /** Parallel edge bundling (§42). */ parallelEdgeStep: 5; maxParallelEdgeOffset: 14; /** Edge hit target stroke width for pointer selection (§99). */ edgeHitWidth: 18; /** Bottom padding. */ bottomPad: 18; }>; /** The line palette size (bands cycle it; color continuity per line). */ export declare const LINE_HUES = 6; /** The canvas kinds of one positioned node. */ export type EvidenceNodeKind = 'event' | 'retract' | 'claim' | 'eureka' | 'source'; /** The relation color class of an event node (null on structure nodes). */ export type EvidenceRelClass = 'supports' | 'contradicts' | 'tests' | 'retract' | 'neutral'; /** One positioned circular node on the canvas. */ export interface EvidenceNodeLayout { /** Stable React key: the ledger event id, claim key, eureka id, or source key. */ readonly id: string; readonly kind: EvidenceNodeKind; /** The raw relation (event/retract nodes); '' on structure nodes. */ readonly rel: string; readonly relClass: EvidenceRelClass | null; readonly x: number; readonly y: number; readonly r: number; /** The research-line hue index (structure color). */ readonly hue: number; /** The claim key whose rail carries the node (null on eureka/source nodes). */ readonly claimKey: string | null; readonly ts: string; /** Tooltip / detail copy (plain text). */ readonly label: string; /** The ledger event id behind the node (provenance jump); null on heads. */ readonly eventId: string | null; readonly conflict: boolean; readonly retracted: boolean; /** The claim head's terminal status (claim nodes only). */ readonly status: string | null; } /** One routed link between nodes. */ export interface EvidenceLinkLayout { readonly kind: 'inflow' | 'external' | 'retract' | 'conflict'; /** The routed SVG path data (§40 perimeter-trimmed endpoints). */ readonly d: string; readonly fromId: string; readonly toId: string; /** The source line hue (inflow color continuity). */ readonly hue: number | null; } /** One claim rail: the horizontal branch line + its head position. */ export interface EvidenceRailLayout { readonly claimKey: string; readonly label: string; readonly y: number; readonly x1: number; readonly x2: number; readonly hue: number; readonly headId: string; readonly status: string | null; } /** One research-line band: the y-axis swimlane grouping claim rails. */ export interface EvidenceBandLayout { readonly key: string; readonly kind: 'idea' | 'project'; readonly label: string | null; readonly hue: number; readonly y: number; readonly height: number; readonly claimKeys: readonly string[]; } /** One date tick on the time axis. */ export interface EvidenceTickLayout { readonly x: number; readonly label: string; } /** The composed, positioned canvas geometry of one fold product. */ export interface EvidenceGraphLayout { readonly width: number; readonly height: number; readonly bands: readonly EvidenceBandLayout[]; readonly rails: readonly EvidenceRailLayout[]; readonly nodes: readonly EvidenceNodeLayout[]; readonly links: readonly EvidenceLinkLayout[]; readonly ticks: readonly EvidenceTickLayout[]; } /** The Eureka shape the layout consumes (structurally the Remote view's row). */ export interface EvidenceEurekaPoint { readonly id: string; readonly at: string; readonly title: string; readonly lineId: string | null; } /** Layout options: researcher-declared Eureka markers (worktree alignment is P2). */ export interface EvidenceGraphLayoutOptions { readonly eurekaDeclarations?: readonly EvidenceEurekaPoint[] | undefined; } /** An Eureka declaration attributed to no band renders on this trailing band. */ export declare const EUREKA_FALLBACK_BAND = "eureka:unattributed"; /** * Lay the fold product out on the deterministic canvas (PRD §9/§111). * @param graph - the fold's `EvidenceGraph`. * @param options - optional Eureka declarations. * @returns the positioned geometry; an empty timeline yields an empty layout. */ export declare function deriveEvidenceGraphLayout(graph: EvidenceGraphLayoutInput, options?: EvidenceGraphLayoutOptions): EvidenceGraphLayout; /** CJK-safe truncation over a char budget (wide chars count double). */ export declare function clipLabel(text: string, maxWidth: number): string; //# sourceMappingURL=evidence-graph-layout.d.ts.map