Development record
A dependency bump lands without a person re-authoring it, and no machine enters the contributor graph
Press Release
A bot-opened dependency bump is re-authored as the repository's owner when its diff is only a manifest and its lock file, so it merges on its own; the attribution gate is untouched and everything else is left alone.
"Every bump sat blocked with auto-merge armed, looking as though it wanted a review no reviewer could give," said a product thinker who had just landed one by hand at the end of a long day. "Now the workflow re-authors the lock-file bumps as me, the message says which bot proposed it and which workflow re-authored it, and anything that is not a bump is left exactly where it was."
Why This Matters
The attribution gate refuses a machine in the author role, on two independent signals, because the contributor graph is built from the author and committer fields and a squash merge re-appends a mis-identified branch author as a co-author. The consequence is deliberate and written down: a bot's pull request is not mergeable as authored. What was not intended is the cost of it, paid on every bump in every ecosystem: the pull request sits with auto-merge armed and every other check green, showing a blocked state that reads as a missing review, and the only way through is a person re-authoring the same two-line diff. On 2026-09-22 that cost a hand-authored branch and two full gate runs for one patch version (iss-2609221820487644). The product thinker ruled the route: re-author the bump before the gate runs, and change the gate not at all.
Mechanism
We expect a bounded re-authoring to end the hand-landing of bumps without letting a machine into the contributor graph, because the bound is the shape of the diff rather than trust in the bot; shown wrong if a commit outside the bound is ever re-authored, or if bumps still need a person after it ships.
Scope Conditions
- Holds where the forge marks a branch as the bot's and the bump's diff is confined to a manifest and its lock file; a bump that edits anything else is a person's.
- Holds for the ecosystems the repository declares; one abcd does not know is left alone rather than guessed at.
- Holds where the repository owner accepts that a workflow re-authors on their behalf under that bound: the authorship claim is the owner's, made once in the configuration rather than per commit.
What's In Scope
- The bound: a commit is re-authored only when its branch is one the forge marks as a declared bot's AND its diff touches nothing but that ecosystem's manifest and lock file (
go.modwithgo.sum,package.jsonwithpackage-lock.json,pyproject.tomlwith its lock,GemfilewithGemfile.lock, and their kin). Every other diff, author or bot is left untouched, and the run says which test the commit failed. - The re-authoring: the commit is replayed with the repository owner as author and committer, its message naming the bot that proposed the bump and the workflow that re-authored it, and carrying
Assisted-by: None, since no model wrote it; the pull request is updated to the re-authored commit. - The gate, unchanged:
scripts/check-attribution.shis not edited; it passes the re-authored commit for the reason it always would, and still refuses the bot's original. - The declaration: the repository names the bots and the ecosystems that qualify; an unlisted bot or an unknown ecosystem is left alone.
- The scaffold: the same verb that writes a managed repository's release workflows writes this one, opt-in per repository; abcd's own repository carries it.
- The record: every re-authoring is written where the repository can see it, naming the bot, the bump and the resulting commit.
- Security review before it ships: it rewrites authorship and pushes to a branch under the repository's own credentials.
What's Out of Scope
- Any change to the attribution gate's rules or its refusals.
- Merging the bump: the queue and the repository's own rules decide that as they do for any pull request.
- Choosing which dependencies to take, or reviewing what a bump contains.
Decisions
Ruled by the product thinker on 2026-09-21, in the interview that filed and planned this intent (iss-2609221820487644 records the vocabulary rulings it rests on):
- Route 2 of the three the capture named (ruled 2026-09-22): re-author before the gate runs; the gate itself does not change.
- The bound is the diff's shape, and it covers every ecosystem dependabot opens, not Go alone.
- The message names the bot and the workflow, and the trailer is
Assisted-by: None. - Scaffolded like the release gate, opt-in per managed repository.
- The authorship point is named rather than assumed: a workflow asserts the owner's authorship with no person in the loop, which the owner accepts once in the configuration, under the bound above.
Open Questions
None open.
Acceptance Criteria
- Given a bot-opened bump on a branch the forge marks as that bot's, whose diff touches only that ecosystem's manifest and lock file, when the workflow runs, then the commit is re-authored as the repository owner and the pull request is updated to it.
- Given a commit on such a branch whose diff touches anything else, or a commit by an unlisted bot or a person, when the workflow runs, then nothing is re-authored and the run names which test the commit failed.
- Given a re-authored commit, when its message is read, then it names the bot that proposed the bump and the workflow that re-authored it, and carries
Assisted-by: None. - Given the attribution gate, when this ships, then its script is unchanged, it passes the re-authored commit, and it still refuses the bot's original.
- Given an ecosystem or a bot the repository has not declared, when a bump arrives from it, then nothing is re-authored and the run says so.
- Given a managed repository that has opted in, when the scaffolding verb runs, then the workflow is written beside its release workflows; a repository that has not opted in is unchanged.
- Given any re-authoring, when the repository is inspected, then a record names the bot, the bump and the resulting commit.
Audit Notes
Fidelity review OWED (receipt rcp-7093bbfa22c6).
- 2026-09-30 — Shipped under the person's ruling DR2 (2026-09-30: "SHIP NOW with the first live bump recorded as owed (after the person creates the App + secrets)"). The first live bump is owed and not yet run: the first acceptance criterion is proven offline only, against a stand-in App API and a local remote, until the person creates and installs the GitHub App, stores its two Dependabot secrets and sets the owner, and one live bump is watched through. iss-2609292030070275 tracks that live run and stays open.
Grounds
- pursued: dependabot opens these continually, every one blocks with auto-merge armed and looks like it wants a review, and tonight one cost a hand-authored branch and two full gate runs; we expect the bounded re-authoring to end that without letting a machine into the contributor graph; shown wrong if a commit outside the bound is ever re-authored or bumps still need a person
Frontmatter
| id | itd-2609221842494980 |
|---|---|
| type | intent |
| lifecycle | shipped |
| kind | standalone |
| severity | minor |
.abcd/development/intents/shipped/itd-2609221842494980-a-dependency-bump-lands-without-a-person.md
open on GitHub ↗ · commit history ↗
References4
- iss-2609221820487644The attribution gate should let a dependabot dependency bump through without a human re-authoring it. The product thinker asked for this on 2026-09-22 after PR 655 sat blocked with auto-merge armed and every other check green. Two things must be said precisely, because the request names the trailer and the trailer is not what fails. The gate refuses a bot on IDENTITY: check_ident reads dependabot[bot] as a machine in the author role on two independent signals, the forge's [bot] name suffix and the bot mailbox, and it deliberately stays silent about the missing Assisted-by trailer so the remedy is not misread, its own comment saying that adding a trailer is not the fix for a dependency bump and landing it as a human is. No review clears an identity refusal, which is why an armed auto-merge looks like it is waiting for a reviewer when it is waiting for something no reviewer can give. The rule is deliberate and stated in AGENTS.md: the contributor graph is built from the author and committer fields, a machine there asserts an authorship it does not hold, and a squash merge re-appends a mis-identified branch author as a co-author, so the consequence, that a dependabot pull request is not mergeable as authored, is written down as intended. Wanted: a way for a dependency bump to land without a person re-authoring it every time, without letting a machine into the contributor graph on any other change. Candidate shapes for the decision to weigh: the gate exempts a commit whose diff touches only go.mod and go.sum on a branch the forge marks as dependabot's, with the exemption named in the refusal it would otherwise raise; or the repository takes dependabot's bumps through a workflow that re-authors them as the human owner before the gate runs, so nothing about the gate changes; or dependabot is turned off for this repository and bumps are made by hand on a schedule. This reverses a stated rule, so it is an ADR plus a brief invariant before any code moves, not a quiet edit to the script.related
- itd-92abcd tells every repo the truth about its fencebuilds on
- itd-149abcd handles inbound security advisories and issues, and cuts the release, for every managed repo. The 2026-08-27 security-advisory pilot proved the loop by hand across two independent operators: advisory and issue intake, recall-dedup triage against the ledger, record-first fixes in isolated worktrees, one integration branch, an independent adversarial gate over the assembled diff, auto-merge armed only after APPROVE, and a derived release cut through the semantic-receipt gates. This intent automates that loop as abcd capability for any managed repo, with findings F-A through F-W of the pilot note as the acceptance-criteria source and F-U (re-run every required pass against the final content commit; never transfer a verdict) and F-Q (the two release gates are human-by-design) load-bearing.related
- itd-2609150819432059A managed repository that is not a plugin gets the same release gaterelated
Referenced by3
- adr-2609292116133348A dependency bump inside the bound is re-authored as the owner and only pushed by an Apprelated
- itd-2609301020001595A pinned-action bump syncs its scaffold template and lands re-authoredbuilt on by
- spc-2609221843355061a-dependency-bump-lands-without-a-person-re-authoring-it-aimplemented by
mentions4
- dcn-26092900000000072026-09-29 — The product thinker answered twenty-six owed rulings and the published-history question in one interview, asked one at a time by orchestrator abcd-23 of autonomous run A (recorded by lane recRulings for orchestrator abcd-cb). The answers are kept verbatim in the local-tier file `.abcd/.work.local/scratch/reports/rulings-answered-2609-29.md`, dated 2026-09-29, and are restated here because that file is not committed. Published history is left as it is, with no rewrite. The build loop's fidelity audit runs once, on the lane that closes the spec, over the whole delivery (AI). On the vendor denylist the product thinker answered, verbatim: "I think we need an allow list rather than trying to catch a deny list." The interviewer's reading of that answer, recorded as a reading and not as the product thinker's words, is that the per-provider allowlist is the control and the vendor denylist is not extended to chase spellings, with whether the bundled `anthropic/*` entry stays as a backstop left to the technical facilitator (AA(a)). Only a route the person set up on their own machine may use their paid key, and a repository's own route to it is refused, which replaces the route half of itd-2609081951381895 decision 8 (AA(b)). The live site setup, the API adapter and the decision adapter may each close on tests against a simulated service, with the live paid check recorded as owed to a person (iss-2609291925387011, iss-2609291925393913, iss-2609291925398978). itd-111's last criterion is met by an agent's timing check on macOS plus the Linux CI run, so the intent may be finished. Automated dependency updates are switched on, pushed with a personal or app token the person creates and stores as a repository secret (itd-2609221842494980; creating the token is the person's act, and the lane builds everything else and names the secret it expects). itd-6 adds a Go MCP module, proposed for the person's explicit sign-off before it is fetched; closing itd-6 on a fake server was not ruled in this interview. (A later answer the same day, H1b in the local-tier file `.abcd/.work.local/scratch/reports/rulings-answered-2609-29-b.md`, dated 2026-09-29, rules that it is not: itd-6 is finished only after running once against the real RepoPrompt app, a check owed to a person.) For itd-148: the store under the home folder wins (adr-2609091248200336); the store draft itd-2609091014076309 owns add, list and clean-up and itd-148 uses them; a session that declares itself the coordinator is exempt from the write block in the primary checkout and every other session is blocked; and the store draft is planned first, with nothing from the store draft, the merged-worktree clean-up included, built before its planning interview (Q4). itd-148's own wait is not part of that ruling: it follows from Q2, because itd-148 uses the store's verbs, and is carried by the `blocked_by` below. itd-148 and spc-42 are rewritten to match in this change, and itd-148 is now `blocked_by` the store draft. A release retrospective is seeded from a release, the intents a tag shipped (AD); itd-24 and its spec are rewritten to the release in this change. An unpointed route is refused naming the one setting to add, as built in 35100512e, so AC11 of itd-2609170822093401 is complete (BR1). A missed target becomes `next`, whatever the following release is numbered (BS1). Spec pieces keep "step" and the lane stages are renamed, a breaking change to the JSON fields `step`, `performed` and `refusal.step` that resolves iss-2609291313276243 and corrects the glossary entry `core/step.md` (BU1), and the old command spellings are removed in that same breaking release (BT1). The text board shows Later as a count only while the site and `--json` keep the full list (BV1), and an intent in progress appears only under Now (BV2). A pause of zero is allowed (BW1); drain stays in the agents' help list until it runs end to end (BX1); a managed repository must hold the drain eligibility decision in its own record, and drain refuses there until it does (BX2); a capture without a remedy is refused (BX3), which tightens the one-line capture friction `commands/capture.md` promises, so the lane that builds it reconciles that page, the principle wording and every caller that files a capture; a run's pick reason keeps the shared `pursued:` kind with its marker (BZ1); and an intent whose blocker was superseded waits on the successor, transitively (BZ2). The five itd-48 follow-ups are planned as one intent, drafted as itd-2609291923559186 (BT2), and all warn rules share one shrink-only baseline file in which a new warning fails, drafted as itd-2609291924469783 (BT3); both drafts wait on their planning interviews. Each ruling that contradicts a shipped behaviour or another record is amended in the change that builds it, not here. itd-7's planning interview stays owed.
- dcn-26093000000000092026-09-30 — The person answered eighteen rulings of autonomous run A on 2026-09-30 (CF1, CF2, CG1, CI1, CI2, CJ1, CK1, CL1, CM1, DR1, DR2, DR4, DR5, DR6, DQ1a, DQ1b, DQ2, DQ3), relayed by the run's interviewer abcd-23 [b1e81b] and recorded by lane recRulingsDR for orchestrator abcd-8d [5bfdfb]. The answers are kept in the local-tier file `.abcd/.work.local/scratch/reports/rulings-answered-2609-29-b.md`, lines 13 to 30, and are restated here because that file is not committed. SETTLED BLOCKERS: a blocker replaced by an accepted ADR counts as settled, so the waiting intent may start (CF1); a blocker reclassified as a discipline counts as settled too (CF2). Neither is built at this entry's base: the blocked pre-start check still refuses both shapes, and iss-2609300751191426 carries the change. AS BUILT: the App token for the dependency re-authoring workflow is minted in the shell, an openssl-signed JWT exchanged with curl and revoked on exit, with no new action (CG1); when the prompt router cannot evaluate a prompt, its envelope carries the error and leaves the active-domain list out, so the client keeps what it had (CI1); a domain that returns to the active set is re-injected on every host, one that appends to a transcript included, not only on a client that snapshots (CI2); `abcd update` shows progress only when stderr is a terminal, and saved output stays clean (DR4). BUILD: the installer (`hooks/bootstrap.sh`) writes the previous release tag into binary-meta when it swaps a binary, the session hook stays read-only, and that tag replaces the setup_version comparison of the itd-111 update notice (CJ1); the SHELL domain also teaches a repository's own guard entries, generated the same way as the bundled registry's (CK1); `step` in `abcd implement check` is renamed `stage` too, in the same breaking v0.12.0 (CM1); the fix rounds a run spends before it hands a lane back are a per-run setting beside `--pace`, for example `--fix-rounds`, default 3 (DR1); the dependency-bump intent itd-2609221842494980 ships now, with the first live bump recorded as owed until the person has created the App and its secrets (DR2); only a self-contained agent is sent to a paid provider by default, so the cold-reading positions may go while a file-reading agent such as the intent auditor is refused with the reason, and a central override, a machine-level settings list the person keeps that no agent or repository can change, may name providers that take bundled-context requests for file-reading agents (DR5); a run works in parallel, building several pieces and running reviewers at once up to its agent limit, which is new build-loop work that makes the pacing intent's criterion 6 testable (DR6); an undecided fidelity audit reopens the work, sending the feature back to a lane, and never closes like a pass (DQ1a, iss-2608290820473197); the audit moves before the merge, as part of the build loop's last lane (per ruling AI), and until that loop is ready it stays after the merge and reopens on an undecided or failed verdict (DQ1b, iss-2608290822140563); the filing-time duplicate check covers every route, the promoted inbox report, the consistency pass and the reading ingest, in a lane after remedyRequired (DQ2, iss-2609281911024185); `abcd ahoy` offers to install gh on an explicit yes (DQ3, iss-2609281911024838). KEEP: a promoted inbox report's own remedy is kept but not usable: the sender's suggestion stays in the issue's text for reference, the remedy field is `none (filed automatically)`, and a drain skips the record until a person writes the fix, so the conservative default recorded above on 2026-09-30 stands and is not widened (CL1). The person added to CL1 that when a person comes to write the real fix for such an issue, the agent offers a state-of-the-art research pass first (principle `prefer-sota`), which `commands/capture.md` says under the `capture remedy` verb. The three rulings of 2026-09-29 owed to this ledger by earlier sessions of the run, the ceilings of five and of eight sub-agents and the remedies ruling, already have their entries above, so this entry adds none.
- iss-2609292030070275The dependency-bump re-authoring (itd-2609221842494980, spc-2609221843355061) has never run against the live forge, so its first acceptance criterion is proven only offline, against a stand-in App API and a local remote. The person's steps are owed: create a GitHub App with Contents read and write, install it on this repository, store its id and private key as the Dependabot secrets DEPENDENCY_REAUTHOR_APP_ID and DEPENDENCY_REAUTHOR_APP_KEY, and set owner_name and owner_email in .abcd/config/dependency-reauthor.conf. Until then every in-bound bump is refused by name and stays a person's to land. Done when one real dependabot go_modules or pip bump is watched re-authored as the owner, re-checked green by the attribution gate and merged; then the spec closes and the intent ships (Refs: iss-2609221820487644).
- iss-2610241550026188record_schema resolves a cross-reference field's target in any record family (internal/core/lint/schema.go:764 checks only that the handle is in the corpus), so itd-2609221842494980 carries related_adrs: [iss-2609221820487644], an issue, and passes record-lint, although the ADR README documents related_adrs as adr-N only; because the link sits in the wrong field, the promote join between that shipped intent and its still-open originating issue is invisible to intent audit --issue-drift.