Skip to content

release: dev → main (pump stall false-trip fix, review batches, autopilot cap frames, Node 24)#664

Merged
ng merged 63 commits into
mainfrom
dev
Jul 12, 2026
Merged

release: dev → main (pump stall false-trip fix, review batches, autopilot cap frames, Node 24)#664
ng merged 63 commits into
mainfrom
dev

Conversation

@ng

@ng ng commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Release summary

50 commits from dev. Highlights:

Fixes

Features

Chores

Test plan

  • CI green on dev (lint, typecheck, unit tests, build) — every commit landed through a PR with its own checks.
  • Post-deploy on a pod: run sp-update, verify .git-info shows the new commit; confirm biometrics writing, /debug console clean, and no pump_alerts rows after a session-duration expiry and a scheduled prime.

Merge with a merge commit (not squash) — preserves semver commit messages for the release tooling.

🤖 Generated with Claude Code

🛏️ Beam this PR onto a sleepypod

Pick the snippet that matches your pod. Already-installed pods can't use the curl bootstraps below — sleepypod's egress firewall DROPs github.com, and the script that knows how to unblock WAN is the very file curl is trying to fetch. Use sp-update instead; it's on disk and opens WAN as its first step.

🔄 Already on a sleepypod (most common — review a PR on a running pod):

sudo sp-update dev

🚀 Fresh pod / first install — bootstraps from GitHub, rebuilds every push:

curl -fsSL https://raw.githubusercontent.com/sleepypod/core/dev/scripts/install \
  | sudo bash -s -- --branch dev

🎯 Pin to this exact build (run 29174365542 · a3d885f) — fresh-pod path, locked to one CI artifact for reproducible review:

curl -fsSL https://raw.githubusercontent.com/sleepypod/core/a3d885f6730ad28a417880eff603551253ba1773/scripts/install \
  | sudo bash -s -- \
      --branch dev \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/29174365542/sleepypod-core.zip'

🧊 Artifact: sleepypod-core · self-destructs in 30 days 💥

