/**
 * Where an annotation came from and how confident we should be in it.
 * Lives on `annotation.provenance`.
 */
export interface AnnotationProvenance {
    /**
     * Display name (or stable id) for who created the annotation — a
     * person, agent, or watcher. Together with `authorKind` this expresses
     * IDID §8's structured `author: { kind, id }`: `authorKind` is the
     * actor category, `author` is the name/id.
     */
    author?: string;
    /**
     * Actor category — *who* created the annotation. IDID §8's
     * `author.kind`. Distinct from `basis` (*how* it was derived) and from
     * the coarser `source`. Open union; consumers may extend.
     */
    authorKind?: AnnotationActorKind;
    /**
     * Origin category. Recognized values are not exhaustive; consumers
     * may extend with their own source labels. Coarser than the
     * `authorKind` / `basis` pair — kept for back-compat and as a single
     * convenience label when the finer split isn't needed.
     */
    source?: AnnotationSource;
    /**
     * Evidence type — *how* the annotation's claim was derived
     * (a hand note, a statistical test, a rule, an LLM inference, an
     * external source). IDID §8's `basis`. Distinct from `authorKind`
     * (the actor) and `source` (the coarse origin): a `"human"` author can
     * relay a `"statistical-test"` basis. Lets a reader weight a note by
     * the strength of its evidence, not just who left it.
     */
    basis?: AnnotationBasis;
    /**
     * Confidence in the assertion, 0–1. `1` is a hand-placed user
     * annotation; LLM-suggested annotations typically land below 0.8.
     */
    confidence?: number;
    /** ISO 8601 timestamp marking when the annotation was created. */
    createdAt?: string;
    /**
     * Identifier of the data snapshot the annotation was made against
     * (IDID §8's `dataVersion`). Lets a consumer tell "this note was
     * written about last week's data" from "this note still tracks the
     * current data," independent of wall-clock freshness.
     */
    dataVersion?: string;
    /**
     * Stable, opaque identifier that survives data refresh and chart
     * recreation. Used by the `"semantic"` anchor-resolution work to
     * re-locate "the Q3 spike" after new data arrives, and as the target
     * of another annotation's `lifecycle.supersedes`.
     */
    stableId?: string;
}
/**
 * Actor category for an annotation — *who* created it. IDID §8 models
 * this as `author.kind`. Open string union: `"system"` covers
 * non-watcher automated placement, and consumers may pass any other
 * label (it is preserved).
 */
export type AnnotationActorKind = "human" | "agent" | "watcher" | "system" | (string & {});
/**
 * Evidence type for an annotation — *how* its claim was derived. IDID
 * §8's `basis`. Open string union so consumers can add evidence kinds
 * (e.g. `"forecast"`, `"manual-review"`) without a type change.
 */
export type AnnotationBasis = "human-note" | "statistical-test" | "rule" | "llm-inference" | "external-source" | "computed" | (string & {});
/**
 * Recognized provenance sources. Open string union — consumers may
 * pass any other label and it will be preserved.
 */
export type AnnotationSource = "user" | "ai" | "agent" | "import" | "computed" | "system" | (string & {});
/**
 * How an annotation ages relative to the chart's current data extent.
 * Default visual treatment (defined in M2): `aging` dims, `stale`
 * draws a dashed border, `expired` is hidden unless
 * `showExpiredAnnotations` is on.
 */
export type AnnotationFreshness = LifecycleBand;
import type { AnnotationAnchor } from "../realtime/types";
export type { AnnotationAnchor } from "../realtime/types";
import type { LifecycleBand, LifecycleBandThresholds } from "../realtime/lifecycleBands";
export { bandFromAge, DEFAULT_LIFECYCLE_THRESHOLDS } from "../realtime/lifecycleBands";
export type { LifecycleBand, LifecycleBandThresholds } from "../realtime/lifecycleBands";
/**
 * Editorial standing of an annotation in a multiplayer conversation —
 * is the note still believed? IDID §8's `status`. Orthogonal to the
 * temporal `freshness` band: a note can be fresh-but-`disputed` or
 * stale-but-`accepted`. Closed union — these four are the editorial
 * state machine the editorial-lifecycle work drives:
 *
 * - `"proposed"` — placed but unreviewed (e.g. a watcher's auto-note).
 * - `"accepted"` — confirmed by a human or agent.
 * - `"disputed"` — contested; under review.
 * - `"retracted"` — withdrawn; treat like an expired note.
 */
