/** * Whether a recorded commit's work is present in a release tag (T12311). * * ## Why SHA reachability alone is the wrong question * * Evidence records `commit:` at the moment a task is verified, which is * while its branch still exists. This repository merges by SQUASH, so that SHA * is discarded at merge time and the identical work lands under a new one. A * plain `git merge-base --is-ancestor ` therefore reports the work * as absent from every release it actually shipped in. * * Measured 2026-09-22 shipping v2026.9.12: T12310 was verified on its branch * as `8a866465`, merged as `645da636`, and `cleo release reconcile` rejected * the release with `commit 8a866465 is not reachable from tag v2026.9.12`. * The suggested repair — re-verify the task — is refused by ADR-051 §11.1 * because the task is already done, so the error named a remedy the system * itself forbids and the only way through was an owner override. That is * structural: EVERY task verified before its own squash merge lands there. * * ## What is asked instead * * A squash preserves the PATCH while destroying the commit identity, so patch * identity is what survives the transformation. `git patch-id --stable` * produces a hash of a diff that is independent of commit metadata, parentage * and SHA — it is the same mechanism `git cherry` uses to answer "has this * change already been applied upstream". Verified on the case above: branch * `8a866465` and squash `645da636` both hash to `8ea37575…`. * * Equivalence is REPORTED, never silently substituted: a presence established * by patch identity names the commit that actually carries it, so a receipt * says which object in the release the evidence resolved to. * * ## What this deliberately does not claim * * Patch identity is not commit identity. A cherry-pick, a rebase and an * independently authored identical change are indistinguishable from a squash * of the original, and all four mean the work is in the tag — which is the * question being asked. It says nothing about authorship or ordering. A merge * commit and an empty commit have no patch to hash and can only be answered by * reachability. * * @module * @task T12311 */ /** Commits scanned back from the tag when looking for a patch-equivalent. */ export declare const PATCH_EQUIVALENT_SEARCH_LIMIT = 500; /** Whether a recorded commit's work is present in a tag, and on what basis. */ export type CommitPresence = { /** The work is in the tag. */ readonly present: true; /** The recorded SHA is itself an ancestor of the tag. */ readonly via: 'ancestor'; /** The recorded SHA. */ readonly sha: string; } | { readonly present: true; /** The recorded SHA is gone, but its patch is carried by another commit. */ readonly via: 'patch-equivalent'; readonly sha: string; /** The commit in the tag that carries the identical patch. */ readonly carriedBy: string; /** The shared `git patch-id --stable` hash. */ readonly patchId: string; } | { /** The work could not be established as present. */ readonly present: false; readonly sha: string; /** What was actually checked and what came back. */ readonly reason: string; /** A repair the caller can execute, given verification may be frozen. */ readonly fix: string; }; /** * Establish whether a recorded commit's work is present in a tag. * * @param projectRoot - Repository to ask; never inferred from cwd. * @param sha - The commit recorded as evidence, which may no longer exist. * @param tag - The release tag, or any committish, to look inside. * @param searchLimit - Commits scanned back from `tag` for a patch-equivalent. * @returns Presence and the basis for it, or an executable repair. * @remarks Reachability is asked first and is the strongest answer. Patch * identity is consulted only when the SHA is gone, and establishes that the * CHANGE shipped, not that the commit did. An unknown object and an absent * change are reported differently, because the repairs differ. * @example * ```ts * const found = resolveCommitPresenceInTag(root, sha, 'v2026.9.12'); * if (found.present && found.via === 'patch-equivalent') record(found.carriedBy); * ``` */ export declare function resolveCommitPresenceInTag(projectRoot: string, sha: string, tag: string, searchLimit?: number): CommitPresence; /** * Whether a path recorded in a `files:` atom belongs to a release, judged * against the tag rather than the working tree (T13364). * * A `files:` atom names the files a task's change touched. A later change in * the same release may legitimately delete one (T13167 removed two files that * T13158's atom names, before the v2026.10.5 tag). The working tree then lacks * the path forever, and a working-tree existence check rejects a shipped * release with a defect that re-verifying cannot repair: reconcile reads the * atoms from the committed plan. * * A path is accounted for when it exists in the working tree, or when some * commit reachable from `tag` touched it (`git rev-list -1 -- `), * meaning it existed and a recorded commit in the release history removed it. * A path with no history up to the tag was never part of the release, and that * evidence stays stale. * * @param projectRoot - Repository root. * @param relPath - Path from the atom, relative to `projectRoot`. * @param tag - The release tag. * @param existsInTree - Whether the path exists in the working tree. * @returns `null` when the path is accounted for, else the stale reason. */ export declare function filesAtomPathProblem(projectRoot: string, relPath: string, tag: string, existsInTree: boolean): string | null; //# sourceMappingURL=commit-presence.d.ts.map