ng and others added 30 commits June 6, 2026 14:57
The weekly mutation baseline (#591) flagged 220 surviving mutants in
src/streaming/mqttBridge.ts — the largest single contributor. The
existing tests asserted topic suffixes and a few fields but never the
full published payloads, so emptying any string literal or flipping a
guard survived undetected.

Add mutation-coverage suites that pin the exact contents the bridge
emits: the full HA discovery config set (deep-equal over all 19
homeassistant/* topics), per-side publishState payloads, the
connect-option/LWT/clientId wiring, the testConnection TLS matrix, and
the error-path warn messages. No source changes.

Scoped Stryker: 220 -> 32 surviving on this file (61.6% baseline file
score -> 92.18%). The remaining 32 are equivalent mutants (slugify's
own empty-string fallback, JSON.stringify dropping undefined,
safePublish's connected-guard, setTimeout timing values, info-level
console.log strings).
## Why

The weekly mutation baseline (#591) flagged **220 surviving mutants** in
`src/streaming/mqttBridge.ts` — the single largest contributor across
all shards. The existing tests asserted topic *suffixes* and a handful
of fields, but never the *full published payloads*, so emptying any
string literal or flipping a guard survived undetected.

## What

Add mutation-coverage test suites to
`src/streaming/tests/mqttBridge.test.ts` that pin the exact contents the
bridge emits. **No source changes.**

- **HA discovery** — a single deep-equality assertion over the full
19-topic `homeassistant/*` config set (climate L/R, water-level, ambient
temp/humidity, pump rpm/loop/stall/clog ×2, biometrics hr/br/hrv ×2).
Kills the bulk of the StringLiteral/ArrayDeclaration survivors
(`manufacturer`, `model`, `payload_available`, config topics,
`identifiers`, templates, `modes`, temp bounds).
- **publishState** — exact payloads for device-status, water-level,
per-side climate (`isPowered → 'heat'/'off'`), biometrics, pump
rpm/loop_temp scaling, stall/clog.
- **connect options + lifecycle** — clientId prefix, LWT
offline-retained will, `end(false)` on shutdown, already-connected no-op
guard, client-error + subscribe-error warns.
- **testConnection** — TLS `rejectUnauthorized` option matrix.
- **resolveConfig** — DB-read-throw warn message, DB-true `haDiscovery`
source (kills the `?? → &&` operator mutant the existing `false`-valued
test couldn't separate).

Every asserted constant is written independently of the source, so any
literal/operator mutation in `mqttBridge.ts` now fails a test.

## Result

Scoped Stryker run on `mqttBridge.ts`: **220 → 32 surviving** (file
score **61.6% → 92.18%**, +18 kills in the second batch). The remaining
32 are equivalent mutants — masked by `slugify`'s own empty-string
fallback, `JSON.stringify` dropping `undefined`, `safePublish`'s
connected-guard, `setTimeout` timing values, and info-level
`console.log` strings.

## Test plan

- `pnpm exec vitest run src/streaming/tests/mqttBridge.test.ts` → **98
passed**.
- `pnpm exec stryker run --mutate src/streaming/mqttBridge.ts` → 32
survived, 400 killed, 92.18%.
- `eslint src/streaming/tests/mqttBridge.test.ts` → clean.

Refs #591

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Tests**
* Added comprehensive test coverage for MQTT bridge functionality,
including Home Assistant discovery payloads, device state publishing,
connection lifecycle management, error handling, and TLS configuration
scenarios.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update worktree-june-6-stryker
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/worktree-june-6-stryker/scripts/install \
  | sudo bash -s -- --branch worktree-june-6-stryker
```

🎯 **Pin to this exact build** ([run
27075004539](https://github.com/sleepypod/core/actions/runs/27075004539)
· `02da363`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/02da363a31477a8e6cb10101a3831a60fd7ea6a8/scripts/install \
  | sudo bash -s -- \
      --branch worktree-june-6-stryker \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27075004539/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27075004539/artifacts/7458281344)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->
… P2) (#637)

## Summary

Adds **Autopilot** — a reactive WHEN/IF/THEN rules engine that sits
beside the scheduler and responds to live pod signals, plus the full
builder UI from the design bundle. Merged to `dev` now with the nav
entry **hidden** so the half-wired signal catalog isn't user-facing
until P2 lands the biometric/ambient/enum signal sources
(sleepypod-core-69).

### Server
- `automations.*` tRPC router — CRUD, `setEnabled`/`setDryRun`, `runs`
(audit log), `status` (live state), kill-switch get/set, `nights`,
`backtest`. Writes hot-reload the running engine (mirrors `schedules.ts`
→ JobManager).
- Real-history backtest (`src/automation/backtest.ts`) — pure replay
over recorded series (movement, ambient, vitals, water) for a chosen
past night, reusing the engine's own
`WindowStore`/`evaluateCondition`/`evaluateExpr` so the preview matches
real behavior. Edge + policy modes.
- Global kill-switch — persisted `autopilotEnabled` setting (migration
0014, additive `ALTER TABLE`) that short-circuits engine ticks and is
restored at boot.

### Builder
- `builderModel.ts` — bidirectional mapper between the friendly
WHEN/IF/THEN UI and the engine AST ("lower 2°F" →
`setTemperature(current − 2)`; "ambient + 3" → `setTemperature(ambient +
3)`). Round-trip unit-tested.

### UI
- `/autopilot` desktop console (full-bleed, like `/debug`): automations
list as plain-English sentences, two-pane rule editor with live sentence
preview + live backtest, diagnostics panel (per-rule state, run-log,
kill-switch, dry-run).
- Compact Autopilot panel inside the `/debug` console (kept — this is
the dogfooding entry point while nav is hidden).
- **BottomNav entry removed** — `/autopilot` is deep-link-only until P2.

### Safety
Engine is inert with zero rules (fresh DB no-ops each tick). Even an
enabled rule today can only act on the live-wired signals (per-side
temp/level, water.low); biometric/ambient/enum read `undefined`→skip by
design. Every action is gated by manual-override hold, dry-run, and the
kill-switch.

### Deferred to P2 (sleepypod-core-69)
Engine handles numeric signals only, so the builder catalog is the
numeric/backtestable subset. Enum/bool signals (sleep stage, occupancy)
wait on their source wiring.

## Test plan
- `pnpm tsc` clean, `pnpm lint` clean, `pnpm next build` clean.
- Vitest: 1922 pass (+22 new); round-trip builder mapper, backtest
replay, engine tick/safety covered.
- Manual: deploy to pod 192.168.1.88; confirm BottomNav shows no
Autopilot tab; confirm `/debug` Autopilot panel renders live engine
state; deep-link `/autopilot` loads the builder.

Closes sleepypod-core-66 (P0+P1). P2 tracked in sleepypod-core-69.

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update worktree-diy-autopilot
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/worktree-diy-autopilot/scripts/install \
  | sudo bash -s -- --branch worktree-diy-autopilot
```

🎯 **Pin to this exact build** ([run
27108297477](https://github.com/sleepypod/core/actions/runs/27108297477)
· `c48a38d`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/c48a38d28dbffffa14c1db146261e44cf7775675/scripts/install \
  | sudo bash -s -- \
      --branch worktree-diy-autopilot \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27108297477/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27108297477/artifacts/7469107386)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## New Features

* **Autopilot Console**: Introduced a reactive automation engine
allowing users to create, manage, and test automation rules with a
structured WHEN/IF/THEN interface.
* **Rule Backtesting**: Added interactive backtest preview showing how
automation rules would behave against historical sensor data.
* **Automation Monitoring**: Added status panel displaying active rules,
execution history, fires-today counts, and recent run audit logs.
* **Safety Controls**: Implemented global kill-switch, dry-run mode for
testing, cooldown gating, and anti-thrash protections.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
…encies (#638)

This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
|
[@formatjs/intl-localematcher](https://redirect.github.com/formatjs/formatjs)
| [`0.8.9` →
`0.8.10`](https://renovatebot.com/diffs/npm/@formatjs%2fintl-localematcher/0.8.9/0.8.10)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@formatjs%2fintl-localematcher/0.8.10?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@formatjs%2fintl-localematcher/0.8.9/0.8.10?slim=true)
|
| [@tanstack/react-query](https://tanstack.com/query)
([source](https://redirect.github.com/TanStack/query/tree/HEAD/packages/react-query))
| [`5.100.14` →
`5.101.0`](https://renovatebot.com/diffs/npm/@tanstack%2freact-query/5.100.14/5.101.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@tanstack%2freact-query/5.101.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@tanstack%2freact-query/5.100.14/5.101.0?slim=true)
|
|
[@types/react](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react))
| [`19.2.15` →
`19.2.16`](https://renovatebot.com/diffs/npm/@types%2freact/19.2.15/19.2.16)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2freact/19.2.16?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2freact/19.2.15/19.2.16?slim=true)
|
| [@vitest/coverage-v8](https://vitest.dev/guide/coverage)
([source](https://redirect.github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8))
| [`4.1.7` →
`4.1.8`](https://renovatebot.com/diffs/npm/@vitest%2fcoverage-v8/4.1.7/4.1.8)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@vitest%2fcoverage-v8/4.1.8?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@vitest%2fcoverage-v8/4.1.7/4.1.8?slim=true)
|
| [@xyflow/react](https://reactflow.dev)
([source](https://redirect.github.com/xyflow/xyflow/tree/HEAD/packages/react))
| [`12.10.2` →
`12.11.0`](https://renovatebot.com/diffs/npm/@xyflow%2freact/12.10.2/12.11.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@xyflow%2freact/12.11.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@xyflow%2freact/12.10.2/12.11.0?slim=true)
|
|
[eslint-config-next](https://nextjs.org/docs/app/api-reference/config/eslint)
([source](https://redirect.github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next))
| [`16.2.6` →
`16.2.7`](https://renovatebot.com/diffs/npm/eslint-config-next/16.2.6/16.2.7)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/eslint-config-next/16.2.7?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/eslint-config-next/16.2.6/16.2.7?slim=true)
|
| [next](https://nextjs.org)
([source](https://redirect.github.com/vercel/next.js)) | [`16.2.6` →
`16.2.7`](https://renovatebot.com/diffs/npm/next/16.2.6/16.2.7) |
![age](https://developer.mend.io/api/mc/badges/age/npm/next/16.2.7?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/next/16.2.6/16.2.7?slim=true)
|
| [react](https://react.dev/)
([source](https://redirect.github.com/facebook/react/tree/HEAD/packages/react))
| [`19.2.6` →
`19.2.7`](https://renovatebot.com/diffs/npm/react/19.2.6/19.2.7) |
![age](https://developer.mend.io/api/mc/badges/age/npm/react/19.2.7?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/react/19.2.6/19.2.7?slim=true)
|
| [react-dom](https://react.dev/)
([source](https://redirect.github.com/facebook/react/tree/HEAD/packages/react-dom))
| [`19.2.6` →
`19.2.7`](https://renovatebot.com/diffs/npm/react-dom/19.2.6/19.2.7) |
![age](https://developer.mend.io/api/mc/badges/age/npm/react-dom/19.2.7?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/react-dom/19.2.6/19.2.7?slim=true)
|
| [shadcn](https://redirect.github.com/shadcn-ui/ui)
([source](https://redirect.github.com/shadcn-ui/ui/tree/HEAD/packages/shadcn))
| [`4.8.2` →
`4.10.0`](https://renovatebot.com/diffs/npm/shadcn/4.8.2/4.10.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/shadcn/4.10.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/shadcn/4.8.2/4.10.0?slim=true)
|
| [tsx](https://tsx.hirok.io)
([source](https://redirect.github.com/privatenumber/tsx)) | [`4.22.3` →
`4.22.4`](https://renovatebot.com/diffs/npm/tsx/4.22.3/4.22.4) |
![age](https://developer.mend.io/api/mc/badges/age/npm/tsx/4.22.4?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/tsx/4.22.3/4.22.4?slim=true)
|
|
[typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint)
([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint))
| [`8.60.0` →
`8.60.1`](https://renovatebot.com/diffs/npm/typescript-eslint/8.60.0/8.60.1)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/typescript-eslint/8.60.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript-eslint/8.60.0/8.60.1?slim=true)
|
| [vitest](https://vitest.dev)
([source](https://redirect.github.com/vitest-dev/vitest/tree/HEAD/packages/vitest))
| [`4.1.7` →
`4.1.8`](https://renovatebot.com/diffs/npm/vitest/4.1.7/4.1.8) |
![age](https://developer.mend.io/api/mc/badges/age/npm/vitest/4.1.8?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/vitest/4.1.7/4.1.8?slim=true)
|

---

### Release Notes

<details>
<summary>formatjs/formatjs
(@&#8203;formatjs/intl-localematcher)</summary>

###
[`v0.8.10`](https://redirect.github.com/formatjs/formatjs/releases/tag/%40formatjs/intl-localematcher%400.8.10):
@&#8203;formatjs/intl-localematcher: 0.8.10

[Compare
Source](https://redirect.github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.8.9...@formatjs/intl-localematcher@0.8.10)

#### 0.8.10 (2026-06-03)

#### What's Changed

- build: dispatch release workflow for npm publishing by
[@&#8203;longlho](https://redirect.github.com/longlho) in
[#&#8203;6677](https://redirect.github.com/formatjs/formatjs/pull/6677)
- chore(deps): update dependency
[@&#8203;typescript/native-preview](https://redirect.github.com/typescript/native-preview)
to v7.0.0-dev.20260521.1 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6679](https://redirect.github.com/formatjs/formatjs/pull/6679)
- chore(deps): update dependency vite to v8.0.14 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6680](https://redirect.github.com/formatjs/formatjs/pull/6680)
- chore(deps): update dependency ts-jest to v29.4.11 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6682](https://redirect.github.com/formatjs/formatjs/pull/6682)
- chore(deps): update dependency webpack to v5.107.1 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6683](https://redirect.github.com/formatjs/formatjs/pull/6683)
- chore(deps): update pnpm to v11.2.2 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6685](https://redirect.github.com/formatjs/formatjs/pull/6685)
- chore(deps): update rust crate serde\_json to v1.0.150 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6686](https://redirect.github.com/formatjs/formatjs/pull/6686)
- chore(deps): update dependency
[@&#8203;typescript/native-preview](https://redirect.github.com/typescript/native-preview)
to v7.0.0-dev.20260522.1 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6687](https://redirect.github.com/formatjs/formatjs/pull/6687)
- chore: keep gazelle idempotent by
[@&#8203;longlho](https://redirect.github.com/longlho) in
[#&#8203;6689](https://redirect.github.com/formatjs/formatjs/pull/6689)
- chore(deps): update dependency
[@&#8203;typescript/native-preview](https://redirect.github.com/typescript/native-preview)
to v7.0.0-dev.20260523.1 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6690](https://redirect.github.com/formatjs/formatjs/pull/6690)
- chore(deps): update dependency
[@&#8203;typescript/native-preview](https://redirect.github.com/typescript/native-preview)
to v7.0.0-dev.20260524.1 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6691](https://redirect.github.com/formatjs/formatjs/pull/6691)
- chore(deps): update pnpm to v11.3.0 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6692](https://redirect.github.com/formatjs/formatjs/pull/6692)
- chore(deps): update codescythe to 0.6.1 by
[@&#8203;longlho](https://redirect.github.com/longlho) in
[#&#8203;6693](https://redirect.github.com/formatjs/formatjs/pull/6693)
- fix(formatjs\_cli): support id interpolation hash algorithms by
[@&#8203;longlho](https://redirect.github.com/longlho) in
[#&#8203;6695](https://redirect.github.com/formatjs/formatjs/pull/6695)
- chore(deps): update babel monorepo to v7.29.7 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6696](https://redirect.github.com/formatjs/formatjs/pull/6696)
- chore(deps): update dependency
[@&#8203;typescript/native-preview](https://redirect.github.com/typescript/native-preview)
to v7.0.0-dev.20260526.1 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6697](https://redirect.github.com/formatjs/formatjs/pull/6697)
- chore(deps): update dependency oxc-transform to ^0.133.0 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6699](https://redirect.github.com/formatjs/formatjs/pull/6699)
- chore(deps): update dependency webpack to v5.107.2 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6698](https://redirect.github.com/formatjs/formatjs/pull/6698)
- chore(deps): update dependency oxfmt to ^0.52.0 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6702](https://redirect.github.com/formatjs/formatjs/pull/6702)
- chore(deps): update dependency oxlint to v1.67.0 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6703](https://redirect.github.com/formatjs/formatjs/pull/6703)
- chore(deps): update typescript-eslint monorepo to v8.60.0 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6704](https://redirect.github.com/formatjs/formatjs/pull/6704)
- fix(deps): update dependency oxc-parser to ^0.133.0 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6705](https://redirect.github.com/formatjs/formatjs/pull/6705)
- fix(formatjs\_cli): speed up skipped message diagnostics by
[@&#8203;longlho](https://redirect.github.com/longlho) in
[#&#8203;6709](https://redirect.github.com/formatjs/formatjs/pull/6709)
- fix(deps): update rust crate oxc\_data\_structures to 0.133 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6713](https://redirect.github.com/formatjs/formatjs/pull/6713)
- fix(deps): update rust OXC crates to 0.133 by
[@&#8203;longlho](https://redirect.github.com/longlho) in
[#&#8203;6714](https://redirect.github.com/formatjs/formatjs/pull/6714)
- build: verify generated package manifests from bazel deps by
[@&#8203;longlho](https://redirect.github.com/longlho) in
[#&#8203;6701](https://redirect.github.com/formatjs/formatjs/pull/6701)
- build: generate package manifests by
[@&#8203;longlho](https://redirect.github.com/longlho) in
[#&#8203;6718](https://redirect.github.com/formatjs/formatjs/pull/6718)
- chore(deps): update dependency
[@&#8203;rescripts/cli](https://redirect.github.com/rescripts/cli) to
v0.0.16 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6716](https://redirect.github.com/formatjs/formatjs/pull/6716)
- chore(deps): update dependency react-scripts to v5.0.1 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6719](https://redirect.github.com/formatjs/formatjs/pull/6719)
- build: align release-please with generated package manifests by
[@&#8203;longlho](https://redirect.github.com/longlho) in
[#&#8203;6720](https://redirect.github.com/formatjs/formatjs/pull/6720)
- chore(deps): update dependency
[@&#8203;rescripts/rescript-env](https://redirect.github.com/rescripts/rescript-env)
to v0.0.14 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6717](https://redirect.github.com/formatjs/formatjs/pull/6717)
- chore(deps): update dependency
[@&#8203;typescript/native-preview](https://redirect.github.com/typescript/native-preview)
to v7.0.0-dev.20260527.1 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6724](https://redirect.github.com/formatjs/formatjs/pull/6724)
- build: add bazel release-please workspace plugin by
[@&#8203;longlho](https://redirect.github.com/longlho) in
[#&#8203;6723](https://redirect.github.com/formatjs/formatjs/pull/6723)
- chore(deps): update dependency rolldown to v1.0.3 by
[@&#8203;renovate](https://redirect.github.com/renovate)\[bot] in
[#&#8203;6725](https://redirect.github.com/formatjs/formatjs/pull/6725)

**Full Changelog**:
<https://github.com/formatjs/formatjs/compare/@formatjs/intl-localematcher@0.8.9...@&#8203;formatjs/intl-localematcher@0.8.10>

##### Dependencies

- The following workspace dependencies were updated
  - dependencies
-
[@&#8203;formatjs/fast-memoize](https://redirect.github.com/formatjs/fast-memoize)
bumped to 3.1.6

</details>

<details>
<summary>TanStack/query (@&#8203;tanstack/react-query)</summary>

###
[`v5.101.0`](https://redirect.github.com/TanStack/query/blob/HEAD/packages/react-query/CHANGELOG.md#51010)

[Compare
Source](https://redirect.github.com/TanStack/query/compare/@tanstack/react-query@5.100.14...@tanstack/react-query@5.101.0)

##### Patch Changes

- Updated dependencies \[]:
-
[@&#8203;tanstack/query-core](https://redirect.github.com/tanstack/query-core)@&#8203;5.101.0

</details>

<details>
<summary>vitest-dev/vitest (@&#8203;vitest/coverage-v8)</summary>

###
[`v4.1.8`](https://redirect.github.com/vitest-dev/vitest/releases/tag/v4.1.8)

[Compare
Source](https://redirect.github.com/vitest-dev/vitest/compare/v4.1.7...v4.1.8)

#####    🐞 Bug Fixes

- **browser**:
- Disable client `cdp` API when `allowWrite/allowExec: false` \[backport
to v4]  -  by [@&#8203;hi-ogawa](https://redirect.github.com/hi-ogawa)
and **Codex** in
[#&#8203;10450](https://redirect.github.com/vitest-dev/vitest/issues/10450)
[<samp>(e4067)</samp>](https://redirect.github.com/vitest-dev/vitest/commit/e4067b3b1)
- Remove orphaned Playwright route when same module is mocked via
multiple ids \[backport to v4]  -  by
[@&#8203;toxik](https://redirect.github.com/toxik) and
[@&#8203;Zelys-DFKH](https://redirect.github.com/Zelys-DFKH) in
[#&#8203;10474](https://redirect.github.com/vitest-dev/vitest/issues/10474)
[<samp>(675b4)</samp>](https://redirect.github.com/vitest-dev/vitest/commit/675b4343f)

#####     [View changes on
GitHub](https://redirect.github.com/vitest-dev/vitest/compare/v4.1.7...v4.1.8)

</details>

<details>
<summary>xyflow/xyflow (@&#8203;xyflow/react)</summary>

###
[`v12.11.0`](https://redirect.github.com/xyflow/xyflow/blob/HEAD/packages/react/CHANGELOG.md#12110)

[Compare
Source](https://redirect.github.com/xyflow/xyflow/compare/@xyflow/react@12.10.2...@xyflow/react@12.11.0)

##### Minor Changes

- [#&#8203;5677](https://redirect.github.com/xyflow/xyflow/pull/5677)
[`e6661de`](https://redirect.github.com/xyflow/xyflow/commit/e6661de531212f9a209dba17dd63fbbd4ee16f62)
- Add `autoPanOnSelection` to auto-pan when user drags a selection close
to the edge of the viewport.

##### Patch Changes

- [#&#8203;5791](https://redirect.github.com/xyflow/xyflow/pull/5791)
[`732c8eb`](https://redirect.github.com/xyflow/xyflow/commit/732c8eb8d5ff86ab1c057588724221e9b3b8553c)
- Adds a type error when `handleId` is used without `handleType` in
`useNodeConnections`

- [#&#8203;5793](https://redirect.github.com/xyflow/xyflow/pull/5793)
[`c5c853d`](https://redirect.github.com/xyflow/xyflow/commit/c5c853d4a2f537caaea725ab9e7bd480e24b86fb)
- Dev Warnings now use library-specific messaging with the correct
documentation links.

- [#&#8203;5776](https://redirect.github.com/xyflow/xyflow/pull/5776)
[`0441e9f`](https://redirect.github.com/xyflow/xyflow/commit/0441e9f9471380b5ba057fc0a6a8cbdc6ff5ed7b)
- Export `NodeHandle` type

- [#&#8203;5755](https://redirect.github.com/xyflow/xyflow/pull/5755)
[`88737f9`](https://redirect.github.com/xyflow/xyflow/commit/88737f9713f3a6f99c6448e02b6518c7aeedae28)
- Add `@types/react` and `@types/react-dom` as optional peer
dependencies to prevent issues with pnpm strict mode (`hoist: false`)

- [#&#8203;5105](https://redirect.github.com/xyflow/xyflow/pull/5105)
[`076ad38`](https://redirect.github.com/xyflow/xyflow/commit/076ad3893725f654641f7b8c39e7a4e7935eb702)
- Fix type for event passed to onNodeDrag

- [#&#8203;5784](https://redirect.github.com/xyflow/xyflow/pull/5784)
[`7055140`](https://redirect.github.com/xyflow/xyflow/commit/7055140e66e4aebb08ce512bdff34add7e115472)
- Fix node resizing possible beyond absolute extents

- [#&#8203;5769](https://redirect.github.com/xyflow/xyflow/pull/5769)
[`ad4d547`](https://redirect.github.com/xyflow/xyflow/commit/ad4d547724a1c2debf8eb7c6e117aabbfd601934)
- Use `useEffect` for StoreUpdater to restore previous behaviour

- Updated dependencies
\[[`732c8eb`](https://redirect.github.com/xyflow/xyflow/commit/732c8eb8d5ff86ab1c057588724221e9b3b8553c),
[`c5c853d`](https://redirect.github.com/xyflow/xyflow/commit/c5c853d4a2f537caaea725ab9e7bd480e24b86fb),
[`e6661de`](https://redirect.github.com/xyflow/xyflow/commit/e6661de531212f9a209dba17dd63fbbd4ee16f62),
[`737194d`](https://redirect.github.com/xyflow/xyflow/commit/737194d571894dd84ce7cbab02f2a4d0b779d018),
[`40660cd`](https://redirect.github.com/xyflow/xyflow/commit/40660cdb054fb1a110799a3ad7cecbf51371727f),
[`4806e7c`](https://redirect.github.com/xyflow/xyflow/commit/4806e7cde6d69cd7570098ecca86523666b80175),
[`7055140`](https://redirect.github.com/xyflow/xyflow/commit/7055140e66e4aebb08ce512bdff34add7e115472)]:
-
[@&#8203;xyflow/system](https://redirect.github.com/xyflow/system)@&#8203;0.0.77

</details>

<details>
<summary>vercel/next.js (eslint-config-next)</summary>

###
[`v16.2.7`](https://redirect.github.com/vercel/next.js/compare/v16.2.6...411c455dcdec630b9e2e83d24e27b0f9e05927b6)

[Compare
Source](https://redirect.github.com/vercel/next.js/compare/v16.2.6...v16.2.7)

</details>

<details>
<summary>vercel/next.js (next)</summary>

###
[`v16.2.7`](https://redirect.github.com/vercel/next.js/compare/v16.2.6...411c455dcdec630b9e2e83d24e27b0f9e05927b6)

[Compare
Source](https://redirect.github.com/vercel/next.js/compare/v16.2.6...v16.2.7)

</details>

<details>
<summary>facebook/react (react)</summary>

###
[`v19.2.7`](https://redirect.github.com/facebook/react/compare/v19.2.6...6117d7cca4906492c51fe6a03381e35adfd86e7d)

[Compare
Source](https://redirect.github.com/facebook/react/compare/v19.2.6...v19.2.7)

</details>

<details>
<summary>facebook/react (react-dom)</summary>

###
[`v19.2.7`](https://redirect.github.com/facebook/react/compare/v19.2.6...6117d7cca4906492c51fe6a03381e35adfd86e7d)

[Compare
Source](https://redirect.github.com/facebook/react/compare/v19.2.6...v19.2.7)

</details>

<details>
<summary>shadcn-ui/ui (shadcn)</summary>

###
[`v4.10.0`](https://redirect.github.com/shadcn-ui/ui/blob/HEAD/packages/shadcn/CHANGELOG.md#4100)

[Compare
Source](https://redirect.github.com/shadcn-ui/ui/compare/shadcn@4.9.0...shadcn@4.10.0)

##### Minor Changes

- [#&#8203;10842](https://redirect.github.com/shadcn-ui/ui/pull/10842)
[`7c63c467361dee9e20631b2999040912439b35d4`](https://redirect.github.com/shadcn-ui/ui/commit/7c63c467361dee9e20631b2999040912439b35d4)
Thanks [@&#8203;shadcn](https://redirect.github.com/shadcn)! - add
support for GitHub registries

###
[`v4.9.0`](https://redirect.github.com/shadcn-ui/ui/blob/HEAD/packages/shadcn/CHANGELOG.md#490)

[Compare
Source](https://redirect.github.com/shadcn-ui/ui/compare/shadcn@4.8.3...shadcn@4.9.0)

##### Minor Changes

- [#&#8203;10834](https://redirect.github.com/shadcn-ui/ui/pull/10834)
[`8e2d2d1439f54260aa0c51747261c220334ec641`](https://redirect.github.com/shadcn-ui/ui/commit/8e2d2d1439f54260aa0c51747261c220334ec641)
Thanks [@&#8203;shadcn](https://redirect.github.com/shadcn)! - add npx
shadcn eject

###
[`v4.8.3`](https://redirect.github.com/shadcn-ui/ui/blob/HEAD/packages/shadcn/CHANGELOG.md#483)

[Compare
Source](https://redirect.github.com/shadcn-ui/ui/compare/shadcn@4.8.2...shadcn@4.8.3)

##### Patch Changes

- [#&#8203;10659](https://redirect.github.com/shadcn-ui/ui/pull/10659)
[`07900769d91b09def00e68179bcb7a821f59b954`](https://redirect.github.com/shadcn-ui/ui/commit/07900769d91b09def00e68179bcb7a821f59b954)
Thanks [@&#8203;raashish1601](https://redirect.github.com/raashish1601)!
- update template handling

- [#&#8203;10495](https://redirect.github.com/shadcn-ui/ui/pull/10495)
[`360e8a19c3ee13ac78b656027462007c8bdaa6d5`](https://redirect.github.com/shadcn-ui/ui/commit/360e8a19c3ee13ac78b656027462007c8bdaa6d5)
Thanks [@&#8203;artemxknpv](https://redirect.github.com/artemxknpv)! -
Preserve quotes in className literals when applying RTL transforms.

</details>

<details>
<summary>privatenumber/tsx (tsx)</summary>

###
[`v4.22.4`](https://redirect.github.com/privatenumber/tsx/releases/tag/v4.22.4)

[Compare
Source](https://redirect.github.com/privatenumber/tsx/compare/v4.22.3...v4.22.4)

##### Bug Fixes

- resolve CommonJS directory requires inside dependencies
([#&#8203;803](https://redirect.github.com/privatenumber/tsx/issues/803))
([1ce8463](https://redirect.github.com/privatenumber/tsx/commit/1ce846335b7c445a3328c7d27f06424949356d97))

***

This release is also available on:

- [npm package (@&#8203;latest
dist-tag)](https://www.npmjs.com/package/tsx/v/4.22.4)

</details>

<details>
<summary>typescript-eslint/typescript-eslint
(typescript-eslint)</summary>

###
[`v8.60.1`](https://redirect.github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8601-2026-06-01)

[Compare
Source](https://redirect.github.com/typescript-eslint/typescript-eslint/compare/v8.60.0...v8.60.1)

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

See [GitHub
Releases](https://redirect.github.com/typescript-eslint/typescript-eslint/releases/tag/v8.60.1)
for more information.

You can read about our [versioning
strategy](https://typescript-eslint.io/users/versioning) and
[releases](https://typescript-eslint.io/users/releases) on our website.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 6am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **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](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/sleepypod/core).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yMDkuNCIsInVwZGF0ZWRJblZlciI6IjQzLjIwOS40IiwidGFyZ2V0QnJhbmNoIjoiZGV2IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyIsImZpeC1wYXRjaCIsIm5vbi1tYWpvciJdfQ==-->

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update renovate/all-minor-patch
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/renovate/all-minor-patch/scripts/install \
  | sudo bash -s -- --branch renovate/all-minor-patch
```

🎯 **Pin to this exact build** ([run
27120913376](https://github.com/sleepypod/core/actions/runs/27120913376)
· `a46cb7c`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/a46cb7c93262bad79ee16d21d071c56b9b9eead6/scripts/install \
  | sudo bash -s -- \
      --branch renovate/all-minor-patch \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27120913376/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27120913376/artifacts/7473360526)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…+ runaway durations (#639)

## Why

Pod 88 (Pod 5 J55) field debug 2026-06-10: `sleep_records` degenerated —
one overnight presence span fragmented into dozens of <15min sessions
with **66-109 bogus bed-exits**, and durations ran away to
**2736/2850min (45-47h)**. Raw vitals/movement/bed_temp streams were
intact, so this was a detection bug, not data loss.

Root cause in `modules/sleep-detector/main.py` `_update()`: raw
per-sample `capSense` presence drove `_exit_count` and session/interval
transitions directly. At 2 Hz a single noisy dropout (sub-second)
immediately counted a bed-exit and split the session; the constant
flapping back to present kept resetting `_last_present_ts`, so `ts -
_last_present_ts >= ABSENCE_TIMEOUT_S` never fired and sessions never
closed.

## What

- **Debounce / hysteresis** (`PRESENCE_DEBOUNCE_S = 30s`): a
present↔absent flip is only committed after the differing raw state
persists for the dwell window. Brief dropouts are cancelled — they no
longer increment `times_exited_bed` or split the session.
`_apply_debounce()` records the true transition timestamp so interval
edges and the session entry time stay accurate. Dwell `<
ABSENCE_TIMEOUT_S` so a real exit still closes the session.
- **Runaway cap** (`MAX_SESSION_S = 16h`): belt-and-suspenders
force-close so no `sleep_record` can persist a multi-day
`sleep_duration_seconds`.

## Test plan

`modules/sleep-detector/test_main.py` — `TestPresenceDebounce`:
- `test_brief_dropout_does_not_increment_exit_or_split_session` — 50
sub-debounce dropouts across one span → exactly **1 record, 1 exit**.
- `test_sustained_absence_counts_single_exit` — a genuine sustained
absence → 1 exit.
- `test_runaway_session_is_capped` — presence past `MAX_SESSION_S` → no
row exceeds the cap.

```
uv run --with pytest pytest -q test_main.py   # 23 passed
```

## Follow-up (manual, pod 88)

Existing garbage rows (`sleep_records` ~id 300-316) predate this fix and
live in the pod's `biometrics.db`; they need a one-time cleanup over SSH
(not done here to avoid mutating live data unprompted):

```sql
-- inspect first
SELECT id, sleep_duration_seconds/60 AS min, times_exited_bed FROM sleep_records WHERE id BETWEEN 300 AND 316;
-- then delete the fragments/runaways
DELETE FROM sleep_records WHERE sleep_duration_seconds > 16*3600 OR times_exited_bed > 20;
```

Separate minor (not addressed): pod clock is UTC, so nightly dates label
as the next UTC day.

Closes sleepypod-core-71.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Presence debouncing with 30-second dwell time applied to bed occupancy
detection
* Session duration capped at maximum 16 hours with automatic closure of
long-running sessions
  * Session timestamps now aligned to actual state transition times

* **Tests**
* Added comprehensive test coverage for presence debounce behavior and
session duration limits

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update fix/sleep-detector-presence-debounce
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/fix/sleep-detector-presence-debounce/scripts/install \
  | sudo bash -s -- --branch fix/sleep-detector-presence-debounce
```

🎯 **Pin to this exact build** ([run
27320090177](https://github.com/sleepypod/core/actions/runs/27320090177)
· `332570f`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/332570fed0a82a1c1f9172125e7b69c4f1eb536b/scripts/install \
  | sudo bash -s -- \
      --branch fix/sleep-detector-presence-debounce \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27320090177/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27320090177/artifacts/7553491736)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->
## Why

The weekly mutation run ([run
26679315747](https://github.com/sleepypod/core/actions/runs/26679315747))
raises Node.js 20 deprecation annotations on two jobs — `summarize` and
`record-baseline`:

> Node.js 20 actions are deprecated. The following actions are running
on Node.js 20 and may not work as expected: `actions/github-script@v7`.
Actions will be forced to run with Node.js 24 by default starting June
16th, 2026. Node.js 20 will be removed from the runner on September
16th, 2026.

`actions/github-script@v7` is the only action in the repo still pinned
to a Node 20 release; every other action (`checkout@v6`,
`setup-node@v6`, `download-artifact@v8`, `upload-artifact@v7`) is
already on a Node 24 major.

## What

Bump all three `actions/github-script@v7` usages in
`.github/workflows/mutation.yml` to `@v9` (Node 24):

- `Comment on PR` step (PR-labeled runs)
- `Update pinned tracking issue` step (`summarize` job)
- `Compute aggregated row` step (`record-baseline` job)

### Why v9 is safe for these scripts

v9's breaking changes are limited to:
- `require('@actions/github')` no longer works in-script
- `getOctokit` is now an injected parameter (can't be `const`/`let`
redeclared)

None of the three scripts touch either — they only use
`require('fs')`/`require('path')` (Node built-ins) plus the standard
`github.rest.*`, `context`, and `core` globals, all unchanged in v9.

## Test plan

- [x] `git diff` confirms the only change is `v7` → `v9` on the three
`uses:` lines; indentation and YAML structure unchanged.
- [x] Confirmed 3 `@v9` / 0 `@v7` remaining in the workflow.
- [ ] After merge, the next scheduled (or manually dispatched) mutation
run should no longer emit the Node.js 20 deprecation annotation on the
`summarize` and `record-baseline` jobs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update ci/mutation-github-script-node24
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/ci/mutation-github-script-node24/scripts/install \
  | sudo bash -s -- --branch ci/mutation-github-script-node24
```

🎯 **Pin to this exact build** ([run
26691633977](https://github.com/sleepypod/core/actions/runs/26691633977)
· `a15deda`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/a15deda978d696b460ff96539ffe49dc577aabc2/scripts/install \
  | sudo bash -s -- \
      --branch ci/mutation-github-script-node24 \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/26691633977/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/26691633977/artifacts/7310401530)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->
…d assertions (#626)

## Why

`src/streaming/mqttBridge.ts` is the single largest source of surviving
mutants in the weekly mutation run — **220 surviving** ([issue
#591](#591), [run
26679315747](https://github.com/sleepypod/core/actions/runs/26679315747)),
roughly 8.5% of the repo's 2580 survivors. The existing discovery test
only asserts that *some* `homeassistant/...` topic is published and pins
a couple of fields; it never checks the config payload bodies. As a
result every `StringLiteral` / `ObjectLiteral` / `ArrayDeclaration` /
`ConditionalExpression` / `EqualityOperator` mutant inside the HA
discovery builders (`haDevice`, `climate`, `sensor`, and the
binary-sensor literals) and their call sites survives.

## What

Add a `mqttBridge — HA discovery payload content` describe block that
drives the bridge with a fixed `MQTT_DEVICE_ID` + topic prefix (so every
payload is deterministic), captures all published `homeassistant/...`
config messages, and `toEqual`-asserts the **complete** payload for each
entity:

- left/right `climate`
- `water_level`, `ambient_temperature`, `ambient_humidity` sensors
- per-side `pump_*_rpm` / `pump_*_loop_temp` sensors
- per-side `pump_*_stall` / `pump_*_clog` binary sensors
- per-side `heart_rate` / `breathing_rate` / `hrv` biometric sensors
- the shared `device` identity block on every config

A full `toEqual` on each payload fails when any string, template, unit,
device-class, mode list, or the `side === 'left'` label conditional is
mutated — which is exactly what kills the surviving mutants.

Scope is deliberately this one file (the biggest cluster) for a focused
PR; the remaining survivors across other files are left for follow-ups.

## Test plan

- [x] `npx vitest run src/streaming/tests/mqttBridge.test.ts` → **87
passed** (was 76; +11 new).
- [x] Empirically verified the assertions kill mutants: mutating
`payload_available: 'online'` → `''` in the `climate` builder fails
exactly the two climate payload tests; source restored after.
- [x] `npx eslint src/streaming/tests/mqttBridge.test.ts` clean.
- [x] `npx tsc --noEmit` clean (exit 0, 0 errors).
- [ ] Confirm mutation-score lift on the `streaming` shard on the next
labeled / scheduled mutation run.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update test/mutation-mqtt-discovery
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/test/mutation-mqtt-discovery/scripts/install \
  | sudo bash -s -- --branch test/mutation-mqtt-discovery
```

🎯 **Pin to this exact build** ([run
26691824606](https://github.com/sleepypod/core/actions/runs/26691824606)
· `ba39c3d`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/ba39c3d5ee088484bc93d025db9ab6b5726d48fd/scripts/install \
  | sudo bash -s -- \
      --branch test/mutation-mqtt-discovery \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/26691824606/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/26691824606/artifacts/7310460917)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->
…#636)

## Why

Field report (and reproduced live on a pod): a side **"gets set to 83
when it's supposed to be off."**

Root cause: the hardware has **no true off state**. Powering a side down
parks it at heat **level 0** (neutral). `responseParser` synthesizes the
temperature straight from the level via `levelToFahrenheit(0)` =
`Math.round(82.5)` = **83**. Because `current/targetTemperature` were
derived from the level rather than a real sensor, every consumer of
`/device/status` — TempScreen, HomeKit, MQTT, automations — saw a target
of **83°F** on a side the firmware reports as off (`targetLevel: 0`).

Verified live against the pod at `.88` before the fix:
```
$ curl http://192.168.1.88:3000/api/device/status
left:  targetLevel: 0  → targetTemperature: 83   ❌
right: targetLevel: 0  → targetTemperature: 83   ❌
```

## What

Fix at the **source** so the phantom can't reach any consumer:
`parseDeviceStatus` now reports `null` for a level-0 side instead of
`levelToFahrenheit(0)`. Level 0 already means "off" everywhere else in
the codebase (`targetLevel !== 0` = powered), so this just makes the
temperature honest about it.

`SideStatus.current/targetTemperature` become `number | null`; consumers
updated to handle null:

- **`responseParser.ts`** — `tempForLevel(level)` → `null` when `level
=== 0` (both sides, current + target)
- **`device.getStatus`** — output schema fields nullable; `convertTemp`
passes `null` through
- **HomeKit** (`thermostat.ts`, `sideController.ts`) — fall back to
neutral, since HomeKit characteristics require a number
- **`automation/signals.ts`** — an off side leaves the temp signal
**absent**, so rules don't fire against a phantom neutral
- **`SideSelector`** — prop widened (the UI was already null-safe via
`?? 80`, and gates display on `targetLevel !== 0`)

Also folded in (same bug surface, found via review/verification):
- **`health.thermal`** — reports `null` for an off side rather than
passing through the stored 83
- **`ThermalTrendChart`** — guards an all-null `temps` window (now
reachable for an off side) so `Math.min(...[])` can't hand the Y-axis an
`Infinity` domain
- **`health.ts`** — corrected a misleading `MIN_FLOW_RPM` comment (it's
a conservative dead-pump floor, independent of the configurable
`pump_stall_rpm_threshold`, default 500)

## Test plan

- `npx tsc --noEmit` clean; full affected suites green (parser, device,
homekit, mqtt, automation, streaming, diagnostics, health).
- New regressions: `responseParser` asserts **null** at level 0 (was
`83`); `device.getStatus` asserts an off side passes `null` end-to-end;
`health.thermal` and `ThermalTrendChart` guard tests.
- **Manual (post-deploy on `.88`):** `curl
http://192.168.1.88:3000/api/device/status` shows `targetTemperature:
null` for the off sides, with `targetLevel: 0` unchanged.
TempScreen/HomeKit show the side as **off** rather than 83°F.

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update feat/thermal-debug-view
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/feat/thermal-debug-view/scripts/install \
  | sudo bash -s -- --branch feat/thermal-debug-view
```

🎯 **Pin to this exact build** ([run
27321593892](https://github.com/sleepypod/core/actions/runs/27321593892)
· `847bbf2`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/847bbf29d265e8dc91d516a0f218131af5f3d63e/scripts/install \
  | sudo bash -s -- \
      --branch feat/thermal-debug-view \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27321593892/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27321593892/artifacts/7554027923)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added thermal trend chart component for visualizing temperature trends
over time
* Added thermal diagnostics endpoint providing comprehensive system
status including pump performance and temperature readings

* **Bug Fixes**
* Fixed temperature reporting for inactive states to correctly return
null instead of phantom readings

* **Tests**
* Added test coverage for thermal trending and diagnostics functionality
with edge cases

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
… assertions (#641)

## Why

Issue #591 (weekly mutation baseline): `src/db/schema.ts` is the top
surviving file at **208 surviving mutants**. The existing
`migrations.test.ts` runs *pre-generated SQL* under
`src/db/migrations/`, so it never exercises the drizzle schema objects —
mutating a column name to `""`, flipping a `.default(false)` to `true`,
or emptying an index array (`}, t => []`) leaves the static SQL
untouched and nothing fails.

## What

Add `src/db/tests/schema.test.ts` that reads the schema objects directly
via `getTableConfig` and pins, per table:

- table name,
- the full ordered column list with `notNull` + a default descriptor
(literal value / `sql` expression / `$defaultFn` / none),
- every index (name, unique flag, columns),
- plus the exact set of exported tables.

One `toEqual` per table kills the StringLiteral
(table/column/default/index names), BooleanLiteral (default flips), and
ArrayDeclaration (`→ []`) mutators together. No source changes — the
schema is correct as-is. Mirrors the test-only approach of #626/#635.

## Test plan

- [x] `npx vitest run src/db/tests/schema.test.ts` → 12/12 pass.
- [x] Applied representative mutations (string default → `""`,
`.default(false)` → `true`, index array → `[]`) and confirmed the test
**fails** under each, then reverted — mutants genuinely killed, not
merely covered.
- [x] Pre-existing `retention.test.ts` failures confirmed unrelated
(fail on clean tree via stash).

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update test/db-schema-mutants
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/test/db-schema-mutants/scripts/install \
  | sudo bash -s -- --branch test/db-schema-mutants
```

🎯 **Pin to this exact build** ([run
27480566648](https://github.com/sleepypod/core/actions/runs/27480566648)
· `d96aa1d`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/d96aa1dbbe021526ab64d3ceecbbe76dfce3418d/scripts/install \
  | sudo bash -s -- \
      --branch test/db-schema-mutants \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27480566648/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27480566648/artifacts/7614941911)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->
## Why

In the Autopilot rule editor, the dry-run notice was tucked at the
bottom of the left-hand form column, below the THEN card — easy to miss,
and far from the preview/backtest the user is actually reading while in
dry-run.

Per the Autopilot.html design handoff, the notice should sit above the
right column's cards so it caps the live preview and reads as context
for "here's what this rule *would* do."

## What

Move the `rule.mode === 'dryrun'` notice from the bottom of the left
form column to the top of the right column, above SentencePreview and
the BacktestPanel card. No styling or logic change — same condition,
same markup, new position.

## Test plan

- `tsc` clean
- `eslint src/components/Autopilot/RuleEditor.tsx` clean
- Manual: open a rule editor, toggle Dry-run — notice now appears at the
top of the right pane above the "Reads as" card; toggle to Active —
notice disappears.

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update feat/autopilot-design
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/feat/autopilot-design/scripts/install \
  | sudo bash -s -- --branch feat/autopilot-design
```

🎯 **Pin to this exact build** ([run
27516922675](https://github.com/sleepypod/core/actions/runs/27516922675)
· `fcf0a90`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/fcf0a906b5e54285c4c594de6d29de08770316b5/scripts/install \
  | sudo bash -s -- \
      --branch feat/autopilot-design \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27516922675/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27516922675/artifacts/7626634849)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Style**
  * Code formatting and layout adjustments with no functional changes.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Why

The Automations right pane shows the capacitive presence matrix
(bed-pressure zones) only as a **live** view — the raw ~2 Hz `capSense2`
frames are never persisted, so the spatial zone replay and `cap.*`
backtest can't reach past nights. This is the foundation for lifting the
night/date selector to pane scope and adding a standalone "Last Night"
historical view (follow-up PRs).

## What

Add a downsampling writer that aggregates the live capacitive stream
into **one row per side per ~5s window** in a new `cap_sense_frames`
table, pruned to **~48h** (the bulkiest sensor stream — only the last
night or two is ever replayed).

- New `cap_sense_frames` table (`zones` head/torso/legs means, scalar
`max/mean/spread`, modal `peakZone`, `frameCount`).
- `streaming/capFramePersistence.ts`: ts-keyed windowing (correct under
stream catch-up), best-effort writes (a DB failure never disrupts the
live stream), throttled 48h prune.
- Wired into the `piezoStream` broadcast loop alongside the existing
live snapshot; windows reset on RAW-file switch.
- Extracted `reduceCap` + new `zoneTriple` into dependency-free
`automation/capReduce.ts` to avoid a `piezoStream ↔ signals.biometrics`
import cycle.

Scalar (Pod 3) sensors persist `zones: null` — no spatial resolution to
replay, but `cap.*` scalars still backtest.

## Scope / non-goals

This PR only **writes** the frames. Reading them into the backtest
series and the UI (pane-level night picker, standalone history view) are
follow-up PRs.

## Test plan

- `vitest run src/automation/tests/capReduce.test.ts
src/streaming/tests/capFramePersistence.test.ts` — new unit coverage for
`zoneTriple` and the window state machine (accumulate within window,
rollover past the 5s boundary, scalar→null zones, per-side independence,
reset).
- `vitest run src/automation/tests/signals.biometrics.test.ts
src/streaming/tests/piezoStream.test.ts src/lib/tests/occupancy.test.ts`
— existing suites green after the `reduceCap` extraction.
- `tsc` clean; `eslint` clean on changed files.
- `pnpm db:biometrics:generate` → migration `0010_fixed_silvermane.sql`.

Manual: on a pod, confirm `cap_sense_frames` accrues ~1 row/side/5s
while occupied and that rows older than 48h are pruned.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added historical storage and analysis of capacitive presence sensor
readings with spatial zone tracking
  * Automatic data retention and cleanup for storage optimization

* **Refactor**
  * Reorganized internal sensor data processing utilities

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update feat/persist-cap-frames
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/feat/persist-cap-frames/scripts/install \
  | sudo bash -s -- --branch feat/persist-cap-frames
```

🎯 **Pin to this exact build** ([run
27516162063](https://github.com/sleepypod/core/actions/runs/27516162063)
· `34b060c`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/34b060c475e873eebcd6765f33607daae66029ae/scripts/install \
  | sudo bash -s -- \
      --branch feat/persist-cap-frames \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27516162063/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27516162063/artifacts/7626417573)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
|
[@types/node](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node))
| [`25.9.1` →
`25.9.3`](https://renovatebot.com/diffs/npm/@types%2fnode/25.9.1/25.9.3)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2fnode/25.9.3?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2fnode/25.9.1/25.9.3?slim=true)
|
|
[@types/react](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react))
| [`19.2.16` →
`19.2.17`](https://renovatebot.com/diffs/npm/@types%2freact/19.2.16/19.2.17)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2freact/19.2.17?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2freact/19.2.16/19.2.17?slim=true)
|
| [bonjour-service](https://redirect.github.com/onlxltd/bonjour-service)
| [`1.4.0` →
`1.4.1`](https://renovatebot.com/diffs/npm/bonjour-service/1.4.0/1.4.1)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/bonjour-service/1.4.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/bonjour-service/1.4.0/1.4.1?slim=true)
|
|
[eslint-config-next](https://nextjs.org/docs/app/api-reference/config/eslint)
([source](https://redirect.github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next))
| [`16.2.7` →
`16.2.9`](https://renovatebot.com/diffs/npm/eslint-config-next/16.2.7/16.2.9)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/eslint-config-next/16.2.9?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/eslint-config-next/16.2.7/16.2.9?slim=true)
|
| [next](https://nextjs.org)
([source](https://redirect.github.com/vercel/next.js)) | [`16.2.7` →
`16.2.9`](https://renovatebot.com/diffs/npm/next/16.2.7/16.2.9) |
![age](https://developer.mend.io/api/mc/badges/age/npm/next/16.2.9?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/next/16.2.7/16.2.9?slim=true)
|
| [pnpm](https://pnpm.io)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm)) |
[`10.34.1` →
`10.34.3`](https://renovatebot.com/diffs/npm/pnpm/10.34.1/10.34.3) |
![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/10.34.3?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/10.34.1/10.34.3?slim=true)
|
|
[semantic-release](https://redirect.github.com/semantic-release/semantic-release)
| [`25.0.3` →
`25.0.5`](https://renovatebot.com/diffs/npm/semantic-release/25.0.3/25.0.5)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/semantic-release/25.0.5?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/semantic-release/25.0.3/25.0.5?slim=true)
|
| [shadcn](https://redirect.github.com/shadcn-ui/ui)
([source](https://redirect.github.com/shadcn-ui/ui/tree/HEAD/packages/shadcn))
| [`4.10.0` →
`4.11.0`](https://renovatebot.com/diffs/npm/shadcn/4.10.0/4.11.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/shadcn/4.11.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/shadcn/4.10.0/4.11.0?slim=true)
|
|
[typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint)
([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint))
| [`8.60.1` →
`8.61.0`](https://renovatebot.com/diffs/npm/typescript-eslint/8.60.1/8.61.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/typescript-eslint/8.61.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript-eslint/8.60.1/8.61.0?slim=true)
|

---

### Release Notes

<details>
<summary>onlxltd/bonjour-service (bonjour-service)</summary>

###
[`v1.4.1`](https://redirect.github.com/onlxltd/bonjour-service/releases/tag/1.4.1)

[Compare
Source](https://redirect.github.com/onlxltd/bonjour-service/compare/1.4.0...1.4.1)

#### What's Changed

- Fix for imports by
[@&#8203;mdidon](https://redirect.github.com/mdidon) in
[#&#8203;80](https://redirect.github.com/onlxltd/bonjour-service/pull/80)
- Addressed
[#&#8203;79](https://redirect.github.com/onlxltd/bonjour-service/issues/79)
raised by [@&#8203;andersk](https://redirect.github.com/andersk)

**Full Changelog**:
<onlxltd/bonjour-service@1.4.0...1.4.1>

</details>

<details>
<summary>vercel/next.js (eslint-config-next)</summary>

###
[`v16.2.9`](https://redirect.github.com/vercel/next.js/compare/v16.2.8...v16.2.9)

[Compare
Source](https://redirect.github.com/vercel/next.js/compare/v16.2.8...v16.2.9)

###
[`v16.2.8`](https://redirect.github.com/vercel/next.js/compare/v16.2.7...v16.2.8)

[Compare
Source](https://redirect.github.com/vercel/next.js/compare/v16.2.7...v16.2.8)

</details>

<details>
<summary>vercel/next.js (next)</summary>

###
[`v16.2.9`](https://redirect.github.com/vercel/next.js/compare/v16.2.8...v16.2.9)

[Compare
Source](https://redirect.github.com/vercel/next.js/compare/v16.2.8...v16.2.9)

###
[`v16.2.8`](https://redirect.github.com/vercel/next.js/compare/v16.2.7...v16.2.8)

[Compare
Source](https://redirect.github.com/vercel/next.js/compare/v16.2.7...v16.2.8)

</details>

<details>
<summary>pnpm/pnpm (pnpm)</summary>

###
[`v10.34.3`](https://redirect.github.com/pnpm/pnpm/compare/v10.34.2...v10.34.3)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v10.34.2...v10.34.3)

###
[`v10.34.2`](https://redirect.github.com/pnpm/pnpm/compare/v10.34.1...v10.34.2)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v10.34.1...v10.34.2)

</details>

<details>
<summary>semantic-release/semantic-release (semantic-release)</summary>

###
[`v25.0.5`](https://redirect.github.com/semantic-release/semantic-release/releases/tag/v25.0.5)

[Compare
Source](https://redirect.github.com/semantic-release/semantic-release/compare/v25.0.4...v25.0.5)

##### Bug Fixes

- **revert:** next
([#&#8203;4200](https://redirect.github.com/semantic-release/semantic-release/issues/4200))
([db8ffaa](https://redirect.github.com/semantic-release/semantic-release/commit/db8ffaad90139532f30c0fcd955cf52ffdc1a267))

###
[`v25.0.4`](https://redirect.github.com/semantic-release/semantic-release/releases/tag/v25.0.4)

[Compare
Source](https://redirect.github.com/semantic-release/semantic-release/compare/v25.0.3...v25.0.4)

##### Bug Fixes

- **code-quality:** add missing comma in context object for consistency
([493d6cd](https://redirect.github.com/semantic-release/semantic-release/commit/493d6cdaa1ed697427acea596d0d25eb53b462a2))

</details>

<details>
<summary>shadcn-ui/ui (shadcn)</summary>

###
[`v4.11.0`](https://redirect.github.com/shadcn-ui/ui/blob/HEAD/packages/shadcn/CHANGELOG.md#4110)

[Compare
Source](https://redirect.github.com/shadcn-ui/ui/compare/shadcn@4.10.0...shadcn@4.11.0)

##### Minor Changes

- [#&#8203;10886](https://redirect.github.com/shadcn-ui/ui/pull/10886)
[`05eb2b968bdc769ad78df9628dc2260e1dec903c`](https://redirect.github.com/shadcn-ui/ui/commit/05eb2b968bdc769ad78df9628dc2260e1dec903c)
Thanks [@&#8203;shadcn](https://redirect.github.com/shadcn)! - improve
search command

##### Patch Changes

- [#&#8203;10851](https://redirect.github.com/shadcn-ui/ui/pull/10851)
[`7dfd933102fdb881f8abd24fc1ef11a669682b94`](https://redirect.github.com/shadcn-ui/ui/commit/7dfd933102fdb881f8abd24fc1ef11a669682b94)
Thanks
[@&#8203;harshithasompura](https://redirect.github.com/harshithasompura)!
- move msw to devDependencies

</details>

<details>
<summary>typescript-eslint/typescript-eslint
(typescript-eslint)</summary>

###
[`v8.61.0`](https://redirect.github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8610-2026-06-08)

[Compare
Source](https://redirect.github.com/typescript-eslint/typescript-eslint/compare/v8.60.1...v8.61.0)

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

See [GitHub
Releases](https://redirect.github.com/typescript-eslint/typescript-eslint/releases/tag/v8.61.0)
for more information.

You can read about our [versioning
strategy](https://typescript-eslint.io/users/versioning) and
[releases](https://typescript-eslint.io/users/releases) on our website.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 6am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **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](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/sleepypod/core).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yMTkuMCIsInVwZGF0ZWRJblZlciI6IjQzLjIxOS4wIiwidGFyZ2V0QnJhbmNoIjoiZGV2IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyIsImZpeC1wYXRjaCIsIm5vbi1tYWpvciJdfQ==-->

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update renovate/all-minor-patch
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/renovate/all-minor-patch/scripts/install \
  | sudo bash -s -- --branch renovate/all-minor-patch
```

🎯 **Pin to this exact build** ([run
27521087530](https://github.com/sleepypod/core/actions/runs/27521087530)
· `46384d7`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/46384d797a73a6dd7c27bdfb2e75b1ce6f1ff79a/scripts/install \
  | sudo bash -s -- \
      --branch renovate/all-minor-patch \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27521087530/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27521087530/artifacts/7628085280)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…642)

## Why

Two UX problems in the Autopilot/Automations builder:

1. The edge-triggered **backtest chart** became unreadable at high event
density (e.g. 7 fires + 70 suppressed). Every fired and suppressed
sample drew a full-height vertical line across the plot, hatching a
"curtain" that buried the actual traces.
2. The builder's **number inputs** were +/- steppers only — you couldn't
click in and type a value. The minute fields also crammed the unit into
the value ("5m") inside the box.

## What

All changes are scoped to the **edge-triggered** path of `Chart` and the
shared `NumberField`. Continuous-policy mode renders identically to
before (guarded by `policy ?`), and the `simulate`/server backtest logic
and the summary Stat cards are untouched.

### Backtest chart (`BacktestPanel.tsx`)
- **Removed** all per-sample full-height vertical lines (both suppressed
and fired); suppressed no longer marks the main plot at all, fires
remain as dots on the avg curve.
- **Cooldown bands**: consecutive suppressed indices collapse into a
single low-opacity grey rect per run (padded half a sample-step each
side) instead of N marks.
- **Event rail**: new ~14px dark rounded lane beneath the plot carries
all event density — one grey tick per suppressed sample, one heavier red
tick per fire on top. Time-axis labels moved below the rail; viewBox
height recomputed from the new geometry.
- **Hierarchy fix**: windowed-avg is now the brightest/heaviest trace
(white `#fafafa`, 2px); raw movement dropped to a 1px hairline at 0.5
opacity behind it.
- **Red does one job**: faint red fire-zone tint above the threshold,
threshold dashed line softened to 0.6 opacity, saturated red reserved
for fires (curve dots + rail ticks).
- **Legend** updated to match: white avg swatch, suppressed shown as a
vertical tick, new translucent "cooldown" block.

### Number inputs (`primitives.tsx`, `RuleEditor.tsx`)
- `NumberField` center is now a typeable `<input>` (click in and type)
alongside the +/- buttons, via a draft string that commits only when it
parses.
- The unit renders **outside** the box (matching the existing
number-then-unit pattern); minute fields now read `[5] minutes` instead
of `5m`. Applies to every builder field (threshold, comparison value,
delta, clamp min/max, window, revert, cooldown).

## Test plan

- `eslint` + `tsc --noEmit` clean on all three files.
- Deployed to Pod 5 (`192.168.1.88`); `sleepypod.service` active, app
serving.
- Manual: open the Automations builder backtest panel on a high-density
night and confirm the plot stays clean with events on the rail; click
into each number field and type a value; confirm continuous-policy mode
chart is visually unchanged.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

**New Features**
- Backtest chart now features edge mode with a dedicated event rail to
better visualize event density
- Cooldown bands now display suppressed event information more clearly
- Number input fields now support direct text entry

**Style**
- Time durations now display as "minutes" for improved clarity
- Updated chart legend to reflect new visualization elements

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update feat/automation-builder-ui
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/feat/automation-builder-ui/scripts/install \
  | sudo bash -s -- --branch feat/automation-builder-ui
```

🎯 **Pin to this exact build** ([run
27520854239](https://github.com/sleepypod/core/actions/runs/27520854239)
· `5cb380c`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/5cb380c75f60169ba951bafe9ce647d5c3067a65/scripts/install \
  | sudo bash -s -- \
      --branch feat/automation-builder-ui \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27520854239/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27520854239/artifacts/7628004076)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->
…lling past target) (#640)

## Summary

The biometrics archive pruner
(`modules/biometrics-archiver/sleepypod-biometrics-pruner`) has never
pruned on a pod with a large archive. It exits before deleting anything,
so `/persistent/biometrics-archive` grows unbounded and `/persistent`
fills past the 80% target.

### Root cause
```bash
oldest=$(find ... -printf '%T@ %p\n' | sort -n | head -1 | awk '{print $2}')
```
Under `set -euo pipefail`, `head -1` closes the pipe after the first
line. With a large archive (thousands of files) `sort` is still writing,
gets `SIGPIPE` → `sort: write failed: 'standard output': Broken pipe`,
the pipeline returns 141, and `set -e` aborts the whole script. Net
effect: `pruned=0` every run, service shows `status=2/INVALIDARGUMENT`.

### Fix
Replace `sort -n | head -1 | awk '{print $2}'` with `sort -n | awk
'NR==1{print $2}'`. `awk` reads the whole stream (prints only line 1) so
`sort` never gets SIGPIPE.

## Evidence (Pod 5 / .88, eight-pod)
- `/persistent` at **84%** (target <80%);
`/persistent/biometrics-archive` = **9.4 GB**, 3,789 `*.RAW.gz`.
- `journalctl -u sleepypod-biometrics-pruner`: `sort: write failed:
'standard output': Broken pipe` → `status=2/INVALIDARGUMENT` every 15
min.

## Test plan
- [x] Repro under `set -o pipefail`: `seq 1 100000 | sort -n | head -1 |
awk '{print $1}'` exits **141**; `sort -n | awk 'NR==1{print $1}'` exits
**0**.
- [x] `bash -n` clean.
- [ ] Deploy to .88, run `systemctl start sleepypod-biometrics-pruner`,
confirm it prunes oldest `.RAW.gz` until `/persistent` < 80% and logs
`pruned=N`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Fixed a premature-pruning failure in the biometrics archive pruner
caused by pipeline breakage under strict error handling. The script now
reliably identifies and prunes the oldest eligible files, preventing it
from aborting early and helping keep archive size properly managed.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update fix/biometrics-pruner-sigpipe
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/fix/biometrics-pruner-sigpipe/scripts/install \
  | sudo bash -s -- --branch fix/biometrics-pruner-sigpipe
```

🎯 **Pin to this exact build** ([run
27520832687](https://github.com/sleepypod/core/actions/runs/27520832687)
· `412c906`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/412c90698d429015f8b045f8173d4f337ed66477/scripts/install \
  | sudo bash -s -- \
      --branch fix/biometrics-pruner-sigpipe \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27520832687/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27520832687/artifacts/7627998221)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->
…lay (#648)

## Why

#645 added the `cap_sense_frames` persistence layer (downsampled
~5s-windowed capacitive presence frames) but **nothing read it**. The
table was write-only: `recordCapFrame` (via `piezoStream`) inserts and
the pruner deletes, but no `SELECT` exists anywhere. Every pod was
paying the write + storage + prune cost of what the schema calls "the
bulkiest sensor stream" with zero consumers — and the schema's own
stated purpose was unrealized:

> windowed row per side (~5s) so the **spatial zone replay and cap.\*
backtest** can reach recent nights

Neither consumer existed. The three `{side}.cap.*` signals were still
flagged `liveOnly: true` (a flag nothing actually reads), and
`CapZoneViz` only rendered the live stream.

## What

Wire both read paths the persistence layer was built for:

**Backtest (`cap.*`)**
- `loadSeries` now pulls `{side}.cap.max/mean/spread` from
`cap_sense_frames` over the night window, mirroring the existing
per-signal series blocks.
- The three cap signals drop the now-false `liveOnly` flag — they are
back-testable.
- `cap.peakZone` deliberately stays out of the engine catalog: it's a
spatial zone index, not a scalar signal (consistent with #645's design
choice).

**Spatial zone replay**
- New `automations.capZoneReplay` query: returns the per-window `[head,
torso, legs]` loads + `peakZone` for a chosen night, stride-downsampled
to a `maxFrames` budget (default 300) so a full night stays a light
payload. Skips Pod-3 scalar frames (null `zones`).
- `CapZoneViz` gains a **Live / Replay** toggle (shown only when a
backtest night is available). Replay scrubs — or auto-plays — through
the recorded zone snapshots beside the backtest, with a stable per-night
normalization.
- Added a `Pause` icon.

## Test plan

- `automations.test.ts` (new): covers `capZoneReplay` night resolution,
the spatial-frame select, stride downsampling (25 rows → maxFrames 10 →
9 frames, first preserved), null-zones coercion, and the no-history
`ok:false` path.
- `npx tsc` clean; ESLint clean on all touched files.
- `vitest run` for automation + streaming suites: 138 pass.
- Manual: open a rule using a Bed pressure signal in the editor →
backtest chart now plots the cap series; toggle Replay → scrub/play the
night's zones.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update feat/cap-frame-readers
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/feat/cap-frame-readers/scripts/install \
  | sudo bash -s -- --branch feat/cap-frame-readers
```

🎯 **Pin to this exact build** ([run
27524905607](https://github.com/sleepypod/core/actions/runs/27524905607)
· `4843f01`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/4843f01247a65a858d4e6bb221426da5777692fb/scripts/install \
  | sudo bash -s -- \
      --branch feat/cap-frame-readers \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27524905607/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27524905607/artifacts/7629394448)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Release Notes

* **New Features**
* Added a Live/Replay view for capacitive zone visualization, including
play/pause controls and timeline scrubbing for historical nights.
* Wired the rule editor’s capacitive zone visualization to backtest
context (selected side and night), so it aligns with the active backtest
window.
* Extended backtest-capable capacitive signals for cap max/mean/spread.

* **Style**
  * Added a Pause icon for replay playback controls.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
> ℹ️ **Note**
> 
> This PR body was truncated due to platform limits.

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [node](https://nodejs.org)
([source](https://redirect.github.com/nodejs/node)) | major | `22` →
`24` |

---

### Release Notes

<details>
<summary>nodejs/node (node)</summary>

###
[`v24.16.0`](https://redirect.github.com/nodejs/node/releases/tag/v24.16.0):
2026-05-21, Version 24.16.0 'Krypton' (LTS), @&#8203;aduh95

[Compare
Source](https://redirect.github.com/nodejs/node/compare/v24.15.0...v24.16.0)

##### Notable Changes

-
\[[`b267f6bca3`](https://redirect.github.com/nodejs/node/commit/b267f6bca3)]
- **(SEMVER-MINOR)** **crypto**: implement `randomUUIDv7()` (nabeel378)
[#&#8203;62553](https://redirect.github.com/nodejs/node/pull/62553)
-
\[[`ec2451b9cd`](https://redirect.github.com/nodejs/node/commit/ec2451b9cd)]
- **(SEMVER-MINOR)** **debugger**: add edit-free runtime expression
probes to `node inspect` (Joyee Cheung)
[#&#8203;62713](https://redirect.github.com/nodejs/node/pull/62713)
-
\[[`9705f628d9`](https://redirect.github.com/nodejs/node/commit/9705f628d9)]
- **(SEMVER-MINOR)** **fs**: add signal option to `fs.stat()` (Mert Can
Altin)
[#&#8203;57775](https://redirect.github.com/nodejs/node/pull/57775)
-
\[[`40ccfdecf9`](https://redirect.github.com/nodejs/node/commit/40ccfdecf9)]
- **(SEMVER-MINOR)** **fs**: expose `frsize` field in `statfs` (Jinho
Jang)
[#&#8203;62277](https://redirect.github.com/nodejs/node/pull/62277)
-
\[[`d7188af5c9`](https://redirect.github.com/nodejs/node/commit/d7188af5c9)]
- **(SEMVER-MINOR)** **http**: harden `ClientRequest` options merge
(Matteo Collina)
[#&#8203;63082](https://redirect.github.com/nodejs/node/pull/63082)
-
\[[`aa1d8a9afc`](https://redirect.github.com/nodejs/node/commit/aa1d8a9afc)]
- **(SEMVER-MINOR)** **http**: add `req.signal` to `IncomingMessage`
(Akshat)
[#&#8203;62541](https://redirect.github.com/nodejs/node/pull/62541)
-
\[[`6f37f7e240`](https://redirect.github.com/nodejs/node/commit/6f37f7e240)]
- **(SEMVER-MINOR)** **stream**: propagate destruction in `duplexPair`
(Ahmed Elhor)
[#&#8203;61098](https://redirect.github.com/nodejs/node/pull/61098)
-
\[[`d14029be7f`](https://redirect.github.com/nodejs/node/commit/d14029be7f)]
- **(SEMVER-MINOR)** **test\_runner**: support test order randomization
(Pietro Marchini)
[#&#8203;61747](https://redirect.github.com/nodejs/node/pull/61747)
-
\[[`d142c584cd`](https://redirect.github.com/nodejs/node/commit/d142c584cd)]
- **(SEMVER-MINOR)** **test\_runner**: align mock timeout api (sangwook)
[#&#8203;62820](https://redirect.github.com/nodejs/node/pull/62820)
-
\[[`01a9552585`](https://redirect.github.com/nodejs/node/commit/01a9552585)]
- **(SEMVER-MINOR)** **test\_runner**: add mock-timers support for
`AbortSignal.timeout` (DeveloperViraj)
[#&#8203;60751](https://redirect.github.com/nodejs/node/pull/60751)
-
\[[`00705a459a`](https://redirect.github.com/nodejs/node/commit/00705a459a)]
- **(SEMVER-MINOR)** **util**: colorize text with hex colors (Guilherme
Araújo)
[#&#8203;61556](https://redirect.github.com/nodejs/node/pull/61556)

##### Commits

-
\[[`dd72df060d`](https://redirect.github.com/nodejs/node/commit/dd72df060d)]
- **assert,util**: fix stale nested cycle memo entries (Ruben
Bridgewater)
[#&#8203;62509](https://redirect.github.com/nodejs/node/pull/62509)
-
\[[`add94f4bc3`](https://redirect.github.com/nodejs/node/commit/add94f4bc3)]
- **build**: track PDL files as inputs in inspector GN build (Robo)
[#&#8203;62888](https://redirect.github.com/nodejs/node/pull/62888)
-
\[[`1b1eb9e334`](https://redirect.github.com/nodejs/node/commit/1b1eb9e334)]
- **build**: remove redundant -fuse-linker-plugin from GCC LTO flags
(Daniel Lando)
[#&#8203;62667](https://redirect.github.com/nodejs/node/pull/62667)
-
\[[`8752b604ec`](https://redirect.github.com/nodejs/node/commit/8752b604ec)]
- **crypto**: deduplicate and canonicalize CryptoKey usages (Filip
Skokan)
[#&#8203;62902](https://redirect.github.com/nodejs/node/pull/62902)
-
\[[`341947e7fd`](https://redirect.github.com/nodejs/node/commit/341947e7fd)]
- **crypto**: reject unintended raw key format string input (Filip
Skokan)
[#&#8203;62974](https://redirect.github.com/nodejs/node/pull/62974)
-
\[[`28a78747fc`](https://redirect.github.com/nodejs/node/commit/28a78747fc)]
- **crypto**: remove Argon2 KDF derivation from its job setup (Filip
Skokan)
[#&#8203;62863](https://redirect.github.com/nodejs/node/pull/62863)
-
\[[`16e8c2b54d`](https://redirect.github.com/nodejs/node/commit/16e8c2b54d)]
- **crypto**: fix unsigned conversion of 4-byte RSA publicExponent
(DeepView Autofix)
[#&#8203;62839](https://redirect.github.com/nodejs/node/pull/62839)
-
\[[`eeae754a87`](https://redirect.github.com/nodejs/node/commit/eeae754a87)]
- **crypto**: reject inherited key type names (Jonathan Lopes)
[#&#8203;62875](https://redirect.github.com/nodejs/node/pull/62875)
-
\[[`9dd5540325`](https://redirect.github.com/nodejs/node/commit/9dd5540325)]
- **crypto**: add memory tracking for secureContext openssl objects
(Mert Can Altin)
[#&#8203;59051](https://redirect.github.com/nodejs/node/pull/59051)
-
\[[`b267f6bca3`](https://redirect.github.com/nodejs/node/commit/b267f6bca3)]
- **(SEMVER-MINOR)** **crypto**: implement randomUUIDv7() (nabeel378)
[#&#8203;62553](https://redirect.github.com/nodejs/node/pull/62553)
-
\[[`7597d204c1`](https://redirect.github.com/nodejs/node/commit/7597d204c1)]
- **crypto**: add support for
[`Ed25519`](https://redirect.github.com/nodejs/node/commit/Ed25519)
context parameter (Filip Skokan)
[#&#8203;62474](https://redirect.github.com/nodejs/node/pull/62474)
-
\[[`4bf85845da`](https://redirect.github.com/nodejs/node/commit/4bf85845da)]
- **debugger**: move ProbeInspectorSession and helpers to separate files
(Joyee Cheung)
[#&#8203;63013](https://redirect.github.com/nodejs/node/pull/63013)
-
\[[`ec2451b9cd`](https://redirect.github.com/nodejs/node/commit/ec2451b9cd)]
- **(SEMVER-MINOR)** **debugger**: add edit-free runtime expression
probes to `node inspect` (Joyee Cheung)
[#&#8203;62713](https://redirect.github.com/nodejs/node/pull/62713)
-
\[[`83e98f77b7`](https://redirect.github.com/nodejs/node/commit/83e98f77b7)]
- **deps**: update corepack to 0.35.0 (Node.js GitHub Bot)
[#&#8203;63375](https://redirect.github.com/nodejs/node/pull/63375)
-
\[[`ec8c6b939a`](https://redirect.github.com/nodejs/node/commit/ec8c6b939a)]
- **deps**: V8: cherry-pick
[`657d8de`](https://redirect.github.com/nodejs/node/commit/657d8de27427)
(Guy Bedford)
[#&#8203;62784](https://redirect.github.com/nodejs/node/pull/62784)
-
\[[`722c0c3274`](https://redirect.github.com/nodejs/node/commit/722c0c3274)]
- **deps**: update nghttp3 to 1.14.0 (Node.js GitHub Bot)
[#&#8203;61187](https://redirect.github.com/nodejs/node/pull/61187)
-
\[[`5304db93d3`](https://redirect.github.com/nodejs/node/commit/5304db93d3)]
- **deps**: update nghttp3 to 1.13.1 (Node.js GitHub Bot)
[#&#8203;60046](https://redirect.github.com/nodejs/node/pull/60046)
-
\[[`e073b3811d`](https://redirect.github.com/nodejs/node/commit/e073b3811d)]
- **deps**: update nghttp3 to 1.11.0 (James M Snell)
[#&#8203;59249](https://redirect.github.com/nodejs/node/pull/59249)
-
\[[`1d00313fb2`](https://redirect.github.com/nodejs/node/commit/1d00313fb2)]
- **deps**: update ngtcp2 to 1.14.0 (James M Snell)
[#&#8203;59249](https://redirect.github.com/nodejs/node/pull/59249)
-
\[[`8b3a4fc18f`](https://redirect.github.com/nodejs/node/commit/8b3a4fc18f)]
- **deps**: update amaro to 1.1.9 (Node.js GitHub Bot)
[#&#8203;63090](https://redirect.github.com/nodejs/node/pull/63090)
-
\[[`62fe0cfcd1`](https://redirect.github.com/nodejs/node/commit/62fe0cfcd1)]
- **deps**: update llhttp to 9.4.1 (Node.js GitHub Bot)
[#&#8203;63045](https://redirect.github.com/nodejs/node/pull/63045)
-
\[[`137e09c8e9`](https://redirect.github.com/nodejs/node/commit/137e09c8e9)]
- **deps**: update corepack to 0.34.7 (Node.js GitHub Bot)
[#&#8203;62810](https://redirect.github.com/nodejs/node/pull/62810)
-
\[[`14a4cb8fbc`](https://redirect.github.com/nodejs/node/commit/14a4cb8fbc)]
- **deps**: update timezone to 2026b (Node.js GitHub Bot)
[#&#8203;62962](https://redirect.github.com/nodejs/node/pull/62962)
-
\[[`3e1036583a`](https://redirect.github.com/nodejs/node/commit/3e1036583a)]
- **deps**: upgrade npm to 11.13.0 (npm team)
[#&#8203;62898](https://redirect.github.com/nodejs/node/pull/62898)
-
\[[`01dfe5961c`](https://redirect.github.com/nodejs/node/commit/01dfe5961c)]
- **deps**: cherry-pick
[libuv/libuv@`439a54b`](https://redirect.github.com/libuv/libuv/commit/439a54b)
(skooch)
[#&#8203;62881](https://redirect.github.com/nodejs/node/pull/62881)
-
\[[`6cd368b10c`](https://redirect.github.com/nodejs/node/commit/6cd368b10c)]
- **deps**: update sqlite to 3.53.0 (Node.js GitHub Bot)
[#&#8203;62699](https://redirect.github.com/nodejs/node/pull/62699)
-
\[[`f218a4f553`](https://redirect.github.com/nodejs/node/commit/f218a4f553)]
- **deps**: update nbytes to 0.1.4 (Node.js GitHub Bot)
[#&#8203;62698](https://redirect.github.com/nodejs/node/pull/62698)
-
\[[`b47688524a`](https://redirect.github.com/nodejs/node/commit/b47688524a)]
- **deps**: update archs files for openssl-3.5.6 (Node.js GitHub Bot)
[#&#8203;62629](https://redirect.github.com/nodejs/node/pull/62629)
-
\[[`d202e2d343`](https://redirect.github.com/nodejs/node/commit/d202e2d343)]
- **deps**: upgrade openssl sources to openssl-3.5.6 (Node.js GitHub
Bot) [#&#8203;62629](https://redirect.github.com/nodejs/node/pull/62629)
-
\[[`2faba66341`](https://redirect.github.com/nodejs/node/commit/2faba66341)]
- **deps**: update minimatch to 10.2.5 (Node.js GitHub Bot)
[#&#8203;62594](https://redirect.github.com/nodejs/node/pull/62594)
-
\[[`fa46c90c5d`](https://redirect.github.com/nodejs/node/commit/fa46c90c5d)]
- **deps**: update googletest to
[`d72f9c8`](https://redirect.github.com/nodejs/node/commit/d72f9c8aea6817cdf1ca0ac10887f328de7f3da2)
(Node.js GitHub Bot)
[#&#8203;62593](https://redirect.github.com/nodejs/node/pull/62593)
-
\[[`099ded5713`](https://redirect.github.com/nodejs/node/commit/099ded5713)]
- **deps**: update simdjson to 4.6.1 (Node.js GitHub Bot)
[#&#8203;62592](https://redirect.github.com/nodejs/node/pull/62592)
-
\[[`7ce95afe96`](https://redirect.github.com/nodejs/node/commit/7ce95afe96)]
- **deps**: libuv: cherry-pick
[`aabb765`](https://redirect.github.com/nodejs/node/commit/aabb7651de)
(Santiago Gimeno)
[#&#8203;62561](https://redirect.github.com/nodejs/node/pull/62561)
-
\[[`57ef845623`](https://redirect.github.com/nodejs/node/commit/57ef845623)]
- **deps**: update icu to 78.3 (Node.js GitHub Bot)
[#&#8203;62324](https://redirect.github.com/nodejs/node/pull/62324)
-
\[[`493ac40e12`](https://redirect.github.com/nodejs/node/commit/493ac40e12)]
- **deps**: update libuv to 1.52.1 (Node.js GitHub Bot)
[#&#8203;61829](https://redirect.github.com/nodejs/node/pull/61829)
-
\[[`b39508b368`](https://redirect.github.com/nodejs/node/commit/b39508b368)]
- **deps**: update undici to 7.25.0 (Node.js GitHub Bot)
[#&#8203;63011](https://redirect.github.com/nodejs/node/pull/63011)
-
\[[`cb67a925e9`](https://redirect.github.com/nodejs/node/commit/cb67a925e9)]
- **deps**: use npm undici\@&#8203;seven tag in `update-undici.sh`
(Matteo Collina)
[#&#8203;62739](https://redirect.github.com/nodejs/node/pull/62739)
-
\[[`aa1e0bc28b`](https://redirect.github.com/nodejs/node/commit/aa1e0bc28b)]
- **doc**: fix typos and inconsistencies in crypto.md and webcrypto.md
(Filip Skokan)
[#&#8203;62828](https://redirect.github.com/nodejs/node/pull/62828)
-
\[[`f2a1735ed9`](https://redirect.github.com/nodejs/node/commit/f2a1735ed9)]
- **doc**: fix duplicate word "to to" in util.styleText (Daijiro Wachi)
[#&#8203;62917](https://redirect.github.com/nodejs/node/pull/62917)
-
\[[`b6378e215c`](https://redirect.github.com/nodejs/node/commit/b6378e215c)]
- **doc**: fix node-config-schema (Сковорода Никита Андреевич)
[#&#8203;61596](https://redirect.github.com/nodejs/node/pull/61596)
-
\[[`233894a9ce`](https://redirect.github.com/nodejs/node/commit/233894a9ce)]
- **doc**: fix the TypeScript Execute (tsx) project link (David
Thornton)
[#&#8203;63093](https://redirect.github.com/nodejs/node/pull/63093)
-
\[[`5d97919f8f`](https://redirect.github.com/nodejs/node/commit/5d97919f8f)]
- **doc**: correct diagnostics\_channel built-in channel names (Bryan
English)
[#&#8203;62995](https://redirect.github.com/nodejs/node/pull/62995)
-
\[[`2a9ccc927e`](https://redirect.github.com/nodejs/node/commit/2a9ccc927e)]
- **doc**: use mjs/cjs blocks for callbackify null reason example
(Daijiro Wachi)
[#&#8203;62884](https://redirect.github.com/nodejs/node/pull/62884)
-
\[[`ef413b5358`](https://redirect.github.com/nodejs/node/commit/ef413b5358)]
- **doc**: fix typo in test.md (Rich Trott)
[#&#8203;62960](https://redirect.github.com/nodejs/node/pull/62960)
-
\[[`76f21c5070`](https://redirect.github.com/nodejs/node/commit/76f21c5070)]
- **doc**: correct typo in PR contribution instructions (Mike McCready)
[#&#8203;62738](https://redirect.github.com/nodejs/node/pull/62738)
-
\[[`ca02af1f7d`](https://redirect.github.com/nodejs/node/commit/ca02af1f7d)]
- **doc**: fix duplicate word "of of" in postMessageToThread (Daijiro
Wachi)
[#&#8203;62917](https://redirect.github.com/nodejs/node/pull/62917)
-
\[[`46c99ed526`](https://redirect.github.com/nodejs/node/commit/46c99ed526)]
- **doc**: fix duplicate word "for for" in compile cache (Daijiro Wachi)
[#&#8203;62917](https://redirect.github.com/nodejs/node/pull/62917)
-
\[[`1a60851734`](https://redirect.github.com/nodejs/node/commit/1a60851734)]
- **doc**: fix typo in dns.lookup options description (Daijiro Wachi)
[#&#8203;62882](https://redirect.github.com/nodejs/node/pull/62882)
-
\[[`169b5ea2ed`](https://redirect.github.com/nodejs/node/commit/169b5ea2ed)]
- **doc**: fix Argon2 parameter bounds (Tobias Nießen)
[#&#8203;62868](https://redirect.github.com/nodejs/node/pull/62868)
-
\[[`9a3a190f4e`](https://redirect.github.com/nodejs/node/commit/9a3a190f4e)]
- **doc**: clarify diffieHellman.generateKeys recomputes same key (Kit
Dallege)
[#&#8203;62205](https://redirect.github.com/nodejs/node/pull/62205)
-
\[[`0fba9e87d6`](https://redirect.github.com/nodejs/node/commit/0fba9e87d6)]
- **doc**: remove Ayase-252 and meixg from triagger team (Antoine du
Hamel)
[#&#8203;62841](https://redirect.github.com/nodejs/node/pull/62841)
-
\[[`9c700f3446`](https://redirect.github.com/nodejs/node/commit/9c700f3446)]
- **doc**: clarify dns.lookup() callback signature when all is true
(eungi)
[#&#8203;62800](https://redirect.github.com/nodejs/node/pull/62800)
-
\[[`6b7280bc17`](https://redirect.github.com/nodejs/node/commit/6b7280bc17)]
- **doc**: add experimental modules lifetime policy (Paolo Insogna)
[#&#8203;62753](https://redirect.github.com/nodejs/node/pull/62753)
-
\[[`ce47ea31c9`](https://redirect.github.com/nodejs/node/commit/ce47ea31c9)]
- **doc**: clarify process.\_debugProcess() in Permission Model (Fahad
Khan)
[#&#8203;62537](https://redirect.github.com/nodejs/node/pull/62537)
-
\[[`ba01633757`](https://redirect.github.com/nodejs/node/commit/ba01633757)]
- **doc**: fix typo in devcontainer guide (Rohan Santhosh Kumar)
[#&#8203;62687](https://redirect.github.com/nodejs/node/pull/62687)
-
\[[`70b4d5839b`](https://redirect.github.com/nodejs/node/commit/70b4d5839b)]
- **doc**: clarify Backport-PR-URL metadata added automatically (Mike
McCready)
[#&#8203;62668](https://redirect.github.com/nodejs/node/pull/62668)
-
\[[`8126d1c3eb`](https://redirect.github.com/nodejs/node/commit/8126d1c3eb)]
- **doc**: update WPT test runner README.md (Filip Skokan)
[#&#8203;62680](https://redirect.github.com/nodejs/node/pull/62680)
-
\[[`978afea4b5`](https://redirect.github.com/nodejs/node/commit/978afea4b5)]
- **doc**: fix spelling in release announcement guidance (Rohan Santhosh
Kumar)
[#&#8203;62663](https://redirect.github.com/nodejs/node/pull/62663)
-
\[[`1684ab8ff8`](https://redirect.github.com/nodejs/node/commit/1684ab8ff8)]
- **doc**: note non-monotonic clock in crypto.randomUUIDv7 (nabeel378)
[#&#8203;62600](https://redirect.github.com/nodejs/node/pull/62600)
-
\[[`86d4f07930`](https://redirect.github.com/nodejs/node/commit/86d4f07930)]
- **doc**: update bug bounty program (Rafael Gonzaga)
[#&#8203;62590](https://redirect.github.com/nodejs/node/pull/62590)
-
\[[`736ed8a08f`](https://redirect.github.com/nodejs/node/commit/736ed8a08f)]
- **doc**: document TransformStream transformer.cancel option (Tom
Pereira)
[#&#8203;62566](https://redirect.github.com/nodejs/node/pull/62566)
-
\[[`938af9be01`](https://redirect.github.com/nodejs/node/commit/938af9be01)]
- **doc**: mention test runner retry attemp is zero based (Moshe Atlow)
[#&#8203;62504](https://redirect.github.com/nodejs/node/pull/62504)
-
\[[`94433e450f`](https://redirect.github.com/nodejs/node/commit/94433e450f)]
- **doc,src,test**: fix dead inspector help URL (semimikoh)
[#&#8203;62745](https://redirect.github.com/nodejs/node/pull/62745)
-
\[[`ddf1f01659`](https://redirect.github.com/nodejs/node/commit/ddf1f01659)]
- **esm**: add `ERR_REQUIRE_ESM_RACE_CONDITION` (Antoine du Hamel)
[#&#8203;62462](https://redirect.github.com/nodejs/node/pull/62462)
-
\[[`4a506acd16`](https://redirect.github.com/nodejs/node/commit/4a506acd16)]
- **fs**: add followSymlinks option to glob (Matteo Collina)
[#&#8203;62695](https://redirect.github.com/nodejs/node/pull/62695)
-
\[[`f4ea495f9b`](https://redirect.github.com/nodejs/node/commit/f4ea495f9b)]
- **fs**: restore fs patchability in ESM loader (Joyee Cheung)
[#&#8203;62835](https://redirect.github.com/nodejs/node/pull/62835)
-
\[[`63c111cd60`](https://redirect.github.com/nodejs/node/commit/63c111cd60)]
- **fs**: validate position argument before length === 0 early return
(Edy Silva)
[#&#8203;62674](https://redirect.github.com/nodejs/node/pull/62674)
-
\[[`9705f628d9`](https://redirect.github.com/nodejs/node/commit/9705f628d9)]
- **(SEMVER-MINOR)** **fs**: add signal option to fs.stat() (Mert Can
Altin)
[#&#8203;57775](https://redirect.github.com/nodejs/node/pull/57775)
-
\[[`40ccfdecf9`](https://redirect.github.com/nodejs/node/commit/40ccfdecf9)]
- **(SEMVER-MINOR)** **fs**: expose frsize field in statfs (Jinho Jang)
[#&#8203;62277](https://redirect.github.com/nodejs/node/pull/62277)
-
\[[`717476a24e`](https://redirect.github.com/nodejs/node/commit/717476a24e)]
- **http**: emit 'drain' on OutgoingMessage only after buffers drain
(Robert Nagy)
[#&#8203;62936](https://redirect.github.com/nodejs/node/pull/62936)
-
\[[`d7188af5c9`](https://redirect.github.com/nodejs/node/commit/d7188af5c9)]
- **(SEMVER-MINOR)** **http**: harden ClientRequest options merge
(Matteo Collina)
[#&#8203;63082](https://redirect.github.com/nodejs/node/pull/63082)
-
\[[`64f15c274a`](https://redirect.github.com/nodejs/node/commit/64f15c274a)]
- **http**: fix leaked error listener on sync HTTP req create + destroy
(Tim Perry)
[#&#8203;62872](https://redirect.github.com/nodejs/node/pull/62872)
-
\[[`5c4798d799`](https://redirect.github.com/nodejs/node/commit/5c4798d799)]
- **http**: fix no\_proxy leading-dot suffix matching (Daijiro Wachi)
[#&#8203;62333](https://redirect.github.com/nodejs/node/pull/62333)
-
\[[`9f3bc70ae5`](https://redirect.github.com/nodejs/node/commit/9f3bc70ae5)]
- **http**: cleanup pipeline queue (Robert Nagy)
[#&#8203;62534](https://redirect.github.com/nodejs/node/pull/62534)
-
\[[`aa1d8a9afc`](https://redirect.github.com/nodejs/node/commit/aa1d8a9afc)]
- **(SEMVER-MINOR)** **http**: add req.signal to IncomingMessage
(Akshat)
[#&#8203;62541](https://redirect.github.com/nodejs/node/pull/62541)
-
\[[`900dc758ff`](https://redirect.github.com/nodejs/node/commit/900dc758ff)]
- **http2**: expose writable stream state on compat response (T)
[#&#8203;63003](https://redirect.github.com/nodejs/node/pull/63003)
-
\[[`b3bfe35912`](https://redirect.github.com/nodejs/node/commit/b3bfe35912)]
- **inspector**: coerce key and value to string in webstorage events
(Ali Hassan)
[#&#8203;62616](https://redirect.github.com/nodejs/node/pull/62616)
-
\[[`3dc3fb6ad8`](https://redirect.github.com/nodejs/node/commit/3dc3fb6ad8)]
- **inspector**: return errors when CDP protocol event emission fails
(Ryuhei Shima)
[#&#8203;62162](https://redirect.github.com/nodejs/node/pull/62162)
-
\[[`4f3f21bd7c`](https://redirect.github.com/nodejs/node/commit/4f3f21bd7c)]
- **inspector**: auto collect webstorage data (Ryuhei Shima)
[#&#8203;62145](https://redirect.github.com/nodejs/node/pull/62145)
-
\[[`36cc04189d`](https://redirect.github.com/nodejs/node/commit/36cc04189d)]
- **inspector**: initial support storage inspection (Ryuhei Shima)
[#&#8203;61139](https://redirect.github.com/nodejs/node/pull/61139)
-
\[[`1718bc3b9b`](https://redirect.github.com/nodejs/node/commit/1718bc3b9b)]
- **inspector**: fix absolute URLs in network http (bugyaluwang)
[#&#8203;62955](https://redirect.github.com/nodejs/node/pull/62955)
-
\[[`97e32c7a74`](https://redirect.github.com/nodejs/node/commit/97e32c7a74)]
- **lib**: avoid quadratic shift() in startup snapshot callback (Daijiro
Wachi)
[#&#8203;62914](https://redirect.github.com/nodejs/node/pull/62914)
-
\[[`25d2e999de`](https://redirect.github.com/nodejs/node/commit/25d2e999de)]
- **lib**: harden kKeyOps lookup with null prototype (Filip Skokan)
[#&#8203;62877](https://redirect.github.com/nodejs/node/pull/62877)
-
\[[`37d3913c8f`](https://redirect.github.com/nodejs/node/commit/37d3913c8f)]
- **lib**: short-circuit WebIDL BufferSource SAB check (Filip Skokan)
[#&#8203;62833](https://redirect.github.com/nodejs/node/pull/62833)
-
\[[`430c69d25f`](https://redirect.github.com/nodejs/node/commit/430c69d25f)]
- **lib**: use js-only implementation of `isDataView()` (René)
[#&#8203;62780](https://redirect.github.com/nodejs/node/pull/62780)
-
\[[`3ba0add6a0`](https://redirect.github.com/nodejs/node/commit/3ba0add6a0)]
- **lib**: fix lint in internal/webstreams/util.js (Filip Skokan)
[#&#8203;62806](https://redirect.github.com/nodejs/node/pull/62806)
-
\[[`9b95c41398`](https://redirect.github.com/nodejs/node/commit/9b95c41398)]
- **lib**: fix sequence argument handling in Blob constructor (Ms2ger)
[#&#8203;62179](https://redirect.github.com/nodejs/node/pull/62179)
-
\[[`314dacdbee`](https://redirect.github.com/nodejs/node/commit/314dacdbee)]
- **lib**: improve Web Cryptography key validation ordering (Filip
Skokan)
[#&#8203;62749](https://redirect.github.com/nodejs/node/pull/62749)
-
\[[`3d18162430`](https://redirect.github.com/nodejs/node/commit/3d18162430)]
- **lib**: reject SharedArrayBuffer in web APIs per spec (Ali Hassan)
[#&#8203;62632](https://redirect.github.com/nodejs/node/pull/62632)
-
\[[`ada3ce879d`](https://redirect.github.com/nodejs/node/commit/ada3ce879d)]
- **lib**: defer AbortSignal.any() following (sangwook)
[#&#8203;62367](https://redirect.github.com/nodejs/node/pull/62367)
-
\[[`b2981ec7eb`](https://redirect.github.com/nodejs/node/commit/b2981ec7eb)]
- **meta**: bump actions/download-artifact from 8.0.0 to 8.0.1
(dependabot\[bot])
[#&#8203;62549](https://redirect.github.com/nodejs/node/pull/62549)
-
\[[`7cd20667b5`](https://redirect.github.com/nodejs/node/commit/7cd20667b5)]
- **meta**: bump github/codeql-action from 4.35.1 to 4.35.3
(dependabot\[bot])
[#&#8203;63074](https://redirect.github.com/nodejs/node/pull/63074)
-
\[[`91a07cfe9f`](https://redirect.github.com/nodejs/node/commit/91a07cfe9f)]
- **meta**: bump Mozilla-Actions/sccache-action from 0.0.9 to 0.0.10
(dependabot\[bot])
[#&#8203;63073](https://redirect.github.com/nodejs/node/pull/63073)
-
\[[`09e17fe47c`](https://redirect.github.com/nodejs/node/commit/09e17fe47c)]
- **meta**: add automation policy (Chengzhong Wu)
[#&#8203;62871](https://redirect.github.com/nodejs/node/pull/62871)
-
\[[`59e7fb7986`](https://redirect.github.com/nodejs/node/commit/59e7fb7986)]
- **meta**: move VoltrexKeyva to emeritus (Matteo Collina)
[#&#8203;62895](https://redirect.github.com/nodejs/node/pull/62895)
-
\[[`1e2915cfa6`](https://redirect.github.com/nodejs/node/commit/1e2915cfa6)]
- **meta**: bump peter-evans/create-pull-request from 8.1.0 to 8.1.1
(dependabot\[bot])
[#&#8203;62845](https://redirect.github.com/nodejs/node/pull/62845)
-
\[[`0253c6e2be`](https://redirect.github.com/nodejs/node/commit/0253c6e2be)]
- **meta**: bump step-security/harden-runner from 2.16.1 to 2.19.0
(dependabot\[bot])
[#&#8203;62844](https://redirect.github.com/nodejs/node/pull/62844)
-
\[[`f503675b86`](https://redirect.github.com/nodejs/node/commit/f503675b86)]
- **meta**: bump actions/setup-node from 6.3.0 to 6.4.0
(dependabot\[bot])
[#&#8203;62842](https://redirect.github.com/nodejs/node/pull/62842)
-
\[[`5e14e4d26e`](https://redirect.github.com/nodejs/node/commit/5e14e4d26e)]
- **meta**: broaden stale bot (Aviv Keller)
[#&#8203;62658](https://redirect.github.com/nodejs/node/pull/62658)
-
\[[`795db76f87`](https://redirect.github.com/nodejs/node/commit/795db76f87)]
- **meta**: pass release version to release worker (flakey5)
[#&#8203;62777](https://redirect.github.com/nodejs/node/pull/62777)
-
\[[`ef384fe39f`](https://redirect.github.com/nodejs/node/commit/ef384fe39f)]
- **meta**: add QUIC to CODEOWNERS (Tim Perry)
[#&#8203;62652](https://redirect.github.com/nodejs/node/pull/62652)
-
\[[`67e0ac568d`](https://redirect.github.com/nodejs/node/commit/67e0ac568d)]
- **meta**: move Michael to emeritus (Michael Dawson)
[#&#8203;62536](https://redirect.github.com/nodejs/node/pull/62536)
-
\[[`5dad616393`](https://redirect.github.com/nodejs/node/commit/5dad616393)]
- **meta**: populate apt list for slim runner in update-openssl workflow
(René)
[#&#8203;62628](https://redirect.github.com/nodejs/node/pull/62628)
-
\[[`a869d25d8a`](https://redirect.github.com/nodejs/node/commit/a869d25d8a)]
- **meta**: bump step-security/harden-runner from 2.15.0 to 2.16.1
(dependabot\[bot])
[#&#8203;62550](https://redirect.github.com/nodejs/node/pull/62550)
-
\[[`769efc0403`](https://redirect.github.com/nodejs/node/commit/769efc0403)]
- **meta**: bump actions/setup-node from 6.2.0 to 6.3.0
(dependabot\[bot])
[#&#8203;62548](https://redirect.github.com/nodejs/node/pull/62548)
-
\[[`73fcc2b055`](https://redirect.github.com/nodejs/node/commit/73fcc2b055)]
- **meta**: bump github/codeql-action from 4.32.4 to 4.35.1
(dependabot\[bot])
[#&#8203;62547](https://redirect.github.com/nodejs/node/pull/62547)
-
\[[`6c001246fe`](https://redirect.github.com/nodejs/node/commit/6c001246fe)]
- **meta**: bump codecov/codecov-action from 5.5.2 to 6.0.0
(dependabot\[bot])
[#&#8203;62545](https://redirect.github.com/nodejs/node/pull/62545)
-
\[[`5ee40d6a03`](https://redirect.github.com/nodejs/node/commit/5ee40d6a03)]
- **meta**: bump actions/cache from 5.0.3 to 5.0.4 (dependabot\[bot])
[#&#8203;62543](https://redirect.github.com/nodejs/node/pull/62543)
-
\[[`ca16ad8a05`](https://redirect.github.com/nodejs/node/commit/ca16ad8a05)]
- **meta**: require DCO signoff in commit message guidelines (James M
Snell)
[#&#8203;62510](https://redirect.github.com/nodejs/node/pull/62510)
-
\[[`db9497fc41`](https://redirect.github.com/nodejs/node/commit/db9497fc41)]
- **meta**: expand memory leak DoS criteria to all DoS (Joyee Cheung)
[#&#8203;62505](https://redirect.github.com/nodejs/node/pull/62505)
-
\[[`13b7d08b8d`](https://redirect.github.com/nodejs/node/commit/13b7d08b8d)]
- **module**: remove duplicated checks from `_resolveFilename` (Antoine
du Hamel)
[#&#8203;62729](https://redirect.github.com/nodejs/node/pull/62729)
-
\[[`6b53efb53a`](https://redirect.github.com/nodejs/node/commit/6b53efb53a)]
- **module,win**: fix long subpath import (Stefan Stojanovic)
[#&#8203;62101](https://redirect.github.com/nodejs/node/pull/62101)
-
\[[`841dfbf6fc`](https://redirect.github.com/nodejs/node/commit/841dfbf6fc)]
- **node-api**: update libuv ABI stability note (Chengzhong Wu)
[#&#8203;62789](https://redirect.github.com/nodejs/node/pull/62789)
-
\[[`01090f2aa1`](https://redirect.github.com/nodejs/node/commit/01090f2aa1)]
- **node-api**: add napi\_create\_external\_sharedarraybuffer (Ben
Noordhuis)
[#&#8203;62623](https://redirect.github.com/nodejs/node/pull/62623)
-
\[[`87443b4355`](https://redirect.github.com/nodejs/node/commit/87443b4355)]
- **node-api**: execute tsfn finalizer after queue drains when aborted
(Kevin Eady)
[#&#8203;61956](https://redirect.github.com/nodejs/node/pull/61956)
-
\[[`e95570c054`](https://redirect.github.com/nodejs/node/commit/e95570c054)]
- **process**: handle rejections only when needed (Gürgün Dayıoğlu)
[#&#8203;62919](https://redirect.github.com/nodejs/node/pull/62919)
-
\[[`37d49f3219`](https://redirect.github.com/nodejs/node/commit/37d49f3219)]
- **process**: optimize asyncHandledRejections by using FixedQueue
(Gürgün Dayıoğlu)
[#&#8203;60854](https://redirect.github.com/nodejs/node/pull/60854)
-
\[[`f697c55e38`](https://redirect.github.com/nodejs/node/commit/f697c55e38)]
- **quic**: add QuicEndpoint.listening & QuicStream.destroy() and tests
(Tim Perry)
[#&#8203;62648](https://redirect.github.com/nodejs/node/pull/62648)
-
\[[`c128942b69`](https://redirect.github.com/nodejs/node/commit/c128942b69)]
- **quic**: fixup token verification to handle zero expiration (James M
Snell)
[#&#8203;62620](https://redirect.github.com/nodejs/node/pull/62620)
-
\[[`abb881ec92`](https://redirect.github.com/nodejs/node/commit/abb881ec92)]
- **quic**: support multiple ALPN negotiation (James M Snell)
[#&#8203;62620](https://redirect.github.com/nodejs/node/pull/62620)
-
\[[`476926c2ad`](https://redirect.github.com/nodejs/node/commit/476926c2ad)]
- **quic**: apply multiple TLS context improvements and SNI support
(James M Snell)
[#&#8203;62620](https://redirect.github.com/nodejs/node/pull/62620)
-
\[[`76d9c24b95`](https://redirect.github.com/nodejs/node/commit/76d9c24b95)]
- **quic**: implement rapidhash for hashing improvements (James M Snell)
[#&#8203;62620](https://redirect.github.com/nodejs/node/pull/62620)
-
\[[`08726cd43d`](https://redirect.github.com/nodejs/node/commit/08726cd43d)]
- **quic**: move quic behind compile time flag (Matteo Collina)
[#&#8203;61444](https://redirect.github.com/nodejs/node/pull/61444)
-
\[[`ea4f19aaa7`](https://redirect.github.com/nodejs/node/commit/ea4f19aaa7)]
- **quic**: use arena allocation for packets (James M Snell)
[#&#8203;62589](https://redirect.github.com/nodejs/node/pull/62589)
-
\[[`21e9239e2a`](https://redirect.github.com/nodejs/node/commit/21e9239e2a)]
- **quic**: fixup linting/formatting issues (James M Snell)
[#&#8203;62387](https://redirect.github.com/nodejs/node/pull/62387)
-
\[[`edeed4303b`](https://redirect.github.com/nodejs/node/commit/edeed4303b)]
- **quic**: update http3 impl details (James M Snell)
[#&#8203;62387](https://redirect.github.com/nodejs/node/pull/62387)
-
\[[`7f3a85e6aa`](https://redirect.github.com/nodejs/node/commit/7f3a85e6aa)]
- **quic**: fix a handful of bugs and missing functionality (James M
Snell)
[#&#8203;62387](https://redirect.github.com/nodejs/node/pull/62387)
-
\[[`45c1ebddf8`](https://redirect.github.com/nodejs/node/commit/45c1ebddf8)]
- **quic**: copy options.certs buffer instead of detaching (Chengzhong
Wu) [#&#8203;61403](https://redirect.github.com/nodejs/node/pull/61403)
-
\[[`a31a8ee680`](https://redirect.github.com/nodejs/node/commit/a31a8ee680)]
- **quic**: reduce boilerplate and other minor cleanups (James M Snell)
[#&#8203;59342](https://redirect.github.com/nodejs/node/pull/59342)
-
\[[`3be70ff43a`](https://redirect.github.com/nodejs/node/commit/3be70ff43a)]
- **quic**: multiple fixups and updates (James M Snell)
[#&#8203;59342](https://redirect.github.com/nodejs/node/pull/59342)
-
\[[`b91a93444c`](https://redirect.github.com/nodejs/node/commit/b91a93444c)]
- **quic**: update more of the quic to the new compile guard (James M
Snell)
[#&#8203;59342](https://redirect.github.com/nodejs/node/pull/59342)
-
\[[`ca0080c164`](https://redirect.github.com/nodejs/node/commit/ca0080c164)]
- **quic**: few additional small comment edits in cid.h (James M Snell)
[#&#8203;59342](https://redirect.github.com/nodejs/node/pull/59342)
-
\[[`6553202d83`](https://redirect.github.com/nodejs/node/commit/6553202d83)]
- **quic**: fixup NO\_ERROR macro conflict on windows (James M Snell)
[#&#8203;59381](https://redirect.github.com/nodejs/node/pull/59381)
-
\[[`6df1508ac2`](https://redirect.github.com/nodejs/node/commit/6df1508ac2)]
- **quic**: fixup windows coverage compile error (James M Snell)
[#&#8203;59381](https://redirect.github.com/nodejs/node/pull/59381)
-
\[[`b2b0bf8b04`](https://redirect.github.com/nodejs/node/commit/b2b0bf8b04)]
- **quic**: update the guard to check openssl version (James M Snell)
[#&#8203;59249](https://redirect.github.com/nodejs/node/pull/59249)
-
\[[`5556b154bd`](https://redirect.github.com/nodejs/node/commit/5556b154bd)]
- **quic**: start re-enabling quic with openssl 3.5 (James M Snell)
[#&#8203;59249](https://redirect.github.com/nodejs/node/pull/59249)
-
\[[`2ca42c8263`](https://redirect.github.com/nodejs/node/commit/2ca42c8263)]
- **repl**: keep reference count for `process.on('newListener')` (Anna
Henningsen)
[#&#8203;61895](https://redirect.github.com/nodejs/node/pull/61895)
-
\[[`2f37f9177f`](https://redirect.github.com/nodejs/node/commit/2f37f9177f)]
- **sqlite**: use OneByte for ASCII text and internalize col names (Ali
Hassan)
[#&#8203;61954](https://redirect.github.com/nodejs/node/pull/61954)
-
\[[`3c96ae1b2f`](https://redirect.github.com/nodejs/node/commit/3c96ae1b2f)]
- **sqlite**: add serialize() and deserialize() (Ali Hassan)
[#&#8203;62579](https://redirect.github.com/nodejs/node/pull/62579)
-
\[[`be4d2f3a4c`](https://redirect.github.com/nodejs/node/commit/be4d2f3a4c)]
- **sqlite**: enable Percentile extension (Jurj Andrei George)
[#&#8203;61295](https://redirect.github.com/nodejs/node/pull/61295)
-
\[[`dafed453b2`](https://redirect.github.com/nodejs/node/commit/dafed453b2)]
- **src**: clean up experimental flag variables (Antoine du Hamel)
[#&#8203;62759](https://redirect.github.com/nodejs/node/pull/62759)
-
\[[`dca1e6aeea`](https://redirect.github.com/nodejs/node/commit/dca1e6aeea)]
- **src**: expose help texts into node-config-schema.json (Pietro
Marchini)
[#&#8203;58680](https://redirect.github.com/nodejs/node/pull/58680)
-
\[[`28c4f44eb1`](https://redirect.github.com/nodejs/node/commit/28c4f44eb1)]
- **src**: add permission support to config file (Marco Ippolito)
[#&#8203;60746](https://redirect.github.com/nodejs/node/pull/60746)
-
\[[`f49175b220`](https://redirect.github.com/nodejs/node/commit/f49175b220)]
- **src**: fix small compile warning in quic/streams.cc (James M Snell)
[#&#8203;60118](https://redirect.github.com/nodejs/node/pull/60118)
-
\[[`c9d4a446d8`](https://redirect.github.com/nodejs/node/commit/c9d4a446d8)]
- **src**: cleanup quic TransportParams class (James M Snell)
[#&#8203;59884](https://redirect.github.com/nodejs/node/pull/59884)
-
\[[`99bb02fd9e`](https://redirect.github.com/nodejs/node/commit/99bb02fd9e)]
- **src**: swap dotenv and config file parsing order (Marco Ippolito)
[#&#8203;63035](https://redirect.github.com/nodejs/node/pull/63035)
-
\[[`ecb4d49b7b`](https://redirect.github.com/nodejs/node/commit/ecb4d49b7b)]
- **src**: add missing \<cstdlib> for abort() declaration (Charles Kerr)
[#&#8203;63001](https://redirect.github.com/nodejs/node/pull/63001)
-
\[[`b6219b6362`](https://redirect.github.com/nodejs/node/commit/b6219b6362)]
- **src**: fix crash in GetErrorSource() for invalid using syntax
(semimikoh)
[#&#8203;62770](https://redirect.github.com/nodejs/node/pull/62770)
-
\[[`b5ca5ad4c5`](https://redirect.github.com/nodejs/node/commit/b5ca5ad4c5)]
- **src**: simplify `TCPWrap::Connect` signature (Anna Henningsen)
[#&#8203;62929](https://redirect.github.com/nodejs/node/pull/62929)
-
\[[`ef7ffce7cf`](https://redirect.github.com/nodejs/node/commit/ef7ffce7cf)]
- **src**: use DCHECK in AsyncWrap::MakeCallback instead emiting a
warning (Gerhard Stöbich)
[#&#8203;62795](https://redirect.github.com/nodejs/node/pull/62795)
-
\[[`cd9890a5ab`](https://redirect.github.com/nodejs/node/commit/cd9890a5ab)]
- **src**: fix MaybeStackBuffer char\_traits deprecation warning
(om-ghante)
[#&#8203;62507](https://redirect.github.com/nodejs/node/pull/62507)
-
\[[`c70ff44aee`](https://redirect.github.com/nodejs/node/commit/c70ff44aee)]
- **src**: use context-free V8 message column getters (René)
[#&#8203;62778](https://redirect.github.com/nodejs/node/pull/62778)
-
\[[`06c405f1d7`](https://redirect.github.com/nodejs/node/commit/06c405f1d7)]
- **src**: coerce `spawnSync` args to string once (Antoine du Hamel)
[#&#8203;62633](https://redirect.github.com/nodejs/node/pull/62633)
-
\[[`6151999ad6`](https://redirect.github.com/nodejs/node/commit/6151999ad6)]
- **src**: use stack allocation for small string encoding (Ali Hassan)
[#&#8203;62431](https://redirect.github.com/nodejs/node/pull/62431)
-
\[[`a71a4ac7a3`](https://redirect.github.com/nodejs/node/commit/a71a4ac7a3)]
- **src**: add contextify interceptor debug logs (Chengzhong Wu)
[#&#8203;62460](https://redirect.github.com/nodejs/node/pull/62460)
-
\[[`ad9a2909c2`](https://redirect.github.com/nodejs/node/commit/ad9a2909c2)]
- **src**: workaround AIX libc++ std::filesystem bug (Richard Lau)
[#&#8203;62788](https://redirect.github.com/nodejs/node/pull/62788)
-
\[[`7792f1ae47`](https://redirect.github.com/nodejs/node/commit/7792f1ae47)]
- **stream**: copyedit `webstreams/adapter.js` (Antoine du Hamel)
[#&#8203;63034](https://redirect.github.com/nodejs/node/pull/63034)
-
\[[`1397d8ce5c`](https://redirect.github.com/nodejs/node/commit/1397d8ce5c)]
- **stream**: remove duplicated utility (Antoine du Hamel)
[#&#8203;63031](https://redirect.github.com/nodejs/node/pull/63031)
-
\[[`ff86b1d64f`](https://redirect.github.com/nodejs/node/commit/ff86b1d64f)]
- **stream**: simplify `setPromiseHandled` utility (Antoine du Hamel)
[#&#8203;63032](https://redirect.github.com/nodejs/node/pull/63032)
-
\[[`24a078149a`](https://redirect.github.com/nodejs/node/commit/24a078149a)]
- **stream**: validate ReadableStream.from iterator objects (Daeyeon
Jeong)
[#&#8203;62911](https://redirect.github.com/nodejs/node/pull/62911)
-
\[[`cfb1fa9680`](https://redirect.github.com/nodejs/node/commit/cfb1fa9680)]
- **stream**: reject duplicate nested transferables (Daeyeon Jeong)
[#&#8203;62831](https://redirect.github.com/nodejs/node/pull/62831)
-
\[[`d0c913758a`](https://redirect.github.com/nodejs/node/commit/d0c913758a)]
- **stream**: ensuring cross-destruction in \_duplexify to prevent leaks
(Daijiro Wachi)
[#&#8203;62824](https://redirect.github.com/nodejs/node/pull/62824)
-
\[[`978f5c15d7`](https://redirect.github.com/nodejs/node/commit/978f5c15d7)]
- **stream**: simplify `readableStreamFromIterable` (Antoine du Hamel)
[#&#8203;62651](https://redirect.github.com/nodejs/node/pull/62651)
-
\[[`3527646ba5`](https://redirect.github.com/nodejs/node/commit/3527646ba5)]
- **stream**: fix nested compose error propagation (Matteo Collina)
[#&#8203;62556](https://redirect.github.com/nodejs/node/pull/62556)
-
\[[`dfb9edef4f`](https://redirect.github.com/nodejs/node/commit/dfb9edef4f)]
- **stream**: allow shared array buffer sources in writable webstream
adapter (René)
[#&#8203;62163](https://redirect.github.com/nodejs/node/pull/62163)
-
\[[`f00cdab627`](https://redirect.github.com/nodejs/node/commit/f00cdab627)]
- **stream**: simplify `createPromiseCallback` (Antoine du Hamel)
[#&#8203;62650](https://redirect.github.com/nodejs/node/pull/62650)
-
\[[`3ed783535f`](https://redirect.github.com/nodejs/node/commit/3ed783535f)]
- **stream**: fix writev unhandled rejection in fromWeb (sangwook)
[#&#8203;62297](https://redirect.github.com/nodejs/node/pull/62297)
-
\[[`29b196694c`](https://redirect.github.com/nodejs/node/commit/29b196694c)]
- **stream**: noop pause/resume on destroyed streams (Robert Nagy)
[#&#8203;62557](https://redirect.github.com/nodejs/node/pull/62557)
-
\[[`d73dbb9fc8`](https://redirect.github.com/nodejs/node/commit/d73dbb9fc8)]
- **stream**: refactor duplexify to be less suceptible to prototype
pollution (Antoine du Hamel)
[#&#8203;62559](https://redirect.github.com/nodejs/node/pull/62559)
-
\[[`6f37f7e240`](https://redirect.github.com/nodejs/node/commit/6f37f7e240)]
- **(SEMVER-MINOR)** **stream**: propagate destruction in duplexPair
(Ahmed Elhor)
[#&#8203;61098](https://redirect.github.com/nodejs/node/pull/61098)
-
\[[`b8816580e9`](https://redirect.github.com/nodejs/node/commit/b8816580e9)]
- **test**: generate `localstorage.db` in a temp dir (Chengzhong Wu)
[#&#8203;62660](https://redirect.github.com/nodejs/node/pull/62660)
-
\[[`31a863fd29`](https://redirect.github.com/nodejs/node/commit/31a863fd29)]
- **test**: update WPT for url to
[`258f285`](https://redirect.github.com/nodejs/node/commit/258f285de0)
(Node.js GitHub Bot)
[#&#8203;63087](https://redirect.github.com/nodejs/node/pull/63087)
-
\[[`d0d19bd8e3`](https://redirect.github.com/nodejs/node/commit/d0d19bd8e3)]
- **test**: update WPT for streams to
[`f8f26a3`](https://redirect.github.com/nodejs/node/commit/f8f26a372f)
(Node.js GitHub Bot)
[#&#8203;62864](https://redirect.github.com/nodejs/node/pull/62864)
-
\[[`f50ac5bc78`](https://redirect.github.com/nodejs/node/commit/f50ac5bc78)]
- **test**: improve config-file permission test coverage (Rafael
Gonzaga)
[#&#8203;60929](https://redirect.github.com/nodejs/node/pull/60929)
-
\[[`a0f90000f4`](https://redirect.github.com/nodejs/node/commit/a0f90000f4)]
- **test**: export isRiscv64 from common module (Jamie Magee)
[#&#8203;62609](https://redirect.github.com/nodejs/node/pull/62609)
-
\[[`da4dd8646f`](https://redirect.github.com/nodejs/node/commit/da4dd8646f)]
- **test**: normalize known inspector crash as completion (Joyee Cheung)
[#&#8203;62851](https://redirect.github.com/nodejs/node/pull/62851)
-
\[[`b7fdd94a4c`](https://redirect.github.com/nodejs/node/commit/b7fdd94a4c)]
- **test**: account for RFC 7919 FFDHE negotiation in OpenSSL 4.0 (Filip
Skokan)
[#&#8203;62805](https://redirect.github.com/nodejs/node/pull/62805)
-
\[[`375a993aaf`](https://redirect.github.com/nodejs/node/commit/375a993aaf)]
- **test**: skip tls-deprecated secp256k1 on OpenSSL 4.0 (Filip Skokan)
[#&#8203;62805](https://redirect.github.com/nodejs/node/pull/62805)
-
\[[`698d8287d1`](https://redirect.github.com/nodejs/node/commit/698d8287d1)]
- **test**: use an always invalid cipher and cover OpenSSL 4.0
behaviours (Filip Skokan)
[#&#8203;62805](https://redirect.github.com/nodejs/node/pull/62805)
-
\[[`036bc6f300`](https://redirect.github.com/nodejs/node/commit/036bc6f300)]
- **test**: use valid DER OCSP responses (Filip Skokan)
[#&#8203;62805](https://redirect.github.com/nodejs/node/pull/62805)
-
\[[`3aa9938da8`](https://redirect.github.com/nodejs/node/commit/3aa9938da8)]
- **test**: skip test-tls-error-stack when engines are unsupported
(Filip Skokan)
[#&#8203;62805](https://redirect.github.com/nodejs/node/pull/62805)
-
\[[`947f1ae246`](https://redirect.github.com/nodejs/node/commit/947f1ae246)]
- **test**: accept renamed OpenSSL 4.0 error code and reason (Filip
Skokan)
[#&#8203;62805](https://redirect.github.com/nodejs/node/pull/62805)
-
\[[`afdd355622`](https://redirect.github.com/nodejs/node/commit/afdd355622)]
- **test**: update test/addons/openssl-binding for OpenSSL 4.0 (Filip
Skokan)
[#&#8203;62805](https://redirect.github.com/nodejs/node/pull/62805)
-
\[[`8637524a99`](https://redirect.github.com/nodejs/node/commit/8637524a99)]
- **test**: mark test-snapshot-reproducible flaky (Filip Skokan)
[#&#8203;62808](https://redirect.github.com/nodejs/node/pull/62808)
-
\[[`c22d34134b`](https://redirect.github.com/nodejs/node/commit/c22d34134b)]
- **test**: check contextify contextual store behavior in strict mode
(René)
[#&#8203;62571](https://redirect.github.com/nodejs/node/pull/62571)
-
\[[`0b4e0d3c94`](https://redirect.github.com/nodejs/node/commit/0b4e0d3c94)]
- **test**: update tls junk data error expectations (Filip Skokan)
[#&#8203;62629](https://redirect.github.com/nodejs/node/pull/62629)
-
\[[`85d83c2cdb`](https://redirect.github.com/nodejs/node/commit/85d83c2cdb)]
- **test**: ensure WPT report is in out/wpt (Filip Skokan)
[#&#8203;62637](https://redirect.github.com/nodejs/node/pull/62637)
-
\[[`9e21711c60`](https://redirect.github.com/nodejs/node/commit/9e21711c60)]
- **test**: improve WPT runner summary (Filip Skokan)
[#&#8203;62636](https://redirect.github.com/nodejs/node/pull/62636)
-
\[[`e04e2c9ac1`](https://redirect.github.com/nodejs/node/commit/e04e2c9ac1)]
- **test**: skip url WPT subtests instead of modifying test script
(Filip Skokan)
[#&#8203;62635](https://redirect.github.com/nodejs/node/pull/62635)
-
\[[`7b1211f88c`](https://redirect.github.com/nodejs/node/commit/7b1211f88c)]
- **test**: capture negative utimes mtime at call time (Yuya Inoue)
[#&#8203;62490](https://redirect.github.com/nodejs/node/pull/62490)
-
\[[`f1a6e9fcc7`](https://redirect.github.com/nodejs/node/commit/f1a6e9fcc7)]
- **test**: allow skipping individual WPT subtests (Filip Skokan)
[#&#8203;62517](https://redirect.github.com/nodejs/node/pull/62517)
-
\[[`23f927542e`](https://redirect.github.com/nodejs/node/commit/23f927542e)]
- **test**: use on-disk fixture for test-npm-install (Joyee Cheung)
[#&#8203;62584](https://redirect.github.com/nodejs/node/pull/62584)
-
\[[`4739c45879`](https://redirect.github.com/nodejs/node/commit/4739c45879)]
- **test**: update WPT for url to
[`7a3645b`](https://redirect.github.com/nodejs/node/commit/7a3645b79a)
(Node.js GitHub Bot)
[#&#8203;62591](https://redirect.github.com/nodejs/node/pull/62591)
-
\[[`f68189b839`](https://redirect.github.com/nodejs/node/commit/f68189b839)]
- **test\_runner**: add `testId` to test events (Moshe Atlow)
[#&#8203;62772](https://redirect.github.com/nodejs/node/pull/62772)
-
\[[`5c2770446e`](https://redirect.github.com/nodejs/node/commit/5c2770446e)]
- **test\_runner**: publish to TracingChannel for OTel instrumentation
(Moshe Atlow)
[#&#8203;62502](https://redirect.github.com/nodejs/node/pull/62502)
-
\[[`d14029be7f`](https://redirect.github.com/nodejs/node/commit/d14029be7f)]
- **(SEMVER-MINOR)** **test\_runner**: support test order randomization
(Pietro Marchini)
[#&#8203;61747](https://redirect.github.com/nodejs/node/pull/61747)
-
\[[`3f74a58979`](https://redirect.github.com/nodejs/node/commit/3f74a58979)]
- **test\_runner**: update node-config-schema (Pietro Marchini)
[#&#8203;58680](https://redirect.github.com/nodejs/node/pull/58680)
-
\[[`60c83f6199`](https://redirect.github.com/nodejs/node/commit/60c83f6199)]
- **test\_runner**: fix failing suite hooks when marked with `todo`
(Moshe Atlow)
[#&#8203;63097](https://redirect.github.com/nodejs/node/pull/63097)
-
\[[`d142c584cd`](https://redirect.github.com/nodejs/node/commit/d142c584cd)]
- **(SEMVER-MINOR)** **test\_runner**: align mock timeout api (sangwook)
[#&#8203;62820](https://redirect.github.com/nodejs/node/pull/62820)
-
\[[`3e72065ed6`](https://redirect.github.com/nodejs/node/commit/3e72065ed6)]
- **test\_runner**: fix suite rerun edge case (Moshe Atlow)
[#&#8203;62860](https://redirect.github.com/nodejs/node/pull/62860)
-
\[[`01a9552585`](https://redirect.github.com/nodejs/node/commit/01a9552585)]
- **(SEMVER-MINOR)** **test\_runner**: add mock-timers support for
AbortSignal.timeout (DeveloperViraj)
[#&#8203;60751](https://redirect.github.com/nodejs/node/pull/60751)
-
\[[`dd43efffa6`](https://redirect.github.com/nodejs/node/commit/dd43efffa6)]
- **test\_runner**: add passed, attempt, and diagnostic to SuiteContext
(Moshe Atlow)
[#&#8203;62504](https://redirect.github.com/nodejs/node/pull/62504)
-
\[[`a12dc445cc`](https://redirect.github.com/nodejs/node/commit/a12dc445cc)]
- **tools**: add a check for clean git tree after tests (Antoine du
Hamel)
[#&#8203;62661](https://redirect.github.com/nodejs/node/pull/62661)
-
\[[`5b49178375`](https://redirect.github.com/nodejs/node/commit/5b49178375)]
- **tools**: use LTS Node.js in notify-on-push workflow (Nenad Spasenic)
[#&#8203;63084](https://redirect.github.com/nodejs/node/pull/63084)
-
\[[`5a93bde5bb`](https://redirect.github.com/nodejs/node/commit/5a93bde5bb)]
- **tools**: update gr2m/create-or-update-pull-request-action to v1.10.1
(Mike McCready)
[#&#8203;63065](https://redirect.github.com/nodejs/node/pull/63065)
-
\[[`b133019d19`](https://redirect.github.com/nodejs/node/commit/b133019d19)]
- **tools**: simplify `update-undici.sh` (Antoine du Hamel)
[#&#8203;63044](https://redirect.github.com/nodejs/node/pull/63044)
-
\[[`04d3538074`](https://redirect.github.com/nodejs/node/commit/04d3538074)]
- **tools**: do not run `test-linux` on unrelated tools changes (Antoine
du Hamel)
[#&#8203;63037](https://redirect.github.com/nodejs/node/pull/63037)
-
\[[`4d396ac4a5`](https://redirect.github.com/nodejs/node/commit/4d396ac4a5)]
- **tools**: bump the eslint group in /tools/eslint with 4 updates
(dependabot\[bot])
[#&#8203;62848](https://redirect.github.com/nodejs/node/pull/62848)
-
\[[`9354bf40e7`](https://redirect.github.com/nodejs/node/commit/9354bf40e7)]
- **tools**: update gyp-next to 0.22.1 (Node.js GitHub Bot)
[#&#8203;62961](https://redirect.github.com/nodejs/node/pull/62961)
-
\[[`c23db1ca85`](https://redirect.github.com/nodejs/node/commit/c23db1ca85)]
- **tools**: fix commit linter for semver-major release proposals
(Antoine du Hamel)
[#&#8203;62993](https://redirect.github.com/nodejs/node/pull/62993)
-
\[[`6e097ee3f1`](https://redirect.github.com/nodejs/node/commit/6e097ee3f1)]
- **tools**: consolidate and simplify .editorconfig deps section
(Daijiro Wachi)
[#&#8203;62887](https://redirect.github.com/nodejs/node/pull/62887)
-
\[[`a47ea6d6ea`](https://redirect.github.com/nodejs/node/commit/a47ea6d6ea)]
- **tools**: set bot as author of tools-deps-update PRs (Antoine du
Hamel)
[#&#8203;62856](https://redirect.github.com/nodejs/node/pull/62856)
-
\[[`00e86f0471`](https://redirect.github.com/nodejs/node/commit/00e86f0471)]
- **tools**: bump brace-expansion from 5.0.4 to 5.0.5 in /tools/eslint
(dependabot\[bot])
[#&#8203;62458](https://redirect.github.com/nodejs/node/pull/62458)
-
\[[`cd7e262e75`](https://redirect.github.com/nodejs/node/commit/cd7e262e75)]
- **tools**: bump brace-expansion in /tools/clang-format
(dependabot\[bot])
[#&#8203;62467](https://redirect.github.com/nodejs/node/pull/62467)
-
\[[`bfc1319bc8`](https://redirect.github.com/nodejs/node/commit/bfc1319bc8)]
- **tools**: exclude
[@&#8203;node-core/doc-kit](https://redirect.github.com/node-core/doc-kit)
from dependabot cooldown (Levi Zim)
[#&#8203;62775](https://redirect.github.com/nodejs/node/pull/62775)
-
\[[`a932fbd10b`](https://redirect.github.com/nodejs/node/commit/a932fbd10b)]
- **tools**: re-enable undici WPTs in daily wpt.fyi job (Filip Skokan)
[#&#8203;62677](https://redirect.github.com/nodejs/node/pull/62677)
-
\[[`f7bd9e3055`](https://redirect.github.com/nodejs/node/commit/f7bd9e3055)]
- **tools**: update gyp-next to 0.22.0 (Node.js GitHub Bot)
[#&#8203;62697](https://redirect.github.com/nodejs/node/pull/62697)
-
\[[`c400d46d87`](https://redirect.github.com/nodejs/node/commit/c400d46d87)]
- **tools**: improve backport review script (Antoine du Hamel)
[#&#8203;62573](https://redirect.github.com/nodejs/node/pull/62573)
-
\[[`be23b75814`](https://redirect.github.com/nodejs/node/commit/be23b75814)]
- **tools**: improve output for unexpected passes in WTP tests (Antoine
du Hamel)
[#&#8203;62587](https://redirect.github.com/nodejs/node/pull/62587)
-
\[[`609c013ece`](https://redirect.github.com/nodejs/node/commit/609c013ece)]
- **tools**: revert OpenSSL update workflow to ubuntu-latest (Richard
Lau) [#&#8203;62627](https://redirect.github.com/nodejs/node/pull/62627)
-
\[[`81bac1ebfd`](https://redirect.github.com/nodejs/node/commit/81bac1ebfd)]
- **tools**: bump the eslint group in /tools/eslint with 2 updates
(dependabot\[bot])
[#&#8203;62552](https://redirect.github.com/nodejs/node/pull/62552)
-
\[[`1fee26522d`](https://redirect.github.com/nodejs/node/commit/1fee26522d)]
- **tools**: allow triagers to queue a PR for CI until it's reviewed
(Antoine du Hamel)
[#&#8203;62524](https://redirect.github.com/nodejs/node/pull/62524)
-
\[[`332088f929`](https://redirect.github.com/nodejs/node/commit/332088f929)]
- **tools**: do not run `commit-lint` on release proposals (Antoine du
Hamel)
[#&#8203;62523](https://redirect.github.com/nodejs/node/pull/62523)
-
\[[`9a25fc8a4d`](https://redirect.github.com/nodejs/node/commit/9a25fc8a4d)]
- **url**: process crash via malformed UNC hostname in pathToFileURL()
(Nicola Del Gobbo)
[#&#8203;62574](https://redirect.github.com/nodejs/node/pull/62574)
-
\[[`7bd08ff60a`](https://redirect.github.com/nodejs/node/commit/7bd08ff60a)]
- **url**: optimize URLSearchParams set/delete duplicate handling
(Gürgün Dayıoğlu)
[#&#8203;62266](https://redirect.github.com/nodejs/node/pull/62266)
-
\[[`2d636388fa`](https://redirect.github.com/nodejs/node/commit/2d636388fa)]
- **url**: align default argument handling for URLPattern with webidl
(Filip Skokan)
[#&#8203;62719](https://redirect.github.com/nodejs/node/pull/62719)
-
\[[`00705a459a`](https://redirect.github.com/nodejs/node/commit/00705a459a)]
- **(SEMVER-MINOR)** **util**: colorize text with hex colors (Guilherme
Araújo)
[#&#8203;61556](https://redirect.github.com/nodejs/node/pull/61556)
-
\[[`0e2adb3e45`](https://redirect.github.com/nodejs/node/commit/0e2adb3e45)]
- **watch**: track worker entry files in watch mode (SudhansuBandha)
[#&#8203;62368](https://redirect.github.com/nodejs/node/pull/62368)
-
\[[`c58fe38211`](https://redirect.github.com/nodejs/node/commit/c58fe38211)]
- **watch**: fix --env-file-if-exists crashing on linux if the file is
missing (Efe)
[#&#8203;61870](https://redirect.github.com/nodejs/node/pull/61870)

###
[`v24.15.0`](https://redirect.github.com/nodejs/node/compare/v24.14.1...v24.15.0)

[Compare
Source](https://redirect.github.com/nodejs/node/compare/v24.14.1...v24.15.0)

###
[`v24.14.1`](https://redirect.github.com/nodejs/node/compare/v24.14.0...v24.14.1)

[Compare
Source](https://redirect.github.com/nodejs/node/compare/v24.14.0...v24.14.1)

###
[`v24.14.0`](https://redirect.github.com/nodejs/node/compare/v24.13.1...v24.14.0)

[Compare
Source](https://redirect.github.com/nodejs/node/compare/v24.13.1...v24.14.0)

###
[`v24.13.1`](https://redirect.github.com/nodejs/node/compare/v24.13.0...v24.13.1)

[Compare
Source](https://redirect.github.com/nodejs/node/compare/v24.13.0...v24.13.1)

###
[`v24.13.0`](https://redirect.github.com/nodejs/node/releases/tag/v24.13.0):
2026-01-13, Version 24.13.0 'Krypton' (LTS), @&#8203;marco-ippolito

[Compare
Source](https://redirect.github.com/nodejs/node/compare/v24.12.0...v24.13.0)

This is a security release.

##### Notable Changes

lib:

- (CVE-2025-59465) add TLSSocket default error handler (RafaelGSS)
[nodejs-private/node-private#797](https://redirect.github.com/nodejs-private/node-private/pull/797)
- (CVE-2025-55132) disable futimes when permission model is enabled
(RafaelGSS)
[nodejs-private/node-private#748](https://redirect.github.com/nodejs-private/node-private/pull/748)
  lib,permission:
- (CVE-2025-55130) require full read and write to symlink APIs
(RafaelGSS)
[nodejs-private/node-private#760](https://redirect.github.com/nodejs-private/node-private/pull/760)
  src:
- (CVE-2025-59466) rethrow stack overflow exceptions in async\_hooks
(Matteo Collina)
[nodejs-private/node-private#773](https://redirect.github.com/nodejs-private/node-private/pull/773)
  src,lib:
- (CVE-2025-55131) refactor unsafe buffer creation to remove zero-fill
toggle (Сковорода Никита Андреевич)
[nodejs-private/node-private#759](https://redirect.github.com/nodejs-private/node-private/pull/759)
  tls:
- (CVE-2026-21637) route callback exceptions through error handlers
(Matteo Collina)
[nodejs-private/node-private#796](https://redirect.github.com/nodejs-private/node-private/pull/796)

##### Commits

-
\[[`2092785d01`](https://redirect.github.com/nodejs/node/commit/2092785d01)]
- **deps**: update c-ares to v1.34.6 (Node.js GitHub Bot)
[#&#8203;60997](https://redirect.github.com/nodejs/node/pull/60997)
-
\[[`3e58b7f2af`](https://redirect.github.com/nodejs/node/commit/3e58b7f2af)]
- **deps**: update undici to 7.18.2 (Node.js GitHub Bot)
[#&#8203;61283](https://redirect.github.com/nodejs/node/pull/61283)
-
\[[`4ba536a5a6`](https://redirect.github.com/nodejs/node/commit/4ba536a5a6)]
- **(CVE-2025-59465)** **lib**: add TLSSocket default error handler
(RafaelGSS)
[nodejs-private/node-private#797](https://redirect.github.com/nodejs-private/node-private/pull/797)
-
\[[`89adaa21fd`](https://redirect.github.com/nodejs/node/commit/89adaa21fd)]
- **(CVE-2025-55132)** **lib**: disable futimes when permission model is
enabled (RafaelGSS)
[nodejs-private/node-private#748](https://redirect.github.com/nodejs-private/node-private/pull/748)
-
\[[`7302b4dae1`](https://redirect.github.com/nodejs/node/commit/7302b4dae1)]
- **(CVE-2025-55130)** **lib,permission**: require full read and write
to symlink APIs (RafaelGSS)
[nodejs-private/node-private#760](https://redirect.github.com/nodejs-private/node-private/pull/760)
- \[[`ac030753c4`](https://redi

> ✂ **Note**
> 
> PR body was truncated to here.


</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 6am on monday"
- Automerge
  - At any time (no schedule defined)

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

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/sleepypod/core).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMTAuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE5NC4wIiwidGFyZ2V0QnJhbmNoIjoiZGV2IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyIsIm1ham9yIl19-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
## Why

PR #416 bumped `.node-version` `22` → `24`, but that file only drives
**dev/CI** (`actions/setup-node` reads `node-version-file:
'.node-version'`). The **pod runtime** version is pinned independently
in `scripts/install` (`NODE_WANTED` / `NODE_FULL`), so fresh pods would
still install Node 22 — leaving dev/CI and production out of lockstep.

## What

Bump the pod's Node pin to `24.16.0` (current v24 LTS, 'Krypton') so
freshly-installed pods match the toolchain.

## Safety

`better-sqlite3` (the only native dep) ships **N-API prebuilds**
(`prebuilds/linux-<arch>/node.napi.node`) and is `pnpm install`-ed **on
the pod**, not bundled from CI. N-API is ABI-stable across Node majors,
so the 22 → 24 move carries no native-module ABI risk. The install
script's existing SHA-256 verification covers the new tarball.

The `CURRENT_NODE_MAJOR -lt NODE_WANTED` guard means pods already on
Node ≥ 24 are left untouched; pods on 22 get upgraded on next install
run.

## Test plan

- `bash -n scripts/install` — syntax clean ✅
- Verified
`https://nodejs.org/dist/v24.16.0/node-v24.16.0-linux-arm64.tar.gz`
returns HTTP 200 ✅
- Manual: run installer on a clean pod, confirm `node -v` reports
v24.16.0 and the app's better-sqlite3 module loads

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update chore/install-node-24
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/chore/install-node-24/scripts/install \
  | sudo bash -s -- --branch chore/install-node-24
```

🎯 **Pin to this exact build** ([run
27525355981](https://github.com/sleepypod/core/actions/runs/27525355981)
· `f1338bb`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/f1338bb773b7c850ef61950cc71f7de5df5fddb9/scripts/install \
  | sudo bash -s -- \
      --branch chore/install-node-24 \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27525355981/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27525355981/artifacts/7629546769)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [typescript](https://www.typescriptlang.org/)
([source](https://redirect.github.com/microsoft/TypeScript)) | [`^5.9.3`
→ `^6.0.0`](https://renovatebot.com/diffs/npm/typescript/5.9.3/6.0.3) |
![age](https://developer.mend.io/api/mc/badges/age/npm/typescript/6.0.3?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript/5.9.3/6.0.3?slim=true)
|

---

### Release Notes

<details>
<summary>microsoft/TypeScript (typescript)</summary>

###
[`v6.0.3`](https://redirect.github.com/microsoft/TypeScript/compare/v6.0.2...050880ce59e30b356b686bd3144efe24f875ebc8)

[Compare
Source](https://redirect.github.com/microsoft/TypeScript/compare/v6.0.2...v6.0.3)

###
[`v6.0.2`](https://redirect.github.com/microsoft/TypeScript/compare/v5.9.3...607a22a90d1a5a1b507ce01bb8cd7ec020f954e7)

[Compare
Source](https://redirect.github.com/microsoft/TypeScript/compare/v5.9.3...v6.0.2)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 6am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

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

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/sleepypod/core).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDIuNyIsInVwZGF0ZWRJblZlciI6IjQzLjIxOS4wIiwidGFyZ2V0QnJhbmNoIjoiZGV2IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyIsIm1ham9yIl19-->

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update renovate/typescript-6.x
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/renovate/typescript-6.x/scripts/install \
  | sudo bash -s -- --branch renovate/typescript-6.x
```

🎯 **Pin to this exact build** ([run
27526054951](https://github.com/sleepypod/core/actions/runs/27526054951)
· `3003ac9`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/3003ac964101578340465f6d642934110c9f35b1/scripts/install \
  | sudo bash -s -- \
      --branch renovate/typescript-6.x \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27526054951/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27526054951/artifacts/7629783757)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Ng <jon@jonathanng.com>
## Problem

The `piezoStream` streaming tests flaked intermittently in CI (e.g.
blocked #650 and #315), each run failing a *different* test in
`src/streaming/tests/piezoStream.test.ts` with `waitFor`/`waitUntil`
timeouts and a trailing `Hook timed out in 10000ms`. They always passed
in isolation, which masked the cause as "slow CI."

## Root cause

Two compounding bugs:

1. **Permanent frame loss from a connect race.** The file-tailing loop
broadcasts live frames *only to currently-connected clients* (no
backfill) and advances its read offset to EOF on the first 10ms tick.
Tests that wrote the RAW file **before** connecting raced that first
tick — under CPU contention the loop consumed the whole file before the
client socket attached, so those frames were lost for good. Confirmed
empirically: even with a 20s wait timeout the frames never arrived
(`messages=[]`), proving permanent loss rather than slow delivery.

2. **Teardown hang cascade.** `WebSocketServer.close()` only fires its
callback once every client has disconnected. When a test bailed before
`client.close()` (because of #1), the still-open socket kept
`shutdownPiezoStreamServer()` from ever resolving → the `afterEach` hook
burned its full 10s timeout and reported a second failure.

## Fix

- **Tests:** append RAW data only *after* the client connects, matching
production (firmware appends to the RAW file while clients stream). This
is the deterministic pattern a few tests already used (`subscribe
filter`, `partial trailing record`). A comment on the `startAndPort`
helper documents the ordering so it isn't "tidied" back.
- **Production (`shutdownPiezoStreamServer`):** terminate live client
sockets before `server.close()` so shutdown always completes — a real
robustness bug, not test-only.

## Test plan

- `pnpm run tsc` — clean
- `eslint` on both changed files — clean
- Full suite: `pnpm test run` → 109 files / 2124 passed, 1 skipped
- **Repro harness:** saturate all cores (`yes > /dev/null` ×2·ncpu) and
run the piezo file repeatedly:
- Before: failed within ~2 runs (different test each time, `messages=[]`
+ 10s hook timeout)
  - After: **6/6 green** under the same saturation; 3/3 in isolation

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update fix/piezo-stream-test-flake
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/fix/piezo-stream-test-flake/scripts/install \
  | sudo bash -s -- --branch fix/piezo-stream-test-flake
```

🎯 **Pin to this exact build** ([run
27527119653](https://github.com/sleepypod/core/actions/runs/27527119653)
· `1ace69b`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/1ace69bbd3bbf7232c2f6341b09052534dacd5fc/scripts/install \
  | sudo bash -s -- \
      --branch fix/piezo-stream-test-flake \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27527119653/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27527119653/artifacts/7630170313)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Bug Fixes**
* Fixed server shutdown hang issue when WebSocket clients remain
connected during shutdown process.

* **Tests**
* Updated streaming protocol tests to eliminate race conditions in data
handling scenarios.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What

Adds mutation-killing tests for `src/server/routers/system.ts`, the
single largest cluster of surviving mutants in the weekly
mutation-testing baseline (#591 — 167 surviving in that file).

## Why

The existing suite asserted **outcomes** (parsed return values, error
wrapping) but never the **exact commands** the router shells out. As a
result every `StringLiteral` / `ArrayDeclaration` / `ObjectLiteral`
mutant on the `df` / `du` / `iptables` / `journalctl` / `systemctl` /
`nmcli` invocations survived — you could swap `'iptables'` for `''`,
drop the `{ timeout }` option, or empty out an argv array and no test
noticed. A handful of `Regex` / `ConditionalExpression` /
`ArithmeticOperator` mutants also survived because single-space test
fixtures never exercised them.

## How

A `recordExec` helper captures every `execFile` call (binary, argv,
options object) so tests can assert the literal commands, plus targeted
edge-case fixtures:

- **internetStatus** — `iptables -L OUTPUT -n`; anchored `^DROP\b`
matching (a mid-line `DROP` and `DROPLET` must **not** read as blocked)
- **setInternetAccess** — the complete ordered iptables flush + LAN-only
ruleset for both block and unblock paths, and that rules are persisted
from `iptables-save`
- **wifiStatus / getLogSources / getLogs / getDiskUsage /
getStorageBreakdown** — exact argv + `timeout`/`maxBuffer` option
objects, service display names
- **edge fixtures** — multi-whitespace `df` output (so `/\s+/` vs `/\s/`
actually matters), zero-total `usedPercent` guard (no `Infinity`), the
`lines + 1` pagination boundary (`>` vs `>=`), and the `"Unknown error"`
/ log-message branches

## Result

`system.ts` mutation score **~52% → 94.5%** (167 → 17 survivors; the
remainder are equivalent mutants — optional chaining on always-defined
values, a no-op `nextCursor = null`, `/\s/` on a `[0]` access). Verified
with `npx stryker run --mutate 'src/server/routers/system.ts'`.

**No production code changed** — tests only. `pnpm vitest run` (51
pass), `tsc --noEmit`, and `eslint` all green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update test/system-router-mutants-591
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/test/system-router-mutants-591/scripts/install \
  | sudo bash -s -- --branch test/system-router-mutants-591
```

🎯 **Pin to this exact build** ([run
27884384868](https://github.com/sleepypod/core/actions/runs/27884384868)
· `6c639a1`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/6c639a17e3c173ab0c9cc36e929b24e3102f7a83/scripts/install \
  | sudo bash -s -- \
      --branch test/system-router-mutants-591 \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27884384868/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27884384868/artifacts/7769047411)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Tests**
* Expanded test coverage for system router endpoints, including
validation of command execution, error handling, and edge cases across
system operations.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@base-ui/react](https://base-ui.com)
([source](https://redirect.github.com/mui/base-ui/tree/HEAD/packages/react))
| [`1.5.0` →
`1.6.0`](https://renovatebot.com/diffs/npm/@base-ui%2freact/1.5.0/1.6.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@base-ui%2freact/1.6.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@base-ui%2freact/1.5.0/1.6.0?slim=true)
|
| [@tailwindcss/postcss](https://tailwindcss.com)
([source](https://redirect.github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss))
| [`4.3.0` →
`4.3.1`](https://renovatebot.com/diffs/npm/@tailwindcss%2fpostcss/4.3.0/4.3.1)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@tailwindcss%2fpostcss/4.3.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@tailwindcss%2fpostcss/4.3.0/4.3.1?slim=true)
|
| [@trpc/client](https://trpc.io)
([source](https://redirect.github.com/trpc/trpc/tree/HEAD/packages/client))
| [`11.17.0` →
`11.18.0`](https://renovatebot.com/diffs/npm/@trpc%2fclient/11.17.0/11.18.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@trpc%2fclient/11.18.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@trpc%2fclient/11.17.0/11.18.0?slim=true)
|
| [@trpc/next](https://trpc.io)
([source](https://redirect.github.com/trpc/trpc/tree/HEAD/packages/next))
| [`11.17.0` →
`11.18.0`](https://renovatebot.com/diffs/npm/@trpc%2fnext/11.17.0/11.18.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@trpc%2fnext/11.18.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@trpc%2fnext/11.17.0/11.18.0?slim=true)
|
| [@trpc/react-query](https://trpc.io)
([source](https://redirect.github.com/trpc/trpc/tree/HEAD/packages/react))
| [`11.17.0` →
`11.18.0`](https://renovatebot.com/diffs/npm/@trpc%2freact-query/11.17.0/11.18.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@trpc%2freact-query/11.18.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@trpc%2freact-query/11.17.0/11.18.0?slim=true)
|
| [@trpc/server](https://trpc.io)
([source](https://redirect.github.com/trpc/trpc/tree/HEAD/packages/server))
| [`11.17.0` →
`11.18.0`](https://renovatebot.com/diffs/npm/@trpc%2fserver/11.17.0/11.18.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@trpc%2fserver/11.18.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@trpc%2fserver/11.17.0/11.18.0?slim=true)
|
|
[@types/node](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node))
| [`25.9.3` →
`25.9.4`](https://renovatebot.com/diffs/npm/@types%2fnode/25.9.3/25.9.4)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2fnode/25.9.4?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2fnode/25.9.3/25.9.4?slim=true)
|
| [@vitest/coverage-v8](https://vitest.dev/guide/coverage)
([source](https://redirect.github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8))
| [`4.1.8` →
`4.1.9`](https://renovatebot.com/diffs/npm/@vitest%2fcoverage-v8/4.1.8/4.1.9)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@vitest%2fcoverage-v8/4.1.9?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@vitest%2fcoverage-v8/4.1.8/4.1.9?slim=true)
|
| [better-sqlite3](https://redirect.github.com/WiseLibs/better-sqlite3)
| [`12.10.0` →
`12.11.1`](https://renovatebot.com/diffs/npm/better-sqlite3/12.10.0/12.11.1)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/better-sqlite3/12.11.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/better-sqlite3/12.10.0/12.11.1?slim=true)
|
| [lucide-react](https://lucide.dev)
([source](https://redirect.github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react))
| [`1.17.0` →
`1.21.0`](https://renovatebot.com/diffs/npm/lucide-react/1.17.0/1.21.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/lucide-react/1.21.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lucide-react/1.17.0/1.21.0?slim=true)
|
| [pnpm](https://pnpm.io)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm)) |
[`10.34.3` →
`10.34.4`](https://renovatebot.com/diffs/npm/pnpm/10.34.3/10.34.4) |
![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/10.34.4?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/10.34.3/10.34.4?slim=true)
|
| [tailwindcss](https://tailwindcss.com)
([source](https://redirect.github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss))
| [`4.3.0` →
`4.3.1`](https://renovatebot.com/diffs/npm/tailwindcss/4.3.0/4.3.1) |
![age](https://developer.mend.io/api/mc/badges/age/npm/tailwindcss/4.3.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/tailwindcss/4.3.0/4.3.1?slim=true)
|
|
[typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint)
([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint))
| [`8.61.0` →
`8.61.1`](https://renovatebot.com/diffs/npm/typescript-eslint/8.61.0/8.61.1)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/typescript-eslint/8.61.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript-eslint/8.61.0/8.61.1?slim=true)
|
| [vitest](https://vitest.dev)
([source](https://redirect.github.com/vitest-dev/vitest/tree/HEAD/packages/vitest))
| [`4.1.8` →
`4.1.9`](https://renovatebot.com/diffs/npm/vitest/4.1.8/4.1.9) |
![age](https://developer.mend.io/api/mc/badges/age/npm/vitest/4.1.9?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/vitest/4.1.8/4.1.9?slim=true)
|

---

### Release Notes

<details>
<summary>mui/base-ui (@&#8203;base-ui/react)</summary>

###
[`v1.6.0`](https://redirect.github.com/mui/base-ui/blob/HEAD/CHANGELOG.md#v160)

[Compare
Source](https://redirect.github.com/mui/base-ui/compare/v1.5.0...v1.6.0)

*Jun 18, 2026*

##### General changes

- Correct inaccurate prop JSDoc
([#&#8203;5036](https://redirect.github.com/mui/base-ui/issues/5036)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Update the hook value when store/arguments change
([#&#8203;4866](https://redirect.github.com/mui/base-ui/issues/4866)) by
[@&#8203;chuganzy](https://redirect.github.com/chuganzy)
- Restore viewport morphing after reopen for kept-mounted popups
([#&#8203;5010](https://redirect.github.com/mui/base-ui/issues/5010)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix pseudo-element bounds in dev mode
([#&#8203;5000](https://redirect.github.com/mui/base-ui/issues/5000)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Accordion

- Fix trigger behavior bugs
([#&#8203;4833](https://redirect.github.com/mui/base-ui/issues/4833)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Remove region role from `Accordion.Root`
([#&#8203;4961](https://redirect.github.com/mui/base-ui/issues/4961)) by
[@&#8203;chuganzy](https://redirect.github.com/chuganzy)
- Align keyboard navigation with APG
([#&#8203;4965](https://redirect.github.com/mui/base-ui/issues/4965)) by
[@&#8203;chuganzy](https://redirect.github.com/chuganzy)

##### Alert Dialog

- Fix programmatic focus return
([#&#8203;4849](https://redirect.github.com/mui/base-ui/issues/4849)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Autocomplete

- Keep ArrowLeft/ArrowRight on the input caret in grid mode
([#&#8203;4948](https://redirect.github.com/mui/base-ui/issues/4948)) by
[@&#8203;spokodev](https://redirect.github.com/spokodev)
- Document `open` requirement for the `inline` prop
([#&#8203;5069](https://redirect.github.com/mui/base-ui/issues/5069)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Avatar

- Fix image status edge cases
([#&#8203;4835](https://redirect.github.com/mui/base-ui/issues/4835)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Checkbox

- Fix parent group cancellation and indeterminate state
([#&#8203;4941](https://redirect.github.com/mui/base-ui/issues/4941)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Ignore `data-focused` Field attribute when disabled
([#&#8203;4998](https://redirect.github.com/mui/base-ui/issues/4998)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix extra `validate` fn calls
([#&#8203;4911](https://redirect.github.com/mui/base-ui/issues/4911)) by
[@&#8203;mj12albert](https://redirect.github.com/mj12albert)

##### Checkbox Group

- Fix parent group cancellation and indeterminate state
([#&#8203;4941](https://redirect.github.com/mui/base-ui/issues/4941)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix parent checkbox with custom `validate` fn
([#&#8203;4912](https://redirect.github.com/mui/base-ui/issues/4912)) by
[@&#8203;mj12albert](https://redirect.github.com/mj12albert)
- Fix validation with multiple required checkboxes
([#&#8203;4958](https://redirect.github.com/mui/base-ui/issues/4958)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Forward group ids
([#&#8203;4997](https://redirect.github.com/mui/base-ui/issues/4997)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Collapsible

- Fix trigger and panel state bugs
([#&#8203;4848](https://redirect.github.com/mui/base-ui/issues/4848)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Combobox

- Fix chip context error
([#&#8203;4877](https://redirect.github.com/mui/base-ui/issues/4877)) by
[@&#8203;lyzno1](https://redirect.github.com/lyzno1)
- Keep ArrowLeft/ArrowRight on the input caret in grid mode
([#&#8203;4948](https://redirect.github.com/mui/base-ui/issues/4948)) by
[@&#8203;spokodev](https://redirect.github.com/spokodev)
- Avoid re-rendering every item on each keystroke
([#&#8203;4964](https://redirect.github.com/mui/base-ui/issues/4964)) by
[@&#8203;flaviendelangle](https://redirect.github.com/flaviendelangle)
- Fix autofill and selected state edge cases
([#&#8203;4972](https://redirect.github.com/mui/base-ui/issues/4972)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Document `open` requirement for the `inline` prop
([#&#8203;5069](https://redirect.github.com/mui/base-ui/issues/5069)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Dialog

- Fix confirmation return focus
([#&#8203;5024](https://redirect.github.com/mui/base-ui/issues/5024)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix programmatic focus return
([#&#8203;4849](https://redirect.github.com/mui/base-ui/issues/4849)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix positioning and viewport edge cases
([#&#8203;4925](https://redirect.github.com/mui/base-ui/issues/4925)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix non-modal focus-out close and tabindex management
([#&#8203;5030](https://redirect.github.com/mui/base-ui/issues/5030)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Drawer

- Fix confirmation return focus
([#&#8203;5024](https://redirect.github.com/mui/base-ui/issues/5024)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Improve swipe dismiss drag performance
([#&#8203;4867](https://redirect.github.com/mui/base-ui/issues/4867)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Drive swipe gestures natively to stop per-frame re-rasterization
([#&#8203;4980](https://redirect.github.com/mui/base-ui/issues/4980)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Add virtual keyboard provider
([#&#8203;4353](https://redirect.github.com/mui/base-ui/issues/4353)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Commit swipe on primary-button release
([#&#8203;5057](https://redirect.github.com/mui/base-ui/issues/5057)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Field

- Fix form validation bugs
([#&#8203;4873](https://redirect.github.com/mui/base-ui/issues/4873)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Reflect disabled `Field.Item` state in `Field.Label`
([#&#8203;4916](https://redirect.github.com/mui/base-ui/issues/4916)) by
[@&#8203;chuganzy](https://redirect.github.com/chuganzy)
- Reflect disabled `Field.Item` state in `Field.Description`
([#&#8203;4960](https://redirect.github.com/mui/base-ui/issues/4960)) by
[@&#8203;chuganzy](https://redirect.github.com/chuganzy)
- Fix valueMissing revalidation
([#&#8203;4995](https://redirect.github.com/mui/base-ui/issues/4995)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix validation bugs
([#&#8203;4894](https://redirect.github.com/mui/base-ui/issues/4894)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Fieldset

- Fix disabled fieldset form bugs
([#&#8203;4890](https://redirect.github.com/mui/base-ui/issues/4890)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Form

- Fix form validation bugs
([#&#8203;4873](https://redirect.github.com/mui/base-ui/issues/4873)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Menu

- Fix submenu trigger interactions
([#&#8203;4892](https://redirect.github.com/mui/base-ui/issues/4892)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Open submenus on hover after a plain delay
([#&#8203;4990](https://redirect.github.com/mui/base-ui/issues/4990)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix controlled hover leave close
([#&#8203;4893](https://redirect.github.com/mui/base-ui/issues/4893)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix positioning and viewport edge cases
([#&#8203;4925](https://redirect.github.com/mui/base-ui/issues/4925)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Menubar

- Fix vertical menu focus behavior
([#&#8203;4922](https://redirect.github.com/mui/base-ui/issues/4922)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Meter

- Sync value text with indicator
([#&#8203;4904](https://redirect.github.com/mui/base-ui/issues/4904)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Navigation Menu

- Preserve exit transition when controlled
([#&#8203;4855](https://redirect.github.com/mui/base-ui/issues/4855)) by
[@&#8203;mattrothenberg](https://redirect.github.com/mattrothenberg)
- Fix interaction, value, and styling-hook bugs
([#&#8203;4942](https://redirect.github.com/mui/base-ui/issues/4942)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Number Field

- Handle unreadable clipboard paste
([#&#8203;4876](https://redirect.github.com/mui/base-ui/issues/4876)) by
[@&#8203;lyzno1](https://redirect.github.com/lyzno1)
- Fix committed values and keyboard stepping
([#&#8203;4905](https://redirect.github.com/mui/base-ui/issues/4905)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Respect Intl rounding options on blur
([#&#8203;4804](https://redirect.github.com/mui/base-ui/issues/4804)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix formatter locale cache
([#&#8203;4999](https://redirect.github.com/mui/base-ui/issues/4999)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Preserve numeric precision while keeping default display formatting
([#&#8203;5040](https://redirect.github.com/mui/base-ui/issues/5040)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix input and scrub edge cases
([#&#8203;5046](https://redirect.github.com/mui/base-ui/issues/5046)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### OTP Field

- 🚨 **Breaking change:** Unmark preview<br />
the namespace export is renamed `OTPFieldPreview` → `OTPField` and
should be imported as: `{ OTPField } from
'@&#8203;base-ui/react/otp-field'`
([#&#8203;5029](https://redirect.github.com/mui/base-ui/issues/5029)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Avoid password manager bubbles after first input
([#&#8203;4868](https://redirect.github.com/mui/base-ui/issues/4868)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Popover

- Fix controlled hover leave close
([#&#8203;4893](https://redirect.github.com/mui/base-ui/issues/4893)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix programmatic focus return
([#&#8203;4849](https://redirect.github.com/mui/base-ui/issues/4849)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix positioning and viewport edge cases
([#&#8203;4925](https://redirect.github.com/mui/base-ui/issues/4925)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix non-modal focus-out close and tabindex management
([#&#8203;5030](https://redirect.github.com/mui/base-ui/issues/5030)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Preview Card

- Fix controlled hover leave close
([#&#8203;4893](https://redirect.github.com/mui/base-ui/issues/4893)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix positioning and viewport edge cases
([#&#8203;4925](https://redirect.github.com/mui/base-ui/issues/4925)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Keep inline preview anchored while open
([#&#8203;4836](https://redirect.github.com/mui/base-ui/issues/4836)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Close when active trigger unmounts
([#&#8203;4886](https://redirect.github.com/mui/base-ui/issues/4886)) by
[@&#8203;michaldudak](https://redirect.github.com/michaldudak)

##### Radio Group

- Forward group ids
([#&#8203;4997](https://redirect.github.com/mui/base-ui/issues/4997)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix selection on space key press
([#&#8203;4930](https://redirect.github.com/mui/base-ui/issues/4930)) by
[@&#8203;chuganzy](https://redirect.github.com/chuganzy)
- Fix disabled selected form submission
([#&#8203;4926](https://redirect.github.com/mui/base-ui/issues/4926)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Honor canceled value changes
([#&#8203;4996](https://redirect.github.com/mui/base-ui/issues/4996)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Scroll Area

- Fix overflow and scrolling state
([#&#8203;4936](https://redirect.github.com/mui/base-ui/issues/4936)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Add scrolling state to Thumb
([#&#8203;4982](https://redirect.github.com/mui/base-ui/issues/4982)) by
[@&#8203;aarongarciah](https://redirect.github.com/aarongarciah)

##### Select

- Fix autofill and selected state edge cases
([#&#8203;4934](https://redirect.github.com/mui/base-ui/issues/4934)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix dirty state not clearing in multiple mode
([#&#8203;4971](https://redirect.github.com/mui/base-ui/issues/4971)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Skip disabled items in typeahead and fix multiple-mode serialization
([#&#8203;5025](https://redirect.github.com/mui/base-ui/issues/5025)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Slider

- Fix extra `validate` fn calls
([#&#8203;4911](https://redirect.github.com/mui/base-ui/issues/4911)) by
[@&#8203;mj12albert](https://redirect.github.com/mj12albert)
- Fix interaction edge cases
([#&#8203;4937](https://redirect.github.com/mui/base-ui/issues/4937)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix touchend listener accumulation leak
([#&#8203;5070](https://redirect.github.com/mui/base-ui/issues/5070)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Switch

- Fix extra `validate` fn calls
([#&#8203;4911](https://redirect.github.com/mui/base-ui/issues/4911)) by
[@&#8203;mj12albert](https://redirect.github.com/mj12albert)

##### Tabs

- Fix state edge cases
([#&#8203;4935](https://redirect.github.com/mui/base-ui/issues/4935)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix suspended panel activation
([#&#8203;4903](https://redirect.github.com/mui/base-ui/issues/4903)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Toast

- Fix timer and limit edge cases
([#&#8203;4933](https://redirect.github.com/mui/base-ui/issues/4933)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Toggle

- Fix grouped cancelation and JSDoc
([#&#8203;4940](https://redirect.github.com/mui/base-ui/issues/4940)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Toggle Group

- Fix grouped cancelation and JSDoc
([#&#8203;4940](https://redirect.github.com/mui/base-ui/issues/4940)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Remove invalid `aria-orientation` from `role="group"` element
([#&#8203;4628](https://redirect.github.com/mui/base-ui/issues/4628)) by
[@&#8203;sernstberger](https://redirect.github.com/sernstberger)
- Fix disabled state and roving focus bugs
([#&#8203;4968](https://redirect.github.com/mui/base-ui/issues/4968)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Toolbar

- Do not forward `disabled` to default toolbar button
([#&#8203;4967](https://redirect.github.com/mui/base-ui/issues/4967)) by
[@&#8203;mj12albert](https://redirect.github.com/mj12albert)
- Fix disabled state and roving focus bugs
([#&#8203;4968](https://redirect.github.com/mui/base-ui/issues/4968)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)

##### Tooltip

- Fix positioning and viewport edge cases
([#&#8203;4925](https://redirect.github.com/mui/base-ui/issues/4925)) by
[@&#8203;atomiks](https://redirect.github.com/atomiks)
- Fix provider delay group lifecycle
([#&#8203;4887](https://redirect.github.com/mui/base-ui/issues/4887)) by
[@&#8203;michaldudak](https://redirect.github.com/michaldudak)
- Reset preventUnmountOnClose on reopen
([#&#8203;4885](https://redirect.github.com/mui/base-ui/issues/4885)) by
[@&#8203;michaldudak](https://redirect.github.com/michaldudak)
- Close when active trigger unmounts
([#&#8203;4886](https://redirect.github.com/mui/base-ui/issues/4886)) by
[@&#8203;michaldudak](https://redirect.github.com/michaldudak)

All contributors of this release in alphabetical order:
[@&#8203;aarongarciah](https://redirect.github.com/aarongarciah),
[@&#8203;atomiks](https://redirect.github.com/atomiks),
[@&#8203;chuganzy](https://redirect.github.com/chuganzy),
[@&#8203;flaviendelangle](https://redirect.github.com/flaviendelangle),
[@&#8203;lyzno1](https://redirect.github.com/lyzno1),
[@&#8203;mattrothenberg](https://redirect.github.com/mattrothenberg),
[@&#8203;michaldudak](https://redirect.github.com/michaldudak),
[@&#8203;mj12albert](https://redirect.github.com/mj12albert),
[@&#8203;sernstberger](https://redirect.github.com/sernstberger),
[@&#8203;spokodev](https://redirect.github.com/spokodev)

</details>

<details>
<summary>tailwindlabs/tailwindcss
(@&#8203;tailwindcss/postcss)</summary>

###
[`v4.3.1`](https://redirect.github.com/tailwindlabs/tailwindcss/blob/HEAD/CHANGELOG.md#431---2026-06-12)

[Compare
Source](https://redirect.github.com/tailwindlabs/tailwindcss/compare/v4.3.0...v4.3.1)

##### Added

- Add `--silent` option to suppress output in `@tailwindcss/cli`
([#&#8203;20100](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20100))

##### Fixed

- Remove deprecation warnings by using `Module#registerHooks` instead of
`Module#register` on Node 26+
([#&#8203;20028](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20028))
- Canonicalization: don't crash when plugin utilities throw for
unsupported values
([#&#8203;20052](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20052))
- Allow `@apply` to be used with CSS mixins
([#&#8203;19427](https://redirect.github.com/tailwindlabs/tailwindcss/pull/19427))
- Ensure `not-*` correctly negates `@container` queries, including
`style(…)` queries
([#&#8203;20059](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20059))
- Ensure `drop-shadow-*` color utilities work with custom shadow values
containing `calc(…)`
([#&#8203;20080](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20080))
- Fix 'Sourcemap is likely to be incorrect' warnings when using
`@tailwindcss/vite`
([#&#8203;20103](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20103))
- Ensure `@tailwindcss/webpack` can be installed in Rspack projects
without requiring `webpack` as a peer dependency
([#&#8203;20027](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20027))
- Canonicalization: don't suggest invalid `calc(…)` expressions (e.g.
`px-[calc(1rem+0px)]` → `px-[calc(1rem+0)]`)
([#&#8203;20127](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20127))
- Canonicalization: avoid suggesting large spacing-scale values for
arbitrary lengths (e.g. `left-[99999px]` → `left-[99999px]`, not
`left-24999.75`)
([#&#8203;20130](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20130))
- Ensure `@tailwindcss/cli` in `--watch` mode recovers when a tracked
dependency is deleted and restored
([#&#8203;20137](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20137))
- Ensure standalone `@tailwindcss/cli` binaries are ignored when
scanning for class candidates
([#&#8203;20139](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20139))
- Ensure class candidates are extracted from Twig `addClass(…)` and
`removeClass(…)` calls
([#&#8203;20198](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20198))
- Don't crash in the Ruby or Vue preprocessors when scanning files
containing invalid UTF-8 bytes
([#&#8203;19588](https://redirect.github.com/tailwindlabs/tailwindcss/pull/19588))
- Allow `@variant` to be used inside `addBase`
([#&#8203;19480](https://redirect.github.com/tailwindlabs/tailwindcss/pull/19480))
- Ensure `@source` globs with symlinks are preserved
([#&#8203;20203](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203))
- Ensure later `@source` rules can re-include files excluded by earlier
`@source not` rules
([#&#8203;20203](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203))
- Upgrade: don't migrate empty class rules to invalid `@utility` rules
([#&#8203;20205](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20205))
- Ensure transitions between `inset-shadow-none` and other inset shadows
work correctly
([#&#8203;20208](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20208))
- Ensure explicitly referenced `@source` directories are scanned even
when ignored by git
([#&#8203;20214](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20214))
- Ensure `@source` globs ending in `**/*` preserve dynamic path segments
to avoid scanning too many files
([#&#8203;20217](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20217))
- Canonicalization: don't fold `calc(…)` divisions when the result would
require high precision (e.g. `w-[calc(100%/3.5)]` →
`w-[calc(100%/3.5)]`, not `w-[28.571428571428573%]`)
([#&#8203;20221](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20221))
- Serve ESM type declarations to ESM importers of `@tailwindcss/postcss`
([#&#8203;20228](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20228))

##### Changed

- Generate `0` instead of `calc(var(--spacing) * 0)` for spacing
utilities like `m-0` and `left-0`
([#&#8203;20196](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20196))
- Generate `var(--spacing)` instead of `calc(var(--spacing) * 1)` for
spacing utilities like `m-1` and `left-1`
([#&#8203;20196](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20196))

</details>

<details>
<summary>trpc/trpc (@&#8203;trpc/client)</summary>

###
[`v11.18.0`](https://redirect.github.com/trpc/trpc/releases/tag/v11.18.0)

[Compare
Source](https://redirect.github.com/trpc/trpc/compare/v11.17.0...v11.18.0)

##### What's Changed

- fix(ci): restore tests package version and pin Bun by
[@&#8203;KATT](https://redirect.github.com/KATT) in
[#&#8203;7393](https://redirect.github.com/trpc/trpc/pull/7393)
- fix(tanstack-react-query): add prefix support for mutation options by
[@&#8203;tmkx](https://redirect.github.com/tmkx) in
[#&#8203;7370](https://redirect.github.com/trpc/trpc/pull/7370)
- chore: fix duplicate "the" in unstable-core JSDoc comment by
[@&#8203;dfedoryshchev](https://redirect.github.com/dfedoryshchev) in
[#&#8203;7366](https://redirect.github.com/trpc/trpc/pull/7366)
- feat(openapi): Add server url support by
[@&#8203;Nick-Lucas](https://redirect.github.com/Nick-Lucas) in
[#&#8203;7411](https://redirect.github.com/trpc/trpc/pull/7411)

##### New Contributors

- [@&#8203;dfedoryshchev](https://redirect.github.com/dfedoryshchev)
made their first contribution in
[#&#8203;7366](https://redirect.github.com/trpc/trpc/pull/7366)

**Full Changelog**:
<trpc/trpc@v11.17.0...v11.18.0>

</details>

<details>
<summary>vitest-dev/vitest (@&#8203;vitest/coverage-v8)</summary>

###
[`v4.1.9`](https://redirect.github.com/vitest-dev/vitest/releases/tag/v4.1.9)

[Compare
Source](https://redirect.github.com/vitest-dev/vitest/compare/v4.1.8...v4.1.9)

##### 🐞 Bug Fixes

- Fix `importOriginal` with optimizer and query import \[backport to v4]
- by **Hiroshi Ogawa**, **David Harris**, **Codex**and **Vladimir** in
[#&#8203;10546](https://redirect.github.com/vitest-dev/vitest/issues/10546)
[<samp>(a5180)</samp>](https://redirect.github.com/vitest-dev/vitest/commit/a5180190c)
- **browser**:
- Wait for orchestrator readiness before resolving browser sessions
\[backport to v4] - by **Vladimir** and **Séamus O'Connor** in
[#&#8203;10555](https://redirect.github.com/vitest-dev/vitest/issues/10555)
[<samp>(7fb29)</samp>](https://redirect.github.com/vitest-dev/vitest/commit/7fb29651a)
- Wait for iframe tester readiness before preparing \[backport to v4] -
by **Vladimir** and **Séamus O'Connor** in
[#&#8203;10497](https://redirect.github.com/vitest-dev/vitest/issues/10497)
and
[#&#8203;10556](https://redirect.github.com/vitest-dev/vitest/issues/10556)
[<samp>(fbc62)</samp>](https://redirect.github.com/vitest-dev/vitest/commit/fbc626c40)
- **mocker**:
- Hoist vi.mock() for vite-plus/test imports \[backport to v4] - by
**Hiroshi Ogawa**, **LongYinan**, **Claude Opus 4.8** and **Vladimir**
in
[#&#8203;10548](https://redirect.github.com/vitest-dev/vitest/issues/10548)
[<samp>(2c955)</samp>](https://redirect.github.com/vitest-dev/vitest/commit/2c9559c02)
- **pool**:
- Prevent test run hang on worker crash \[backport to v4] - by **Ari
Perkkiö** and **Jattioui Ismail** in
[#&#8203;10543](https://redirect.github.com/vitest-dev/vitest/issues/10543)
and
[#&#8203;10564](https://redirect.github.com/vitest-dev/vitest/issues/10564)
[<samp>(934b0)</samp>](https://redirect.github.com/vitest-dev/vitest/commit/934b0f587)

##### [View changes on
GitHub](https://redirect.github.com/vitest-dev/vitest/compare/v4.1.8...v4.1.9)

</details>

<details>
<summary>WiseLibs/better-sqlite3 (better-sqlite3)</summary>

###
[`v12.11.1`](https://redirect.github.com/WiseLibs/better-sqlite3/releases/tag/v12.11.1)

[Compare
Source](https://redirect.github.com/WiseLibs/better-sqlite3/compare/v12.10.1...v12.11.1)

#### What's Changed

- Fix Electron v42 build errors on Windows by
[@&#8203;m4heshd](https://redirect.github.com/m4heshd) in
[#&#8203;1488](https://redirect.github.com/WiseLibs/better-sqlite3/pull/1488)

**Full Changelog**:
<WiseLibs/better-sqlite3@v12.11.0...v12.11.1>

###
[`v12.10.1`](https://redirect.github.com/WiseLibs/better-sqlite3/releases/tag/v12.10.1)

[Compare
Source](https://redirect.github.com/WiseLibs/better-sqlite3/compare/v12.10.0...v12.10.1)

#### What's Changed

- Bump the github-actions group across 1 directory with 4 updates by
[@&#8203;dependabot](https://redirect.github.com/dependabot)\[bot] in
[#&#8203;1451](https://redirect.github.com/WiseLibs/better-sqlite3/pull/1451)
- Fix V8 external API usage for Electron 42 by
[@&#8203;tstone-1](https://redirect.github.com/tstone-1) in
[#&#8203;1475](https://redirect.github.com/WiseLibs/better-sqlite3/pull/1475)

**Full Changelog**:
<WiseLibs/better-sqlite3@v12.10.0...v12.10.1>

</details>

<details>
<summary>lucide-icons/lucide (lucide-react)</summary>

###
[`v1.21.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/1.21.0):
Version 1.21.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/1.20.0...1.21.0)

