import type { BaselineCatalog } from "./catalog.js"; import { type BaselineEvidenceLock } from "./schema.js"; /** * Fan-out support for the baseline vet. * * A from-scratch vet is CPU-bound and scales with component count, so a single * host is the bottleneck rather than the work being irreducible. This module * lets the component set be split across hosts and the resulting receipts * merged back into one prior lock, which the ordinary incremental assembly run * then consumes. * * The split is safe because a receipt carries no host-specific state. It is * exactly `{id, paths, treeSha256, verdict, analyzers, findings}` — all derived * from scanned content — and `decideComponentReuse` re-hashes the live tree and * re-checks the required-analyzer identity set before splicing anything. A * shard therefore cannot contribute a receipt for content the assembly host * does not itself hash to the same value; a mismatched or stale receipt is * rescanned rather than trusted. What sharding distributes is the *cost* of * producing receipts, never the authority to assert one. */ export interface ShardSelector { /** 1-based shard number. */ readonly index: number; /** Total number of shards. */ readonly total: number; } /** * Parse an `i/n` shard selector. Strict on purpose: a silently misparsed shard * would drop components from the fan-out and the assembly run would quietly * rescan them, turning a correctness bug into a mere slowdown that nobody * notices. Both parts must be plain positive integers and `i` must not exceed * `n`. */ export declare function parseShardSelector(value: string): ShardSelector; /** * Select this shard's components from a catalog by round-robin on catalog * order. Round-robin rather than contiguous blocks because component scan cost * is wildly uneven and correlated with position — the catalog groups large * runtime components together — so contiguous blocks would leave one host doing * most of the work. * * Sharding is applied per catalog, so every shard receives at least one * component from each source as long as `total` does not exceed the smaller * catalog's size. That matters because the evidence schema requires each source * to carry at least one component. */ export declare function shardCatalog(catalog: BaselineCatalog, shard: ShardSelector): BaselineCatalog; /** Largest shard count for which every catalog still yields a component. */ export declare function maxUsefulShards(catalogs: readonly BaselineCatalog[]): number; /** * Merge shard receipt bundles into one prior lock for the assembly run. * * Order-independent: the assembly run looks receipts up by component id and * re-verifies each one, so the merged component order is irrelevant to the * artifact it produces. */ export declare function mergeReceiptBundles(bundles: readonly BaselineEvidenceLock[]): BaselineEvidenceLock; /** Per-source coverage of a merged bundle against the catalogs it must cover. */ export interface ShardCoverage { readonly sourceId: string; readonly expected: number; readonly covered: number; readonly missing: readonly string[]; } /** * Report which catalog components no receipt bundle covers. Incomplete coverage * is not an error — the assembly run simply rescans what is missing — but it is * always worth saying out loud, because a silently-dropped shard would look * exactly like a slow assembly run. */ export declare function shardCoverage(catalogs: readonly BaselineCatalog[], merged: BaselineEvidenceLock): ShardCoverage[]; export declare function formatShardCoverage(coverage: readonly ShardCoverage[]): string[];