/**
 * coverage/types — the shared vocabulary of the two coverage primitives.
 *
 * Pattern: one value type, two consumers — `absent()` says "I looked HERE and
 *          found nothing", `coverage()` says "my answer covers THIS and not
 *          THAT". Both are statements about the same thing: the ground a
 *          result stands on. Spelling them with one vocabulary is what lets
 *          the answer-level block merge an absence's boundary with a
 *          verdict's without translating between two grammars.
 * Role:    core/ layer, pure data. No behavior; TYPE-only imports (they erase
 *          at runtime): the one period shape (`period.ts`) and the one
 *          provenance shape `describedResult()` already declares
 *          (`semantics/types.ts`), so an absence says its source and time
 *          in the same words a described result does.
 * Emits:   N/A.
 */
import type { DescribedResultDeclaration, SemanticProvenance } from '../types.js';
import type { DeclaredPeriod, PeriodOnWire } from './period.js';
import type { PagingDeclaration, ResolvedDeclaration } from './search/resultFacts.js';
/**
 * One piece of ground, and (optionally) why it is where it is.
 *
 * `what` is prose the TOOL AUTHOR wrote — a source, a window, a filter, a
 * fleet ("the fcns database on shq-fab-a", "the last 24h", "all four
 * arrays"). It is never composed from the model's arguments by this library,
 * because the library does not know which of them are real.
 */
export interface CoverageItem {
    /** The source, window, filter or population. Non-empty. */
    readonly what: string;
    /**
     * Why it sits where it does. REQUIRED on `cannotCover` (a permanent blind
     * spot is a claim about capability, and a claim with no reason cannot be
     * acted on or disproved); optional on `checked` and `notChecked`, where
     * "we did" and "we did not need to" are often the whole story.
     */
    readonly why?: string;
    /**
     * A short plain form of `what`, for a person reading a report — "every VM
     * disk in the RVTools export of 2026-09-19" for a `what` that names the two
     * tables it read. Optional; at most 80 characters, one line, and never
     * longer than `what`.
     *
     * RECORD-ONLY: it rides the events (`tools.absent`,
     * `tools.coverage_declared`), the tracked `coverageDeclared` rows and the
     * answer account, and is REMOVED from what the model is served
     * (`read.ts` · `servedToModel`). It is also withheld from the evidence
     * corpus (`evidence.ts`), because it is the field an author is most tempted
     * to personalise: NEVER interpolate the caller's arguments into it — a true
     * short form restates `what`, so no value should live only here.
     */
    readonly short?: string;
    /**
     * What kind of ground a `notChecked` or `cannotCover` item is — a CLOSED
     * set, read by the answer account's existence check:
     *
     *   • `'existence'` — whether the thing asked about exists at all, or is
     *     the kind of thing the question assumes ("whether that name is a
     *     storage array").
     *   • `'scope'` — a population, family or source outside what this tool
     *     reaches ("hosts that are not VMware").
     *
     * Refused on `checked`. RECORD-ONLY, like `short`. Absent = not declared:
     * a reader never infers a kind from `what`. Library code never switches
     * EXHAUSTIVELY over this union (every switch has a `default` arm), so a
     * later member is an additive change for producers.
     */
    readonly kind?: 'existence' | 'scope';
}
/** What an author may write in a coverage list: bare prose, or prose + why. */
export type CoverageInput = string | CoverageItem;
/**
 * One thing the tool READ and found still RUNNING — a backup in progress, a
 * replication session still synchronizing — whose outcome is therefore not
 * known yet: neither a success nor a failure (`coverage()`'s `inProgress`).
 *
 * The TOOL decides which of its vendor's states are in flight — this library
 * never reads a state name, and the vendor's own verdict field, when there is
 * one, is the tool's to weigh. `what` is the author's prose, as for every
 * coverage item; `short` is the same RECORD-ONLY short form. `count` says how
 * many things this one entry stands for ("96 sessions still synchronizing" is
 * one entry with `count: 96`); omitted, the entry is one thing. It is served —
 * the model reads the number as the tool's own.
 *
 * No `kind`: that names ground a call did NOT reach, and an item in progress
 * is ground it reached.
 */