#### What's Changed

- ci(release.yml): Remove new-version in release flow by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[#&#8203;4478](https://redirect.github.com/lucide-icons/lucide/pull/4478)
- ci(release.yml): Fix workflow and remove `version` scripts in package
scripts by [@&#8203;ericfennis](https://redirect.github.com/ericfennis)
in
[#&#8203;4479](https://redirect.github.com/lucide-icons/lucide/pull/4479)
- fix(docs): rename navigation category label by
[@&#8203;Hsiii](https://redirect.github.com/Hsiii) in
[#&#8203;4483](https://redirect.github.com/lucide-icons/lucide/pull/4483)
- feat(icons): added `broken-bone` icon by
[@&#8203;Patolord](https://redirect.github.com/Patolord) in
[#&#8203;4131](https://redirect.github.com/lucide-icons/lucide/pull/4131)

#### New Contributors

- [@&#8203;Hsiii](https://redirect.github.com/Hsiii) made their first
contribution in
[#&#8203;4483](https://redirect.github.com/lucide-icons/lucide/pull/4483)
- [@&#8203;Patolord](https://redirect.github.com/Patolord) made their
first contribution in
[#&#8203;4131](https://redirect.github.com/lucide-icons/lucide/pull/4131)

**Full Changelog**:
<lucide-icons/lucide@1.20.0...1.21.0>

###
[`v1.20.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/1.20.0):
Version 1.20.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/1.19.0...1.20.0)

#### What's Changed

- fix(icons): decreased size of arrows inside `square-arrow-*` icons by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[#&#8203;3926](https://redirect.github.com/lucide-icons/lucide/pull/3926)
- chore(tags): Add tags to `search-` icons by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[#&#8203;4099](https://redirect.github.com/lucide-icons/lucide/pull/4099)
- feat(icons): added `save-check` icon by
[@&#8203;Konixy](https://redirect.github.com/Konixy) in
[#&#8203;3120](https://redirect.github.com/lucide-icons/lucide/pull/3120)
- feat(icons): added `tag-plus` and `tag-x` icons by
[@&#8203;adam-kov](https://redirect.github.com/adam-kov) in
[#&#8203;3980](https://redirect.github.com/lucide-icons/lucide/pull/3980)
- feat(icons): added `banknote-check` icon by
[@&#8203;mfjramirezf](https://redirect.github.com/mfjramirezf) in
[#&#8203;3956](https://redirect.github.com/lucide-icons/lucide/pull/3956)
- feat(icons): added `clock-arrow-in` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[#&#8203;2403](https://redirect.github.com/lucide-icons/lucide/pull/2403)
- feat(icons): added `summary` icon by
[@&#8203;jpjacobpadilla](https://redirect.github.com/jpjacobpadilla) in
[#&#8203;3114](https://redirect.github.com/lucide-icons/lucide/pull/3114)
- feat(icons): added `user-round-arrow-in` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[#&#8203;2283](https://redirect.github.com/lucide-icons/lucide/pull/2283)
- feat(icons): added `clock-arrow-out` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[#&#8203;2404](https://redirect.github.com/lucide-icons/lucide/pull/2404)
- docs(docs): fix broken Svelte package source link in README by
[@&#8203;SRKrukowski](https://redirect.github.com/SRKrukowski) in
[#&#8203;4468](https://redirect.github.com/lucide-icons/lucide/pull/4468)
- chore(deps-dev): bump
[@&#8203;angular/compiler](https://redirect.github.com/angular/compiler)
from 21.2.5 to 21.2.17 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)\[bot] in
[#&#8203;4474](https://redirect.github.com/lucide-icons/lucide/pull/4474)
- chore(deps-dev): bump
[@&#8203;angular/core](https://redirect.github.com/angular/core) from
21.2.5 to 21.2.17 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)\[bot] in
[#&#8203;4470](https://redirect.github.com/lucide-icons/lucide/pull/4470)
- chore(deps-dev): bump vitest from 4.0.12 to 4.1.0 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)\[bot] in
[#&#8203;4429](https://redirect.github.com/lucide-icons/lucide/pull/4429)
- chore(deps-dev): bump markdown-it from 14.1.1 to 14.2.0 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)\[bot] in
[#&#8203;4475](https://redirect.github.com/lucide-icons/lucide/pull/4475)
- chore(deps-dev): bump
[@&#8203;angular/common](https://redirect.github.com/angular/common)
from 21.2.5 to 21.2.17 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)\[bot] in
[#&#8203;4471](https://redirect.github.com/lucide-icons/lucide/pull/4471)
- feat(icons): added `pencil-sparkles` icon by
[@&#8203;jennieboops](https://redirect.github.com/jennieboops) in
[#&#8203;4445](https://redirect.github.com/lucide-icons/lucide/pull/4445)

#### New Contributors

- [@&#8203;Konixy](https://redirect.github.com/Konixy) made their first
contribution in
[#&#8203;3120](https://redirect.github.com/lucide-icons/lucide/pull/3120)
- [@&#8203;adam-kov](https://redirect.github.com/adam-kov) made their
first contribution in
[#&#8203;3980](https://redirect.github.com/lucide-icons/lucide/pull/3980)
- [@&#8203;mfjramirezf](https://redirect.github.com/mfjramirezf) made
their first contribution in
[#&#8203;3956](https://redirect.github.com/lucide-icons/lucide/pull/3956)
- [@&#8203;SRKrukowski](https://redirect.github.com/SRKrukowski) made
their first contribution in
[#&#8203;4468](https://redirect.github.com/lucide-icons/lucide/pull/4468)
- [@&#8203;jennieboops](https://redirect.github.com/jennieboops) made
their first contribution in
[#&#8203;4445](https://redirect.github.com/lucide-icons/lucide/pull/4445)

**Full Changelog**:
<lucide-icons/lucide@1.19.0...1.20.0>

###
[`v1.19.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/1.19.0):
Version 1.19.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/1.18.0...1.19.0)

#### What's Changed

- chore(deps): upgrade pnpm to version 11.6.0 by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[#&#8203;4458](https://redirect.github.com/lucide-icons/lucide/pull/4458)
- feat(icons): added `star-*` icons by
[@&#8203;RajnishKMehta](https://redirect.github.com/RajnishKMehta) in
[#&#8203;3918](https://redirect.github.com/lucide-icons/lucide/pull/3918)
- chore(suggest-tags): Update metadata suggestion script by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[#&#8203;4462](https://redirect.github.com/lucide-icons/lucide/pull/4462)
- feat(icons): added `save-pen` icon by
[@&#8203;vaporvee](https://redirect.github.com/vaporvee) in
[#&#8203;4179](https://redirect.github.com/lucide-icons/lucide/pull/4179)
- feat(icons): added `wrench-off` icon by
[@&#8203;nilsjonsson](https://redirect.github.com/nilsjonsson) in
[#&#8203;4434](https://redirect.github.com/lucide-icons/lucide/pull/4434)
- feat(icons): added `ad` icon by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[#&#8203;4323](https://redirect.github.com/lucide-icons/lucide/pull/4323)
- feat(icons): added `eye-dashed` icon by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[#&#8203;4415](https://redirect.github.com/lucide-icons/lucide/pull/4415)
- feat(icons): added `save-plus` icon by
[@&#8203;jwlinqx](https://redirect.github.com/jwlinqx) in
[#&#8203;4448](https://redirect.github.com/lucide-icons/lucide/pull/4448)
- feat(icons): added `list-sort-descending` icon by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[#&#8203;4457](https://redirect.github.com/lucide-icons/lucide/pull/4457)
- fix(lucide-react-native): Fix provider exports by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[#&#8203;4463](https://redirect.github.com/lucide-icons/lucide/pull/4463)
- fix(site): reserve space for icon detail drawer by
[@&#8203;vyctorbrzezowski](https://redirect.github.com/vyctorbrzezowski)
in
[#&#8203;4344](https://redirect.github.com/lucide-icons/lucide/pull/4344)
- fix(icons): changed `wallet-cards` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[#&#8203;3888](https://redirect.github.com/lucide-icons/lucide/pull/3888)
- feat(site): Improve search and add sorting options by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[#&#8203;4453](https://redirect.github.com/lucide-icons/lucide/pull/4453)
- feat(icons): added `podium` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[#&#8203;2124](https://redirect.github.com/lucide-icons/lucide/pull/2124)

#### New Contributors

- [@&#8203;vaporvee](https://redirect.github.com/vaporvee) made their
first contribution in
[#&#8203;4179](https://redirect.github.com/lucide-icons/lucide/pull/4179)
- [@&#8203;nilsjonsson](https://redirect.github.com/nilsjonsson) made
their first contribution in
[#&#8203;4434](https://redirect.github.com/lucide-icons/lucide/pull/4434)
- [@&#8203;jwlinqx](https://redirect.github.com/jwlinqx) made their
first contribution in
[#&#8203;4448](https://redirect.github.com/lucide-icons/lucide/pull/4448)
-
[@&#8203;vyctorbrzezowski](https://redirect.github.com/vyctorbrzezowski)
made their first contribution in
[#&#8203;4344](https://redirect.github.com/lucide-icons/lucide/pull/4344)

**Full Changelog**:
<lucide-icons/lucide@1.18.0...1.19.0>

###
[`v1.18.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/1.18.0):
Version 1.18.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/1.17.0...1.18.0)

#### What's Changed

- chore(site): Remove survey from site by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[#&#8203;4417](https://redirect.github.com/lucide-icons/lucide/pull/4417)
- feat(icons): added `play-off` icon by
[@&#8203;Ahmed-Dghaies](https://redirect.github.com/Ahmed-Dghaies) in
[#&#8203;4412](https://redirect.github.com/lucide-icons/lucide/pull/4412)
- fix(metadata): add missing use-cases prop on play-off.json by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[#&#8203;4423](https://redirect.github.com/lucide-icons/lucide/pull/4423)
- fix(docs): force hide #bb-banner, if html.has-bb-banner is missing by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[#&#8203;4422](https://redirect.github.com/lucide-icons/lucide/pull/4422)
- fix(docs): Remove `@next` from installation instructions
for`@lucide/svelte` by
[@&#8203;alecglassford](https://redirect.github.com/alecglassford) in
[#&#8203;4432](https://redirect.github.com/lucide-icons/lucide/pull/4432)
- feat(packages/angular): add support for Angular v22 and onwards by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[#&#8203;4450](https://redirect.github.com/lucide-icons/lucide/pull/4450)
- fix(ci): add check to skip release if latest tag was created today by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[#&#8203;4085](https://redirect.github.com/lucide-icons/lucide/pull/4085)
- feat(icons): added `webcam-off` icon by
[@&#8203;jordan-burnett](https://redirect.github.com/jordan-burnett) in
[#&#8203;4242](https://redirect.github.com/lucide-icons/lucide/pull/4242)

#### New Contributors

- [@&#8203;alecglassford](https://redirect.github.com/alecglassford)
made their first contribution in
[#&#8203;4432](https://redirect.github.com/lucide-icons/lucide/pull/4432)
- [@&#8203;jordan-burnett](https://redirect.github.com/jordan-burnett)
made their first contribution in
[#&#8203;4242](https://redirect.github.com/lucide-icons/lucide/pull/4242)

**Full Changelog**:
<lucide-icons/lucide@1.17.0...1.18.0>

</details>

<details>
<summary>pnpm/pnpm (pnpm)</summary>

###
[`v10.34.4`](https://redirect.github.com/pnpm/pnpm/compare/v10.34.3...v10.34.4)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v10.34.3...v10.34.4)

</details>

<details>
<summary>typescript-eslint/typescript-eslint
(typescript-eslint)</summary>

###
[`v8.61.1`](https://redirect.github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8611-2026-06-15)

[Compare
Source](https://redirect.github.com/typescript-eslint/typescript-eslint/compare/v8.61.0...v8.61.1)

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

See [GitHub
Releases](https://redirect.github.com/typescript-eslint/typescript-eslint/releases/tag/v8.61.1)
for more information.

You can read about our [versioning
strategy](https://typescript-eslint.io/users/versioning) and
[releases](https://typescript-eslint.io/users/releases) on our website.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 6am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/sleepypod/core).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yMzUuMCIsInVwZGF0ZWRJblZlciI6IjQzLjIzNS4wIiwidGFyZ2V0QnJhbmNoIjoiZGV2IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyIsImZpeC1wYXRjaCIsIm5vbi1tYWpvciJdfQ==-->

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update renovate/all-minor-patch
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/renovate/all-minor-patch/scripts/install \
  | sudo bash -s -- --branch renovate/all-minor-patch
```

🎯 **Pin to this exact build** ([run
27973841616](https://github.com/sleepypod/core/actions/runs/27973841616)
· `6f84753`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/6f84753a8a8fb583e4704a7f070f73a9fd7c5374/scripts/install \
  | sudo bash -s -- \
      --branch renovate/all-minor-patch \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/27973841616/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/27973841616/artifacts/7800955542)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…655)

This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@tanstack/react-query](https://tanstack.com/query)
([source](https://redirect.github.com/TanStack/query/tree/HEAD/packages/react-query))
| [`5.101.0` →
`5.101.1`](https://renovatebot.com/diffs/npm/@tanstack%2freact-query/5.101.0/5.101.1)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@tanstack%2freact-query/5.101.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@tanstack%2freact-query/5.101.0/5.101.1?slim=true)
|
| [@xyflow/react](https://reactflow.dev)
([source](https://redirect.github.com/xyflow/xyflow/tree/HEAD/packages/react))
| [`12.11.0` →
`12.11.1`](https://renovatebot.com/diffs/npm/@xyflow%2freact/12.11.0/12.11.1)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@xyflow%2freact/12.11.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@xyflow%2freact/12.11.0/12.11.1?slim=true)
|
| [bonjour-service](https://redirect.github.com/onlxltd/bonjour-service)
| [`1.4.1` →
`1.4.2`](https://renovatebot.com/diffs/npm/bonjour-service/1.4.1/1.4.2)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/bonjour-service/1.4.2?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/bonjour-service/1.4.1/1.4.2?slim=true)
|
| [globals](https://redirect.github.com/sindresorhus/globals) |
[`17.6.0` →
`17.7.0`](https://renovatebot.com/diffs/npm/globals/17.6.0/17.7.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/globals/17.7.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/globals/17.6.0/17.7.0?slim=true)
|
| [recharts](https://redirect.github.com/recharts/recharts) | [`3.8.1` →
`3.9.0`](https://renovatebot.com/diffs/npm/recharts/3.8.1/3.9.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/recharts/3.9.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/recharts/3.8.1/3.9.0?slim=true)
|
| [shadcn](https://redirect.github.com/shadcn-ui/ui)
([source](https://redirect.github.com/shadcn-ui/ui/tree/HEAD/packages/shadcn))
| [`4.11.0` →
`4.12.0`](https://renovatebot.com/diffs/npm/shadcn/4.11.0/4.12.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/shadcn/4.12.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/shadcn/4.11.0/4.12.0?slim=true)
|
|
[typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint)
([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint))
| [`8.61.1` →
`8.62.0`](https://renovatebot.com/diffs/npm/typescript-eslint/8.61.1/8.62.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/typescript-eslint/8.62.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript-eslint/8.61.1/8.62.0?slim=true)
|

---

### Release Notes

<details>
<summary>TanStack/query (@&#8203;tanstack/react-query)</summary>

###
[`v5.101.1`](https://redirect.github.com/TanStack/query/blob/HEAD/packages/react-query/CHANGELOG.md#51011)

[Compare
Source](https://redirect.github.com/TanStack/query/compare/@tanstack/react-query@5.101.0...@tanstack/react-query@5.101.1)

##### Patch Changes

- Updated dependencies
\[[`9eff92e`](https://redirect.github.com/TanStack/query/commit/9eff92ed86e284ec0125b3a3539d028688235bd1)]:
-
[@&#8203;tanstack/query-core](https://redirect.github.com/tanstack/query-core)@&#8203;5.101.1

</details>

<details>
<summary>xyflow/xyflow (@&#8203;xyflow/react)</summary>

###
[`v12.11.1`](https://redirect.github.com/xyflow/xyflow/blob/HEAD/packages/react/CHANGELOG.md#12111)

[Compare
Source](https://redirect.github.com/xyflow/xyflow/compare/@xyflow/react@12.11.0...@xyflow/react@12.11.1)

##### Patch Changes

- [#&#8203;5815](https://redirect.github.com/xyflow/xyflow/pull/5815)
[`87da45c`](https://redirect.github.com/xyflow/xyflow/commit/87da45cdf55aaf4549120a60165598675993783d)
- Fix `FinalConnectionState` type so it preserves the discriminated
union.

- [#&#8203;5823](https://redirect.github.com/xyflow/xyflow/pull/5823)
[`a6afc91`](https://redirect.github.com/xyflow/xyflow/commit/a6afc91160e0a0e172b03d82c43972222f9ae740)
- Update attribution link

- [#&#8203;5824](https://redirect.github.com/xyflow/xyflow/pull/5824)
[`6b1dac5`](https://redirect.github.com/xyflow/xyflow/commit/6b1dac50ff1b837688c362ede5dcc8a57ac97444)
- Do not fire on pane click when connection ends on pane

- [#&#8203;5818](https://redirect.github.com/xyflow/xyflow/pull/5818)
[`4ddc2d8`](https://redirect.github.com/xyflow/xyflow/commit/4ddc2d8420c39ca2e16bbce0e2265601a63a332f)
- Provide the shared handle config (`connectOnClick`, `noPanClassName`,
`rfId`) through context instead of subscribing to the store in every
`Handle`, so a store update no longer runs a selector once per handle

- [#&#8203;5817](https://redirect.github.com/xyflow/xyflow/pull/5817)
[`8df250b`](https://redirect.github.com/xyflow/xyflow/commit/8df250b095d0c8a6c82c9155d22250b94b295e76)
- Reduce per-handle work on store updates by returning a shared
connection state while no connection is in progress.

- [#&#8203;5822](https://redirect.github.com/xyflow/xyflow/pull/5822)
[`a6249de`](https://redirect.github.com/xyflow/xyflow/commit/a6249de56c5181edbbe205058a2e5eb593dc278b)
- Return stable reference for edge position when connected node gets
deleted

- Updated dependencies
\[[`ceb8604`](https://redirect.github.com/xyflow/xyflow/commit/ceb8604047f97e6c9028fed17bb10186a7ca9e8b),
[`87da45c`](https://redirect.github.com/xyflow/xyflow/commit/87da45cdf55aaf4549120a60165598675993783d)]:
-
[@&#8203;xyflow/system](https://redirect.github.com/xyflow/system)@&#8203;0.0.78

</details>

<details>
<summary>onlxltd/bonjour-service (bonjour-service)</summary>

###
[`v1.4.2`](https://redirect.github.com/onlxltd/bonjour-service/releases/tag/1.4.2)

[Compare
Source](https://redirect.github.com/onlxltd/bonjour-service/compare/1.4.1...1.4.2)

#### What's Changed

- Bump tar from 7.5.15 to 7.5.16 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)\[bot] in
[#&#8203;81](https://redirect.github.com/onlxltd/bonjour-service/pull/81)
- Bump undici from 6.25.0 to 6.27.0 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)\[bot] in
[#&#8203;82](https://redirect.github.com/onlxltd/bonjour-service/pull/82)
- Bump js-yaml from 4.1.1 to 4.2.0 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)\[bot] in
[#&#8203;83](https://redirect.github.com/onlxltd/bonjour-service/pull/83)

**Full Changelog**:
<onlxltd/bonjour-service@1.4.1...1.4.2>

</details>

<details>
<summary>sindresorhus/globals (globals)</summary>

###
[`v17.7.0`](https://redirect.github.com/sindresorhus/globals/compare/v17.6.0...a19670cc86c1218e915657c55ea02ba3e7623834)

[Compare
Source](https://redirect.github.com/sindresorhus/globals/compare/v17.6.0...v17.7.0)

</details>

<details>
<summary>recharts/recharts (recharts)</summary>

###
[`v3.9.0`](https://redirect.github.com/recharts/recharts/releases/tag/v3.9.0)

[Compare
Source](https://redirect.github.com/recharts/recharts/compare/v3.8.1...v3.9.0)

#### What's Changed

##### Animations

3.9 comes with new animations! There are several bug fixes and what's
best, all animations are now fully customizable.

See the animations guide on
<https://recharts.github.io/en-US/guide/animations/>

- Animation guide by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7179](https://redirect.github.com/recharts/recharts/pull/7179)
- Animation tests by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7255](https://redirect.github.com/recharts/recharts/pull/7255)
- New animation props by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7215](https://redirect.github.com/recharts/recharts/pull/7215)
- test: cover legacy animation length changes by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7283](https://redirect.github.com/recharts/recharts/pull/7283)
- test: add sparse animation path tests for Line component by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7295](https://redirect.github.com/recharts/recharts/pull/7295)
- Export and document interpolate function by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7293](https://redirect.github.com/recharts/recharts/pull/7293)
- test: enhance line animation tests for ComposedChart and responsive by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7289](https://redirect.github.com/recharts/recharts/pull/7289)
- Manual animations on website by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7483](https://redirect.github.com/recharts/recharts/pull/7483)
- Add new example where chart animates by scroll by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7484](https://redirect.github.com/recharts/recharts/pull/7484)
- fix: preserve single-value line dash gaps during animation by
[@&#8203;puneetdixit200](https://redirect.github.com/puneetdixit200) in
[#&#8203;7405](https://redirect.github.com/recharts/recharts/pull/7405)
- Add animate-by-scroll example and update docs by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7487](https://redirect.github.com/recharts/recharts/pull/7487)
- Add custom fillOpacity on hover website example by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7489](https://redirect.github.com/recharts/recharts/pull/7489)
- honorable mention to
[@&#8203;robjampar](https://redirect.github.com/robjampar) for PR
[#&#8203;6973](https://redirect.github.com/recharts/recharts/pull/6973)
which ended up declined but it introduced the starting idea for the new
animation props

##### New features other than animations

- Expose and document chart layout hooks and layout types in public API
by [@&#8203;Copilot](https://redirect.github.com/Copilot) in
[#&#8203;7265](https://redirect.github.com/recharts/recharts/pull/7265)
- feat: allow HTML attributes passthrough on ResponsiveContainer by
[@&#8203;techcodie](https://redirect.github.com/techcodie) in
[#&#8203;7168](https://redirect.github.com/recharts/recharts/pull/7168)
- feat: add nodeInset and nodeGap properties to Treemap for better la…
by [@&#8203;MaximSrour](https://redirect.github.com/MaximSrour) in
[#&#8203;7044](https://redirect.github.com/recharts/recharts/pull/7044)
- feat(PieChart): add dataKey to Legend payload by
[@&#8203;Harikrushn9118](https://redirect.github.com/Harikrushn9118) in
[#&#8203;7137](https://redirect.github.com/recharts/recharts/pull/7137)

##### Bugfixes

- fix: preserve valid falsy custom names (0, "") in tooltips by
[@&#8203;vamsi2246](https://redirect.github.com/vamsi2246) in
[#&#8203;7175](https://redirect.github.com/recharts/recharts/pull/7175)
- fix(ResponsiveContainer): Fix erroneous console warning on init by
[@&#8203;andypoorman](https://redirect.github.com/andypoorman) in
[#&#8203;7174](https://redirect.github.com/recharts/recharts/pull/7174)
- fix(DataUtils): improve isPercent validation to exclude invalid
formats by [@&#8203;vamsi2246](https://redirect.github.com/vamsi2246) in
[#&#8203;7178](https://redirect.github.com/recharts/recharts/pull/7178)
- fix(BarChart): render stacked bars when all values are 0
([#&#8203;6235](https://redirect.github.com/recharts/recharts/issues/6235))
by [@&#8203;andypoorman](https://redirect.github.com/andypoorman) in
[#&#8203;7199](https://redirect.github.com/recharts/recharts/pull/7199)
- fix(Sankey): prevent NaN node positions when link values sum to zero
by [@&#8203;Mridul012](https://redirect.github.com/Mridul012) in
[#&#8203;7185](https://redirect.github.com/recharts/recharts/pull/7185)
- fix(Funnel): prevent NaN coordinate layout crash when all values are
zero by [@&#8203;Mridul012](https://redirect.github.com/Mridul012) in
[#&#8203;7184](https://redirect.github.com/recharts/recharts/pull/7184)
- fixes an issue where XAxis and YAxis padding were ignored by the
clipping mask when allowDataOverflow={true} was used alongside a
restricted domain by
[@&#8203;emiedonmokumo](https://redirect.github.com/emiedonmokumo) in
[#&#8203;7232](https://redirect.github.com/recharts/recharts/pull/7232)
- fix: use originalDataIndex for tooltip dispatch in Bar by
[@&#8203;mayrang](https://redirect.github.com/mayrang) in
[#&#8203;7273](https://redirect.github.com/recharts/recharts/pull/7273)
- fix: resolve TypeScript 6 deprecation errors in tsconfig files by
[@&#8203;shreedharbhat98](https://redirect.github.com/shreedharbhat98)
in
[#&#8203;7285](https://redirect.github.com/recharts/recharts/pull/7285)
- fix(bar): use Math.round instead of bitwise truncation for bar
positioning by [@&#8203;EduardF1](https://redirect.github.com/EduardF1)
in
[#&#8203;7297](https://redirect.github.com/recharts/recharts/pull/7297)
- fix(types): propagate Tooltip types in chart helper contexts by
[@&#8203;mixelburg](https://redirect.github.com/mixelburg) in
[#&#8203;7125](https://redirect.github.com/recharts/recharts/pull/7125)
- fix(Legend): prevent overlap with chart on container resize by
[@&#8203;maroKanatani](https://redirect.github.com/maroKanatani) in
[#&#8203;7201](https://redirect.github.com/recharts/recharts/pull/7201)
- test(YAxis): failing repro for
[#&#8203;7362](https://redirect.github.com/recharts/recharts/issues/7362)
— function domain doesn't render ticks on empty/all-null data by
[@&#8203;nlenepveu](https://redirect.github.com/nlenepveu) in
[#&#8203;7384](https://redirect.github.com/recharts/recharts/pull/7384)

##### Tree-shaking

We now have focused tree-shaking tests that allow us to observe exactly
which components end up in the final bundle and why. I have also removed
some unnecessary loops and you should see the final bundle size decrease
somewhat as a result.

There are also two new examples on the website, showing real bundle
size:

-
<https://recharts.github.io/recharts/canary/www/en-US/examples/BundleSizeTreemap/>
-
<https://recharts.github.io/recharts/canary/www/en-US/examples/BundleSizeSunburst/>

* Improve bundle tracing and tree-shaking for Shape defaults by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7348](https://redirect.github.com/recharts/recharts/pull/7348)
* Refactor Shape props to reduce bundle sizes by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7349](https://redirect.github.com/recharts/recharts/pull/7349)
* Types: switch Shape from spread to separate prop object by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7351](https://redirect.github.com/recharts/recharts/pull/7351)

##### Documentation updates

- docs: clarify valid types for axis tick prop by
[@&#8203;Harikrushn9118](https://redirect.github.com/Harikrushn9118) in
[#&#8203;7191](https://redirect.github.com/recharts/recharts/pull/7191)
- style: update layout gaps and add new navigation links by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7412](https://redirect.github.com/recharts/recharts/pull/7412)
- www: show deployed commit hash in footer across production and staging
builds by [@&#8203;Copilot](https://redirect.github.com/Copilot) in
[#&#8203;7258](https://redirect.github.com/recharts/recharts/pull/7258)
- Replace old bundle-viz with two new chart examples by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7390](https://redirect.github.com/recharts/recharts/pull/7390)
- Remove our custom storybook plugins by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7382](https://redirect.github.com/recharts/recharts/pull/7382)
- feat: add PolarAngleAxis component storybook story by
[@&#8203;whatfontisthis](https://redirect.github.com/whatfontisthis) in
[#&#8203;7243](https://redirect.github.com/recharts/recharts/pull/7243)
- feat: add LabelList component Storybook story by
[@&#8203;whatfontisthis](https://redirect.github.com/whatfontisthis) in
[#&#8203;7244](https://redirect.github.com/recharts/recharts/pull/7244)
- docs: add Windows install workaround to DEVELOPING.md by
[@&#8203;harsh-05](https://redirect.github.com/harsh-05) in
[#&#8203;7324](https://redirect.github.com/recharts/recharts/pull/7324)
- docs: add [@&#8203;since](https://redirect.github.com/since) 3.9
annotation to hooks by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7326](https://redirect.github.com/recharts/recharts/pull/7326)
- Add [@&#8203;since](https://redirect.github.com/since) annotation to
useChartLayout by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7360](https://redirect.github.com/recharts/recharts/pull/7360)
- Add since annotation to useActiveTooltipDataPoints by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7338](https://redirect.github.com/recharts/recharts/pull/7338)
- devops: upload test results to Flakiness.io by
[@&#8203;aslushnikov](https://redirect.github.com/aslushnikov) in
[#&#8203;7359](https://redirect.github.com/recharts/recharts/pull/7359)
- Omnidoc: add API examples support and enhance example discovery by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7342](https://redirect.github.com/recharts/recharts/pull/7342)
- Dedup website examples by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7340](https://redirect.github.com/recharts/recharts/pull/7340)
- Remove Area.baseLine type by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7317](https://redirect.github.com/recharts/recharts/pull/7317)
- docs: add session storage support for controls state by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7279](https://redirect.github.com/recharts/recharts/pull/7279)
- fix(Scatter): use HTTPS in JSDoc links by
[@&#8203;Parth10P](https://redirect.github.com/Parth10P) in
[#&#8203;7192](https://redirect.github.com/recharts/recharts/pull/7192)
- Update copyright year to 2026 by
[@&#8203;ojhawkins](https://redirect.github.com/ojhawkins) in
[#&#8203;7288](https://redirect.github.com/recharts/recharts/pull/7288)
- Fix Legend props not appearing in omnidoc website by
[@&#8203;Copilot](https://redirect.github.com/Copilot) in
[#&#8203;7203](https://redirect.github.com/recharts/recharts/pull/7203)
- docs: add Deno to install instructions by
[@&#8203;bartlomieju](https://redirect.github.com/bartlomieju) in
[#&#8203;7473](https://redirect.github.com/recharts/recharts/pull/7473)

#### New Contributors

- [@&#8203;MaximSrour](https://redirect.github.com/MaximSrour) made
their first contribution in
[#&#8203;7044](https://redirect.github.com/recharts/recharts/pull/7044)
- [@&#8203;vamsi2246](https://redirect.github.com/vamsi2246) made their
first contribution in
[#&#8203;7175](https://redirect.github.com/recharts/recharts/pull/7175)
- [@&#8203;andypoorman](https://redirect.github.com/andypoorman) made
their first contribution in
[#&#8203;7174](https://redirect.github.com/recharts/recharts/pull/7174)
- [@&#8203;Mridul012](https://redirect.github.com/Mridul012) made their
first contribution in
[#&#8203;7185](https://redirect.github.com/recharts/recharts/pull/7185)
- [@&#8203;emiedonmokumo](https://redirect.github.com/emiedonmokumo)
made their first contribution in
[#&#8203;7232](https://redirect.github.com/recharts/recharts/pull/7232)
- [@&#8203;mayrang](https://redirect.github.com/mayrang) made their
first contribution in
[#&#8203;7273](https://redirect.github.com/recharts/recharts/pull/7273)
-
[@&#8203;legions-developer](https://redirect.github.com/legions-developer)
made their first contribution in
[#&#8203;7280](https://redirect.github.com/recharts/recharts/pull/7280)
- [@&#8203;ojhawkins](https://redirect.github.com/ojhawkins) made their
first contribution in
[#&#8203;7288](https://redirect.github.com/recharts/recharts/pull/7288)
- [@&#8203;EduardF1](https://redirect.github.com/EduardF1) made their
first contribution in
[#&#8203;7297](https://redirect.github.com/recharts/recharts/pull/7297)
- [@&#8203;harsh-05](https://redirect.github.com/harsh-05) made their
first contribution in
[#&#8203;7324](https://redirect.github.com/recharts/recharts/pull/7324)
- [@&#8203;aslushnikov](https://redirect.github.com/aslushnikov) made
their first contribution in
[#&#8203;7359](https://redirect.github.com/recharts/recharts/pull/7359)
- [@&#8203;maroKanatani](https://redirect.github.com/maroKanatani) made
their first contribution in
[#&#8203;7201](https://redirect.github.com/recharts/recharts/pull/7201)
- [@&#8203;techcodie](https://redirect.github.com/techcodie) made their
first contribution in
[#&#8203;7168](https://redirect.github.com/recharts/recharts/pull/7168)
- [@&#8203;whatfontisthis](https://redirect.github.com/whatfontisthis)
made their first contribution in
[#&#8203;7243](https://redirect.github.com/recharts/recharts/pull/7243)
- [@&#8203;nlenepveu](https://redirect.github.com/nlenepveu) made their
first contribution in
[#&#8203;7384](https://redirect.github.com/recharts/recharts/pull/7384)
- [@&#8203;bartlomieju](https://redirect.github.com/bartlomieju) made
their first contribution in
[#&#8203;7473](https://redirect.github.com/recharts/recharts/pull/7473)
- [@&#8203;puneetdixit200](https://redirect.github.com/puneetdixit200)
made their first contribution in
[#&#8203;7405](https://redirect.github.com/recharts/recharts/pull/7405)

**Full Changelog**:
<recharts/recharts@v3.8.1...v3.9.0-canary.0>

</details>

<details>
<summary>shadcn-ui/ui (shadcn)</summary>

###
[`v4.12.0`](https://redirect.github.com/shadcn-ui/ui/blob/HEAD/packages/shadcn/CHANGELOG.md#4120)

[Compare
Source](https://redirect.github.com/shadcn-ui/ui/compare/shadcn@4.11.1...shadcn@4.12.0)

##### Minor Changes

- [#&#8203;11022](https://redirect.github.com/shadcn-ui/ui/pull/11022)
[`18fcf0f766857a7249cc0daac3c1609610edd158`](https://redirect.github.com/shadcn-ui/ui/commit/18fcf0f766857a7249cc0daac3c1609610edd158)
Thanks [@&#8203;shadcn](https://redirect.github.com/shadcn)! - add
scroll-fade and shimmer utilities

###
[`v4.11.1`](https://redirect.github.com/shadcn-ui/ui/blob/HEAD/packages/shadcn/CHANGELOG.md#4111)

[Compare
Source](https://redirect.github.com/shadcn-ui/ui/compare/shadcn@4.11.0...shadcn@4.11.1)

##### Patch Changes

- [#&#8203;10905](https://redirect.github.com/shadcn-ui/ui/pull/10905)
[`9197676b3d09b77f51b17b63e5978db29e498ca4`](https://redirect.github.com/shadcn-ui/ui/commit/9197676b3d09b77f51b17b63e5978db29e498ca4)
Thanks [@&#8203;shadcn](https://redirect.github.com/shadcn)! - replace
node-fetch with native fetch

- [#&#8203;10967](https://redirect.github.com/shadcn-ui/ui/pull/10967)
[`365d53b590a6ddb79c1487a9dbeabcde5f4ac37f`](https://redirect.github.com/shadcn-ui/ui/commit/365d53b590a6ddb79c1487a9dbeabcde5f4ac37f)
Thanks [@&#8203;shadcn](https://redirect.github.com/shadcn)! - Preserve
existing dependency specifiers in package.json when running `shadcn
add`.

</details>

<details>
<summary>typescript-eslint/typescript-eslint
(typescript-eslint)</summary>

###
[`v8.62.0`](https://redirect.github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8620-2026-06-22)

[Compare
Source](https://redirect.github.com/typescript-eslint/typescript-eslint/compare/v8.61.1...v8.62.0)

##### 🚀 Features

- remove redundant package.json "files"
([#&#8203;12444](https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12444))

##### ❤️ Thank You

- Kirk Waiblinger
[@&#8203;kirkwaiblinger](https://redirect.github.com/kirkwaiblinger)

See [GitHub
Releases](https://redirect.github.com/typescript-eslint/typescript-eslint/releases/tag/v8.62.0)
for more information.

You can read about our [versioning
strategy](https://typescript-eslint.io/users/versioning) and
[releases](https://typescript-eslint.io/users/releases) on our website.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 6am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/sleepypod/core).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDIuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI0Mi4yIiwidGFyZ2V0QnJhbmNoIjoiZGV2IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyIsImZpeC1wYXRjaCIsIm5vbi1tYWpvciJdfQ==-->

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update renovate/all-minor-patch
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/renovate/all-minor-patch/scripts/install \
  | sudo bash -s -- --branch renovate/all-minor-patch
```

🎯 **Pin to this exact build** ([run
28416699862](https://github.com/sleepypod/core/actions/runs/28416699862)
· `04149a0`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/04149a027f56722bd36f4798aab268a4a61b44b7/scripts/install \
  | sudo bash -s -- \
      --branch renovate/all-minor-patch \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/28416699862/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/28416699862/artifacts/7969733819)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
44 verified findings (1 critical, 3 high, 16 medium, 24 low) across
server/API, hardware/streaming, Python device modules, scheduler/
automation/HomeKit, DB/migrations, and frontend.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Self-contained work plan (4 batches, 44 items) with locations, concrete
changes, and verification steps, for execution in a fresh session.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The hand-edited when for 0003_sensor_calibration (1773714000000) was greater
than 0004's and 0005's, so drizzle's migrator skipped them on incremental
upgrades past 0003 — missing tables then made 0009 fail and the pod could not
boot. Set it strictly between 0002 and 0004.

Adds a journal monotonicity guard and an incremental-upgrade regression test
(migrate to 0003, then run the full migrator, assert 0004+ tables exist).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drift compared DB schedule rows against schedulerJobCount minus only
PRIME/REBOOT, so LED-brightness, away-mode, run-once, and calibration jobs
made every health poll flag drift and rebuild the whole scheduler (~7s).
Count only schedule-backed job types (temperature/power_on/power_off/alarm)
on the scheduler side instead.

Also fixes the test db mock: drizzle tables all have constructor name
SQLiteTable, so the per-table detection silently returned the temp array for
power/alarm queries, hiding the phantom drift in existing tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…read timeout

When a DAC response timed out, the losing readMessage() stayed subscribed and
later consumed the NEXT command's response, shifting every subsequent
command/response pair; connectDac's early-return blocked recovery. Reads now
take an AbortSignal and settle when the timeout fires, and each send first
discards any stale buffered responses (commands are strictly sequential, so
anything buffered at send time is stale by definition).

Same fix applied to the dev/test SocketClient path: its single pendingRead
slot already cancelled on timeout, but the late response sat in the queue and
misaligned the next command — now discarded before each send.

Covers review items 1.3 and 3.5. Adds regression tests for dropped and
late-buffered responses.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ndow

A record with a far-future ts landed in bed_temp/freezer_temp, and because
the downsample cursors seed from MAX(timestamp) at startup, every subsequent
write was blocked forever — surviving restarts. Add sanitize_ts (mirroring
sleep-detector's, plus an upper bound of now+60s) and clamp the DB-seeded
cursors to now so an already-poisoned DB self-heals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…port test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The latch was set on every HomeKit toggle and never cleared, so external
power changes (scheduler off, auto-off, pump stall guard) were shadowed
forever: isEffectivelyPowered reported stale ON and setTargetTemperature
could re-heat a bed the scheduler had turned off. Clear the latch once a
status update confirms the intended state; keep it while the write is still
propagating (status lags a poll interval).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ng and others added 19 commits July 2, 2026 23:22
Signal 1 zeroed movement for BOTH beds whenever EITHER pump had RPM>0, and
the pump-off guard period was likewise global, so the idle side's real
movement was discarded for entire pump runtimes. RPM gating and the guard
period are now tracked per side; cross-side mechanical coupling remains
covered by Signal 2 (correlated ref-anomaly).

Also fixes a latent guard bug: _pump_off_at initialized to 0.0 gated
everything for the first PUMP_GUARD_S after process start when
time.monotonic() has a near-zero origin — now -inf ('never turned off').

Not validated against recorded pod data (none available in this repo);
covered with unit tests instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… stalls

After the first WS frame, a sticky ref permanently set refetchInterval:false,
so a dying WS server froze temps, pump-stall, alarm, and water-level status
with no fallback. WS is now trusted only while the socket is connected AND a
frame arrived within 15s; otherwise HTTP polls at 7s. While WS is live, HTTP
idles at 60s instead of off — each idle poll re-evaluates freshness, so a
silently-stalled (half-open) socket self-heals within one cycle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
During snooze nothing is vibrating, so handleStop built its targets from
leftAlarmActive/rightAlarmActive (both false), fired no clearAlarm mutation,
and the alarm resumed at the end of the snooze. When no side is actively
vibrating, targets now come from the snoozed sides (backend clearAlarm
already cancels the pending snooze timer).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ms it

The visible device status is WS-preferred, so HTTP refetch()/invalidate()
after mutations never updated the UI, and clearing the dial's local target in
onSettled snapped it back to the stale value for ~2s before the next frame.
New useOptimisticValue hook: preview() for in-progress drags, commit() holds
the value until the server reports it (6s fallback), discard() on mutation
error. Applied to the TempScreen dial, ±1 buttons, power toggle, and
PowerButton — whose doc comment promised an optimistic toggle it never had.

Covers review items 3.8, 3.9, and 4.20.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…Sense2

Review items:
- 4.7 piezo-processor: tolerate truncated int32 buffers (len % 4 != 0 killed
  the module via np.frombuffer ValueError)
- 4.9 piezo-processor: HRTracker re-seeds after a sustained streak of
  uncorrectable readings instead of freezing on a stale median; single
  outliers still stay out of history. Also fix FrzHealthPumpState's pump-off
  guard falsely asserting for the first 5s when time.monotonic() starts near
  zero (same sentinel bug as sleep-detector's gate; made its tests flaky on
  fast runs)
- 4.8 calibration: drop non-dict trigger JSON instead of crash-looping the
  calibrator on .get()
- 4.10 calibration: scan the final quiet window in CapCalibrator
  (off-by-one vs CapSense2Calibrator)
- 4.11 calibration: write_trigger_atomic gets pid+counter uniquifier (the old
  with_suffix('.tmp') collapsed all writers to one tmp path) and fsyncs file
  + directory around the rename

Also includes the pre-existing verified working-tree change to
CapSense2Calibrator: accept 6-value capSense2 frames (Pod 4/5 firmware
without the REF pair), mirroring sleep-detector's extractor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 4.3 normalizeFrame: optional-chain nested frzHealth/frzTherm wire fields so
  a firmware build omitting a branch degrades to zeros instead of throwing in
  the WS message handler
- 4.4 clamp snooze setTimeout delays to the 32-bit ms ceiling (larger values
  wrap and restart the alarm immediately)
- 4.5 mqttBridge.testConnection resolves tlsInsecure via resolveConfig's
  db-then-env precedence instead of env only
- 4.6 piezoStream seek: chunked async reads + periodic parse yields replace
  the up-to-64MB readSync that blocked the event loop for all clients

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 4.12 timeOfDay triggers fire on the first tick at-or-after the slot within
  a 10-minute grace window instead of exact-minute equality (a >60s tick gap
  silently skipped the slot). Fired-state is now keyed by local calendar date
  from the tz-aware clock — the old weekday key also blocked the same slot
  every following week for the life of the process.
- 4.13 scheduleRunOnceSession cancels the session's existing jobs before
  scheduling: an in-process restore passes a filtered set-point list whose
  indices shift, so stale ids could double-fire set points.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 4.14 delete 0002_nappy_warpath.sql — orphaned byte-identical duplicate of
  0003_previous_phil_sheldon.sql, absent from the journal
- 4.15 reconstruct missing meta/0007_snapshot.json (0006 schema + 0007's MQTT
  columns, id taken from 0008's prevId); drizzle-kit check passes and
  generate produces no diff
- 4.16 new biometrics migration 0011: plain timestamp indexes on vitals,
  movement, and vitals_quality so retention pruning can seek instead of
  full-scanning the pod's largest tables
- 4.17 prune vitals_quality on the same cutoff as vitals — vitals_id is a
  logical, unenforced reference and no module pruned the table, so quality
  rows orphaned forever (a real FK would need a table rebuild and PRAGMA
  foreign_keys in every writer; documented in the schema instead)
- 4.18 install --restore removes live -wal/-shm sidecars after copying the
  .db so SQLite can't replay post-backup transactions over the restore

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 4.2 triggerUpdate branch validation also rejects '..', '//',
  leading/trailing '/', leading '-', and '.lock' (git-ref-safe; the
  character class alone allowed traversal and option injection)
- 4.21 DeviceSettingsForm resets from server data only when the values
  actually change — every refetch produced a new object identity and stomped
  fields mid-edit
- 4.22 diagnostics pump-stall tile: armed = green (flag was inverted)
- 4.23 CapZoneViz: reduce instead of spreading a long replay's flattened
  zones into Math.max (RangeError past the argument limit)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 4.24 untrack + gitignore biometrics.dev.db-shm/-wal (transient per-machine
  WAL state; the .db fixture itself stays tracked)
- 4.25 fill in CLAUDE.md Build & Test, Architecture Overview, and
  Conventions sections
- 4.26 Dependabot triage tracked as ygg task core-3
- 4.19 decision noted in the fix plan: keep the pump-stall opt-in safety
  reset as-is (power-cutting feature; safe default wins)
- mark all Batch 4 checkboxes; lint cleanups from the batch

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… 2026-07-01 review docs

The 2026-07-01 repo-wide review is fully remediated (47/47 items); its
docs are retired from docs/ and remain in git history. The new plan
covers the 1 Major + 4 Minor findings left from the 2026-07-03
adversarial Codex review, self-contained since .reviews/ is gitignored.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fix RAW file selection so the streamer skips `SEQNO.RAW` and, if the
top-level `/persistent` scan finds nothing usable, falls back to
`/persistent/biometrics`.

Pod evidence:
- `sleepypod.service` had no `RAW_DATA_DIR` override in its environment,
so the app used its default path.
- `/persistent` contained `SEQNO.RAW` and the `biometrics/` directory;
`/persistent/biometrics` contained the real capture file `00D0660E.RAW`.
- `journalctl -u sleepypod.service` showed `[sensorStream] Switched to
RAW file: SEQNO.RAW`, followed by CBOR resync errors, which explained
why only `DEV` appeared in the Sensors tab.

Implementation:
- keep the existing one-directory scan behavior
- skip only `SEQNO.RAW`
- if the scan of `/persistent` finds nothing, retry in
`/persistent/biometrics`
- add a regression test for the fallback path and `SEQNO.RAW` exclusion

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved RAW file detection so streaming attaches to the newest valid
capture instead of a placeholder file.
* Added fallback discovery for devices that store captures in a nested
biometrics folder, reducing resync errors and failed attachments.

* **Tests**
* Added coverage for RAW selection behavior across top-level and
fallback locations, including handling of placeholder files and empty
directories.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Jonathan Ng <jon@jonathanng.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@eslint/css](https://redirect.github.com/eslint/css) | [`1.3.0` →
`1.4.0`](https://renovatebot.com/diffs/npm/@eslint%2fcss/1.3.0/1.4.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/@eslint%2fcss/1.4.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@eslint%2fcss/1.3.0/1.4.0?slim=true)
|
| [@tailwindcss/postcss](https://tailwindcss.com)
([source](https://redirect.github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss))
| [`4.3.1` →
`4.3.2`](https://renovatebot.com/diffs/npm/@tailwindcss%2fpostcss/4.3.1/4.3.2)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@tailwindcss%2fpostcss/4.3.2?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@tailwindcss%2fpostcss/4.3.1/4.3.2?slim=true)
|
| [@tanstack/react-query](https://tanstack.com/query)
([source](https://redirect.github.com/TanStack/query/tree/HEAD/packages/react-query))
| [`5.101.1` →
`5.101.2`](https://renovatebot.com/diffs/npm/@tanstack%2freact-query/5.101.1/5.101.2)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@tanstack%2freact-query/5.101.2?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@tanstack%2freact-query/5.101.1/5.101.2?slim=true)
|
|
[eslint-config-next](https://nextjs.org/docs/app/api-reference/config/eslint)
([source](https://redirect.github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next))
| [`16.2.9` →
`16.2.10`](https://renovatebot.com/diffs/npm/eslint-config-next/16.2.9/16.2.10)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/eslint-config-next/16.2.10?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/eslint-config-next/16.2.9/16.2.10?slim=true)
|
| [lucide-react](https://lucide.dev)
([source](https://redirect.github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react))
| [`1.21.0` →
`1.23.0`](https://renovatebot.com/diffs/npm/lucide-react/1.21.0/1.23.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/lucide-react/1.23.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lucide-react/1.21.0/1.23.0?slim=true)
|
| [next](https://nextjs.org)
([source](https://redirect.github.com/vercel/next.js)) | [`16.2.9` →
`16.2.10`](https://renovatebot.com/diffs/npm/next/16.2.9/16.2.10) |
![age](https://developer.mend.io/api/mc/badges/age/npm/next/16.2.10?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/next/16.2.9/16.2.10?slim=true)
|
| [recharts](https://redirect.github.com/recharts/recharts) | [`3.9.0` →
`3.9.1`](https://renovatebot.com/diffs/npm/recharts/3.9.0/3.9.1) |
![age](https://developer.mend.io/api/mc/badges/age/npm/recharts/3.9.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/recharts/3.9.0/3.9.1?slim=true)
|
| [shadcn](https://redirect.github.com/shadcn-ui/ui)
([source](https://redirect.github.com/shadcn-ui/ui/tree/HEAD/packages/shadcn))
| [`4.12.0` →
`4.13.0`](https://renovatebot.com/diffs/npm/shadcn/4.12.0/4.13.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/shadcn/4.13.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/shadcn/4.12.0/4.13.0?slim=true)
|
| [tailwindcss](https://tailwindcss.com)
([source](https://redirect.github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss))
| [`4.3.1` →
`4.3.2`](https://renovatebot.com/diffs/npm/tailwindcss/4.3.1/4.3.2) |
![age](https://developer.mend.io/api/mc/badges/age/npm/tailwindcss/4.3.2?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/tailwindcss/4.3.1/4.3.2?slim=true)
|
| [tsx](https://tsx.hirok.io)
([source](https://redirect.github.com/privatenumber/tsx)) | [`4.22.4` →
`4.23.0`](https://renovatebot.com/diffs/npm/tsx/4.22.4/4.23.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/tsx/4.23.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/tsx/4.22.4/4.23.0?slim=true)
|
|
[typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint)
([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint))
| [`8.62.0` →
`8.62.1`](https://renovatebot.com/diffs/npm/typescript-eslint/8.62.0/8.62.1)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/typescript-eslint/8.62.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript-eslint/8.62.0/8.62.1?slim=true)
|

---

### Release Notes

<details>
<summary>eslint/css (@&#8203;eslint/css)</summary>

###
[`v1.4.0`](https://redirect.github.com/eslint/css/blob/HEAD/CHANGELOG.md#140-2026-07-01)

[Compare
Source](https://redirect.github.com/eslint/css/compare/e447a05a298047a2340da00e5abd415707c2c3c5...8d7c2c553db62e3bce71ecfaa8665ecfeeeda334)

##### Features

- add suggestions to prefer-logical-properties
([#&#8203;474](https://redirect.github.com/eslint/css/issues/474))
([045277e](https://redirect.github.com/eslint/css/commit/045277e498d6dcd486f514c1632f40ad6cb7aa4a))

##### Bug Fixes

- check for preludes in `[@import](https://redirect.github.com/import)`
([#&#8203;470](https://redirect.github.com/eslint/css/issues/470))
([cc8791d](https://redirect.github.com/eslint/css/commit/cc8791dcb277473fc7a49487c02155c5b049645e))
- false negative when font used as identifier
([#&#8203;471](https://redirect.github.com/eslint/css/issues/471))
([f248a32](https://redirect.github.com/eslint/css/commit/f248a32d5d99dbdf3ebdf5da6838a4c3c174bc86))
- reporting font-size unit with percentage in line-height
([#&#8203;466](https://redirect.github.com/eslint/css/issues/466))
([bae9097](https://redirect.github.com/eslint/css/commit/bae9097c0a355b1eb85ad6dcc2737f29f22b3a90))
- type compatibility issue between CSS v1 and ESLint v9
([#&#8203;473](https://redirect.github.com/eslint/css/issues/473))
([3cb31a5](https://redirect.github.com/eslint/css/commit/3cb31a5f94a121706ab5150f95f09f2023826797))
- update baseline data
([6726b1f](https://redirect.github.com/eslint/css/commit/6726b1f9facf5f178e3035a87e415d45b3511541))
- update baseline data
([#&#8203;469](https://redirect.github.com/eslint/css/issues/469))
([99ba37f](https://redirect.github.com/eslint/css/commit/99ba37f373e76d5c86fd34319e6c7c833e2a5110))
- update baseline data
([#&#8203;475](https://redirect.github.com/eslint/css/issues/475))
([7dbbb9d](https://redirect.github.com/eslint/css/commit/7dbbb9d27c7f17db021bbc5124c51a96c6e3ca10))
- update baseline data
([#&#8203;482](https://redirect.github.com/eslint/css/issues/482))
([cd52c73](https://redirect.github.com/eslint/css/commit/cd52c7305a0f85f9d0811b83e19a9082307e13cd))
- update dependency
[@&#8203;eslint/plugin-kit](https://redirect.github.com/eslint/plugin-kit)
to ^0.7.2
([#&#8203;463](https://redirect.github.com/eslint/css/issues/463))
([1678418](https://redirect.github.com/eslint/css/commit/167841821aeb4a9ba1f632b0d756dd1d3bd2ed5c))

</details>

<details>
<summary>tailwindlabs/tailwindcss
(@&#8203;tailwindcss/postcss)</summary>

###
[`v4.3.2`](https://redirect.github.com/tailwindlabs/tailwindcss/blob/HEAD/CHANGELOG.md#432---2026-06-26)

[Compare
Source](https://redirect.github.com/tailwindlabs/tailwindcss/compare/v4.3.1...v4.3.2)

##### Fixed

- Support bare spacing values for `auto-rows-*` and `auto-cols-*`
utilities (e.g. `auto-rows-12` and `auto-cols-16`)
([#&#8203;20229](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20229))
- Prevent `@tailwindcss/cli` in `--watch` mode from crashing on Windows
when `@source` points to a directory that doesn't exist
([#&#8203;20242](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20242))
- Prevent `@tailwindcss/vite` from crashing in Deno v2.8.x when
`context.parentURL` is not a valid URL
([#&#8203;20245](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20245))
- Ensure `@tailwindcss/cli` in `--watch` mode rebuilds when the input
CSS file changes in an ignored directory
([#&#8203;20246](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20246))
- Allow `@variant` rules used in `addBase(…)` to use custom variants
defined later
([#&#8203;20247](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20247))
- Prevent `@tailwindcss/vite` from crashing during HMR when scanned
files or directories are deleted
([#&#8203;20259](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20259))
- Generate `font-size` instead of `color` declarations for
`text-[--spacing(…)]`
([#&#8203;20260](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20260))
- Prevent `@source` patterns from scanning unrelated sibling files and
folders
([#&#8203;20263](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20263))
- Extract class candidates adjacent to Template Toolkit delimiters like
`%]…[%` in `.tt`, `.tt2`, and `.tx` files
([#&#8203;20269](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269))
- Extract class candidates from conditional Maud syntax like
`p.text-black[condition]`
([#&#8203;20269](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269))
- Prevent `@position-try` rules from triggering unknown at-rule warnings
when optimizing CSS
([#&#8203;20277](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20277))
- Support class suggestions for named opacity modifiers from `--opacity`
theme values
([#&#8203;20287](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20287))
- Prevent type errors in `@tailwindcss/postcss` when used with newer
PostCSS patch releases
([#&#8203;20289](https://redirect.github.com/tailwindlabs/tailwindcss/pull/20289))

</details>

<details>
<summary>TanStack/query (@&#8203;tanstack/react-query)</summary>

###
[`v5.101.2`](https://redirect.github.com/TanStack/query/blob/HEAD/packages/react-query/CHANGELOG.md#51012)

[Compare
Source](https://redirect.github.com/TanStack/query/compare/@tanstack/react-query@5.101.1...@tanstack/react-query@5.101.2)

##### Patch Changes

- Updated dependencies \[]:
-
[@&#8203;tanstack/query-core](https://redirect.github.com/tanstack/query-core)@&#8203;5.101.2

</details>

<details>
<summary>vercel/next.js (eslint-config-next)</summary>

###
[`v16.2.10`](https://redirect.github.com/vercel/next.js/compare/v16.2.9...v16.2.10)

[Compare
Source](https://redirect.github.com/vercel/next.js/compare/v16.2.9...v16.2.10)

</details>

<details>
<summary>lucide-icons/lucide (lucide-react)</summary>

###
[`v1.23.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/1.23.0):
Version 1.23.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/1.22.0...1.23.0)

#### What's Changed

- fix(docs): prevent scrollbar layout shift on icons page by
[@&#8203;g30r93g](https://redirect.github.com/g30r93g) in
[#&#8203;4500](https://redirect.github.com/lucide-icons/lucide/pull/4500)
- chore(docs): Remove certificates banner by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[#&#8203;4504](https://redirect.github.com/lucide-icons/lucide/pull/4504)
- ci(repo-journal.yml): GH copilot repo summary by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[#&#8203;4505](https://redirect.github.com/lucide-icons/lucide/pull/4505)
- ci(repo-journal.yml): Small fix in the workflow by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[#&#8203;4508](https://redirect.github.com/lucide-icons/lucide/pull/4508)
- ci(repo-journal.yml): Switch to token by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[#&#8203;4509](https://redirect.github.com/lucide-icons/lucide/pull/4509)
- feat(icons): added `paper-bag` icon by
[@&#8203;dkast](https://redirect.github.com/dkast) in
[#&#8203;4023](https://redirect.github.com/lucide-icons/lucide/pull/4023)

#### New Contributors

- [@&#8203;g30r93g](https://redirect.github.com/g30r93g) made their
first contribution in
[#&#8203;4500](https://redirect.github.com/lucide-icons/lucide/pull/4500)
- [@&#8203;dkast](https://redirect.github.com/dkast) made their first
contribution in
[#&#8203;4023](https://redirect.github.com/lucide-icons/lucide/pull/4023)

**Full Changelog**:
<lucide-icons/lucide@1.22.0...1.23.0>

###
[`v1.22.0`](https://redirect.github.com/lucide-icons/lucide/compare/1.21.0...1.22.0)

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/1.21.0...1.22.0)

</details>

<details>
<summary>vercel/next.js (next)</summary>

###
[`v16.2.10`](https://redirect.github.com/vercel/next.js/compare/v16.2.9...v16.2.10)

[Compare
Source](https://redirect.github.com/vercel/next.js/compare/v16.2.9...v16.2.10)

</details>

<details>
<summary>recharts/recharts (recharts)</summary>

###
[`v3.9.1`](https://redirect.github.com/recharts/recharts/releases/tag/v3.9.1)

[Compare
Source](https://redirect.github.com/recharts/recharts/compare/v3.9.0...v3.9.1)

#### What's Changed

- perf: optimize ScatterChart hover by reducing re-renders from O(n) to
O(1) by [@&#8203;roy7](https://redirect.github.com/roy7) in
[#&#8203;7133](https://redirect.github.com/recharts/recharts/pull/7133)
- fix(YAxis): render explicit ticks when a non-literal domain can't
resolve on empty data
([#&#8203;7362](https://redirect.github.com/recharts/recharts/issues/7362))
by [@&#8203;nlenepveu](https://redirect.github.com/nlenepveu) in
[#&#8203;7393](https://redirect.github.com/recharts/recharts/pull/7393)
- fix: avoid Sankey nodes overlapping skipped-depth links by
[@&#8203;pupuking723](https://redirect.github.com/pupuking723) in
[#&#8203;7471](https://redirect.github.com/recharts/recharts/pull/7471)
- Add stacked bar chart with horizontal threshold line example by
[@&#8203;nijuse](https://redirect.github.com/nijuse) in
[#&#8203;7495](https://redirect.github.com/recharts/recharts/pull/7495)
- fix(DefaultLegendContent): omit empty value from legend icon
aria-label by
[@&#8203;greymoth-jp](https://redirect.github.com/greymoth-jp) in
[#&#8203;7501](https://redirect.github.com/recharts/recharts/pull/7501)
- chore(deps): bump immer from 10.2.0 to 11.1.8 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)\[bot] in
[#&#8203;7452](https://redirect.github.com/recharts/recharts/pull/7452)
- fix(getNiceTickValues): remove trailing duplicate tick when
allowDecimals=false by
[@&#8203;JSap0914](https://redirect.github.com/JSap0914) in
[#&#8203;7482](https://redirect.github.com/recharts/recharts/pull/7482)
- Fix/per graphical item formatter prop by
[@&#8203;shreedharbhat98](https://redirect.github.com/shreedharbhat98)
in
[#&#8203;7287](https://redirect.github.com/recharts/recharts/pull/7287)

#### New Contributors

- [@&#8203;pupuking723](https://redirect.github.com/pupuking723) made
their first contribution in
[#&#8203;7471](https://redirect.github.com/recharts/recharts/pull/7471)
- [@&#8203;nijuse](https://redirect.github.com/nijuse) made their first
contribution in
[#&#8203;7495](https://redirect.github.com/recharts/recharts/pull/7495)
- [@&#8203;greymoth-jp](https://redirect.github.com/greymoth-jp) made
their first contribution in
[#&#8203;7501](https://redirect.github.com/recharts/recharts/pull/7501)
- [@&#8203;JSap0914](https://redirect.github.com/JSap0914) made their
first contribution in
[#&#8203;7482](https://redirect.github.com/recharts/recharts/pull/7482)

**Full Changelog**:
<recharts/recharts@v3.9.0...v3.9.1>

</details>

<details>
<summary>shadcn-ui/ui (shadcn)</summary>

###
[`v4.13.0`](https://redirect.github.com/shadcn-ui/ui/blob/HEAD/packages/shadcn/CHANGELOG.md#4130)

[Compare
Source](https://redirect.github.com/shadcn-ui/ui/compare/shadcn@4.12.0...shadcn@4.13.0)

##### Minor Changes

- [#&#8203;11082](https://redirect.github.com/shadcn-ui/ui/pull/11082)
[`f3e7de11752b087b1c4bf61f4035a866f3a4f9ed`](https://redirect.github.com/shadcn-ui/ui/commit/f3e7de11752b087b1c4bf61f4035a866f3a4f9ed)
Thanks [@&#8203;shadcn](https://redirect.github.com/shadcn)! - base-ui
is now default

</details>

<details>
<summary>privatenumber/tsx (tsx)</summary>

###
[`v4.23.0`](https://redirect.github.com/privatenumber/tsx/releases/tag/v4.23.0)

[Compare
Source](https://redirect.github.com/privatenumber/tsx/compare/v4.22.5...v4.23.0)

##### Bug Fixes

- avoid redundant filesystem probes during module resolution
([257bbbb](https://redirect.github.com/privatenumber/tsx/commit/257bbbb7eb2784cad6a3bb7a2d9c9747d28d96ec)),
closes
[privatenumber/tsx#809](https://redirect.github.com/privatenumber/tsx/issues/809)

##### Features

- add multi-scenario startup benchmark suite
([c178197](https://redirect.github.com/privatenumber/tsx/commit/c178197b104d055fd3431f7448982f3156394d12)),
closes
[privatenumber/tsx#809](https://redirect.github.com/privatenumber/tsx/issues/809)
[#&#8203;809](https://redirect.github.com/privatenumber/tsx/issues/809)
[hi#signal](https://redirect.github.com/hi/issues/signal)
[privatenumber/tsx#145](https://redirect.github.com/privatenumber/tsx/issues/145)
[#&#8203;809](https://redirect.github.com/privatenumber/tsx/issues/809)

***

This release is also available on:

- [npm package (@&#8203;latest
dist-tag)](https://www.npmjs.com/package/tsx/v/4.23.0)

###
[`v4.22.5`](https://redirect.github.com/privatenumber/tsx/releases/tag/v4.22.5)

[Compare
Source](https://redirect.github.com/privatenumber/tsx/compare/v4.22.4...v4.22.5)

##### Bug Fixes

- isolate hook state per async module.register() registration
([a305f36](https://redirect.github.com/privatenumber/tsx/commit/a305f365f0cbcc31a44549dcbb0e63dc2883e96d))

***

This release is also available on:

- [npm package (@&#8203;latest
dist-tag)](https://www.npmjs.com/package/tsx/v/4.22.5)

</details>

<details>
<summary>typescript-eslint/typescript-eslint
(typescript-eslint)</summary>

###
[`v8.62.1`](https://redirect.github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8621-2026-06-29)

[Compare
Source](https://redirect.github.com/typescript-eslint/typescript-eslint/compare/v8.62.0...v8.62.1)

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

See [GitHub
Releases](https://redirect.github.com/typescript-eslint/typescript-eslint/releases/tag/v8.62.1)
for more information.

You can read about our [versioning
strategy](https://typescript-eslint.io/users/versioning) and
[releases](https://typescript-eslint.io/users/releases) on our website.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 6am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/sleepypod/core).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDIuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI0Mi4yIiwidGFyZ2V0QnJhbmNoIjoiZGV2IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyIsImZpeC1wYXRjaCIsIm5vbi1tYWpvciJdfQ==-->

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update renovate/all-minor-patch
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/renovate/all-minor-patch/scripts/install \
  | sudo bash -s -- --branch renovate/all-minor-patch
```

🎯 **Pin to this exact build** ([run
28830928213](https://github.com/sleepypod/core/actions/runs/28830928213)
· `c266978`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/c266978a460403455fefd313a12b20f9e084ab37/scripts/install \
  | sudo bash -s -- \
      --branch renovate/all-minor-patch \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/28830928213/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/28830928213/artifacts/8124378585)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…all pods (#662)

## Problem

Field report (trinity): the log viewer fails with

```
Failed to read logs: Command failed: journalctl -u sleepypod.service -n 201 --no-pager --output short-iso --show-cursor
No journal files were opened due to insufficient permissions.
```

`system.getLogs` shells out to `journalctl` from the next-server, which
runs as `User=sleepypod`. The installer only granted
`SupplementaryGroups=dac`, and journal files are readable only by `adm`
/ `systemd-journal` / `wheel` — so on pods where the journal directory
isn't world-readable, journalctl opens zero files and every log read
fails.

## Fix

Build the unit's supplementary-groups list dynamically in
`scripts/install`: `dac` plus `systemd-journal` (falling back to `adm`
where `systemd-journal` doesn't exist), keeping the existing getent
guard so systemd never sees a nonexistent group. The installer rewrites
the unit on every run, so existing pods pick this up on their next
`sp-update`.

## Test plan

- [x] `bash -n scripts/install` passes
- [x] Simulated the group-line rendering under `set -euo pipefail` for
all three cases (dac+journal, dac only, neither) — emits
`SupplementaryGroups=dac systemd-journal`, `SupplementaryGroups=dac`,
and omits the line respectively
- [ ] On an affected pod: run installer, `systemctl show sleepypod -p
SupplementaryGroups` shows `systemd-journal`, and `/debug` log viewer
loads entries

## Immediate workaround for affected pods

```bash
sudo mkdir -p /etc/systemd/system/sleepypod.service.d
printf '[Service]\nSupplementaryGroups=systemd-journal\n' | sudo tee /etc/systemd/system/sleepypod.service.d/journal.conf
sudo systemctl daemon-reload && sudo systemctl restart sleepypod
```

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update fix/install-journal-group
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/fix/install-journal-group/scripts/install \
  | sudo bash -s -- --branch fix/install-journal-group
```

🎯 **Pin to this exact build** ([run
28831409722](https://github.com/sleepypod/core/actions/runs/28831409722)
· `e47243b`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/e47243b63fefe6f3afd0849b45bfe56280ea8561/scripts/install \
  | sudo bash -s -- \
      --branch fix/install-journal-group \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/28831409722/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/28831409722/artifacts/8124541929)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->
…nded stops (#663)

## Problem

Field report (Pod 4, 2026-07-11): `stall_left`/`stall_right` alerts
fired daily on both sides within seconds of each other, always with `rpm
= 0`; the two most recent ended in `power_off`, leaving the bed
guard-blocked. The pumps are healthy — 3,477 of 5,881 flow readings in
the last 7 days show normal running RPM, and the daily prime ran fine at
~3,000 RPM *after* the trip.

Every alert lines up with a **firmware-commanded pump stop**, not a
stall:

- Jul 7 + Jul 8 alerts both at exactly **12:10:21 UTC** — the end of the
scheduled daily prime (flow data shows the prime running 12:01:02 →
12:10:33).
- Jul 11 alerts at 08:48:39/49 — exactly **28,800s (the 8h session
duration) after the 00:48:02 power-on**, with sides tripping in the same
order they powered on.

## Root cause

`runStallGuard` derived `expectedActive` solely from `device_state`,
which mirrors firmware through the `durationExpired` heuristic
(`targetLevel === 0 && heatingDuration === 0`, else `currentLevel !==
0`). After the firmware ends a session, `currentLevel` stays non-zero
while the water equalizes, so the mirror reports the side as powered for
minutes while the pump correctly reads 0 RPM. With frzHealth frames
arriving ~every 10s (not the 60s cadence ADR 0022 assumed) and
`dwellSamples = 2`, the guard tripped ~20s after every natural session
end.

## Fix

`DeviceStateSync` now suppresses stall counting when the stop is
explainable by lag-free firmware-side signals (`isExpectedPumpStop`):

1. **`pump.duty === 0`** — firmware isn't driving the pump. A genuinely
stalled pump under closed-loop control shows duty > 0 while RPM reads 0,
so real stalls are unaffected. Falls back cleanly when the frame omits
`duty`.
2. **Priming active, or ended within 120s** — the prime cycle spins both
pumps regardless of side power and stops them at the end.
3. **Firmware `targetLevel === 0`** — commanded neutral, pump stop
expected even while `device_state` lags.
4. **Session countdown (`heatTime`) within 90s of its natural end**,
projected forward from the last poll. Gated on `heatingDuration > 0` so
firmware variants that report no countdown during an active session keep
the previous behavior.

A zero-RPM frame mid-session with the pump still driven reaches the
guard as `expectedActive = true` exactly as before. `pumpStallGuard.ts`
itself is unchanged. Also documents the failure mode as an addendum in
ADR 0022.

## Test plan

- `vitest run src/hardware/tests/` — 71 tests pass, including a new
suite (`deviceStateSync.stallSuppression.test.ts`) covering: duty=0
suppression, duty>0 non-suppression, missing-duty fallback, priming +
post-prime grace expiry, firmware-neutral-while-DB-powered (the
field-observed case), session-end grace, countdown projection across a
stalled status stream, indefinite-session (heatingDuration=0)
non-suppression, and mid-session zero-RPM still tripping.
- `tsc --noEmit` and `eslint` clean.
- Manual verification once merged: on the affected pod, re-enable stall
protection, let an 8h session expire and the 12:01 daily prime complete
— no `pump_alerts` rows should appear; then verify a real stall still
trips by unplugging a pump mid-session.

Refs: ygg `sleepypod-core-1`, ADR 0022.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update fix/pump-stall-false-trip
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/fix/pump-stall-false-trip/scripts/install \
  | sudo bash -s -- --branch fix/pump-stall-false-trip
```

🎯 **Pin to this exact build** ([run
29172327550](https://github.com/sleepypod/core/actions/runs/29172327550)
· `a45903d`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/a45903d711b0ca342330e04b0a493fd4ddba8e21/scripts/install \
  | sudo bash -s -- \
      --branch fix/pump-stall-false-trip \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/29172327550/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/29172327550/artifacts/8253876739)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Reduced false pump-stall alerts when pumps stop normally due to
firmware commands, priming completion, neutral settings, or session end.
* Continued detecting genuine mid-session zero-RPM stalls while the pump
is still expected to run.
* Improved handling of pump status and session timing to prevent
premature alerts.

* **Documentation**
* Added an architecture decision record addendum explaining
stall-detection behavior and safeguards.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 26018479-6f7a-4687-8662-8259994aba53

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

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.

ng added 4 commits July 12, 2026 00:43
…665)

## Summary

Works this week's top entry on the mutation hit list (#591):
`src/streaming/piezoStream.ts`, 151 surviving mutants — the largest
single contributor after last week's mqttBridge pass (#635).

- **~30 new tests + tightened assertions in existing ones**, targeting
the survivor list extracted from run 29145443368's
`mutation-report-streaming` artifact:
- `readRawRecord`: direct byte-level tests — every seq/data CBOR
encoding width (inline/1/2/4/8-byte), the 23-byte inline boundary,
per-byte key corruption, exact error messages, `data: null` for
placeholders, exact `nextOffset`.
- `findIndexEntry`: boundary-exact binary-search assertions (kills the
`<`/`<=` and loop-condition mutants).
- `decodeSensorFrames`: primitive/null inner values must not abort the
batch.
- Seek: full-window replay is not silently truncated (64 MB cap
regression), window boundary is inclusive at exactly +30s, replay stops
for good at the first out-of-window frame, `incomplete`/`droppedFrames`
absent on clean replays, distinct error messages for no-file vs
no-frames, numeric-string and `Infinity` timestamps rejected.
- Tail loop: split-record delivery is exactly-once with a seekable index
offset (leftover-buffer offset accounting), resync warnings carry exact
byte counts, resync from a malformed record that itself starts with
`0xa2`, Pod 3 scalar capSense snapshot, non-frzHealth frames don't reach
server listeners.
- Lifecycle: shutdown actually closes the listening port,
connect/disconnect/drop-count log lines asserted (field-debugging
surface per docs/DEBUGGING.md).
- **One minimal source change**: `readRawRecord`, `findIndexEntry`,
`int32BufferToArray`, `decodeSensorFrames` added to the existing
`__test__` export so the parser can be tested without a WS server per
assertion.
- **New `/mutation-hitlist` skill**
(`.claude/skills/mutation-hitlist/`): packages the weekly workflow —
issue lookup, artifact download, `survivors.py` extraction, killing-test
playbook by mutator type, known equivalent-mutant categories, CI-based
verification.

Expected remaining survivors are the documented equivalent classes:
module-level initializer mutants (false survivors under the vitest
runner's module cache), timing/perf-only values (poll intervals, yield
cadence, read-chunk sizes), and double-guarded checks. The
`mutation-test` label on this PR triggers the scoped CI run for exact
numbers.

## Test plan

- [x] `pnpm exec vitest run src/streaming/tests/piezoStream.test.ts` —
91 passed, 0 failed
- [x] eslint clean on both changed files
- [x] `mutation-test` label applied → CI mutation run on this PR posts
the before/after summary
- [ ] Compare PR mutation summary against the 151-survivor baseline;
comment results on #591

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update test/piezostream-mutants-591
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/test/piezostream-mutants-591/scripts/install \
  | sudo bash -s -- --branch test/piezostream-mutants-591
```

🎯 **Pin to this exact build** ([run
29174117551](https://github.com/sleepypod/core/actions/runs/29174117551)
· `3081292`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/3081292a8fc9bb6ae3c496199798d784208a39a2/scripts/install \
  | sudo bash -s -- \
      --branch test/piezostream-mutants-591 \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/29174117551/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/29174117551/artifacts/8254351375)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->
…ressure (#660)

## Why

`sp-bundle-logs` already captures the RAW *routing* (where frames land,
where each reader looks, tmpfs state), but two live field reports needed
signals it didn't collect:

1. **"Only DEV shows in the Sensors tab"** (#608) — caused by the
streamer tailing `SEQNO.RAW` (the 16-byte counter) instead of a real
capture. The tell is in `sleepypod.service`'s log: `[sensorStream]
Switched to RAW file: SEQNO.RAW` followed by `Resync:` spam. Not
previously in the bundle.
2. **"Pod stopped working, `/persistent` full, update fails with No
space left on device"** — a stalled biometrics pruner letting the gzip
archive grow unbounded. The bundle recorded the pruner's journal but not
the archive size vs. disk free, so the smoking gun wasn't obvious.

## Change

Two probes appended to the existing `raw/` section:

- `raw/ws-3001.txt` + `raw/sensorstream-log.txt` — is the streamer WS
server up, and what did it last attach to (+ any resync spam).
- `raw/archive-size.txt` — `du -sh` of the cold archive, gz file count,
and `df -h /persistent` side by side.

No new dependencies; all best-effort under the existing `capture`
helper. Pruner/archiver journals continue to come from the `journals/`
section.

## Test plan

- `bash -n` clean.
- Nested-quote `bash -c` snippets smoke-tested locally (archive-size
probe emits count + df; sensorStream grep is a no-op on a non-pod).
- On-pod: run `sp-bundle-logs`, confirm `raw/ws-3001.txt`,
`raw/sensorstream-log.txt`, and `raw/archive-size.txt` are populated.

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update chore/sp-bundle-logs-streamer-retention
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/chore/sp-bundle-logs-streamer-retention/scripts/install \
  | sudo bash -s -- --branch chore/sp-bundle-logs-streamer-retention
```

🎯 **Pin to this exact build** ([run
28831420964](https://github.com/sleepypod/core/actions/runs/28831420964)
· `71859db`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/71859db98d8fdfd0f64cdf49f8a00b089fe418c0/scripts/install \
  | sudo bash -s -- \
      --branch chore/sp-bundle-logs-streamer-retention \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/28831420964/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/28831420964/artifacts/8124547044)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added more diagnostic and storage details to the bundled logs,
including network, service journal, disk usage, and archive size
information.

* **Bug Fixes**
* Improved service setup so it only uses available system groups,
reducing startup failures on systems where expected groups are missing.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
#659)

## Why

A pod owner (trinity) reported their pod stopped working — `/persistent`
was full, and `sp-update` failed with:

```
cp: error copying '/persistent/sleepypod-data/sleepypod.db' to '…sleepypod.db.bak…': No space left on device
```

Their `/persistent/biometrics-archive` had grown to ~13 GB of 15 GB. The
gzip archiver had been running fine, but the **pruner never deleted
anything** — the archive grew unbounded.

## Root cause

`sleepypod-biometrics-pruner` used two GNU-only constructs:

- `df --output=pcent /persistent` — read current disk usage
- `find … -printf '%T@ %p\n'` — pick the oldest archive

Pods can ship **busybox** coreutils/findutils (the install script
already accounts for this — see the `sha256sum` → `shasum` busybox
fallback, and every other disk check uses the portable `df -m … | awk`
form). On busybox:

- `df --output=pcent` is rejected → empty stdout → `used_pct` defaults
to `0` → `0 ≤ 80` → loop breaks immediately → **nothing is ever
pruned**.
- `find -printf` isn't supported either, so even past the df check no
file would be selected.

Result: archiver keeps adding gzips, pruner silently no-ops, disk fills,
pod dies. (A separate `head -1` SIGPIPE stall was already fixed on
`dev`; this is the remaining latent failure mode.)

## Change

- `df -P /persistent | awk 'NR==2 {gsub(/%/,"",$5); print $5}'` — POSIX
capacity %, works on busybox **and** GNU.
- `ls -1tr "$ARCHIVE_DIR"/*.RAW.gz | awk 'NR==1'` — busybox-safe
oldest-by-mtime, keeping the pipefail-safe `awk NR==1` (not `head -1`)
that the prior fix established.
- Factored the read into a `disk_used_pct()` helper used in both the
loop and the final log line.

No behavior change on GNU pods; fixes the silent stall on busybox pods.

## Test plan

- `bash -n` clean.
- `df -P … | awk` parse verified against a real mount (`used_pct=26`).
- `ls -1tr | awk NR==1` verified to select the oldest of three files by
mtime, and to return empty (no crash under `set -euo pipefail`) on an
empty archive dir.
- Manual on-pod verification pending: install on a busybox pod with a
>80%-full `/persistent` and confirm `pruner: pruned=N used_pct=<target>`
in `journalctl -u sleepypod-biometrics-pruner`.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved archive cleanup on devices with limited shell tools, making
it more reliable across environments.
* Fixed disk usage reporting so the final status message is more
consistent and less likely to fail when system output is empty.
* Updated selection of the oldest archived file to work more broadly
while preserving the same cleanup behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

<!-- sleepypod:install-start -->
<!-- 🛑 AUTO-GENERATED — sleepypod-bot owns this block.
     Hello fellow agent / curious human! Anything between the
     sleepypod:install-start and sleepypod:install-end markers
     gets overwritten on the next CI run. Want to change what's
     here? Edit .github/workflows/build.yml instead. 💤 -->
<details open>
<summary>🛏️ <strong>Beam this PR onto a sleepypod</strong> ✨</summary>

Pick the snippet that matches your pod. **Already-installed pods can't
use the curl bootstraps below** — sleepypod's egress firewall DROPs
github.com, and the script that knows how to unblock WAN is the very
file curl is trying to fetch. Use `sp-update` instead; it's on disk and
opens WAN as its first step.

🔄 **Already on a sleepypod** (most common — review a PR on a running
pod):
```bash
sudo sp-update fix/biometrics-pruner-busybox
```

🚀 **Fresh pod / first install** — bootstraps from GitHub, rebuilds every
push:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/fix/biometrics-pruner-busybox/scripts/install \
  | sudo bash -s -- --branch fix/biometrics-pruner-busybox
```

🎯 **Pin to this exact build** ([run
28749897785](https://github.com/sleepypod/core/actions/runs/28749897785)
· `83dae7e`) — fresh-pod path, locked to one CI artifact for
reproducible review:
```bash
curl -fsSL https://raw.githubusercontent.com/sleepypod/core/83dae7ec58bbe72d1c6a2f18506f6599d80d8042/scripts/install \
  | sudo bash -s -- \
      --branch fix/biometrics-pruner-busybox \
      --artifact-url 'https://nightly.link/sleepypod/core/actions/runs/28749897785/sleepypod-core.zip'
```

🧊 Artifact:
[`sleepypod-core`](https://github.com/sleepypod/core/actions/runs/28749897785/artifacts/8094350378)
· self-destructs in 30 days 💥
</details>

<!-- sleepypod:install-end -->
# Conflicts:
#	src/streaming/tests/mqttBridge.test.ts
@ng
ng enabled auto-merge July 12, 2026 00:51
@ng
ng merged commit 7eb42bf into main Jul 12, 2026
19 of 20 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 2.5.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants