/** * ⟨q-cc0819dc⟩ — A `done` MAY CITE A COMMIT WHEN THE WORK HAS NO PR BY RULE. * * Docs-direct work (queue curation, canon, board moves) is pushed straight to the shared * branch by policy; the `done` gate demanded a `{kind:'pr'}` cite, so the compliant path did * not exist and the aide downgraded to `fyi` (2026-09-12 15:50). The fix accepts a commit * cite — and only a commit that is REAL: a fabricated sha must not become a citable DONE. * * What "real" means here, stated so the ancestry call below is not mistaken for a merge test: * is this exact commit object reachable from origin/main in `repo`? A docs-direct push puts * THE COMMIT ITSELF on the shared branch, so reachability is the right question for it — this * is not "was this branch's work squashed in", which `--is-ancestor` cannot answer * (docs/LANDEDNESS.md); a squash-merged PR is cited by its PR, never by its branch sha. * * Full 40-hex only, REFUSED rather than normalised: a prefix is a claim about a sha the * joiners (verdict/landing/closure readers) compare in full; normalising here would write a * sha the sender never saw. No network: one local `git` in `repo`, which the caller passes * because the send path has no repository of its own. */ import { execFileSync } from "node:child_process"; export const FULL_SHA = /^[0-9a-f]{40}$/; export const SHARED_BRANCH_CANDIDATES = ["origin/main", "origin/master"]; export type CommitCiteVerdict = | { ok: true; sha: string; branch: string } | { ok: false; why: string }; function git(repo: string, args: string[]): { status: number; out: string } { try { const out = execFileSync("git", ["-C", repo, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }); return { status: 0, out: out.trim() }; } catch (e) { return { status: Number((e as { status?: number }).status ?? 1), out: "" }; } } /** Verify one commit cite against the shared branch of `repo`. */ export function verifyCommitCite(ref: string, repo: string | undefined): CommitCiteVerdict { const sha = String(ref ?? "").trim(); if (!FULL_SHA.test(sha)) { return { ok: false, why: `commit cite '${sha}' is not a full 40-hex sha — refused, not normalised: a prefix is a claim the joiners compare in full` }; } if (!repo) { return { ok: false, why: `commit cite ${sha.slice(0, 7)} cannot be verified without \`repo\` — pass the repository whose origin/main carries it (no network is used)` }; } if (git(repo, ["rev-parse", "--verify", "--quiet", `${sha}^{commit}`]).status !== 0) { return { ok: false, why: `commit ${sha.slice(0, 7)} does not exist in ${repo} — a sha the repository has never seen cannot be a citable DONE` }; } for (const branch of SHARED_BRANCH_CANDIDATES) { if (git(repo, ["rev-parse", "--verify", "--quiet", branch]).status !== 0) continue; // Is the cited commit reachable from the shared branch? (the reachability question, // asked of the commit object itself — see the header for why that is the right one here) if (git(repo, ["merge-base", "--is-ancestor", sha, branch]).status === 0) return { ok: true, sha, branch }; return { ok: false, why: `commit ${sha.slice(0, 7)} exists but is not reachable from ${branch} — work that is done is on the shared branch; a commit that is not is not done` }; } return { ok: false, why: `${repo} has no origin/main or origin/master to verify commit ${sha.slice(0, 7)} against — fetch the shared branch first` }; }