export interface InProgressItem {
    /** What is still running. Non-empty. */
    readonly what: string;
    /** Since when, or what the vendor reported — optional. */
    readonly why?: string;
    /** RECORD-ONLY short form, the {@link CoverageItem.short} rules. */
    readonly short?: string;
    /** How many things this entry stands for — a positive whole number; omitted = one. */
    readonly count?: number;
}
/** What an author may write in `inProgress`: bare prose, or an {@link InProgressItem}. */
export type InProgressInput = string | InProgressItem;
/**
 * The three lists, normalized. This is the shape everything downstream reads —
 * the renderer, the event payload, the answer-level block.
 *
 * The three are NOT interchangeable, and the difference is the whole point:
 *
 *   • `checked` — ground this result actually stands on. A clean verdict here
 *     means VERIFIED.
 *   • `notChecked` — ground this run could have covered and did not (budget,
 *     a timeout, a scope the caller chose). A clean verdict says nothing
 *     about it. Re-asking with a wider scope can move it to `checked`.
 *   • `cannotCover` — ground no call to this tool will ever reach (no
 *     collector, no permission, no such telemetry). A clean verdict says
 *     nothing about it, and no retry ever will. This is the list that turns
 *     "everything looks fine" into "everything I can see looks fine".
 */
export interface Coverage {
    readonly checked: readonly CoverageItem[];
    readonly notChecked: readonly CoverageItem[];
    readonly cannotCover: readonly CoverageItem[];
}
/** What a tool author passes to {@link import('./ledger.js').coverage}. */
export interface CoverageDeclaration {
    readonly checked?: readonly CoverageInput[];
    readonly notChecked?: readonly CoverageInput[];
    readonly cannotCover?: readonly CoverageInput[];
}
/**
 * The other TOOL a suggestion points at, typed (9.113.0) — `tryInsteadTool`
 * on the declaration, `try_instead_tool` on the envelope.
 *
 * The `tryInstead` sentence puts a tool's name inside prose ("…or check
 * cluster_inventory for the collected names."), and a reader that wants to
 * know WHICH tool was suggested could only find out by parsing that sentence.
 * This library never parses a tool name out of prose, so the name rides here
 * as data — BESIDE the sentence, never in its place: `try_instead` stays a
 * string, so every reader of it reads what it always read.
 *
 * `tool` is NOT looked up. The tool may be served by a provider that resolves
 * per iteration, or be offered on a later turn; `absent()` requires a
 * non-empty name and records it as declared. Which names a provider accepts is
 * `lib/toolName.ts` · `assertValidToolName`'s question, and the library only
 * warns about it (dev mode), here as at `defineTool`.
 */
