/** * Validate spawn readiness — unified pre-flight hygiene runner (T10451). * * Runs all 3 gates in parallel: * 1. Changeset lint (via scripts/lint-changesets.mjs) * 2. Changelog drift (CHANGELOG.md has current version header) * 3. Worktree location (cwd matches expected worktree path) * * The result is a VALUE, not a side effect (gh#1366). `runSpawnReadinessHygieneCli` * returns the structured result and additionally sets `process.exitCode` for the * bare `cleo hygiene` surface; it never calls `process.exit`, so every caller * MUST branch on the returned value. The previous contract — report failure by * setting `process.exitCode` and returning normally — read as "exits on failure" * to its caller in `release.ts`, which therefore ran on past a failed gate. * * @task T10451 * @task gh#1366 — readiness result is a value; envelope and exit code agree * @task gh#1367 — a timeout and a validation failure are different facts * @saga T10431 */ /** Severity level for a gate result. */ type Severity = 'error' | 'warn'; /** * Why a gate failed. * * Exists so a timeout is never reported as a validation failure (gh#1367). The * two facts imply different remedies: `validation` means "the checked artifact * is wrong", `timeout` means "we never finished checking it". Collapsing them * into one message told operators to repair changesets that were all valid. */ export type HygieneGateFailureReason = 'validation' | 'timeout' | 'not-found' | 'io-error'; /** Result from a single hygiene gate. */ export interface HygieneGateResult { /** Gate name. */ name: string; /** Whether the gate passed. */ passed: boolean; /** Human-readable message. */ message: string; /** Severity if failed. */ severity: Severity; /** Why the gate failed. Absent when `passed` is true. */ reason?: HygieneGateFailureReason; } /** Overall result from the spawn-readiness check. */ export interface SpawnReadinessResult { /** Per-gate results. */ gates: HygieneGateResult[]; /** True only if ALL gates passed, regardless of severity. */ allPassed: boolean; /** * True when at least one gate of severity `'error'` failed. * * This — not `allPassed` — is what a caller blocks on: a failed `'warn'` gate * is informational and must not stop a release. */ hasBlockingFailure: boolean; /** Names of the gates that failed at severity `'error'`. */ blockingGates: string[]; /** ISO timestamp of the check. */ checkedAt: string; } /** * Wall-clock bound for the changeset lint subprocess. * * Deliberately left at 10 s. gh#1367 argued for raising it from a measurement of * 91,061 ms over 275 entries, concluding the gate "is expected to fail on every * invocation, on every machine, indefinitely". That conclusion does not survive * re-measurement: the 91 s was taken while the repo lived on an ntfs-3g FUSE * mount, and it measured the filesystem, not this script. Re-measured * 2026-09-14 over 315 entries — MORE entries than the original run: * * btrfs (canonical /home checkout) 0.54 s * GitHub Actions runner 1.60 s * ntfs-3g mount, cold page cache 346.69 s * * On the two environments that actually run this gate, 10 s is 6–18x of * HEADROOM, not 9x of overrun. Widening the bound to accommodate a number we * can no longer reproduce would spend a real signal: at 10 s, a future timeout * means a genuine hang rather than a slow disk, which is exactly when the * operator most needs to be told the truth about it. * * The per-entry cost is not the driver either — parsing is ~0.21 ms/entry, so * even 10,000 changesets add ~2 s. Runtime here is dominated by module loading, * which is why `lint-changesets.mjs` imports the deep changesets module instead * of the core barrel. * * `CLEO_CHANGESET_LINT_TIMEOUT_MS` is the escape hatch for an environment * genuinely slower than both measurements above, so a degraded filesystem needs * a variable rather than a source edit. */ export declare const DEFAULT_CHANGESET_LINT_TIMEOUT_MS = 10000; /** Environment variable that overrides {@link DEFAULT_CHANGESET_LINT_TIMEOUT_MS}. */ export declare const CHANGESET_LINT_TIMEOUT_ENV = "CLEO_CHANGESET_LINT_TIMEOUT_MS"; /** * Resolve the changeset-lint timeout from the environment. * * An invalid override is REJECTED rather than silently replaced by the default: * a bound that quietly ignores what the operator set is how a gate ends up * measuring something nobody asked for. * * @param env - Environment to read (default: `process.env`). * @returns The resolved bound, or an error message when the override is invalid. */ export declare function resolveChangesetLintTimeoutMs(env?: NodeJS.ProcessEnv): { ok: true; ms: number; } | { ok: false; message: string; }; /** * Run the full spawn-readiness hygiene check. * * @param projectRoot - Absolute path to project root (default: process.cwd()). * @param worktreePath - Expected worktree path (optional). * @returns Structured result with per-gate details. */ export declare function runSpawnReadinessHygiene(projectRoot?: string, // CWD-OK: public API default — caller passes explicit root when invoked from non-cwd context worktreePath?: string): Promise; /** * CLI-friendly entry point. Prints results and RETURNS them. * * Sets `process.exitCode = 1` on a blocking failure so the bare * `cleo hygiene validate-spawn-readiness` surface still exits non-zero, but it * never calls `process.exit` and never throws. **Callers must branch on the * returned value** — that is the whole of gh#1366. It also no longer forces * `process.exitCode = 0` on success, which would have cleared a failure code * set by something else earlier in the process. * * The report goes to `report` (stdout by default). A command that prints its * own LAFS envelope on stdout passes a stderr writer, so stdout carries that * one envelope (ADR-086, T13322). * * @param projectRoot - Absolute path to project root. * @param worktreePath - Expected worktree path (optional). * @param report - Writes one report line. @defaultValue `console.log` * @returns The structured readiness result. */ export declare function runSpawnReadinessHygieneCli(projectRoot?: string, // CWD-OK: CLI entry point default — `cleo hygiene` invoked from project cwd worktreePath?: string, report?: (line: string) => void): Promise; export {}; //# sourceMappingURL=validate-spawn-readiness.d.ts.map