/**
 * What a Skill card's approval is bound to, as ONE value: the skill the call names and the two lists approving it releases,
 * in the rule grammar's canonical spelling (de-duplicated, sorted). Its hash is the `boundGrantDigest` a parked approval is
 * judged by, so a reader holds the list a person approved and the binding that covers it as the same fact — the live
 * `AskRequest`, the parked row and the inbox projection all carry it (minted by `skillGrantBindingMembers`).
 *
 * A leaf on purpose: the checkpoint projection reads it at its boundary and may not import the module that mints it (it imports only
 * the hash).
 */
export interface BoundSkillGrants {
    /** The skill's name as the loaded table spells it, or `null` when the call names no loaded skill (it grants nothing). */
    readonly skill: string | null;
    /** The skill's `allowed-tools` entries — what approving the activation lets be used without asking. */
    readonly allowedTools: readonly string[];
    /** The skill's `disallowed-tools` entries — what activating it refuses for the rest of the run. */
    readonly disallowedTools: readonly string[];
}
/**
 * Why a card carries no binding digest — the closed set of `boundGrantAbsence`: `not_bindable` (the call is not an
 * activation of the engine's `Skill` tool: it binds no grant) or `unreadable` (the card binds a grant and what it binds
 * cannot be read: a stored row whose digest is not a string, or that says neither).
 */
export declare const BOUND_GRANT_ABSENCES: readonly ["not_bindable", "unreadable"];
export type BoundGrantAbsence = (typeof BOUND_GRANT_ABSENCES)[number];
/**
 * A stored value read as a {@link BoundSkillGrants}, whole or not at all: a fresh copy of the three members and nothing else,
 * or `undefined` when any member is not of its type. Every member is read ONCE, so the value screened is the value published.
 */
export declare function readBoundSkillGrants(raw: unknown): BoundSkillGrants | undefined;
/** The card members every ask carries about its binding — exactly one arm: a call to the engine's `Skill` tool carries the
 *  digest and the value it hashes, every other call the absence word. */
export type SkillGrantBindingMembers = {
    readonly boundGrantDigest: string;
    readonly boundGrants: BoundSkillGrants;
    readonly boundGrantAbsence?: never;
} | {
    readonly boundGrantAbsence: BoundGrantAbsence;
    readonly boundGrantDigest?: never;
    readonly boundGrants?: never;
};
/** The members of a card that is not a `Skill` activation: the factory's other arm, and what a tool's own consent card (never a
 *  `Skill` call) spreads. */
export declare const NOT_BINDABLE: Readonly<{
    readonly boundGrantAbsence: "not_bindable";
}>;
/** The leg's binding factory ({@link SkillGrantBindingMembers} for a call over `args`), the one every ask-mint site spreads. */
export type GrantBindingOf = (call: {
    readonly toolName: string;
}, args: unknown) => SkillGrantBindingMembers;
/**
 * The binding members of a stored parked row, as the inbox projection publishes them — exactly one of three: the digest when it
 * is a string (and the lists only as the value that digest hashes — {@link readBoundSkillGrants} whole, and equal to the digest by
 * hash; a pair that disagrees, or lists beside no digest, would show an approver one list while the approval binds another), else
 * the row's absence word when it is a member of the set, else `unreadable` — the row does not say what it binds.
 */
export declare function readBoundBinding(row: {
    readonly boundGrantDigest?: unknown;
    readonly boundGrants?: unknown;
    readonly boundGrantAbsence?: unknown;
}): {
    boundGrantDigest: string;
    boundGrants?: BoundSkillGrants;
} | {
    boundGrantAbsence: BoundGrantAbsence;
};