export interface TryInsteadTool {
    /** The tool's registered name, as a call would name it. */
    readonly tool: string;
    /** Why that tool, in the author's words ("it lists the collected names"). */
    readonly why?: string;
}
/** What a tool author passes to {@link import('./absent.js').absent}. */
export interface AbsenceDeclaration {
    /**
     * What was looked for, in the author's own words ("FLOGI entries on
     * fc1/3"). Required: an absence that cannot say what it did not find is
     * indistinguishable from a tool that returned nothing by accident.
     */
    readonly what: string;
    /**
     * The coverage of the search — REQUIRED and non-empty. An absence that
     * names no coverage is a `null` with extra steps: the reader still cannot
     * tell "I looked and there is nothing" from "I could not look", which is
     * the entire failure this primitive exists to prevent.
     */
    readonly checked: readonly CoverageInput[];
    /** Ground the search did not reach this time — an absence here proves
     *  nothing about it. */
    readonly notChecked?: readonly CoverageInput[];
    /** Ground no search by this tool can reach. Each needs a `why`. */
    readonly cannotCover?: readonly CoverageInput[];
    /**
     * Where to go INSTEAD, in one sentence ("widen the window with
     * `window: '7d'`, or ask for a different interface"). Optional, and the
     * highest-value optional field in the shape: the loop this primitive stops
     * is a model with nowhere else to go.
     *
     * Prose for the model. Nothing in this library reads a tool name out of it:
     * when the sentence points at another tool, name that tool in
     * {@link AbsenceDeclaration.tryInsteadTool} as well.
     */
    readonly tryInstead?: string;
    /**
     * The other TOOL the suggestion points at, as data (9.113.0) —
     * `{ tool, why? }`. Beside the sentence, not instead of it: the sentence is
     * what the model is told, this is what a reader reads without parsing
     * prose. Either may be given without the other; when both are given they
     * must name the same tool, and the library cannot check that they do — it
     * would have to read a tool name out of the sentence. ONE tool; a list is
     * refused (see `absent.ts` · `readToolSuggestion` for why).
     */
    readonly tryInsteadTool?: TryInsteadTool;
    /**
     * Where the search looked and how old that source is — the SAME shape
     * `describedResult()` declares (`measuredAt`, `source`, and optionally
     * `ageSeconds`, `sourceExportDate`), respelled to the same snake_case wire
     * (honesty step 7b). `measuredAt` and `source` are both required once it is
     * present. So the found branch and the not-found branch of one `execute`
     * carry their source and time in one shape: "searched the 02:00 export —
     * nothing" as data, not prose in `checked`. `measuredAt` is the tool's own
     * words, never parsed.
     */
    readonly provenance?: NonNullable<DescribedResultDeclaration['provenance']>;
    /**
     * What the search's READ covered in time — the instants it asked for, and
     * what the store holds (or `'unknown'`, said out loud) — honesty step 7b.
     * Every value is an ISO 8601 instant with a zone; a malformed period is
     * refused here. The results layer files its verdict (covered · partly held ·
     * not held · unknown), and `.limitsTravelWithTheAnswer()` prints it.
     */
    readonly period?: DeclaredPeriod;
    /**
     * The entity each population value RESOLVED to — `[{ argument, id, name?,
     * aliases? }]` — the tool's own claim, said out loud. Read by a tool that
     * declares its `search`: it binds the value the call was SENT for and no
     * other entity. Refused here when malformed.
     */
    readonly resolved?: readonly ResolvedDeclaration[];
    /**
     * Whether there is a next page — `{ next: null }` says there is none. A tool
     * with a `page` argument whose result declares no `paging` is never complete.
     */
    readonly paging?: PagingDeclaration;
}
/**
 * An absence whose coverage the tool's `search` DECLARES —
 * `absent({ what, checked: 'declared' })`. The author writes the search once;
 * the dispatch funnel composes `checked` (and the gaps) from the declaration
 * and the arguments the call ran with. A tool with no `search` that returns
 * one has its call refused, naming the field to add.
 */
export type DeclaredAbsenceDeclaration = Omit<AbsenceDeclaration, 'checked'> & {
    readonly checked: 'declared';
};
/**
 * The list a missed name was looked up in — `absent({ what, among })`.
 *
 * A lookup that checks a name against a known list IS a search, and its miss
 * says only that the name is not on THAT list. `among` declares the list, and
 * the mint composes the rest: the names facet the tool searched, the gap the
 * author cannot remove ("names outside <source>" — and, for a `partial` read,
 * "not every name in <source> was read"), and the absence's `provenance` from
 * `source` and `measuredAt`. The gap holds where `among` is declared; a plain
 * `absent({ what })` or a thrown refusal never passes through it.
 *
 * @example a name lookup that found nothing in the inventory export
 *   if (!array) return absent({
 *     what: array_id,
 *     among: { argument: 'array_id', source: inventory.source, measuredAt: inventory.readAt,
 *              count: inventory.names.length, names: inventory.names },
 *   });
 */
export interface AmongDeclaration {
    /** The input argument whose value was looked up ('array_id'). */
    readonly argument: string;
    /** The list the names were read from, in the author's words ('the PowerStore inventory export'). One line. */
    readonly source: string;
    /**
     * When that list was read — the tool's own words (the `provenance` rule).
     * When it is an ISO 8601 instant this library can read, the names facet
     * also carries a dated note, "names as of <measuredAt>" — no judgement of
     * whether that is old.
     */
    readonly measuredAt: string;
    /** How many names the list holds — a whole number. The tool's claim; served on the facet. */
    readonly count: number;
    /**
     * The names the list holds, read ONLY to check `count`: when given,
     * `names.length` must equal it (`names-count-mismatch`). No name is served
     * to the model or written to an event or a record.
     */
    readonly names?: readonly string[];
    /**
     * `true` when the read did not see every name in the source — a truncated
     * or paged inventory. The mint then composes a completeness gap, "not every
     * name in <source> was read" (`bears: 'completeness'`), beside "names
     * outside <source>", and `authoritative` never removes it.
     */
    readonly partial?: boolean;
    /**
     * The ONE opt-out of the "names outside <source>" gap: the author says the
     * source is every name there is, and why — the tool's claim, not verified.
     * Every use is listed for review by `check:semantics` (`authoritative-names`).
     */
    readonly authoritative?: {
        readonly why: string;
    };
}
/**
 * `absent()` given an {@link AmongDeclaration}: `checked` becomes optional (the
 * mint composes the names facet first) and `provenance` is refused — `among`
 * composes it from its own `source` and `measuredAt`.
 */
