diff --git a/.abcd/development/intents/drafts/itd-93-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md b/.abcd/development/intents/planned/itd-93-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md similarity index 63% rename from .abcd/development/intents/drafts/itd-93-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md rename to .abcd/development/intents/planned/itd-93-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md index 7ce916e..0d89871 100644 --- a/.abcd/development/intents/drafts/itd-93-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md +++ b/.abcd/development/intents/planned/itd-93-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md @@ -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: [] @@ -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 @@ -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] - ` 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. @@ -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 @@ -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/._ diff --git a/.abcd/development/plans/2026-07-18-next-drain-run-queue.md b/.abcd/development/plans/2026-07-18-next-drain-run-queue.md index 30de05b..5fae3c0 100644 --- a/.abcd/development/plans/2026-07-18-next-drain-run-queue.md +++ b/.abcd/development/plans/2026-07-18-next-drain-run-queue.md @@ -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):** diff --git a/.abcd/development/specs/open/spc-14-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md b/.abcd/development/specs/open/spc-14-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md new file mode 100644 index 0000000..a817683 --- /dev/null +++ b/.abcd/development/specs/open/spc-14-abcd-scaffolds-a-hardened-changelog-driven-release-gate-into.md @@ -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.