/** * Shard runner — drives N shard workers in parallel and collects their * serializable `ShardBuildResult` fragments. * * Each shard is built in its own child process (`graph-shard-worker`), so * heap is isolated per shard: N shards × per-shard budget ≈ total budget, * the same memory-scaling property the legacy `--workspace` runner has. * Concurrency is capped at `cpus()-1` by default. A worker that exits * non-zero is surfaced as a `ShardFailure` attributable to its shard id * rather than aborting the whole build. * * The spec is handed to the worker via a temp FILE (not argv) because a * shard can enumerate thousands of files, well past the OS argv limit. */ import type { Shard, ShardBuildResult, ShardFailureEvidence } from './shard-model.js'; import type { GraphLanguageAdapter } from '../../lang-adapter/types.js'; import type { CatalogRepo } from '../../persistence/catalog-repo.js'; import type { ResolutionMode } from '../../types.js'; /** * The machine-filterable failure taxonomy for a shard worker, stamped on the * parent's `graph.shard.runner.shard_failed` event (subprocess-correlation * telemetry spec, Failure taxonomy). Every value is LIVE — `timeout` became * emittable with the hard kill-timeout below (M3); there is no dead enum value. * * - `spawn` — the child process failed to spawn (`child.on('error')`). * - `exit_nonzero` — the child spawned but exited with a non-zero code. * - `stdout_parse` — the child exited 0 but its stdout was not valid JSON. * - `timeout` — the hard kill-timeout fired and SIGKILLed a hung child. * - `ipc_error` — reserved for the fork (live-engine) transport (Phase 2). */ export type FailureClass = 'spawn' | 'exit_nonzero' | 'stdout_parse' | 'timeout' | 'ipc_error'; /** Inputs for the sharded build: the shards to run plus the shared project root, CLI entry, and worker limits. */ export interface RunShardsInput { readonly shards: readonly Shard[]; /** Common project root — every fragment's filePaths resolve against it. */ readonly projectRoot: string; /** CLI entry script (`process.argv[1]`); children run `node graph-shard-worker `. */ readonly cliScript: string; /** Optional adapter id requested by the parent `graph --language ` run. */ readonly language?: string; readonly resolutionMode: ResolutionMode; /** Concurrency cap. Default: `max(1, cpus()-1)`. */ readonly concurrency?: number; /** * Hard wall-clock kill-timeout (ms) after which a hung shard worker is * SIGKILLed with `failureClass: 'timeout'` (M3). Defaults to * {@link SHARD_HARD_KILL_TIMEOUT_MS} (10 min) — the conservative production * floor. Exposed as an input ONLY so the timeout path is deterministically * exercisable in tests with a short value (the resilience spec, Q3/M3, will * later make it user-configurable); production never sets it. */ readonly hardKillTimeoutMs?: number; } /** A shard whose worker failed — attributable, non-fatal. */ export interface ShardFailure { readonly shardId: string; readonly exitCode: number; /** * The FULL captured stderr — drives the user-facing message and stays * UNTRUNCATED here (M4). Structured events expose only bounded presence and * length metadata; they never copy worker output into shared logs. */ readonly stderr: string; /** Machine-filterable failure taxonomy ({@link FailureClass}); absent on a clean exit. */ readonly failureClass?: FailureClass; /** Process signal reported by Node when the worker did not exit normally. */ readonly signal?: string; } /** Result of the sharded build: successful fragments plus any per-shard failures. */ export interface RunShardsOutput { readonly fragments: readonly ShardBuildResult[]; readonly failures: readonly ShardFailure[]; } /** Retain only a bounded stderr tail when projecting an internal worker failure. */ export declare function boundedShardFailureEvidence(failure: ShardFailure): ShardFailureEvidence; /** * Build every shard in a bounded parallel pool. Always resolves; per-shard * failures are collected in `failures` (never thrown) so one bad shard * doesn't sink the build. */ export declare function runShardsInParallel(input: RunShardsInput): Promise; /** Partition of a build's shards into reusable-from-cache vs needs-rebuild. */ export interface ShardWorkPlan { /** Fragments loaded verbatim from the per-shard cache — no worker runs. */ readonly cached: readonly ShardBuildResult[]; /** Shards whose files (or config/mode) changed — a worker must rebuild them. */ readonly toBuild: readonly Shard[]; } /** * Decide, per shard, whether its cached fragment is still valid (config * key + files fingerprint match) and can be reused without a worker, or * whether the shard must be rebuilt. This is the incremental-parse fix: * unchanged shards skip parse entirely. With `useCache=false` (or no * repo) every shard is rebuilt. * * Cheap by design — it stats each shard's files (fingerprint) and reads * each shard's config (cacheKey); no parsing, no worker spawn. */ export declare function planShardWork(shards: readonly Shard[], repo: CatalogRepo | null, adapter: GraphLanguageAdapter, resolutionMode: ResolutionMode, useCache: boolean): Promise; //# sourceMappingURL=shard-runner.d.ts.map