Commit Graph

2433 Commits

Author SHA1 Message Date
renovate[bot]
2d93ea0955 chore(deps): update dependency sonner to v2.0.8 (#6093)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [sonner](https://sonner.emilkowal.ski/)
([source](https://redirect.github.com/emilkowalski/sonner)) | [`2.0.7` →
`2.0.8`](https://renovatebot.com/diffs/npm/sonner/2.0.7/2.0.8) |
![age](https://developer.mend.io/api/mc/badges/age/npm/sonner/2.0.8?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/sonner/2.0.7/2.0.8?slim=true)
|

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>emilkowalski/sonner (sonner)</summary>

###
[`v2.0.8`](https://redirect.github.com/emilkowalski/sonner/compare/v2.0.7...ecce1841c55e4a72dfe139a8992b56498660125e)

[Compare
Source](https://redirect.github.com/emilkowalski/sonner/compare/v2.0.7...v2.0.8)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- 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/block/buzz).

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

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-21 18:28:51 -06:00
renovate[bot]
9390e11c9b chore(deps): update rust crate http-body-util to v0.1.4 (#5452)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [http-body-util](https://redirect.github.com/hyperium/http-body) |
dependencies | patch | `0.1.3` → `0.1.5` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>hyperium/http-body (http-body-util)</summary>

###
[`v0.1.5`](https://redirect.github.com/hyperium/http-body/compare/http-body-util-v0.1.4...http-body-util-v0.1.5)

[Compare
Source](https://redirect.github.com/hyperium/http-body/compare/http-body-util-v0.1.4...http-body-util-v0.1.5)

###
[`v0.1.4`](https://redirect.github.com/hyperium/http-body/releases/tag/http-body-util-v0.1.4)

[Compare
Source](https://redirect.github.com/hyperium/http-body/compare/http-body-util-v0.1.3...http-body-util-v0.1.4)

#### What's Changed

- Add `Fused` body combinator that always returns `None` once completed.
- Add `BodyExt::into_stream()` to convert a body into a `Stream`.
- Add `Full::into_inner()` to get the full `Buf`.
- Add `InspectFrame` and `InspectErr` combinators.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- 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/block/buzz).

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

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-21 18:28:38 -06:00
renovate[bot]
1a0a27d358 chore(deps): update rust crate http to v1.4.2 (#5451)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [http](https://redirect.github.com/hyperium/http) | dependencies |
patch | `1.4.0` → `1.4.2` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>hyperium/http (http)</summary>

###
[`v1.4.2`](https://redirect.github.com/hyperium/http/blob/HEAD/CHANGELOG.md#142-June-8-2026)

[Compare
Source](https://redirect.github.com/hyperium/http/compare/v1.4.1...v1.4.2)

- Fix `uri::Builder` to allow `"*"` as the path when scheme and
authority are also set, used in HTTP/2 requests.
- Fix `Uri` to properly reject `DEL` characters.

###
[`v1.4.1`](https://redirect.github.com/hyperium/http/blob/HEAD/CHANGELOG.md#141-May-25-2026)

[Compare
Source](https://redirect.github.com/hyperium/http/compare/v1.4.0...v1.4.1)

- Fix `PathAndQuery::from_static()` and `from_shared()` to reject inputs
that do not start with `/`.
- Fix `Extend` for `HeaderMap` to clamp max size hint and not overflow.
- Fix `header::IntoIter` that could use-after-free if the generic value
type could panic on drop.
- Fix `header::{IterMut, ValuesIterMut}` to not violate stacked borrows.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- 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/block/buzz).

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

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-21 18:28:22 -06:00
renovate[bot]
d874d67c11 chore(deps): update rust crate futures-util to v0.3.33 (#5448)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [futures-util](https://rust-lang.github.io/futures-rs)
([source](https://redirect.github.com/rust-lang/futures-rs)) |
dependencies | patch | `0.3.32` → `0.3.34` |
| [futures-util](https://rust-lang.github.io/futures-rs)
([source](https://redirect.github.com/rust-lang/futures-rs)) |
workspace.dependencies | patch | `0.3.32` → `0.3.34` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>rust-lang/futures-rs (futures-util)</summary>

###
[`v0.3.34`](https://redirect.github.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#0334---2026-08-11)

[Compare
Source](https://redirect.github.com/rust-lang/futures-rs/compare/0.3.33...0.3.34)

- Preserve cloned waker identity.
([#&#8203;3032](https://redirect.github.com/rust-lang/futures-rs/issues/3032))
- Updato `syn` to 3.
([#&#8203;3028](https://redirect.github.com/rust-lang/futures-rs/issues/3028))

###
[`v0.3.33`](https://redirect.github.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#0333---2026-07-18)

[Compare
Source](https://redirect.github.com/rust-lang/futures-rs/compare/0.3.32...0.3.33)

- Fix `ReadLine`'s soundness issue regarding to exception safety.
([#&#8203;3020](https://redirect.github.com/rust-lang/futures-rs/issues/3020))
- Fix unsound `Send` impl for `IterPinRef` and `Iter`.
([#&#8203;3003](https://redirect.github.com/rust-lang/futures-rs/issues/3003))
- Fix stacked borrows violation in `compat01as03` implementation.
([#&#8203;3012](https://redirect.github.com/rust-lang/futures-rs/issues/3012))
- Fix memory leak in `FuturesUnordered::IntoIter`.
([#&#8203;3005](https://redirect.github.com/rust-lang/futures-rs/issues/3005))
- Add `portable-atomic-alloc` feature and use it in `FuturesUnordered`.
([#&#8203;3007](https://redirect.github.com/rust-lang/futures-rs/issues/3007))
- Re-export `alloc::task::Wake`.
([#&#8203;3010](https://redirect.github.com/rust-lang/futures-rs/issues/3010))
- Update `spin` to 0.12.
([#&#8203;3014](https://redirect.github.com/rust-lang/futures-rs/issues/3014))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- 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/block/buzz).

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

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-21 18:28:08 -06:00
renovate[bot]
2cef92df67 chore(deps): update rust crate futures to v0.3.33 (#5445)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [futures](https://rust-lang.github.io/futures-rs)
([source](https://redirect.github.com/rust-lang/futures-rs)) |
dev-dependencies | patch | `0.3.32` → `0.3.34` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>rust-lang/futures-rs (futures)</summary>

###
[`v0.3.34`](https://redirect.github.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#0334---2026-08-11)

[Compare
Source](https://redirect.github.com/rust-lang/futures-rs/compare/0.3.33...0.3.34)

- Preserve cloned waker identity.
([#&#8203;3032](https://redirect.github.com/rust-lang/futures-rs/issues/3032))
- Updato `syn` to 3.
([#&#8203;3028](https://redirect.github.com/rust-lang/futures-rs/issues/3028))

###
[`v0.3.33`](https://redirect.github.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#0333---2026-07-18)

[Compare
Source](https://redirect.github.com/rust-lang/futures-rs/compare/0.3.32...0.3.33)

- Fix `ReadLine`'s soundness issue regarding to exception safety.
([#&#8203;3020](https://redirect.github.com/rust-lang/futures-rs/issues/3020))
- Fix unsound `Send` impl for `IterPinRef` and `Iter`.
([#&#8203;3003](https://redirect.github.com/rust-lang/futures-rs/issues/3003))
- Fix stacked borrows violation in `compat01as03` implementation.
([#&#8203;3012](https://redirect.github.com/rust-lang/futures-rs/issues/3012))
- Fix memory leak in `FuturesUnordered::IntoIter`.
([#&#8203;3005](https://redirect.github.com/rust-lang/futures-rs/issues/3005))
- Add `portable-atomic-alloc` feature and use it in `FuturesUnordered`.
([#&#8203;3007](https://redirect.github.com/rust-lang/futures-rs/issues/3007))
- Re-export `alloc::task::Wake`.
([#&#8203;3010](https://redirect.github.com/rust-lang/futures-rs/issues/3010))
- Update `spin` to 0.12.
([#&#8203;3014](https://redirect.github.com/rust-lang/futures-rs/issues/3014))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- 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/block/buzz).

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

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-21 18:27:52 -06:00
renovate[bot]
f84511c169 chore(deps): update dependency @tauri-apps/api to v2.11.1 (#5444)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@tauri-apps/api](https://redirect.github.com/tauri-apps/tauri) |
[`2.11.0` →
`2.11.1`](https://renovatebot.com/diffs/npm/@tauri-apps%2fapi/2.11.0/2.11.1)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@tauri-apps%2fapi/2.11.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@tauri-apps%2fapi/2.11.0/2.11.1?slim=true)
|

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Release Notes

<details>
<summary>tauri-apps/tauri (@&#8203;tauri-apps/api)</summary>

###
[`v2.11.1`](https://redirect.github.com/tauri-apps/tauri/releases/tag/%40tauri-apps/api-v2.11.1):
@&#8203;tauri-apps/api v2.11.1

[Compare
Source](https://redirect.github.com/tauri-apps/tauri/compare/@tauri-apps/api-v2.11.0...@tauri-apps/api-v2.11.1)

<details>
<summary><em><h4>PNPM Audit</h4></em></summary>

```
No known vulnerabilities found
```

</details>

#### \[2.11.1]
##### Enhancements

-
[`916782601`](9167826011)
([#&#8203;15520](https://redirect.github.com/tauri-apps/tauri/pull/15520)
by [@&#8203;polw1](https://www.github.com/tauri-apps/tauri/../../polw1))
Document that `Monitor.size`, `Monitor.position` and `Monitor.workArea`
are in physical pixels, with examples showing how to convert them to the
logical pixels expected by window creation options via
`toLogical(monitor.scaleFactor)`.

<details>
<summary><em><h4>PNPM Publish</h4></em></summary>

```
> @tauri-apps/api@2.11.1 npm-publish /home/runner/work/tauri/tauri/packages/api
> pnpm build && cd ./dist && pnpm publish --access public --loglevel silly --no-git-checks

> @tauri-apps/api@2.11.1 build /home/runner/work/tauri/tauri/packages/api
> rollup -c --configPlugin typescript


./src/app.ts, ./src/core.ts, ./src/dpi.ts, ./src/event.ts, ./src/image.ts, ./src/index.ts, ./src/menu.ts, ./src/mocks.ts, ./src/path.ts, ./src/tray.ts, ./src/webview.ts, ./src/webviewWindow.ts, ./src/window.ts → ./dist, ./dist...
created ./dist, ./dist in 883ms

src/index.ts → ../../crates/tauri/scripts/bundle.global.js...
created ../../crates/tauri/scripts/bundle.global.js in 1.4s
npm verbose cli /opt/hostedtoolcache/node/24.16.0/x64/bin/node /opt/hostedtoolcache/node/24.16.0/x64/bin/npm
npm info using npm@11.13.0
npm info using node@v24.16.0
npm silly config load:file:/opt/hostedtoolcache/node/24.16.0/x64/lib/node_modules/npm/npmrc
npm silly config load:file:/tmp/286e8dee195254a4370e608b672019b0/.npmrc
npm silly config load:file:/home/runner/.npmrc
npm silly config load:file:/home/runner/.config/pnpm/rc
npm verbose title npm publish tauri-apps-api-2.11.1.tgz
npm verbose argv "publish" "--ignore-scripts" "tauri-apps-api-2.11.1.tgz" "--access" "public" "--loglevel" "silly"
npm verbose logfile logs-max:10 dir:/home/runner/.npm/_logs/2026-06-17T13_41_23_851Z-
npm verbose logfile /home/runner/.npm/_logs/2026-06-17T13_41_23_851Z-debug-0.log
npm warn Unknown env config "verify-deps-before-run". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.
npm warn Unknown env config "npm-globalconfig". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.
npm warn Unknown env config "overrides". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.
npm warn Unknown env config "_jsr-registry". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.
npm silly logfile done cleaning log files
npm verbose publish [ 'tauri-apps-api-2.11.1.tgz' ]
npm http cache file:/tmp/286e8dee195254a4370e608b672019b0/tauri-apps-api-2.11.1.tgz 0ms (cache hit)
npm notice
npm notice 📦  @tauri-apps/api@2.11.1
npm notice Tarball Contents
npm notice 99.3kB CHANGELOG.md
npm notice 10.2kB LICENSE_APACHE-2.0
npm notice 1.1kB LICENSE_MIT
npm notice 3.5kB README.md
npm notice 5.9kB app.cjs
npm notice 5.4kB app.d.ts
npm notice 5.5kB app.js
npm notice 11.2kB core.cjs
npm notice 6.5kB core.d.ts
npm notice 10.7kB core.js
npm notice 11.0kB dpi.cjs
npm notice 8.8kB dpi.d.ts
npm notice 10.8kB dpi.js
npm notice 5.8kB event.cjs
npm notice 4.9kB event.d.ts
npm notice 5.7kB event.js
npm notice 2.2kB external/tslib/tslib.es6.cjs
npm notice 2.2kB external/tslib/tslib.es6.js
npm notice 3.0kB image.cjs
npm notice 2.4kB image.d.ts
npm notice 2.9kB image.js
npm notice 738B index.cjs
npm notice 1.2kB index.d.ts
npm notice 669B index.js
npm notice 1.1kB menu.cjs
npm notice 451B menu.d.ts
npm notice 717B menu.js
npm notice 3.6kB menu/base.cjs
npm notice 887B menu/base.d.ts
npm notice 3.6kB menu/base.js
npm notice 2.2kB menu/checkMenuItem.cjs
npm notice 1.5kB menu/checkMenuItem.d.ts
npm notice 2.2kB menu/checkMenuItem.js
npm notice 7.4kB menu/iconMenuItem.cjs
npm notice 6.1kB menu/iconMenuItem.d.ts
npm notice 7.4kB menu/iconMenuItem.js
npm notice 5.1kB menu/menu.cjs
npm notice 4.4kB menu/menu.d.ts
npm notice 5.0kB menu/menu.js
npm notice 1.7kB menu/menuItem.cjs
npm notice 1.3kB menu/menuItem.d.ts
npm notice 1.6kB menu/menuItem.js
npm notice 1.1kB menu/predefinedMenuItem.cjs
npm notice 2.6kB menu/predefinedMenuItem.d.ts
npm notice 1.1kB menu/predefinedMenuItem.js
npm notice 7.1kB menu/submenu.cjs
npm notice 4.8kB menu/submenu.d.ts
npm notice 6.9kB menu/submenu.js
npm notice 9.8kB mocks.cjs
npm notice 5.0kB mocks.d.ts
npm notice 9.7kB mocks.js
npm notice 1.8kB package.json
npm notice 22.7kB path.cjs
npm notice 17.7kB path.d.ts
npm notice 21.7kB path.js
npm notice 7.1kB tray.cjs
npm notice 8.5kB tray.d.ts
npm notice 7.0kB tray.js
npm notice 20.7kB webview.cjs
npm notice 23.8kB webview.d.ts
npm notice 20.5kB webview.js
npm notice 8.4kB webviewWindow.cjs
npm notice 4.9kB webviewWindow.d.ts
npm notice 8.3kB webviewWindow.js
npm notice 68.1kB window.cjs
npm notice 64.9kB window.d.ts
npm notice 67.2kB window.js
npm notice Tarball Details
npm notice name: @tauri-apps/api
npm notice version: 2.11.1
npm notice filename: tauri-apps-api-2.11.1.tgz
npm notice package size: 135.7 kB
npm notice unpacked size: 699.0 kB
npm notice shasum: cd6b13fc26403ca095a02e39ecdbec8048d2872d
npm notice integrity: sha512-M2FPuYND2m+wh[...]sUepJWugQCvAA==
npm notice total files: 67
npm notice
npm http fetch GET https://run-actions-1-azure-eastus.actions.githubusercontent.com/113//idtoken/***/***?api-version=2.0&audience=npm%3Aregistry.npmjs.org 200 76ms
npm http fetch POST 201 https://registry.npmjs.org/-/npm/v1/oidc/token/exchange/package/@tauri-apps%2fapi 674ms
npm verbose oidc Successfully retrieved and set token
npm http fetch GET 200 https://registry.npmjs.org/@tauri-apps%2fapi 54ms (cache miss)
npm notice Publishing to https://registry.npmjs.org/ with tag latest and public access
npm notice publish Signed provenance statement with source and build information from GitHub Actions
npm notice publish Provenance statement published to transparency log: https://search.sigstore.dev/?logIndex=1851797040
npm http fetch PUT 200 https://registry.npmjs.org/@tauri-apps%2fapi 2070ms
+ @tauri-apps/api@2.11.1
npm verbose cwd /tmp/286e8dee195254a4370e608b672019b0
npm verbose os Linux 6.17.0-1018-azure
npm verbose node v24.16.0
npm verbose npm  v11.13.0
npm verbose exit 0
npm info ok
```

</details>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- 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/block/buzz).

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

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-21 18:27:38 -06:00
renovate[bot]
9008a4d172 chore(deps): update ubuntu:24.04 docker digest to 561618e (#5442)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [ubuntu](https://hub.docker.com/_/ubuntu)
([source](https://git.launchpad.net/cloud-images/+oci/ubuntu-base)) |
container | digest | `4fbb8e6` → `561618e` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- 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/block/buzz).

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

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-21 18:27:17 -06:00
renovate[bot]
694d804b24 chore(deps): update swatinem/rust-cache digest to 6323deb (#5441)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [Swatinem/rust-cache](https://redirect.github.com/Swatinem/rust-cache)
([changelog](e18b497796..6323deb102))
| action | digest | `e18b497` → `6323deb` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/1) for more information.

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- 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/block/buzz).

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

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-21 18:26:43 -06:00
morgmart
97b1fee5c3 fix(desktop): restore true zoom by scaling the root rem (#6514)
## Summary

Follow-up to #5644. Cmd +/- had become a text-only zoom: type scaled
while rem-based padding, gaps, widths, avatars, and controls stayed
frozen, which produced cramped layouts (see [#buzz-frontend
thread](buzz://message?channel=a410ffde-c61f-416a-96e0-c296b5f5ecc9&id=1a758115cf07b00c097f6e988553908c045165325a57637519cfa7ed9c9accec)).

Root cause: #5644 introduced a virtual typography rem so the **Font
size** preference could change text without moving layout — a good
decoupling — but it also routed **Cmd +/- zoom** through that same
px-valued token and pinned the real root at 16px. One decision ("freeze
layout") was applied to two dials that shouldn't share it.

This PR gives each dial one owner and lets CSS compose them:

| Control | Changes | How |
|---|---|---|
| **Cmd +/- zoom** | Everything — true zoom | Scales the real `<html>`
font-size again (`useWebviewZoomShortcuts`) |
| **Font size preference** | Text only | Sets `data-font-size`;
`typography.css` maps it to a unitless `--buzz-type-scale`, mirroring
how density already works |

`--buzz-type-rem` becomes `calc(1rem * var(--buzz-type-scale))` —
rem-relative, so it rides on zoom automatically. Resulting text px = `16
× zoom × scale × token-ratio`. The 13 / 14 / 15px conversation contract
is unchanged at default zoom. Density and the type ramp from #5644 are
untouched.

The preference module no longer does px math or knows about zoom; the
zoom hook no longer imports the preference module. Net deletion in
production code.

## Validation

- `pnpm test` — 5,308 desktop unit tests
- `pnpm check:px-text`, `tsc --noEmit`, biome
- Playwright: `top-chrome-zoom-clearance.spec.ts` (native-chrome
clearance stays fixed under root zoom),
`inbox-refactor-screenshots.spec.ts` (zoomed row padding now asserts
`4.4px` instead of the frozen `4px`), and both `profile.spec.ts` zoom
tests (composed zoom × preference, cross-window storage reset)
- Before/after screenshots at 140% zoom in the comment below

---------

Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-08-21 17:21:36 -07:00
Max Lampert
eb484387d5 chore(desktop): drop unused ORIGINAL_CONTENT from empty-edit-delete spec (#6517)
`biome check` fails with `lint/correctness/noUnusedVariables` on
`ORIGINAL_CONTENT` in `desktop/tests/e2e/empty-edit-delete.spec.ts`,
which fails `pnpm check` (Desktop Core) for **every PR touching desktop
paths** — e.g. it currently blocks #6460. It presumably landed while
Desktop Core was path-skipped on the introducing PR.

One-line removal; the constant has no remaining references (the
assertions use `RENDERED_ORIGINAL_CONTENT`).

Signed-off-by: Max Lampert <maxwell@squareup.com>
2026-08-21 18:20:19 -06:00
Taylor Ho
0e48ff2691 feat(workflows): clarify workflow setup and activation (#6470)
**Category:** new-feature
**User Impact:** Workflow authors can build filtered, runtime-aware
automations, understand them at a glance, and get a clear warning before
turning on workflows likely to run often.
**Problem:** Workflow setup exposed raw configuration without enough
help composing message templates, filtering triggers, or understanding
saved behavior; activation could also make a broadly triggered workflow
live without explaining its likely frequency.
**Solution:** Batch 3 adds local, deterministic template variables,
trigger filters, and semantic summaries, then refines cards and
activation around configured behavior and a risk-aware warning boundary.
Scheduling remains the already-shipped implementation, advanced
expressions remain lossless, and network-backed identity/message
enrichment stays in Batch 4.

| Message inputs | Trigger filters |
| --- | --- |
| Caret-aware, keyboard-accessible suggestions expose trigger-local
values and safe prior-step outputs in `send_message.text`. | Structured
conditions and validated manual IDs block invalid submission while
preserving advanced expressions. |
| ![Message variable
autocomplete](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6470/message-variables.png)
| ![Structured trigger
filters](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6470/trigger-filters.png)
|

| Workflow cards | Risk-aware activation |
| --- | --- |
| Semantic labels, channel-first hierarchy, configured reaction/action
visuals, real step stacks, and compact status controls make behavior
scannable. | Broad message and frequent schedule triggers explain the
risk before **Turn on**; narrowly scoped triggers proceed without
unnecessary ceremony. |
| ![Semantic workflow
card](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6470/workflow-card.png)
| ![Activation
confirmation](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6470/activation-choice-v2.png)
|

## Changes

<details>
<summary>File changes</summary>

**desktop/src/features/workflows/ui/WorkflowActionsMenu.tsx**  
Separates direct card status controls from secondary actions while
retaining modal status actions.

**desktop/src/features/workflows/ui/WorkflowCard.tsx**  
Adds semantic behavior, channel-first hierarchy, configured
reaction/action visuals, real subsequent-step stacks, status controls,
and reduced-motion-aware trigger feedback.

**desktop/src/features/workflows/ui/WorkflowDialog.tsx**  
Warns before activating broadly triggered workflows while allowing
narrowly scoped workflows to proceed directly.

**desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx**  
Connects structured trigger filters and template-aware step inputs while
preserving schedules, trigger transitions, and selected YAML authority.

**desktop/src/features/workflows/ui/WorkflowStepCard.tsx**  
Replaces generic labels with deterministic configured-step descriptions.

**desktop/src/features/workflows/ui/WorkflowTemplateTextarea.tsx**  
Adds caret-aware variable suggestions with keyboard navigation and focus
restoration.

**desktop/src/features/workflows/ui/WorkflowTriggerConditions.tsx**  
Adds structured local filters, validated author/message IDs, and a
lossless advanced-expression fallback.

**desktop/src/features/workflows/ui/workflowActivationWarning.ts** and
**workflowActivationWarning.test.mjs**
Classify broad message and frequent schedule triggers for contextual
activation warnings.

**desktop/src/features/workflows/ui/workflowConditionExpression.ts** and
**workflowConditionExpression.test.mjs**
Model and cover parsing, serialization, validation, and
advanced-expression preservation.

**desktop/src/features/workflows/ui/workflowDefinition.ts** and
**workflowDefinition.test.mjs**
Preserve trigger/step configuration and derive deterministic card
metadata across YAML round trips.

**desktop/src/features/workflows/ui/workflowStepDescription.ts** and
**workflowStepDescription.test.mjs**
Generate and cover local step summaries.

**desktop/src/features/workflows/ui/workflowTemplateVariables.ts** and
**workflowTemplateVariables.test.mjs**
Define and cover trigger-specific, order-bounded variables and caret
insertion.

**desktop/src/features/workflows/ui/workflowTriggerDescription.ts** and
**workflowTriggerDescription.test.mjs**
Generate and cover semantic trigger summaries without network lookups.

**desktop/tests/e2e/workflow-local-controls.spec.ts** and snapshot  
Cover filters, IDs, advanced expressions, autocomplete, activation
choices, summaries, and YAML authority.

**desktop/tests/e2e/workflow-reaction-picker.spec.ts**  
Covers configured reaction emoji in workflow nodes and summaries.

**desktop/tests/e2e/workflows.spec.ts**  
Covers risk-aware activation warnings, direct safe creation,
duplication, and card status controls.

</details>

## Reproduction steps

1. Create a message-posted workflow in **Workflows**, add a Send message
step, and type `{{trig`; verify keyboard-selectable variables insert at
the caret.
2. Configure message-text and manual ID filters; verify malformed IDs
block submission and advanced expressions survive Form/YAML transitions.
3. Create a broad message workflow; verify **Back** persists nothing,
**Keep off** saves it disabled, and **Turn on** enables it. Confirm a
narrowly triggered webhook skips the warning.
4. Inspect the saved card; verify its channel, semantic behavior,
configured actions/reaction, real step stack, and status are
understandable without opening YAML.

## Validation

Validated at exact clean head `f99503819889b95ee3c61657c5c3850aae35481e`
on base `24ec6a468ec9d0d425ee58fbfc4d416412c446ad`.

- Focused workflow regressions passed 59/60 locally; the only local miss
was a 438-pixel macOS snapshot drift, while the checked-in Linux
baseline comes from the failing CI artifact. Repository pre-push gates
and E2E build/typecheck passed.
- A broader 36-test smoke invocation had 31 passes and five unrelated
pre-existing expectation/snapshot failures, so it is not claimed as
fully green. Adversarial fixes are recorded in [round
one](https://github.com/block/buzz/pull/6470#issuecomment-5366366670)
and [round
two](https://github.com/block/buzz/pull/6470#issuecomment-5366407535).

---------

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Co-authored-by: Mongo <5398c5fd039b963ce132b3e078e7c4af097dd997517bb5e14c2682fe68c25197@buzz.block.builderlab.xyz>
2026-08-21 16:53:50 -07:00
Max Lampert
b85d680fb1 perf(desktop): stop the Projects fan refetching on re-entry and running after leave (#6458)
Entering Projects fires a large fan: an exhaustive paginated relay
enumeration (projects/repos/tombstones), five 2,000-event work-item
queries plus assignment-operation scans, per-repo activity summaries,
and a local-repository filesystem scan. Measured on a large community
(101 issues / 258 PRs):

| query | measured cost |
|---|---|
| work-items (5 × 2,000-event REQs + assignment scans) | 3.5–3.9s |
| activity summaries | 4.1s |
| repository activity | 1.0–2.2s |
| local repository scan | 1.7s |

Two lifecycle bugs made the fan far more expensive than it needs to be:

- **Freshness windows guaranteed a full refetch on nearly every
re-entry** (60s enumeration, 30s work-items/activity, 10s local scan) —
i.e., the costs above were re-paid on almost every visit. Every local
write path already invalidates its keys explicitly (issue/PR mutations,
project creation, repo sync), so the short windows only served
remote-actor freshness. Raised to 5m/2m/2m with a 30m enumeration cache:
re-entries now paint from cache, and the fan re-runs at most every 2–5
minutes.
- **Leaving Projects left the whole fan running**, competing with the
next surface's channel fetches on the same relay connection. AbortSignal
is now threaded through the enumeration and assignment pagination loops
(optional params — behavior identical without a signal), and leaving the
surface cancels the work-items query. Deliberately NOT cancelled: the
enumeration (the always-mounted sidebar projects section observes it and
its 30m cache is valuable), repo snapshots and local scans (native work
that can't abort — cancelling would discard the finished result and
force the same clones again), and activity summaries (a single bounded
request).

Abort behavior is covered by red-first unit tests on both pagination
loops. Remaining follow-up (out of scope): the queries themselves want a
relay-side aggregate instead of shipping thousands of events to compute
counts client-side.

---------

Signed-off-by: Max Lampert <maxwell@squareup.com>
2026-08-21 17:40:35 -06:00
Max Lampert
b0466ac465 perf(desktop): keep the member roster off the channel-switch path (#6456)
Switching channels triggered a full-roster fetch (kind:39002 plus a
kind:0 profile batch with every member pubkey as an author) in the
common case, and several render paths walked the full roster per render.
None of this scales past a few hundred members; the product target is
10k+.

- **Members query staleTime 30s → 5min.** Every membership change the
client can observe already invalidates the key explicitly: live
join/leave system messages for the active channel, member-added/removed
notifications for the current identity, and all membership mutations —
including previously-uncovered direct write paths (moderation kick,
agent-deletion cleanup), which now invalidate through a shared helper.
The 30s window bought correctness we already had and charged a roster
fetch per switch.
- **ChannelMembersBar no longer mounts the roster query for non-DM
channels** — the count renders from the channel summary, and the
private-channel huddle gate accepts `channel.isMember` (derived from the
same kind:39002 event as the roster's self entry).
- **Roster-derived lookups are cached on roster identity**
(`rosterDerivations.ts`): role map, agent-member subset, member/bot
pubkey sets. These were rebuilt O(members) on every live message /
profile re-key. React Query's structural sharing keeps the roster
identity stable, so each derivation computes once per distinct roster.
- **Backend: the kind:0 profile join in `get_channel_members` is capped
at the first 500 members** (roster order). Members past the cap keep
`display_name: None` (UI falls back to pubkey labels and profile
caches); `role=="bot"` agent flags are roster-derived and unaffected.
Full roster pagination is the structural follow-up.
- **Composer keystroke path**: `useCanAddChannelMembers` re-scanned
channels + roster per keystroke; now memoized on data identities,
sharing the cached pubkey set.

### Measured / estimated impact

| metric | before | after |
|---|---|---|
| roster fetches while switching (live trace) | nearly every switch | ≤1
per channel per 5 min |
| roster fetch cost on the wire (live, 51-member channel) | 273ms per
fetch | amortized away |
| kind:0 `authors` filter size at 10k members | ~670KB per request (~67
B/pubkey) | capped at 500 authors (~34KB) |
| warm-switch longtask at 10k members (mock harness, 4× throttle) |
364ms | 318ms |
| per-render roster walks (role map, agent sets) at 10k members |
O(members) per live message | once per distinct roster |

Deferred deliberately: protocol-level roster pagination and removing
`memberPubkeys` from channel summaries (needs relay support).

---------

Signed-off-by: Max Lampert <maxwell@squareup.com>
2026-08-21 17:40:20 -06:00
Brad Seiler
47526784d5 fix(deletion): allow IRSA S3 credentials (#6495)
## Why
`buzz-admin deletions` runs inside bb-public relay pods, where S3
credentials are provided by the pod credential chain rather than static
`BUZZ_S3_ACCESS_KEY` / `BUZZ_S3_SECRET_KEY` values. The deletion CLI was
requiring those two env vars to be non-empty before constructing the
shared media storage client, so it could not reach the existing default
AWS credential chain.

## What
- Treat missing/blank deletion S3 access key and secret key as an empty
credential pair so `MediaStorage::new` can use `Credentials::default()`.
- Keep the existing static-credential path unchanged when both values
are non-empty.
- Keep deletion unit tests deterministic by covering only deletion env
normalization for missing/blank pair, trimmed static pair, and
partial/whitespace-partial outputs; shared media tests continue to own
credential-pair enforcement.

## Risk Assessment
Low and scoped to the operator-only community deletion CLI startup path.
The shared media storage credential validation still owns
static-vs-default credential selection and still rejects mixed partial
credentials.

## Testing
At committed head `0a86c2914b1f97caf4788a771048aa8d9d9d88ac` with a
clean worktree before and after (`git rev-parse HEAD` before/after
matched):
- `just fmt-check` — passed.
- `cargo test -p buzz-deletion` — passed: 12 passed, 9 ignored.
- `cargo test -p buzz-media` — passed: 120 passed;
`static_creds_round_trip_against_minio` remained ignored because it
requires live MinIO.
- `cargo test -p buzz-admin` — passed: 1 passed.
- `cargo clippy -p buzz-deletion --all-targets -- -D warnings` — passed.
- Startup smoke at the same head: built `buzz-admin`, then ran
`target/debug/buzz-admin deletions drain` with `BUZZ_S3_ACCESS_KEY=` and
`BUZZ_S3_SECRET_KEY=' '` plus `AWS_ACCESS_KEY_ID` /
`AWS_SECRET_ACCESS_KEY` fallback credentials; command exited `0`,
proving startup transitions past deletion S3 key validation and
exercises the shared default credential-chain branch using AWS env
fallback credentials.
- `git push origin HEAD:seiler/deletion-irsa-credentials` — passed;
pre-push hooks passed.

Not run: the full `TESTING.md` live-local relay workflow. Docker Desktop
currently refuses CLI access on this machine with `Sign in to continue
using Docker Desktop. Membership in the [squareup] organization is
required.`

## References
- Buzz channel:
`buzz://message?channel=9e4aabc6-414c-4978-aba7-b9f5228776de&id=177c5b8ad9e78a647f438ec7040d25f0c20a7c2b8678dd0e34768effe053f7f4`

Generated with Codex

---------

Signed-off-by: coder 0 <d97ebdbb198c7237c94f84ea8bb8a73583ea067407eebd0062abbb3962527fb1@buzz.block.builderlab.xyz>
Co-authored-by: coder 0 <d97ebdbb198c7237c94f84ea8bb8a73583ea067407eebd0062abbb3962527fb1@buzz.block.builderlab.xyz>
2026-08-21 19:14:00 -04:00
Tyler
d97780b477 docs(nips): comprehensive NIP-FI — core + claimable profiles (EDGE/LIFECYCLE/DELEG/CONF) (#5946)
## What

Comprehensive NIP-FI against `main`: one normative core plus four
separately
claimable profiles, replacing the single-document structure of #3726
(which was
based on #1485's branch, not `main`). Six documents, 1,975 lines, docs
only.

- **`NIP-FI.md` (core, 632 lines)** — issuer-qualified identity `(iss,
sub)`,
independent Nostr proof, client-attached assertion, partial bijection
with
durable tombstones, atomic final admission, bounded leases, private
denials
  with a closed response vocabulary, retire/revoke/rotate, two contract
identities (`assertion_policy_id`, `transport_contract_id`), per-policy
  `skew` / `maximum_assertion_age` / `maximum_status_age` with missing
configuration denying, a closed token-class rule (`at+jwt`,
`nip-fi+jwt`,
  named compatibility; ID tokens always deny), declared freshness class
  (`offline-jwt` | `current-status`), server-declared body authorization
  relevance (NIP-98 payload-binding fix, including a `payload` tag on an
irrelevant-body operation), BCP 14, "equivalent" defined over identity /
bounds / provenance classes, a compact non-normative worked wire
example,
  and a non-normative comparison with DPoP, mTLS-bound tokens, and HTTP
  Message Signatures. FI-INV-01..16 are normative core text. The
behavioral-oracle table lists exactly 30 oracle IDs, one per row, with
no
  shorthand.
- **`NIP-FI-EDGE.md`** — trusted-edge surface: the
`trusted-proxy-hmac-v2`
envelope + canonicalization, or a private authenticated-edge adapter
under a
reviewed contract; `authorization_domain_id` derivation (exact 16 RFC
9562
UUID bytes); `proof_transport_code` registry (0x01 NIP-42, 0x02 NIP-98;
  0x03 Git smart-HTTP and 0x04 Blossom reserved pending their transport
contracts; 0x05–0x7f unassigned pending published stable specifications)
  + extension procedure; body-acquisition bounds; three normative test
vectors. An independent Nostr proof (the NIP-98 event in
`Authorization`,
  which reaches the verifier byte-identical, or the NIP-42 event after
connect) is the only decision input outside the MAC; absent or
incomplete
  provenance on an edge-required route is `missing_evidence`,
  present-but-failing provenance is `evidence_rejected`.
  Header-trust-without-provenance is nonconformant.
- **`NIP-FI-LIFECYCLE.md`** — provision / disable / re-enable /
administrative
expiry (`binding_not_after`) / pending-replacement lineage, one
conformance
trace per privileged transition; every binding-creating transition
declares
whether it continues or establishes a grant; a private-condition table
for
  CONF enumeration agreement.
- **`NIP-FI-DELEG.md`** — delegated agents; explicit temporal boundaries
matching core's inclusive-`nbf`/exclusive-`exp` idiom, with the
delegated
`skew` configured by this profile; lease deadline anchored to the lease
  issue instant; strict path separation — a delegated request carries no
assertion or provenance field, so it cannot traverse an edge-provenance
  route and uses ingress on which NIP-FI-EDGE is not required.
- **`NIP-FI-CONF.md`** — conformance evidence: an immutable claim tuple
  including the governing document revision and exit fixture digest; the
  complete 16-row denial-fixture enumeration with three mechanical
  enumeration-agreement checks; mutation adequacy with a countable
  denominator — one retained killed mutant per literal oracle-table row
(30 core + 6 EDGE + 11 LIFECYCLE + 7 DELEG + 4 CONF = 58), rows selected
structurally by their first cell, never by section title, with the
release
gate and CONF's own oracle rows stated in the same listed-oracle terms
and
  a mutant defined for CONF's own report- and suite-subject oracles; an
  interoperability exit test compared over signing inputs (per-transport
NIP-01 serialization for the NIP-98 and NIP-42 proofs; decoded protected
header and claims as JSON values for the assertion), with a shared exit
  fixture pinning complete pre-signature header/claim JSON and complete
unsigned event fields for both transports, and mandatory negative
controls.
  `FI-CONF-INTEROP-EXIT` is `deferred` with reason
`no-independent-implementation` until a second independent
implementation
  exists; the canonical fixture is editor-authored at
`docs/nips/fixtures/nip-fi-conf-exit.json` and is **not in this PR** —
until
it is published a claim records `pending-canonical-fixture`, valid only
  while the exit test is deferred. Explicit not-applicable dispositions,
including `offline-jwt` deployments for the two current-status oracles
and
  absence of a revocation-bounded external capability projection for
  `FI-TRACE-CAPABILITY-REVOCATION`.
- **`NIP-FI-MODEL.md`** — non-normative companion; defines no
requirement or
  conformance claim and is not claimable.

## Why

The prior draft rated 9 (soundness) / 6 (minimalness) / 7 (elegance) /
7 (correctness) in adversarial + comparative review. This restructure
keeps the
two-invariant spine untouched, makes everything else a claimable
profile, and
collapses five stacked versioning mechanisms into two contract
identities.

Mutation adequacy counts one mutant per literal oracle-table row — a set
two
implementers enumerate identically — instead of "each normative
requirement,"
which had four defensible readings.

Resolved product calls (owner-approved):
1. Enrollment/denial posture is private — boolean enrollment discovery,
TOFU
extension claim not self-advertised, `key_mismatch →
authorization_denied`
   joins the denial anonymity set, and replayed evidence is classed
   `authorization_denied` so resubmission reveals nothing about commit.
2. Revocation honesty — only `current-status` deployments may advertise
an
   unconditional residual-revocation bound; `offline-jwt` advertises
unbounded/unknown. Access tokens keep RFC 9068 `at+jwt`; `nip-fi+jwt` is
   reserved for a separately minted Buzz assertion.

## Acceptance bar

- Nothing in core is deletable without losing a stated core guarantee.
- From the core document plus the CONF exit fixture, a second
implementer can
produce a valid request equal over the request compared object (signing
  inputs), and a byte-exact public denial per class — no reference
  implementation.
- Every oracle-table row ships a retained killed mutant satisfying only
the
  entry it was selected for.
- Both deployment profiles (trusted proxy = EDGE, client-held OIDC =
core
  client-attached) pass the same lifecycle conformance suite.

## Status

Ready at head e720a5cda. Every revision below is on this branch: the
2026-08-17 and 2026-08-18 review laps (Wren, Dawn, Perci, Sami, Mari,
Quinn)
closed at 513e03b06, 17d455a9b, and 4f913a813; the 2026-08-20 external
line-by-line review (R1–R10, R12) closed across 56e74141e..772ba7a72;
the
2026-08-20/21 adversarial lap (#6437) squash-merged as b8db13d88; the
round-3
external review (R13, R14), the DELEG×EDGE composition note, and three
terminology nits closed at e720a5cda; R11 is this description. Oracle
census: 58 (30 core, 6 EDGE, 11 LIFECYCLE, 7 DELEG, 4 CONF).

Known follow-ups, filed after merge and out of scope here: adapter-only
edge
deployments and FI-EDGE claimability; an EDGE private-condition table
for
CONF's enumeration-agreement check; an enumerable definition of the
positive/negative oracle sets used by the global mutation controls;
NIP-OA's clock-free verification versus NIP-FI-DELEG's wall-clock
expiry.

Supersedes #3726 as the spec vehicle; #1485 remains the design-history
anchor.

---------

Signed-off-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Signed-off-by: Max <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@buzz.block.builderlab.xyz>
Signed-off-by: Perci <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@buzz.block.builderlab.xyz>
Signed-off-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Signed-off-by: Dawn <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@buzz.block.builderlab.xyz>
Signed-off-by: Tyler Longwell <tlongwell@squareup.com>
Signed-off-by: Meli <5aaa86bce934fc3445fc254aab560a40923f10252f92107e665073dede0e04d3@buzz.block.builderlab.xyz>
Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Co-authored-by: Max <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@buzz.block.builderlab.xyz>
Co-authored-by: Perci <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@buzz.block.builderlab.xyz>
Co-authored-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Co-authored-by: Dawn <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@buzz.block.builderlab.xyz>
Co-authored-by: Meli <5aaa86bce934fc3445fc254aab560a40923f10252f92107e665073dede0e04d3@buzz.block.builderlab.xyz>
2026-08-21 17:18:24 -04:00
Salman Mohammed
025425591e fix(benchmarks): wait for scripted event delivery (#6487)
## Why

The Buzz-native runtime could stop a solo agent after one turn even when
a scripted follow-up event was queued or already running. That could
turn a harness timing race into a benchmark failure.

Follow-up to #6448.

## What

- Treat solo tasks with scripted events separately from ordinary
one-turn tasks.
- Wait until turn counts and authored message IDs remain idle and
unchanged for several polls before stopping the agent.
- Remove the message-count shortcut that could stop an active turn.
- Add focused regressions for a delayed follow-up turn and an
already-running turn with a `DONE:` message.

## Testing

- `pytest -q tests/test_container_runtime.py -k "solo_turn_end or
scripted_events"` — 3 passed
- `ruff check` on the three touched Python files
- `ruff format --check` on the three touched Python files
- Local `buzz-native-solo-luna.yaml` Harbor run, one attempt per
affected task:
- `cross-thread-requests` — reward 1.0; all 6 task-specific checks
passed
- `interleaved-agent-reports` — reward 1.0; all 7 task-specific checks
passed
  - 2 completed trials, 0 exceptions, 56 seconds total

## Risk

Low. This only changes completion detection for solo benchmark tasks
with scripted events. Ordinary solo tasks retain immediate completion
after their first turn ends.

---
**Update Aug 21, 13:07 EDT:** Replaced the fixed settle delay with exact
delivery receipts after [review
feedback](https://github.com/block/buzz/pull/6487#discussion_r3832050452).

- ACP now records the event IDs delivered by each completed turn; the
runtime also recognizes existing successful-steer receipts.
- Scripted trials stop only after every expected event ID is
acknowledged and no turn is active. Missing receipts wait for the trial
budget instead of producing partial evidence.
- TDD regression delayed delivery beyond the old five-poll boundary and
failed before the implementation; the receipt parser and Rust receipt
format are pinned independently.
- Focused verification: 31 container-runtime tests passed, 6 ACP
delivery tests passed, plus Ruff, rustfmt, and Clippy.
- Receipt-gated Luna run: 2 completed trials and 0 exceptions.
`interleaved-agent-reports` scored 1.0. `cross-thread-requests`
completed both calculations and thread isolation but Luna omitted the
user mention on ALPHA, so that model-output dimension scored 0.
- Risk remains low: the ACP production change adds delivery receipt
logging and restores a missing turn-end log on a
completed-before-control race; it does not change queue dispatch
behavior.

Generated with Codex

---------

Signed-off-by: Salman Mohammed <smohammed@squareup.com>
2026-08-21 16:09:14 -04:00
klopez4212
aeb741fd31 Polish mobile channel navigation and message sends (#6488)
## Summary
- align iOS back controls and affected titles across channel details,
settings, and pairing
- make channel star and mute actions reflect their state immediately
- animate locally sent channel, thread, and DM messages from behind the
composer with a 300ms ease-out

## Testing
- `just mobile-check`
- full mobile test suite (1,573 tests)

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: Kenny Lopez <klopez4212@gmail.com>
Co-authored-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
2026-08-21 19:13:16 +01:00
Tyler
7da8f9abf3 Clarify huddle message destination (#6496)
## Summary
- identify the injected channel ID as the attached main channel, not the
live huddle channel
- direct spoken replies to the channel UUID in the current Context block
- pin the distinction with regression assertions

## Testing
- `just desktop-tauri-test`
- pre-push desktop Tauri checks

Signed-off-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Co-authored-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
2026-08-21 13:52:40 -04:00
Will Pfleger
fc2ce6728b feat(archive): add observer-frame retention schema and gated DB adapter (#5719)
The local-save archive (`~/.buzz/archive/archive.db`) grows without
bound — observer frames (kind 24200) are 99.95% of it by bytes (~1.3M
rows, 75–375 MB/day). This lays the schema and process-wide foundations
for bounding that growth: a single global retention window for observer
frames, kept in `archive_meta`, plus the gated DB adapter every later
phase builds on. The prune worker that actually deletes lands in a
follow-up; nothing here removes data.

## What this adds

- **Migration M4** (`add_archive_meta`, crash-safe): creates the
`archive_meta` k/v table and the `archived_at`-covering scope-age index
used by the future prune scan, and seeds `observer_retention_days=30`.
Runs under one `BEGIN IMMEDIATE` with an in-lock marker recheck and the
marker written last, so a crash before COMMIT rolls back every object
and the next open re-runs from scratch. Fails closed on an
externally-created `archive_meta` present without the marker.
- **Process init barrier + gated `ArchiveDb` adapter** owning every
production open. All subscription-mutation commands and the archive sync
task route their DB work through `ArchiveDb::with_conn`, which awaits
the init barrier once. This also fixes a pre-existing bug where
`create_save_subscription` ran blocking DB work on the async runtime.
- **Commands**: `get_observer_retention_days` /
`set_observer_retention_days` (fail-closed — rejects days `< 1` or `>
36500` before writing) and `archive_size_stats` (physical file bytes for
the main DB + `-wal` sidecar, plus `page_size` / `page_count` /
`freelist_count` — PRAGMAs and file metadata only, no payload scans).

## Scope

Observer frames (24200) are the only kind with a retention setting.
NIP-AM metrics (44200) and every other archived kind are kept
indefinitely with no retention state — no policy table, no per-kind or
per-subscription configurability. This is the simplified design ruled in
over the earlier per-subscription × per-kind approach: bounding observer
frames alone captures essentially all the value.

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
2026-08-21 13:35:33 -04:00
Tyler
6039fed565 fix(desktop): restore human barge-in over agent TTS in huddles (#6431)
## Problem

Humans cannot interrupt agents in huddles: agent TTS keeps playing over
a talking human (reported by @tlongwell-block, 2026-08-20). The full
requirement: **any human talking — local or remote, any input mode, any
audio rig — must interrupt any agent on the huddle.**

## This is a restoration, not a new feature

- **`b29c8cdaa` (#4281, 2026-08-04) deleted working local VAD
barge-in.** The pre-image shipped `BARGE_IN_DEBOUNCE_FRAMES = 20` (320
ms sustained speech cancels TTS), live at the production call site
(`pipeline.rs` passed `Some(tts_cancel)` unconditionally). The same day,
`ce3cf3cd2` (#4694) flipped the default input mode from VAD to
push-to-talk, which masked the loss.
- **`068a83b09` (#5671, 2026-08-13) removed the remaining TTS-awareness
plumbing from STT** (deliberately, to keep transcribing over agent audio
— a good change). Consequence: this PR is a re-plumb through the
`PlaybackCoordinator` from #6341, not a revert.
- A gap that **never** worked is also closed: PTT-mode users who open
the mic via the mute button (`manual_mic_unmuted` postdates the
deletion) transcribed fine but could not barge in.

## Design

All floor state lives under the single `PlaybackCoordinator` lock —
onset acceptance, epoch bump, synthesis invalidation, player
replacement, and output lease are one committed transition. No cancel
flag can be observed out of order with the playback state it describes.

- **Human floor**: local + per-peer remote ownership with epoch
invalidation. Onset cancels playback by queue replacement; late
synthesis for a stale epoch cannot append or restart.
- **Local onset (VAD)**: on an **isolated output route** (all CoreAudio
output-stream terminals report headphones), a confirmed short onset
interrupts immediately — no echo path exists. On a **coupled route**
(speakers, unknown, virtual, mixed), the restored **20-frame / 320 ms
sustained-speech debounce** discriminates a real human from speaker
bleed; the deleted code's comment records that 80 ms was tried and
false-triggered on laptop speakers. Route classification is queried
fresh at each onset (never cached — default-device re-routing mid-huddle
would strand a stale verdict).
- **Mic-open gate is per-frame**: barge-in observes on any frame where
the mic is actually open — pure VAD mode, or PTT with the mic manually
unmuted (key-held frames defer to the shortcut's own cancel).
- **Remote onset**: sustained non-DTX frames from a peer enter the same
persistent floor (independent of whether playback is live — a human
speaking while TTS is idle blocks late-arriving synthesis from starting
over them). Release on sustained DTX/absence, peer departure, and
recv-loop exit, with guards so a vanished peer cannot wedge the floor.
- **Output lease**: accepted appends renew an `Active` lease;
drain/cancel/onset start a 100 ms tail hangover (conservative against
measured ~12 ms/~1 ms CoreAudio tails), so speaker-tail bleed in the
just-drained window cannot self-trigger the coupled path.

## Known limitations (phase 2 pointers)

- Coupled-route mid-output barge-in pays the 320 ms debounce; a
playback-reference echo discriminator would shorten it.
- A speakers-rig participant's bleed can enter their mic and hold the
floor for other machines (bounded by release debounce).
- Non-macOS routes classify as coupled (fail-safe).

## Verification

- Full `buzz-desktop --lib` suite at head `b0459ae4a`: **2707 passed, 0
failed, 18 ignored** (pinned cargo 1.95.0).
- Exact CI recipe `just desktop-tauri-clippy`: PASS at head; base arm at
merge-base `b728a2af3` confirms the two
`#[allow(clippy::too_many_arguments)]`s cover branch-caused threshold
crossings (human_floor threading), not inherited noise.
- Regression tests pin: 20-frame threshold + reset-on-gap, short-coupled
rejection, sustained-coupled acceptance, coupled-idle acceptance,
remote-idle delayed-TTS rejection, output-tail hangover boundary (during
= rejected, after = accepted), isolated onset, per-frame mic-open gate
truth table, PTT+manual-unmute sustained coupled acquisition.
- `LocalBargeIn::observe` is covered as two joined halves (gate truth
table in `local_barge_in.rs`, floor transition in `tts_playback.rs`);
its body is a straight-line wrapper around a live CoreAudio query, left
uninjected deliberately.
- Coverage precision (mutation-verified):
`manual_open_ptt_sustained_speech_acquires_coupled_floor` pins the gate
→ 20-frame debounce → acquire → floor-blocked chain on the
coupled-**idle** cell. The live-output override leg is carried by
`sustained_coupled_speech_overrides_live_output_suppression`
(tts_playback.rs); the joiner's `sustained_coupled` argument is not
load-bearing there (flipping it to `false` leaves the test green, while
shortening the debounce by one frame turns it red).
- Live arms in progress: pre-regression build `b29c8cdaa^` staged to
confirm the deleted mechanism worked; two-endpoint remote-leg test
pending a second human.

## Commits

1. `fb681a5a9` — restore human barge-in (coordinator floor, lease, route
isolation, remote floor, 320 ms coupled debounce)
2. `b4265418e` — enable barge-in for manually opened mics (per-frame
gate; closes the PTT-open-mic gap)
3. `886489f2b` — extract local barge-in policy module (file-size
ratchet; also hoists the CoreAudio route query from per-frame to
per-onset, named in the commit message)
4. `b0459ae4a` — two targeted clippy allows for the widened worker
signatures

## Credits

Built by **Wren**. Regression archaeology and the PTT-open-mic gap by
**Dawn** (who also killed her own first fix as vacuous and caught a
clippy blocker before it hit CI). Review blockers (coordinator
serialization, idle-onset floors, output lease) by **Mari**. Live rig
verification by **Max**. Coordination and verification by **Eva**.
Opened by Eva with Tyler's explicit direction; commits carry agent
trailers.

---------

Signed-off-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Co-authored-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
2026-08-21 12:51:55 -04:00
Wes
1e6f1a2584 chore(release): release Buzz Desktop version 0.5.18 (#6489)
## Buzz Desktop release v0.5.18

- **Frozen main:** `aea0ef8df9fc24d9aa8bf5c761ab2910026a601b`
- **Reviewed candidate:** `39f8b46935736334cdd7045a4e4b5d7eb1a33888`
- **Previous desktop release:** `desktop-v0.5.17`
- **Proposed immutable tag:** `desktop-v0.5.18`

This PR may be **squash merged** after the Desktop Release Candidate
check and all protected-branch checks pass. Merging authorizes
publication of the exact reviewed candidate; later or unrelated changes
on `main` cannot alter it.

The checked-in changelog accounts for every non-merge commit in the
release range. The Desktop tag points to the reviewed candidate commit,
not the later squash commit. Publication remains bound to that immutable
candidate tag.

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Release Automation <release-automation@users.noreply.github.com>
2026-08-21 10:37:05 -06:00
Wes
aea0ef8df9 fix(desktop): simplify duplicate agent provenance (#6401)
## Summary

- leave the local same-name agent row unlabelled because locality is
implied
- mark only the remote identity with a compact cloud badge reading
`Other setup` in mention autocomplete and Channel members
- suppress the redundant `managed by you` text for duplicate owned
agents while retaining distinct short npubs and exact-pubkey routing

## Testing

- Desktop E2E build/typecheck: `pnpm build:e2e`
- focused Playwright smoke test: `duplicate owned agents preserve
provenance and exact pubkey selection` (1 passed)
  - visible provenance in autocomplete and Channel members
  - local identity remains unmarked
  - keyboard selection routes each exact pubkey
  - narrow 760×640 viewport containment
- focused Biome check on the changed marker and E2E files
- `pnpm check:px-text`
- `pnpm check:pubkey-truncation`
- `just file-size-check`
- `git diff --check`

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
2026-08-21 10:05:45 -06:00
Salman Mohammed
b56a52ca11 test(benchmarks): expand Buzz-native dataset (#6448)
## Why
Terminal task correctness alone does not guard Buzz-native collaboration
behavior such as exact reply routing, non-waking narrative names,
batched agent synthesis, thread isolation, and ambiguous identity
targeting.

## What
- Add five medium/hard Harbor tasks for multiline delivery, narrative
agent names, interleaved agent reports, cross-thread requests, and
ambiguous user mentions
- Add signed scripted-event fixtures, duplicate-display-name profiles,
and public-only evidence export support
- Add positive and adversarial verifier fixtures covering dropped
inputs, extra posts, incorrect routing, and unintended mentions

## Risk Assessment
Low — changes are limited to benchmark tooling and datasets; production
behavior is exercised but not modified.

## References
- Grounded in behavior reported in `buzz-community` and public issues
#5787, #5176, #5839, #4942, #4072, #4303, and #6257
- Live Claude Sonnet 4.6 smoke run: 2/5 passed; the three failures
exposed top-level instead of threaded delivery, empty narrative output,
and silent ambiguous-identity completion
- Live GPT-5.6 Luna run (`buzz-native-solo-luna.yaml`): 3/5 passed.
Passed `ambiguous-user-mention`, `cross-thread-requests`, and
`interleaved-agent-reports`. Failed `multiline-message` and
`narrative-agent-names` because both omitted the event-level user
mention despite otherwise-correct content and threading.



<img width="1176" height="805" alt="Screenshot 2026-08-21 at 11 11
17 AM"
src="https://github.com/user-attachments/assets/fc259ec9-892c-4436-b022-1bf85415617d"
/>

Signed-off-by: Salman Mohammed <smohammed@squareup.com>
2026-08-21 12:00:04 -04:00
Wes
4e3c9e619c fix(desktop): sender names in notifications + macOS click-through routing (#6427)
> Opened by the agents Brain and Pinky on behalf of @wesbillman.

Fixes two desktop notification issues (requested in Buzz channel
`desktop-notification-improvements`):

## 1. Notifications now show who sent the message

Live DM and thread-reply notifications showed only "Direct message" /
"Reply in #channel", while home-feed mention toasts already carried the
sender's name. All message-notification copy is now centralized:

- **`formatMessageNotification`**
(`notifications/lib/notificationFormat.ts`) — canonical title/body for
all five sources (mention, approval, needs-action, DM, thread reply).
Sender-first titles with neutral fallbacks, never a raw pubkey:
  - DM: `Taylor` instead of `Direct message`
- Thread reply: `Taylor replied in #ship-room` instead of `Reply in
#ship-room`
- **`useNotificationSenderName`** — synchronous cache-only lookup
(react-query users-batch entry cache → persisted label cache); a cold
miss ships the fallback title immediately and warms the cache in the
background. No toast delay, no new network machinery.
- **`buildEventNotificationTarget` / `buildFeedItemNotificationTarget`**
(`notifications/lib/target.ts`) — the click-through target payload is
built in one place instead of three hand-rolled copies.

## 2. macOS notification clicks route to the target message (#3509)

On packaged builds, clicking a notification focused the app but never
navigated. Three independent gaps lined up behind one symptom:

- **Reveal hang**: notification navigation now starts before the
best-effort `unminimize → show → setFocus` chain, so a hung native
invoke cannot gate click-through; the existing 1.5s reveal timeout
remains as a secondary guard.
- **Lost emit**: the Rust delegate queues the activation target *before*
emitting `native-notification-activated`; a lost emit stranded the
target with nothing re-draining the queue. The macOS listener now also
drains on window `focus` / `visibilitychange` — delivered by WebKit
independently of the Tauri event channel, and always produced by the
click's own foregrounding.
- **Silent no-op**: `commitNavigation` skips same-href destinations;
`goChannel` / `goForumPost` / `openSearchHit` now accept `force`, and
the notification activation handler passes it so a click always routes.
Multiple queued activations are serialized FIFO with rejection
containment so an older click cannot finish after and overwrite a newer
one. Queue teardown now aborts already-running activations as well as
pending ones; async forum-comment destination resolution rechecks
ownership before community-scoped cache writes or routing.

Diagnostic evidence from the macOS unified log (packaged v0.5.17):
delegate confirmed live in release builds (`willPresent` honored —
`(["list"])` presentations); a real click response at 09:25:06 reached
`usernoted`, the app was fronted by LaunchServices, and no navigation
followed.

## Verification

- Fixed the stale relay-backed DM dedupe expectation: exactly one toast
remains required, with sender-first title `alice` instead of channel
title `alice-tyler`
- Rebased onto `origin/main` and verified 15 focused activation/click
tests, desktop typecheck/check, file-size gate, Biome on changed files,
and `git diff --check` at `21a7e0cf5`
- Notification + navigation + AppShell.helpers unit tests: 89/89 pass
(includes new `notificationFormat.test.mjs`, `target.test.mjs`,
`desktopActivations.test.mjs`)
- Full desktop JS suite run by Pinky at f03979ea: 5133/5133 pass;
pre-push hooks (desktop-test, desktop-typecheck, desktop-tauri-checks,
rust-tests, file-size ratchet) all green on this branch
- `tsc --noEmit` and changed-file Biome checks clean; re-verified after
rebasing current `origin/main`
- Click-through on a packaged build still needs human verification —
@wesbillman, next release build is the real test.

---------

Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
Co-authored-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
Co-authored-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
2026-08-21 09:17:04 -06:00
Will Pfleger
8740a1fa94 docs: clarify two-layer moderation ownership (#6481)
Clarify how the two moderation layers map to hosted and self-hosted
relay deployments.

- State that platform safety belongs to whoever operates the relay, with
hosted and self-hosted accountability spelled out.
- Distinguish the relay/platform operator-and-moderator roster from
community owner and admin roles.

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Alia <d32955ad69077062930cc46cfe2df30ca9aaf6f8e76422681265e9e9af704d78@buzz.block.builderlab.xyz>
2026-08-21 10:38:09 -04:00
klopez4212
ffb12d3b05 Fix mobile thread tail and iOS channel header (#6399)
## Summary

- Hide the thread Latest control once the lazy tail is fully reached.
- Polish the mobile channel header and use native iOS liquid glass for
Back.
- Keep the two-line header aligned and safe at larger text sizes.

## Validation

- `just mobile-check`
- `flutter test` (1,553 tests)
- Signed iPhone build installed and launched

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Co-authored-by: Carl <3c4caeafb646d23867f1c4832e68211d77e2561946171625f75c3ce1a3f2670f@buzz.block.builderlab.xyz>
2026-08-21 15:27:30 +01:00
Tyler
2edacde4d4 chore(deps): pin earshot below 1.2.0 pending a VAD threshold re-pick (#6392)
## Problem

`earshot` is our huddle VAD. `desktop/src-tauri/Cargo.toml:143` declares
`earshot = "1.0"` — a caret range — so **only the lockfile** holds us at
1.1.0. `renovate.json` has `automerge: true` with `postUpdateOptions:
["cargo:updateLockfile"]`, and exempts only *major* bumps from
automerge. 1.2.2 published 2026-08-19 and satisfies the range, so it is
eligible on Renovate's next run.

That bump is not safe to take on its own. It is a **quantized
re-implementation, not a tuning release**: `weights.bin` goes 77,124 →
39,940 bytes, the RNN weights move `f32` → `i16`, the mel filterbank
offsets are rebuilt, and `sqrtf` is replaced with a fast `rsqrtf`. Same
crate name, different network — and the probability scale moves with it
(1.1.0 never exceeds 0.935 and puts 1.0% of frames above 0.9; 1.2.2
reaches 0.9909 with 35.4% above 0.9).

Measured on a matched 121-clip corpus (11 Pocket TTS voices × 11
conditions, 38,254 scored frames), at our shipped threshold:

| metric | 1.1.0 | 1.2.2 |
|---|---|---|
| TPR | 89.57% | **88.46%** |
| FPR | 1.54% | **2.79%** |
| CPU / frame | 6,550–6,777 ns | **3,841–3,978 ns** |

AUC does improve (+0.0045 all-conditions) and CPU is a genuine 1.70x
win, so the bump is worth taking — but the AUC gain is in an ROC region
we do not operate in, and the FPR-matched threshold for 1.2.2 is ~0.574,
not 0.5. It needs a threshold re-pick, not a lockfile bump.

The risk is the shape of the diff. The last earshot bump — #654, "update
rust crate earshot to v1.1.0" — was lockfile-only (+23/−26, one file)
and went from opened to merged in **15 minutes**. That is the correct
instinct for a lockfile bump and exactly wrong here: two lines in
`Cargo.lock` would silently re-tune the VAD.

## Fix

One `packageRules` entry pinning earshot below 1.2.0, following the
existing `evalexpr` and `@tiptap/*` pin pattern in the same file. The
rationale lives in the `description` field so the next person to hit the
pin sees why.

A source comment cannot prevent this, because Renovate does not read
comments. This is the mechanical guard.

## Verification

- `renovate.json` parses; the new entry's key set matches the two
existing `allowedVersions` pins.
- Range semantics checked: 1.0.0 / 1.1.0 / 1.1.9 allowed; 1.2.0 / 1.2.1
/ 1.2.2 / 2.0.0 blocked.
- All eight pre-push gates green (branch-skew, file-size, desktop
check/typecheck/test, mobile, rust-tests, desktop-tauri-checks).
- I could **not** run `renovate-config-validator` — the npm registry is
unreachable from this host (`ECONNRESET` via the Artifactory mirror).
The checks above are a structural and semantic substitute, not a
substitute for the official validator.

## Scope

Config-only. No behavior change, no code touched. Unblocking is a
deliberate follow-up: take 1.2.2 together with a threshold re-pick
against the same corpus, which is already parked in the Silero bake-off
arc.

Measurement details and the harness are in my workspace at
`RESEARCH/EARSHOT_1_1_0_TO_1_2_2_MEASUREMENT_2026_08_20.md` (not in this
repo).

Signed-off-by: Dawn <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@buzz.block.builderlab.xyz>
Signed-off-by: Tyler <tlongwell@block.xyz>
Co-authored-by: Dawn <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@buzz.block.builderlab.xyz>
Co-authored-by: Tyler <tlongwell@block.xyz>
2026-08-21 09:02:21 -04:00
thomaspblock
9b32e055fe polish(desktop): finish Projects navigation and context chrome (#6429)
## Summary

After #6396, Projects still split chrome across the workspace header, a
copy-link control, and a labeled Actions group that mixed people,
create, and metadata. This PR finishes that surface: the right-hand
context box is unlabeled actions plus a Details group, people stacks and
contribution heatmaps are gone from that box, Create review sits with
Create task, and the top chrome is terminal / chat / info with no
copy-link. Sent project context collapses to a pill, and review file
diffs keep the last good git view instead of flashing empty while
queries refetch.

This also lands the remaining navigation polish that followed Part 3:
overview and list presentation, readme and commit layout, and opening
the latest matching conversation from the Channels tab without leaving
the project.

### Related issue
N/A. Related: #6396

## Testing
- Walked Files, Tasks, Reviews, task/review detail, overview tabs, and
chrome chat vs info in the running desktop app
- Pre-push: desktop typecheck, unit tests, Tauri checks, and file-size
gate passed
- Updated Projects smoke specs for the new context groups, Create
review, chrome order, and removed copy-link control
- Merged current `origin/main`; one conflict in discussion-channel rows
kept conversation-panel navigation and took main's bounded channel-name
lookup

## Post-Deploy Monitoring & Validation
- validate Projects workspace chrome, context box, and review file diffs
in the first staging Desktop session
- healthy signals: context box shows unlabeled actions then Details,
chat toggle sits between terminal and info, review diffs stay populated
across selection changes
- failure signals: missing Create review, restored heatmap/people in the
context box, or empty Files Changed while the review is still selected;
mitigate by reverting this PR

---------

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
2026-08-21 05:45:55 -07:00
Matt Toohey
9891e64f6b fix(desktop): clarify add agents channel action (#6374)
"Create agent" button takes you to a UI to **invite** your existing
agents to a channel. Rewording the button to make this clear.

Before
<img width="481" height="251" alt="Screenshot 2026-08-21 at 1 58 40 pm"
src="https://github.com/user-attachments/assets/1b64f722-62b8-46fa-a6c4-dafcf2bdfaa7"
/>


After
(Sorry about different elements being in hover state in the screenshots)
<img width="481" height="313" alt="Screenshot 2026-08-21 at 1 58 16 pm"
src="https://github.com/user-attachments/assets/f68a9c9b-2276-4ef5-ace8-c4017977b1e8"
/>
## Summary

- Clarify that the empty-channel intro action adds existing agents to
the channel.
- Assert the exact action title and description in the existing E2E
coverage while preserving the separate Welcome create-agent flow.

### Related issue

None found.

### Testing

- `../node_modules/.bin/biome check
src/features/channels/ui/useChannelIntro.tsx tests/e2e/channels.spec.ts`
passed.
- `./node_modules/.bin/tsc && ./node_modules/.bin/vite build --mode e2e`
passed.
- The isolated Playwright smoke case `empty channel shows intro actions`
passed (1/1) after installing the repo-pinned Chromium.
- `env -u BUZZ_AGENT_PROVIDER just ci` passed.
- Screenshots not captured; this is a copy-only UI change.

---------

Signed-off-by: Matt Toohey <contact@matttoohey.com>
2026-08-21 07:07:36 -04:00
Wes
24ec6a468e Repair stale large channel roster snapshots (#6251)
## Summary

- detect relay-authored NIP-29 kind 39002 roster snapshots truncated by
the former 1,000-member query cap and repair stale large rosters during
relay startup
- serialize canonical roster capture and replacement with membership
writes, preserving tenant, channel, signer, pubkey, and role boundaries
through mixed-version deployments
- install migration 0032's fail-closed roster fence on the partitioned
events table and verify its catalog shape plus behavior before opening
relay listeners

## Rollout

Migration 0032 is a hard schema-before-code compatibility boundary.
Apply migrations before rolling this relay version. Startup refuses to
open listeners when the parent/partition triggers are missing, disabled,
mis-shaped, or behaviorally inert. For large installations, prefer
`buzz-admin migrate` and monitor lock acquisition as documented in the
chart README.

## Validation

Exact head: `bcbba271f54bc0046a6683007e5a2b70403a11d5`

- rebased onto `569308c23c9c2bf620dd3a9a5e4baecbcfa22e16`; the nine-file
feature patch is byte-identical to pre-rebase head
`be8ea0084f4d4c78c7c2550baad4399e4df8ce73`
- pre-push hook passed at exact head: branch-skew, file-size, full Rust
unit suite, Desktop Tauri clippy, and Desktop Tauri tests
- `cargo fmt --all -- --check`
- `cargo test -p buzz-relay
group_members_snapshot_keeps_members_past_one_thousand -- --nocapture`
- focused CI-mode Playwright regression: `selected relay agents revoked
after the invite prompt cause no side effects` passed at exact head
- prior exact-patch validation:
`large_roster_reconciliation_candidates_respect_snapshot_count_and_signer`,
mixed-writer locking/rollback, migration admission, partition trigger
coverage, and desired-schema parity regressions

## Review

Independent DB/relay review found no blocking issues in the exact
feature patch. The concurrency fence holds the established replacement
and membership locks on one transaction/connection through replacement;
failures roll back both soft-delete and insert. Reconciliation remains
tenant/channel/signer scoped and validates exact normalized
pubkey-plus-role membership.

The prior red Desktop shard was unrelated to this backend-only diff: its
mocked mention test exercises no relay, database, or migration path. It
reproduced as a timing flake on the old head, passed on retry/base, and
now passes locally after rebasing onto current main.

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
2026-08-20 21:22:41 -06:00
Taylor Ho
de8a2741c7 feat(desktop-messages): show compact Buzz link metadata (#6252)
**Category:** improvement
**User Impact:** Buzz links in messages now resolve into compact,
descriptive chips with predictable navigation, while tooltips use the
neutral secondary surface consistently across light and dark themes.

**Problem:** Raw Buzz-native links and opaque identifiers make message
context difficult to scan, while oversized previews disrupt the
conversation. Missing, delayed, or deleted metadata also needs a stable
presentation that does not mislead users or break navigation.

**Solution:** Keep message and issue chips metadata-independent: message
chips render only the channel name, while issue chips render only the
repository name—never fetched content/title or an event hash. Fetched
context remains available in each hover tooltip. Other native links
continue to resolve into concise inline labels, with muted secondary
fallbacks, distinct deleted states, and existing navigation paths
preserved. This also makes two explicit shared-tooltip behavior changes:

1. **Color:** shared and rich tooltips move from the primary color pair
to the neutral secondary semantic pair, including dedicated huddle-token
handling and matching rich-descendant foregrounds.
2. **Hover behavior:** tooltip roots set Radix
`disableHoverableContent`, and tooltip content is pointer-transparent,
so moving off the trigger dismisses the tooltip instead of letting the
pointer enter and keep the popover open.

Together these preserve readable contrast, authoritative project
context, and predictable hover dismissal.

<details>
<summary>File changes</summary>

**desktop/src/features/communities/useCommunityInit.ts**
Primes channel metadata needed to resolve native links promptly.

**desktop/src/features/messages/lib/messageLinkMetadata.test.mjs**
Covers message preview extraction, fallbacks, and deleted-message
semantics.

**desktop/src/features/messages/lib/messageLinkMetadata.ts**
Normalizes fetched message metadata into compact labels and status-aware
presentation.

**desktop/src/features/messages/ui/SentFromThreadLine.tsx**
Provides thread context to linked-message metadata resolution.

**desktop/src/shared/lib/useResolvedLinkPreviews.ts**
Exposes resolved preview state for native entity chips.

**desktop/src/shared/styles/globals/markdown.css**
Adds compact chip layout and semantic disabled-state styling.

**desktop/src/shared/styles/globals/theme.css**
Defines the semantic colors used by unavailable and deleted chips.

**desktop/src/shared/ui/markdown.test.mjs**
Exercises native-link rendering and provider-backed entity metadata
behavior.

**desktop/src/shared/ui/markdown.tsx**
Routes native markdown links through metadata-aware chip components
without changing navigation contracts.

**desktop/src/shared/ui/markdown/ChannelDeepLink.test.mjs**
Covers resolved, unresolved, private, archived, and forum channel
presentations.

**desktop/src/shared/ui/markdown/ChannelDeepLink.tsx**
Renders channel names and concise channel metadata inline with stable
fallbacks.

**desktop/src/shared/ui/markdown/MessageLinkPill.tsx**
Renders loading, ready, unavailable, DM, forum, and deleted message
states compactly.

**desktop/src/shared/ui/markdown/entityLinks.tsx**
Enriches repository, issue, and pull-request chips and uses
containing-project context in tooltips.

**desktop/src/shared/ui/markdown/types.ts**
Extends markdown runtime metadata required by native chip rendering.

**desktop/src/shared/ui/markdown/useMessageLinkMetadata.ts**
Fetches and classifies linked-message metadata while preserving
navigable fallbacks.

**desktop/src/testing/e2eBridge.ts**
Adds deterministic metadata controls for runtime visual and navigation
tests.

**desktop/tailwind.config.js**
Makes semantic disabled colors available to chip styles.

**desktop/tests/e2e/entity-link-recipient-cards.spec.ts**
Verifies entity labels, project-aware tooltips, delayed metadata, and
navigation behavior.

**desktop/tests/e2e/navigation.spec.ts**
Verifies channel and message chip states, metadata resolution, deletion
handling, and navigation.

**desktop/src/shared/ui/tooltip.tsx**
Migrates the shared tooltip surface from the primary color pair to the
semantic secondary pair. It also sets Radix `disableHoverableContent`
and makes tooltip content pointer-transparent so leaving the trigger
dismisses the tooltip predictably.

**desktop/src/features/agents/ui/RestartDiffBadge.tsx**
Aligns restart-diff tooltip values and supporting copy with the
secondary tooltip foreground.

**desktop/src/features/channels/ui/AddChannelBotTeamsSection.tsx**
Aligns rich team tooltip descriptions, persona chips, avatars, and names
with secondary tooltip semantics.

**desktop/src/features/projects/ui/ProjectAuthorIdentity.tsx**
Uses the matching secondary tooltip foreground for project author
metadata.

**desktop/src/features/projects/ui/ProjectCards.tsx**
Aligns repository-unavailable tooltip descriptions with the secondary
tooltip foreground.

**desktop/src/shared/styles/globals/utilities.css**
Makes huddle tooltips consume their dedicated palette directly without
misleading primary or secondary aliases.

**desktop/src/shared/styles/globals/tooltipSemantics.test.mjs**
Pins direct huddle-token consumption and rejects semantic alias drift.

**desktop/tests/e2e/tooltip-semantics.spec.ts**
Verifies simple and rich tooltip surfaces and descendant tokens in Buzz
light and Catppuccin Mocha dark themes.

**desktop/playwright.config.ts**
Registers tooltip semantic coverage in the desktop smoke suite.

</details>

## Reproduction steps

1. Run the desktop app and open a message containing Buzz links for a
channel, message, repository, issue, and pull request.
2. Confirm message links show only the channel name and issue links show
only the repository name inline, with no fetched content/title or event
hash; confirm other native links remain compact rather than rendering
raw identifiers or expanded previews.
3. Hover the chips and confirm the neutral secondary tooltip adds
concise context without duplicating the visible label.
4. Open each chip and confirm it follows the same channel, message,
repository, issue, or pull-request navigation as before.
5. Inspect links while metadata is loading, unavailable, or definitively
deleted and confirm the fallback remains compact, legible, and navigable
where appropriate.
6. In Buzz light and Catppuccin Mocha dark themes, compare a simple
channel-members tooltip and the rich Add agents team tooltip; both
should use secondary semantics with readable nested content.
7. Move the pointer from a trigger toward its tooltip; confirm the
tooltip dismisses rather than remaining open as hoverable content.

## Screenshots

The matrix below covers both the default light theme and Catppuccin
Mocha with an orange accent. Message/issue-chip rows affected by the
stable-label pivot are temporarily omitted until they can be recaptured
from the real built UI; the prior images showed the obsolete expanding
inline label.

| State | Default light | Dark · orange accent |
|---|---|---|
| Public stream channel tooltip | ![Public stream channel tooltip —
default
light](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/light-default/01-public-stream-channel-tooltip.png)
| ![Public stream channel tooltip — dark orange
accent](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/dark-orange/01-public-stream-channel-tooltip.png)
|
| Private forum channel tooltip | ![Private forum channel tooltip —
default
light](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/light-default/02-private-forum-channel-tooltip.png)
| ![Private forum channel tooltip — dark orange
accent](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/dark-orange/02-private-forum-channel-tooltip.png)
|
| Public forum channel tooltip | ![Public forum channel tooltip —
default
light](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/light-default/03-forum-channel-tooltip.png)
| ![Public forum channel tooltip — dark orange
accent](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/dark-orange/03-forum-channel-tooltip.png)
|
| Channel references, including unresolved | ![Channel references,
including unresolved — default
light](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/light-default/04-unresolved-channel-reference.png)
| ![Channel references, including unresolved — dark orange
accent](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/dark-orange/04-unresolved-channel-reference.png)
|
| Unknown channel permalink | ![Unknown channel permalink — default
light](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/light-default/05-unknown-channel-permalink.png)
| ![Unknown channel permalink — dark orange
accent](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/dark-orange/05-unknown-channel-permalink.png)
|
| Archived channel tooltip | ![Archived channel tooltip — default
light](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/light-default/06-archived-channel-tooltip.png)
| ![Archived channel tooltip — dark orange
accent](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/dark-orange/06-archived-channel-tooltip.png)
|
| Repository entity | ![Repository entity — default
light](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/light-default/13-repository-entity.png)
| ![Repository entity — dark orange
accent](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/dark-orange/13-repository-entity.png)
|
| Pull request entity | ![Pull request entity — default
light](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/light-default/14-pull-request-entity.png)
| ![Pull request entity — dark orange
accent](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/chip-metadata/dark-orange/14-pull-request-entity.png)
|
| Entity metadata fallback | ![Corrected entity metadata fallback
tooltip — default
light](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/17-entity-metadata-fallback-corrected-light.png)
| ![Corrected entity metadata fallback tooltip — dark orange
accent](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6252/17-entity-metadata-fallback-corrected-dark-orange.png)
|



### Tooltip semantic surface spot check

| Buzz light | Catppuccin Mocha dark |
|---|---|
| ![Rich team tooltip on the secondary surface in Buzz
light](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6290/buzz-team-tooltip.png)
| ![Rich team tooltip on the secondary surface in Catppuccin Mocha
dark](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6290/catppuccin-mocha-team-tooltip.png)
|

---------

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
2026-08-20 19:01:18 -07:00
Will Pfleger
c6e3fe7dfa feat(workflows): reply in-thread from send_message action (#6178)
The `send_message` workflow action could only post new top-level channel
messages. This adds a `reply_in_thread` option so a `message_posted`
workflow can reply in the triggering message's thread, plus a
`trigger_is_reply` filter variable so a workflow can fire only on
top-level messages.

Every NIP-10 thread-marker reader in the tree now routes through one
shared parser and one collapse rule in `buzz-core`, deleting four
hand-rolled copies that had drifted on id-validity and marker semantics.

## What changed

- **Schema** (`crates/buzz-workflow/src/schema.rs`): new
`reply_in_thread: bool` (serde default `false`) on
`ActionDef::SendMessage`. `validate()` rejects `reply_in_thread: true`
on `schedule`/`webhook` triggers — they carry no message to reply to.
- **Executor** (`crates/buzz-workflow/src/executor.rs`): threads
`reply_to: Option<&str>` (the trigger `message_id`) through
`ActionSink::send_message` when `reply_in_thread` is set; errors clearly
if the trigger has no `message_id`. `resolve_step_templates` carries the
new field. Adds `trigger_is_reply` (boolean) to the eval context.
- **Relay sink** (`crates/buzz-relay/src/workflow_sink.rs`): when
`reply_to` is set, resolves parent/root/depth from the known trigger
event, persists real thread metadata instead of the hardcoded top-level
`depth: 0`, and pushes the live kind:39005 thread-summary overlay after
insert so subscribed desktops update the root's reply badge without
refetching — matching the human ingest path. Emits the same NIP-10
`e`-tag shape as `buzz_sdk::builders::thread_tags`: a single `["e", id,
"", "reply"]` tag for a direct reply (parent == root), and the `root` +
`reply` pair only when nested — so every writer produces one wire shape
per reply kind.
- **Ingest resolver** (`crates/buzz-relay/src/handlers/ingest.rs`): new
`resolve_relay_reply_thread_meta` + `ReplyAncestry`. Unlike the
client-facing `resolve_nip10_thread_meta` (which validates
client-supplied tags), this computes root/depth from the known parent
and enforces the same same-channel and depth-limit invariants. When the
parent has no `thread_metadata` row, both resolvers share
`derive_ancestry_from_parent_tags`, which applies
`ThreadMarkers::resolve()`: a marked nested parent remains depth 2,
while a root-only, malformed, or unmarked parent is top-level and starts
its reply thread at itself. Both the client resolver and the
parent-ancestor fallback now read markers via the shared parser instead
of hand-scanning `e`-tags.
- **Shared NIP-10 parser** (`crates/buzz-core/src/nip10.rs`):
`parse_thread_markers` reads an event's `root`/`reply` markers, honoring
a marker only when its event id is exactly 64 ASCII-hex characters.
`ThreadMarkers::resolve()` is the single definition of the (root, reply)
→ (root_id, parent_id) collapse: `root`+`reply` as-is, `reply`-only →
`(reply, reply)`, a lone `root` or neither → top-level. A slice-based
`parse_thread_markers_from_parts` entry point serves consumers holding
raw JSON tag arrays. Relay ingest, the workflow `trigger_is_reply`
predicate, ACP anchoring, and the CLI reply resolver all call these, so
they cannot drift on marker, id-validity, or collapse semantics.
- **ACP** (`crates/buzz-acp/src/queue.rs`): `parse_thread_tags`
delegates marker parsing and collapse to `buzz_core::nip10`, keeping
only its local `p`-tag mention collection. This fixes a parity gap with
ingest: a malformed non-64-hex marker id is no longer counted as a
thread link, and a lone `root` marker is now top-level rather than being
treated as root == parent.
- **CLI** (`crates/buzz-cli/src/commands/messages.rs`):
`find_root_from_tags` routes its JSON tags through the shared slice
parser and collapse rule. CLI replies to root-only, malformed, or
unmarked parents now correctly start at that immediate parent;
reply-only and root+reply parent ancestry remain intact.
- **Trigger context** (`crates/buzz-workflow/src/lib.rs`):
`build_trigger_context` derives `is_reply` solely from a valid NIP-10
`reply` marker (no DB hit). A lone `root` marker is top-level to ingest,
so it does not count; neither does a `reply` marker whose event id is
malformed, nor a bare/unmarked `e`-tag (mentions, quotes).
- **Desktop** (`workflowFormTypes.ts`, `WorkflowStepCard.tsx`):
`replyInThread` form field with YAML round-trip, and a "Reply to
triggering message in thread" checkbox shown only for message-based
triggers. Switching to `schedule` or `webhook` clears the option on
every step before serialization, so a value hidden behind an action
change cannot resurrect when the action is switched back. The form
parser also requires `reply_in_thread` to be a boolean and refuses
`reply_in_thread: true` under an ineligible trigger, falling back to
YAML mode rather than silently normalizing a backend-invalid definition.

## Usage

```yaml
trigger:
  on: message_posted
  filter: trigger_is_reply == false
steps:
  - id: auto_reply
    action: send_message
    text: "pre-written reply text"
    reply_in_thread: true
```

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
2026-08-20 19:44:21 -04:00
Will Pfleger
c63ac746cd perf(desktop): split discover_acp_providers into cheap and forced paths (#6330)
Splits the `discover_acp_providers` Tauri command into a cheap cached
path and an explicit forced re-discovery path.

The profiling flight-recorder identified `discover_acp_providers` as the
acute UI-freeze correlate: a 20–65s probe pipeline (PATH re-fetch, CLI
auth probes, process spawns) was running on routine renders like channel
switches, because hot surfaces remounted the wrapping query and
automatic staleness refetches re-ran the full pipeline. This is
complementary to the idle auto-reload (#5588) and bounded-accumulator
(#5596) work.

## Backend
- Added a `force` parameter to `discover_acp_providers` /
`discover_acp_runtimes_from`. The default (cheap) path serves cached
availability and auth statuses with zero process spawns; `force: true`
runs the full pipeline (cache clear, PATH re-fetch, CLI auth probes).
- Added a single-flight coalescer (`forced_single_flight`) so concurrent
forced runs share one probe instead of stacking.
- Extracted the auth-status cache and `resolve_auth_statuses` into
`discovery/auth_status_cache.rs`.

## Renderer
- Raised `staleTime` to 30 min; forced refresh flows only through an
explicit `fetchQuery` path (`refreshAcpRuntimes`), so automatic
staleness refetches can never re-run probes.
- Added `useAcpRuntimesQueryForced` for Settings and onboarding
surfaces; connect/install/save/delete mutations force-refresh in
`onSettled`.
- Switched `SetupStep`, `HarnessCatalogDialog`, and
`HarnessesSettingsPanel` to the forced hook.

## Structure
The touched files were at or over the grandfathered 1000-line file-size
ceiling, so the change is delivered as cohesive extractions rather than
in-place growth: `forced_single_flight.rs`, `auth_status_cache.rs`,
`discovery/tests/forced_discovery.rs`, `acpRuntimesQuery.ts`, and
`tauriAcpDiscovery.ts`. Dependencies are one-directional (`hooks.ts`
imports from `acpRuntimesQuery.ts` and re-exports the forced hook, so
consumer imports are unchanged; no import cycle).

## Tests
Added Rust tests pinning the cheap-vs-forced split: a probe is spawned
only when forced, the cheap path reuses the cache, and auth status is
`Unknown` before any probe runs.

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
2026-08-20 19:44:05 -04:00
Wes
569308c23c fix(desktop): restore recent channel sorting (#6402)
## Summary

- batch desktop last-message queries into groups of 128 so workspaces
with larger channel counts stay within the relay's explicit-channel
limit
- propagate timestamp query failures instead of replacing the sidebar's
cached recency with all-null data
- advance channel recency from live message events so Recent ordering
updates without waiting for the next refresh

## Root cause

The desktop sent one explicit `#h` filter per channel in a single
`/query`. The relay rejects a request with more than 128 aggregate
explicit channel values. The desktop swallowed that rejection and
returned no timestamps, so Recent correctly fell back to A–Z for every
channel.

## Testing

- `cargo test --manifest-path desktop/src-tauri/Cargo.toml
last_message_filters_stay_within_relay_channel_cap --lib`
- `cd desktop && pnpm test` (5,132 passed)
- `cd desktop && pnpm exec biome check
src/features/channels/useLiveChannelUpdates.ts
src/features/channels/lib/channelRecency.ts
src/features/channels/lib/channelRecency.test.mjs
tests/e2e/channel-sort.spec.ts`
- `cd desktop && pnpm check:file-sizes`
- `cargo fmt --all -- --check`
- `cd desktop && pnpm build:e2e` followed by `pnpm exec playwright test
tests/e2e/channel-sort.spec.ts --project=smoke --workers=1` against a
dedicated static server (4 passed)

## Manual test

In a workspace with more than 128 channels, choose **Channels → Sort →
Recent**. Channels should order by latest message instead of A–Z. While
Recent is selected, a new message in a visible channel should move that
channel to the top immediately.

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
2026-08-20 17:31:39 -06:00
Matt Krueger
b298a175c4 fix(desktop): isolate main timeline stacking context from focus drawer (#6398)
The "Jump to latest" pill (`z-50`) in the main timeline renders on top
of the focus thread drawer (`z-41`) because both share the same stacking
context. This wraps the timeline contents in an `isolate` div so the
pill's z-index can't escape above the drawer.

The diff is large but the actual change is two lines — one wrapper
`<div>`. The rest is biome re-indenting the children. The
`DropZoneOverlay` also moves inside the wrapper, so its top edge no
longer extends behind the header during drag-over.

### Repro

1. Open a channel with enough history to scroll up past the bottom
2. Scroll up so the "Jump to latest" pill appears
3. Open a thread in focus mode — the pill renders on top of the drawer

### Related issue
None found.

Before:
<img width="824" height="730" alt="Before"
src="https://github.com/user-attachments/assets/eae0eb88-bcef-4c2a-bb05-08d0af6f7f38"
/>

After:
<img width="1280" height="720" alt="after-drawer-hides-pill"
src="https://github.com/user-attachments/assets/0370ba71-efc5-478a-a8e0-aac902a66082"
/>

Signed-off-by: Matt Krueger <krueger.matt@ymail.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-08-20 17:28:06 -06:00
Wes
06e8be9098 fix(desktop): make reconnect repair lossless (#6415)
## Summary

- repair exact-channel reconnect gaps from a source-coupled 1,865-second
floor (`900` seconds of relay future tolerance + `960` seconds of DB
created-at floor + `5` seconds of fence margin)
- page the existing authenticated `POST /query` bridge losslessly with
`(until, before_id)`, including dense timestamp boundaries and an
unbounded first page that does not trust the renderer clock
- keep the restored live REQ unchanged while deduplicating live/repair
overlap until both live EOSE and repair completion for the active
connection generation

## Scope and behavior

The wider repair applies only to live subscriptions containing the exact
channel-event kind set and one `#h`. Profile, read-state, global,
channel-less, and other subscription behavior is unchanged. Failed or
stale repairs retain their pinned lower bound for the next reconnect.

This intersects the replay path described in #3215, but does not claim
to fix that issue. Desktop already has a bounded notification-side
event-ID guard; this PR adds transport dispatch dedupe for the
restored-live/repair overlap. Notification behavior should remain a
focused regression check while this wider repair window rolls out.

## Testing

- `cd desktop && pnpm typecheck`
- `cd desktop && pnpm biome check
src/shared/api/channelReconnectRepair.ts
src/shared/api/relayClientSession.ts src/shared/api/relayClientShared.ts
src/shared/api/relayClosedRecovery.ts
src/shared/api/relayReconnectReplay.ts
src/shared/api/relayReconnectReplay.test.mjs src/testing/e2eBridge.ts`
- `cd desktop && node --test
src/shared/api/relayReconnectReplay.test.mjs` (26 passed)
- `cargo test --manifest-path desktop/src-tauri/Cargo.toml
channel_reconnect_repair` (2 passed)
- pre-push hooks passed at `743283439eb6be7969e19951cbb6720c5e493a04`

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
2026-08-20 17:13:47 -06:00
Will Pfleger
cd0d33f085 fix(hooks): scope pre-push lanes to branch merge-base diff (#6423)
Lefthook selected pre-push lanes from the file set `git diff --name-only
HEAD @{push}` returns, which is overinclusive two different ways:

- **Rebase/merge poisoning.** `@{push}` is a two-dot diff against the
branch's last-pushed tip. After a rebase onto newer main — or the `git
merge origin/main` that `check-branch-skew.sh` itself instructs agents
to run — that diff includes everything `main` changed since the last
push, so `mobile-checks`, the `desktop-*` lanes, and `rust-tests` fire
on branches that never touched those trees (a recent relay-only push
discovered 266 files, 26 of them `mobile/`).
- **Brand-new branch in a worktree.** When `@{push}` doesn't resolve,
lefthook reads `$GIT_DIR/refs/remotes/origin/HEAD` — which doesn't exist
in a linked worktree's git-dir — then falls back to the
alphabetically-first `HEAD ->` remote. In a clone with a stale
third-party remote sorted before `origin`, that diffs against a frozen
tip and runs the full suite. All agent work happens in worktrees.

## Fix

Add `files: git diff --name-only origin/main...HEAD` to the six globbed
pre-push lanes (`rust-tests`, `desktop-check`, `desktop-typecheck`,
`desktop-test`, `desktop-tauri-checks`, `mobile-checks`). The three-dot
form is the branch's merge-base diff against `origin/main` — the same
base resolution `scripts/check-file-sizes-core.mjs` (`resolveBaseRef`)
and CI's dorny/paths-filter already use. A lane now fires only when this
branch actually changed a file it covers; `main`-side changes never
re-trigger it, and a new branch diffs against `origin/main` (empty diff
→ all globbed lanes skip) rather than a stale remote. `branch-skew` and
`file-size-check` stay unfiltered by design.

Also pin hook dispatch to the Hermit-managed lefthook. The generated
`.git/hooks/*` dispatchers prefer `$LEFTHOOK_BIN`, then a `lefthook` on
`PATH` — so a Homebrew lefthook shadowed the pinned 2.1.3. A `rc:
bin/.lefthookrc` (a lefthook config key `lefthook install` bakes into
every dispatcher) exports `LEFTHOOK_BIN` to `bin/lefthook`, so a push
runs the pinned version regardless of `PATH`. `just hooks` already runs
`lefthook install`, so re-running it picks up the `rc` line — no recipe
change needed.

`AGENTS.md` documents that lanes are scoped by merge-base diff and that
agent shells should lead `PATH` with `./bin` so pinned tools win.

## Verification

Reproduced both bugs in a scratch repo mirroring the worktree +
stale-remote topology, with lanes stubbed to echo on selection:

- **Bug 1:** relay-only branch, `git merge origin/main` (main carried
`mobile/` + `desktop/` changes). Without the fix, `desktop-check` and
`mobile-checks` fired; with it, three-dot diff = only the relay file,
all globbed lanes skip.
- **Bug 2:** brand-new branch, no upstream, in a linked worktree with an
alphabetically-first stale remote. Confirmed `@{push}` is `fatal`,
`refs/remotes/origin/HEAD` is absent from the worktree git-dir, and the
stale remote's `HEAD ->` sorts first. Without the fix it fired lanes off
the stale tip; with it, lanes scope to `origin/main` merge-base and
skip.
- **Positive controls:** a `mobile/**` commit still fires
`mobile-checks`; a `crates/**` commit still fires `rust-tests` +
`desktop-tauri-checks`.
- **Dispatch:** with Homebrew lefthook 2.1.10 on `PATH`, running the
real generated `.git/hooks/pre-push` under `LEFTHOOK_VERBOSE=1` shows it
sourcing `bin/.lefthookrc`, exporting `LEFTHOOK_BIN`, and running
`lefthook v2.1.3`.
- This PR's own push (a brand-new branch in a linked worktree — the bug
2 case) ran only `branch-skew` and `file-size-check`; no
mobile/desktop/rust lanes fired, since the branch touches only
`lefthook.yml`, `AGENTS.md`, and `bin/.lefthookrc`.

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
2026-08-20 15:55:00 -04:00
Jordan Mecom
3ee465e12b Enforce a three-day dependency cooldown (#6426)
Configure Renovate to wait three days before proposing newly released
dependencies.

The policy requires a registry publication timestamp and suppresses
branches until the release ages past the window. Renovate security-alert
updates continue to bypass minimum-release-age checks, so known fixes
are not delayed.

Checked with `renovate-config-validator --strict --no-global
renovate.json`, `jq`, and `git diff --check`.

Signed-off-by: Jordan Mecom <jm@squareup.com>
2026-08-20 19:26:53 +00:00
Will Pfleger
54bbe7305b perf(desktop): resolve references without directory scans (#6328)
## Summary

- keep the channel poll membership-only and fetch the open-channel
directory only from explicit discovery surfaces
- resolve unknown ID-bearing references through one bounded
`get_channel_details` lookup, while name references remain limited to
member channels plus a browse/search-warm directory cache
- fail closed for fetched private metadata and cover cold lookup,
warm/member hits, private visibility, and cached misses with mounted
hook contracts

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Hayt <9e1c23a3fd83f61da34420e4e88ff1b16e45cafcc0cd9019eb07d4ecfa8ca9b0@buzz.block.builderlab.xyz>
Co-authored-by: Hayt <9e1c23a3fd83f61da34420e4e88ff1b16e45cafcc0cd9019eb07d4ecfa8ca9b0@buzz.block.builderlab.xyz>
2026-08-20 15:20:24 -04:00
Will Pfleger
b728a2af31 feat(llm): stamp thinking effort on call-completed log line (#6424)
The performance-analysis pipeline measures harness × provider × model ×
effort from production logs, but thinking effort was the only dimension
not stamped per call — it had to be attributed by config-changeover
timestamp.

Add `thinking_effort = ?cfg.thinking_effort` to the `llm: call
completed` `tracing::info!` in `Llm::complete()` so every call
self-describes all four dimensions. `?`-formatting preserves the
`None`-vs-`Some(...)` distinction the same way the token fields keep
None-vs-zero.

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
2026-08-20 14:45:03 -04:00
Wes
ee0c7076af Fix cross-owner relay agent mentions in owner-only builds (#6338)
## Summary

- keep `BUZZ_BUILD_AGENT_ACCESS_OWNER_ONLY` scoped to Desktop-managed
local start and provider deployment boundaries
- stop filtering independently operated relay agents by viewer/owner
equality in native discovery, autocomplete, and send-time revalidation
- preserve NIP-OA ownership verification, owner-authored `respond_to`
policy, shared-channel membership, and fail-closed send-time checks
- replace the packaged-build regression expectation with coverage for
cross-owner allowlisted and `respond_to=anyone` relay agents, including
the emitted agent `p` tag

Fixes #6329.

## Why

The packaged 0.5.17 build reused its managed-runtime owner-only
capability in relay-agent mention admission. That silently hid correctly
configured shared agents owned by another operator, even when their
verified policy explicitly authorized the viewer. The capability is
intended to constrain runtimes Desktop starts or deploys, not external
relay agents.

## Validation

- `pnpm --dir desktop test` (5093 passed)
- `cargo test --manifest-path desktop/src-tauri/Cargo.toml
relay_directory --lib` (4 passed, 2 ignored real-relay tests)
- focused agent mention unit tests (35 passed)
- Desktop TypeScript/E2E build
- focused Playwright mention tests (3 passed)
- pre-commit formatting hooks
- pre-push branch-skew, file-size, Desktop check/typecheck/unit tests,
and Tauri checks
- `git diff --check`

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-20 12:35:07 -06:00
morgmart
84c095f8be feat(cli): accept Buzz message links for thread reads (#6359)
## Summary

- let `buzz messages thread` accept a canonical `buzz://message` link
directly
- treat the selected message ID as authoritative, verify its channel,
and derive its containing thread root from the event
- reject stale or forged `thread` hints that disagree with the selected
message
- preserve the existing `--channel` / `--event` form while allowing it
to target any message in a thread

## Why

Agent skills should be able to hand first-class Buzz links to the public
Buzz CLI instead of carrying their own URL parsing wrappers. Link
handling belongs with the CLI that owns the protocol; identity and relay
selection remain explicit through the existing Buzz CLI environment and
do not read Buzz Desktop private state.

## Verification

- `cargo test -p buzz-cli` — 360 passed
- `cargo clippy -p buzz-cli -- -D warnings`
- `cargo fmt --all -- --check`
- repository pre-push gates, including 5,070 Desktop tests
- final architecture/code review — no must-fix findings

A relay-backed manual smoke test was not run because this session did
not have `BUZZ_RELAY_URL` and `BUZZ_PRIVATE_KEY` configured; the change
has focused parser, CLI argument, channel/root binding, and mismatch
tests.

---------

Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
2026-08-20 12:17:50 -06:00
Taylor Ho
1934e83bf5 feat(workflows): add workflow editor (#6248)
**Category:** new-feature
**User Impact:** Users can create, edit, duplicate, and deep-link to
workflows in a responsive visual editor without losing unsupported YAML
or unsaved work.
**Problem:** Workflow editing was split across disconnected surfaces and
lacked reliable URL state, lifecycle protection, and parity between Form
and YAML modes. **Solution:** This adds a route-addressable editor
foundation with stable pane identity, guarded dirty exits, lossless
Form/YAML transitions, responsive workflow and channel controls, and
matching reaction-filter execution support.

<details>
<summary>File changes</summary>

**crates/buzz-workflow/src/lib.rs**
Apply reaction trigger filters during workflow execution and cover
target-message gating.

**crates/buzz-workflow/src/schema.rs**
Extend the reaction trigger schema with the editor-owned filter field.

**desktop/src/app/navigation/useAppNavigation.ts**
Add navigation helpers for explicit workflow create, edit, and duplicate
editor modes.

**desktop/src/app/routes/WorkflowsRouteScreen.tsx**
Coordinate route state with the shared workflow library and editor
dialog.

**desktop/src/app/routes/lazyWorkflowsRouteScreen.ts**
Share one lazy route component across workflow route entry points to
avoid loading flashes.

**desktop/src/app/routes/workflows.$workflowId.tsx**
Parse workflow editor modes and pane deep links for workflow-specific
URLs.

**desktop/src/app/routes/workflows.tsx**
Parse library-level create state and render the shared workflow route
screen.

**desktop/src/app/AppWorkflowEditorOverlayProvider.tsx**
Host the shared workflow editor at the app-shell level so
channel-originated workflow dialogs stay above the active channel
instead of replacing it.

**desktop/src/shared/context/WorkflowEditorOverlayContext.tsx**
Expose route-independent open-existing and create-new workflow actions
to channel settings.

**desktop/src/features/workflows/ui/WorkflowEditorHost.tsx**
Share editor loading, unavailable, and dialog lifecycle wiring between
canonical workflow routes and the channel overlay.

**desktop/src/features/channels/ui/ChannelManagementSheet.tsx**
Add an experiment-gated, Canvas-style Workflows ingress below Canvas,
including channel-scoped loading, error, empty, and list states plus
open/create actions; disabled users issue no workflow query.

**desktop/src/features/channels/ui/ChannelWorkflowsSection.tsx**
Render the channel workflow list and New workflow action without pushing
the existing settings sheet past its file-size ceiling.

**desktop/src/features/workflows/ui/ChannelCombobox.tsx**
Adopt the final channel presentation, portalled scrolling, and one-shot
create-flow opening behavior.

**desktop/src/features/workflows/ui/CreateWorkflowDialog.tsx**
Remove the superseded create-only dialog in favor of the unified
workflow editor.

**desktop/src/features/workflows/ui/WorkflowCard.tsx**
Open workflow cards in the detail and run-history modal while preserving
explicit edit and duplicate actions.

**desktop/src/features/workflows/ui/WorkflowDetailDialog.tsx**
Present workflow Trigger/Steps in the shared modal chrome, with
top-chrome ingress to a responsive right-side run-history inspector and
an explicit edit action.

**desktop/src/features/workflows/ui/WorkflowDialog.tsx**
Unify create, edit, and duplicate lifecycle handling with URL panes,
generated-name synchronization, dirty-exit guards, stale-write
preservation, and protected webhook-secret handoff.

**desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx**
Build the responsive Form/YAML editor shell, stable step selection,
insertion and removal behavior, and lossless canonical-YAML
synchronization.

**desktop/src/features/workflows/ui/WorkflowStepCard.tsx**
Align workflow step controls and presentation with the final editor
interaction model.

**desktop/src/features/workflows/ui/WorkflowUnavailableDialog.tsx**
Show a non-disclosing loading or unavailable state for missing and
inaccessible workflow links, with retry and close actions.

**desktop/src/features/workflows/ui/WorkflowWebhookSecretDialog.tsx**
Obscure one-time webhook secrets by default and require explicit
confirmation before any close or navigation discards them.

**desktop/src/features/workflows/ui/WorkflowsScreen.tsx**
Connect library state and workflow actions to the route-addressable
editor.

**desktop/src/features/workflows/ui/WorkflowsView.tsx**
Restore the responsive workflow library, create tile, cards, loading
states, and shared action menu.

**desktop/src/features/workflows/ui/workflowEditorPane.test.mjs**
Cover pane parsing, serialization, and stable step-ID reconciliation.

**desktop/src/features/workflows/ui/workflowEditorPane.ts**
Define explicit trigger and stable step pane URL state.

**desktop/src/features/workflows/ui/workflowYamlDocument.ts**
Read and update header fields independently of full form validation so
incomplete steps cannot clear or disable the workflow title.

**desktop/src/features/workflows/ui/workflowYamlDocument.test.mjs**
Cover document-level workflow header reads and writes for incomplete
definitions.

**desktop/tests/e2e/workflow-title-stability.spec.ts**
Verify generated, renamed, saved, and duplicated titles remain stable
while moving between trigger and step panes.

**desktop/src/features/workflows/ui/workflowFormTypes.test.mjs**
Cover lossless Form/YAML round trips and actionable fallback for
unsupported fields.

**desktop/src/features/workflows/ui/workflowFormTypes.ts**
Own canonical workflow YAML conversion while preserving supported
trigger and step fields.

**desktop/src/shared/ui/PortalledScrollArea.tsx**
Provide bounded scrolling for popovers rendered outside their dialog
container.

**desktop/src/shared/ui/popover.tsx**
Allow workflow popovers to use the shared portalled scroll container.

**desktop/tests/e2e/channels.spec.ts**
Cover disabled and enabled Workflows experiment states, including
suppressed queries while disabled, placement beneath Canvas, channel
workflow listing and opening, channel-preselected workflow creation, and
direct return to the channel Workflows panel after close, discard, or
cancel.

**desktop/tests/e2e/workflows.spec.ts**
Exercise library actions, deep links, create/edit/duplicate lifecycle,
dirty exits, responsive editor behavior, YAML safety, stale updates, and
one-shot channel selection.

</details>

## Reproduction steps

1. Open **Workflows** and confirm the responsive card library, create
tile, card action menu, and card-to-detail/run-history modal navigation.
2. Open `?view=create`; confirm the channel chooser opens once, the
trigger inspector stays hidden until a channel is selected, and closing
the chooser does not make it reopen after unrelated edits.
3. Create a workflow, switch between Form and YAML, add and remove
steps, refresh a pane deep link, and confirm the selected trigger or
stable step remains addressable.
4. Edit or duplicate a workflow, make an unsaved change, and confirm
close, Escape, browser navigation, and route target changes require
discard confirmation while pane-only navigation does not.
5. Enter unsupported YAML and confirm Form mode gives an actionable
fallback without rewriting the definition; verify reaction triggers
preserve and execute their filter.

6. Open a channel’s settings, select **Workflows** below **Canvas**, and
open or create a workflow; confirm the shared modal stays over the
channel, the channel URL does not change, New workflow preselects that
channel, and closing or discarding returns directly to the channel’s
**Workflows** panel.
7. In create, edit, and duplicate modes, move between the trigger and
incomplete step panes and confirm the generated or edited title remains
visible and editable.

## Screenshots

Fresh captures from product head
`c5c3abc91a71fe511d43e6cc9168b1626d0c217c`; the later review-guidance
fix does not alter these pictured states.

### Workflow library and actions

![Workflow library with action
menu](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6248/workflow-library-actions-c5c3abc.png)

### Workflow editor — wide

![Wide workflow editor with step
details](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6248/workflow-editor-wide-c5c3abc.png)

### Workflow editor — narrow inspector overlay

![Narrow workflow editor with inspector
overlay](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6248/workflow-editor-narrow-c5c3abc.png)

### Workflow editor — active channel overlay

![Workflow editor portalled over the active
channel](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6248/workflow-editor-channel-overlay-c5c3abc.png)

## Review feedback addressed

- Corrected Diff Posted condition guidance to use the executor-supported
`str_contains(trigger_text, "deploy")` syntax and added a visible
Playwright regression assertion.
- Scoped direct workflow-detail navigation coverage to the stable `Edit
workflow` dialog name, asserted the workflow title separately, and
retained the trigger-node assertion.
- Routed dirty channel-overlay Duplicate/Edit transitions through the
existing discard confirmation, preserving the original YAML draft when
the user keeps editing.
- Made workflow deletion await relay success, remain non-dismissible
while pending, and retain the confirmation/editor/draft with an
actionable inline error on rejection.
- Gated the channel-settings Workflows ingress and channel workflow
query behind the `workflows` experiment, with defensive rendering if the
flag changes while that view is active.
- Matched the Reaction Added trigger to the prototype reaction picker,
preserving native/custom/legacy values in canonical YAML and providing
an explicit clear action.
- Kept a channel’s Workflows panel mounted beneath channel-origin
editors so clean close, dirty discard, and create cancel return directly
to that panel without changing the channel URL.

## Verification

Verified at exact pushed head
`76ebba7b7ace1e13445744200da70ca9da231b7e`:

- Push hooks passed: destination-org policy, branch-skew, differential
file-size, Desktop checks, TypeScript typecheck, and **5,115/5,115**
Desktop unit tests
- Focused channel lifecycle E2E passed: dirty edit discard returns
directly to the channel Workflows panel; create cancel does the same
while preserving the channel URL and preselected channel
- E2E production build, standalone TypeScript typecheck, and Biome
checks on both touched files passed
- Reaction-picker regression spec remains recorded at
`dc28ffa98ec34b4e0656757fb2dd93e60a84674d`: **5/5 passed** (picker
interaction, canonical YAML persistence/clear, legacy-value
preservation, save/reopen round trip, narrow viewport containment)
- Blox existing workflow E2E regression set at
`dc28ffa98ec34b4e0656757fb2dd93e60a84674d`: **36/36 passed**
- Earlier blocker and review regressions remain recorded at
`3760c3d657a525f5af98e8d0f98bdd03999d8e61`: **5,114/5,114** Desktop unit
tests and the dirty-overlay/deletion focused checks
- Working tree clean; local branch, remote branch, and PR head all match
the exact SHA above

### Related issue

None found. Closest prior work: #231.

---------

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Codex <noreply@openai.com>
2026-08-20 12:15:56 -06:00
Tyler
7ebe3ea699 fix(desktop): preserve huddle speech boundaries (#6397)
## Problem and intent

Buzz huddles have been clipping speech into fragments: one live turn
arrived as the single letter “M,” and another ended mid-sentence. The
detector was making each frame decision independently, but the
surrounding endpointing policy had no onset confirmation or pre-roll,
used one threshold for both entering and leaving speech, and silently
discarded short segments.

This PR keeps Earshot 1.1.0 and fixes that policy around it. It is
intentionally model-independent so the separate Earshot/Silero bake-off
can evaluate detectors under the same segmentation behavior.

## What changed

One production file changed: `desktop/src-tauri/src/huddle/stt.rs`
(**+367/−79** versus `main`).

- Add a pure `VadEndpoint` state machine around Earshot probabilities.
- Preserve 256 ms (16 frames) of pre-roll before confirmed onset.
- Require three consecutive frames above 0.50 to enter speech.
- Use 0.35 to leave speech, preserving hysteresis-band audio.
- Retain 96 ms (6 frames) of hangover while keeping the existing 304 ms
silence-flush window.
- Make short-segment drops visible in logs instead of silent.
- Add boundary, onset, hysteresis, hangover, drop-path, and PTT policy
tests.
- Bind the thresholds to Earshot 1.1.0 in source. Earshot 1.2.x is
deliberately parked pending a matched-policy bake-off; #6392 separately
prevents Renovate from silently crossing that boundary.

## Boundary behavior and known tradeoffs

A hard message boundary clears pre-roll. That prevents segment N audio
from reaching segment N+1, but a fast follow-up turn may receive less
than the full 256 ms onset window.

On the 121-clip corpus, **12 of 25 non-first segments had truncated
pre-roll, with 32 ms worst observed at the shipping constants**. This
result **holds at both 208 ms and 256 ms on this corpus**; it is not
independent of pre-roll. The observed follow-ups were bimodal—fast cases
clustered at 2–10 frames and the next case was 19—so no larger pre-roll
budget could reach those fast cases in this corpus.

If a future refactor makes pre-roll survive a boundary, segment N
reaches segment N+1 under the strict predicate:

```text
gap < VAD_PRE_ROLL_FRAMES - VAD_ONSET_FRAMES
```

At the shipped values that means gaps 0–12 leak and gap 13 is the first
clean case. Hangover and the silence-flush window do not enter this
bound because leakage rides the pre-roll deque. Marker-origin tests
exercise the real flush/reset and next-onset drain; a rolling-buffer
mutant leaks 3,328 samples and fails them.

Other known behavior:

- `voiced_frames` now counts frames above the 0.35 exit threshold once
speech begins, not only frames above 0.50. Corpus drop counts measured
under `> 0.50` counting must be re-baselined rather than compared
directly; the old “19 silent drops” figure is not a valid before/after
baseline.
- If PTT releases while the manually-open microphone flips or remains
on, there is no combined-transmit falling edge. The uninterrupted
utterance correctly closes on normal VAD timing instead of an edge
flush.
- The GUI-to-`push_audio_pcm` wiring is unchanged. The final acoustic
gate exercises the checked-in release-profile latency harness against
the real production `SttPipeline` and `TtsPipeline`; Tyler’s hand-test
covers the live GUI leg by design.

## Verification ledger

All gates attest exact head `2dad6bb0e2e2a0af115a9a06c26cf6183fedb633`.

- **Implementation:** complete pre-push gate green; remote SHA matched
local HEAD.
- **Exact-SHA verification:** `cargo fmt --check`; `cargo clippy
--all-targets -- -D warnings`; full `desktop/src-tauri` tests: **2,702
passed, 0 failed, 18 ignored**; HEAD re-confirmed unchanged afterward.
- **Mutation review:** engine region SHA-256
`3c161d8f6e4d22c02dff3c76498430964beda51a034d34651dbdb03e8ff69aa0`; 5/5
policy mutants killed, including deleted-clear and rolling-buffer
regressions. Direct gap sweep leaked at 0–12 and was clean from 13.
- **Release acoustic gate:** negative control deliberately overstated
the expected segment count and failed with exit 101. Soft/short onset
produced 1/1 segment (`“I'm happy.”`). Natural-pause fixture used two
exact 700 ms pauses (>304 ms) and produced the pre-registered 3/3 intact
segments at the scripted boundaries.
- **Release CPU beside Pocket TTS:** soft fixture median 32.1%, p95/max
56.8% (5 sparse samples); natural fixture median 14.55%, p95/max 17.2%
(8 sparse samples). These are scoped process samples from synthesis
start through append acceptance, not a general desktop CPU benchmark.

Local review receipts (not committed to the repository):

- `.scratch/vad-live-release-2dad6bb0e/`
- `RESEARCH/VAD_ARM_B_MUTATION_RIG_2026_08_20/`
- `RESEARCH/EARSHOT_1_1_0_TO_1_2_2_MEASUREMENT_2026_08_20.md`

## Hand-test focus

Before merge, exercise the two live shapes that originally failed:

1. Soft short openers such as “M” and “yes.”
2. Natural mid-sentence pauses.

Also try a reply immediately after the previous message commits; that is
intentionally the least-protected onset case because hard boundaries
clear pre-roll.

---

Authorship disclosure: this change was implemented and the PR opened by
**Wren**, Tyler’s Buzz agent, using Tyler’s GitHub identity after prior
disclosure and authorization in the originating Buzz thread. Tyler
remains the accountable human reviewer/operator.

---------

Signed-off-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Co-authored-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
2026-08-20 14:06:00 -04:00
Diem Nguyen
886cef7f72 test(desktop): use a wordlist-safe separator in passphrase word-count test (#6356)
## Summary

Fixes #6249.


`key_backup::tests::generated_passphrase_respects_word_count_and_separator`
joined words with `-` and asserted the phrase splits back into exactly
`count` parts. The EFF short wordlist contains exactly one hyphenated
entry (`yo-yo`, line 1281 of 1296), so drawing it into either
hyphen-joined arm yields one extra part — a ~1-in-186 flake per full
suite run (`1 - (1 - 1/1296)^7 ≈ 0.539%`).

This switches the two hyphen arms to `|`, which cannot appear in the
wordlist — the exact guard the sibling test
`generated_passphrase_clamps_word_count` already documents and uses. The
space, dot, and empty-separator arms are untouched (no wordlist entry
contains a space or a dot), so the test still covers word count,
wordlist membership, and minimum length.

`generate_passphrase` itself is unchanged — a hyphenated word in a
hyphen-joined passphrase is not a product defect, only an ambiguity the
test's parsing could not handle.

## Verification

At `main` (196d62f), compiled the desktop test binary once and looped it
2000× per state:

| State | Failures / 2000 runs | Expected |
|---|---|---|
| old code | 15 | ~10.8 (P ≈ 0.539%) |
| fixed | 0 | 0 |

Full desktop Tauri suite (`cargo test --workspace` in
`desktop/src-tauri`): **2693 passed, 0 failed**.

Signed-off-by: Fizz <1f3b09af3c417274e5516bf95fadd3c118f35a31ae922257d550c69159ba931c@buzz.block.builderlab.xyz>
Co-authored-by: Fizz <1f3b09af3c417274e5516bf95fadd3c118f35a31ae922257d550c69159ba931c@buzz.block.builderlab.xyz>
2026-08-20 11:53:09 -06:00
Will Pfleger
2ce8df8533 fix(models): curate Databricks alias-aware labels for 5 missing endpoints (#6360)
Curates Databricks model labels through prefix-stripping aliasing and
materializes exact records for five endpoints missing from the
Databricks catalog.

**Alias-aware label resolution** (Databricks v2)
- Strip workspace-specific prefixes (`goose-`, `team-x-`, etc.) before
exact-record lookup so any prefixed alias resolves to its canonical
label without enumerating every alias variant.
- Return `None` for uncurated ids instead of falling back to a raw
string; callers control the fallback display.

**New exact records — label-only (Anthropic Messages route, axes from
family rules)**
- `databricks-claude-fable-5` → "Claude Fable 5" (materialized from
`anthropic-adaptive-xhigh-fable-5`)
- `databricks-claude-opus-4-8` → "Claude Opus 4.8" (materialized from
`anthropic-adaptive-xhigh-opus-4-8`)
- `databricks-claude-opus-5` → "Claude Opus 5" (materialized from
`anthropic-adaptive-xhigh-opus-5`)
- `databricks-claude-sonnet-5` → "Claude Sonnet 5" (materialized from
`anthropic-adaptive-xhigh-sonnet-5`)

**New capability-bearing record — Kimi K3 (MLflow Chat route)**
- `databricks-kimi-k3` → "Kimi K3" with axes from models.dev Moonshot
catalog: reasoning toggle + effort `[low, high, max]`, no default;
`_reconciliation_doc` records the source and reconciliation policy.

**Corpus and tests**
- 6 new normative-corpus vectors (canonical + one `goose-*` alias per
new id); executable vector count updated to 113 in both Rust and TS
gates.
- Rust and TS label tests extended to cover all 3 new canonical ids and
their aliases via the prefix stripper.
- Sentinel variable fix in discovery-provider test to prevent false
failure in Databricks dev environments where `BUZZ_AGENT_PROVIDER` is
set.

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
2026-08-20 13:46:10 -04:00
Will Pfleger
d274a6e949 fix(acp): guard against unrequested public relay skills (#6394)
Adds a shared base-prompt instruction that agents must not read or
blindly follow public Buzz relay skills unless a human explicitly
requests them.

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
2026-08-20 13:44:06 -04:00
thomaspblock
3c228b1082 feat(desktop): refine context-aware Projects collaboration (#6396)
## Summary
- give inline project agents bounded visible-page and selection context
while reusing the shared message-thread presentation
- add contextual collaboration actions for discussing project entities
in related channels
- align project list metadata, context rails, and work-item
communication actions with the active workspace

This is Part 3 of the Projects v6 stack, following #6368. Part 4
contains the remaining navigation and detail-page polish.

## Testing
- Desktop unit suite: 5,125/5,125 passed
- Projects smoke specs: 62/62 passed
- TypeScript, Biome, typography, pubkey, and differential file-size
checks passed
- full pre-push gate passed

## Post-Deploy Monitoring & Validation
- validate Projects overview/detail agent chat and discuss-in-channel
journeys in the first staging Desktop session
- healthy signals: context matches the active project/repository/work
item, messages remain in the chosen channel, and restored conversations
exclude unrelated DM history
- failure signals: stale or cross-project context, duplicate/missing
thread rows, or collaboration actions targeting the wrong channel;
mitigate by reverting this PR

Related: #6335

---------

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
2026-08-20 12:59:09 -04:00
Wes
2e7583bf5a fix(desktop): distinguish duplicate agent devices (#6337)
## Summary

- distinguish same-name owned agents by management provenance: `managed
here` for Desktop-managed identities and `managed elsewhere` for
same-owner relay identities
- show provenance only when same-name suggestions collide, alongside
each identity's short npub
- preserve exact-pubkey selection and keep unique-agent autocomplete
unchanged
- add a composed mock-bridge regression covering relay owner
propagation, rendered labels, keyboard/pointer selection, and outbound
mention pubkeys

## Testing

- focused mention suggestion mapping and label tests
- composed Desktop E2E passes for both same-name identities and
exact-pubkey routing
- causal mutation verified: replacing the relay candidate's
`ownerPubkey` with `null` makes the composed E2E fail on the `managed
elsewhere` assertion
- pre-push Desktop checks: Biome, TypeScript, file-size ratchet, and
5,103 Desktop tests

## Manual test

With two same-name owned agents visible in a channel, type `@<name>`.
Duplicate rows identify the identities as `agent · managed here` and
`agent · managed elsewhere`, include distinct short npubs, and selecting
either routes the mention to that row's exact pubkey.

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-20 10:16:01 -06:00
Matt Kursmark
e5d1dfef7b feat(desktop): close Buzz window with Cmd+W (#6314)
## Summary

- close the current Buzz window with `Cmd-W` on macOS
- keep Buzz Term's existing `Cmd-W` behavior when the terminal owns
input, where it closes the active terminal tab
- cover the close-window chord and its modifier/composition guards with
unit tests

## Why

Buzz removes macOS's native Close Window menu accelerator so the webview
can conditionally route `Cmd-W` to Buzz Term. That also left normal Buzz
mode without the standard close-window shortcut. The new app-level
bubble-phase handler restores window closing while allowing the
terminal's capture-phase handler to retain priority.

For the main window, the existing Rust close-request handler keeps the
webview alive and hides it to the tray, matching the titlebar close
button.

## Validation

- desktop unit tests: 5,093 passed
- focused close-window and terminal shortcut tests: 28 passed at
`71a2cce42013440e297c7b237d45b20e9638078d`
- desktop TypeScript: passed
- desktop checks: passed (pre-existing warnings only)
- workspace Rust clippy: passed
- Tauri Rust clippy/check: passed
- desktop build: passed
- mobile format/analyze: passed
- Tauri tests: 2,592 desktop tests and 26/27 terminal tests passed; the
existing `default_prog_child_observes_the_login_argv0` PTY fixture
repeatedly timed out waiting for `/bin/sh`, including when run alone,
and is unrelated to this TypeScript shortcut change

---------

Signed-off-by: Matt Kursmark <kursmark@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
2026-08-20 16:31:39 +01:00