export type AnnotationStatus = "proposed" | "accepted" | "disputed" | "retracted";
/**
 * Lifecycle state for an annotation. Lives on `annotation.lifecycle`.
 *
 * Two orthogonal axes: the **temporal** band (`freshness`, derived from
 * `createdAt` + `ttlHint`) and the **editorial** state (`status`,
 * driven by the multiplayer accept/dispute/retract flow). `supersedes`
 * links a revision to the note it replaces.
 */
export interface AnnotationLifecycle {
    /**
     * Current freshness band. When omitted, `computeAnnotationFreshness`
     * derives it from `ttlHint` and the data's current temporal extent.
     */
    freshness?: AnnotationFreshness;
    /**
     * Editorial standing (IDID §8's `status`). Set by the multiplayer
     * accept/dispute/retract flow; orthogonal to `freshness`. When
     * omitted, the annotation is treated as unconditionally shown (the
     * pre-editorial-lifecycle behavior). Status-driven visual treatment
     * is owed alongside the editorial-lifecycle work — the field ships
     * first so it can be stamped now.
     */
    status?: AnnotationStatus;
    /**
     * `provenance.stableId` of the annotation this one replaces (IDID
     * §8's `supersedes`). Forms a revision chain so a reader can trace how
     * an interpretation changed; the superseded note is typically hidden
     * once its replacement is `accepted`.
     */
    supersedes?: string;
    /**
     * How long this annotation should be considered fresh. Either an
     * ISO 8601 duration string (`"PT24H"`, `"P7D"`) or a number of
     * milliseconds. The freshness computation walks `fresh → aging
     * → stale → expired` as the chart's "now" advances past
     * `createdAt + ttlHint`.
     */
    ttlHint?: string | number;
    /** Anchor resolution strategy. Defaults to `"fixed"` when omitted. */
    anchor?: AnnotationAnchor;
}
/**
 * Carries the new optional blocks onto whatever annotation type the
 * chart accepts. Use as `Annotated<typeof myAnnotation>` for explicit
 * typing, or call `withProvenance()` for inline authoring.
 */
export type Annotated<T> = T & {
    provenance?: AnnotationProvenance;
    lifecycle?: AnnotationLifecycle;
};
/**
 * Convenience builder — attaches provenance + lifecycle blocks to an
 * annotation without disturbing its existing fields. Returns a new
 * object; does not mutate. Pure function, safe to call in SSR.
 *
 * ```ts
 * withProvenance(
 *   { type: "y-threshold", value: 100, label: "SLA breach" },
 *   {
 *     provenance: { author: "alice", source: "user", createdAt: "2026-05-20T14:00:00Z" },
 *     lifecycle: { ttlHint: "P30D", anchor: "semantic" },
 *   }
 * )
 * ```
 */
export declare function withProvenance<T extends object>(annotation: T, blocks: {
    provenance?: AnnotationProvenance;
    lifecycle?: AnnotationLifecycle;
}): Annotated<T>;
/**
 * Returns an ISO 8601 wall-clock timestamp suitable for stamping
 * `provenance.createdAt`. Sugar over `new Date().toISOString()`, but
 * named to make intent obvious in streaming consumers: "mark this
 * annotation as created now, so the lifecycle helpers can age it."
 *
 * Pair with `applyAnnotationLifecycle({ dataExtent })` on time-series
 * charts to have annotations age against chart-time rather than
 * wall-clock — the chart's latest data point becomes the "now"
 * reference, and recently-stamped annotations stay fresh for as long
 * as new data is flowing.
 */
