// aidlc-unit.ts - atomic Unit claim registry and checkout-local scope binding. import { spawnSync } from "node:child_process"; import { createHash, randomUUID } from "node:crypto"; import { mkdtempSync, mkdirSync, readFileSync, realpathSync, rmSync, unlinkSync, writeFileSync, } from "node:fs"; import { basename, dirname, join, resolve } from "node:path"; import { tmpdir } from "node:os"; import { fileURLToPath } from "node:url"; import { appendAuditEntry } from "./aidlc-audit.ts"; import { activeIntentUuid, activeSpace, artifactFilename, auditBlockField, auditShardName, type AuditShardEvent, type CachedUnitClaim, candidateReviewCoverageProjection, clearClaimGeneration, clearUnitScopeStamp, ensureCloneId, errorMessage, extractMarkdownSection, filterProducesByKind, getField, humanPresenceGuardDisabled, idSuffix, invalidateLiveClaimPayloadCache, isNonAnswer, isReadOnlyEngineProbe, isTeamUnitOwnership, isoTimestamp, loadScopeMetadata, loadStageGraphAll, parseArgs, parseBoltDag, readAuditShardEvents, readUnitClaimRegistryCache, readApplicableTeamUnitScopeStamp, readUnitMergeTransaction, readStateFile, readUnitGateRhythm, readUnitScopeStamp, parseReviewRecordBytes, pairedReviewRecordForCompletion, relativeRecordDir, REVIEW_RECORDS_DIR, reviewRecordDigest, type ReviewRecord, requireLiveClaimForTeamUnit, resolveProjectDir, resolveReviewClass, selfAttributedDecisionMarker, type UnitMergeEvidence, type UnitMergeTransaction, UNIT_MERGE_DIR, type UnitScopeStamp, unitGateStatus, unitLifecycleSnapshot, unitDependencyPath, unitMergedReceipts, unitMajorConstructionStageSlugs, unitParticipantPath, unitReleasePendingPath, validateUnitName, withAuditLock, writeUnitClaimRegistryCache, writeUnitMergeTransaction, writeStateFile, writeUnitScopeStamp, writeClaimGeneration, } from "./aidlc-lib.js"; import { parseTestingContract, PLAN_APPROVAL_CHECKPOINT, recordedApprovalFingerprint, resolveTestingPosture, } from "./aidlc-testing-posture.ts"; const CLAIM_FILE = ".aidlc-unit-claim.json"; const ZERO_OID = "0000000000000000000000000000000000000000"; interface GitResult { ok: boolean; stdout: string; stderr: string; code: number; } function git(projectDir: string, args: string[], env?: NodeJS.ProcessEnv): GitResult { const result = spawnSync("git", args, { cwd: projectDir, encoding: "utf-8", env: { ...process.env, ...env }, }); return { ok: result.status === 0, stdout: result.stdout ?? "", stderr: result.stderr ?? "", code: result.status ?? 1, }; } function localGit( projectDir: string, args: string[], env?: NodeJS.ProcessEnv, ): GitResult { return git(projectDir, args, { GIT_NO_LAZY_FETCH: "1", ...env, }); } function fail(message: string): never { throw new Error(message); } export interface UnitClaimPayload { version: 1; status: "claimed" | "released"; owner: string; space: string; intent_uuid: string; intent_id8: string; unit: string; generation: number; nonce: string; base_oid: string; integration_ref: string; claim_ref: string; predecessor_oid: string | null; gate_rhythm: "per-stage" | "unit-end"; audit_shard?: string; candidate_tree_oid?: string; candidate_head_oid?: string; } export interface UnitClaimView { unit: string; status: "claimed" | "released"; owner: string; generation: number; nonce: string; oid: string; ref: string; observedAt?: string; movementObserved?: boolean; payload: UnitClaimPayload; } export interface UnitClaimOverview { claimable: string[]; claimed: Array<{ unit: string; owner: string; generation: number }>; waiting: Array<{ unit: string; blockedBy: string[] }>; claims: Map; warning?: string; } function repositoryRemote(projectDir: string): string | null { const result = git(projectDir, ["remote"]); if (!result.ok) return null; const remotes = result.stdout.split(/\r?\n/).map((v) => v.trim()).filter(Boolean); if (remotes.length === 0) return null; if (remotes.includes("origin")) return "origin"; if (remotes.length === 1) return remotes[0]; fail(`Multiple git remotes are configured (${remotes.join(", ")}); configure origin for Unit claims.`); } function currentBranch(projectDir: string): string { const result = git(projectDir, ["branch", "--show-current"]); return result.ok && result.stdout.trim() ? result.stdout.trim() : "main"; } function affirmedIntegrationBranch(projectDir: string): string | null { const memoryRoot = join( projectDir, "aidlc", "spaces", activeSpace(projectDir), "memory", ); for (const name of ["project.md", "team.md", "org.md"]) { try { const body = readFileSync(join(memoryRoot, name), "utf-8"); const section = extractMarkdownSection(body, "## Way of Working"); const explicit = /\b(?:base|integration|merge target)(?: branch)?\b[^`\n]*`([^`]+)`/i.exec(section) ?? /`([^`]+)`[^.\n]*\b(?:base|integration|merge target)(?: branch)?\b/i.exec(section); if ( explicit && /^(?:main|master|develop|release\/[A-Za-z0-9._/-]+)$/.test(explicit[1]) ) { return explicit[1]; } } catch { // Try the next narrower/broader method layer. } } return null; } function integrationBranch(projectDir: string, remote: string | null): string { const affirmed = affirmedIntegrationBranch(projectDir); if (affirmed) return affirmed; if (remote) { const cached = git(projectDir, ["symbolic-ref", "--short", `refs/remotes/${remote}/HEAD`]); if (cached.ok && cached.stdout.trim().startsWith(`${remote}/`)) { return cached.stdout.trim().slice(remote.length + 1); } const advertised = git(projectDir, ["ls-remote", "--symref", remote, "HEAD"]); const match = advertised.stdout.match(/^ref:\s+refs\/heads\/([^\s]+)\s+HEAD$/m); if (match) return match[1]; } const current = currentBranch(projectDir); const configured = git(projectDir, ["config", `branch.${current}.merge`]); if (configured.ok && configured.stdout.trim().startsWith("refs/heads/")) { return configured.stdout.trim().slice("refs/heads/".length); } for (const candidate of ["main", "master", current]) { if ( candidate && git(projectDir, ["rev-parse", "--verify", `refs/heads/${candidate}`]).ok ) { return candidate; } } return current || "main"; } function fetchIntegration(projectDir: string): { remote: string | null; branch: string; ref: string; oid: string; } { const remote = repositoryRemote(projectDir); const branch = integrationBranch(projectDir, remote); if (remote) { const fetched = git(projectDir, ["fetch", remote, branch]); if (!fetched.ok) fail(`git fetch ${remote} ${branch} failed: ${fetched.stderr.trim()}`); } const ref = remote ? `refs/remotes/${remote}/${branch}` : `refs/heads/${branch}`; const oid = git(projectDir, ["rev-parse", "--verify", ref]); if (!oid.ok) fail(`Integration ref ${ref} does not exist.`); return { remote, branch, ref, oid: oid.stdout.trim() }; } function claimRef(intentId8: string, unit: string): string { return `refs/heads/claim/${intentId8}/${unit}`; } function fetchClaimRefs(projectDir: string, remote: string | null): void { if (!remote) return; const fetched = git(projectDir, [ "fetch", "--no-filter", remote, "+refs/heads/claim/*:refs/remotes/" + remote + "/claim/*", ]); if (!fetched.ok) { fail(`Unit claim registry fetch failed: ${fetched.stderr.trim()}`); } } function refTip( projectDir: string, remote: string | null, ref: string, ): string | null { if (remote) { const found = git(projectDir, ["ls-remote", remote, ref]); if (!found.ok) { fail(`Unit claim registry read failed: ${found.stderr.trim() || found.stdout.trim()}`); } const line = found.stdout.trim().split(/\r?\n/).find(Boolean); return line ? line.split(/\s+/)[0] : null; } const found = git(projectDir, ["rev-parse", "--verify", ref]); return found.ok ? found.stdout.trim() : null; } function readPayload( projectDir: string, oid: string, options: { localOnly?: boolean } = {}, ): UnitClaimPayload | null { const shown = options.localOnly ? localGit(projectDir, ["show", `${oid}:${CLAIM_FILE}`]) : git(projectDir, ["show", `${oid}:${CLAIM_FILE}`]); if (!shown.ok) return null; try { const parsed = JSON.parse(shown.stdout) as UnitClaimPayload; if ( parsed.version !== 1 || (parsed.status !== "claimed" && parsed.status !== "released") || typeof parsed.unit !== "string" || !Number.isInteger(parsed.generation) || typeof parsed.nonce !== "string" || !/^[0-9a-f]{40}$/.test(parsed.base_oid) || typeof parsed.integration_ref !== "string" || typeof parsed.claim_ref !== "string" || (parsed.audit_shard !== undefined && (typeof parsed.audit_shard !== "string" || !/^[A-Za-z0-9._-]+\.md$/.test(parsed.audit_shard))) || ( parsed.candidate_tree_oid !== undefined && !/^[0-9a-f]{40}$/.test(parsed.candidate_tree_oid) ) || ( parsed.candidate_head_oid !== undefined && !/^[0-9a-f]{40}$/.test(parsed.candidate_head_oid) ) ) { return null; } return parsed; } catch { return null; } } function ensureObject( projectDir: string, remote: string | null, oid: string, ref: string, ): void { const hasCommit = (): boolean => localGit(projectDir, ["cat-file", "-e", `${oid}^{commit}`]).ok; const payloadBlob = (): string | null => { const found = localGit(projectDir, ["rev-parse", `${oid}:${CLAIM_FILE}`]); return found.ok && /^[0-9a-f]{40}$/.test(found.stdout.trim()) ? found.stdout.trim() : null; }; const hasBlob = (blob: string | null): boolean => blob !== null && localGit(projectDir, ["cat-file", "-e", blob]).ok; let blob = payloadBlob(); if (hasCommit() && hasBlob(blob)) return; if (!remote) { fail( `Unit claim registry payload is unavailable at ${ref}; the local repository may be a partial clone with the claim payload blob missing.`, ); } const fetched = git(projectDir, [ "fetch", "--no-tags", "--no-filter", remote, ref, ]); if (!fetched.ok) { fail( `Unit claim registry fetch failed: ${fetched.stderr.trim()} ` + `(a partial clone requires a non-filtered fetch of ${ref}).`, ); } blob = payloadBlob(); if (blob && !hasBlob(blob)) { const hydrated = git(projectDir, [ "fetch", "--no-tags", "--no-filter", remote, blob, ]); if (!hydrated.ok) { fail( `Unit claim registry fetch failed: ${hydrated.stderr.trim()} ` + `(the partial clone is missing payload blob ${blob} for ${ref}).`, ); } } if (!hasCommit() || !hasBlob(blob)) { fail( `Unit claim registry fetch failed: payload at ${ref} is unavailable after a non-filtered fetch; ` + "the partial clone is missing the claim payload blob.", ); } } function currentClaim( projectDir: string, remote: string | null, ref: string, ): UnitClaimView | null { const oid = refTip(projectDir, remote, ref); if (!oid) return null; ensureObject(projectDir, remote, oid, ref); const payload = readPayload(projectDir, oid, { localOnly: true }); if (!payload) fail(`Unit claim registry payload is invalid at ${ref}.`); return { unit: payload.unit, status: payload.status, owner: payload.owner, generation: payload.generation, nonce: payload.nonce, oid, ref, payload, }; } function createClaimCommit( projectDir: string, parentOid: string, payload: UnitClaimPayload, sourceTreeOid?: string, additionalParentOid?: string, ): string { const scratch = mkdtempSync(join(tmpdir(), "aidlc-unit-claim-")); const index = join(scratch, "index"); try { const env = { GIT_INDEX_FILE: index, GIT_AUTHOR_NAME: "AI-DLC Unit Claims", GIT_AUTHOR_EMAIL: "aidlc-unit@local", GIT_COMMITTER_NAME: "AI-DLC Unit Claims", GIT_COMMITTER_EMAIL: "aidlc-unit@local", }; const read = git(projectDir, ["read-tree", sourceTreeOid ?? parentOid], env); if (!read.ok) fail(`git read-tree failed: ${read.stderr.trim()}`); const blob = spawnSync("git", ["hash-object", "-w", "--stdin"], { cwd: projectDir, encoding: "utf-8", input: `${JSON.stringify(payload, null, 2)}\n`, }); if (blob.status !== 0) fail(`git hash-object failed: ${(blob.stderr ?? "").trim()}`); const update = git( projectDir, ["update-index", "--add", "--cacheinfo", `100644,${(blob.stdout ?? "").trim()},${CLAIM_FILE}`], env, ); if (!update.ok) fail(`git update-index failed: ${update.stderr.trim()}`); const tree = git(projectDir, ["write-tree"], env); if (!tree.ok) fail(`git write-tree failed: ${tree.stderr.trim()}`); const commitArgs = [ "commit-tree", tree.stdout.trim(), "-p", parentOid, ...(additionalParentOid ? ["-p", additionalParentOid] : []), "-m", `aidlc unit ${payload.status}: ${payload.unit} generation ${payload.generation}`, ]; const commit = git(projectDir, commitArgs, env); if (!commit.ok) fail(`git commit-tree failed: ${commit.stderr.trim()}`); return commit.stdout.trim(); } finally { rmSync(scratch, { recursive: true, force: true }); } } function updateClaimRef( projectDir: string, remote: string | null, ref: string, commitOid: string, expectedOid: string | null, ): boolean { if (remote) { const lease = `--force-with-lease=${ref}:${expectedOid ?? ""}`; const pushed = git(projectDir, ["push", remote, lease, `${commitOid}:${ref}`]); return pushed.ok; } const updated = git(projectDir, [ "update-ref", ref, commitOid, expectedOid ?? ZERO_OID, ]); return updated.ok; } function activeIdentity(projectDir: string): { space: string; intentUuid: string; intentId8: string; } { const space = activeSpace(projectDir); const intentUuid = activeIntentUuid(projectDir, space); if (!intentUuid) fail("No active intent UUID; switch to the workflow before claiming a Unit."); return { space, intentUuid, intentId8: idSuffix(intentUuid) }; } function stateAtOid(projectDir: string, oid: string): string { const relative = relativeRecordDir(projectDir); if (!relative) fail("Cannot resolve the active intent record path."); const shown = git(projectDir, ["show", `${oid}:${relative}/aidlc-state.md`]); if (!shown.ok) fail("The fetched integration ref does not contain the active intent state."); return shown.stdout; } function dependencyEdgesAtOid(projectDir: string, oid: string): ReturnType { const relative = relativeRecordDir(projectDir); if (!relative) fail("Cannot resolve the active intent record path."); const shown = git( projectDir, ["show", `${oid}:${relative}/inception/units-generation/unit-of-work-dependency.md`], ); if (!shown.ok) fail("The fetched integration ref has no Unit dependency artifact."); return parseBoltDag(shown.stdout); } function completedUnits(state: string): Set { const match = /^## Unit Progress\s*$/m.exec(state); if (!match) return new Set(); const after = match.index + match[0].length; const next = /^## /m.exec(state.slice(after)); const section = state.slice(after, next ? after + next.index : state.length); const table = section .split(/\r?\n/) .filter((line) => line.startsWith("|")) .map((line) => line.split("|").slice(1, -1).map((cell) => cell.trim())); const header = table.find((cells) => cells[0]?.toLowerCase() === "unit"); if (!header) return new Set(); const mergedIndex = header.findIndex( (cell) => cell.toLowerCase() === "merged", ); const done = new Set(); for (const cells of table) { if (cells.length !== header.length || cells.length < 4) continue; if ( (cells[0].toLowerCase() === "unit" && cells[1].toLowerCase() === "owner") || cells.every((cell) => /^-+$/.test(cell)) ) { continue; } const workCells = cells.slice( 2, mergedIndex >= 0 ? mergedIndex : undefined, ); if ( workCells.every((cell) => cell === "[x]") && (mergedIndex < 0 || cells[mergedIndex] === "[x]") ) { done.add(cells[0]); } } return done; } function skeletonCompletedAtOid(projectDir: string, oid: string): boolean { const relative = relativeRecordDir(projectDir); if (!relative) return false; const listed = git(projectDir, [ "ls-tree", "-r", "--name-only", oid, `${relative}/audit`, ]); if (!listed.ok) return false; const events: Array<{ event: string; names: string; timestamp: string; skeleton: boolean; position: number; }> = []; let position = 0; for (const path of listed.stdout.split(/\r?\n/).filter(Boolean)) { const shown = git(projectDir, ["show", `${oid}:${path}`]); if (!shown.ok) continue; for (const block of shown.stdout.split(/\n---\n/)) { const event = /^\*\*Event\*\*:\s*(.+)$/m.exec(block)?.[1]?.trim(); const names = /^\*\*Bolt names\*\*:\s*(.+)$/m.exec(block)?.[1]?.trim() ?? ""; if (!event) continue; events.push({ event, names, timestamp: /^\*\*Timestamp\*\*:\s*(.+)$/m.exec(block)?.[1]?.trim() ?? "", skeleton: /^\*\*Walking skeleton\*\*:\s*true\s*$/m.test(block), position: position++, }); } } events.sort((a, b) => a.timestamp !== b.timestamp ? (a.timestamp < b.timestamp ? -1 : 1) : a.position - b.position ); const started = new Set(); for (const event of events) { if (event.event === "WORKFLOW_STARTED" || event.event === "STAGE_JUMPED") { started.clear(); continue; } if (event.event === "BOLT_STARTED" && event.skeleton) { started.add(event.names); continue; } if (event.event === "BOLT_COMPLETED" && started.has(event.names)) { return true; } } return false; } function openingStatus( projectDir: string, baseOid: string, ): { units: string[]; blockers: Map; completed: Set } { const state = stateAtOid(projectDir, baseOid); if (!isTeamUnitOwnership(state)) fail("Unit claims require Unit Ownership: team."); const parsed = dependencyEdgesAtOid(projectDir, baseOid); if (!parsed.ok) fail(`Cannot resolve Unit dependencies: ${parsed.reason}: ${parsed.detail}`); const completed = completedUnits(state); const scope = getField(state, "Scope") ?? ""; const skeletonOn = loadScopeMetadata()[scope]?.skeleton === true; const skeletonBlocked = skeletonOn && !skeletonCompletedAtOid(projectDir, baseOid); const blockers = new Map(); for (const edge of parsed.units) { const waiting = edge.depends_on.filter((dep) => !completed.has(dep)); if (skeletonBlocked) waiting.unshift("walking-skeleton"); blockers.set(edge.name, [...new Set(waiting)]); } return { units: parsed.units.map((edge) => edge.name), blockers, completed }; } function localOpeningStatus( projectDir: string, ): { units: string[]; blockers: Map; completed: Set } { const state = readStateFile(projectDir); const dependencyBody = readFileSync(unitDependencyPath(projectDir), "utf-8"); return localOpeningStatusFrom(state, dependencyBody); } function localOpeningStatusFrom( state: string, dependencyBody: string, ): { units: string[]; blockers: Map; completed: Set } { if (!isTeamUnitOwnership(state)) fail("Unit claims require Unit Ownership: team."); const parsed = parseBoltDag(dependencyBody); if (!parsed.ok) fail(`Cannot resolve Unit dependencies: ${parsed.reason}: ${parsed.detail}`); const completed = completedUnits(state); const scope = getField(state, "Scope") ?? ""; const skeletonBlocked = loadScopeMetadata()[scope]?.skeleton === true && !completed.has(parsed.units[0]?.name ?? ""); const blockers = new Map(); for (const edge of parsed.units) { const waiting = edge.depends_on.filter((dep) => !completed.has(dep)); if (skeletonBlocked) waiting.unshift("walking-skeleton"); blockers.set(edge.name, [...new Set(waiting)]); } return { units: parsed.units.map((edge) => edge.name), blockers, completed }; } function allClaims( projectDir: string, remote: string | null, intentId8: string, units: string[], ): Map { fetchClaimRefs(projectDir, remote); const claims = new Map(); for (const unit of units) { const ref = claimRef(intentId8, unit); const claim = currentClaim(projectDir, remote, ref); if (claim) claims.set(unit, claim); } return claims; } function buildOverview( opening: ReturnType, claims: Map, warning?: string, ): UnitClaimOverview { const claimable: string[] = []; const claimed: Array<{ unit: string; owner: string; generation: number }> = []; const waiting: Array<{ unit: string; blockedBy: string[] }> = []; for (const unit of opening.units) { if (opening.completed.has(unit)) continue; const claim = claims.get(unit); if (claim?.status === "claimed") { claimed.push({ unit, owner: claim.owner, generation: claim.generation }); continue; } const blockedBy = opening.blockers.get(unit) ?? []; if (blockedBy.length > 0) waiting.push({ unit, blockedBy }); else claimable.push(unit); } return { claimable, claimed, waiting, claims, ...(warning ? { warning } : {}) }; } function cacheClaims( projectDir: string, claims: Map, warning?: string, ): Map { const identity = activeIdentity(projectDir); const priorCache = readUnitClaimRegistryCache(projectDir); const cached: Record = {}; for (const [unit, claim] of claims) { const prior = priorCache?.space === identity.space && priorCache.intent_uuid === identity.intentUuid ? priorCache.claims[unit] : undefined; const movementObserved = prior !== undefined && prior.oid !== claim.oid; const observedAt = prior?.observed_at ?? isoTimestamp(); const nextObservedAt = movementObserved ? isoTimestamp() : observedAt; claim.observedAt = observedAt; claim.movementObserved = movementObserved; cached[unit] = { status: claim.status, owner: claim.owner, generation: claim.generation, nonce: claim.nonce, ref: claim.ref, oid: claim.oid, observed_at: nextObservedAt, }; if (claim.status === "claimed") { writeClaimGeneration(projectDir, unit, claim.generation); } else { clearClaimGeneration(projectDir, unit); } } writeUnitClaimRegistryCache(projectDir, { version: 1, space: identity.space, intent_uuid: identity.intentUuid, claims: cached, ...(warning ? { warning } : {}), }); return claims; } interface UnitClaimIdentity { space: string; intentUuid: string; intentId8: string; } function cachedClaimsForIdentity( projectDir: string, identity: UnitClaimIdentity, includeCache: boolean, ): Map { const cache = readUnitClaimRegistryCache(projectDir); const claims = new Map(); if ( includeCache && cache && cache.space === identity.space && cache.intent_uuid === identity.intentUuid ) { for (const [unit, claim] of Object.entries(cache.claims)) { claims.set(unit, { unit, status: claim.status, owner: claim.owner, generation: claim.generation, nonce: claim.nonce, oid: claim.oid, ref: claim.ref, observedAt: claim.observed_at, movementObserved: false, payload: { version: 1, status: claim.status, owner: claim.owner, space: identity.space, intent_uuid: identity.intentUuid, intent_id8: identity.intentId8, unit, generation: claim.generation, nonce: claim.nonce, base_oid: "", integration_ref: "", claim_ref: claim.ref, predecessor_oid: null, gate_rhythm: "per-stage", }, }); } } const refs = localGit(projectDir, [ "for-each-ref", "--format=%(objectname) %(refname)", "refs/heads/claim/", "refs/remotes/", ]); if (!refs.ok) return claims; for (const line of refs.stdout.split(/\r?\n/).filter(Boolean)) { const [oid, ref] = line.trim().split(/\s+/, 2); if (!oid || !ref) continue; if ( !ref.startsWith(`refs/heads/claim/${identity.intentId8}/`) && !new RegExp( `^refs/remotes/[^/]+/claim/${identity.intentId8.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/`, ).test(ref) ) { continue; } const payload = readPayload(projectDir, oid, { localOnly: true }); if (!payload || payload.intent_uuid !== identity.intentUuid) { throw new Error( `Local Unit claim registry payload is unavailable or invalid at ${ref}; ` + "fetch that claim ref without a partial-clone filter before retrying.", ); } const prior = claims.get(payload.unit); if ( prior && (prior.generation > payload.generation || (prior.generation === payload.generation && ( prior.oid === oid || (prior.status === "claimed" && payload.status === "released") ))) ) { continue; } claims.set(payload.unit, { unit: payload.unit, status: payload.status, owner: payload.owner, generation: payload.generation, nonce: payload.nonce, oid, ref: payload.claim_ref, observedAt: cache?.space === identity.space && cache.intent_uuid === identity.intentUuid ? cache.claims[payload.unit]?.observed_at : undefined, movementObserved: cache?.space === identity.space && cache.intent_uuid === identity.intentUuid && cache.claims[payload.unit] !== undefined && cache.claims[payload.unit]?.oid !== oid, payload, }); } return claims; } function cachedClaims(projectDir: string): Map { return cachedClaimsForIdentity(projectDir, activeIdentity(projectDir), true); } export function cachedUnitClaimOverview( projectDir: string, options: { writeCache?: boolean } = {}, ): UnitClaimOverview { const pd = resolveProjectDir(projectDir); const state = readStateFile(pd); if (!isTeamUnitOwnership(state)) { return { claimable: [], claimed: [], waiting: [], claims: new Map() }; } const opening = localOpeningStatus(pd); const cache = readUnitClaimRegistryCache(pd); let claims = cachedClaims(pd); if (options.writeCache !== false && !isReadOnlyEngineProbe()) { claims = cacheClaims(pd, claims, cache?.warning); } return buildOverview(opening, claims, cache?.warning); } export function localUnitClaimOverviewForIntent( projectDir: string, selector: { space: string; intentUuid: string; stateContent: string; dependencyBody: string; }, ): UnitClaimOverview { const pd = resolveProjectDir(projectDir); if (!isTeamUnitOwnership(selector.stateContent)) { return { claimable: [], claimed: [], waiting: [], claims: new Map() }; } const opening = localOpeningStatusFrom( selector.stateContent, selector.dependencyBody, ); const claims = cachedClaimsForIdentity( pd, { space: selector.space, intentUuid: selector.intentUuid, intentId8: idSuffix(selector.intentUuid), }, true, ); return buildOverview(opening, claims); } export function unitClaimOverview(projectDir: string): UnitClaimOverview { const pd = resolveProjectDir(projectDir); const state = readStateFile(pd); if (!isTeamUnitOwnership(state)) { return { claimable: [], claimed: [], waiting: [], claims: new Map() }; } const identity = activeIdentity(pd); const integration = fetchIntegration(pd); const opening = openingStatus(pd, integration.oid); const claims = allClaims(pd, integration.remote, identity.intentId8, opening.units); const observedClaims = cacheClaims(pd, claims); return buildOverview(opening, observedClaims); } function updateCachedClaim( projectDir: string, claim: UnitClaimView, ): void { const claims = cachedClaims(projectDir); claims.set(claim.unit, claim); cacheClaims(projectDir, claims); } function gitOutput(projectDir: string, args: string[], label: string): string { const result = git(projectDir, args); if (!result.ok) { fail(`${label}: ${result.stderr.trim() || result.stdout.trim() || `exit ${result.code}`}`); } return result.stdout.trim(); } function gitPathExistsAt( projectDir: string, oid: string, path: string, ): boolean { return git(projectDir, ["cat-file", "-e", `${oid}:${path}`]).ok; } function gitTextAt( projectDir: string, oid: string, path: string, ): string { const shown = git(projectDir, ["show", `${oid}:${path}`]); if (!shown.ok) fail(`Pinned candidate is missing ${path}.`); return shown.stdout; } type CandidateAuditEvent = AuditShardEvent; function candidateAuditEvents( projectDir: string, oid: string, shards: string[], ): CandidateAuditEvent[] { const events = shards.flatMap((path, shardIndex) => gitTextAt(projectDir, oid, path) .replace(/\r\n/g, "\n") .split(/\n---\n/) .filter((block) => block.trim().length > 0) .map((block, pos): CandidateAuditEvent | null => { const event = auditBlockField(block, "Event"); if (!event) return null; return { event, block, timestamp: auditBlockField(block, "Timestamp") ?? "", shard: path, shardIndex, pos, }; }) .filter((event): event is CandidateAuditEvent => event !== null) ); return events.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; }); } function auditBlockMatchesStage(block: string, stage: string): boolean { const gateStages = auditBlockField(block, "Gate Stages"); if (gateStages) { return gateStages .split(",") .map((value) => value.trim()) .includes(stage); } return auditBlockField(block, "Stage") === stage; } function attemptEventMatches( event: CandidateAuditEvent, unit: string, generation: number, stage: string, ): boolean { return ( auditBlockField(event.block, "Unit") === unit && auditBlockField(event.block, "Attempt Generation") === String(generation) && auditBlockMatchesStage(event.block, stage) ); } function candidateReviewFingerprint( projectDir: string, oid: string, recordPrefix: string, unit: string, stage: { slug: string; produces?: string[]; optional_produces?: string[]; produces_kinds?: Record; }, unitKind: string | null, ): string { const names = filterProducesByKind( stage.produces_kinds, [...(stage.produces ?? []), ...(stage.optional_produces ?? [])], unitKind, ); const manifest: Array<[string, string]> = names.map((name) => { const logicalPath = `construction/${unit}/${stage.slug}/${artifactFilename(name)}`; const path = `${recordPrefix}/${logicalPath}`; if (!gitPathExistsAt(projectDir, oid, path)) { return [logicalPath, "missing"]; } const digest = createHash("sha256") .update(gitTextAt(projectDir, oid, path)) .digest("hex"); return [logicalPath, `sha256:${digest}`]; }); manifest.sort(([a], [b]) => a.localeCompare(b)); return `sha256:${ createHash("sha256").update(JSON.stringify(manifest)).digest("hex") }`; } function candidateReviewerReady( events: CandidateAuditEvent[], projectDir: string, oid: string, recordPrefix: string, unit: string, generation: number, stage: { slug: string; reviewer?: string; produces?: string[]; optional_produces?: string[]; produces_kinds?: Record; }, unitKind: string | null, ): boolean { const expectedFingerprint = candidateReviewFingerprint( projectDir, oid, recordPrefix, unit, stage, unitKind, ); const completionRecord = (block: string): ReviewRecord | null => pairedReviewRecordForCompletion(projectDir, block, (_projectDir, ref) => { const path = `${recordPrefix}/${ref.path}`; if (!gitPathExistsAt(projectDir, oid, path)) return null; const bytes = gitTextAt(projectDir, oid, path); if (reviewRecordDigest(bytes) !== ref.digest) return null; return parseReviewRecordBytes(bytes); }); const artifactPrefix = `construction/${unit}/${stage.slug}/`; return candidateReviewCoverageProjection(events, { unit, generation, stage: stage.slug, reviewer: stage.reviewer, artifactPrefix, expectedFingerprint, completionRecord, }); } function validateCandidateUnitProgress( state: string, claim: UnitClaimView, stages: string[], ): void { const heading = /^## Unit Progress\s*$/m.exec(state); if (!heading) fail("Pinned candidate state has no Unit Progress projection."); const after = heading.index + heading[0].length; const next = /^## /m.exec(state.slice(after)); const section = state.slice(after, next ? after + next.index : state.length); const rows = section .split(/\r?\n/) .filter((line) => line.startsWith("|")) .map((line) => line.split("|").slice(1, -1).map((cell) => cell.trim())); const header = rows.find((cells) => cells[0]?.toLowerCase() === "unit"); if (!header) fail("Pinned candidate Unit Progress projection has no header."); const row = rows.find((cells) => cells[0] === claim.unit); if (!row || row.length !== header.length) { fail(`Pinned candidate Unit Progress has no valid row for "${claim.unit}".`); } const ownerIndex = header.findIndex((cell) => cell.toLowerCase() === "owner"); if (ownerIndex < 0 || row[ownerIndex] !== claim.owner) { fail(`Pinned candidate Unit Progress owner does not match "${claim.owner}".`); } for (const stage of stages) { const stageIndex = header.indexOf(stage); if (stageIndex < 0 || row[stageIndex] !== "[x]") { fail(`Pinned candidate Unit Progress stage "${stage}" is not complete.`); } } const gateIndex = header.findIndex((cell) => cell.toLowerCase() === "gate"); if (gateIndex < 0 || row[gateIndex] !== "[x]") { fail("Pinned candidate Unit Progress gate is not approved."); } } function mainUnitRowMerged( projectDir: string, transaction: UnitMergeTransaction, ): boolean { const state = readStateFile(projectDir); const heading = /^## Unit Progress\s*$/m.exec(state); if (!heading) return false; const after = heading.index + heading[0].length; const next = /^## /m.exec(state.slice(after)); const rows = state .slice(after, next ? after + next.index : state.length) .split(/\r?\n/) .filter((line) => line.startsWith("|")) .map((line) => line.split("|").slice(1, -1).map((cell) => cell.trim())); const header = rows.find((cells) => cells[0]?.toLowerCase() === "unit"); const row = rows.find((cells) => cells[0] === transaction.unit); if (!header || !row || row.length !== header.length) return false; const expected = [ "owner", ...(transaction.live_stage_columns ?? transaction.evidence.stages_expected), "gate", "merged", ]; return expected.every((name) => { const index = header.findIndex((cell) => cell.toLowerCase() === name); if (index < 0) return false; return name === "owner" ? row[index] === transaction.owner : row[index] === "[x]"; }); } interface CandidateBoundary { changedAudit: string[]; outsideUnitRecordPaths: string[]; violations: string[]; } const TRANSPORTED_ATTEMPT_EVENTS = new Set([ "UNIT_STARTED", "UNIT_PAUSED", "UNIT_RESUMED", "UNIT_COMPLETED", "STAGE_AWAITING_APPROVAL", "STAGE_REVISING", "GATE_APPROVED", "GATE_REJECTED", "PLAN_APPROVAL_RECORDED", "REVIEW_REQUESTED", "REVIEW_COMPLETED", ]); const TRANSPORTED_DATA_EVENTS = new Set([ "ARTIFACT_CREATED", "ARTIFACT_UPDATED", ]); function isTransportedMainAuthority(event: CandidateAuditEvent): boolean { if ( event.event === "HUMAN_TURN" || event.event === "QUESTION_ANSWERED" || event.event === "SUMMARY_CONFIRMATION_RECORDED" || event.event === "AUTONOMY_MODE_SET" || event.event === "UNIT_MERGED" || event.event.startsWith("MERGE_DISPATCH_") ) { return true; } return ( (event.event === "GATE_APPROVED" || event.event === "GATE_REJECTED") && ( auditBlockField(event.block, "Stage") === "unit-merge" || auditBlockField(event.block, "Gate Scope") === "unit-merge" ) ); } function transportedAuditViolation( event: CandidateAuditEvent, unit: string, generation: number, ): string | null { if (isTransportedMainAuthority(event)) { return `${event.event} is main-authority evidence`; } if (TRANSPORTED_ATTEMPT_EVENTS.has(event.event)) { const eventUnit = auditBlockField(event.block, "Unit"); const eventGeneration = auditBlockField( event.block, "Attempt Generation", ); if (eventUnit !== unit) { return `${event.event} receipt belongs to Unit ${eventUnit ?? "(unitless)"}`; } if (eventGeneration !== String(generation)) { return ( `${event.event} receipt belongs to attempt generation ` + `${eventGeneration ?? "(missing)"}, expected ${generation}` ); } return null; } if (TRANSPORTED_DATA_EVENTS.has(event.event)) { const eventUnit = auditBlockField(event.block, "Unit"); const eventGeneration = auditBlockField( event.block, "Attempt Generation", ); if (eventUnit !== null && eventUnit !== unit) { return `${event.event} row belongs to Unit ${eventUnit}`; } if ( eventGeneration !== null && eventGeneration !== String(generation) ) { return `${event.event} row belongs to attempt generation ${eventGeneration}`; } const file = (auditBlockField(event.block, "File") ?? "") .replace(/\\/g, "/"); const unitArtifactRoot = `construction/${unit}/`; if ( !file.startsWith(unitArtifactRoot) && !file.includes(`/${unitArtifactRoot}`) ) { return `${event.event} row is outside claimed Unit artifacts`; } return null; } return `${event.event} is not in the transported Unit evidence allowlist`; } function candidateBoundary( projectDir: string, baseOid: string, candidateOid: string, recordPrefix: string, unit: string, generation: number, expectedAuditShard?: string, ): CandidateBoundary { const auditRoot = `${recordPrefix}/audit`; const auditChanges = gitOutput( projectDir, [ "diff", "--no-renames", "--name-status", `${baseOid}..${candidateOid}`, "--", auditRoot, ], "Cannot compare candidate audit shards", ) .split(/\r?\n/) .filter(Boolean); const addedAudit = auditChanges .filter((line) => line.startsWith("A\t")) .map((line) => line.split("\t").at(-1) ?? "") .filter(Boolean); const changedAudit = addedAudit.filter((path) => isActiveIntentAuditPath(path, recordPrefix) ); const violations = auditChanges .filter((line) => !line.startsWith("A\t")) .map((line) => `${line.split("\t").at(-1) ?? line} (inherited audit shard)`); for (const path of addedAudit.filter((path) => !isActiveIntentAuditPath(path, recordPrefix) )) { violations.push(`${path} (invalid active-intent audit shard path)`); } if (changedAudit.length !== 1) { violations.push( `${auditRoot}/ (expected exactly one newly added team audit shard; found ${changedAudit.length})`, ); } if ( expectedAuditShard && ( changedAudit.length !== 1 || changedAudit[0] !== `${auditRoot}/${expectedAuditShard}` ) ) { violations.push( `${auditRoot}/ (expected claim-bound audit shard ${expectedAuditShard})`, ); } const changedPaths = gitOutput( projectDir, ["diff", "--no-renames", "--name-only", `${baseOid}..${candidateOid}`], "Cannot inspect pinned candidate diff", ) .split(/\r?\n/) .filter(Boolean); const unitRoot = `${recordPrefix}/construction/${unit}/`; const constructionRoot = `${recordPrefix}/construction/`; const reviewUnitMarker = `/${REVIEW_RECORDS_DIR}/`; const unitRootKey = unitRoot.toLowerCase(); const constructionRootKey = constructionRoot.toLowerCase(); const recordPrefixKey = `${recordPrefix}/`.toLowerCase(); const outsideUnitRecordPaths: string[] = []; for (const path of changedPaths) { if (isEngineMergeMetadata(projectDir, path, recordPrefix)) continue; const pathKey = path.toLowerCase(); const reviewMarkerIndex = path.indexOf(reviewUnitMarker); if (reviewMarkerIndex !== -1) { const reviewParts = path.slice(reviewMarkerIndex + reviewUnitMarker.length).split("/"); if ( reviewParts.length === 5 && reviewParts[1] === "units" && reviewParts[2] === unit ) continue; } if (pathKey.startsWith(unitRootKey)) continue; if (changedAudit.includes(path)) continue; if ( pathKey.startsWith(constructionRootKey) || pathKey.startsWith(recordPrefixKey) || pathKey.startsWith("aidlc/") ) { violations.push(`${path} (outside claimed Unit record tree)`); continue; } outsideUnitRecordPaths.push(path); } for (const event of candidateAuditEvents( projectDir, candidateOid, changedAudit, )) { const violation = transportedAuditViolation(event, unit, generation); if (violation) { violations.push( `${event.shard} (${violation})`, ); } } return { changedAudit: [...new Set(changedAudit)].sort(), outsideUnitRecordPaths: [...new Set(outsideUnitRecordPaths)].sort(), violations: [...new Set(violations)].sort(), }; } function candidateEvidence( projectDir: string, claim: UnitClaimView, candidateBaseOid: string, liveIntegrationOid = candidateBaseOid, ): UnitMergeEvidence { const recordPrefix = relativeRecordDir(projectDir); if (!recordPrefix) fail("Cannot resolve the active intent record for candidate evidence."); const statePath = `${recordPrefix}/aidlc-state.md`; const state = gitTextAt(projectDir, claim.oid, statePath); if (!isTeamUnitOwnership(state)) { fail("Pinned candidate state does not record Unit Ownership: team."); } const integrationState = stateAtOid(projectDir, liveIntegrationOid); if (!isTeamUnitOwnership(integrationState)) { fail("Pinned integration state does not record Unit Ownership: team."); } const scope = getField(integrationState, "Scope") ?? ""; const stages = unitMajorConstructionStageSlugs( scope, integrationState, true, ); if (stages.length === 0) fail("Pinned candidate has no active per-unit Construction stages."); validateCandidateUnitProgress(state, claim, stages); const graph = loadStageGraphAll(); const baseState = stateAtOid(projectDir, candidateBaseOid); const baseStages = unitMajorConstructionStageSlugs( getField(baseState, "Scope") ?? "", baseState, true, ); const baseDag = dependencyEdgesAtOid(projectDir, candidateBaseOid); const dag = dependencyEdgesAtOid(projectDir, liveIntegrationOid); if (!baseDag.ok) { fail(`Pinned candidate base Unit DAG is ${baseDag.reason}: ${baseDag.detail}.`); } if (!dag.ok) { fail(`Pinned integration Unit DAG is ${dag.reason}: ${dag.detail}.`); } const contract = ( units: typeof dag.units, stageColumns: string[], ): string => JSON.stringify({ stage_columns: stageColumns, units: units.map((entry) => ({ name: entry.name, kind: entry.kind ?? null, depends_on: [...entry.depends_on].sort(), })), }); if (contract(baseDag.units, baseStages) !== contract(dag.units, stages)) { fail( `Unit "${claim.unit}" candidate is based on a stale Construction contract; ` + "rebase onto the current integration branch and publish again.", ); } const unit = dag.units.find((entry) => entry.name === claim.unit); if (!unit) fail(`Pinned integration Unit DAG has no Unit "${claim.unit}".`); const unitKind = unit.kind ?? null; const forcedMergeJournals = gitOutput( projectDir, [ "diff", "--name-only", `${candidateBaseOid}..${claim.oid}`, "--", `aidlc/${UNIT_MERGE_DIR}`, ], "Cannot inspect candidate merge journals", ) .split(/\r?\n/) .filter(Boolean); if (forcedMergeJournals.length > 0) { fail( `Pinned candidate contains engine merge journals: ${forcedMergeJournals.join(", ")}.`, ); } const boundary = candidateBoundary( projectDir, candidateBaseOid, claim.oid, recordPrefix, claim.unit, claim.generation, claim.payload.audit_shard, ); if (!claim.payload.audit_shard) { fail( `Pinned candidate claim has no bound audit shard; release and re-claim Unit "${claim.unit}" before publishing again.`, ); } if (boundary.violations.length > 0) { fail( `Pinned candidate violates claimed Unit ownership at: ${ boundary.violations.join(", ") }.`, ); } const changedAudit = boundary.changedAudit; const transportedEvents = candidateAuditEvents( projectDir, claim.oid, changedAudit, ); const authorityRows = transportedEvents.filter((event) => TRANSPORTED_ATTEMPT_EVENTS.has(event.event) || TRANSPORTED_DATA_EVENTS.has(event.event) ); const events = authorityRows; const stagesCompleted = stages.filter((stage) => unitLifecycleSnapshot( projectDir, stage, authorityRows, integrationState, { artifactFingerprint: (stageNode, unitName) => candidateReviewFingerprint( projectDir, claim.oid, recordPrefix, unitName, stageNode, unitKind, ), }, ).receipts.has(claim.unit) ); const gatesExpected = claim.payload.gate_rhythm === "unit-end" ? [stages[stages.length - 1]] : stages; const gatesApproved = gatesExpected.filter((stage) => unitGateStatus( projectDir, stage, claim.unit, claim.payload.gate_rhythm, authorityRows, ) === "approved" ); const reviewersExpected: string[] = []; const reviewersReady: string[] = []; const artifactPaths: string[] = []; for (const stageSlug of stages) { const stage = graph.find((entry) => entry.slug === stageSlug); if (!stage) fail(`Pinned candidate references unknown stage "${stageSlug}".`); const names = filterProducesByKind( stage.produces_kinds, stage.produces ?? [], unitKind, ); for (const name of names) { const path = `${recordPrefix}/construction/${claim.unit}/${stageSlug}/${artifactFilename(name)}`; if (!gitPathExistsAt(projectDir, claim.oid, path)) { fail(`Pinned candidate is missing required artifact ${path}.`); } artifactPaths.push(path); } if (stage.reviewer) { const reviewClass = resolveReviewClass( stage.review_class ?? "adversarial", scope, integrationState, ); if (reviewClass !== "none") { reviewersExpected.push(stageSlug); if ( candidateReviewerReady( events, projectDir, claim.oid, recordPrefix, claim.unit, claim.generation, stage, unitKind, ) ) { reviewersReady.push(stageSlug); } } } } const questionsPath = `${recordPrefix}/construction/${claim.unit}/code-generation/code-generation-questions.md`; let planFingerprint: string | null = null; if (stages.includes("code-generation")) { const plan = gitTextAt( projectDir, claim.oid, `${recordPrefix}/construction/${claim.unit}/code-generation/code-generation-plan.md`, ); const instructions = gitTextAt( projectDir, claim.oid, `${recordPrefix}/construction/${claim.unit}/code-generation/unit-test-instructions.md`, ); const questions = gitTextAt(projectDir, claim.oid, questionsPath); const fingerprint = recordedApprovalFingerprint(questions); const embedded = parseTestingContract(plan); const currentContract = resolveTestingPosture(projectDir); const approvalEvent = events.findLast((event) => event.event === "PLAN_APPROVAL_RECORDED" && attemptEventMatches( event, claim.unit, claim.generation, "code-generation", ) ); const questionsSha256 = createHash("sha256") .update(questions, "utf-8") .digest("hex"); const promptSha256 = createHash("sha256") .update( `${questions .replace(/^\[Answer\]:[ \t]*.*$/gm, "[Answer]:") .trimEnd()}\n`, "utf-8", ) .digest("hex"); if ( fingerprint && instructions.trim().length > 0 && embedded?.contract_sha256 === currentContract.contract_sha256 && approvalEvent && auditBlockField(approvalEvent.block, "Details") === "Approve Plan" && auditBlockField(approvalEvent.block, "Checkpoint") === PLAN_APPROVAL_CHECKPOINT && auditBlockField(approvalEvent.block, "Plan Target") === `unit:${claim.unit}` && auditBlockField(approvalEvent.block, "Intent") === claim.payload.intent_uuid && auditBlockField(approvalEvent.block, "Approval Fingerprint") === fingerprint && auditBlockField(approvalEvent.block, "Questions File") === questionsPath && auditBlockField(approvalEvent.block, "Questions SHA-256") === questionsSha256 && auditBlockField(approvalEvent.block, "Prompt SHA-256") === promptSha256 && (auditBlockField(approvalEvent.block, "Directive Epoch") ?? "").length > 0 && (auditBlockField(approvalEvent.block, "Run floor") ?? "").length > 0 && (auditBlockField(approvalEvent.block, "Session") ?? "").length > 0 && /^\[Answer\]:\s*A\.\s*Approve Plan\s*$/m.test(questions) ) { planFingerprint = fingerprint; } } const mergeHeld = (getField(state, "Merge-Held") ?? "").trim() === "true"; const evidence: UnitMergeEvidence = { stages_expected: stages, stages_completed: stagesCompleted, gates_expected: gatesExpected, gates_approved: gatesApproved, reviewers_expected: reviewersExpected, reviewers_ready: reviewersReady, plan_fingerprint: planFingerprint, artifact_paths: artifactPaths, audit_shards: changedAudit, outside_unit_record_paths: boundary.outsideUnitRecordPaths, merge_held: mergeHeld, }; const incomplete: string[] = []; if (stagesCompleted.length !== stages.length) incomplete.push("UNIT_COMPLETED receipts"); if (gatesApproved.length !== gatesExpected.length) incomplete.push("team gate approvals"); if (reviewersReady.length !== reviewersExpected.length) incomplete.push("reviewer READY receipts"); if (stages.includes("code-generation") && !planFingerprint) { incomplete.push("Plan Approval fingerprint"); } if (changedAudit.length === 0) { incomplete.push("transportable audit shard"); } if (incomplete.length > 0) { fail(`Pinned candidate evidence is incomplete: ${incomplete.join(", ")}.`); } return evidence; } function publishUnit(args: string[], projectDir?: string): void { const { positional } = parseArgs(args); const unit = positional[0]; if (!unit) fail("Usage: aidlc-unit publish "); const pd = resolveProjectDir(projectDir); const stamp = requireLiveClaimForTeamUnit(pd, unit); if (!stamp) fail("Unit publication requires a scoped team checkout."); const dirty = gitOutput( pd, ["status", "--porcelain", "--untracked-files=no"], "Cannot inspect candidate worktree", ); if (dirty) fail("Unit publication requires a clean tracked worktree; commit the candidate first."); const remote = repositoryRemote(pd); const current = currentClaim(pd, remote, stamp.claim_ref); if ( current?.status !== "claimed" || current.nonce !== stamp.nonce || current.generation !== stamp.generation ) { fail(`Unit "${unit}" claim is stale or released; publication refused.`); } const headOid = gitOutput(pd, ["rev-parse", "HEAD"], "Cannot resolve candidate HEAD"); const headTree = gitOutput( pd, ["rev-parse", "HEAD^{tree}"], "Cannot resolve candidate tree", ); const integration = fetchIntegration(pd); const integrationIsAncestor = localGit( pd, ["merge-base", "--is-ancestor", integration.oid, headOid], ).ok; const publicationBaseOid = integrationIsAncestor ? integration.oid : current.payload.base_oid; const publicationIntegrationRef = integrationIsAncestor ? integration.ref : current.payload.integration_ref; if ( current.payload.candidate_tree_oid === headTree && current.payload.candidate_head_oid === headOid && current.payload.base_oid === publicationBaseOid && current.payload.integration_ref === publicationIntegrationRef ) { const recoveredStamp = { ...stamp, claim_oid: current.oid }; finalizeClaimCheckout(pd, recoveredStamp, current); console.log(JSON.stringify({ published: true, recovered: true, unit, candidate_oid: current.oid, generation: current.generation, })); return; } const payload: UnitClaimPayload = { ...current.payload, predecessor_oid: current.oid, base_oid: publicationBaseOid, integration_ref: publicationIntegrationRef, candidate_tree_oid: headTree, candidate_head_oid: headOid, }; const commit = createClaimCommit( pd, current.oid, payload, headTree, headOid, ); if (!updateClaimRef(pd, remote, stamp.claim_ref, commit, current.oid)) { fail(`Unit "${unit}" publication compare-and-swap failed; refresh the claim and retry.`); } invalidateLiveClaimPayloadCache(pd, unit); const published = currentClaim(pd, remote, stamp.claim_ref); if (!published || published.oid !== commit || published.nonce !== stamp.nonce) { fail(`Unit "${unit}" publication verification failed.`); } const updatedStamp = { ...stamp, claim_oid: published.oid }; finalizeClaimCheckout(pd, updatedStamp, published); console.log(JSON.stringify({ published: true, unit, candidate_oid: published.oid, candidate_head_oid: headOid, generation: published.generation, })); } interface PinnedClaimCheck { claim: UnitClaimView; releasedTombstone?: UnitClaimView; } function pinnedClaimFromTransaction( projectDir: string, transaction: UnitMergeTransaction, ): UnitClaimView { const payload = readPayload(projectDir, transaction.pinned_oid, { localOnly: true, }); if ( payload?.status !== "claimed" || payload.unit !== transaction.unit || payload.intent_uuid !== transaction.intent_uuid || payload.generation !== transaction.generation || payload.nonce !== transaction.nonce || payload.owner !== transaction.owner || payload.base_oid !== transaction.candidate_base_oid || payload.candidate_tree_oid !== transaction.candidate_tree_oid ) { fail(`Pinned Unit "${transaction.unit}" claim payload is unavailable or invalid.`); } return { unit: payload.unit, status: payload.status, owner: payload.owner, generation: payload.generation, nonce: payload.nonce, oid: transaction.pinned_oid, ref: transaction.claim_ref, payload, }; } function currentPinnedClaim( projectDir: string, transaction: UnitMergeTransaction, options: { acceptReleasedAttempt?: boolean } = {}, ): PinnedClaimCheck { invalidateLiveClaimPayloadCache(projectDir, transaction.unit); let current: UnitClaimView | null; try { current = currentClaim( projectDir, repositoryRemote(projectDir), transaction.claim_ref, ); } catch (error) { const message = errorMessage(error); if ( !message.startsWith("Unit claim registry read failed:") && !message.startsWith("Unit claim registry fetch failed:") ) { throw error; } fail( `Unit "${transaction.unit}" claim registry is unavailable (${message}); ` + "merge gate and landing fail closed because the pinned attempt may have been tombstoned. Restore registry access and retry.", ); } if ( current?.status === "released" && current.payload.predecessor_oid === transaction.pinned_oid && current.generation === transaction.generation + 1 ) { const accepted = transaction.released_after_git?.tombstone_oid === current.oid && transaction.released_after_git.tombstone_generation === current.generation; if ( (!options.acceptReleasedAttempt && !accepted) || transaction.status !== "git-landed" ) { fail( `Unit "${transaction.unit}" was released after its merge commit landed. ` + `Inspect the landed commit, then recover explicitly with aidlc unit land ${transaction.unit} ` + '--accept-released-attempt --user-input "".', ); } return { claim: pinnedClaimFromTransaction(projectDir, transaction), releasedTombstone: current, }; } if ( current?.status === "claimed" && current.oid === transaction.pinned_oid && current.generation === transaction.generation && current.nonce === transaction.nonce && current.owner !== transaction.owner ) { fail( `Unit "${transaction.unit}" merge journal owner does not match the pinned claim payload owner.`, ); } if ( current?.status !== "claimed" || current.oid !== transaction.pinned_oid || current.generation !== transaction.generation || current.nonce !== transaction.nonce || current.owner !== transaction.owner || current.payload.base_oid !== transaction.candidate_base_oid || current.payload.candidate_tree_oid !== transaction.candidate_tree_oid ) { fail( `Unit "${transaction.unit}" claim ref moved or changed attempt after pin; run aidlc-unit pin ${transaction.unit} again.`, ); } return { claim: current }; } function orderedAuditRows(projectDir: string): ReturnType { return readAuditShardEvents(projectDir).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; }); } function mainAuthorityAuditRows( projectDir: string, ): ReturnType { const mainShard = auditShardName(projectDir); return orderedAuditRows(projectDir).filter( (row) => basename(row.shard) === mainShard, ); } function assertTransactionIdentity( projectDir: string, transaction: UnitMergeTransaction, ): void { const identity = activeIdentity(projectDir); if ( transaction.space !== identity.space || transaction.intent_uuid !== identity.intentUuid || transaction.intent_id8 !== identity.intentId8 || transaction.claim_ref !== claimRef(identity.intentId8, transaction.unit) ) { fail( `Unit "${transaction.unit}" merge transaction belongs to another active space or intent.`, ); } } function requireMergeDispatchDecision( projectDir: string, transaction: UnitMergeTransaction, ): { strategy: "merge"; target: string } { const all = mainAuthorityAuditRows(projectDir); if (!transaction.pin_id) { fail(`Unit "${transaction.unit}" merge transaction has no pin identity; pin it again.`); } const relevant = all.filter( (row) => ( row.event === "MERGE_DISPATCH_INVOKED" || row.event === "MERGE_DISPATCH_RETURNED" || row.event === "MERGE_DISPATCH_FALLBACK" ) && auditBlockField(row.block, "Bolt slug") === transaction.unit && auditBlockField(row.block, "Pinned OID") === transaction.pinned_oid && auditBlockField(row.block, "Attempt Generation") === String(transaction.generation) && auditBlockField(row.block, "Pin Transaction") === transaction.pin_id, ); const invokedIndex = relevant.findLastIndex( (row) => row.event === "MERGE_DISPATCH_INVOKED", ); if (invokedIndex < 0) { fail(`Unit "${transaction.unit}" merge gate requires MERGE_DISPATCH_INVOKED after pinning.`); } const terminal = relevant .slice(invokedIndex + 1) .findLast( (row) => row.event === "MERGE_DISPATCH_RETURNED" || row.event === "MERGE_DISPATCH_FALLBACK", ); if (!terminal) { fail(`Unit "${transaction.unit}" merge dispatch has no terminal result.`); } if (!humanPresenceGuardDisabled()) { const terminalIndex = all.indexOf(terminal); const previousGate = [...all] .reverse() .find( (row) => (row.event === "GATE_APPROVED" || row.event === "GATE_REJECTED") && auditBlockField(row.block, "Stage") !== null, ); const previousGateIndex = previousGate ? all.indexOf(previousGate) : -1; const humanFloor = Math.max(terminalIndex, previousGateIndex); if ( terminalIndex < 0 || !all.slice(humanFloor + 1).some((row) => row.event === "HUMAN_TURN") ) { fail( `Unit "${transaction.unit}" merge gate requires a typed human turn after merge dispatch.`, ); } } if (terminal.event === "MERGE_DISPATCH_FALLBACK") { return { strategy: "merge", target: transaction.integration_branch }; } const strategy = auditBlockField(terminal.block, "Strategy"); const target = auditBlockField(terminal.block, "Target branch"); if (strategy !== "merge") { fail( `Unit "${transaction.unit}" pinned transaction requires merge strategy; dispatch returned "${strategy ?? "missing"}".`, ); } if (!target) fail(`Unit "${transaction.unit}" merge dispatch omitted its target branch.`); return { strategy: "merge", target }; } function mergeGateRecord( projectDir: string, transaction: UnitMergeTransaction, ): { decision: "approve" | "reject"; strategy: string | null; target: string | null; } | null { const decisions = mainAuthorityAuditRows(projectDir).filter( (row) => (row.event === "GATE_APPROVED" || row.event === "GATE_REJECTED") && auditBlockField(row.block, "Stage") === "unit-merge" && auditBlockField(row.block, "Unit") === transaction.unit && auditBlockField(row.block, "Pinned OID") === transaction.pinned_oid && auditBlockField(row.block, "Attempt Generation") === String(transaction.generation) && auditBlockField(row.block, "Gate Scope") === "unit-merge", ); const latest = decisions.at(-1); if (!latest) return null; return { decision: latest.event === "GATE_APPROVED" ? "approve" : "reject", strategy: auditBlockField(latest.block, "Strategy"), target: auditBlockField(latest.block, "Target branch"), }; } function pinUnit(args: string[], projectDir?: string): void { const { positional } = parseArgs(args); const unit = positional[0]; if (!unit) fail("Usage: aidlc-unit pin "); const pd = resolveProjectDir(projectDir); if (readApplicableTeamUnitScopeStamp(pd)) { fail("Unit pinning must run from an unscoped main checkout."); } assertMainCheckout(pd); const state = readStateFile(pd); if (!isTeamUnitOwnership(state)) fail("Unit pinning requires Unit Ownership: team."); const identity = activeIdentity(pd); const inFlight = readUnitMergeTransaction(pd, unit); if ( inFlight && inFlight.space === identity.space && inFlight.intent_uuid === identity.intentUuid && ["approved", "git-landed", "state-folded", "complete"].includes( inFlight.status, ) ) { fail( `Unit "${unit}" already has a ${inFlight.status} merge transaction; recover it with aidlc unit land ${unit} instead of re-pinning.`, ); } const integration = fetchIntegration(pd); const ref = claimRef(identity.intentId8, unit); const claim = currentClaim(pd, integration.remote, ref); if ( claim?.status !== "claimed" || claim.payload.intent_uuid !== identity.intentUuid || !claim.payload.candidate_tree_oid ) { fail(`Unit "${unit}" has no published live candidate to pin.`); } writeClaimGeneration(pd, unit, claim.generation); const evidence = candidateEvidence( pd, claim, claim.payload.base_oid, integration.oid, ); const mainBefore = gitOutput(pd, ["rev-parse", "HEAD"], "Cannot resolve main HEAD"); const transaction: UnitMergeTransaction = { version: 1, status: "pinned", space: identity.space, intent_uuid: identity.intentUuid, intent_id8: identity.intentId8, unit, owner: claim.owner, generation: claim.generation, nonce: claim.nonce, claim_ref: ref, pinned_oid: claim.oid, candidate_tree_oid: claim.payload.candidate_tree_oid, candidate_base_oid: claim.payload.base_oid, integration_oid: integration.oid, integration_branch: integration.branch, main_before_oid: mainBefore, pinned_at: isoTimestamp(), pin_id: randomUUID(), audit_shard: claim.payload.audit_shard, evidence, }; updateCachedClaim(pd, claim); writeUnitMergeTransaction(pd, transaction); console.log(JSON.stringify({ pinned: true, unit, pinned_oid: claim.oid, pin_id: transaction.pin_id, generation: claim.generation, evidence, gate_required: true, merge_dispatch_required: true, })); } function gateUnitMerge(args: string[], projectDir?: string): void { const { positional, flags } = parseArgs(args); const unit = positional[0]; const decision = flags.decision; const userInput = flags["user-input"]?.trim(); if (!unit || (decision !== "approve" && decision !== "reject") || !userInput) { fail( "Usage: aidlc-unit gate --decision --user-input ", ); } if ( !humanPresenceGuardDisabled() && isNonAnswer(userInput) ) { fail( `Refusing Unit "${unit}" merge approval: --user-input "${userInput}" is cancellation boilerplate, not a human decision.`, ); } const approvalAuthorship = humanPresenceGuardDisabled() ? null : selfAttributedDecisionMarker(userInput, "approval"); if (approvalAuthorship) { fail( `Refusing Unit "${unit}" merge approval: decision self-attribution blocked ` + `(${approvalAuthorship.category}) in --user-input: "${approvalAuthorship.phrase}".`, ); } const pd = resolveProjectDir(projectDir); const transaction = readUnitMergeTransaction(pd, unit); if (!transaction || !["pinned", "approved", "rejected"].includes(transaction.status)) { fail(`Unit "${unit}" has no pinned merge transaction.`); } assertTransactionIdentity(pd, transaction); const claim = currentPinnedClaim(pd, transaction).claim; const liveIntegration = fetchIntegration(pd); const evidence = candidateEvidence( pd, claim, transaction.candidate_base_oid, liveIntegration.oid, ); if (JSON.stringify(evidence) !== JSON.stringify(transaction.evidence)) { fail(`Unit "${unit}" pinned evidence journal changed; run aidlc-unit pin ${unit} again.`); } if (transaction.evidence.merge_held) { fail( `Unit "${unit}" merge is held. Resolve the existing HOLD-MERGE flow in the team checkout, publish, and re-pin.`, ); } const existingDecision = mergeGateRecord(pd, transaction)?.decision; if ( ( (transaction.status === "approved" && decision === "approve") || (transaction.status === "rejected" && decision === "reject") ) && existingDecision === decision ) { console.log(JSON.stringify({ gated: true, recovered: true, unit, decision, pinned_oid: transaction.pinned_oid, })); return; } const dispatch = requireMergeDispatchDecision(pd, transaction); appendAuditEntry( decision === "approve" ? "GATE_APPROVED" : "GATE_REJECTED", { Stage: "unit-merge", Unit: unit, "Pinned OID": transaction.pinned_oid, "Attempt Generation": String(transaction.generation), "Gate Scope": "unit-merge", Strategy: dispatch.strategy, "Target branch": dispatch.target, "Outside the unit record tree": transaction.evidence.outside_unit_record_paths.join(", ") || "none", ...(decision === "approve" ? { "User Input": userInput } : { Feedback: userInput }), }, pd, ); writeUnitMergeTransaction(pd, { ...transaction, status: decision === "approve" ? "approved" : "rejected", decision, user_input: userInput, target_branch: dispatch.target, strategy: dispatch.strategy, }); console.log(JSON.stringify({ gated: true, unit, decision, pinned_oid: transaction.pinned_oid, generation: transaction.generation, outside_unit_record_paths: transaction.evidence.outside_unit_record_paths, outside_unit_record_tree_note: "These paths are outside the unit's record tree and require human overlap judgment.", })); } function isActiveIntentAuditPath( path: string, recordPrefix: string, ): boolean { const root = `${recordPrefix}/audit/`; if (!path.startsWith(root)) return false; const leaf = path.slice(root.length); return /^[A-Za-z0-9._-]+\.md$/.test(leaf); } function isEngineMergeMetadata( projectDir: string, path: string, recordPrefix = relativeRecordDir(projectDir), ): boolean { if (!recordPrefix) return path === CLAIM_FILE; const activeIntentPointer = `${dirname(recordPrefix)}/active-intent`; return new Set([ CLAIM_FILE, "aidlc/active-space", activeIntentPointer, `${recordPrefix}/aidlc-state.md`, `${recordPrefix}/runtime-graph.json`, ]).has(path); } function conflictFiles(projectDir: string): string[] { const listed = git(projectDir, ["diff", "--name-only", "--diff-filter=U"]); return listed.ok ? listed.stdout.split(/\r?\n/).map((value) => value.trim()).filter(Boolean) : []; } function checkpointMainMetadata( projectDir: string, message: string, ): { parentOid: string; commitOid?: string } { const parentOid = gitOutput( projectDir, ["rev-parse", "HEAD"], "Cannot resolve metadata checkpoint parent", ); const statusResult = git( projectDir, ["status", "--porcelain=v1", "-z", "--untracked-files=all"], ); if (!statusResult.ok) { fail( `Cannot inspect main worktree: ${statusResult.stderr.trim() || `exit ${statusResult.code}`}`, ); } const status = statusResult.stdout; if (!status) return { parentOid }; const recordPrefix = relativeRecordDir(projectDir); if (!recordPrefix) { fail("Cannot resolve active intent metadata for Unit landing."); } const paths: string[] = []; const records = status.split("\u0000"); for (let i = 0; i < records.length; i++) { const record = records[i]; if (record.length < 4) continue; const code = record.slice(0, 2); paths.push(record.slice(3)); if (/[RC]/.test(code) && records[i + 1]) { paths.push(records[++i]); } } const unsafe = paths.filter( (path) => !isEngineMergeMetadata(projectDir, path, recordPrefix) && path !== `${recordPrefix}/audit/${auditShardName(projectDir)}`, ); if (unsafe.length > 0) { fail( `Unit landing requires a clean source worktree; commit or stash: ${unsafe.join(", ")}.`, ); } const added = git(projectDir, ["add", "-A", "--", ...paths]); if (!added.ok) { fail( `Failed to stage main engine metadata checkpoint: ${added.stderr.trim() || added.stdout.trim()}.`, ); } const committed = git(projectDir, [ "commit", "-m", message, ]); if (!committed.ok) { fail(`Failed to checkpoint main engine metadata: ${committed.stderr.trim()}.`); } return { parentOid, commitOid: gitOutput( projectDir, ["rev-parse", "HEAD"], "Cannot resolve metadata checkpoint commit", ), }; } function restoreMainMetadata( projectDir: string, paths: string[], ): void { const recordPrefix = relativeRecordDir(projectDir); for (const path of paths.filter((path) => isEngineMergeMetadata(projectDir, path, recordPrefix) )) { if (gitPathExistsAt(projectDir, "HEAD", path)) { const restored = git(projectDir, ["checkout", "HEAD", "--", path]); if (!restored.ok) fail(`Failed to retain main metadata path ${path}.`); const added = git(projectDir, ["add", "--", path]); if (!added.ok) fail(`Failed to stage retained metadata path ${path}.`); } else { git(projectDir, ["rm", "-f", "--cached", "--ignore-unmatch", "--", path]); try { unlinkSync(join(projectDir, path)); } catch { // Candidate-only metadata may already be absent. } } } } function gitObjectAt( projectDir: string, oid: string, path: string, ): string | null { const result = git(projectDir, ["rev-parse", "--verify", `${oid}:${path}`]); return result.ok ? result.stdout.trim() : null; } function candidateChangedPaths( projectDir: string, transaction: UnitMergeTransaction, ): string[] { return gitOutput( projectDir, [ "diff", "--name-only", `${transaction.candidate_base_oid}..${transaction.pinned_oid}`, ], "Cannot inspect pinned candidate diff", ) .split(/\r?\n/) .filter(Boolean); } function mergeCommitParents(projectDir: string, commitOid: string): string[] { return gitOutput( projectDir, ["show", "-s", "--format=%P", commitOid], `Cannot inspect merge commit ${commitOid}`, ) .split(/\s+/) .filter(Boolean); } function landedTreeViolations( projectDir: string, transaction: UnitMergeTransaction, treeish: string, mainParent: string, ): string[] { const candidatePaths = candidateChangedPaths(projectDir, transaction); const recordPrefix = relativeRecordDir(projectDir); const boundary = recordPrefix ? candidateBoundary( projectDir, transaction.candidate_base_oid, transaction.pinned_oid, recordPrefix, transaction.unit, transaction.generation, transaction.audit_shard, ) : { violations: ["active intent record is unavailable"], }; const allowedCommitChanges = new Set( candidatePaths.filter((path) => !isEngineMergeMetadata(projectDir, path, recordPrefix) ), ); const actualCommitChanges = gitOutput( projectDir, ["diff", "--name-only", `${mainParent}..${treeish}`], "Cannot inspect landed merge tree", ) .split(/\r?\n/) .filter(Boolean); const violations = [ ...boundary.violations, ...actualCommitChanges.filter( (path) => !allowedCommitChanges.has(path), ), ]; for (const path of candidatePaths) { const actual = gitObjectAt(projectDir, treeish, path); const expected = isEngineMergeMetadata(projectDir, path, recordPrefix) ? gitObjectAt(projectDir, mainParent, path) : gitObjectAt(projectDir, transaction.pinned_oid, path); if (actual !== expected) violations.push(path); } return [...new Set(violations)].sort(); } function assertLandCandidateBoundary( projectDir: string, transaction: UnitMergeTransaction, ): void { const recordPrefix = relativeRecordDir(projectDir); if (!recordPrefix) { fail("Cannot resolve the active intent record for Unit landing."); } const boundary = candidateBoundary( projectDir, transaction.candidate_base_oid, transaction.pinned_oid, recordPrefix, transaction.unit, transaction.generation, transaction.audit_shard, ); if (boundary.violations.length > 0) { fail( `Unit "${transaction.unit}" landing violates claimed Unit ownership at: ${ boundary.violations.join(", ") }.`, ); } } function validateLandedMerge( projectDir: string, transaction: UnitMergeTransaction, commitOid: string, target: string, ): void { const branch = gitOutput( projectDir, ["branch", "--show-current"], "Cannot resolve landing branch", ); if (branch !== target) { fail(`Unit landing expected branch "${target}", found "${branch}".`); } if ( !git( projectDir, ["merge-base", "--is-ancestor", commitOid, "HEAD"], ).ok ) { fail(`Recorded Unit merge commit ${commitOid} is not on ${target}.`); } const parents = mergeCommitParents(projectDir, commitOid); if (parents.length < 2 || parents[1] !== transaction.pinned_oid) { fail( `Unit "${transaction.unit}" landing is not a controlled merge of pinned OID ${transaction.pinned_oid}.`, ); } const mainParent = parents[0]; const violations = landedTreeViolations( projectDir, transaction, commitOid, mainParent, ); if (violations.length > 0) { fail( `Unit "${transaction.unit}" merge commit violates candidate-exact policy at: ${violations.join(", ")}.`, ); } } function recoveredMergeCommit( projectDir: string, transaction: UnitMergeTransaction, target: string, ): string | null { const history = git( projectDir, [ "log", "--first-parent", "--format=%H%x00%P", `${transaction.main_before_oid}..HEAD`, ], ); if (!history.ok) return null; for (const line of history.stdout.split(/\r?\n/).filter(Boolean)) { const [commitOid, parentText = ""] = line.split("\u0000"); const parents = parentText.split(/\s+/).filter(Boolean); if (parents[1] !== transaction.pinned_oid) continue; validateLandedMerge(projectDir, transaction, commitOid, target); return commitOid; } return null; } function metadataCheckpointAtHead( projectDir: string, unit: string, ): { parentOid: string; commitOid: string } | null { const commitOid = gitOutput( projectDir, ["rev-parse", "HEAD"], "Cannot inspect metadata checkpoint", ); const subject = gitOutput( projectDir, ["show", "-s", "--format=%s", commitOid], "Cannot inspect metadata checkpoint subject", ); if (subject !== `Checkpoint Unit ${unit} merge gate`) return null; const parents = mergeCommitParents(projectDir, commitOid); if (parents.length !== 1) return null; const paths = gitOutput( projectDir, ["diff", "--name-only", `${parents[0]}..${commitOid}`], "Cannot inspect metadata checkpoint paths", ) .split(/\r?\n/) .filter(Boolean); const recordPrefix = relativeRecordDir(projectDir); if (!recordPrefix) return null; if ( paths.length === 0 || paths.some( (path) => !isEngineMergeMetadata(projectDir, path, recordPrefix) && !isActiveIntentAuditPath(path, recordPrefix), ) ) { return null; } return { parentOid: parents[0], commitOid }; } function validateMetadataCheckpoint( projectDir: string, transaction: UnitMergeTransaction, ): void { if (!transaction.checkpoint_commit_oid) return; const checkpoint = metadataCheckpointAtHead(projectDir, transaction.unit); if ( !checkpoint || checkpoint.commitOid !== transaction.checkpoint_commit_oid || checkpoint.parentOid !== transaction.checkpoint_parent_oid ) { fail(`Unit "${transaction.unit}" metadata checkpoint is invalid.`); } } function rollbackMetadataCheckpoint( projectDir: string, transaction: UnitMergeTransaction, ): UnitMergeTransaction { if ( transaction.checkpoint_commit_oid && transaction.checkpoint_parent_oid && gitOutput(projectDir, ["rev-parse", "HEAD"], "Cannot inspect checkpoint HEAD") === transaction.checkpoint_commit_oid ) { validateMetadataCheckpoint(projectDir, transaction); const reset = git( projectDir, ["reset", "--mixed", transaction.checkpoint_parent_oid], ); if (!reset.ok) { fail(`Failed to restore pre-merge metadata checkpoint: ${reset.stderr.trim()}.`); } } return { ...transaction, checkpoint_parent_oid: undefined, checkpoint_commit_oid: undefined, }; } function landGit( projectDir: string, transaction: UnitMergeTransaction, target: string, ): UnitMergeTransaction { assertLandCandidateBoundary(projectDir, transaction); if (transaction.git_commit_oid) { validateLandedMerge( projectDir, transaction, transaction.git_commit_oid, target, ); return transaction; } const recovered = recoveredMergeCommit(projectDir, transaction, target); if (recovered) { return { ...transaction, status: "git-landed", target_branch: target, strategy: "merge", git_commit_oid: recovered, }; } currentPinnedClaim(projectDir, transaction); const branch = gitOutput( projectDir, ["branch", "--show-current"], "Cannot resolve main branch", ); if (branch !== target) { fail(`Unit landing expected branch "${target}", found "${branch}".`); } let working = transaction; if (!working.checkpoint_commit_oid) { const recoveredCheckpoint = metadataCheckpointAtHead( projectDir, transaction.unit, ); if (recoveredCheckpoint) { working = { ...working, checkpoint_parent_oid: recoveredCheckpoint.parentOid, checkpoint_commit_oid: recoveredCheckpoint.commitOid, }; writeUnitMergeTransaction(projectDir, working); } } else { validateMetadataCheckpoint(projectDir, working); } const existingMergeHead = git( projectDir, ["rev-parse", "-q", "--verify", "MERGE_HEAD"], ); if (!existingMergeHead.ok) { if (working.checkpoint_commit_oid) { const head = gitOutput( projectDir, ["rev-parse", "HEAD"], "Cannot inspect metadata checkpoint", ); if (head !== working.checkpoint_commit_oid) { fail("Unit merge metadata checkpoint no longer matches HEAD."); } } else { const checkpoint = checkpointMainMetadata( projectDir, `Checkpoint Unit ${transaction.unit} merge gate`, ); working = { ...working, checkpoint_parent_oid: checkpoint.parentOid, checkpoint_commit_oid: checkpoint.commitOid, }; writeUnitMergeTransaction(projectDir, working); } } else if (existingMergeHead.stdout.trim() !== transaction.pinned_oid) { fail("Another git merge is already in progress."); } const changed = candidateChangedPaths(projectDir, transaction); const merged = existingMergeHead.ok ? { ok: true, stdout: "", stderr: "", code: 0 } : git( projectDir, ["merge", "--no-commit", "--no-ff", transaction.pinned_oid], ); restoreMainMetadata(projectDir, changed); const conflicts = conflictFiles(projectDir).filter( (path) => !isEngineMergeMetadata(projectDir, path), ); if (conflicts.length > 0) { git(projectDir, ["merge", "--abort"]); working = rollbackMetadataCheckpoint(projectDir, working); writeUnitMergeTransaction(projectDir, { ...working, conflict_files: conflicts, }); fail(`Unit "${transaction.unit}" source conflicts: ${conflicts.join(", ")}.`); } if (!merged.ok && !git(projectDir, ["rev-parse", "-q", "--verify", "MERGE_HEAD"]).ok) { working = rollbackMetadataCheckpoint(projectDir, working); writeUnitMergeTransaction(projectDir, working); fail(`Pinned git merge failed: ${merged.stderr.trim() || merged.stdout.trim()}.`); } const pendingTree = gitOutput( projectDir, ["write-tree"], "Cannot materialize pending Unit merge tree", ); const mainParent = gitOutput( projectDir, ["rev-parse", "HEAD"], "Cannot resolve pending Unit merge parent", ); const policyViolations = landedTreeViolations( projectDir, working, pendingTree, mainParent, ); if (policyViolations.length > 0) { git(projectDir, ["merge", "--abort"]); working = rollbackMetadataCheckpoint(projectDir, working); writeUnitMergeTransaction(projectDir, { ...working, conflict_files: policyViolations, }); fail( `Unit "${transaction.unit}" candidate-exact merge policy refused auto-merged paths: ` + `${policyViolations.join(", ")}. Rebase onto the current target and republish.`, ); } const committed = git(projectDir, [ "commit", "--no-edit", "-m", `Merge Unit ${transaction.unit} @ ${transaction.pinned_oid.slice(0, 12)}`, ]); if (!committed.ok) { git(projectDir, ["merge", "--abort"]); working = rollbackMetadataCheckpoint(projectDir, working); writeUnitMergeTransaction(projectDir, working); fail(`Pinned git merge commit failed: ${committed.stderr.trim()}.`); } const commitOid = gitOutput( projectDir, ["rev-parse", "HEAD"], "Cannot resolve landed merge commit", ); try { validateLandedMerge(projectDir, working, commitOid, target); } catch (error) { const reset = git(projectDir, ["reset", "--hard", mainParent]); if (!reset.ok) { fail( `Unit merge validation failed and rollback also failed: ${errorMessage(error)}; ${reset.stderr.trim()}.`, ); } working = rollbackMetadataCheckpoint(projectDir, working); writeUnitMergeTransaction(projectDir, working); throw error; } return { ...working, status: "git-landed", target_branch: target, strategy: "merge", git_commit_oid: commitOid, conflict_files: undefined, }; } function runStateFold( projectDir: string, transaction: UnitMergeTransaction, ): void { const tool = join(dirname(fileURLToPath(import.meta.url)), "aidlc-state.ts"); const result = spawnSync( process.execPath, [ tool, "fold-unit-merge", "--unit", transaction.unit, "--pinned-oid", transaction.pinned_oid, "--generation", String(transaction.generation), "--project-dir", projectDir, ], { cwd: projectDir, encoding: "utf-8", env: { ...process.env, AIDLC_STATE_TRANSITION_OWNER: `unit-merge:${process.pid}`, }, }, ); if (result.status !== 0) { fail(`Unit state fold failed: ${(result.stderr || result.stdout).trim()}.`); } } function validateMergeRiskAcknowledgment( projectDir: string, unit: string, userInput: string | undefined, ): string { const answer = userInput?.trim(); if (!answer) { fail( `Unit "${unit}" released-attempt recovery requires --user-input .`, ); } if (!humanPresenceGuardDisabled() && isNonAnswer(answer)) { fail( `Refusing Unit "${unit}" released-attempt recovery: --user-input "${answer}" is cancellation boilerplate.`, ); } const authorship = humanPresenceGuardDisabled() ? null : selfAttributedDecisionMarker(answer, "approval"); if (authorship) { fail( `Refusing Unit "${unit}" released-attempt recovery: decision self-attribution blocked ` + `(${authorship.category}) in --user-input: "${authorship.phrase}".`, ); } if (!humanPresenceGuardDisabled()) { const all = mainAuthorityAuditRows(projectDir); const floor = all.findLastIndex( (row) => row.event === "GATE_APPROVED" || row.event === "GATE_REJECTED" || ( row.event === "RECOVERY_COMPLETED" && auditBlockField(row.block, "Recovery") === "unit-merge-released-attempt" ), ); if (!all.slice(floor + 1).some((row) => row.event === "HUMAN_TURN")) { fail( `Unit "${unit}" released-attempt recovery requires a fresh typed human turn from main's audit shard.`, ); } } return answer; } function recordReleasedAfterGitAcceptance( projectDir: string, transaction: UnitMergeTransaction, tombstone: UnitClaimView, userInput: string, ): UnitMergeTransaction { if ( transaction.released_after_git?.tombstone_oid === tombstone.oid && transaction.released_after_git.tombstone_generation === tombstone.generation ) { return transaction; } appendAuditEntry( "RECOVERY_COMPLETED", { Recovery: "unit-merge-released-attempt", Unit: transaction.unit, "Pinned OID": transaction.pinned_oid, "Attempt Generation": String(transaction.generation), "Tombstone OID": tombstone.oid, "Tombstone Generation": String(tombstone.generation), "User Input": userInput, Details: "Human accepted completion of the already-landed merge after the exact claim attempt was tombstoned.", }, projectDir, ); const updated: UnitMergeTransaction = { ...transaction, released_after_git: { accepted_at: isoTimestamp(), user_input: userInput, tombstone_oid: tombstone.oid, tombstone_generation: tombstone.generation, }, }; writeUnitMergeTransaction(projectDir, updated); updateCachedClaim(projectDir, tombstone); return updated; } function landUnit(args: string[], projectDir?: string): void { const { positional, flags } = parseArgs(args); const unit = positional[0]; const step = flags.step ?? "all"; const acceptReleasedAttempt = flags["accept-released-attempt"] === "true"; if ( !unit || !["git", "state", "audit", "all"].includes(step) || (flags.strategy !== undefined && flags.strategy !== "merge") ) { fail( "Usage: aidlc-unit land [--step git|state|audit|all] [--target ] " + "[--strategy merge] [--accept-released-attempt --user-input ]", ); } const pd = resolveProjectDir(projectDir); assertMainCheckout(pd); const existing = readUnitMergeTransaction(pd, unit); if (!existing || !["approved", "git-landed", "state-folded", "complete"].includes(existing.status)) { fail(`Unit "${unit}" merge is not approved.`); } let transaction: UnitMergeTransaction = existing; let claimCheck: PinnedClaimCheck | null = null; assertTransactionIdentity(pd, transaction); if (acceptReleasedAttempt && transaction.status !== "git-landed") { fail( `Unit "${unit}" --accept-released-attempt applies only after the git step landed and before state folding.`, ); } if ( transaction.status === "approved" || transaction.status === "git-landed" ) { claimCheck = currentPinnedClaim(pd, transaction, { acceptReleasedAttempt, }); if ( claimCheck.releasedTombstone && !transaction.released_after_git ) { const userInput = validateMergeRiskAcknowledgment( pd, unit, flags["user-input"], ); transaction = recordReleasedAfterGitAcceptance( pd, transaction, claimCheck.releasedTombstone, userInput, ); } } const gate = mergeGateRecord(pd, transaction); if (gate?.decision !== "approve") { fail(`Unit "${unit}" has no current approved merge-gate receipt.`); } if (gate.strategy !== "merge" || !gate.target) { fail(`Unit "${unit}" approved merge gate has invalid strategy or target evidence.`); } const target = flags.target ?? gate.target; if ( target !== gate.target ) { fail( `Unit "${unit}" merge gate approved target "${gate.target}", not "${target}".`, ); } transaction = { ...transaction, target_branch: gate.target, strategy: "merge", }; if (transaction.evidence.merge_held) { fail( `Unit "${unit}" merge is held. Resolve the existing HOLD-MERGE flow in the team checkout, publish, and re-pin.`, ); } const runGitStep = step === "git" || step === "all"; const runStateStep = step === "state" || step === "all"; const runAuditStep = step === "audit" || step === "all"; if (step === "state" && transaction.status === "approved") { fail(`Unit "${unit}" git step has not landed.`); } if ( step === "audit" && !["state-folded", "complete"].includes(transaction.status) ) { fail(`Unit "${unit}" state step has not folded.`); } if (runGitStep && transaction.status === "approved") { if (!claimCheck) { fail(`Unit "${unit}" git landing has no current pinned-claim evidence.`); } const liveIntegration = fetchIntegration(pd); const landingBranch = currentBranch(pd); if (landingBranch !== target) { fail(`Unit landing expected branch "${target}", found "${landingBranch}".`); } const landingHead = gitOutput( pd, ["rev-parse", "HEAD"], "Cannot resolve local landing target", ); if ( !git( pd, ["merge-base", "--is-ancestor", liveIntegration.oid, landingHead], ).ok ) { fail( `Unit "${unit}" local target "${target}" is stale: fetched ` + `${liveIntegration.ref} at ${liveIntegration.oid}, but local HEAD is ` + `${landingHead}. Fast-forward or rebase "${target}", then re-run landing.`, ); } const liveEvidence = candidateEvidence( pd, claimCheck.claim, transaction.candidate_base_oid, landingHead, ); if (JSON.stringify(liveEvidence) !== JSON.stringify(transaction.evidence)) { fail( `Unit "${unit}" live integration evidence changed after merge approval; ` + `run aidlc unit pin ${unit} again and obtain a new merge gate.`, ); } transaction = landGit(pd, transaction, target); writeUnitMergeTransaction(pd, transaction); } if ( runStateStep && ["git-landed", "state-folded"].includes(transaction.status) ) { if (!transaction.git_commit_oid) { fail(`Unit "${unit}" has no validated git landing commit.`); } validateLandedMerge( pd, transaction, transaction.git_commit_oid, target, ); const liveState = readStateFile(pd); const liveScope = getField(liveState, "Scope") ?? ""; const liveStageColumns = unitMajorConstructionStageSlugs( liveScope, liveState, true, ); if (liveStageColumns.length === 0) { fail(`Unit "${unit}" live main state has no active per-unit Construction columns.`); } transaction = { ...transaction, live_stage_columns: liveStageColumns, state_fold_authorized: transaction.state_fold_authorized ?? ( claimCheck ? { authorized_at: isoTimestamp(), mode: claimCheck.releasedTombstone ? "released-after-git" : "live-claim", observed_oid: claimCheck.releasedTombstone?.oid ?? claimCheck.claim.oid, owner: claimCheck.claim.owner, } : transaction.state_fold_authorized ), }; if (!transaction.state_fold_authorized) { fail( `Unit "${unit}" state fold has no current land-bound claim authorization.`, ); } writeUnitMergeTransaction(pd, transaction); runStateFold(pd, transaction); transaction = { ...transaction, status: "state-folded" }; writeUnitMergeTransaction(pd, transaction); } if (runAuditStep && transaction.status !== "complete") { if (!unitMergedReceipts(pd).has(unit)) { fail(`Unit "${unit}" state fold has no current-generation UNIT_MERGED receipt.`); } if (!mainUnitRowMerged(pd, transaction)) { fail(`Unit "${unit}" state fold has not applied the authoritative merged row.`); } checkpointMainMetadata( pd, `Finalize Unit ${unit} merge metadata`, ); transaction = { ...transaction, status: "complete" }; writeUnitMergeTransaction(pd, transaction); } console.log(JSON.stringify({ landed: transaction.status === "complete", status: transaction.status, unit, pinned_oid: transaction.pinned_oid, git_commit_oid: transaction.git_commit_oid ?? null, })); } function assertMainCheckout(projectDir: string): void { const top = git(projectDir, ["rev-parse", "--show-toplevel"]); const common = git(projectDir, ["rev-parse", "--git-common-dir"]); if (!top.ok || !common.ok) fail("Cannot resolve the main git checkout."); const topReal = realpathSync(top.stdout.trim()); const commonAbs = resolve(topReal, common.stdout.trim()); const mainReal = realpathSync(dirname(commonAbs)); if (topReal !== mainReal) { fail(`This command must run from the unscoped main checkout, not sibling worktree ${topReal}.`); } } function validateClaimRefUnit(intentId8: string, unit: string): void { const ref = claimRef(intentId8, unit); const checked = spawnSync("git", ["check-ref-format", ref], { encoding: "utf-8", }); if (checked.status !== 0) { fail( `Unit "${unit}" is not claim-ref safe; avoid '..', '.lock' endings, ` + "leading dots, and other git-ref-reserved forms.", ); } } function claimOwnerLabel(projectDir: string, supplied?: string): string { const owner = supplied?.trim() || git(projectDir, ["config", "user.name"]).stdout.trim() || "team"; if (/[\r\n|]/.test(owner)) { fail("Team labels cannot contain pipes or newlines."); } return owner; } function finalizeClaimCheckout( projectDir: string, stamp: UnitScopeStamp, claim: UnitClaimView, ): void { stamp.claim_oid = claim.oid; stamp.audit_shard = claim.payload.audit_shard; writeUnitScopeStamp(projectDir, stamp); writeClaimGeneration(projectDir, stamp.unit, stamp.generation); ensureCloneId(projectDir); updateCachedClaim(projectDir, claim); } interface PendingRelease { version: 1; status: "pending" | "released"; intent_uuid: string; unit: string; claim_generation: number; claim_nonce: string; release_nonce: string; released_generation?: number; released_oid?: string; } function readPendingRelease( projectDir: string, unit: string, identity: ReturnType, ): PendingRelease | null { try { const parsed = JSON.parse( readFileSync( unitReleasePendingPath( projectDir, unit, identity.space, identity.intentUuid, ), "utf-8", ), ) as Partial; if ( parsed.version !== 1 || (parsed.status !== "pending" && parsed.status !== "released") || typeof parsed.intent_uuid !== "string" || typeof parsed.unit !== "string" || !Number.isInteger(parsed.claim_generation) || typeof parsed.claim_nonce !== "string" || typeof parsed.release_nonce !== "string" ) { return null; } return parsed as PendingRelease; } catch { return null; } } function writePendingRelease( projectDir: string, identity: ReturnType, pending: PendingRelease, ): void { const path = unitReleasePendingPath( projectDir, pending.unit, identity.space, identity.intentUuid, ); mkdirSync(dirname(path), { recursive: true }); writeFileSync( path, `${JSON.stringify(pending, null, 2)}\n`, "utf-8", ); } function adoptUnit(args: string[], projectDir?: string): void { const { positional } = parseArgs(args); const unit = positional[0]; if (!unit) fail("Usage: aidlc-unit adopt "); const unitError = validateUnitName(unit); if (unitError) fail(unitError); const pd = resolveProjectDir(projectDir); const state = readStateFile(pd); if (!isTeamUnitOwnership(state)) fail("Unit adoption requires Unit Ownership: team."); const identity = activeIdentity(pd); const ref = claimRef(identity.intentId8, unit); const branch = gitOutput( pd, ["symbolic-ref", "--quiet", "HEAD"], "Unit adoption requires the checked-out local claim branch", ); if (branch !== ref) { fail(`Unit adoption requires checked-out branch "${ref}", found "${branch}".`); } const existing = readUnitScopeStamp(pd); if (existing && existing.unit !== unit) { fail(`This checkout is already scoped to Unit "${existing.unit}".`); } const claim = currentClaim(pd, repositoryRemote(pd), ref); if ( claim?.status !== "claimed" || claim.payload.space !== identity.space || claim.payload.intent_uuid !== identity.intentUuid || claim.payload.intent_id8 !== identity.intentId8 || claim.payload.unit !== unit || claim.payload.claim_ref !== ref || !claim.payload.audit_shard || !/^[A-Za-z0-9._-]+\.md$/.test(claim.payload.audit_shard) ) { fail(`Unit "${unit}" checked-out claim identity or audit shard is invalid.`); } const head = gitOutput(pd, ["rev-parse", "HEAD"], "Cannot resolve checked-out claim"); if (head !== claim.oid) { fail(`Unit adoption requires HEAD at live claim OID ${claim.oid}.`); } const checkedOut = readPayload(pd, head, { localOnly: true }); if ( !checkedOut || checkedOut.nonce !== claim.nonce || checkedOut.generation !== claim.generation || checkedOut.audit_shard !== claim.payload.audit_shard ) { fail(`Unit "${unit}" checked-out claim payload does not match the live claim ref.`); } const stamp: UnitScopeStamp = { version: 1, space: identity.space, intent_uuid: identity.intentUuid, intent_id8: identity.intentId8, unit, owner: claim.owner, generation: claim.generation, nonce: claim.nonce, claim_ref: ref, claim_oid: claim.oid, claimed_from_oid: claim.payload.base_oid, integration_ref: claim.payload.integration_ref, gate_rhythm: claim.payload.gate_rhythm, audit_shard: claim.payload.audit_shard, }; finalizeClaimCheckout(pd, stamp, claim); console.log(JSON.stringify({ adopted: true, ...stamp })); } function claimUnit(args: string[], projectDir?: string): void { const { positional, flags } = parseArgs(args); const unit = positional[0]; if (!unit) fail("Usage: aidlc-unit claim [--team