Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
id: itd-93
slug: abcd-scaffolds-a-hardened-changelog-driven-release-gate-into
spec_id: null
kind: null
spec_id: spc-14
kind: standalone
suggested_kind: null
reclassification_history: []
builds_on: []
Expand All @@ -14,17 +14,20 @@ severity: minor

## Press Release

> _Facilitator-seeded draft — the product thinker owns the final press-release
> framing._
> _Design settled in the 2026-07-24 maintainer grill (see DECISIONS.md); the
> four resolved decisions are folded below and recorded in § Open Questions._

> **A repo abcd manages gets a release process that is correct the day it goes
> public — no self-inflicted first-release failure.** Ask abcd to set up
> releases and it lands a changelog-driven release gate: rolling `[Unreleased]`
> into a dated version in a reviewed PR is the release decision, and on merge the
> automation tags exactly that commit and publishes. The gate that verifies the
> release is armed against the *reviewed content commit*, so the very first
> public release cannot hit the receipt-vs-tag self-reference that once blocked
> abcd's own.
> releases and `abcd launch scaffold` lands a changelog-driven release gate:
> rolling `[Unreleased]` into a dated version in a reviewed PR is the release
> decision, and on merge the automation tags exactly that commit and publishes.
> The gate that verifies the release is armed against the *reviewed content
> commit*, so the very first public release cannot hit the receipt-vs-tag
> self-reference that once blocked abcd's own. Before that first release the
> operator runs a built-in rehearsal — a `workflow_dispatch` dry run that arms
> the full gate against a simulated release and publishes nothing — so a green
> rehearsal proves the gate works before it is ever trusted with a real tag.
>
> "I flipped my repo public and cut a release the same afternoon — it just
> worked," said Alice, a solo founder. "I didn't have to discover, the hard
Expand Down Expand Up @@ -56,15 +59,33 @@ at its first public release.

## What's In Scope

- **A scaffold path** (verb TBD — see Open Questions) that writes, into a
managed repo that lacks them, the fixed release machinery: a `release.yml`
(verify → build → publish, gate armed against the reviewed content commit) and
an `auto-release.yml` (detect newest dated CHANGELOG version → tag that commit
→ call `release.yml`), both `GITHUB_TOKEN`-only and injection-safe.
- **A `launch` sub-verb** (`abcd launch scaffold`), extending the existing
04-launch surface — which already owns how a release is cut and gated — that
writes, into a managed repo that lacks them, the fixed release machinery: a
`release.yml` (verify → build → publish, gate armed against the reviewed
content commit) and an `auto-release.yml` (detect newest dated CHANGELOG
version → tag that commit → call `release.yml`), both `GITHUB_TOKEN`-only and
injection-safe.
- **The adr-37 policy, carried as a per-repo runbook**: the CHANGELOG is the
release instrument; rolling `[Unreleased]` → `## [X.Y.Z] - <date>` in a
reviewed PR is the release decision; the two-commit release-branch shape
(roll → receipts) is documented so `HEAD^2^` resolution holds.
- **Self-scaffold parity — one template, proven by abcd-cli's own release**:
the scaffold ships a single template, and abcd-cli's own
`release.yml`/`auto-release.yml` are regenerated from it (with abcd-cli's
substitutions) under a test that asserts the tree matches the template output.
The proven pattern and the shipped template are one artifact by construction,
so every abcd release exercises the exact machinery a managed repo receives.
- **A built-in `workflow_dispatch` rehearsal mode**: the scaffolded workflow
carries a dry run that arms the full gate against a simulated changelog roll
and reviewed-content commit, asserts the gate admits it, and publishes
nothing. The runbook makes a green rehearsal the precondition for the first
real release.
- **Producer-agnostic on the changelog seam**: the dated CHANGELOG heading *is*
the seam with derived versioning (itd-73). `auto-release` keys on the newest
dated heading, so `launch ship`'s derived version is one optional producer and
a hand-rolled heading fires the same machinery; the scaffold stays
producer-agnostic.
- **The receipt/charter interop already fixed in abcd-cli**: the sha-keyed
receipt-dir convention plus the `check-reviews` (RD001) exemption, so the two
in-repo review conventions do not collide.
Expand All @@ -91,30 +112,48 @@ at its first public release.