export declare function currentTimestamp(): string;
/**
 * Stamp an annotation with `provenance.createdAt = currentTimestamp()`
 * (unless it already has a `createdAt`) and optional additional
 * provenance fields. Intended for the streaming "I'm marking the
 * latest data point" pattern, where the annotation's age should be
 * measured from when the consumer added it.
 *
 * Equivalent to:
 *   ```ts
 *   withProvenance(ann, {
 *     provenance: { createdAt: currentTimestamp(), ...rest },
 *     lifecycle: ann.lifecycle,
 *   })
 *   ```
 * — but reads cleaner at call sites and preserves any existing
 * `createdAt`.
 */
export declare function withCurrentProvenance<T extends object>(annotation: T, rest?: Omit<AnnotationProvenance, "createdAt"> & {
    createdAt?: string;
}): Annotated<T>;
/**
 * Options accepted by `computeAnnotationFreshness` and
 * `applyAnnotationLifecycle`.
 */
export interface ComputeAnnotationFreshnessOptions {
    /**
     * "Now" reference for age calculations. Number is epoch ms; string is
     * any value `Date.parse` accepts. When omitted, defaults to the max
     * of `dataExtent`, falling back to `Date.now()`.
     */
    now?: number | Date | string;
    /**
     * The chart's current temporal extent — typically `[oldest, newest]`
     * x values. Used to derive a sensible "now" for streaming charts
     * (where wall-clock time and the data's notion of "now" can drift).
     */
    dataExtent?: ReadonlyArray<number | Date | string> | {
        min: number | Date | string;
        max: number | Date | string;
    };
    /**
     * Override the default age thresholds. Each value is a multiplier of
     * `ttlHint`. Defaults: aging at 1×, stale at 1.5×, expired at 3×.
     * Same shape as `LifecycleBandThresholds` from the shared primitive.
     */
    thresholds?: LifecycleBandThresholds;
}
/**
 * Classify an annotation into a freshness band. Exported for tests and
 * for consumers that want the per-annotation band without rebuilding
 * the entire array.
 *
 * Returns the annotation's existing `lifecycle.freshness` verbatim if
 * the annotation lacks the `createdAt` or `ttlHint` needed to compute
 * a band — i.e. an explicit assignment always wins over inference.
 */
export declare function annotationFreshnessFor<T>(annotation: Annotated<T>, nowMs: number, thresholds?: LifecycleBandThresholds): AnnotationFreshness;
/**
 * Walk an annotations array and populate `lifecycle.freshness` on each
 * entry from its `provenance.createdAt` and `lifecycle.ttlHint`.
 *
 * Pure function — returns a new array; does not mutate input. Safe
 * to call in SSR. Annotations missing the inputs needed to compute a
 * band keep whatever `lifecycle.freshness` they already had (so an
 * explicit assignment always wins).
 *
 * For non-temporal charts, pass `now` explicitly. For streaming /
 * time-series charts, pass `dataExtent` — the helper picks the latest
 * value as "now" so freshness tracks chart-time, not wall-clock.
 */
export declare function computeAnnotationFreshness<T>(annotations: ReadonlyArray<Annotated<T>>, options?: ComputeAnnotationFreshnessOptions): Annotated<T>[];
/**
 * Style overrides per freshness band. Each map is partial — bands not
 * present fall back to the defaults below. `null` for a value removes
 * the default rather than applying it (e.g. `{ opacity: { aging: null } }`
 * disables dimming aging annotations).
 */