export interface AbsenceAmongDeclaration extends Omit<AbsenceDeclaration, 'checked' | 'provenance'> {
    /** The list the missed name was looked up in. */
    readonly among: AmongDeclaration;
    /** Further ground the search covered, after the composed names facet. */
    readonly checked?: readonly CoverageInput[];
}
/**
 * The names facet an `among` miss composes — the first `checked` item. A
 * {@link CoverageItem} whose `what` the library writes from the declaration
 * (never from the looked-for value).
 */
export interface NamesFacetItem extends CoverageItem {
    readonly facet: 'names';
    /** The input argument whose value was looked up. */
    readonly argument: string;
    /** How many names the list holds. */
    readonly count: number;
    /** The list, as declared. */
    readonly source: string;
    /** The names came from the tool's own read. */
    readonly from: 'result';
    /** Present only when the author declared the list authoritative. */
    readonly authoritative?: {
        readonly why: string;
    };
}
/**
 * The gap an `among` miss adds and its author cannot remove except by
 * `authoritative` — the first `not_checked` item: names outside the source
 * the tool read. It bears on the source facet: a claim that leaves the source
 * open (a flat "X does not exist") rests on ground this search never covered.
 * `kind` is record-only, like every item's.
 */
export interface SourceGapItem extends CoverageItem {
    readonly kind: 'scope';
    readonly relevance: 'bears';
    readonly bears: 'source';
}
/**
 * The gap a `partial` among read adds, which nothing removes: the names in
 * the source the read did not see. It bears on completeness — a claim that
 * the name is not in the source rests on a read that did not see all of it.
 */
export interface CompletenessGapItem extends CoverageItem {
    readonly kind: 'scope';
    readonly relevance: 'bears';
    readonly bears: 'completeness';
}
/**
 * What a tool author passes to {@link import('./ledger.js').coverage}: the
 * three lists, and the period the verdict's read covered (honesty step 7b).
 * `coverage()` takes no `provenance` — a value that comes as rows from a
 * system of record has `describedResult()`.
 *
 * @inline
 */
export type CoverageLedgerDeclaration = CoverageDeclaration & {
    /**
     * What the read behind this value covered in time — the instants it asked
     * for, and what the store holds (or `'unknown'`). Refused when malformed.
     */
    readonly period?: DeclaredPeriod;
    /**
     * What the read found still RUNNING — its outcome not known yet (a backup in
     * progress, a session still synchronizing). The tool decides what is in
     * flight; the library never reads a vendor's state name. Needs `checked`
     * beside it (an item in progress is ground the call read). An empty list
     * says nothing and is omitted, like every coverage list. Served as
     * `in_progress`, with one static clause after the note; recorded on the
     * `coverageDeclared` row and `tools.coverage_declared`; printed under
     * `.limitsTravelWithTheAnswer()`. It never changes the answer's standing.
     */
    readonly inProgress?: readonly InProgressInput[];
};
/**
 * The rendered absence — the exact object a tool hands back and the model
 * reads. Field names are snake_case and English on purpose: this value is
 * read by a language model far more often than by code, and `af_absent` is
 * the only field here that exists for the machine.
 *
 * The `af_absent` key is RESERVED vocabulary on the tool-result wire (the
 * `propose-transition` / `require-instruction` precedent): a plain object
 * carrying it is an absence, and nothing else in this library will treat any
 * other shape as one.
 */
