Operator direction, 2026-09-04: "please add majors too. we want to move fast. we forget it otherwise, then get security alerts. the NEXT real PR will get pipeline fails, and if this happens (and only then) we create new tickets." Plus the cost anchor he named: a routine js-yaml ^4 → ^5 bump consumed roughly an hour and a large share of a scarce Fable budget on hand-verification and a review cycle — work an automated bump does for free.
The trade is deliberate and it is his to make: spend cheap CI on dev instead of scarce reasoning tokens, and ticket a break only when a real PR trips over it.
The Problem
Dependabot already runs here — but only for security. Five merged Dependabot PRs sit in this repo's history (#18132 2026-09-02, #16669, #16608, #16478, #16476), all titled bump the npm_and_yarn group, which is the security-updates group. Security updates need no config file; they are a repository setting.
Version updates need .github/dependabot.yml, and no repository in the org has one. Checked at 2026-09-04: neo, neo-agent-skills, neo-agent-brain, neo-agent-institution, create-app, workspace, devindex, jsdoc-x, benchmarks, pages — all ten carry a package.json, none carries a Dependabot config.
So dependencies move only when an advisory fires. That is exactly the reported symptom — "we forget it otherwise, then get security alerts" is the mechanism, not a figure of speech: an advisory is currently the only event that moves a dependency.
The Architectural Reality
Three measured facts decide the shape, and two of them are prerequisites rather than nice-to-haves.
dev has zero required status checks.GET /repos/neomjs/neo/rules/branches/dev returns ["code_scanning","copilot_code_review","deletion","non_fast_forward"], and the merge-readiness projection reports requiredSet.contexts: []. GitHub auto-merge waits only for required checks. With none required, enabling auto-merge merges each PR as soon as it is mergeable — before CI reports. "Green CI is enough" would silently become "CI is irrelevant."
No PR gate blocks bots at all. The premise was false — twice corrected.(First revision over-scoped it to four gates; this revision retracts it entirely, on @neo-gpt's review of PR #18322, source-verified.)
pr-baseline.yml does fire on a Dependabot PR — that part held. But it is a caller, and the work happens in the pinned reusable workflow at neo-agent-skills@e409dea5d, which I had never opened. Both of its PR-body steps carry:
A Dependabot PR is authored by dependabot[bot] and labelled dependencies / javascript (per #18132). It matches neither clause, so the body validator never runs on it. There is nothing to exempt.
The callee's own comment states the design, and it also states why a caller-level skip would be actively harmful: "The steps are gated rather than the job, so the check still REPORTS on a human PR: a skipped job cannot serve as a required status context." A caller-level if: marks all five jobs skipped — pr-base, skills-materialized, source-comment-archaeology, substrate-size, pr-body — and a skipped job cannot be bound as a required context. It would therefore have broken prerequisite (1) of this very ticket.
Consequence: prerequisite (2) does not exist. Only the required-checks prerequisite (1) remains, and this ticket is a one-file delivery.
How the error survived a deliberate verification pass: I swept four workflow on: blocks and concluded correctly that pr-baseline fires. I never asked the next question — whether the job inside it applies to a bot. The instrument was pointed at the caller's trigger; the gate lives one level down, in a pinned SHA. A caller firing is not a check running.
A bad bump on dev cannot reach consumers.npm-publish.yml triggers on release: and workflow_dispatch only — never on a push to dev. Publishing sits behind the release cut (buildScripts/release/publish.mjs, the atomic dev → main commit), which is human-driven per AGENTS.md §critical_gates 8. This is the structural reason the operator's risk call is contained: agent work targets dev, main is release-only, and the blast radius of an auto-merged bump ends at dev.
Major updates need no configuration. They are Dependabot's default; you opt out with ignore: update-types: ["version-update:semver-major"]. The requirement is satisfied by not adding that key.
The Fix
Commit a ~12-line .github/dependabot.yml. Build no mechanism around it.
An installer/materializer in neo-agent-skills was the intuitive shape and is declined by precedent. #17798 settled it: the operator rejected copied-bytes-plus-policing-machinery twice (SSOT violation on neomjs/devindex#6; merged-then-reverted neomjs/neo-agent-brain#5), with the ruling "a store whose contents are duplicated N times is not canonical, and the machinery needed to police those duplicates was evidence of the mistake rather than mitigation of it." Its Contract Ledger already names this exact surface: freshness | npm | npm outdated / dependabot | ecosystem-native; no bespoke gate.
A materializer plus a drift check is byte-copying plus a policing guard — the rejected shape, applied to a file of a dozen static lines that changes perhaps once a year. There is no freshness question here worth machinery. Five hand-committed files is the whole job.
github-actions is included because the pinned action versions (actions/checkout@v4, actions/setup-node@v4) are a live supply-chain surface that nothing currently updates.
Operator-owned steps
Two settings are outside agent scope and must land for the policy to mean what it says:
Make unit and componentsrequired status checks on dev — without this, auto-merge ignores CI entirely (Reality 1).
Enable auto-merge on the repository.
Contract Ledger Matrix
Target Surface
Source of Authority
Proposed Behavior
Fallback
Docs
Evidence
.github/dependabot.yml
operator direction 2026-09-04
daily grouped version updates, npm + github-actions, majors included by default
absent ⇒ today's behaviour (security-only)
file comment
no config in any of 10 org repos at 2026-09-04
pr-baseline.yml and its pinned callee
reusable-pr-baseline.yml@e409dea5d :203, :222
unchanged — the callee already scopes body validation to neo-* authors or the ai label, so a bot PR reports green through its existing skip
a caller-level exemption would mark all five jobs skipped, which cannot serve as a required context
callee's own docblock
both steps' if: read at the pinned SHA
dev required checks
GitHub auto-merge semantics
unit + components required
empty required set ⇒ auto-merge merges before CI
ruleset
requiredSet.contexts: []
freshness mechanism
#17798 Contract Ledger
none — ecosystem-native, no installer, no drift check
a materializer would re-run the twice-rejected copied-bytes shape
this ticket
#17798, devindex#6, neo-agent-brain#5
Acceptance Criteria
.github/dependabot.yml exists on dev with npm + github-actions ecosystems, daily, grouped, and noignore entry for version-update:semver-major.
No workflow is modified. The delivery is one file. Verified at the pinned callee that a Dependabot PR already reports green through the existing author/label scoping.
Post-merge receipt on the first real bot PR: grouped version-update PRs appear from the dev config, all five baseline contexts are still emitted (not skipped), and baseline / PR body is green because its agent-only steps skipped — not because anything suppressed the workflow. A missing context is the failure signal here, since it would mean something removed a check.
No materializer, installer, sync workflow, or drift check is added in this ticket or a sibling — #17798 governs.
The two operator-owned settings are recorded here as done or explicitly deferred, with the consequence of deferral stated (auto-merge without required checks ignores CI).
Out of Scope
The installer / materializer — declined by #17798; see The Fix.
Sibling repos.neo-agent-skills, neo-agent-brain, neo-agent-institution, create-app each want the same file, but each has its own gate set to check. One leaf per repo after this one proves the shape; not a fan-out from here.
Renovate or any alternative — Dependabot is already partially live; switching tools is a different question.
Reverting a bad bump. Per operator direction, a break is discovered by the next real PR's CI and ticketed then.
Avoided Traps
Enabling auto-merge before required checks exist. The most expensive possible outcome: it looks like "merge on green" and is actually "merge, ignore CI". Reality 1 is why the ordering in The Fix is not arbitrary.
Adding a mechanism because five repos need the same file. The pull toward an installer is real and #17798 already ruled on it. Five files, once, by hand.
Citing careful manual verification as evidence that manual verification is needed. A reviewer (me) cited the js-yaml bump's hand-verification as an argument for review; the operator corrected it as the cost being avoided. Recorded so the next reader does not re-derive the inverted economics.
Treating dev breakage as a release risk. It is not: npm-publish.yml never fires from dev.
Related
#17798 (skills reach consumers as an npm dependency, never copied bytes — governs the transport question) · #18135, #18205, #17461 (the security-advisory path that currently is the only mover) · #18132 (most recent Dependabot security PR)
Live latest-open sweep: latest 20 open issues at 2026-09-04T17:57Z; no equivalent.
Closed sweep run (mandatory for a "we should start doing X" ticket): surfaced #17798, which changed this ticket's prescription from an installer to no-mechanism, and the five merged Dependabot security PRs that corrected its premise.
A2A in-flight claim sweep: 15 most recent messages across all read-states at 2026-09-04T18:02Z; no claim on this scope.
Memory Core rationale sweep: returned only 2025-era unrelated hits — a known live degradation (@neo-opus-ada reported semantic recall silently serving 2025 results at 17:22Z today). Recorded as a null result, not a clean sweep.
Own-assignment sweep: 12 open assignments, none on this surface.
Decision Record impact:none — no ADR governs dependency-update cadence. #17798's Contract Ledger row on freshness is the binding precedent and this ticket complies with it rather than amending it.
Context
Operator direction, 2026-09-04: "please add majors too. we want to move fast. we forget it otherwise, then get security alerts. the NEXT real PR will get pipeline fails, and if this happens (and only then) we create new tickets." Plus the cost anchor he named: a routine
js-yaml ^4 → ^5bump consumed roughly an hour and a large share of a scarce Fable budget on hand-verification and a review cycle — work an automated bump does for free.The trade is deliberate and it is his to make: spend cheap CI on
devinstead of scarce reasoning tokens, and ticket a break only when a real PR trips over it.The Problem
Dependabot already runs here — but only for security. Five merged Dependabot PRs sit in this repo's history (
#181322026-09-02,#16669,#16608,#16478,#16476), all titledbump the npm_and_yarn group, which is the security-updates group. Security updates need no config file; they are a repository setting.Version updates need
.github/dependabot.yml, and no repository in the org has one. Checked at 2026-09-04:neo,neo-agent-skills,neo-agent-brain,neo-agent-institution,create-app,workspace,devindex,jsdoc-x,benchmarks,pages— all ten carry apackage.json, none carries a Dependabot config.So dependencies move only when an advisory fires. That is exactly the reported symptom — "we forget it otherwise, then get security alerts" is the mechanism, not a figure of speech: an advisory is currently the only event that moves a dependency.
The Architectural Reality
Three measured facts decide the shape, and two of them are prerequisites rather than nice-to-haves.
devhas zero required status checks.GET /repos/neomjs/neo/rules/branches/devreturns["code_scanning","copilot_code_review","deletion","non_fast_forward"], and the merge-readiness projection reportsrequiredSet.contexts: []. GitHub auto-merge waits only for required checks. With none required, enabling auto-merge merges each PR as soon as it is mergeable — before CI reports. "Green CI is enough" would silently become "CI is irrelevant."No PR gate blocks bots at all.The premise was false — twice corrected. (First revision over-scoped it to four gates; this revision retracts it entirely, on @neo-gpt's review of PR #18322, source-verified.)pr-baseline.ymldoes fire on a Dependabot PR — that part held. But it is a caller, and the work happens in the pinned reusable workflow atneo-agent-skills@e409dea5d, which I had never opened. Both of its PR-body steps carry:if: startsWith(github.event.pull_request.user.login, 'neo-') || contains(github.event.pull_request.labels.*.name, 'ai')A Dependabot PR is authored by
dependabot[bot]and labelleddependencies/javascript(per #18132). It matches neither clause, so the body validator never runs on it. There is nothing to exempt.The callee's own comment states the design, and it also states why a caller-level skip would be actively harmful: "The steps are gated rather than the job, so the check still REPORTS on a human PR: a skipped job cannot serve as a required status context." A caller-level
if:marks all five jobs skipped —pr-base,skills-materialized,source-comment-archaeology,substrate-size,pr-body— and a skipped job cannot be bound as a required context. It would therefore have broken prerequisite (1) of this very ticket.Consequence: prerequisite (2) does not exist. Only the required-checks prerequisite (1) remains, and this ticket is a one-file delivery.
How the error survived a deliberate verification pass: I swept four workflow
on:blocks and concluded correctly thatpr-baselinefires. I never asked the next question — whether the job inside it applies to a bot. The instrument was pointed at the caller's trigger; the gate lives one level down, in a pinned SHA. A caller firing is not a check running.A bad bump on
devcannot reach consumers.npm-publish.ymltriggers onrelease:andworkflow_dispatchonly — never on a push todev. Publishing sits behind the release cut (buildScripts/release/publish.mjs, the atomicdev→maincommit), which is human-driven perAGENTS.md §critical_gates8. This is the structural reason the operator's risk call is contained: agent work targetsdev,mainis release-only, and the blast radius of an auto-merged bump ends atdev.Major updates need no configuration. They are Dependabot's default; you opt out with
ignore: update-types: ["version-update:semver-major"]. The requirement is satisfied by not adding that key.The Fix
Commit a ~12-line
.github/dependabot.yml. Build no mechanism around it.An installer/materializer in
neo-agent-skillswas the intuitive shape and is declined by precedent.#17798settled it: the operator rejected copied-bytes-plus-policing-machinery twice (SSOT violationonneomjs/devindex#6; merged-then-revertedneomjs/neo-agent-brain#5), with the ruling "a store whose contents are duplicated N times is not canonical, and the machinery needed to police those duplicates was evidence of the mistake rather than mitigation of it." Its Contract Ledger already names this exact surface:freshness | npm | npm outdated / dependabot | ecosystem-native; no bespoke gate.A materializer plus a drift check is byte-copying plus a policing guard — the rejected shape, applied to a file of a dozen static lines that changes perhaps once a year. There is no freshness question here worth machinery. Five hand-committed files is the whole job.
version: 2 updates: - package-ecosystem: npm directory: "/" schedule: {interval: daily} groups: all-deps: patterns: ["*"] - package-ecosystem: github-actions directory: "/" schedule: {interval: daily} groups: actions: patterns: ["*"]github-actionsis included because the pinned action versions (actions/checkout@v4,actions/setup-node@v4) are a live supply-chain surface that nothing currently updates.Operator-owned steps
Two settings are outside agent scope and must land for the policy to mean what it says:
unitandcomponentsrequired status checks ondev— without this, auto-merge ignores CI entirely (Reality 1).Contract Ledger Matrix
.github/dependabot.ymlpr-baseline.ymland its pinned calleereusable-pr-baseline.yml@e409dea5d:203, :222neo-*authors or theailabel, so a bot PR reports green through its existing skipif:read at the pinned SHAdevrequired checksunit+componentsrequiredrequiredSet.contexts: []#17798Contract Ledger#17798,devindex#6,neo-agent-brain#5Acceptance Criteria
.github/dependabot.ymlexists ondevwith npm + github-actions ecosystems,daily, grouped, and noignoreentry forversion-update:semver-major.devconfig, all five baseline contexts are still emitted (not skipped), andbaseline / PR bodyis green because its agent-only steps skipped — not because anything suppressed the workflow. A missing context is the failure signal here, since it would mean something removed a check.#17798governs.Out of Scope
#17798; see The Fix.neo-agent-skills,neo-agent-brain,neo-agent-institution,create-appeach want the same file, but each has its own gate set to check. One leaf per repo after this one proves the shape; not a fan-out from here.Avoided Traps
#17798already ruled on it. Five files, once, by hand.js-yamlbump's hand-verification as an argument for review; the operator corrected it as the cost being avoided. Recorded so the next reader does not re-derive the inverted economics.devbreakage as a release risk. It is not:npm-publish.ymlnever fires fromdev.Related
#17798(skills reach consumers as an npm dependency, never copied bytes — governs the transport question) ·#18135,#18205,#17461(the security-advisory path that currently is the only mover) ·#18132(most recent Dependabot security PR)Live latest-open sweep: latest 20 open issues at 2026-09-04T17:57Z; no equivalent. Closed sweep run (mandatory for a "we should start doing X" ticket): surfaced
#17798, which changed this ticket's prescription from an installer to no-mechanism, and the five merged Dependabot security PRs that corrected its premise. A2A in-flight claim sweep: 15 most recent messages across all read-states at 2026-09-04T18:02Z; no claim on this scope. Memory Core rationale sweep: returned only 2025-era unrelated hits — a known live degradation (@neo-opus-ada reported semantic recall silently serving 2025 results at 17:22Z today). Recorded as a null result, not a clean sweep. Own-assignment sweep: 12 open assignments, none on this surface.Decision Record impact:
none— no ADR governs dependency-update cadence.#17798's Contract Ledger row on freshness is the binding precedent and this ticket complies with it rather than amending it.