export interface AnnotationLifecycleTreatment {
    opacity?: Partial<Record<AnnotationFreshness, number | null>>;
    strokeDasharray?: Partial<Record<AnnotationFreshness, string | null>>;
    /** Suffix appended to `label` for that band. Default suffixes are off. */
    labelSuffix?: Partial<Record<AnnotationFreshness, string>>;
    /**
     * When true, expired annotations stay in the returned array (with
     * the expired treatment applied). When false (default), expired
     * annotations are filtered out — matching the "hidden by default"
     * contract from the talk-readiness roadmap.
     */
    showExpiredAnnotations?: boolean;
}
export type ApplyAnnotationLifecycleOptions = ComputeAnnotationFreshnessOptions & AnnotationLifecycleTreatment;
/**
 * Compute freshness and apply the default visual treatment in one pass.
 *
 * Behavior per band (overridable via options):
 * - **fresh** — no change
 * - **aging** — `opacity` 0.55
 * - **stale** — `opacity` 0.35, `strokeDasharray` `"4 4"` (cascades
 *   through the annotation's stroked children)
 * - **expired** — filtered out by default; pass
 *   `showExpiredAnnotations: true` to keep them with `opacity` 0.2 and
 *   `strokeDasharray` `"2 4"`
 *
 * Treatment composes cleanly with annotations that already carry their
 * own `color` / `opacity` — explicit fields on the annotation win,
 * the treatment only fills in what isn't already set.
 */
export declare function applyAnnotationLifecycle<T>(annotations: ReadonlyArray<Annotated<T>>, options?: ApplyAnnotationLifecycleOptions): Annotated<T>[];
/**
 * Style overrides per editorial status. Each map is partial — statuses not
 * present fall back to the defaults below. `null` for a value removes the
 * default rather than applying it.
 */
export interface AnnotationStatusVisibility {
    /**
     * Keep `retracted` annotations instead of filtering them out. Default false
     * — retracted is hidden like `expired`.
     */
    showRetractedAnnotations?: boolean;
    /**
     * Keep an annotation that another *present* note supersedes. Default false
     * — a superseded note is hidden once its replacement is in the array.
     */
    showSupersededAnnotations?: boolean;
}
export interface AnnotationStatusTreatment extends AnnotationStatusVisibility {
    /**
     * Opacity *factor* per status, multiplied into any existing opacity so it
     * composes with the freshness treatment (run `applyAnnotationLifecycle`
     * first, then this). `null` disables the factor for that status.
     */
    opacity?: Partial<Record<AnnotationStatus, number | null>>;
    strokeDasharray?: Partial<Record<AnnotationStatus, string | null>>;
    /**
     * Suffix appended to a string `label` for that status — the `disputed`
     * default `" (?)"` is the query affordance the strategy calls for.
     */
    labelSuffix?: Partial<Record<AnnotationStatus, string>>;
}
/**
 * Apply the default editorial visibility contract without changing annotation
 * styling. Retracted notes and notes replaced by a present revision are hidden
 * unless explicitly requested. Shared by visual treatment, chart descriptions,
 * and navigation trees so they expose the same current set.
 */
export declare function filterAnnotationsByStatus<T>(annotations: ReadonlyArray<Annotated<T>>, options?: AnnotationStatusVisibility): Annotated<T>[];
/**
 * Apply the editorial-status visual treatment (M7) — the orthogonal companion
 * to {@link applyAnnotationLifecycle}'s temporal-freshness treatment. The two
 * compose (a note can be stale-and-disputed); run freshness first, then this.
 *
 * Per status (overridable via options):
 * - **accepted** — no change (full weight).
 * - **proposed** — `opacity` ×0.7, dashed `"3 3"`, `label` suffix `" (proposed)"`.
 *   An unreviewed (e.g. watcher) note reads provisionally.
 * - **disputed** — `opacity` ×0.7, dashed `"2 3"`, `label` suffix `" (?)"`.
 *   The suffix is the query affordance: a contested note announces itself.
 * - **retracted** — filtered out by default (like `expired`); pass
 *   `showRetractedAnnotations: true` to keep it at `opacity` ×0.25.
 *
 * Also resolves **supersession**: a note whose `provenance.stableId` is the
 * `lifecycle.supersedes` target of another *present, non-retracted* note is
 * hidden (the revision replaced it), unless `showSupersededAnnotations` is set.
 *
 * Pure — returns a new array; safe in SSR. Opacity is multiplied into any
 * existing value, so it composes with freshness dimming and author-set opacity.
 */
export declare function applyAnnotationStatus<T>(annotations: ReadonlyArray<Annotated<T>>, options?: AnnotationStatusTreatment): Annotated<T>[];
