Summary
The merge job in .github/workflows/dependabot-auto-merge.yml has two independent defects. The first makes it a no-op; the second means that if the first were fixed naively, it would merge Dependabot PRs whose CI had not passed.
MERGE_POLICY.md adoption step 6 is "Enable Class A auto-merge", and dependency patch/minor is Class A. This job is the mechanism that step depends on, so both defects are load-bearing for that plan.
Defect 1 — update type is read from a field that does not exist
const metadata = await github.request('GET /repos/{owner}/{repo}/pulls/{pull_number}', {
..., mediaType: { previews: ['dorian'] },
});
const updateType = metadata.data?.dependency?.update_type ?? ...;
if (!updateType) { core.info('Could not determine update type...'); continue; }
GET /repos/{owner}/{repo}/pulls/{pull_number} returns no dependency, update_type, or dependency_update_type field, and no media-type preview adds one (REST docs). updateType is therefore always undefined, the guard always fires, and every pull request is skipped before any merge is attempted.
The approve job in the same file gets this right — it uses dependabot/fetch-metadata@v3, which exists precisely because there is no such API field.
Defect 2 — the readiness gate reads commit statuses, which contain no CI
const { data: combined } = await github.rest.repos.getCombinedStatusForRef({...});
if (combined.state !== 'success') { continue; }
Every check named in MERGE_POLICY.md gate 2 — validate, guards, lint-python, lint-frontend, build, test, CodeQL, gitleaks (working tree), dependency-review, PR Governance, Canonical issue and evidence — is a check run. getCombinedStatusForRef returns only commit statuses, which on this repo are just Vercel's two and CodeRabbit's.
Observed live on #1433 today: combined status was success at 20:48 UTC (two Vercel statuses) while build, test, lint-python, lint-frontend and guards were all still queued. A job gated this way would merge with CI unfinished.
Why this was not caught
tests/unit/test_dependabot_automation_workflow.py asserts the merge script contains the substrings "dependabot[bot]", "pulls.merge" and "semver-major". All three are present in the broken script, so the tests pass on a job that cannot merge anything. The assertions pin vocabulary, not behaviour.
Note on current state
vars.DEPENDABOT_AUTO_MERGE_ENABLED is not set to 'true' — on #1433, a Dependabot PR meeting every other condition in the approve job's if, the job was skipped. So neither job has ever executed and both defects are latent rather than active. Flipping that variable without fixing the job would produce either silence (defect 1) or unsafe merges (defect 2). Setting the variable is a repository-settings decision and is deliberately out of scope here.
Acceptance criteria
Summary
The
mergejob in.github/workflows/dependabot-auto-merge.ymlhas two independent defects. The first makes it a no-op; the second means that if the first were fixed naively, it would merge Dependabot PRs whose CI had not passed.MERGE_POLICY.mdadoption step 6 is "Enable Class A auto-merge", and dependency patch/minor is Class A. This job is the mechanism that step depends on, so both defects are load-bearing for that plan.Defect 1 — update type is read from a field that does not exist
GET /repos/{owner}/{repo}/pulls/{pull_number}returns nodependency,update_type, ordependency_update_typefield, and no media-type preview adds one (REST docs).updateTypeis therefore alwaysundefined, the guard always fires, and every pull request is skipped before any merge is attempted.The
approvejob in the same file gets this right — it usesdependabot/fetch-metadata@v3, which exists precisely because there is no such API field.Defect 2 — the readiness gate reads commit statuses, which contain no CI
Every check named in
MERGE_POLICY.mdgate 2 —validate,guards,lint-python,lint-frontend,build,test,CodeQL,gitleaks (working tree),dependency-review,PR Governance,Canonical issue and evidence— is a check run.getCombinedStatusForRefreturns only commit statuses, which on this repo are just Vercel's two and CodeRabbit's.Observed live on #1433 today: combined status was
successat 20:48 UTC (two Vercel statuses) whilebuild,test,lint-python,lint-frontendandguardswere all stillqueued. A job gated this way would merge with CI unfinished.Why this was not caught
tests/unit/test_dependabot_automation_workflow.pyasserts the merge script contains the substrings"dependabot[bot]","pulls.merge"and"semver-major". All three are present in the broken script, so the tests pass on a job that cannot merge anything. The assertions pin vocabulary, not behaviour.Note on current state
vars.DEPENDABOT_AUTO_MERGE_ENABLEDis not set to'true'— on #1433, a Dependabot PR meeting every other condition in theapprovejob'sif, the job was skipped. So neither job has ever executed and both defects are latent rather than active. Flipping that variable without fixing the job would produce either silence (defect 1) or unsafe merges (defect 2). Setting the variable is a repository-settings decision and is deliberately out of scope here.Acceptance criteria
update-type(it does for some indirect bumps, e.g. build(deps-dev): bump js-yaml from 4.3.0 to 4.3.1 #1433).skipped/neutralcount as satisfied per gate 2's conditional list.approve/mergecheck runs are excluded from the readiness scan, so the gate cannot deadlock against itself.checks: readpermission is granted, without which the readiness call 403s.