export interface ToolAbsence {
    readonly af_absent: true;
    /** The plain-English handle. Present so a model that skims one key still
     *  reads the outcome rather than inferring it from a missing field. */
    readonly outcome: 'nothing_found';
    readonly looked_for: string;
    readonly checked: readonly CoverageItem[];
    readonly not_checked?: readonly CoverageItem[];
    readonly cannot_cover?: readonly CoverageItem[];
    /** Stated as data as well as prose — the note can be skimmed past, a
     *  `true` in a field named for the question cannot. */
    readonly retry_returns_the_same: true;
    /** The author's sentence. A string, always — the typed tool rides its own
     *  key, so a reader of this one never has to narrow it. */
    readonly try_instead?: string;
    /** The typed tool the suggestion points at (9.113.0), as declared — the
     *  author's words, `{ tool, why? }`. The model reads it as written. */
    readonly try_instead_tool?: TryInsteadTool;
    /** Where the search looked and when that source was measured — the wire
     *  `describedResult()` mints (`measured_at`, `source`, …), honesty step 7b. */
    readonly provenance?: SemanticProvenance;
    /** What the search's read covered in time — `queried`, `held` (or
     *  `'unknown'`), `read_at` — honesty step 7b. */
    readonly period?: PeriodOnWire;
    /** The entity each population value resolved to, as declared. */
    readonly resolved?: readonly ResolvedDeclaration[];
    /** Whether there is a next page, as declared. */
    readonly paging?: PagingDeclaration;
    /** The static sentence. Never interpolated — see `absent.ts`. */
    readonly note: string;
}
/**
 * The envelope `absent({ checked: 'declared' })` mints, before the dispatch
 * funnel composes its coverage. `readAbsence` does not read it (its `checked`
 * is not a list), so every reader that predates it sees data;
 * `recognize.ts` · `readDeclaredAbsence` is its one recognizer.
 */
export type DeclaredToolAbsence = Omit<ToolAbsence, 'checked'> & {
    readonly checked: 'declared';
};
/**
 * A ledger whose `checked` the tool's `search` DECLARES —
 * `coverage(rows, { checked: 'declared', … })`, the twin of
 * {@link DeclaredAbsenceDeclaration} for a value that came back with rows.
 */
export type DeclaredLedgerDeclaration = Omit<CoverageLedgerDeclaration, 'checked'> & {
    readonly checked: 'declared';
};
/**
 * The envelope `coverage(rows, { checked: 'declared' })` mints, before the
 * dispatch funnel composes it. `readCoverageLedger` does not read it, so a
 * reader that predates it sees data; `recognize.ts` · `readDeclaredLedger` is
 * its one recognizer.
 */
export interface DeclaredCoveredResult<T = unknown> {
    readonly af_coverage: Omit<CoveredResult['af_coverage'], 'checked'> & {
        readonly checked: 'declared';
    };
    readonly result: T;
}
/** The rendered coverage ledger, wrapped around the result it bounds. */
export interface CoveredResult<T = unknown> {
    readonly af_coverage: {
        readonly checked?: readonly CoverageItem[];
        readonly not_checked?: readonly CoverageItem[];
        readonly cannot_cover?: readonly CoverageItem[];
        /** What the read found still running — its outcome not known yet.
         *  Serialized before `result`, like the lists. */
        readonly in_progress?: readonly InProgressItem[];
        /** What the read behind the value covered in time — honesty step 7b.
         *  Serialized before `result`, like the lists. */
        readonly period?: PeriodOnWire;
        readonly note: string;
    };
    /** The tool's own answer, untouched. */
    readonly result: T;
}
/**
 * One coverage statement as the RUN recorded it — what the event carries and
 * what accumulates in `AgentState.coverageDeclared`.
 *
 * `kind` is kept because the two read differently at the answer boundary: a
 * `'ledger'` bounds a verdict the answer is probably built on, an
 * `'absence'` bounds a search that found nothing.
 */
export interface DeclaredCoverage extends Coverage {
    readonly kind: 'absence' | 'ledger';
    readonly toolName: string;
    readonly toolCallId?: string;
    readonly iteration: number;
    /** Present for `'absence'` only — what the search was for. */
    readonly lookedFor?: string;
    /**
     * The period the declaration said its read covered, in the record's
     * camelCase form (honesty step 7b) — present only when the envelope declared
     * a well-formed one. A described result with a period and no coverage lists
     * files a `'ledger'` row whose three lists are empty.
     */
    readonly period?: DeclaredPeriod;
    /**
     * What the call found still running — its outcome not known yet — as the
     * `coverage()` declared it (copied item by item; `short` and `count` when
     * valid). Present only on a `'ledger'` row whose envelope declared a
     * well-formed, non-empty `in_progress`.
     */
    readonly inProgress?: readonly InProgressItem[];
}
