Development record
abcd Scaffolds a Release Gate That Works on the First Try
Press Release
Design settled in the 2026-07-24 maintainer grill (see dcn-2607240000000003); 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
abcd launch scaffoldlands 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 — aworkflow_dispatchdry 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 way, that my release gate could never be satisfied. abcd gave me the version abcd itself only reached after a day of untangling."
Why This Matters
When abcd-cli went public and cut its first release, the semantic release gate
— which had never run end-to-end while the repo was private — fail-closed by
construction: it armed against the tagged commit and read the reviewer
receipts from that commit's own tree, but a receipt names the commit its
reviewer read and can only live in a later commit, so a receipt naming the
tagged commit can never sit in the tagged commit's tree. The fix
(PR #99, recorded in
[iss-108]) was to arm against the reviewed content commit (HEAD^2^ on the
auto-release merge path, HEAD^ on a direct tag) and to structure the release
branch as two commits — the changelog roll, then the receipts naming it.
That flaw was abcd-cli's own CI, and it did not reach managed repos —
abcd ships and scaffolds no release workflow today ([iss-108] verified this:
launch-payload.json excludes .github/, ahoy/launch write no CI). But that is
exactly the gap this intent closes: abcd is a configuration layer for
development, and "how you cut a correct, gated release" is configuration a
managed repo should be able to inherit rather than re-derive — and re-derive
with the same latent self-reference bug baked in. The lesson abcd paid for
once should ship as a working default, not a trap every managed repo rediscovers
at its first public release.
What's In Scope
- A
launchsub-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: arelease.yml(verify → build → publish, gate armed against the reviewed content commit) and anauto-release.yml(detect newest dated CHANGELOG version → tag that commit → callrelease.yml), bothGITHUB_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 soHEAD^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.ymlare 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_dispatchrehearsal 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-releasekeys on the newest dated heading, solaunch 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. - Wiring to the repo's own facts: the 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.
- The deterministic ship flow (folded 2026-08-19 from iss-327, the
maintainer's decision after abcd-cli's own v0.6.0 tag fail-closed
unpublishably — iss-326): the gate that today fires at tag time — the most
expensive, unrecoverable moment — shifts left into the verb, so the happy
path is the only path an operator can walk. Three pieces: the emit step
prints the receipts protocol as its own checklist (run the semantic gates
against the commit this cut produces; receipts commit on top) instead of
assuming the runbook was read; the ingest step refuses to finish a cut it
cannot prove releasable — it refuses on
main, and a cut whose content commit lacks validating PROMOTE receipts is loudly incomplete, never quietly mergeable; and alaunch receiptssub-verb runs the exact receipt-gate check the release job runs, locally, before the merge — a red result costs an amend instead of a dead tag. Bootstrap ordering belongs to the tool, not the operator's memory. - Idempotent + fail-safe scaffolding: re-running is a no-op when the machinery is current; it never overwrites a workflow the operator hand-edited without a transparent-confirm; it refuses rather than half-writing.
What's Out of Scope
- The semantic detectors themselves (
docs-currency-reviewer,brief↔surface cross-check) — they are host-run LLM passes, not scaffolded CI; a managed repo opts into them (or runs none) and the gate's required-detector list reflects that. Scaffolding must degrade cleanly to the deterministic gates alone when no semantic detector is configured. - Signing/attestation infrastructure beyond what the built-in
GITHUB_TOKEN+actions/attestalready provide (no new dependency, no PAT). - Non-GitHub forges — this scaffold targets GitHub Actions; other CI hosts are a later concern.
- Choosing the version number — that remains adr-31/itd-73 (derived from intent impact); this intent scaffolds the cutting and gating machinery.
Scope Conditions
None stated.
Acceptance Criteria
BDD format, per the itd-1 discipline. 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
launch scaffoldsub-verb, thenrelease.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 and a green
workflow_dispatchrehearsal 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
launch scaffoldsub-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_dispatchrehearsal, 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.
- Given an operator on a release branch whose content commit has no
receipts, when they run the
launch receiptscheck (or the ingest step completes), then the output names each missing or non-PROMOTE receipt and the commit it must name — and the same repository state fails the release job's receipt gate identically, so the local check and the remote gate can never disagree (folded 2026-08-19, iss-327). - Given an operator who runs the emit step, when it renders the cut, then the output ends with the receipts protocol as a numbered checklist — the semantic gates to run, the commit to key receipts to, and the two-commit branch shape — so a first-time operator learns the protocol from the verb, never from a failed release run (folded 2026-08-19, iss-327).
Prior Art
- adr-37 — 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
All four resolved in the 2026-07-24 maintainer grill (see dcn-2607240000000003
and dcn-2607240000000005). The PRD is synthesised from that interview; promotion is
queued in ../../plans/2026-07-24-next-run-queue.md (Track 1).
- Which surface scaffolds it? RESOLVED: a
launchsub-verb (e.g.abcd launch scaffold) — launch already owns how a release is cut and gated; explicit and opt-in; extends the existing 04-launch chapter. Rejected: new top-level verb (new surface to reconcile),ahoy installstep (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). - How much is templated vs. copied? RESOLVED: self-scaffold parity —
one template; abcd-cli's own
release.yml/auto-release.ymlare regenerated from it (with abcd-cli's substitutions) and a test asserts the tree matches the template output. The proven pattern and the shipped template are one artifact by construction; every abcd release exercises the exact machinery managed repos get. Rejected: lockstep diff test between two hand-maintained artifacts; frozen verbatim copy. - Private→public activation. RESOLVED: built-in rehearsal mode — the
scaffold ships a
workflow_dispatchdry-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. - Relationship to itd-73 (derived versioning) — RESOLVED: the CHANGELOG
dated-heading format is the seam;
auto-releasekeys on the newest dated heading, solaunch ship's derived version is one optional producer and a hand-rolled heading fires the same machinery. The scaffold stays producer-agnostic.
Audit Notes
Fidelity review — receipt rcp-1957b22ad5cc (verifier intent-auditor claude-fable-5-1).
Provenance: intent-auditor@claude-fable-5-1 · rubric_hash sha256:effa65b3e9e88ff29433b443ec2be159522a8b0b71cf1434526514aa61edb13e · prompt_hash sha256:973d1c700a856b8b62db01f196dbd65d4e4def78c99456b1cbac4743eb54e436 Input attestations: diff:internal/core/launch/scaffold and internal/surface/cli/launch_receipts.go at main 811fba17 (git ls-tree -r; delivered through 273f8cbc, 1cb31e21, 09e0af6c, 2ccf16b7 on 2026-09-25)@sha256:218f24486c3a5c40420205c1de4c2424083215692234048b0100a9dd77bc6947;
Acceptance rollup: MET 8 · MET_WITH_CONCERNS 0 · NOT_MET 0 · INCONCLUSIVE 0
Per-criterion verdicts:
- ac-1 — MET: the scaffold renders release.yml, auto-release.yml and the runbook from one template set, wires the required checks from the repository's own pull-request workflow through DeriveCIChecks, and a test runs the workflow audit and the duplicate-key check over the rendered files evidence: internal/core/launch/scaffold/scaffold.go:106 — "func Scaffold(req Request) (Report, error) {" evidence: internal/core/launch/scaffold/cichecks.go:55 — "func DeriveCIChecks(repoRoot string) []string {" evidence: internal/core/launch/scaffold/wiring_test.go:107 — "func TestScaffoldWiresTheRepositorysOwnCIChecks" evidence: internal/core/launch/scaffold/wiring_test.go:227 — "func TestScaffoldedWorkflowsPassTheWorkflowAudit"
- ac-2 — MET: a test drives a scaffolded repository's first release through the merge path and asserts a published release, with the gate armed against the reviewed content commit carried as content_sha from verify to the release job evidence: internal/core/launch/scaffold/mergepath_release_test.go:41 — "func TestScaffoldedGateCutsAFirstReleaseThatPublishes" evidence: internal/core/launch/scaffold/templates/release.yml.tmpl:131 — "content_sha: ${{ steps.receipts.outputs.content_sha }}" evidence: internal/core/launch/scaffold/contentsha_workflow_test.go:20 — "func TestReleaseConsumesTheContentShaVerifyGated"
- ac-3 — MET: the bare substitutions carry no semantic gates, the bare release.yml omits every abcd-specific detector while keeping the deterministic gates and the rehearsal, and the bare runbook states that no semantic detector is configured evidence: internal/core/launch/scaffold/substitutions.go:56 — "SemanticGates: nil," evidence: internal/core/launch/scaffold/scaffold_test.go:96 — "func TestBareRenderOmitsAbcdMachinery" evidence: internal/core/launch/scaffold/scaffold_test.go:132 — "No semantic detector is configured"
- ac-4 — MET: a re-run over current machinery reports no_op with every file current, and a hand-edited file refuses the whole run with ErrScaffoldBlocked unless Confirm is set evidence: internal/core/launch/scaffold/scaffold.go:22 — "var ErrScaffoldBlocked = errors.New("scaffold refused: an existing file was hand-edited (pass --confirm to overwrite)")" evidence: internal/core/launch/scaffold/scaffold.go:129 — "report.NoOp = wrote == 0" evidence: internal/core/launch/scaffold/scaffold_test.go:297 — "func TestScaffoldIdempotentAndRefusesHandEdit"
- ac-5 — MET: the scaffolded reviews charter exempts sha-keyed receipt directories from the dated-review shape and a test asserts the exemption evidence: internal/core/launch/scaffold/templates/check-reviews.sh.tmpl:9 — "receipt gate). They are exempt from the dated shape here, so the two review" evidence: internal/core/launch/scaffold/wiring_test.go:160 — "func TestScaffoldedCharterExemptsShaKeyedReceiptDirs"
- ac-6 — MET: workflow_dispatch runs the rehearsal job, which arms the gate's resolution path against a simulated release, and tests assert it publishes nothing and that the release job is gated off the rehearsal event evidence: internal/core/launch/scaffold/templates/release.yml.tmpl:65 — "workflow_dispatch:" evidence: internal/core/launch/scaffold/scaffold_test.go:240 — "func TestRehearsalPublishesNothing" evidence: internal/core/launch/scaffold/scaffold_test.go:277 — "func TestReleaseJobGatedOffRehearsal"
- ac-7 — MET:
abcd launch receiptsnames each missing or non-PROMOTE receipt and the commit it must name, and a test holds its verdict identical to the release job's receipt gate on the same repository state evidence: internal/surface/cli/launch_receipts.go:36 — "Use: "receipts"," evidence: internal/surface/cli/launch_receipts_test.go:63 — "func TestLaunchReceiptsNamesEachMissingReceiptAndTheCommit" evidence: internal/surface/cli/launch_receipts_test.go:103 — "func TestLaunchReceiptsFailsIdenticallyToTheReleaseJobsGate" - ac-8 — MET: the emit step ends its render with the receipts protocol as a numbered checklist, rendered by renderReceiptsProtocol and asserted by a test on the ship output evidence: internal/surface/cli/launch_receipts.go:123 — "func renderReceiptsProtocol(w io.Writer, p release.ReceiptsProtocol) {" evidence: internal/surface/cli/launch_receipts_test.go:247 — "func TestLaunchShipEmitEndsWithTheReceiptsProtocol"
Gap audit:
- honoured:
- self-scaffold parity: one template regenerates abcd's own workflows under a test asserting the tree matches evidence: internal/core/launch/scaffold/scaffold_test.go:33 — "func TestSelfScaffoldParity"
- GITHUB_TOKEN-only, injection-safe workflows evidence: internal/core/launch/scaffold/scaffold_test.go:183 — "func TestGeneratedYAMLIsGithubTokenOnly" evidence: internal/core/launch/scaffold/archive_workflow_test.go:129 — "func TestNoWorkflowCarriesTheRepositoryCheckInShell"
- the tag waits on the verify gate and the publish condition needs a green verify evidence: internal/core/launch/scaffold/tagorder_workflow_test.go:30 — "func TestTheTagWaitsOnTheVerifyGate"
- idempotent and fail-safe: a refused file leaves nothing written evidence: internal/core/launch/scaffold/scaffold.go:155 — "// A run that refuses any file writes NOTHING and returns ErrScaffoldBlocked with"
- diverged: (none)
- missing: (none)
Frontmatter
| id | itd-93 |
|---|---|
| type | intent |
| lifecycle | shipped |
| kind | standalone |
| severity | minor |
.abcd/development/intents/shipped/itd-93-abcd-scaffolds-a-hardened-changelog.md
open on GitHub ↗ · commit history ↗
References1
- adr-37Releases are changelog-driven — rolling `[Unreleased]` is the release decision, and automation tags exactly that commitrelated
Referenced by5
- iss-327The ship flow permits an unreleasable cut: launch ship writes the dated heading with no check that the receipts protocol can complete, so the receipt gate fires at tag time — the most expensive possible moment, unrecoverable once tagged. Folded into itd-93 by maintainer decision: the emit prints the receipts protocol as a checklist, the ingest refuses a cut it cannot prove releasable, and a launch receipts sub-verb runs the release job's exact check locally before the mergerelated
- iss-2610262036512603itd-93 says abcd's release workflows are generated from the one scaffold template, so abcd runs exactly what a managed repo gets; the docs chapter says abcd's release workflow has a docs-currency step that the scaffolded template never namesrelated
- itd-106abcd Sets Up the CI a Repo Requires, and Reports What It Didbuilt on by
- spc-14abcd-scaffolds-a-hardened-changelog-driven-release-gate-intoimplemented by
- spc-2609230613193436Scaffolded release gate: CI-name wiring, the receipts check and the protocolimplemented by
mentions27
- adr-31The release version is derived from the intents in it, never authored
- adr-47abcdev.app is rendered from this repository alone
- dcn-26072400000000032026-07-24 — itd-93 design settled in maintainer grill: (a) surface is a
- dcn-26072400000000052026-07-24 — Next-run queue reshaped by the grill: the small consequences
- dcn-26072700000000042026-07-27 — itd-93 parity tension resolved: Branch A. The scaffold template is the single source for release.yml/auto-release.yml; abcd-cli's live workflows are regenerated from it; the only sanctioned live diff is the additive workflow_dispatch rehearsal (trigger + non-publishing dry-run job). Rejected: substitution-gating the rehearsal off for abcd (weakens the parity guarantee on the one novel component).
- dcn-26082000000000022026-08-20 — bughunt round 2 (branch bughunt-b/round-2): captured the round-2 records (iss-346..iss-357, with the two colliding ids re-minted as iss-358/iss-359), fixed
- dcn-26092300000000162026-09-23 — itd-4 AC3 built as ruled (B3): the promote join's back-links are `related_issues` on the intent and `related_intents` on the ledger record, and `abcd intent audit --issue-drift` checks them. Seven implementation decisions the ruling left open, taken by the implementing lane. (1) No reader tolerates the retired `promoted_to` / `promoted_from`: the ledger reader refuses and skips a record carrying `promoted_to`, the intent reader ignores `promoted_from`, and a promote write meeting either refuses. The refusal, the record gate's finding and the drift finding each name the successor and the remedy, `abcd capture migrate --apply`, a verb that reports by default, writes only with `--apply`, and is idempotent. It is a verb and not a one-off script because managed repositories hold the same retired names and need the same repair. (2) "Promoted" is the PAIR, an intent in the record's `related_intents` that names the record back in its `related_issues`, because an issue's `related_intents` already carried loose relations before the rename and still does; the double-promote refusal and the record page's next move read the pair. So the migration completes a join an older abcd wrote from one end only (iss-327 and itd-93, iss-2609091642508005 and itd-2609111003026787), or those records would stop reading as promoted. (3) Link mode on the issue route writes both halves; before the rename it stamped the issue alone, which left a hand-filed draft with no edge back. (4) `related_issues` holds `rdi-N` as well as `iss-N`: a reading item lives in the issue ledger's tree and graduates the same way, and one key per side keeps the join one shape. The first entry is the record the intent was promoted from; a later link appends, so `back_edge_kept` still reports the first. (5) The drift check reports an intent naming a record that does not name it back, but not an ISSUE naming an intent that does not name it back, since that is a loose relation; a reading item carries no loose relation, so from its end a one-way stamp is drift. A shipped intent naming an issue in `wontfix/` is drift, like one in `open/`, because the itd-4 scope asks whether the issue "actually moved to resolved/". The check is not wired into preflight or CI; `--strict` is there for whoever wires it. (6) The historical passages in shipped intents, closed specs and adr-0057 carry a `(historical)` marker beside the retired names, the precedent `development/activity` set, so the new `retired-promote-back-links` ban can gate every current record. (7) The impact is `breaking`: itd-4 declares none, and the rename removes `promoted_to` from `capture list --json`, `promoted_from` from the intent JSON and both link keys from the record page, and makes an unmigrated ledger unreadable until the migration runs.
- dcn-26092500000000282026-09-25 — The build's open-question check reads the record's own settled convention and stays fail-closed (lane implementer, autonomous run A, fix round 1 of the loop lane, on iss-2609252053576085; the lane's first ruling, that every list item under `## Open Questions` is a question whatever it says, lived only in its report and refused intents the record had settled). `intent.OpenQuestions` recognises exactly two markers, learned from the 12 planned intents that carry list items there. A section whose first non-blank line is an italic `_All resolved …_`, with at most one count word (`_All four resolved …_`), is settled whole (itd-111, itd-93); `_All but one resolved_` is not. An item explicitly marked resolved or deferred is not a question: a bold span opening with the word (`**Resolved — …**`, `**Deferred**`, `**Deferred to a follow-up intent**`, `**explicitly deferred**`, `**explicit deferral**`) or the word as a label (`resolved:`, `RESOLVED:`, `Deferred:`), anywhere in the item including its continuation lines. Everything else stays a question: an item led `**Open` whatever it goes on to say (itd-60's "Open, and not gating scope"), an item that only points to another record (itd-76's "travel with itd-126"), `**Out of scope …**`, and a question that merely mentions deferral. With the rule, itd-111 and itd-93 pass the check; itd-7, itd-60, itd-65, itd-66, itd-76, itd-82, itd-117, itd-131, itd-2609170822093401 and itd-2609211116005482 still refuse, each on an item the record does not mark settled. Relabelling those items is the product thinker's call through the planning interview, not the loop's.
- iss-108iss-35 semantic release gate was self-referential under changelog-driven auto-release (adr-37): it armed receipt_gate with the tagged commit but read receipts from that commit's own tree, which can never hold a receipt naming itself. Dormant while private, it fail-closed the first public release (v0.3.0).
- iss-172abcd-managed repos need PR-queue hygiene when branch protection requires up-to-date branches: a queued auto-merge PR whose base moved sits BEHIND forever because GitHub auto-merge never updates branches. Two delivery rungs per basics-built-in/SOTA-delegated: (1) protocol-level now — after arming auto-merge, poll mergeStateStatus and run gh pr update-branch on BEHIND (works with the agent's own token, CI triggers normally); (2) scaffolded CI later — abcd scaffolds an update-branch workflow into managed repos, which requires a PAT/GitHub-App secret because the default GITHUB_TOKEN's pushes do not trigger workflows (the recursion suppression trap), or points at a merge queue where the plan allows. Same scaffolding family as itd-93's release gate; same merged-work-hygiene family as itd-95.
- iss-326The v0.6.0 tag is permanently unpublishable: its roll branch carried no receipts commit, the receipt gate fail-closed at release time, and the re-release path builds only from the tagged commit whose frozen tree can never contain receipts naming its own content commit. The tag stays as a record (anti-tag-move); v0.6.1 is the recovery
- iss-355a batched merge-queue push makes github.sha the batch tip, so auto-release tags the wrong commit and release.yml's HEAD-caret-2-caret receipt derivation resolves an unrelated PR's commit whenever the release roll is not the last entry in its queue batch; the ancestry guard passes and the run wedges after the immutable tag, the iss-326 outcome by a route itd-93's pre-merge check cannot close because batch composition is decided by the queue
- iss-372The CHANGELOG Unreleased section and DECISIONS.md tail are structural merge-conflict magnets under parallel PRs: every concurrent branch appends to the same two files, and the maintainer hand-resolved conflicts across the 2026-08-20 merge sweep with bughunt round 3 DIRTY on exactly these files as the third occurrence. The derived-cut model points at the fix: entries could live in the records themselves (per-record files never conflict) and compose at cut time, retiring the shared Unreleased append entirely — itd-93's surface should weigh it
- iss-2608211146562243RD001 is documented as unconditional in both definition sites (.abcd/work/reviews/README.md and brief/05-internals/06-lint.md name only the root README as exempt), but scripts/check-reviews.sh exempts 40-hex sha-keyed semantic-gate receipt directories — 7 of the 10 live review directories. The exemption is principled and recorded elsewhere ([dcn-2607180000000001](../../decisions/dcn-2607180000000001-the-iss-35-semantic-release-gate-was.md), spc-14, itd-93 acceptance criterion), but a reader auditing the folder against either charter sees 7 apparent blockers, and 06-lint.md says the rule 'ports into internal/core/lint', so an implementer working from the record alone would port it without the exemption and turn the gate permanently red.
- iss-2609081941074556releaseOf stamps the homepage feature block by strings.Contains of the record id against each CHANGELOG line, with no word boundary, walking newest dated section first. A short id therefore inherits a longer one: on ec7f40d6 releaseOf(itd-9) returns 0.4.1 off the itd-93 credit and releaseOf(itd-1) returns 0.7.1 off itd-130, and a future superstring landing in a newer section restamps the featured id. site check does not validate the stamp. The same package already carries bodyHandleRe. Fix: match the record id at a word boundary (reuse bodyHandleRe, or split the line into tokens); newest-section-first can stay. Detector: a changelog whose newer dated section mentions itd-1990 must not stamp featured itd-199, while a line naming itd-199 as its own id still matches. Independent of the Audit Notes rollup scanner. Reported as GitHub issue 624 against ec7f40d6. <!-- record-lint: illustrative -->
- iss-2609091642508005The agent-contract prompt lint ships and is armed as a blocker in the record-lint configuration, enforcing the frontmatter floor on every prompt under the agents directory and gating the diff-armed unbumped-edit check, yet the intent that promised it sits in the planned bucket and its spec sits open. The definition of done says a change that delivers a planned intent closes its spec in the same change, and that the omission is silent by construction: the release cut composes its changelog from terminal folders only, so an intent whose code is on the branch with its spec still open ships with no line and the cut exits zero doing so. That is the state here, and it means the release notes for this cut describe a repository in which this rule does not exist. The condition was found by a cross-check of the design record against the shipped surface rather than by any gate, because no gate asks whether a planned intent's work is already present: the record lint reads what the records say about each other and the release derivation reads only what reached a terminal folder, so the one question that would catch it, whether the code a planned intent describes is already merged, is asked by nothing. Fix: close the spec so the intent ships and the cut sees it, once the acceptance criteria are checked against what actually landed, which is the maintainer's call rather than an automatic move. Detector: a planned intent whose acceptance criteria are satisfied by code already on the branch is reported before a release derives its cut, so the choice to ship it or to keep it planned is made rather than defaulted.
- iss-2609251755386183The release job's semantic receipt gate admits a release that carries no receipts of its own, whenever an earlier release's receipts are in the tree. record-lint --derive-content-sha (lint.DeriveReleaseContentSha) arms the gate against the NEAREST commit on the released lineage that a .abcd/work/reviews/<sha>/ directory names, and never checks that the commit belongs to this release. A roll to a new version with no new receipts derives the previous release's content commit, whose PROMOTE receipts are valid, so receipt_gate passes and the release publishes unreviewed. Reproduced on a scratch clone of this repository at the v0.10.0 tip: a commit rolling CHANGELOG to 0.11.0 derived 64ea8f62 (the v0.10.0 cut) and the armed gate printed no finding. Every release after the first that ever recorded receipts is exposed; the itd-93 scaffolded gate and abcd launch receipts inherit it through the same reader. Fix direction: bind the derived commit to the release — its newest dated CHANGELOG version must equal the released tree's, else fail closed naming both.
- iss-2609252053576085The build's open_questions check (intent.OpenQuestions, read by internal/core/implement/loop/check.go) counts every list item under '## Open Questions' as a question whatever it says, so it refuses records that follow the record's own settled convention: 12 of 50 planned intents carry list items there, and some are settled by their own words, itd-111's section opening '_All resolved or explicitly deferred at planning_' and itd-93's '_All four resolved_', itd-76's item marked '**explicitly deferred**', itd-60's items marked '**Resolved', itd-117's '**Deferred**' items. 'abcd build next' (itd-2609211116005482) would meet refusals nobody planned, and the ruling lives only in a lane report. Keep the check fail-closed, but read the markers the record actually uses.
- iss-2610021502084298No check meets the retired role word in an intent's press release at the record: the docs-lint rule roles/retired-role-word roots at the docs, the command pages and the rules, so a shipped or planned intent's press release carrying it is refused only when the site composer renders it as the landing page's hero quote, which is how itd-60's first MET audit broke the site-render gate (iss-2610021446271464). After the R5 reword of itd-60, thirteen shipped press releases still carry the word (itd-65, itd-66, itd-67, itd-69, itd-73, itd-74, itd-93, itd-102, itd-111, itd-114, itd-125, itd-2609111003026787, itd-2609212137129937), so the next MET audit ingested for any of them refuses the render again on a branch that only recorded an audit; the product thinker's ruling R5 (2026-10-02) accepted that a future slip breaks the build and did not ask for this check. Related to iss-2610020731591808, which names the brief, the principles and the personas registry as swept but unguarded.
- iss-2610262045201587itd-94 has the agent run `abcd intent ready itd-93` with no other argument and read its verdict; itd-179 makes `intent ready` refuse without a grounds argument
- itd-1Every Intent Has Acceptance Criteria; Every Audit Verifies Them
- itd-4Nothing You Notice Gets Lost
- itd-73abcd Cuts the Version — You Never Type One
- itd-94An intent that is not planned cannot be implemented: abcd gains a machine-checkable implement-readiness gate that refuses with a remedy and offers the planning interview
- itd-139Carol's team adopts abcd and gets a readable record the next day, without writing a line of site code
- itd-2609150819432059A managed repository that is not a plugin gets the same release gate
- spc-9an-intent-that-is-not-planned-cannot-be-implemented-abcd-gai