/**
 * toolEffects — the typed tool-effects channel (9.19.0). ONE owner of the
 * result-envelope grammar: the two effect kinds, the outcome-status
 * vocabulary and the envelope recognizer. (The instruction-lease carriers a
 * granted `require-instruction` effect becomes are `injection-engine/leases.ts`.)
 *
 * THE LAW this module implements: *push mandatory procedure; pull optional
 * knowledge; never let arbitrary text promote itself into control authority.*
 * Before this channel, a tool that wanted to steer the run had exactly one
 * medium — its result STRING — and any convention riding it ("ROUTE:billing")
 * was arbitrary text one prompt-injection away from control authority. The
 * envelope replaces the convention with DATA the framework validates:
 *
 *   • `propose-transition` — the typed replacement for string routing
 *     markers. The GRAPH decides: an accepted proposal moves the cursor like
 *     a declared edge (a same-batch declared edge still wins — the
 *     `reroute_superseded` precedent), a refusal is teaching and recorded.
 *     Proposals come from TOOLS — deterministic code the author shipped — so
 *     they are framework-tier evidence: admitted under every posture
 *     (`assist`/`guard`/`rails`), but always reachability-checked against
 *     the graph's own law. An unreachable target is refused, out loud.
 *
 *   • `require-instruction` — pushes a REGISTERED instruction (a skill body
 *     or a declared snippet) into the next iteration(s) per a delivery
 *     lease. `read_skill` stays the pull door; this is the push door, and it
 *     can only push what was registered at build — an unknown id is refused,
 *     never improvised.
 *
 * Beside the effects rides an optional `status` — the outcome-status
 * normalization: `'denied'` must never route like `'success'`, so route
 * edges can key on MEANING (`onToolStatus`) instead of parsing prose.
 *
 * RECOGNITION IS STRICT, and the strictness is the zero-cost guarantee.
 * A value is an envelope iff it is a plain object whose keys are a subset of
 * `{ content, effects, status }`, `content` is present, `effects` is an
 * array, and EVERY element carries one of the two known `kind`s (an empty
 * `effects: []` needs a valid `status` to say anything at all). Everything
 * else — every shape any tool has ever returned — takes the exact path it
 * always took, byte for byte. The two `kind` strings are therefore RESERVED
 * vocabulary on the tool-result wire; a recognized envelope whose fields are
 * malformed is refused teachingly (recorded), never half-applied.
 */
/**
 * The outcome words, re-exported under the names they have always had.
 *
 * They are DECLARED in `semantics/toolOutcome.ts` (9.34.0) — a
 * zero-import leaf — because a skill-graph route edge keys on them
 * (`onToolStatus`) and `InjectionContext.toolResults[].status` is typed by
 * them. Leaving the declaration here meant the graph's own context type
 * reached into the agent loop for one string union, which points the
 * dependency backwards: the loop depends on the graph, never the reverse.
 *
 * This module remains the owner of the ENVELOPE grammar below — the two
 * effect kinds and the recognizer. Only the vocabulary moved down; the lease
 * carriers live with their reader, `injection-engine/leases.ts`.
 */
export type { ToolResultStatus } from './toolOutcome.js';
export { TOOL_RESULT_STATUSES } from './toolOutcome.js';
import type { ToolResultStatus } from './toolOutcome.js';
/** A tool proposes moving the skill-graph cursor. The graph decides. */
export interface ProposeTransitionEffect {
    readonly kind: 'propose-transition';
    /** The skill node to move to. Reachability-checked against the graph's
     *  own law (`reachableSkills(cursor)`); unreachable = teaching refusal. */
    readonly targetSkillId: string;
    /** Why — goes on the record (`tools.effect`), never optional: a routing
     *  proposal with no reason is exactly the arbitrary authority this
     *  channel exists to replace. */
    readonly reason: string;
}
/** How long a pushed instruction stays delivered. */
export type InstructionDeliveryLease = 'next-call' | 'until-skill-exit';
/** A tool pushes a registered instruction into the coming iteration(s). */
export interface RequireInstructionEffect {
    readonly kind: 'require-instruction';
    /** A REGISTERED injection id (a skill or an instruction). Unknown ids are
     *  refused teachingly — the push door serves the declared catalog only. */
    readonly instructionId: string;
    /** `'next-call'` — exactly the next LLM call; `'until-skill-exit'` — every
     *  call while the tenure that granted it holds (the skill the cursor was
     *  on when the tool returned). */
    readonly deliveryLease: InstructionDeliveryLease;
}
/** The typed effects a tool result may carry. Two kinds — deliberately. */
export type ProposedEffect = ProposeTransitionEffect | RequireInstructionEffect;
/**
 * What a tool handler returns to opt into the channel:
 * `{ content, effects, status? }`. `content` is what the model reads (any
 * value — strings pass through, objects stringify exactly as a bare return
 * would). Returning anything else keeps today's path, byte for byte.
 *
 * `effects` is REQUIRED — it is the envelope marker itself. The recognizer
 * refuses to treat a value without an `effects` array as an envelope (that
 * strictness IS the zero-cost guarantee: `{ content, status: 'success' }`
 * is a shape a domain object could already have), so the type says exactly
 * what the recognizer accepts. Status-only is spelled `effects: []` — the
 * explicit marker when only `status` matters.
 */
export interface ToolResultEnvelope {
    readonly content: unknown;
    readonly effects: readonly ProposedEffect[];
    readonly status?: ToolResultStatus;
}
/** A recognized envelope, read: content unwrapped, VALID effects listed,
 *  malformed ones named (one teaching entry per bad effect). */
export interface ReadToolResultEnvelope {
    readonly content: unknown;
    readonly effects: readonly ProposedEffect[];
    readonly status?: ToolResultStatus;
    /** Effects that carried a known `kind` with malformed fields — refused
     *  loudly (recorded + a teaching sentence), never half-applied. */
    readonly malformed: ReadonlyArray<{
        readonly kind: ProposedEffect['kind'];
        readonly refusalReason: string;
    }>;
}
/**
 * Recognize (or decline to recognize) a tool's return value as an effects
 * envelope. `undefined` = not an envelope: the caller keeps today's path
 * untouched. See the module header for the exact recognition rule and why
 * it is strict.
 */
export declare function readToolResultEnvelope(result: unknown): ReadToolResultEnvelope | undefined;
/**
 * Name the ONE near-miss a tool author is likeliest to write: a status-only
 * envelope with the `effects` marker left off — `{ content, status: 'denied' }`.
 * That shape is NOT an envelope (recognition demands the `effects` array;
 * see `ToolResultEnvelope`), and it stays data byte-for-byte — but a value
 * whose only keys are envelope keys AND whose `status` speaks the closed
 * outcome vocabulary is far more likely a dropped `effects: []` than a
 * coincidence, and letting it route like an undeclared result with no word
 * of why would be accepted-and-silently-wrong. Returns the teaching sentence
 * for the caller's dev-mode warning; `undefined` for every other value.
 * Diagnosis only — never changes what any value does.
 */
export declare function explainStatusOnlyNearMiss(result: unknown): string | undefined;
//# sourceMappingURL=toolEffects.d.ts.map