import type { ProjectType } from "../core/config.js";
import type { EnforcedContext } from "../core/gate-declaration-drift.js";
import type { HealthFinding } from "./contract.js";
/** Material ruleset fields health compares. */
export interface HealthRuleset {
    readonly name: string;
    readonly target: unknown;
    readonly enforcement: unknown;
    readonly conditions: unknown;
    readonly rules: unknown;
}
/**
 * Injectable structured ruleset reader. Implementations must honor `signal`
 * and release any owned handles before settling.
 */
export type RulesetReader = (owner: string, repo: string, projectRoot: string, timeoutMs: number, signal: AbortSignal) => Promise<readonly HealthRuleset[]>;
/** Ruleset comparison result containing names only. */
export interface RulesetDrift {
    readonly missing: readonly string[];
    readonly drifted: readonly string[];
}
/**
 * Default fixed-argv detailed GitHub ruleset reader.
 * @param owner
 * @param repo
 * @param projectRoot
 * @param timeoutMs
 * @param signal
 */
export declare const readGithubRulesets: RulesetReader;
/**
 * Read expected material rulesets after the same per-project normalization as apply.
 * @param lisaRoot - Lisa package root
 * @param projectRoot - Canonical host root
 * @param types - Canonically ordered project types
 * @param config - Safe project config
 * @returns Expected rulesets sorted by name
 */
export declare function expectedRulesets(lisaRoot: string, projectRoot: string, types: readonly ProjectType[], config: Readonly<Record<string, unknown>>): Promise<readonly HealthRuleset[]>;
/**
 * The required status contexts one project's ruleset templates name, with the
 * file each requirement was read from.
 *
 * `expectedRulesets` already normalizes templates the way apply does, but it
 * answers with whole ruleset documents and loses which file said what. The
 * declaration comparison has to name the template file — "this context is
 * required and no declaration asks for it" is not actionable without it — so
 * this walk keeps the attribution instead.
 *
 * Returning an empty list is meaningful and must not be read as "nothing is
 * enforced": callers treat an empty result as a source they could not reach,
 * because a comparison against nothing reports every declaration as unenforced.
 * @param lisaRoot - Lisa package root
 * @param projectRoot - Canonical host root
 * @param types - Canonically ordered project types
 * @param config - Safe project config
 * @returns Required contexts with their ruleset and source file
 */
export declare function expectedRequiredContexts(lisaRoot: string, projectRoot: string, types: readonly ProjectType[], config: Readonly<Record<string, unknown>>): Promise<readonly EnforcedContext[]>;
/**
 * The required status contexts a live ruleset payload names.
 * @param actual - Rulesets as the repository actually holds them
 * @returns Required contexts with their ruleset, sorted
 */
export declare function liveRequiredContexts(actual: readonly HealthRuleset[]): readonly EnforcedContext[];
/**
 * Compare expected and observed material ruleset documents.
 * @param expected
 * @param actual
 */
export declare function compareRulesets(expected: readonly HealthRuleset[], actual: readonly HealthRuleset[]): RulesetDrift;
/**
 * Collect and compare detailed material GitHub ruleset state.
 * @param lisaRoot - Lisa package root
 * @param projectRoot - Canonical host root
 * @param types - Safely detected project types
 * @param config - Safe project config
 * @param reader - Structured remote ruleset reader
 * @param timeoutMs - Remaining shared deadline
 * @param signal - Shared cancellation signal
 * @returns GitHub ruleset finding
 */
export declare function rulesetFinding(lisaRoot: string, projectRoot: string, types: readonly ProjectType[], config: Readonly<Record<string, unknown>>, reader: RulesetReader, timeoutMs: number, signal: AbortSignal): Promise<HealthFinding>;
//# sourceMappingURL=ruleset-inspection.d.ts.map