/**
 * skillNeverRoutes — the NEGATIVE routing row: a phrase this graph must claim
 * NOWHERE.
 *
 * ## Why the negative form is the valuable one
 *
 * `skillExamples.ts` pins the positive assertion — this rule claims this
 * phrasing — and it cannot state the opposite. Field use says the opposite is
 * the one that catches the expensive failure. An UNDER-triggering skill costs a
 * turn: the deterministic layer declines, the model tier picks, and the answer
 * is usually still reachable. An OVER-triggering skill costs the whole answer:
 * the wrong body enters the system prompt, the wrong tools enter the tools
 * slot, and everything the model then says is shaped by a skill that had no
 * business in the turn. One reviewer of a production graph had written his own
 * harness for exactly this, outside the library, because the library could only
 * express the cheap half.
 *
 * ## Where a negative row lives, and why it is NOT on a skill
 *
 * `examples` sits on the rule it is about. A negative row cannot: the phrase it
 * describes belongs to NO skill, and hanging it on one would make three things
 * wrong at once —
 *
 *   • it would read as that skill's business ("weather questions, filed under
 *     billing") when the point is that it is nobody's;
 *   • the assertion is satisfied only when EVERY rule declines, so a row read
 *     as one rule's property would be checked against one rule and pass while
 *     another rule swallowed the phrase;
 *   • deleting the skill would delete the assertion — exactly when a graph is
 *     re-partitioned, which is exactly when over-triggering is introduced.
 *
 * A negative row is a property of the PARTITION, so it is declared at the graph
 * level (`.neverRoutes([...])` / `neverRoutes: [...]`) and judged against every
 * rule in declaration order.
 *
 * ## What is asserted — precisely, and what it does NOT cover
 *
 * The claim this module proves is: **no declared start RULE claims the
 * phrase.** It runs the compiled conditions on a cold-start context, exactly as
 * `skillExamples.ts` does, and reports the rule that says yes.
 *
 * It does NOT prove "no routing at all occurs", and could not without becoming
 * a different kind of check:
 *
 *   • an INTENT rule compiles to no sync predicate — a classifier judges it at
 *     run time, with a scorer (and, for `llmClassifier`, a model call). Running
 *     that would make the check async, non-deterministic, and in the LLM case
 *     billable — `graph.checkupIntents()` is where scorer-dependent auditing
 *     already lives;
 *   • a scorer menu (`.entryBy()`) and `.entryByRead()` RANK descriptions;
 *     there is no claim to run;
 *   • the model tier can open any open skill by name with `read_skill`, at
 *     which point no declaration is deciding anything.
 *
 * That statement ships on the report as {@link NEVER_ROUTES_BOUNDARY}, next to
 * the problems, for the same reason the examples boundary does: a reader who
 * meets a boundary only in prose docs meets a clean report first.
 *
 * A predicate that THROWS on the cold context counts as a no-match here, and is
 * not reported — because routing itself treats a throw as a no-match, so the
 * phrase really does not route through that rule. Its own rule's `examples`
 * report the throw as an error (that is a defect in the rule, not in the
 * partition).
 *
 * Composed into `graph.checkup()` by `skillGraph.ts`, like every other domain
 * check, and reporting in the shared `GraphProblem` voice.
 *
 * Zone: PURE CORE. Pinned by
 * `test/injection-engine/skill-graph-fence.test.ts`.
 */
import type { GraphProblem } from './skillGraphCheckup.js';
import { type StartRuleDecl } from './startRuleClaim.js';
/**
 * The statement the negative check makes about its own reach, carried on
 * `GraphCheckup.notes` whenever a graph declared any negative row. Same voice
 * as `EXAMPLES_BOUNDARY` (skillExamples.ts): silence here is evidence about the declared
 * RULES, and about nothing downstream of them.
 */
export declare const NEVER_ROUTES_BOUNDARY: string;
/** The slice of an entry declaration this check reads: the shared claim shape,
 *  plus the POSITIVE phrases the same rule declared (a phrase asserted both
 *  ways is a contradiction the author wrote, and is reported as one). */
export interface NeverRoutesRuleDecl extends StartRuleDecl {
    readonly examples?: readonly string[];
}
/** What {@link checkNeverRoutes} found, plus what it wants to say about its own
 *  reach. Both empty when the graph declared no negative row. */
export interface NeverRoutesCheckup {
    readonly problems: readonly GraphProblem[];
    readonly notes: readonly string[];
}
/** How two phrases are compared for "the same phrase": trimmed and
 *  case-folded, the same normalization `duplicate-intent-example` uses — an
 *  author who writes one row in two casings meant one row. Exported so the
 *  builder's accumulated-rows set is keyed the SAME way the refusal is; two
 *  spellings of one rule is how a duplicate slips through. */
export declare function neverRouteKey(phrase: string): string;
/**
 * Validate a graph-level `neverRoutes` list at DECLARATION time, refusing every
 * shape whose check-up answer could only mislead — each refusal naming the fix:
 *
 *   • not an array / an EMPTY array — nothing to assert, and a check-up that
 *     passes in silence reads as coverage;
 *   • a non-string or blank entry — there is no phrase to run a matcher on;
 *   • a phrase already declared — a repeat asserts nothing the first one did
 *     not, and reads as if two different phrasings were meant.
 *
 * A single string is accepted and read as a one-row list: `.neverRoutes('what
 * is the weather')` is the commonest call, and making the author type brackets
 * for it buys nothing.
 *
 * Returns a frozen copy of the ROWS THIS CALL ADDS, so the stored list cannot
 * drift from the validated one.
 */
export declare function validateNeverRoutes(phrases: unknown, where: string, alreadyDeclared: ReadonlySet<string>): readonly string[];
/**
 * Run the negative rows against the declared start rules. Pure, and
 * byte-identically silent when the graph declared none (one length check and
 * out).
 *
 * Unlike the positive examples, this needs NO `orderDecides` gate: the
 * assertion is "nobody claims it", which every rule has to satisfy, so the
 * order they are read in cannot change the answer. That is also why it is the
 * one phrase check that stays meaningful under a classifier — tier 1 is still
 * read first there, and a rule that claims the phrase still takes the turn
 * before any scorer runs.
 */
export declare function checkNeverRoutes(input: {
    readonly entries: readonly NeverRoutesRuleDecl[];
    readonly phrases: readonly string[];
}): NeverRoutesCheckup;
