# Push-to-main shape: the merge base IS HEAD, so the fragment set this guard
# would replay is HEAD's own — nothing was consumed between the two points,
# and comparing a tree against itself would assert nothing. Named honestly,
# the same discipline as changelog-monotonic's vacuous line.
if["$merge_base"="$(git rev-parse HEAD)"];then
echo"changelog-assembled: vacuous (the merge base IS HEAD, so no fragments were consumed between them — there is no diff for the section to answer to)."
exit0
fi
# --- applicability: the ceremony PR, and nothing else ------------------------
if ! git cat-file -e "$merge_base:$dir" 2>/dev/null;then
notice "no '$dir/' at the merge base ($short_base) — legacy mode; the changelog is edited directly and there is no fragment set for a section to answer to"
fi
# version_read refuses loudly on a missing or empty source; the wrapper line
# names the guard so a workflow log shows which check refused.
ver="$(version_read "$version_source")"||{
echo"changelog-assembled: cannot read the version (version-source: $version_source)" >&2
exit1
}
if version_is_dev "$ver";then
notice "version '$ver' is a development tree — no release section is being stamped; whatever this PR does to '$dir/' is cargo for a future ceremony, not a consumption to verify"
fi
tmp="$(mktemp -d)"
trap'rm -rf "$tmp"' EXIT
git show "$merge_base:$changelog" >"$tmp/base-changelog.md" 2>/dev/null || : >"$tmp/base-changelog.md"
# A branch that merely SITS on a release is not the ceremony that stamped
# it: right after a release merges, main's version is bare until the -dev
# bump lands, and a PR branched in that window would otherwise be asked to
# answer for a consumption that happened at its merge base, not on it. If
# the section already existed at the merge base, this branch did not stamp
# it. Whole-version match, as everywhere in this family.
if awk -v ver="$ver"'/^## / && $2 == ver { found = 1; exit } END { exit !found }'"$tmp/base-changelog.md";then
notice "the section for '$ver' already exists at the merge base ($short_base) — this branch is not the ceremony that stamped it, so there is no consumed set to answer to"
fi
# --- the replay: the merge base's fragment set, byte for byte ----------------
# Every blob in the directory is extracted — strays included, and subtrees
# recreated — so the replay refuses exactly what a real assembler run over
# that tree would have refused, instead of quietly narrowing the set.
echo"changelog-assembled: the version is '$ver' (a release tree) and '$dir/' at the"
echo" merge base ($short_base) holds $frag_count fragment(s), but $changelog has no"
echo" non-empty section for '$ver' on HEAD."
echo
echo" The fragments were consumed and their prose went nowhere: the release"
echo" this tree is about to publish would have a body the authors never got"
echo" to write. The ceremony's edit is one tool run, in this PR:"
echo
echo" bin/changelog-assemble '$ver'"
} >&2
failures=$((failures +1))
else
if ! diff_out="$(diff -u \
--label "expected — assembled from the $frag_count fragment(s) at the merge base ($short_base)"\
--label "found — section '$ver' in $changelog on HEAD"\
<(printf'%s\n'"$expected") <(printf'%s\n'"$found"))"; then
{
echo"changelog-assembled: the section '$ver' in $changelog is NOT what the fragments it consumed assemble to:"
echo
printf'%s\n'"$diff_out"| sed 's/^/ /'
echo
echo" The release body is published verbatim from this section, so any"
echo" difference here ships: a missing line is an author's entry silently"
echo" dropped from history, an extra or edited line is prose nobody wrote,"
echo" and a re-ordering is not the canonical order the assembler produces."
echo" The fix is to redo the ceremony's edit with the tool — re-run"
echo" bin/changelog-assemble '$ver' <date> from the merge base's fragments —"
echo" never to hand-edit the section into agreement."
} >&2
failures=$((failures +1))
fi
fi
else
{
echo"changelog-assembled: the merge base's fragment set does not assemble — the replay refuses:"
echo
printf'%s\n'"$expected"| sed 's/^/ /'
echo
echo" The set replayed is exactly '$dir/' as of the merge base ($short_base)."
echo" A section that bin/changelog-assemble would refuse to produce cannot"
echo" have been produced by it — whatever stamped this section did it by"
echo" hand, and the release body cannot be trusted to be what the fragment"
echo" authors wrote."
} >&2
failures=$((failures +1))
fi
["$failures" -eq 0]||exit1
echo"changelog-assembled: section '$ver' in $changelog is byte-for-byte the assembly of the $frag_count fragment(s) consumed at the merge base ($short_base)"