## Acceptance Criteria

> _BDD format, per the itd-1 discipline. Facilitator-seeded from the abcd-cli
> fix; the product thinker should confirm the bar._
> _BDD format, per the [itd-1 discipline](../disciplines/itd-1-acceptance-gates.md).
> The bar was confirmed in the 2026-07-24 maintainer grill: the five seeded
> criteria stand, amended for the rehearsal-mode decision (c), with a sixth
> covering the rehearsal itself._

- **Given** a managed GitHub repo with no release workflow, **when** the
operator runs the release-scaffold verb, **then** `release.yml`,
operator runs the `launch scaffold` sub-verb, **then** `release.yml`,
`auto-release.yml`, and the release runbook are written, wired to the repo's
own CI check names, and pass the repo's workflow audit (e.g. zizmor) with no
injection or duplicate-key findings.
- **Given** a repo with the scaffolded gate, **when** it cuts its first public
release (roll `[Unreleased]` → dated heading, merge), **then** the release
publishes — the gate is armed against the reviewed content commit and does
**not** hit the receipt-vs-tag self-reference (a test exercises the merge path
and asserts a published release, not a fail-closed gate).
- **Given** a repo with the scaffolded gate **and a green `workflow_dispatch`
rehearsal on record**, **when** it cuts its first public release (roll
`[Unreleased]` → dated heading, merge), **then** the release publishes — the
gate is armed against the reviewed content commit and does **not** hit the
receipt-vs-tag self-reference (a test exercises the merge path and asserts a
published release, not a fail-closed gate).
- **Given** a repo that configures **no** semantic detector, **when** it
releases, **then** the deterministic gates alone admit the release and the
receipt gate requires nothing (no host-run pass is silently treated as
missing).
- **Given** the machinery is already present and current, **when** the scaffold
verb runs again, **then** it reports a no-op and mutates nothing; **and given**
an operator hand-edited a scaffolded workflow, **when** the verb runs, **then**
it refuses or transparent-confirms rather than clobbering.
- **Given** the machinery is already present and current, **when** the
`launch scaffold` sub-verb runs again, **then** it reports a no-op and mutates
nothing; **and given** an operator hand-edited a scaffolded workflow, **when**
the verb runs, **then** it refuses or transparent-confirms rather than
clobbering.
- **Given** the scaffolded `check-reviews`/RD001 charter, **when** sha-keyed
receipt directories exist, **then** they are exempt from the dated-review-dir
shape (the abcd-cli collision does not recur in the managed repo).
- **Given** the scaffolded rehearsal mode, **when** the operator triggers the
`workflow_dispatch` rehearsal, **then** the full gate is armed against a
simulated changelog roll and reviewed-content commit, the gate admits it, and
nothing is published — a green rehearsal proves the gate before the first real
release.

## Prior Art

