feat: abcd launch scaffold — the release-gate scaffolder (itd-93) - #154
Merged
Conversation
Assisted-by: Claude:claude-opus-4-8[1m]
The scaffold package renders the changelog-driven release machinery
(release.yml, auto-release.yml, adr-37 runbook) from one embedded template,
using <% %> delimiters so GitHub Actions ${{ }} passes through literally.
AbcdSubstitutions reproduces abcd-cli's live workflows byte-for-byte
(TestSelfScaffoldParity), so the proven pattern and the shipped template are one
artifact; abcd-cli's own release.yml is regenerated from the template, adding
only the additive workflow_dispatch rehearsal (trigger + release-job guard +
non-publishing rehearsal job) — the sole sanctioned live-workflow diff (Branch A).
BareSubstitutions degrades cleanly for a managed repo with no semantic detector:
the deterministic Go gates alone, a generic build, GITHUB_TOKEN-only. Repo facts
(default branch, Go version) are derived and validated against an injection-safe
allowlist before reaching the YAML.
itd-93 / spc-14.
Assisted-by: Claude:claude-opus-4-8[1m]
abcd launch scaffold writes the release machinery into a managed repo that lacks it, wired to the repo's own default branch and Go version. Idempotent and fail-safe: a re-run on current machinery is a no-op (exit 0), a hand-edited file is refused (exit 1) rather than clobbered unless --confirm, a structural fault exits 2. Reachable from both front doors: the CLI subcommand under launch, and the plugin markdown surface (commands/abcd/launch.md). The brief 04-launch surface doc, the surface baseline, and the generated CLI reference record the new sub-verb; CHANGELOG entry added. itd-93 / spc-14. Assisted-by: Claude:claude-opus-4-8[1m]
…orkflow The bare release.yml has no attest step, so its caller need not hand down id-token/attestations. Least-privilege for the managed-repo profile; abcd's own auto-release is unchanged (self-scaffold parity holds byte-for-byte). itd-93 / spc-14 Assisted-by: Claude:claude-opus-4-8[1m]
On the all-or-nothing refusal-abort path the first pass marked absent files StatusWritten before any write, so a run that refused a hand-edited sibling reported '[written]' for a file it never wrote and that was absent on disk (the report contradicted disk and the wrote counter). Classify now returns a disposition, a planned write is provisional (StatusSkipped) until the second pass actually writes it, and only a successful write flips it to StatusWritten; on abort or a mid-write fault the unwritten files stay skipped with a reason. The CLI now also renders the partial report on a mid-write fault before exit 2. Adds TestRefusalAbortReportMatchesDisk (watched fail before, pass after). Ruthless-review FIX-FIRST. itd-93 / spc-14 Assisted-by: Claude:claude-opus-4-8[1m]
…affold # Conflicts: # .abcd/work/DECISIONS.md
…affold # Conflicts: # .abcd/work/DECISIONS.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
abcd launch scaffold— the release-gate scaffolder (itd-93 / spc-14). Writes thechangelog-driven release machinery into a managed repo that lacks it, from a single
embedded template that abcd-cli's own release workflows are regenerated from
(self-scaffold parity).
Delivery per acceptance criterion
abcd launch scaffoldwritesrelease.yml,auto-release.yml, and the adr-37 runbook, wired to the repo's owndefault branch and Go version (derived from
.git+go.mod, validated against aninjection-safe allowlist),
GITHUB_TOKEN-only. Bare-profile YAML verified to parseand to reference no secret other than
GITHUB_TOKEN.against the reviewed content commit (
HEAD^2^merge path /HEAD^direct tag);the abcd rendering reproduces that proven arming byte-for-byte, so the receipt-vs-tag
self-reference cannot recur — satisfied by construction and pinned by the parity test.
omits the semantic-gate block entirely; the runbook states no detector is configured.
Tested (
TestBareRenderOmitsAbcdMachinery).no-op on current machinery, refuse (exit 1) on a hand-edit unless
--confirm. Tested.runbook documents the exemption. (The executable check-reviews charter is abcd-specific
and not scaffolded into a bare repo — a repo with no charter has no collision.)
workflow_dispatchrehearsal simulates the two-commit roll + merge, resolves the content commit, and holds
contents: readonly — nogh release create, tag push, or attest. Tested(
TestRehearsalPublishesNothing).Branch A (maintainer-sanctioned 2026-07-27)
The template is the single source for
release.yml/auto-release.yml; abcd-cli's liveworkflows are regenerated from it. The only diff to the live
release.ymlis theadditive rehearsal, in three additive parts:
workflow_dispatchtrigger,if: github.event_name != 'workflow_dispatch'on the existingrelease(publish) job, so a rehearsal never reaches the publish path, and
rehearsaljob.TestSelfScaffoldParitypinsrender(AbcdSubstitutions)byte-for-byte to the committedworkflows;
auto-release.ymlis byte-identical for abcd. The existing verify/build/publish/semantic-gate job bodies are reproduced verbatim (105 insertions, 0 deletions).
Part (2) is a job-level guard, not a step-body change; flagged here as the one judgment
call within "the additive rehearsal" for the merge review.
Decision recorded in
.abcd/work/DECISIONS.md(2026-07-27).Reviews
the derived facts (both allowlisted to
\d+\.\d+/ git-ref chars before reaching YAML,passed to shell via
env:only), the write path (symlink/TOCTOU/traversal/clobber, allbehind
ReadGuarded+ atomic rename), the token/permission model, rehearsal-publishes-nothing, and the live-workflow invariants — nothing survived.
files
writtenon the all-or-nothing abort path (report contradicted disk). Fixed:writes are provisional (
skipped) until actually committed;TestRefusalAbortReportMatchesDiskadded (watched fail → pass). NOTE-1 (CLI dropped the partial report on a mid-write fault)
addressed. NOTE-2 (
deriveBranchreads only loose refs; a packed-refs repo scaffolded froma feature branch wires that branch) left as documented safe degradation — validated and
visible in the printed
branch <name>.Preflight
make preflightclean (build,gofmt -l .empty, vet,go test ./..., race); record-lint,docs-lint, check-reviews, smoke all exit 0. Pre-push hook (full preflight + record-lint)
passed.
Record: itd-93 / spc-14. Maintainer merges.