Skip to content

chore(deps): Update dev tooling (non-major) - #184

Merged
looptroop-ai merged 2 commits into
mainfrom
renovate/dev-tooling-(non-major)
Sep 23, 2026
Merged

looptroop-ai merged 2 commits into
mainfrom
renovate/dev-tooling-(non-major)

Conversation

@renovate

@renovate renovate Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
@​codemirror/state ^6.7.1 → ^6.7.5 age confidence
@​codemirror/view ^6.43.9 → ^6.43.12 age confidence
@tanstack/react-query (source) ^5.102.8 → ^5.103.0 age confidence
@types/react (source) ^19.2.18 → ^19.3.0 age confidence
@types/react-dom (source) ^19.2.4 → ^19.3.0 age confidence
@vitejs/plugin-react (source) ^6.1.0 → ^6.1.1 age confidence
eslint-plugin-react-refresh ^0.5.4 → ^0.5.7 age confidence
globals ^17.11.0 → ^17.12.0 age confidence
lucide-react (source) ^1.33.0 → ^1.46.0 age confidence
react (source) ^19.2.8 → ^19.3.0 age confidence
react-dom (source) ^19.2.8 → ^19.3.0 age confidence
react-virtuoso (source) ^4.18.12 → ^4.18.13 age confidence
tailwind-merge (source) ^3.6.0 → ^3.7.0 age confidence
tsx (source) ^4.23.12 → ^4.23.13 age confidence
typescript-eslint (source) ^8.67.0 → ^8.70.0 age confidence
vite (source) ^8.2.2 → ^8.3.0 age confidence

Release Notes

TanStack/query (@​tanstack/react-query)

v5.103.0

Compare Source

Patch Changes
vitejs/vite-plugin-react (@​vitejs/plugin-react)

v6.1.1

Compare Source

Add compiler.logDiagnostics option

Recoverable React Compiler diagnostics are no longer logged by default. Set compiler.logDiagnostics to true to log them through Vite. Fatal diagnostics are always logged and fail the transform.

