/**
 * The behavioural face of a segment: a functional {@link SegmentHandle}.
 *
 * Where {@link Segment} is the immutable data, a {@link SegmentHandle} is the
 * small bag of closures a caller actually uses — `note`, `child`, `fail`,
 * `close`. Each operation derives the next frozen segment value and emits a
 * {@link TraceSignal} onto an injected `sink`. There is intentionally **no
 * class hierarchy**: a sampled-in handle is a plain object of closures built by
 * {@link openHandle}, and a sampled-out handle is the single frozen
 * {@link NOOP_HANDLE} value implementing the same shape with empty methods — not
 * a subclass, not a separate `NoopSegment` type.
 *
 * The handle keeps the segment's *current* value in a closed-over variable so
 * that `note`/`fail` can derive successive values; this is the only mutable
 * state in the module and it never escapes — callers only ever see immutable
 * {@link Segment}/{@link TraceRecord} values via the emitted signals.
 */
import type { TraceSignal } from "../channel/signal";
import { type SegmentKind } from "./segment";
/** A consumer of trace signals — typically a {@link import('../channel/signal').SignalChannel}'s `emit`. */
export type SignalSink = (signal: TraceSignal) => void;
/**
 * The functional handle over a single in-flight segment.
 *
 * `note`, `child`, and `fail` are no-ops after `close`; `close` itself is
 * idempotent (the first call wins, later calls do nothing). This makes the
 * happy path forgiving of double-close in `finally` blocks.
 */
export interface SegmentHandle {
    /** The trace this handle's segment belongs to. Hex; stable across the trace. */
    readonly traceId: string;
    /** This segment's own id. Hex. `""` for the {@link NOOP_HANDLE}. */
    readonly id: string;
    /** Whether this handle does real work (`true`) or is the sampled-out no-op. */
    readonly active: boolean;
    /** Amend the segment's attributes; emits an `update` signal. */
    note(attributes: Readonly<Record<string, unknown>>): void;
    /** Open a child segment under this one, sharing the trace; returns its handle. */
    child(kind: SegmentKind, name: string): SegmentHandle;
    /** Record a failure (sets the closing status to `error`). Does not close. */
    fail(error: unknown): void;
    /** Close the segment; emits a `close` signal carrying the {@link TraceRecord}. */
    close(status?: "ok" | "error"): void;
}
/** Inputs for opening a real, sampled-in handle. */
export interface OpenHandleInput {
    readonly kind: SegmentKind;
    readonly name: string;
    /** Trace to join; a fresh trace id is minted when omitted (a root). */
    readonly traceId?: string;
    /** Enclosing segment id, or `null`/omitted for a root. */
    readonly parentId?: string | null;
    /** Initial attributes. */
    readonly attributes?: Readonly<Record<string, unknown>>;
}
/**
 * Open a live segment and return its functional handle.
 *
 * Immediately emits an `open` {@link TraceSignal} carrying the fresh frozen
 * {@link Segment}. Subsequent `note`/`fail`/`close` derive successive frozen
 * values and emit `update`/`close` signals through the same `sink`. Children
 * inherit `traceId` and are parented to this segment, and share the `sink`.
 */
export declare function openHandle(input: OpenHandleInput, sink: SignalSink): SegmentHandle;
/**
 * The single shared sampled-out handle.
 *
 * A frozen no-op object satisfying {@link SegmentHandle}: it emits nothing,
 * allocates nothing per call, and returns *itself* from `child` so an entire
 * sampled-out subtree costs nothing. This is the whole "noop" story — there is
 * no `NoopSegment` class to subclass.
 */
export declare const NOOP_HANDLE: SegmentHandle;
