// Swarm convergence referee — the deterministic verdict surface the conductor consults. // // The swarm fires only under human-granted Construction autonomy, inside a live // Claude Code session. That session — the conductor — owns the fan-out (N parallel // Task calls, or an inline Dynamic Workflow when AIDLC_USE_SWARM=1) and the retry // loop. A bun subprocess cannot issue Task calls, so the worker-dispatch layer is // NOT here. What lives here is everything that must be deterministic: the // convergence verdict, the anti-tamper guard, the serialised merge-back, the audit // taxonomy, and the typed failure envelope. // // THE SPLIT (three concerns): the conductor owns fan-out + loop drive (knowledge); // this tool owns the convergence verdict + merge + audit (determinism); the human // grants autonomy and takes the baton on the envelope (judgement). // // THREE STATELESS SUBCOMMANDS (no iteration counter, no persisted state): // prepare --batch --units [--base ] [--concurrency ] // [--degraded-from ] [--repo ] // Fork an isolated git worktree per unit (aidlc-worktree create + // aidlc-bolt start --worktree) and emit SWARM_STARTED once for the units // whose worktrees were successfully prepared. // --repo (P7) selects the sibling repo the batch's worktrees fork inside (a // multi-repo intent requires it; single-repo infers the lone repo); the // resolved name is forwarded to every aidlc-worktree create + bolt start. // The anti-tamper baseline is each worktree's OWN git fork (HEAD) — nothing // is stored; check/finalize re-derive the pristine bytes with `git diff // --quiet HEAD`. Runs before any worker, so it cannot fold into check. // --degraded-from records a loud downgrade (AIDLC_USE_SWARM=1 but the // Workflow tool was unavailable, so the conductor ran the subagent floor): // emits SWARM_DEGRADED. The driver-SELECTION read (AIDLC_USE_SWARM) is // conductor-side — this tool only learns a degrade happened via the flag. // check --check-cmd [--test-file ] // Stateless single-unit verdict: the project's check command (exit 0 = green, // the AUTHORITATIVE signal — a worker's own success claim is never trusted) // plus an anti-tamper compare of the protected file against its forked-git // baseline. Prints {unit, converged, tampered, reason}; exits 0 iff the unit // is GENUINELY converged (green AND untampered), non-zero otherwise. Emits // no audit — it informs the conductor's retry decision (knowledge), it does // not commit anything. Same input → same verdict, however many times called. // finalize --batch --units --claimed --check-cmd // [--test-file ] [--reasons =,...] // The AUTHORITATIVE gate. The conductor's claimed-converged set is an // explicit input and the only thing finalize trusts from it. For each // claimed unit, RE-RUN the check (green + untampered) and, when the current // stage declares a reviewer, require that unit's matching post-BOLT_STARTED // REVIEW_COMPLETED receipt before any merge. A unit named in --claimed but // red or unreviewed on disk is refused the merge and lands in the failure // envelope (the lying-conductor guard). Serialised HOLD-MERGE merge-back of // the genuine passes only, then emit the full SWARM_* audit trail + the typed // envelope + exit 0/2. --reasons carries the conductor's // typed attribution for a DECLINED (unclaimed) unit — unsatisfiable / // budget-exhausted / cap-exhausted — recorded faithfully (the conductor // judges WHY a unit gave up; the tool only records it, never for a claimed // unit, whose reason is always the tool's own re-verify verdict). // // WHY STATELESS / NO CAP CONSTANT. "The cap" is three jobs on three concerns — the // verdict (determinism -> check), the retry decision (knowledge -> the conductor, // which judges "one more try vs unsatisfiable"), and the runaway backstop // (determinism -> the harness 8-block Stop-hook ceiling). A per-unit counter here // would make determinism do the knowledge job and is redundant on the other // drivers (the ultracode script's cap is its `for`-bound; /goal's is its // turn-clause). So this tool holds none of it: check is advisory, finalize is // authoritative (re-verifies at the merge gate), so a red unit cannot merge even // if the conductor lies or misremembers. // // COMPOSES existing tools, does NOT reimplement them: // - aidlc-worktree create -> the isolated git worktree per unit // - aidlc-bolt start --worktree -> state/audit/runtime-graph fork into it // - aidlc-bolt complete --merge -> the AIDLC-data merge back to the base // - aidlc-bolt release-merge -> release the existing per-Bolt HOLD-MERGE // lock before a serialised merge (idempotent — safe if never held). The merge // phase is serial (a one-at-a-time loop), so only one merge is ever in flight. // - aidlc-bolt fail -> close a failed unit's Bolt lifecycle // (BOLT_FAILED paired with the BOLT_STARTED that `start --worktree` emitted). import { spawnSync } from "node:child_process"; import { createHash, randomUUID } from "node:crypto"; import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { basename, dirname, join, posix, relative, resolve, sep } from "node:path"; import { fileURLToPath } from "node:url"; import { appendAuditEntry } from "./aidlc-audit.ts"; import { assertNoSymlinkInChainOrThrow, auditBlockField, auditShardDir, boltSlugForUnit, filterProducesByKind, filteredRawIndexEntries, findAllEvents, getField, isRegularFile, latestMainWorkflowStageRunFloor, latestMainWorkflowStageRunFloorForProject, parseArgs, parseSourceListing, readAuditShardEvents, readUnitSourceManifest, readUnitSourceSnapshot, readRegularFileNoFollowOrThrow, readStateFile, recordDir, relativeRecordDir, reviewArtifactFingerprint, reviewArtifactBytesSnapshot, reviewedSourceRef, resolveAuditWorktreePath, resolveBoltDag, resolveConstructionRepo, resolveProjectDir, resolveStage, sourceListingSha256, shapeSourceSnapshotIndex, sourceClaimCovers, sourceListingEntriesEqual, type SourceClaimModel, UNBINDABLE_FINGERPRINT, validateUnitName, worktreeAuditFilePath, worktreePath, worktreeRuntimeGraphPath, workspaceSourceEmbeddedGitPaths, workspaceSourceFingerprint as worktreeSourceFingerprint, workspaceSourceListing, workspaceSourceSnapshotPaths, worktreeStateFilePath, worktreeReviewAttemptProjection, writeBufferAtomic, } from "./aidlc-lib.ts"; import { compiledExecutable } from "./aidlc-runtime-paths.ts"; import { beginCodeGeneration, evaluateCodeGenerationApproval, } from "./aidlc-testing-posture.ts"; const TOOLS_DIR = dirname(fileURLToPath(import.meta.url)); // The typed reason enum the conductor branches on. budget-exhausted stays valid // for the ultracode driver's token ceiling; cap-exhausted is the loop-ended- // without-convergence sense; error covers a tamper / lying-claim / plumbing fault. type FailureReason = "unsatisfiable" | "budget-exhausted" | "cap-exhausted" | "error"; // The driver the conductor degraded away from (records the loud downgrade). type DriverName = "subagent" | "ultracode"; const DRIVER_VALUES: DriverName[] = ["subagent", "ultracode"]; // The typed reasons the conductor may attribute to a DECLINED unit (one it did // not claim converged). Judging WHICH applies is the conductor's knowledge call // (D-I) — the tool only records it, exactly as it records --claimed and // --degraded-from. `error` is excluded: it is the tool's OWN verdict for a // claimed-but-red / tampered unit, never a conductor-supplied attribution. const DECLINED_REASONS: FailureReason[] = ["unsatisfiable", "budget-exhausted", "cap-exhausted"]; interface UnitResult { unit: string; status: "converged" | "failed"; reason?: FailureReason; detail?: string; tampered?: boolean; } interface SourceBinding { fingerprint: string; commit: string; } interface ReceiptCheck { error: string | null; artifactFingerprint?: string; sourceFingerprint?: string; unitSourceFingerprint?: string; } interface ReviewedRecordSnapshotEntry { logicalPath: string; bytes: Buffer | null; } interface ReviewedRecordSnapshot { entries: ReviewedRecordSnapshotEntry[]; } interface SwarmAttemptStamp { stage: string; floor: string; } // --- Sibling-tool composition (synchronous; these calls are quick) ---------- interface ToolRun { ok: boolean; stdout: string; stderr: string; } function runTool(toolFile: string, args: string[], projectDir: string): ToolRun { const executable = compiledExecutable(); const noun = toolFile.replace(/^aidlc-/, "").replace(/\.ts$/, ""); const command = executable ? [executable, "engine", noun, ...args, "--project-dir", projectDir] : [process.execPath, join(TOOLS_DIR, toolFile), "--project-dir", projectDir, ...args]; const result = spawnSync(command[0], command.slice(1), { encoding: "utf-8", cwd: projectDir, timeout: 60_000, env: { ...process.env, AIDLC_PROJECT_DIR: projectDir }, }); return { ok: result.status === 0, stdout: result.stdout ?? "", stderr: result.stderr ?? "", }; } // --- The deterministic verdict primitives ----------------------------------- // Tool-owned convergence signal. Running the project's check command in the // worktree (exit 0 = green) is the AUTHORITATIVE green check — a worker's own // claim of success is never trusted (it could fake a pass). // // Run via a shell rather than a hardcoded `bash` argv, because `bash` is ENOENT // on native Windows PowerShell — the old form launched bash with a -c argument // and made every convergence check spuriously fail there. We pick the shell so the // command runs on every platform AND keeps its original interpreter on POSIX: // - win32: shell:true → cmd.exe (bash is unavailable; there is no other // choice, and a Construction check command on Windows is written for it). // - POSIX with /bin/bash present: shell:"/bin/bash" → preserves the exact // bash interpreter the old code used, so a bash-only check command // (`[[ ]]`, process substitution, arrays) keeps working. Bare shell:true // would route through /bin/sh, which on dash-default distros (Debian/Ubuntu) // would regress those bashisms — so we keep bash where it exists. // - POSIX without /bin/bash: shell:true → /bin/sh (best available). // Exit-code semantics (0 = converged) and the 60s timeout are unchanged across // all three. // // checkCmd is shell-interpreted, so shell metacharacters in it are honoured — // that is acceptable here: the swarm only fires under human-granted // Construction autonomy inside a live session, and checkCmd is the user's own // project check command (a trusted input), not attacker-controlled. (It was // already shell-interpreted under the old `bash -c` form — no new surface.) function checkConverged(cwd: string, checkCmd: string): boolean { const shell = process.platform !== "win32" && existsSync("/bin/bash") ? "/bin/bash" : true; const result = spawnSync(checkCmd, { cwd, encoding: "utf-8", timeout: 60_000, shell, }); return result.status === 0; } // Anti-tamper, re-derived from the worktree's own git fork (stateless): the // protected file's pristine bytes are its content at HEAD (the fork point), so a // worker edit shows as a working-tree change. `git diff --quiet HEAD -- ` // exits 0 when unchanged, 1 when changed; any other status (e.g. 128 — path not // tracked at HEAD) is not a confirmed tamper, so only status 1 trips the guard. function fileTampered(cwd: string, relPath: string): boolean { const result = spawnSync("git", ["diff", "--quiet", "HEAD", "--", relPath], { cwd, encoding: "utf-8", timeout: 60_000, }); return result.status === 1; } interface Verdict { exists: boolean; converged: boolean; tampered: boolean; confineError?: string; } // Compute a unit's stateless verdict from on-disk state alone. Re-derives the // worktree path from (projectDir, unit) — no stored handle — so check and // finalize agree without sharing state. function verdictFor( unit: string, projectDir: string, checkCmd: string, testFile?: string ): Verdict { const wt = worktreePath(projectDir, swarmBoltSlug(unit)); if (!existsSync(wt)) { return { exists: false, converged: false, tampered: false }; } const converged = checkConverged(wt, checkCmd); let tampered = false; let confineError: string | undefined; if (testFile) { // Confine the path inside the unit's worktree — a `../` escape would point // the guard at a file the worker never touched and silently DISABLE it, so // reject it as a configuration error rather than ship a false "untampered". const candidate = resolve(wt, testFile); const root = resolve(wt) + sep; if (!candidate.startsWith(root)) { confineError = `--test-file resolves outside the unit worktree: ${testFile}`; } else { tampered = fileTampered(wt, testFile); } } return { exists: true, converged, tampered, confineError }; } interface ReviewerRequirement { stage: string; reviewer: string | null; reviewClass: "adversarial" | "advisory"; maxIterations: number; error?: string; } function reviewerRequirement(projectDir: string): ReviewerRequirement { try { const stage = getField(readStateFile(projectDir), "Current Stage")?.trim() ?? ""; if (!stage) { return { stage: "", reviewer: null, reviewClass: "adversarial", maxIterations: 2, error: "cannot resolve reviewer requirement: Current Stage is empty", }; } const definition = resolveStage(stage); if (!definition) { return { stage, reviewer: null, reviewClass: "adversarial", maxIterations: 2, error: `cannot resolve reviewer requirement: stage "${stage}" is absent from the stage graph`, }; } const reviewClass = definition.review_class ?? "adversarial"; return { stage, reviewer: definition.reviewer?.trim() || null, reviewClass, maxIterations: reviewClass === "advisory" ? 1 : definition.reviewer_max_iterations ?? 2, }; } catch (e) { return { stage: "", reviewer: null, reviewClass: "adversarial", maxIterations: 2, error: `cannot resolve reviewer requirement: ${e instanceof Error ? e.message : String(e)}`, }; } } // A claimed autonomous unit must prove its configured review happened inside // this Bolt attempt. BOLT_STARTED is a stronger floor than STAGE_STARTED here: // it excludes a matching receipt inherited from main when prepare forked the // worktree, while preserving a receipt across a merge retry on that worktree. function reviewerReceiptError( projectDir: string, unit: string, stage: string, reviewer: string, reviewClass: "adversarial" | "advisory", maxIterations: number, ): ReceiptCheck { const boltSlug = swarmBoltSlug(unit); const wt = worktreePath(projectDir, boltSlug); const creationRows = readAuditShardEvents(projectDir) .filter( (row) => row.event === "WORKTREE_CREATED" && auditBlockField(row.block, "Bolt slug") === boltSlug && ( auditBlockField(row.block, "Worktree path") !== null && resolveAuditWorktreePath( projectDir, auditBlockField(row.block, "Worktree path") as string, ) === wt ), ) .sort((a, b) => { if (a.timestamp !== b.timestamp) return a.timestamp < b.timestamp ? -1 : 1; if (a.shard === b.shard) return a.pos - b.pos; return a.shard < b.shard ? -1 : 1; }); const creationBlock = creationRows.at(-1)?.block ?? null; const creationBaseCommit = creationBlock === null ? null : auditBlockField(creationBlock, "Base commit"); const creationBaseListing = creationBlock === null ? null : auditBlockField(creationBlock, "Base Source Listing"); const creationModern = creationBaseCommit !== null || creationBaseListing !== null; const reviewAttempt = worktreeReviewAttemptProjection( wt, readAuditShardEvents(wt), { boltSlug, unit, stage, reviewer, reviewClass, maxIterations, }, ); if (reviewAttempt.boltStart === null) { return { error: `claimed converged but worktree audit has no BOLT_STARTED boundary for unit "${unit}"`, }; } const boltStartBlock = reviewAttempt.boltStart.block; const baseCommit = auditBlockField(boltStartBlock, "Base commit"); const baseSourceListing = auditBlockField(boltStartBlock, "Base Source Listing"); if ( creationModern && (baseCommit !== creationBaseCommit || baseSourceListing !== creationBaseListing) ) { return { error: `claimed converged but modern WORKTREE_CREATED attestation was not propagated to BOLT_STARTED for unit "${unit}"`, }; } let verifiedBaseListing: Map | null = null; if (baseCommit !== null) { const metaPath = join(wt, ".aidlc", "worktree-meta.json"); let meta: unknown; try { meta = JSON.parse(readFileSync(metaPath, "utf-8")); } catch { return { error: `claimed converged but worktree base-commit metadata is missing or malformed for unit "${unit}"` }; } if ( typeof meta !== "object" || meta === null || Array.isArray(meta) || (meta as Record).baseCommit !== baseCommit || baseSourceListing === null || (meta as Record).baseSourceListing !== baseSourceListing ) { return { error: `claimed converged but worktree Base commit/source listing does not match its BOLT_STARTED attestation for unit "${unit}"` }; } const listingPath = join(wt, ".aidlc", "base-source-listing.tsv"); let serialized: string; try { serialized = readFileSync(listingPath, "utf-8"); } catch { return { error: `claimed converged but worktree base source listing is missing for unit "${unit}"` }; } if (`sha256:${sourceListingSha256(serialized)}` !== baseSourceListing) { return { error: `claimed converged but worktree base source listing hash does not match for unit "${unit}"` }; } verifiedBaseListing = parseSourceListing(serialized); if (verifiedBaseListing === null) { return { error: `claimed converged but worktree base source listing is malformed for unit "${unit}"` }; } } const latestTerminal = reviewAttempt.terminal === null ? null : { block: reviewAttempt.terminal.event.block, binding: reviewAttempt.terminal.binding, }; if (latestTerminal === null) { return { error: `claimed converged but no terminal REVIEW_COMPLETED for stage "${stage}", ` + `unit "${unit}", reviewer "${reviewer}" exists after this Bolt started`, }; } const definition = resolveStage(stage); const recordedArtifactFp = auditBlockField(latestTerminal.block, "Artifact Fingerprint"); const currentArtifactFp = definition ? reviewArtifactFingerprint(wt, definition, unit, { requireRequiredArtifacts: true, }) : null; if ( recordedArtifactFp === null || !/^sha256:[0-9a-f]{64}$/.test(recordedArtifactFp) || currentArtifactFp === null || recordedArtifactFp !== currentArtifactFp ) { return { error: `claimed converged but no terminal REVIEW_COMPLETED for stage "${stage}", ` + `unit "${unit}", reviewer "${reviewer}" with a current artifact fingerprint exists after this Bolt started`, }; } if (!definition?.workspace_requires) { return { error: null, artifactFingerprint: recordedArtifactFp }; } const recordedSourceFp = auditBlockField(latestTerminal.block, "Source Fingerprint"); if (process.env.AIDLC_SKIP_SOURCE_FRESHNESS === "1") { return { error: null, artifactFingerprint: recordedArtifactFp }; } if (recordedSourceFp === null) { if (baseCommit === null) { return { error: null, artifactFingerprint: recordedArtifactFp }; } return { error: `claimed converged but modern worktree unit "${unit}" has no Source Fingerprint; ` + `re-run the reviewer in the worktree and record a fresh verdict before finalizing`, }; } const currentSourceFp = worktreeSourceFingerprint(wt); if ( recordedSourceFp === UNBINDABLE_FINGERPRINT || currentSourceFp === null || currentSourceFp !== recordedSourceFp ) { return { error: `claimed converged but the reviewed source no longer matches its worktree's ` + `fingerprint for stage "${stage}", unit "${unit}" (source-fingerprint mismatch); ` + `re-invoke the reviewer against the current worktree source and record a fresh ` + `verdict before finalizing`, }; } // Pre-upgrade worktrees have no attested base commit and retain migration // fail-open behavior. Modern worktrees must validate the exact unit binding // that the reviewer saw before trusting its claims for footprint coverage. let unitSourceFingerprint: string | undefined; if (baseCommit !== null) { const recordedUnitFp = auditBlockField( latestTerminal.block, "Unit Source Fingerprint", ); const bindingBypass = auditBlockField(latestTerminal.block, "Unit Source Binding Bypass") === "true"; if (bindingBypass || recordedUnitFp === null || recordedUnitFp === UNBINDABLE_FINGERPRINT) { return { error: `claimed converged but unit "${unit}" has no verifiable modern Unit Source Fingerprint; ` + `re-run the reviewer in the worktree and record a fresh verdict before finalizing`, }; } unitSourceFingerprint = recordedUnitFp; const manifest = readUnitSourceManifest(wt, stage, unit, { worktreeRelative: true, }); const snapshot = readUnitSourceSnapshot(wt, stage, unit, recordedUnitFp); if ( !manifest.ok || snapshot === null || snapshot.manifestSha256 !== manifest.rawBytesSha256 ) { return { error: `claimed converged but unit "${unit}"'s reviewed source manifest binding is missing, ` + `corrupt, or no longer matches its review; re-run the reviewer in the worktree and ` + `record a fresh verdict before finalizing`, }; } const reviewedClaims: SourceClaimModel = { claims: manifest.claims, prefixes: manifest.prefixes, }; const idx = join(tmpdir(), `aidlc-swarm-footprint-${process.pid}-${randomUUID().slice(0, 8)}`); const env = { ...process.env, GIT_INDEX_FILE: idx }; const git = (args: string[]) => spawnSync("git", ["-C", wt, ...args], { env, encoding: "utf-8", maxBuffer: 512 * 1024 * 1024, }); try { if (git(["read-tree", "HEAD"]).status !== 0 || git(["add", "-A"]).status !== 0) { return { error: `claimed converged but the worktree footprint could not be computed for unit "${unit}"` }; } if (shapeSourceSnapshotIndex(wt, idx, true) === null) { return { error: `claimed converged but the reviewed source boundary could not be applied to unit "${unit}"'s footprint`, }; } const tree = git(["write-tree"]); if (tree.status !== 0 || !tree.stdout.trim()) return { error: `claimed converged but the worktree footprint tree could not be written for unit "${unit}"` }; const diff = git([ "diff", "--name-only", "-z", "--no-renames", baseCommit, tree.stdout.trim(), ]); if (diff.status !== 0) return { error: `claimed converged but the worktree footprint could not be compared for unit "${unit}"` }; const outside = new Set( diff.stdout .split("\0") .filter(Boolean), ); const currentListing = workspaceSourceListing(wt); if (verifiedBaseListing === null || currentListing === null) { return { error: `claimed converged but raw-aware worktree footprint evidence is unavailable for unit "${unit}"` }; } for (const [path, oid] of verifiedBaseListing) { if (!sourceListingEntriesEqual(currentListing.get(path), oid)) { outside.add(path.slice(path.indexOf("\0") + 1)); } } for (const path of currentListing.keys()) { if (!verifiedBaseListing.has(path)) outside.add(path.slice(path.indexOf("\0") + 1)); } const outsideClaims = [...outside] .filter((path) => !sourceClaimCovers(`\0${path}`, reviewedClaims)); if (outsideClaims.length > 0) { const rendered = outsideClaims.slice(0, 10).join(", ") + (outsideClaims.length > 10 ? ` … and ${outsideClaims.length - 10} more` : ""); return { error: `claimed converged but the worktree wrote application-source paths outside unit "${unit}"'s ` + `source manifest (${rendered}); update construction/${unit}/code-generation/source-manifest.json ` + `in the worktree, re-run the reviewer there, and record a fresh verdict before finalizing`, }; } } finally { rmSync(idx, { force: true }); } } return { error: null, artifactFingerprint: recordedArtifactFp, sourceFingerprint: recordedSourceFp, unitSourceFingerprint, }; } function captureReviewedRecordSnapshot( projectDir: string, unit: string, stage: NonNullable>, receipt: ReceiptCheck, ): { snapshot?: ReviewedRecordSnapshot; error?: string } { const wt = worktreePath(projectDir, swarmBoltSlug(unit)); const artifacts = reviewArtifactBytesSnapshot(wt, stage, unit, { requireRequiredArtifacts: true, captureBytes: true, }); if (artifacts === null) { return { error: `cannot snapshot required record artifacts for unit "${unit}"` }; } if ( receipt.artifactFingerprint !== undefined && artifacts.fingerprint !== receipt.artifactFingerprint ) { return { error: `record artifacts changed while finalizing unit "${unit}"; ` + `re-run the reviewer against the current artifacts`, }; } const entries: ReviewedRecordSnapshotEntry[] = []; for (const artifact of artifacts.entries) { if (artifact.state === "not-file") { return { error: `record artifact ${artifact.logicalPath} for unit "${unit}" is not a regular file`, }; } if (artifact.state === "file" && artifact.bytes === undefined) { return { error: `cannot capture record artifact ${artifact.logicalPath} for unit "${unit}"`, }; } entries.push({ logicalPath: artifact.logicalPath, bytes: artifact.state === "file" ? artifact.bytes! : null, }); } if (receipt.unitSourceFingerprint !== undefined) { const wtRecord = recordDir(wt); if (wtRecord === null) { return { error: `cannot resolve reviewed source evidence for unit "${unit}"` }; } const manifest = readUnitSourceManifest(wt, stage.slug, unit, { worktreeRelative: true, }); const snapshot = readUnitSourceSnapshot( wt, stage.slug, unit, receipt.unitSourceFingerprint, ); if ( !manifest.ok || snapshot === null || snapshot.manifestSha256 !== manifest.rawBytesSha256 ) { return { error: `reviewed source evidence changed while finalizing unit "${unit}"; ` + `re-run the reviewer`, }; } const manifestPath = join( wtRecord, "construction", unit, stage.slug, "source-manifest.json", ); let manifestBytes: Buffer; try { manifestBytes = readRegularFileNoFollowOrThrow( assertNoSymlinkInChainOrThrow( realpathSync(wt), relative(wt, manifestPath), ), `source manifest for unit ${unit}`, ); } catch { return { error: `cannot capture reviewed source evidence for unit "${unit}"` }; } if ( createHash("sha256").update(manifestBytes).digest("hex") !== manifest.rawBytesSha256 ) { return { error: `reviewed source evidence changed while finalizing unit "${unit}"; ` + `re-run the reviewer`, }; } entries.push( { logicalPath: `construction/${unit}/${stage.slug}/source-manifest.json`, bytes: manifestBytes, }, ); } return { snapshot: { entries } }; } function mergeReviewedRecordSnapshot( projectDir: string, unit: string, snapshot: ReviewedRecordSnapshot, ): string | null { const record = recordDir(projectDir); if (record === null) return `cannot resolve the main record directory for unit "${unit}"`; let root: string; try { root = assertNoSymlinkInChainOrThrow( realpathSync(projectDir), relative(projectDir, record), ); if (!lstatSync(root).isDirectory()) { return `main record path is not a directory for unit "${unit}"`; } } catch (error) { return ( `cannot validate the main record directory for unit "${unit}": ` + `${error instanceof Error ? error.message : String(error)}` ); } const operations: Array<{ target: string; logicalPath: string; next: Buffer | null; previous: Buffer | null; }> = []; for (const entry of snapshot.entries) { try { const target = assertNoSymlinkInChainOrThrow(root, entry.logicalPath); const previous = existsSync(target) ? readRegularFileNoFollowOrThrow( target, `existing record artifact ${entry.logicalPath}`, ) : null; operations.push({ target, logicalPath: entry.logicalPath, next: entry.bytes, previous, }); } catch (error) { return ( `record artifact preflight failed for ${entry.logicalPath}: ` + `${error instanceof Error ? error.message : String(error)}` ); } } const applied: typeof operations = []; try { for (const operation of operations) { if (operation.next === null) { rmSync(operation.target, { force: true }); applied.push(operation); } else { mkdirSync(dirname(operation.target), { recursive: true }); writeBufferAtomic(operation.target, operation.next); applied.push(operation); if ( process.env.AIDLC_TEST === "1" && process.env.AIDLC_TEST_RECORD_VERIFY_FAIL === operation.logicalPath ) { throw new Error( `injected verification failure for ${operation.logicalPath}`, ); } if ( !readRegularFileNoFollowOrThrow( operation.target, `landed record artifact ${operation.logicalPath}`, ).equals(operation.next) ) { throw new Error(`verification failed for ${operation.logicalPath}`); } } } } catch (error) { const rollbackErrors: string[] = []; for (const operation of [...applied].reverse()) { try { if (operation.previous === null) { rmSync(operation.target, { force: true }); } else { mkdirSync(dirname(operation.target), { recursive: true }); writeBufferAtomic(operation.target, operation.previous); } } catch (rollbackError) { rollbackErrors.push( `${operation.logicalPath}: ${ rollbackError instanceof Error ? rollbackError.message : String(rollbackError) }`, ); } } return ( `record artifact transaction failed for unit "${unit}": ` + `${error instanceof Error ? error.message : String(error)}` + (rollbackErrors.length > 0 ? `; rollback failed for ${rollbackErrors.join(", ")}` : "") ); } return null; } // Materialize the reviewed application bytes as an immutable commit without // moving the Bolt branch. The temporary index starts from HEAD, overlays the // worktree, then restores framework-owned paths from HEAD so the later source // merge carries application source only. Recompute the fingerprint after the // object is written to close a concurrent-edit window; the validated value is // the one carried to the convergence row. function recoverableSubmoduleUrls( repoDir: string, ): Map | null { const modulesPath = join(repoDir, ".gitmodules"); if (!existsSync(modulesPath)) return new Map(); const paths = spawnSync( "git", [ "-C", repoDir, "config", "-f", ".gitmodules", "--get-regexp", "^submodule\\..*\\.path$", ], { encoding: "utf-8", maxBuffer: 512 * 1024 * 1024 }, ); if (paths.status === 1) return new Map(); if (paths.status !== 0) return null; const recoverable = new Map(); for (const line of paths.stdout.split(/\r?\n/)) { if (!line) continue; const separator = line.indexOf(" "); if (separator <= 0) return null; const key = line.slice(0, separator); const path = line.slice(separator + 1).trim().replace(/\\/g, "/"); if (!key.endsWith(".path") || !path) return null; const urlKey = `${key.slice(0, -".path".length)}.url`; const url = spawnSync( "git", ["-C", repoDir, "config", "-f", ".gitmodules", "--get", urlKey], { encoding: "utf-8", maxBuffer: 512 * 1024 * 1024 }, ); if (url.status !== 0 || !url.stdout.trim()) continue; recoverable.set(path, url.stdout.trim()); } return recoverable; } function configuredParentRemoteUrl(repoDir: string): string | null { const branch = spawnSync( "git", ["-C", repoDir, "symbolic-ref", "--quiet", "--short", "HEAD"], { encoding: "utf-8", maxBuffer: 512 * 1024 * 1024 }, ); if (branch.status === 0 && branch.stdout.trim()) { const remoteName = spawnSync( "git", [ "-C", repoDir, "config", "--get", `branch.${branch.stdout.trim()}.remote`, ], { encoding: "utf-8", maxBuffer: 512 * 1024 * 1024 }, ); if ( remoteName.status === 0 && remoteName.stdout.trim() && remoteName.stdout.trim() !== "." ) { const remoteUrl = spawnSync( "git", [ "-C", repoDir, "config", "--get", `remote.${remoteName.stdout.trim()}.url`, ], { encoding: "utf-8", maxBuffer: 512 * 1024 * 1024 }, ); if (remoteUrl.status === 0 && remoteUrl.stdout.trim()) { return remoteUrl.stdout.trim(); } } } const origin = spawnSync( "git", ["-C", repoDir, "config", "--get", "remote.origin.url"], { encoding: "utf-8", maxBuffer: 512 * 1024 * 1024 }, ); return origin.status === 0 && origin.stdout.trim() ? origin.stdout.trim() : null; } function resolveRelativeSubmoduleUrl( repoDir: string, metadataUrl: string, ): string | null { if (!metadataUrl.startsWith("./") && !metadataUrl.startsWith("../")) { return metadataUrl; } const parentUrl = configuredParentRemoteUrl(repoDir); if (!parentUrl) return null; if (/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(parentUrl)) { try { const base = parentUrl.endsWith("/") ? parentUrl : `${parentUrl}/`; return new URL(metadataUrl, base).toString(); } catch { return null; } } if ( !/^[A-Za-z]:[\\/]/.test(parentUrl) && /^[^/\\:]+:.+/.test(parentUrl) ) { const colon = parentUrl.indexOf(":"); const host = parentUrl.slice(0, colon); const remotePath = parentUrl.slice(colon + 1); return `${host}:${posix.normalize(`${remotePath}/${metadataUrl}`)}`; } return resolve(parentUrl, metadataUrl); } const NEW_GITLINK_RECOVERY_BUDGET_MS = 30_000; const NEW_GITLINK_RECOVERY_COMMAND_TIMEOUT_MS = 15_000; const NEW_GITLINK_RECOVERY_PROOF_CAP = 32; interface NewGitlinkRecoveryBudget { budgetMs: number; commandTimeoutMs: number; deadlineMs: number | null; proofCap: number; proofsStarted: number; } function positiveIntegerEnv(name: string, fallback: number): number { const value = process.env[name]; return value && /^[1-9][0-9]*$/.test(value) ? Number(value) : fallback; } function newGitlinkRecoveryBudget(): NewGitlinkRecoveryBudget { return { budgetMs: positiveIntegerEnv( "AIDLC_TEST_NEW_GITLINK_RECOVERY_BUDGET_MS", NEW_GITLINK_RECOVERY_BUDGET_MS, ), commandTimeoutMs: positiveIntegerEnv( "AIDLC_TEST_NEW_GITLINK_RECOVERY_COMMAND_TIMEOUT_MS", NEW_GITLINK_RECOVERY_COMMAND_TIMEOUT_MS, ), deadlineMs: null, proofCap: positiveIntegerEnv( "AIDLC_TEST_NEW_GITLINK_RECOVERY_PROOF_CAP", NEW_GITLINK_RECOVERY_PROOF_CAP, ), proofsStarted: 0, }; } function remainingNewGitlinkRecoveryMs( budget: NewGitlinkRecoveryBudget, ): number | null { if (budget.deadlineMs === null) { budget.deadlineMs = Date.now() + budget.budgetMs; } const remaining = budget.deadlineMs - Date.now(); return remaining <= 0 ? null : Math.min(budget.commandTimeoutMs, remaining); } function newGitlinkRecoveryError( repoDir: string, subDir: string, path: string, metadataUrl: string, commit: string, budget: NewGitlinkRecoveryBudget, ): string | null { if (budget.proofsStarted >= budget.proofCap) { return `new submodule recovery proof cap exceeded (${budget.proofCap} per finalize)`; } const lsRemoteTimeout = remainingNewGitlinkRecoveryMs(budget); if (lsRemoteTimeout === null) { return `new submodule recovery deadline exceeded (${budget.budgetMs}ms cumulative per finalize)`; } budget.proofsStarted += 1; const endpoint = resolveRelativeSubmoduleUrl(repoDir, metadataUrl); if (!endpoint) { return `cannot resolve .gitmodules recovery URL for new submodule ${path}`; } if (metadataUrl.startsWith("./") || metadataUrl.startsWith("../")) { const origin = spawnSync( "git", ["-C", subDir, "remote", "get-url", "origin"], { encoding: "utf-8", maxBuffer: 512 * 1024 * 1024 }, ); const normalize = (value: string): string => value.trim().replace(/\\/g, "/").replace(/\/+$/, ""); if ( origin.status !== 0 || normalize(origin.stdout) !== normalize(endpoint) ) { return `new submodule ${path} origin does not match its resolved .gitmodules recovery URL`; } } const advertised = spawnSync( "git", ["ls-remote", endpoint, "HEAD", "refs/heads/*", "refs/tags/*"], { encoding: "utf-8", env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }, maxBuffer: 512 * 1024 * 1024, timeout: lsRemoteTimeout, }, ); if (advertised.status !== 0) { if ( budget.deadlineMs !== null && Date.now() >= budget.deadlineMs ) { return `new submodule recovery deadline exceeded (${budget.budgetMs}ms cumulative per finalize)`; } return `new submodule ${path} recovery endpoint is unavailable`; } const advertisedRefs = new Set(); for (const line of advertised.stdout.split(/\r?\n/)) { if (!line) continue; const [oid, ref] = line.split(/\s+/, 2); if (!/^[0-9a-f]{40,64}$/.test(oid) || !ref) continue; const baseRef = ref.endsWith("^{}") ? ref.slice(0, -3) : ref; if ( baseRef !== "HEAD" && !baseRef.startsWith("refs/heads/") && !baseRef.startsWith("refs/tags/") ) { continue; } if (!ref.endsWith("^{}")) advertisedRefs.add(ref); } if (advertisedRefs.size === 0) { return `new submodule ${path} recovery endpoint advertises no cloneable refs`; } if (advertisedRefs.size > 10_000) { return `new submodule ${path} recovery endpoint advertises too many refs`; } const recoveryRefspecs = [...advertisedRefs].sort().map((ref) => { if (ref === "HEAD") return "+HEAD:refs/aidlc/recovery/HEAD"; if (ref.startsWith("refs/heads/")) { return `+${ref}:refs/aidlc/recovery/heads/${ref.slice("refs/heads/".length)}`; } return `+${ref}:refs/aidlc/recovery/tags/${ref.slice("refs/tags/".length)}`; }); const recoveryRefspecInput = `${recoveryRefspecs.join("\n")}\n`; if (Buffer.byteLength(recoveryRefspecInput, "utf-8") > 1024 * 1024) { return `new submodule ${path} recovery endpoint refspecs exceed the size budget`; } const recoveryRepo = mkdtempSync( join(tmpdir(), `aidlc-submodule-recovery-${process.pid}-`), ); try { const initialized = spawnSync( "git", ["-C", recoveryRepo, "init", "--bare", "-q"], { encoding: "utf-8", maxBuffer: 512 * 1024 * 1024 }, ); if (initialized.status !== 0) { return `cannot initialize recovery proof for new submodule ${path}`; } const fetchTimeout = remainingNewGitlinkRecoveryMs(budget); if (fetchTimeout === null) { return `new submodule recovery deadline exceeded (${budget.budgetMs}ms cumulative per finalize)`; } const fetched = spawnSync( "git", [ "-C", recoveryRepo, "fetch", "--quiet", "--no-tags", "--no-write-fetch-head", "--filter=blob:none", "--stdin", endpoint, ], { encoding: "utf-8", env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }, input: recoveryRefspecInput, maxBuffer: 512 * 1024 * 1024, timeout: fetchTimeout, }, ); if (fetched.status !== 0) { if ( budget.deadlineMs !== null && Date.now() >= budget.deadlineMs ) { return `new submodule recovery deadline exceeded (${budget.budgetMs}ms cumulative per finalize)`; } return `cannot fetch advertised recovery history for new submodule ${path}`; } const recovered = spawnSync( "git", ["-C", recoveryRepo, "cat-file", "-e", `${commit}^{commit}`], { encoding: "utf-8", maxBuffer: 512 * 1024 * 1024 }, ); if (recovered.status === 0) return null; } finally { rmSync(recoveryRepo, { recursive: true, force: true }); } return `new submodule ${path} commit ${commit} is not reachable from an advertised recovery ref`; } function initializedSubmoduleSourceError( subDir: string, displayPath: string, visited: Set, depth = 1, ): string | null { if (depth > 64) { return `cannot verify initialized submodule ${displayPath}: nesting exceeds 64 levels`; } let real: string; try { real = realpathSync(subDir); } catch { return `cannot resolve initialized submodule ${displayPath}`; } if (visited.has(real)) return null; visited.add(real); if (visited.size > 10_000) { return "cannot verify initialized submodules: more than 10000 checkouts are materialized"; } const status = spawnSync( "git", [ "-C", subDir, "status", "--porcelain=v1", "-z", "--untracked-files=all", "--ignore-submodules=none", ], { encoding: "utf-8", maxBuffer: 512 * 1024 * 1024 }, ); if (status.status !== 0) { return `cannot verify reviewed submodule state for ${displayPath}`; } if (status.stdout.length > 0) { return ( `cannot bind dirty initialized submodule ${displayPath}; commit or discard its reviewed ` + "changes, then re-run the reviewer before finalizing" ); } const sourcePaths = workspaceSourceSnapshotPaths(subDir, false); if (sourcePaths === null) { return `cannot resolve the reviewed source boundary for initialized submodule ${displayPath}`; } if (sourcePaths.length > 0) { const ignored = spawnSync( "git", ["-C", subDir, "check-ignore", "-z", "--stdin"], { input: `${sourcePaths.join("\0")}\0`, encoding: "utf-8", maxBuffer: 512 * 1024 * 1024, }, ); if (ignored.status !== 0 && ignored.status !== 1) { return `cannot verify ignored reviewed source for initialized submodule ${displayPath}`; } if (ignored.status === 0 && ignored.stdout.length > 0) { return ( `cannot bind dirty initialized submodule ${displayPath}; ignored application source ` + "is part of the reviewed fingerprint but cannot be represented by the parent gitlink" ); } } const gitlinks = spawnSync( "git", ["-C", subDir, "ls-files", "-s", "-z"], { encoding: "utf-8", maxBuffer: 512 * 1024 * 1024 }, ); if (gitlinks.status !== 0) { return `cannot enumerate nested submodules for ${displayPath}`; } const trackedNestedPaths = new Set(); for (const record of gitlinks.stdout.split("\0")) { if (!record.startsWith("160000 ")) continue; const tab = record.indexOf("\t"); if (tab === -1) { return `cannot parse a nested submodule gitlink under ${displayPath}`; } const nestedPath = record.slice(tab + 1); trackedNestedPaths.add(nestedPath.replace(/\\/g, "/")); const nestedDir = join(subDir, nestedPath); if (!existsSync(join(nestedDir, ".git"))) continue; const nestedError = initializedSubmoduleSourceError( nestedDir, `${displayPath}/${nestedPath.replace(/\\/g, "/")}`, visited, depth + 1, ); if (nestedError) return nestedError; } const embeddedPaths = workspaceSourceEmbeddedGitPaths(subDir, false); if (embeddedPaths === null) { return `cannot resolve embedded Git checkouts under initialized submodule ${displayPath}`; } for (const embeddedPath of embeddedPaths) { if (trackedNestedPaths.has(embeddedPath)) continue; const embeddedDir = join(subDir, embeddedPath); if (!existsSync(join(embeddedDir, ".git"))) continue; const embeddedDisplayPath = `${displayPath}/${embeddedPath}`; const embeddedError = initializedSubmoduleSourceError( embeddedDir, embeddedDisplayPath, visited, depth + 1, ); if (embeddedError) return embeddedError; return ( `cannot bind embedded Git checkout ${embeddedDisplayPath}: it is not a tracked submodule. ` + "Use git submodule add so the parent records a gitlink and .gitmodules recovery metadata, " + "or flatten/remove the embedded checkout before re-running review." ); } return null; } function bindReviewedSource( projectDir: string, unit: string, fingerprint: string, recoveryBudget: NewGitlinkRecoveryBudget, ): { binding?: SourceBinding; error?: string } { const wt = worktreePath(projectDir, unit); const idx = join(tmpdir(), `aidlc-swarm-source-${process.pid}-${randomUUID().slice(0, 8)}`); // commit-tree is an internal snapshot operation, not a user-authored commit. // Give it a framework-owned identity so finalize does not depend on ambient // user.name/user.email configuration (CI and fresh automation often have none). const env = { ...process.env, GIT_INDEX_FILE: idx, GIT_AUTHOR_NAME: "AI-DLC", GIT_AUTHOR_EMAIL: "aidlc@localhost", GIT_COMMITTER_NAME: "AI-DLC", GIT_COMMITTER_EMAIL: "aidlc@localhost", }; const git = (args: string[]) => spawnSync("git", ["-C", wt, ...args], { env, encoding: "utf-8", maxBuffer: 512 * 1024 * 1024, }); try { const head = git(["rev-parse", "HEAD^{commit}"]); if (head.status !== 0 || !head.stdout.trim()) return { error: "cannot resolve the Bolt HEAD commit" }; if (git(["read-tree", "HEAD"]).status !== 0) return { error: "cannot seed the source snapshot index" }; const initialSubmodules = git(["ls-files", "-s", "-z"]); if (initialSubmodules.status !== 0) { return { error: "cannot enumerate pre-shape submodule state" }; } const initialGitlinkPaths = new Set(); for (const record of initialSubmodules.stdout.split("\0")) { if (!record.startsWith("160000 ")) continue; const tab = record.indexOf("\t"); if (tab === -1) { return { error: "cannot parse a pre-shape submodule gitlink" }; } initialGitlinkPaths.add(record.slice(tab + 1).replace(/\\/g, "/")); } if (git(["add", "-A"]).status !== 0) return { error: "cannot stage the reviewed source snapshot" }; const shape = shapeSourceSnapshotIndex(wt, idx, true); if (shape === null) { return { error: "cannot apply the reviewed source boundary to the snapshot" }; } if (shape.externalSymlinkPaths.length > 0) { const rendered = shape.externalSymlinkPaths.slice(0, 10).join(", ") + ( shape.externalSymlinkPaths.length > 10 ? ` ... and ${shape.externalSymlinkPaths.length - 10} more` : "" ); return { error: `cannot bind external source symlink target${shape.externalSymlinkPaths.length === 1 ? "" : "s"} ` + `(${rendered}); a Source Commit records link text but cannot represent external target bytes. ` + "Move the target into the worktree or replace the link before re-running review.", }; } const modulesIndexed = git([ "ls-files", "--error-unmatch", "--", ".gitmodules", ]); let recoverableNewGitlinks = new Map(); if (modulesIndexed.status === 0) { const recoverable = recoverableSubmoduleUrls(wt); if (recoverable === null) { return { error: "cannot parse .gitmodules recovery metadata" }; } recoverableNewGitlinks = recoverable; } else if (modulesIndexed.status !== 1) { return { error: "cannot verify .gitmodules snapshot state" }; } // The parent tree can represent only a submodule's checked-out commit // (mode 160000), never dirty bytes inside that checkout. The fingerprint // deliberately includes those bytes, so accepting them here would produce // a Source Commit different from what the reviewer inspected. Fail closed // rather than silently retaining the old gitlink. A clean submodule checked // out at another commit remains representable: `git add -A` staged its new // gitlink above. const submodules = git(["ls-files", "-s", "-z"]); if (submodules.status !== 0) return { error: "cannot verify reviewed submodule state" }; const visitedSubmodules = new Set(); for (const record of submodules.stdout.split("\0")) { if (!record.startsWith("160000 ")) continue; const tab = record.indexOf("\t"); if (tab === -1) return { error: "cannot parse a reviewed submodule gitlink" }; const commit = record.slice(0, tab).split(" ")[1] ?? ""; if (!/^[0-9a-f]{40,64}$/.test(commit)) { return { error: "cannot parse a reviewed submodule commit" }; } const path = record.slice(tab + 1); const subDir = join(wt, path); if (!existsSync(join(subDir, ".git"))) continue; // uninitialized: no reviewed bytes to carry const submoduleError = initializedSubmoduleSourceError( subDir, path.replace(/\\/g, "/"), visitedSubmodules, ); if (submoduleError) return { error: submoduleError }; const normalizedPath = path.replace(/\\/g, "/"); if (!initialGitlinkPaths.has(normalizedPath)) { const recoveryUrl = recoverableNewGitlinks.get(normalizedPath); if (recoveryUrl) { const recoveryError = newGitlinkRecoveryError( wt, subDir, normalizedPath, recoveryUrl, commit, recoveryBudget, ); if (recoveryError) return { error: recoveryError }; continue; } return { error: `cannot bind embedded Git checkout ${normalizedPath}: it is not a tracked submodule. ` + "Use git submodule add so the parent records a gitlink and .gitmodules recovery metadata, " + "or flatten/remove the embedded checkout before re-running review.", }; } } const rawEntries = filteredRawIndexEntries( wt, idx, shape.includedRegularPaths, ); if (rawEntries === null) return { error: "cannot bind raw bytes for filtered source paths" }; for (const entry of rawEntries) { const indexed = git(["ls-files", "-s", "-z", "--", entry.path]); const mode = indexed.status === 0 ? indexed.stdout.slice(0, indexed.stdout.indexOf(" ")) : ""; if (!/^100(?:644|755)$/.test(mode)) { return { error: `cannot resolve the index mode for filtered path ${entry.path}` }; } const raw = git(["hash-object", "-w", "--no-filters", "--", entry.path]); if (raw.status !== 0 || raw.stdout.trim() !== entry.sha) { return { error: `cannot materialize raw reviewed bytes for filtered path ${entry.path}` }; } if (git(["update-index", "--cacheinfo", mode, entry.sha, entry.path]).status !== 0) { return { error: `cannot bind raw reviewed bytes for filtered path ${entry.path}` }; } } const tree = git(["write-tree"]); if (tree.status !== 0 || !tree.stdout.trim()) return { error: "cannot write the reviewed source tree" }; const commit = git(["commit-tree", tree.stdout.trim(), "-p", head.stdout.trim(), "-m", `Reviewed source for Bolt ${unit}`]); if (commit.status !== 0 || !commit.stdout.trim()) return { error: "cannot create the immutable reviewed-source commit" }; const after = worktreeSourceFingerprint(wt); if (after === null || after !== fingerprint) { return { error: "source-fingerprint mismatch while binding the reviewed source; re-run the reviewer" }; } const commitSha = commit.stdout.trim(); const retained = git(["update-ref", reviewedSourceRef(unit, commitSha), commitSha]); if (retained.status !== 0) { return { error: "cannot retain the immutable reviewed-source commit" }; } return { binding: { fingerprint, commit: commitSha } }; } finally { rmSync(idx, { force: true }); } } // --- Audit emission (this tool owns the whole swarm taxonomy) --------------- // // The engine is read-only and the conductor (prose) never emits audit events, so // the deterministic tool is the sole emitter. SWARM_STARTED fires once per batch // in `prepare`; SWARM_DEGRADED fires there too when the conductor reports a loud // downgrade. The per-unit pair, the per-failed-unit baton row, and the batch // tally all fire from `finalize`, the authoritative gate. function emitSwarmStarted( pd: string, batch: string, units: string[], obligations: string[], concurrency: string, attempt: SwarmAttemptStamp, ): void { appendAuditEntry( "SWARM_STARTED", { "Batch number": batch, "Unit names": units.join(","), "Unit obligations": obligations.join(","), "Concurrency cap": concurrency, Stage: attempt.stage, "Run floor": attempt.floor, }, pd ); } // Loud-degrade: AIDLC_USE_SWARM=1 was requested but the Workflow tool was // unavailable, so the conductor ran the subagent floor. The referee makes the // substrate difference invisible to convergence, but the downgrade is recorded. function emitSwarmDegraded(pd: string, batch: string, requested: DriverName): void { appendAuditEntry( "SWARM_DEGRADED", { "Batch number": batch, "Requested driver": requested, "Fallback driver": "subagent", }, pd ); } // Each converged row carries the exact attempt stamp captured by prepare. // Finalize must never recompute this from current state: a late retry against a // preserved prior-attempt worktree would otherwise be mislabeled as current. function emitUnitConverged( pd: string, batch: string, unit: string, attempt: SwarmAttemptStamp, binding?: SourceBinding, sourceFreshnessBypassed = false, ): void { appendAuditEntry( "SWARM_UNIT_CONVERGED", { "Batch number": batch, "Unit name": unit, Stage: attempt.stage, "Run floor": attempt.floor, ...(binding ? { "Source Fingerprint": binding.fingerprint, "Source Commit": binding.commit, } : sourceFreshnessBypassed ? { "Source Freshness Bypass": "true" } : {}), }, pd ); } function emitUnitFailed( pd: string, batch: string, unit: string, reason: FailureReason ): void { appendAuditEntry( "SWARM_UNIT_FAILED", { "Batch number": batch, "Unit name": unit, Reason: reason }, pd ); } function emitBatonReturned( pd: string, batch: string, unit: string, reason: FailureReason ): void { appendAuditEntry( "SWARM_BATON_RETURNED", { "Batch number": batch, "Unit name": unit, Reason: reason }, pd ); } function emitSwarmCompleted( pd: string, batch: string, convergedCount: number, failedCount: number ): void { appendAuditEntry( "SWARM_COMPLETED", { "Batch number": batch, "Converged count": String(convergedCount), "Failed count": String(failedCount), }, pd ); } // Close a failed unit's per-Bolt lifecycle by composing `aidlc-bolt fail` (emits // BOLT_FAILED paired with the BOLT_STARTED that `start --worktree` emitted). // Preserves the worktree per the halt-and-ask contract. Best-effort: the swarm's // own SWARM_UNIT_FAILED is the authoritative swarm signal, so a failure to emit // BOLT_FAILED must not mask it. function emitBoltFailed(pd: string, unit: string, errorSummary: string): void { runTool( "aidlc-bolt.ts", ["fail", "--name", unit, "--slug", swarmBoltSlug(unit), "--error", errorSummary], pd ); } // --- prepare ---------------------------------------------------------------- function handlePrepare(rest: string[]): void { const { flags } = parseArgs(rest); const projectDir = resolveProjectDir(flags["project-dir"]); if (!flags.batch || !/^[1-9][0-9]*$/.test(flags.batch)) { fail("prepare requires --batch "); } if (!flags.units) { fail("prepare requires --units "); } const units = splitCsv(flags.units); if (units.length === 0) { fail("--units resolved to an empty list"); } if (flags["degraded-from"]) { const requested = flags["degraded-from"] as DriverName; if (!DRIVER_VALUES.includes(requested)) { fail(`--degraded-from must be one of: ${DRIVER_VALUES.join(", ")}`); } } const state = readStateFile(projectDir); const stage = (getField(state, "Current Stage") ?? "") .trim() .toLowerCase() .replace(/\s+/g, "-"); const autonomy = (getField(state, "Construction Autonomy Mode") ?? "").trim(); // Human lines for source drift accepted under Change Control `relaxed` when // protected Code Generation authority started for the batch's units. const swarmChangeNotices: string[] = []; if (stage === "code-generation" && autonomy === "autonomous") { const invalid = units .map((unit) => evaluateCodeGenerationApproval(projectDir, { unit })) .filter((approval) => !approval.ok); if (invalid.length > 0) { fail( "prepare requires a current, explicitly approved Code Generation plan for every autonomous " + `unit before worktrees are forked: ${invalid .map((approval) => `${approval.unit} (${approval.reason})`) .join("; ")}`, ); } try { for (const unit of units) { swarmChangeNotices.push(...beginCodeGeneration(projectDir, { unit })); } } catch (error) { fail( `prepare could not start protected Code Generation authority: ${ error instanceof Error ? error.message : String(error) }`, ); } } const dag = resolveBoltDag(projectDir, flags.intent, flags.space); if (dag.state === "malformed") { fail( `prepare cannot resolve the authoritative unit DAG: ${dag.reason} ` + `(${dag.detail}). Fix unit-of-work-dependency.md before starting the swarm.`, ); } const stageDefinition = resolveStage(stage); if (dag.state !== "ok") { fail("prepare requires a current resolved Unit DAG"); } for (const unit of units) { if (!dag.units.includes(unit)) { fail(`prepare unit "${unit}" is not in the current resolved Unit DAG`); } if ( stageDefinition && filterProducesByKind( stageDefinition.produces_kinds, stageDefinition.produces ?? [], dag.unitKinds?.get(unit) ?? null, ).length === 0 ) { fail(`prepare unit "${unit}" has no applicable required outputs for stage "${stage}"`); } } assertUniqueSwarmBoltSlugs(dag.units); // P7: the construction repo this batch targets. resolveConstructionRepo errors // on a multi-repo intent with no --repo (forwarded as the batch failure), infers // the lone repo for a single-repo intent, and yields cwd=projectDir for a legacy // intent (today's behaviour). The repoCwd is where `--base` is derived from and // is forwarded to every `aidlc-worktree create` so the worktree forks in-repo. let repoCwd: string; let repoName: string | null; try { const resolved = resolveConstructionRepo(projectDir, flags.repo, flags.intent, flags.space); repoCwd = resolved.cwd; repoName = resolved.repo; } catch (e) { fail(e instanceof Error ? e.message : String(e)); } const base = flags.base ?? currentBranch(repoCwd); const concurrency = flags.concurrency && /^[1-9][0-9]*$/.test(flags.concurrency) ? flags.concurrency : String(units.length); const attempt = currentSwarmAttempt(projectDir); if (!attempt) { fail( "prepare could not resolve the current stage attempt from state and audit", ); } // Record a loud downgrade BEFORE the batch-start row, if the conductor reports // one. The driver-selection read (AIDLC_USE_SWARM) is conductor-side; the tool // only learns a degrade happened via this flag. if (flags["degraded-from"]) { emitSwarmDegraded( projectDir, flags.batch, flags["degraded-from"] as DriverName, ); } const prepared: { unit: string; ok: boolean; worktree_path?: string; error?: string; }[] = []; // Forward the RESOLVED repo name (not the raw flag) so every sibling primitive // anchors to the same repo — an inferred lone repo is passed explicitly too, so // create/merge/discard never re-resolve to a different repo than prepare chose. const repoArgs = repoName ? ["--repo", repoName] : []; for (const unit of units) { const boltSlug = swarmBoltSlug(unit); const created = runTool( "aidlc-worktree.ts", [ "create", "--slug", boltSlug, "--base", base, "--swarm-unit", unit, "--swarm-batch", flags.batch, "--swarm-stage", attempt.stage, "--swarm-floor", attempt.floor, ...repoArgs, ], projectDir ); if (!created.ok) { prepared.push({ unit, ok: false, error: `worktree create failed: ${created.stderr.trim() || created.stdout.trim()}`, }); continue; } let worktreeDir: string; try { worktreeDir = JSON.parse(created.stdout).worktree_path; } catch { prepared.push({ unit, ok: false, error: "could not parse worktree_path from aidlc-worktree create", }); continue; } const started = runTool( "aidlc-bolt.ts", ["start", "--worktree", "--slug", boltSlug, "--batch", flags.batch, "--name", unit, ...repoArgs], projectDir ); if (!started.ok) { prepared.push({ unit, ok: false, worktree_path: worktreeDir, error: `bolt start failed: ${started.stderr.trim() || started.stdout.trim()}`, }); continue; } prepared.push({ unit, ok: true, worktree_path: worktreeDir }); } // Stamp only worktrees this invocation actually created and started. Emitting // before creation would let a failed re-prepare in a later stage attempt // relabel an old preserved worktree with the current attempt, allowing stale // data to pass finalize's exact-attempt check. const readyUnits = prepared.filter((unit) => unit.ok).map((unit) => unit.unit); if (readyUnits.length > 0) { emitSwarmStarted( projectDir, flags.batch, readyUnits, dag.units, concurrency, attempt, ); } console.log( JSON.stringify( { batch: flags.batch, base, concurrency: Number(concurrency), units: prepared, ...(swarmChangeNotices.length > 0 ? { change_notices: swarmChangeNotices } : {}), }, null, 2 ) ); // Exit 2 if any worktree failed to fork — the conductor must take the baton. process.exit(prepared.some((p) => !p.ok) ? 2 : 0); } // --- check ------------------------------------------------------------------ function handleCheck(rest: string[]): void { const { positional, flags } = parseArgs(rest); const projectDir = resolveProjectDir(flags["project-dir"]); const unit = positional[0] ?? flags.unit; if (!unit) { fail("check requires a unit name (positional `check ` or --unit )"); } swarmBoltSlug(unit); if (!flags["check-cmd"]) { fail("check requires --check-cmd "); } const verdict = verdictFor(unit, projectDir, flags["check-cmd"], flags["test-file"]); if (!verdict.exists) { fail(`no worktree for unit "${unit}" — run \`prepare\` first`); } if (verdict.confineError) { console.log( JSON.stringify({ unit, converged: false, tampered: false, reason: "error", detail: verdict.confineError, }) ); process.exit(1); } const genuine = verdict.converged && !verdict.tampered; const out: Record = { unit, converged: verdict.converged, tampered: verdict.tampered, reason: verdict.tampered ? "error" : null, }; if (verdict.tampered) out.detail = "protected test file was modified"; console.log(JSON.stringify(out)); // Exit 0 ONLY for a genuine convergence — the seam the ultracode script and // the conductor gate on (a worker's self-claim is never read). process.exit(genuine ? 0 : 1); } // --- finalize --------------------------------------------------------------- function handleFinalize(rest: string[]): void { const { positional, flags } = parseArgs(rest); const projectDir = resolveProjectDir(flags["project-dir"]); const batch = flags.batch ?? positional[0]; if (!batch || !/^[1-9][0-9]*$/.test(batch)) { fail("finalize requires --batch "); } if (!flags["check-cmd"]) { fail("finalize requires --check-cmd "); } const claimed = flags.claimed ? splitCsv(flags.claimed) : []; // The universe of units in the batch; defaults to the claimed set when the // conductor passes only --claimed (then declined-unit accounting is a no-op). const allUnits = flags.units ? splitCsv(flags.units) : claimed.slice(); const dag = resolveBoltDag(projectDir, flags.intent, flags.space); if (dag.state !== "ok") fail("finalize requires a current resolved Unit DAG"); const currentStage = (getField(readStateFile(projectDir), "Current Stage") ?? "") .trim() .toLowerCase() .replace(/\s+/g, "-"); const stageDefinition = resolveStage(currentStage); for (const unit of new Set([...allUnits, ...claimed])) { swarmBoltSlug(unit); if (!dag.units.includes(unit)) { fail(`finalize unit "${unit}" is not in the current resolved Unit DAG`); } if ( stageDefinition && filterProducesByKind( stageDefinition.produces_kinds, stageDefinition.produces ?? [], dag.unitKinds?.get(unit) ?? null, ).length === 0 ) { fail(`finalize unit "${unit}" has no applicable required outputs for stage "${currentStage}"`); } } const claimedSet = new Set(claimed); const testFile = flags["test-file"]; const checkCmd = flags["check-cmd"]; const review = reviewerRequirement(projectDir); const currentAttempt = currentSwarmAttempt(projectDir); // Optional per-declined-unit typed reasons: `--reasons a=unsatisfiable,b=budget-exhausted`. // The conductor judged WHY each unclaimed unit gave up (knowledge → conductor, // D-I); the tool records that attribution faithfully (determinism → tool), // mirroring how --claimed / --degraded-from carry conductor decisions. Applies // ONLY to declined units — a claimed unit's reason is always the tool's own // re-verify verdict, so the lying-conductor guard cannot be talked out of an // `error`. Unparseable / out-of-enum entries are rejected loudly rather than // silently downgraded; an unlisted declined unit defaults to `cap-exhausted`. const declinedReasons: Record = {}; if (flags.reasons) { for (const pair of splitCsv(flags.reasons)) { const eq = pair.indexOf("="); if (eq <= 0) { fail(`--reasons entry must be =: "${pair}"`); } const unit = pair.slice(0, eq).trim(); swarmBoltSlug(unit); const reason = pair.slice(eq + 1).trim() as FailureReason; if (!DECLINED_REASONS.includes(reason)) { fail(`--reasons reason for "${unit}" must be one of: ${DECLINED_REASONS.join(", ")}`); } declinedReasons[unit] = reason; } } // Re-verify every claimed unit (the lying-conductor guard) and account for any // declined unit the conductor did not claim. const results: UnitResult[] = []; const genuine: string[] = []; const preparedAttempts = new Map(); const sourceBindings = new Map(); const recordSnapshots = new Map(); const sourceFreshnessBypassed = process.env.AIDLC_SKIP_SOURCE_FRESHNESS === "1"; const recoveryBudget = newGitlinkRecoveryBudget(); for (const unit of allUnits) { if (claimedSet.has(unit)) { const verdict = verdictFor(unit, projectDir, checkCmd, testFile); const preparedAttempt = preparedSwarmAttempt( projectDir, batch, unit, ); if (!preparedAttempt) { results.push({ unit, status: "failed", reason: "error", detail: "no stamped SWARM_STARTED boundary for this unit and batch; run prepare in the current attempt", }); } else if ( !currentAttempt || preparedAttempt.stage !== currentAttempt.stage || preparedAttempt.floor !== currentAttempt.floor ) { results.push({ unit, status: "failed", reason: "error", detail: `prepared swarm attempt ${preparedAttempt.stage}/${preparedAttempt.floor} ` + `does not match the current attempt ` + `${currentAttempt ? `${currentAttempt.stage}/${currentAttempt.floor}` : "(unresolved)"}`, }); } else if (!verdict.exists) { results.push({ unit, status: "failed", reason: "error", detail: "no worktree on re-verify (prepare not run?)", }); } else if (verdict.confineError) { results.push({ unit, status: "failed", reason: "error", detail: verdict.confineError }); } else if (verdict.tampered) { results.push({ unit, status: "failed", reason: "error", detail: "convergence rejected: protected test file was modified", tampered: true, }); } else if (verdict.converged) { const receipt: ReceiptCheck = review.error ? { error: review.error } : review.reviewer ? reviewerReceiptError( projectDir, unit, review.stage, review.reviewer, review.reviewClass, review.maxIterations, ) : { error: null }; if (receipt.error) { results.push({ unit, status: "failed", reason: "error", detail: receipt.error, }); } else { const captured = stageDefinition ? captureReviewedRecordSnapshot( projectDir, unit, stageDefinition, receipt, ) : { error: `cannot resolve stage "${currentStage}"` }; const bound = receipt.sourceFingerprint ? bindReviewedSource( projectDir, swarmBoltSlug(unit), receipt.sourceFingerprint, recoveryBudget, ) : {}; if (captured.error || !captured.snapshot) { results.push({ unit, status: "failed", reason: "error", detail: captured.error ?? `cannot snapshot record artifacts for unit "${unit}"`, }); } else if (bound.error) { results.push({ unit, status: "failed", reason: "error", detail: bound.error, }); } else { if (bound.binding) sourceBindings.set(unit, bound.binding); recordSnapshots.set(unit, captured.snapshot); genuine.push(unit); preparedAttempts.set(unit, preparedAttempt); results.push({ unit, status: "converged" }); } } } else { // Claimed converged, but the check command does not pass on re-verify — // the lying / misremembering conductor. Refuse the merge. results.push({ unit, status: "failed", reason: "error", detail: "claimed converged but the check command did not pass on re-verify", }); } } else { // The conductor did not claim this unit: its driver loop ended without // convergence. The conductor may attribute a typed reason via --reasons // (e.g. `unsatisfiable` when it judged the unit fundamentally unbuildable, // `budget-exhausted` when the ultracode token ceiling stopped it); absent // an attribution, `cap-exhausted` is the catch-all (the loop ended without // convergence and the conductor offered no finer classification). const reason = declinedReasons[unit] ?? "cap-exhausted"; results.push({ unit, status: "failed", reason, detail: reason === "cap-exhausted" ? "unit not claimed converged by the conductor" : `unit not claimed converged; conductor attributed: ${reason}`, }); } } // Serialised HOLD-MERGE merge-back of the genuine passes only (sorted for a // deterministic merge order). release-merge is idempotent — safe whether or not // the lock was ever held; complete --merge reaches the add/add-conflict abort // pinned at the composed surface by the worktree-merge tests. const mergeFailures: { unit: string; detail: string }[] = []; for (const unit of [...genuine].sort()) { const boltSlug = swarmBoltSlug(unit); const recordSnapshot = recordSnapshots.get(unit); const recordMergeError = recordSnapshot ? mergeReviewedRecordSnapshot(projectDir, unit, recordSnapshot) : `reviewed record snapshot is missing for unit "${unit}"`; if (recordMergeError !== null) { mergeFailures.push({ unit, detail: recordMergeError }); continue; } runTool("aidlc-bolt.ts", ["release-merge", "--slug", boltSlug], projectDir); const merged = runTool( "aidlc-bolt.ts", ["complete", "--merge", "--slug", boltSlug, "--batch", batch, "--name", unit], projectDir ); if (!merged.ok) { mergeFailures.push({ unit, detail: merged.stderr.trim() || merged.stdout.trim() }); } } // Authoritative audit trail: one row per unit, the baton per failed unit, the // batch tally to close. A converged unit whose merge-back FAILED gets no // SWARM_UNIT_CONVERGED row: that row is the engine's batch-advance signal, and // emitting it for a unit whose metadata never landed on main would advance the // run past an unmerged unit. It gets no SWARM_UNIT_FAILED row either - the // unit did converge; the failure envelope + exit 2 carry the merge outcome. // The row lands when a finalize retry scoped to that unit merges cleanly (the // worktree is preserved and release-merge is idempotent, so the retry is a // pure re-invocation - no prepare). const mergeFailed = new Set(mergeFailures.map((f) => f.unit)); for (const r of results) { if (r.status === "converged") { if (!mergeFailed.has(r.unit)) { const attempt = preparedAttempts.get(r.unit); if (attempt) { emitUnitConverged( projectDir, batch, r.unit, attempt, sourceBindings.get(r.unit), sourceFreshnessBypassed, ); } } } else { emitUnitFailed(projectDir, batch, r.unit, r.reason ?? "error"); emitBoltFailed(projectDir, r.unit, r.detail ?? `unit "${r.unit}" failed: ${r.reason}`); } } const failedResults = results.filter((r) => r.status === "failed"); for (const r of failedResults) { emitBatonReturned(projectDir, batch, r.unit, r.reason ?? "error"); } const convergedCount = genuine.length; const failedCount = failedResults.length; emitSwarmCompleted(projectDir, batch, convergedCount, failedCount); const envelope = { batch, units: results.map((result) => ({ ...result, bolt_slug: swarmBoltSlug(result.unit), })), converged: convergedCount, failed: failedCount, merge_failures: mergeFailures, }; console.log(JSON.stringify(envelope, null, 2)); // Exit 2 signals "the conductor must take the baton" (a unit failed or a merge // failed); exit 0 means every claimed unit was genuinely converged and merged. process.exit(failedCount > 0 || mergeFailures.length > 0 ? 2 : 0); } // --- shared helpers --------------------------------------------------------- function splitCsv(value: string): string[] { return value .split(",") .map((u) => u.trim()) .filter((u) => u !== ""); } function swarmBoltSlug(unit: string): string { const unitNameError = validateUnitName(unit); if (unitNameError) fail(unitNameError); return boltSlugForUnit(unit); } function assertUniqueSwarmBoltSlugs(units: string[]): void { const owners = new Map(); for (const unit of units) { const boltSlug = swarmBoltSlug(unit); const existing = owners.get(boltSlug); if (existing && existing !== unit) { fail( `Units "${existing}" and "${unit}" resolve to the same internal Bolt slug ` + `"${boltSlug}". Rename one Unit before starting the autonomous swarm.`, ); } owners.set(boltSlug, unit); } } function currentSwarmAttempt(projectDir: string): SwarmAttemptStamp | null { try { const stage = getField(readStateFile(projectDir), "Current Stage")?.trim() ?? ""; if (!stage) return null; return { stage, floor: latestMainWorkflowStageRunFloorForProject(projectDir, stage), }; } catch { return null; } } function preparedSwarmAttempt( projectDir: string, batch: string, unit: string, ): SwarmAttemptStamp | null { const matching = readAuditShardEvents(projectDir).filter((event) => { if (event.event !== "SWARM_STARTED") return false; if (auditBlockField(event.block, "Batch number") !== batch) return false; const units = splitCsv(auditBlockField(event.block, "Unit names") ?? ""); return units.includes(unit); }); const stamped = matching.filter( (event) => auditBlockField(event.block, "Stage") !== null && auditBlockField(event.block, "Run floor") !== null, ); if (stamped.length > 0) { stamped.sort((a, b) => { if (a.timestamp !== b.timestamp) { return a.timestamp < b.timestamp ? -1 : 1; } if (a.shardIndex !== b.shardIndex) return a.shardIndex - b.shardIndex; return a.pos - b.pos; }); const timestamp = stamped[stamped.length - 1].timestamp; const latest = stamped.filter((event) => event.timestamp === timestamp); const stamps = new Map(); for (const event of latest) { const stage = auditBlockField(event.block, "Stage"); const floor = auditBlockField(event.block, "Run floor"); if (!stage || !floor) continue; stamps.set(`${stage}\0${floor}`, { stage, floor }); } // Same-second starts in different shards are unordered. A shared stamp is // harmless; differing stamps fail closed instead of picking by filename. if ( new Set(latest.map((event) => event.shard)).size > 1 && stamps.size !== 1 ) { return null; } return stamps.values().next().value ?? null; } return legacyPreparedSwarmAttempt(projectDir, batch, unit); } function legacyPreparedSwarmAttempt( projectDir: string, batch: string, unit: string, ): SwarmAttemptStamp | null { const boltSlug = swarmBoltSlug(unit); const wt = worktreePath(projectDir, boltSlug); const recordPrefix = relativeRecordDir(projectDir); const wtState = worktreeStateFilePath(wt, recordPrefix); const wtAudit = worktreeAuditFilePath(wt, recordPrefix, projectDir); const wtRuntime = worktreeRuntimeGraphPath(wt, recordPrefix); if ( !existsSync(wt) || !isRegularFile(wtState) || !isRegularFile(wtAudit) || !isRegularFile(wtRuntime) ) { return null; } let worktreeAudit: string; let state: string; try { worktreeAudit = readFileSync(wtAudit, "utf-8"); state = readFileSync(wtState, "utf-8"); } catch { return null; } const fork = findAllEvents(worktreeAudit, "AUDIT_FORKED") .filter((event) => auditBlockField(event.block, "Bolt slug") === boltSlug) .at(-1); const boundaryRaw = fork ? auditBlockField(fork.block, "Fork Boundary") : null; const sourceHash = fork ? auditBlockField(fork.block, "Source Audit Hash") : null; if (!boundaryRaw || !sourceHash || !/^[0-9]+$/.test(boundaryRaw)) return null; const mainDir = auditShardDir(projectDir); if (!mainDir) return null; const mainShard = join(mainDir, basename(wtAudit)); let mainBytes: Buffer; try { mainBytes = readFileSync(mainShard); } catch { return null; } const boundary = Number(boundaryRaw); if (!Number.isSafeInteger(boundary) || boundary < 0 || mainBytes.length < boundary) { return null; } const frozenBytes = mainBytes.subarray(0, boundary); if (createHash("sha256").update(frozenBytes).digest("hex") !== sourceHash) { return null; } const frozenAudit = frozenBytes.toString("utf-8"); const frozenBlocks = frozenAudit.replace(/\r\n/g, "\n").split(/\n---\n/); const legacyStarts: number[] = []; const boltStarts: number[] = []; const stateForks: number[] = []; for (let index = 0; index < frozenBlocks.length; index++) { const block = frozenBlocks[index]; const event = auditBlockField(block, "Event"); if ( event === "SWARM_STARTED" && auditBlockField(block, "Batch number") === batch && !auditBlockField(block, "Stage") && !auditBlockField(block, "Run floor") && splitCsv(auditBlockField(block, "Unit names") ?? "").includes(unit) ) { legacyStarts.push(index); } if ( event === "BOLT_STARTED" && auditBlockField(block, "Batch number") === batch && auditBlockField(block, "Bolt slug") === boltSlug ) { boltStarts.push(index); } if ( event === "STATE_FORKED" && auditBlockField(block, "Bolt slug") === boltSlug ) { stateForks.push(index); } } const hasPreparationSequence = legacyStarts.some((started) => boltStarts.some((bolt) => bolt > started && stateForks.some((forked) => forked > bolt), ), ); if (!hasPreparationSequence) return null; const stage = getField(state, "Current Stage")?.trim() ?? ""; if (!stage) return null; return { stage, floor: latestMainWorkflowStageRunFloor(frozenAudit, stage), }; } function currentBranch(projectDir: string): string { const r = spawnSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: projectDir, encoding: "utf-8", }); return (r.stdout ?? "main").trim() || "main"; } function fail(msg: string): never { console.error(JSON.stringify({ error: msg })); process.exit(1); } export function main(argv: string[]): void { // The subcommand is the first bare token that is NOT a flag NOR a flag's value. // Walk argv skipping `--flag value` / `--flag=value` pairs so // `--project-dir check ...` and `check --project-dir ...` both // resolve to `check`. The handlers re-read every flag from `rest`, and a // positional unit (e.g. `check `) survives in rest. let subcommand: string | undefined; let subIndex = -1; for (let i = 0; i < argv.length; i++) { const a = argv[i]; if (a.startsWith("--")) { if (!a.includes("=") && i + 1 < argv.length && !argv[i + 1].startsWith("--")) { i++; } continue; } subcommand = a; subIndex = i; break; } const rest = subIndex >= 0 ? [...argv.slice(0, subIndex), ...argv.slice(subIndex + 1)] : argv; switch (subcommand) { case "prepare": handlePrepare(rest); break; case "check": handleCheck(rest); break; case "finalize": handleFinalize(rest); break; default: console.error( JSON.stringify({ error: `Unknown subcommand: ${subcommand ?? "(none)"}. Valid: prepare, check, finalize`, }) ); process.exit(1); } } if (import.meta.main) main(process.argv.slice(2));