Respect environment sourcemap option for React Compiler transform when builder.sharedPlugins is enabled (#​1439)

The React Compiler transform was using the top-level sourcemap option instead of the environment sourcemap option. This caused a problem when the experimental builder.sharedPlugins was enabled.

ArnaudBarre/eslint-plugin-react-refresh (eslint-plugin-react-refresh)

v0.5.7

Compare Source

Add allowCompoundComponents option (#​117)

Default: false (true in vite config)

Don't warn when components are exported as an object gathering them. Every member of the object must be a component, and a member holding an anonymous function requires a component name as key.

This should be enabled if the fast refresh implementation correctly handles this case. Vite supports it since @vitejs/plugin-react 4.7.0, @vitejs/plugin-react-swc 3.11.0.

{
  "react-refresh/only-export-components": [
    "error",
    { "allowCompoundComponents": true }
  ]
}

Enabling this option allows code such as the following:

const Root = () => <></>;
const Label = () => <></>;
export const Tag = { Root, Label };

v0.5.6

Compare Source

  • Support re-exporting namespace components (fixes #​116)

v0.5.5

Compare Source

  • Fix SCREAMING_SNAKE_CASE constant exported via export { Name } incorrectly treated as React component #​114 (fixes #​113)
  • Add contentType and size to allowExportNames in Next config #​115
sindresorhus/globals (globals)

v17.12.0

Compare Source


lucide-icons/lucide (lucide-react)

v1.46.0: Version 1.46.0

Compare Source

What's Changed

Full Changelog: lucide-icons/lucide@1.45.0...1.46.0

v1.45.0: Version 1.45.0

Compare Source

What's Changed

New Contributors

Full Changelog: lucide-icons/lucide@1.44.0...1.45.0

v1.44.0: Version 1.44.0

Compare Source

What's Changed

New Contributors

Full Changelog: lucide-icons/lucide@1.43.0...1.44.0

v1.43.0: Version 1.43.0

Compare Source

What's Changed

Full Changelog: lucide-icons/lucide@1.42.0...1.43.0

v1.42.0: Version 1.42.0

Compare Source

What's Changed

New Contributors

Full Changelog: lucide-icons/lucide@1.41.0...1.42.0

v1.41.0: Version 1.41.0

Compare Source

What's Changed

New Contributors

Full Changelog: lucide-icons/lucide@1.40.0...1.41.0

v1.40.0: Version 1.40.0

Compare Source

What's Changed

New Contributors

Full Changelog: lucide-icons/lucide@1.39.0...1.40.0

v1.39.0: Version 1.39.0

Compare Source

What's Changed

Full Changelog: lucide-icons/lucide@1.38.0...1.39.0

v1.38.0: Version 1.38.0

Compare Source

What's Changed

Full Changelog: lucide-icons/lucide@1.36.0...1.38.0

v1.37.0: Version 1.37.0

Compare Source

What's Changed

New Contributors

Full Changelog: lucide-icons/lucide@1.35.0...1.37.0

v1.36.0: Version 1.36.0

Compare Source

What's Changed

New Contributors

Full Changelog: lucide-icons/lucide@1.35.0...1.36.0

What's Changed

New Contributors

Full Changelog: lucide-icons/lucide@1.35.0...1.36.0

v1.35.0: Version 1.35.0

Compare Source

What's Changed
New Contributors

Full Changelog: lucide-icons/lucide@1.34.0...1.35.0

v1.34.0: Version 1.34.0

Compare Source

What's Changed

Full Changelog: lucide-icons/lucide@1.33.0...1.34.0

react/react (react)

v19.3.0

Compare Source

react/react (react-dom)

v19.3.0

Compare Source

petyosi/react-virtuoso (react-virtuoso)

v4.18.13

Compare Source

Patch Changes
  • #​1493 d3c437e Thanks @​albertcalasanzs! - Fix the transcript blanking for a frame when an older page is prepended.

    The compensation for a prepend was a deviation that grows the content followed, one
    requestAnimationFrame later, by the scroll that cancels it. In between there is a painted frame in
    which the list is displaced by the whole page — and because prepends fire near scrollTop 0, that
    displacement is the entire viewport.

    The scroll now runs as soon as the renderer acknowledges, from a layout effect, that the deviation
    has reached the DOM: after the mutation, before paint. Both land in the same paint, and because the
    content has already grown the scroll can no longer be clamped to the old maximum. If nothing
    acknowledges by the next frame the previous deferred behaviour still applies, so the worst case is
    unchanged.

dcastil/tailwind-merge (tailwind-merge)

v3.7.0

Compare Source

privatenumber/tsx (tsx)

v4.23.13

Compare Source

typescript-eslint/typescript-eslint (typescript-eslint)

v8.70.0

Compare Source

🩹 Fixes
  • eslint-plugin: [no-deprecated] report deprecated imported values used in object shorthand properties (#​12780)
❤️ Thank You

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.69.0

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.68.0

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

vitejs/vite (vite)

v8.3.0

Compare Source

Features
  • build: avoid settling seen preload dependencies for performance (#​23446) (e6f6b3e)
Bug Fixes
Performance Improvements

Configuration

📅 Schedule: (in timezone Europe/Bucharest)

  • Branch creation
    • Between 12:00 AM and 05:59 AM (* 0-5 * * *)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

👻 Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate renovate Bot added dependencies Pull requests that update a dependency file frontend Bundled frontend package that ships to users labels Sep 23, 2026
@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: e524be33-8922-4379-8039-c1995882453c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@deepsource-io

deepsource-io Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in 147aaf7...9d2cc83 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
Docker Sep 23, 2026 2:43p.m. Review ↗
JavaScript Sep 23, 2026 2:43p.m. Review ↗
Shell Sep 23, 2026 2:43p.m. Review ↗
Secrets Sep 23, 2026 2:43p.m. Review ↗
CSS Sep 23, 2026 2:43p.m. Review ↗
PowerShell Sep 23, 2026 2:43p.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity · 0 duplication

Metric Results
Complexity 0
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@kilo-code-bot kilo-code-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Status: No Issues Found | Recommendation: Merge

This is an automated Renovate dependency-update PR. Only package.json and package-lock.json were changed — all version bumps are within the same major versions (e.g., React 19.2.x → 19.3.0, Vite 8.2.x → 8.3.0, typescript-eslint 8.67.0 → 8.7.0). Peer dependency constraints are consistent (e.g., react-dom peer react updated from ^19.2.8 to ^19.3.0; @types/react-dom peer @types/react updated from ^19.2.0 to ^19.3.0). Lock file integrity hashes are regenerated correctly. No source code changes — nothing to review at the code level. CI checks from Socket, SonarCloud, and Codacy all pass.

Files Reviewed (2 files)
  • package.json
  • package-lock.json

@kilo-code-bot

kilo-code-bot Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Code Review Summary

This review did not finish. The model reached its output limit before it
could write the review — a reasoning model can spend the whole budget thinking.
Re-run the review, or lower the model's thinking effort, and it should get
further. Any inline comments below are from an earlier review.

Previous Review Summaries (2 snapshots, latest commit 990be1c)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 990be1c)

Status: No Issues Found | Recommendation: Merge

This is an automated Renovate dependency-update PR. All version bumps are within the same major versions (e.g., React 19.2.x → 19.3.0, Vite 8.2.x → 8.3.0, typescript-eslint 8.67.0 → 8.70.0). Peer dependency constraints are consistent (e.g., react-dom peer react updated from ^19.2.8 to ^19.3.0; @types/react-dom peer @types/react updated from ^19.2.0 to ^19.3.0). Lock file integrity hashes are regenerated correctly. The THIRD-PARTY-NOTICES.md file was regenerated to reflect the updated dependency versions. No source code changes — nothing to review at the code level. CI checks from Socket, SonarCloud, and Codacy all pass.

Files Reviewed (3 files)
  • package.json
  • package-lock.json
  • THIRD-PARTY-NOTICES.md

Previous review (commit 909f8eb)

Status: No Issues Found | Recommendation: Merge

This is an automated Renovate dependency-update PR. Only package.json and package-lock.json were changed — all version bumps are within the same major versions (e.g., React 19.2.x → 19.3.0, Vite 8.2.x → 8.3.0, typescript-eslint 8.67.0 → 8.7.0). Peer dependency constraints are consistent (e.g., react-dom peer react updated from ^19.2.8 to ^19.3.0; @types/react-dom peer @types/react updated from ^19.2.0 to ^19.3.0). Lock file integrity hashes are regenerated correctly. No source code changes — nothing to review at the code level. CI checks from Socket, SonarCloud, and Codacy all pass.

Files Reviewed (2 files)
  • package.json
  • package-lock.json

@looptroop-ai

looptroop-ai commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Command Code — findings and recommendations.

1. [Medium] The "bundled frontend" grouping rule is dead — this PR is the proof

.github/renovate.json:81-114 groups react, react-dom, lucide-react, tailwind-merge, react-virtuoso, @codemirror/state, @codemirror/view … as "bundled frontend (ships to users)", and :82 states why: attributing a regression to the package that produced it. But the later rule at :127-138 matches all non-major devDependencies and sets groupName: "dev tooling (non-major)"; later rules win, so it takes them.

Empirical proof in this very PR: the title/group is "dev tooling (non-major)" and it carries react 19.2.8 → 19.3.0 and react-dom → 19.3.0 — code Vite inlines into dist/client and ships to users — while the labels come back dependencies, frontend from the earlier rule. Group and label disagree, and the attribution :82 exists for is lost: a React 19.3 regression would arrive inside a 23-package tooling batch.

Not a safety hole (the batch is automerge: false, notices were regenerated, licenses:check byte-compares). It is a config rule that no longer does what its own description claims. Fix by moving the dev-tooling rule above the frontend rules, or by excluding the frontend names from it (matchPackageNames: ["!react", "!react-dom", …]), then confirm the next PR groups them separately again.

2. BEHIND by exactly one commit — and a phantom downgrade that is not this PR's doing

Base is b9b1be02; main is 0f0f5e60 (#182). A two-dot compare against main shows @testing-library/react: ^16.3.3 -> ^16.3.2, but this PR's actual diff never touches that key — the branch simply predates #182. git merge-tree --write-tree origin/main <head> exits 0 with no conflicts and main's ^16.3.3 survives (the branch never edited those lines), so the required update is conflict-free; just confirm ^16.3.3 after it.

3. All fifteen direct moves are patch or minor; the TypeScript ceiling is respected

Patch: @codemirror/state ^6.7.1→^6.7.5, @codemirror/view ^6.43.9→^6.43.12, @vitejs/plugin-react ^6.1.0→^6.1.1, eslint-plugin-react-refresh ^0.5.4→^0.5.7, react-virtuoso ^4.18.12→^4.18.13, tsx ^4.23.12→^4.23.13. Minor: @types/react ^19.2.18→^19.3.0, @types/react-dom ^19.2.4→^19.3.0, globals ^17.11.0→^17.12.0, lucide-react ^1.33.0→^1.46.0, react/react-dom ^19.2.8→^19.3.0, tailwind-merge ^3.6.0→^3.7.0, typescript-eslint ^8.67.0→^8.70.0, vite ^8.2.2→^8.3.0. typescript is correctly absent — still ^6.0.3, so the <6.1.0 ceiling holds and typescript-eslint@8.70.0's peer >=4.8.4 <6.1.0 is satisfied (verified against the registry, unchanged from 8.67.0).

4. Lockfile integrity and the transitive chain: clean, and every move is forced by a parent

Full base-vs-head comparison: 44 version changes, 1 added entry (@rolldown/binding-android-arm-eabi, a new platform in rolldown 1.2.8), 0 removals, and 0 same-version resolved/integrity rewrites — i.e. no unrelated re-resolution. Each transitive move is compelled: vite 8.3.0 declares postcss ^8.5.28, picomatch ^4.0.7, rolldown ~1.2.6; rolldown 1.2.8 pins @oxc-project/types =0.149.0; react-dom 19.3.0 requires scheduler ^0.28.0.

5. Behavioural risk of the four packages that can actually bite

  • react / react-dom 19.3.0 (ship to users): the release post lists features only — no breaking/deprecated entries. StrictMode now double-invokes Effects during hydration, which is moot for this client-rendered SPA; Transitions render independently; conditional use now warns. react-dom's peer react ^19.3.0 is satisfied because both moved.
  • vite 8.3.0: the 8.3.0 changelog has no breaking-changes section. Its "warn on named imports from JSON modules" does not trigger (both JSON imports in this repo are default imports: src/components/config/__tests__/AboutDialog.test.tsx:4, server/routes/__tests__/health.test.ts:9), and server.watch.usePolling (vite.config.ts:361-362) is still honoured. Peers: vitest 4/5 vite ^6||^7||^8 ✓, @tailwindcss/vite ✓, @vitejs/plugin-react peer range identical in 6.1.0 and 6.1.1 ✓.
  • lucide-react 1.33→1.46 (13 minors): icon additions plus one rename sweep in 1.44.0; any renamed icon the app imports would fail tsc --noEmit, which is green — per-icon renames were not audited one by one.
  • tailwind-merge 3.7.0: a real (fixing) change to shipped class-merge behaviour for arbitrary color()/light-dark() values, plus an additive themeKey. App tests green.

eslint-plugin-react-refresh is 0.x, which :140 deliberately keeps out of automerge because patches can break — correctly inside this non-automerge group.

6. allowScripts ↔ esbuild: the coupling that will break this group next

Untouched here, and correctly so: esbuild does not move (lock still 0.28.2), so the versioned keys esbuild@0.25.12, esbuild@0.28.2, fsevents@2.3.3 still match the lock exactly and tests/installScriptPolicy.test.ts's "policy equals lockfile" assertion holds. Because those keys embed a version, the day a vite bump drags in a new esbuild, this same group goes red until someone hand-edits package.json. Keying the policy by package name (with the version in the disposition file), or at least documenting the coupling on allowScripts' own doc line, would stop that from landing as an unexplained test failure.

7. THIRD-PARTY-NOTICES.md: complete, and this is where the conflicts are

Changed rows are exactly the redistributed packages whose lock versions moved — @codemirror/state 6.7.5, @codemirror/view 6.43.12, lucide-react 1.46.0, react 19.3.0, react-dom 19.3.0, react-virtuoso 4.18.13, scheduler 0.28.0, tailwind-merge 3.7.0 (+5 group lines); tooling packages correctly do not appear. licenses:check regenerates the whole file and byte-compares (ci.yml:144, release.yml:413, prepublishOnly), so a partial regeneration fails rather than passes — and .github/renovate.json notes Renovate cannot do this itself, which is why renovate-notices produced the second commit.

Pairwise git merge-tree across the four open PRs:

pair result
184 × 183 clean
184 × 185 conflict in THIRD-PARTY-NOTICES.md only (adjacent rows: lucide-react line 76 vs js-yaml line 75)
184 × 186 conflict in package.json + package-lock.json (vite line 159 / vitest line 160 are adjacent)

Exactly two conflict pairs exist and both involve this PR, so any order costs two resolutions — there is no free ordering. Whichever way it goes, resolve the notices one by regenerating (npm ci && npm run build && npm run licenses:generate, or let renovate-notices push after the rebase) rather than hand-merging rows, and prefer Renovate's rebase over Update branch, which stops dead on a conflict.

8. minimumReleaseAge: 7 days demonstrably filtered this batch

Tightest accepted age is @codemirror/* at 8 days (published 09-15). Exclusions prove the rule works: typescript-eslint 8.70.1 (published 09-21) and lucide-react 1.47.0 (09-17) were both skipped and will follow in a later PR. All other pins verified untouched: esbuild, @types/node (<25), drizzle rc pair, tailwindcss group, node/npm toolchain, action/Docker digest rules.

9. CI: 100 checks, zero failures

Every non-skipping check passes; the five skipping rows (Sourcery, DeepSource CSS/PowerShell, notices commit, one Windows gate) are non-required by design. BEHIND (point 2) is the only merge-readiness gap — and as on #183, the duplicate push + pull_request runs mean a required job on the second run can re-gate this PR after the first was green.

@renovate
renovate Bot force-pushed the renovate/dev-tooling-(non-major) branch from 990be1c to 86c7723 Compare September 23, 2026 14:38
@sonarqubecloud

Copy link
Copy Markdown

@looptroop-ai
looptroop-ai merged commit d2a8493 into main Sep 23, 2026
103 of 104 checks passed
@looptroop-ai
looptroop-ai deleted the renovate/dev-tooling-(non-major) branch September 23, 2026 15:09
looptroop-ai added a commit that referenced this pull request Sep 23, 2026
* feat(renovate): let the Node floor pull request finish itself

What changed
- .github/renovate.json: the "node floor" rule now automerges, and its PR
  text says nothing needs doing by hand. Its description records why that is
  safe. Top-level gitIgnoredAuthors now names github-actions[bot]'s commit
  email.
- .github/workflows/renovate-node-floor.yml: a daily schedule (07:17 UTC,
  after Renovate's own 00:00-05:59 Bucharest window) plus workflow_dispatch,
  and a new `recheck` job. It finds Renovate's open renovate/node-floor pull
  request (same repository, author app/renovate) and re-runs every run on its
  head that ended failure or timed_out. It checks nothing out, reads no
  secret, and holds only actions: write, contents: read and
  pull-requests: read.
- .github/CONTRIBUTING.md: the floor section describes the automatic flow.
  There is no manual changelog or website step any more. The website's
  Follow LoopTroop main workflow picks up a new floor within a day. A major is
  still moved by hand.
- CHANGELOG.md [Unreleased]: the Changed entry no longer says "a person
  merges it", and a Fixed entry covers the Renovate stall below.

Why
The owner asked for the monthly floor raise to need nobody. Three gaps stood
in the way:
1. A person had to merge the pull request, add a changelog line, and update
   the website afterwards.
2. When a late package feed catches up, nothing on the pull request changes,
   so nothing re-ran the required Verify check. It stayed red until someone
   clicked re-run.
3. Renovate treats any commit by another author as a hand edit. After that it
   stops rebasing the pull request and stops moving it to newer releases, as
   its gitIgnoredAuthors documentation describes. The floor workflow commits
   to every floor pull request, so without the ignore entry each one froze
   after that first commit, and with strict up-to-date checks it could never
   merge itself. Renovate notices pull requests had the same problem (#184
   needed a manual rebase).

Key decisions
- Floor raises get no changelog line, like any other non-major update
  (AGENTS.md). The Unreleased text about 24.18.0 is left as written; it mixes
  the current floor with historical examples, so rewriting it automatically
  would corrupt history.
- recheck re-runs any failed run on the head, not only Verify. A flaky lane
  blocks an automerge just the same, and a genuinely failing check fails
  again, so nothing merges red.
- The committing workflows are derived in the test, as renovate-*.yml files
  that set git's user.email. Each one's email must be in gitIgnoredAuthors,
  so a changed commit identity cannot freeze these pull requests unnoticed.

Tests (tests/workflowPolicy.test.ts)
- Floor workflow jobs are regenerate, push and recheck.
- recheck's trigger, exact permissions, no secret, no checkout, the fork and
  author filter, and the rerun command.
- The writing jobs stay gated to the floor branch.
- gitIgnoredAuthors covers every committing Renovate workflow.
- The floor rule automerges.
Six deliberate breakages (drop the ignore entry, automerge off, run on pull
requests, hand it a secret, drop the fork filter, widen a permission) each
turned one test red.

Checked: renovate-config-validator 44.40.0 passes on .github/renovate.json;
actionlint and shellcheck are clean; the full suite passes (446 files, 6790
tests); lint and typecheck pass.

Side effects: every Renovate pull request the notices workflow commits to is
now rebased by Renovate again, instead of freezing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(ci): mark release.yml's inline JavaScript as meant to be single-quoted

actionlint's shellcheck pass reported SC2016 (expressions don't expand in
single quotes) for the `node -e '...'` block that checks release-assets
against the release manifest. The quotes are intended: the `${...}` inside is
JavaScript template syntax and must reach node unexpanded. Marked with the
same `# shellcheck disable=SC2016` comment the other workflows use for this
case, which leaves actionlint clean across every workflow. No behaviour
change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ci): ask Renovate to rebase the floor pull request once a run is too old to re-run

GitHub re-runs a workflow run only within 30 days of its start (Codex review
on #187). A package feed that stays behind longer than that would have left
the daily recheck failing quietly for good. Each `gh run rerun` was refused,
turned into a warning, and the self-merging floor pull request stayed red with
nothing left to move it.

Now a refused re-run makes the job tick the rebase box in Renovate's own
pull request text (`- [ ] <!-- rebase-check -->`). Renovate then rebuilds the
branch, the floor workflow writes the floor in again, and every check starts a
fresh run with a fresh 30 days.
- A box already ticked is left alone; Renovate acts on it in its next window.
- Text with no box fails the job, so a change in Renovate's format is reported
  instead of silently stalling.
- The body is edited through the REST API (`gh api --method PATCH`) rather
  than `gh pr edit`, which has failed under GITHUB_TOKEN on some gh versions.
- The job's pull-requests permission goes from read to write for that one
  edit. It still checks nothing out and reads no secret.

Tests: a new case runs the job's real script against a stand-in `gh` and
covers every path: no pull request, nothing failed, re-runs allowed,
re-runs refused with an unticked box (only the box changes), with a ticked
box (nothing is edited), and with no box (the job fails). Three deliberate
breakages (the old warn-only loop, a PATCH that replaces the whole body, a
missing box passing silently) each turn it red. The permission assertion
follows. Two non-null assertions in the new author test became `?? ''`
(DeepSource).

CONTRIBUTING and the unreleased CHANGELOG entry describe the fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ci): tick Renovate's rebase box correctly under macOS's bash 3.2

The new recheck test failed on both macOS lanes of #187. The job substituted
the ticked box with a quoted replacement,
`${body/"${unticked}"/"${ticked}"}`. bash 4.3 and later remove those quotes,
but bash 3.2, which macOS ships, keeps them as text. So the PR body came out
as `"- [x] <!-- rebase-check -->"` with the quotes in it, and Renovate would
not have recognised the ticked box.

The job itself runs on ubuntu-latest (bash 5.2), where it worked, but the
same script should mean the same thing on every bash. The replacement is now
unquoted. That is literal in bash 3.2 and 5.2 alike, and it contains no `&`
for bash 5.2's patsub_replacement to expand. A comment on the line says why.

Checked by running the job's real script, with the same stand-in gh as the
test, in the bash:3.2 and bash:5.2 images. Before the fix 3.2 wrote the
quotes; after it, both write exactly the ticked box.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: tidy the recheck tests DeepSource flagged

- The rerun assertion matches the shell text `"${run}"` with a regex instead
  of a plain string holding `${`, which DeepSource reads as a template
  literal written with the wrong quotes.
- The stand-in gh runner fills its defaults by spreading an object, and reads
  its output files through a small helper, which takes `execute` below
  DeepSource's complexity threshold. What it asserts does not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
looptroop-ai added a commit that referenced this pull request Sep 24, 2026
…rom .nvmrc (#189)

* chore(renovate): merge nothing automatically, group less, read Node from .nvmrc

What changed
- No Renovate update merges itself. The patch-level lint/test lane and the
  Node floor pull request used to automerge; `automerge: false` is now stated
  at the top level and every per-rule automerge is gone.
  tests/workflowPolicy.test.ts walks the whole config and fails on any
  `automerge` that is not false.
- `rebaseWhen: behind-base-branch`. `main` requires branches to be up to date,
  and that requirement lives in a ruleset (the branch-protection API answers
  404), so Renovate's `auto` detection could not be relied on. Without
  automerge it would otherwise fall back to rebasing only on conflict.
- Fewer groups. Below a major: "ships to users" (runtime deps + the frontend
  packages Vite bundles), "dev tooling" (now also typescript, @types/node,
  tailwind and the old lint/test lane), "CI and container" (actions + Dockerfile
  digests). esbuild, Drizzle, the OpenCode SDK (now genuinely its own PR; it was
  silently in the runtime group), toolchain, Node floor, lockfile refresh and
  security fixes stay separate. Every major arrives alone, including action
  majors, which the old actions group used to batch. Tailwind + its Vite plugin
  still move together across a major.
- Fixed a latent rule-order bug: the "bundled frontend" group sat above the dev
  tooling rule, so later-wins put react, codemirror etc. into dev tooling
  (visible in #184). The frontend grouping rule now comes after it. Confirmed
  with a local `renovate --platform=local --dry-run=lookup` run.
- prConcurrentLimit 5 -> 10. osvVulnerabilityAlerts on (direct deps only; also
  blocks updates to versions OSV lists as malicious). Security PRs bypass the
  concurrency limit per Renovate docs.
- Toolchain group renamed "toolchain (node + npm)" (it is not the floor).
- Stale description fixed: renovate-notices.yml regenerates
  THIRD-PARTY-NOTICES.md, nothing is committed by hand.

Workflows read the build Node from .nvmrc
- 49 `node-version: <typed pin>` steps across 8 workflows became
  `node-version-file: .nvmrc`, so Renovate's toolchain PR (which moves .nvmrc
  and the Dockerfile) is complete as opened instead of red until every copy is
  edited. The release `npm` job had no checkout; it now checks out `.nvmrc`
  alone (sparse, no credentials) before setup-node.
- tests/workflowPolicy.test.ts now refuses any typed toolchain version, and
  requires every node-version-file step to read `.nvmrc` from a root checkout
  that precedes it. Named exceptions unchanged: the 26.9.0 binary builder, the
  declared-floor lanes (read engines.node at run time), the Node 26
  early-warning lane.
- tests/nodeFloor.test.ts no longer requires CONTRIBUTING to state the pin
  (that copy would have turned every toolchain PR red); it must name `.nvmrc`
  and state no stray version.

Side effects
- The user floor (engines.node) is unaffected.
- Republish workflows check out an old tag, so they now use that release's own
  .nvmrc Node (as its Dockerfile already did). Tags before v0.4.2 have no
  .nvmrc and could no longer be republished; alpha, accepted.
- Group branch names change (renovate/ships-to-users-(non-major) etc.);
  nothing keys on them except renovate/node-floor, which is unchanged.
- CONTRIBUTING documents the review-and-merge flow, and warns against GitHub's
  "Update branch" button: that commit is not Renovate's, and Renovate stops
  maintaining the branch.
- Website docs deliberately not touched (owner's instruction).

Checks: renovate-config-validator --strict (44.13.2), actionlint 1.7.12,
typecheck, lint, full suite (6791 passed; installScriptPolicy needs npm 12 and
passes with it), verify:version. Each new assertion mutation-checked red.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(workflows): put .nvmrc in sparse checkouts; harden Renovate policy tests

Review round 1 on #189 (Gitar, Codex, Greptile, CodeRabbit, and relayed
reviews from Copilot, Antigravity, opencode, Muse Spark, Grok, Claude).

Fixed
- Release blocker: four jobs check out only `scripts` (non-cone sparse) and
  then ask setup-node for `node-version-file: .nvmrc`, which was never on disk:
  release.yml container-manifest and container-notes, container-republish.yml
  manifest and notes. Every release would have failed at the container index
  and notes, and container repairs too. `.nvmrc` is now listed in each sparse
  set. The policy test missed it because it only checked that a root checkout
  came first; it now requires `.nvmrc` in any sparse-checkout list that feeds a
  `node-version-file` step (mutation-checked red).
- Presets could re-enable automerge: `extends` rules are applied before this
  file's, and the top-level `automerge: false` does not override a rule that
  sets it. A last catch-all rule (`matchPackageNames: ["*"], automerge: false`)
  now wins over everything; the test requires it to be last and do nothing
  else, and scans the file with a JSON.parse reviver instead of a recursive
  walker.
- The node-floor rule lost its existence check when the automerge assertion
  went; renaming its groupSlug would have left renovate-node-floor.yml looking
  for a branch that never appears. Restored.
- The rule-order bug this PR fixed had no regression test. A test now requires
  the frontend "ships to users" rule after the dev tooling rule, and the
  frontend label and group rules to list the same packages.
- The setup-node checks moved into two helpers, which also clears DeepSource's
  JS-R1005 complexity findings on the changed test.

Docs corrected
- "Every major arrives alone" was not true: besides Drizzle, Tailwind and the
  toolchain, config:recommended's presets group majors of React/react-dom,
  CodeMirror, Radix, ESLint and the artifact actions (confirmed in the
  44.13.2 preset source). Kept on purpose: those must move together, and
  splitting them would open pull requests that cannot pass. CONTRIBUTING,
  CHANGELOG and the major rule's description now say so.
- Ten open PRs is not a hard cap; security fixes open past it.
- 49 -> 45 replaced lines; the Dockerfile has two FROM lines; the pre-.nvmrc
  boundary is 0.5.0, not 0.4.2 (no such tag).
- OSV is still experimental and a malicious hit holds back every update to
  that dependency, not one version; worded accurately.
- An older Unreleased entry said "the concurrent limit is 5", contradicting
  this release; reworded.

Not changed, with reason
- published-smoke `plan` reads main's `.nvmrc` before switching to the tag:
  before this PR it read main's typed literal, so the Node it gets is the same.
- Website docs: the owner asked for no website changes in this PR.
- Fallback Node for pre-0.5.0 tags: alpha, no backward compatibility.
- CI load from rebasing up to ten PRs: noted, to watch rather than pre-empt.
- Kilo failed on a rate limit; Sourcery and Qodo did not review.

Checks: renovate-config-validator --strict, local Renovate dry run (grouping
unchanged, resolved automerge false throughout), actionlint, typecheck, lint,
full suite 6793 passed, verify:version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(renovate): pair React and Vite majors, pin every lane's automerge, split the Node test

Review round 2 on #189 (Codex, Grok, Muse Spark, Copilot, CodeRabbit,
DeepSource). Round 1's commit claimed to clear DeepSource's complexity
finding; it did not, and that claim was wrong.

Fixed
- React majors: the hosted app runs Renovate 44.111.4, whose monorepo:react
  matches both github.com/facebook/react and github.com/react/react. npm
  publishes react and react-dom from the second and eslint-plugin-react-hooks
  from the first, so a hooks-plugin major (a lint-rule release) would ride in
  the React major pull request. The pinned 44.13.2 validator knows only the
  first URL, so react and react-dom were not reliably paired either. A rule now
  groups react, react-dom, @types/react and @types/react-dom majors as
  "react (major)"; the hooks plugin stays on the preset group alone.
- Vite majors: @vitejs/plugin-react peers vite ^8.0.0 only, and no preset
  pairs the two (different repositories), so a Vite major alone fails npm ci.
  They now share "vite (major)". @tailwindcss/vite stays with Tailwind.
- The CI rule said every action major arrives alone; group:githubArtifactActions
  keeps upload-artifact and download-artifact together. Description corrected.
- Two lanes the "*" catch-all cannot reach now say automerge: false
  themselves. Renovate forces vulnerabilityAlerts onto a security update after
  every packageRule (verified in lib/workers/repository/init/vulnerability),
  and a lockfile refresh has no package name for the catch-all to match
  (packageRules do run after it, per updates/flatten). The test requires both.
- The toolchain -> node-floor rule order is load-bearing: engines.node matches
  the toolchain group too, and only the later floor rule keeps it on
  renovate/node-floor, the branch renovate-node-floor.yml acts on. Now tested.
- DeepSource JS-R1005 (complexity 17) and JS-0067 (module-scope helpers): the
  Node workflow test is split into three tests (typed copies, setup-node steps,
  matrix + Dockerfile), and its two helpers live inside the describe block.
- CHANGELOG: raising the limit reduces the chance a lockfile refresh is crowded
  out; it does not guarantee capacity (CodeRabbit).
- CONTRIBUTING and CHANGELOG list the React and Vite pairs.

Every new assertion was mutation-checked red, one mutation at a time.

Not changed
- Greptile P1, releases before 0.5.0 lack .nvmrc: alpha, no backward
  compatibility, already stated.
- Kilo hit its output limit; Copilot found nothing.

Checks: renovate-config-validator --strict, local Renovate dry run (grouping
unchanged, automerge false throughout), actionlint, typecheck, lint, full
suite 6795 passed, verify:version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file frontend Bundled frontend package that ships to users

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant