
Eleven PRs in one afternoon — the day the bot became a teammate
On Wednesday I opened the Portfolio repository and the pull request queue looked like an auction: eleven dependabot PRs stacked up, each with the same polite request — “bump X from A to B”. In projects I maintained in the past, that queue meant a lost afternoon: reading changelogs by hand, running the build, crossing fingers. This time the process was different, and the difference wasn’t luck.
What came in the batch
| Package | From | To |
|---|---|---|
| vercel | 58.9.0 | 59.11.7 |
| vitest | 4.1.10 | 5.0.0 |
| framer-motion | 13.0.0 | 13.2.0 |
| mercadopago | 3.3.0 | 3.6.0 |
| eslint-config-next | 16.3.0 | 16.3.4 |
| @testing-library/user-event | 14.6.3 | 14.6.7 |
| @testing-library/jest-dom | 6.9.1 | 7.0.1 |
| @testing-library/react | 16.3.2 | 16.3.3 |
| @vitejs/plugin-react | 6.0.5 | 6.1.1 |
| netlify-cli | 27.1.1 | 27.5.0 |
| actions/setup-python | v6 | v7 |
Most of the batch is what I call invisible polishing: deploy CLIs, lint configs, testing bindings. None of these ship in the bundle the user downloads. The real risk concentrates in two spots: vitest, which jumped a major version (4 to 5), and framer-motion, which controls the animation of everything that moves on the home page.
The major that didn’t hurt
A test runner major is usually the scariest PR in the queue — it’s the package that decides whether CI stays green. Vitest 4.1.10 to 5.0.0 came in as PR #77 and passed without a single change to the test code. That’s not the dependabot’s merit, it’s the merit of technical debt I never took on: the project uses no experimental runner APIs, no obscure plugins, no exotic configuration. The rule I learned maintaining this repository: the duller your testing dependencies, the cheaper the major.
The framer-motion snapshot false alarm
Framer-motion 13.2.0 (PR #78) came at the end of the queue and became the last merge of the day. And in the same week, a visual regression test run failed with a 6% diff against a 5% budget. First-hour instinct: “the update broke something”.
Except the same test, run again against an identical build with frozen baselines, passed without a single pixel of difference. The 6% diff was animation timing — a frame captured in a different phase of the transition — not a visual regression. Framer-motion is the most alive package on the home page: it animates entrance, hover and scroll, and any test that photographs the page mid-transition is photographing time, not pixels.
The process that holds the batch
The flow that makes this day possible is simple to describe and expensive to build:
- Dependabot opens the PR with a changelog and release link
- CI runs the entire suite on the PR branch — unit and E2E tests
- Green = merge; red = the PR waits and the investigation happens in isolation
- After the batch, an integration commit ties everything into the project’s history
Step 3 is what turns a queue of 11 PRs into routine instead of a gamble. CI is what reads the changelog for me — it doesn’t summarize features, but it answers the only question that matters: does it still work?
| PR type | What decides | What can hurt |
|---|---|---|
| CLI patch/minor | green CI | nothing, in practice |
| Test runner major | the whole suite | broken config, removed API |
| UI/animation lib | CI + VRT | snapshot flake, timing |
The lesson of the day
The counterintuitive part of keeping dependencies up to date isn’t technical — it’s trust. Trust that CI covers what the changelog doesn’t tell you, and the discipline of never merging a PR the CI hasn’t seen. Eleven PRs in a single afternoon isn’t robot productivity: it’s the result of a project where the safe path is also the fast path.
The batch closed with a green suite and an empty queue. Next round, dependabot will open more — and the queue, again, will be routine.