- [adr-37](../../decisions/adrs/0037-changelog-driven-releases.md) — the
changelog-driven release policy this scaffolds.
- iss-108 — the self-reference flaw, its abcd-cli fix (PR #99), and the verified
finding that no release machinery currently reaches managed repos.
- `.abcd/development/release-gate/` — abcd-cli's own runbook + detectors, the
proven pattern to generalise.

## Open Questions

Expand Down Expand Up @@ -147,11 +186,6 @@ queued in `../../plans/2026-07-24-next-run-queue.md` (Track 1)._
and a hand-rolled heading fires the same machinery. The scaffold stays
producer-agnostic.

## References
## Audit Notes

- [adr-37](../../decisions/adrs/0037-changelog-driven-releases.md) — the
changelog-driven release policy this scaffolds.
- iss-108 — the self-reference flaw, its abcd-cli fix (PR #99), and the verified
finding that no release machinery currently reaches managed repos.
- `.abcd/development/release-gate/` — abcd-cli's own runbook + detectors, the
proven pattern to generalise.
_Empty. Populated by intent-fidelity-reviewer when intent moves to shipped/._
2 changes: 1 addition & 1 deletion .abcd/development/plans/2026-07-18-next-drain-run-queue.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ PR #99) — scaffold `release.yml`/`auto-release.yml` (armed against the reviewe
content commit), the runbook, and the sha-keyed-receipt/RD001 interop into a
managed repo, so its first public release cannot hit the self-reference abcd-cli
paid to discover. Backing intent:
[`../intents/drafts/itd-93-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md`](../intents/drafts/itd-93-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md).
[`../intents/planned/itd-93-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md`](../intents/planned/itd-93-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md).

**NOT yet run-ready — readiness gates (a drain burst must check these first and
SKIP-with-reason if unmet, per the protocol's skip filter):**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
id: spc-14
slug: abcd-scaffolds-a-hardened-changelog-driven-release-gate-into
intent: itd-93
---
# abcd-scaffolds-a-hardened-changelog-driven-release-gate-into

## Summary

spc-14 delivers itd-93: a `launch` sub-verb (`abcd launch scaffold`) that writes,
into a managed repo that lacks them, the fixed changelog-driven release machinery
abcd-cli reached only after untangling its own first-release failure — a
`release.yml` and an `auto-release.yml` whose verify gate is armed against the
reviewed *content* commit, so the very first public release cannot hit the
receipt-vs-tag self-reference. The scaffold ships one template that abcd-cli's own
release workflows are regenerated from (self-scaffold parity), and carries a
built-in `workflow_dispatch` rehearsal a repo runs green before its first real
release.

This spec is the product requirement synthesised from the 2026-07-24 maintainer
grill (DECISIONS.md) and the intent. Its four design decisions are settled here;
the **implementation design and build are a separate, focused run** and are out
of scope for this promotion (2026-07-24 next-run queue, Track 1: "Promotion only
— implementation is NOT in this run").

## Scope

- **Surface — a `launch` sub-verb** (`abcd launch scaffold`), extending the
existing 04-launch chapter, which already owns how a release is cut and gated.
It is explicit and opt-in.
- **What it writes:** into a managed repo with no release workflow, a
`release.yml` (verify → build → publish, the verify gate armed against the
reviewed content commit — `HEAD^2^` on the auto-release merge path, `HEAD^` on
a direct tag) and an `auto-release.yml` (newest dated CHANGELOG version → tag
that commit → call `release.yml`), both `GITHUB_TOKEN`-only and injection-safe,
plus the adr-37 release runbook.
- **Self-scaffold parity — one template.** abcd-cli's own
`release.yml`/`auto-release.yml` are regenerated from the shipped template
(with abcd-cli's substitutions) under a test that asserts the tree matches the
template output, so the proven pattern and the template are one artifact.
- **A built-in `workflow_dispatch` rehearsal mode** that arms the full gate
against a simulated changelog roll and reviewed-content commit, asserts the
gate admits it, and publishes nothing. The runbook makes a green rehearsal the
precondition for the first real release.
- **Producer-agnostic on the changelog seam.** The dated CHANGELOG heading *is*
the seam with derived versioning (itd-73); `auto-release` keys on the newest
dated heading, so `launch ship`'s derived version is one optional producer and
a hand-rolled heading fires the same machinery.
- **Receipt/charter interop** already fixed in abcd-cli: the sha-keyed
receipt-dir convention plus the `check-reviews` (RD001) exemption, so the two
in-repo review conventions do not collide.
- **Wiring to the repo's own facts:** required-status-check contexts and the
release-gate's required detectors are derived from the target repo's actual CI
job names / configured gates, not hard-coded to abcd-cli's.
- **Idempotent + fail-safe:** re-running is a no-op when the machinery is
current; it never overwrites a hand-edited workflow without a
transparent-confirm; it refuses rather than half-writing.

Out of scope (itd-93 § What's Out of Scope): the semantic detectors themselves
(host-run LLM passes, not scaffolded CI — the scaffold degrades cleanly to the
deterministic gates when none is configured); signing/attestation beyond the
built-in `GITHUB_TOKEN` + `actions/attest`; non-GitHub forges; and choosing the
version number (adr-31/itd-73). **Also out of scope for this spec:** the
implementation design — the concrete workflow YAML, the template-substitution
mechanism, and the verb wiring are deferred to the focused implementation run.

## Design decisions (resolved in the 2026-07-24 maintainer grill)

| # | Question | Resolution | Rejected |
|---|---|---|---|
| (a) | Which surface scaffolds it? | A `launch` sub-verb (`abcd launch scaffold`) extending 04-launch — launch already owns how a release is cut and gated; explicit and opt-in. | New top-level verb (new surface to reconcile); `ahoy install` step (release CI silently arriving with install is the non-deliberate path this intent argues against); embark-time record family (couples to a round-trip most managed repos won't use). |
| (b) | Templated vs. copied? | Self-scaffold parity: one template; abcd-cli's own workflows are regenerated from it and a test asserts the tree matches the template output, so the proven pattern and the template are one artifact. | Lockstep diff test between two hand-maintained artifacts; frozen verbatim copy. |
| (c) | Private→public activation | Built-in `workflow_dispatch` rehearsal mode: arms the full gate against a simulated roll and reviewed-content commit, asserts it admits, publishes nothing; a green rehearsal is the runbook precondition for the first real release. | — |
| (d) | Relationship to itd-73 | The dated CHANGELOG heading **is** the seam; `auto-release` keys on the newest dated heading, so `launch ship`'s derived version is one optional producer and a hand-rolled heading fires the same machinery. The scaffold stays producer-agnostic. | — |

## Approach

The design generalises abcd-cli's own release gate — its runbook and detectors
under `.abcd/development/release-gate/`, and the self-reference fix recorded in
iss-108 (PR #99) — into configuration a managed repo inherits rather than
re-derives with the same latent bug baked in.

The load-bearing correctness property is the same one abcd-cli paid for once: the
verify gate arms against the reviewed *content* commit, not the tagged commit, so
a receipt naming the release can live in a later commit than the one it names.
The scaffold carries the two-commit release-branch shape (roll → receipts) so
`HEAD^2^` resolution holds, and derives the required-status-check contexts and
required detectors from the target repo's own CI rather than abcd-cli's.

Self-scaffold parity (b) makes the shipped template and abcd-cli's proven
workflows one artifact: every abcd release exercises the exact machinery a
managed repo receives, and a parity test fails if they drift. The rehearsal mode
(c) closes the private→public activation gap that produced the original failure —
a gate that never ran while the repo was private now proves itself green, against
a simulated roll that publishes nothing, before the first real tag.

**The implementation design is deferred.** The concrete `release.yml` /
`auto-release.yml` contents, the template-and-substitution mechanism, the parity
test, the rehearsal `workflow_dispatch` job, and the `launch scaffold` verb wiring
are the focused implementation run's work (2026-07-24 queue, "itd-93
implementation — focused run once promoted"); synthesising them here would exceed
what the grill settled. This spec fixes the product requirement and the four
design decisions the implementation builds against.

## Acceptance-criteria satisfaction

Each criterion in itd-93 § Acceptance Criteria maps to the design element that
delivers it; the implementation run builds each and lands the test the criterion
names.

- **Scaffold writes wired, audit-clean workflows** — the `launch scaffold`
sub-verb (a) writes `release.yml`, `auto-release.yml`, and the runbook, wired to
the repo's own CI check names, `GITHUB_TOKEN`-only and injection-safe so the
repo's workflow audit (e.g. zizmor) is clean.
- **First public release publishes after a green rehearsal** — the reviewed
content-commit gate arming, plus the rehearsal precondition (c), together make
the first release publish rather than fail closed on the receipt-vs-tag
self-reference; a test exercises the merge path and asserts a published release.
- **No semantic detector configured → deterministic gates alone admit** — the
scaffold degrades cleanly to the deterministic gates and the required-detector
list reflects that none is configured, so no host-run pass is treated as
missing.
- **Re-run is a no-op; hand-edits are not clobbered** — the idempotent,
fail-safe scaffolding reports a no-op when current and refuses or
transparent-confirms rather than overwriting a hand-edited workflow.
- **Sha-keyed receipt dirs are exempt from the dated-review-dir shape** — the
scaffolded `check-reviews`/RD001 charter carries the exemption, so the abcd-cli
collision does not recur in the managed repo.
- **Rehearsal arms the full gate and publishes nothing** — the built-in
`workflow_dispatch` rehearsal (c) arms the full gate against a simulated roll
and reviewed-content commit, admits it, and publishes nothing, proving the gate
before the first real release.