Commit Graph

121 Commits

Author SHA1 Message Date
Yuval Dinodia 78c5d7ceb5 fix(buzz): messages sent during Gateway downtime are dropped after restart (#117259)
* fix(buzz): messages sent during Gateway downtime are dropped after restart

Every new Gateway process subscribed to Buzz rooms starting at its own
start time, because the lookback flag that enables backlog paging is
process-local. That cutoff is applied as the NIP-01 since filter, so any
room message a human sent while the process was down was never returned
by the relay and never reached the agent or the transcript.

The account gateway now persists a per-account recovery watermark in the
plugin state store. First-ever setup still starts from the current time;
later process starts resume from the saved watermark, clamped to the
existing 24 hour retention floor. The watermark advances only after
inbound handling completes and is stored at the admitted message
created_at, so the inclusive since boundary re-offers the last admitted
message to the existing persistent event-id dedupe guard.

* fix(buzz): keep the cold-start recovery cursor behind unfinished work

Codex review found two ways the recovery watermark could still drop room
messages. Backlog replay dispatches up to eight handlers concurrently, so
a newer message finishing before an older one committed the newer
timestamp; a crash then left the older message with no dedupe record and
a cursor already past it. The stored timestamp was also the sender
controlled created_at, so a future dated room event pushed the cursor
past locally observed time and excluded real downtime messages on the
next start.

The account gateway now tracks a recovery frontier per session. A
checkpoint is the highest completed message time bounded by the oldest
still running message, the oldest failed message, and the receipt time
observed when the message was admitted. Checkpointing stays closed until
the bus reports the room backlog fully drained, so a session that is
still paging history cannot commit past events it has not seen yet.
catchUpHistory now reports drained or incomplete for that signal.

* fix(buzz): scope cold-start recovery per room and fence it at enqueue

Admit replay work into the recovery frontier when it enters the dispatch queue instead of when a worker starts it, so a crash cannot persist a cutoff past an event that is still queued.

Key recovery cursors by room instead of by account, so a room configured after the first start resolves to the current time and gets no backfill, while existing rooms resume from their own cursor.

Record an account-level start marker so the first start under a watermark-aware build recovers the existing retention window instead of repeating the reported loss on the first restart after an upgrade.

* fix(buzz): keep cold-start recovery to accounts that already ran

An account with no persisted cursor is a fresh install as often as it is a
pre-watermark upgrade, and stored state cannot tell them apart, so the first
start no longer replays the retention window. It records the current time as
each room cursor and recovers only from the second start onward.

Dropping the account start marker also removes the interrupted-bootstrap
window where a marker written before the room cursors made the next start
treat cursor-less rooms as initialized.

Recovery state capacity is now derived from the supported room limit instead
of a smaller fixed number, and any non-complete history paging outcome, not
just timestamp-over-limit, holds the recovery frontier undrained.

* fix(buzz): bound the recovery cursor store to each account

ClawSweeper found that the recovery watermark opened one fixed plugin-state
namespace for every account while sizing it at the per-account supported room
count. Plugin-state capacity is enforced per plugin and namespace, so once one
account registered its full room allowance, a second account's register call
threw and its rooms stayed at the current-time cutoff, which is the same
dropped-message outcome this PR set out to fix.

The store is now opened against a namespace derived from the account identity,
so each account carries its own supported room capacity. The account moves out
of the entry key into the namespace, which leaves one account-scoped store path
rather than a fallback, and makes cross-account cursor mixing unrepresentable.

* fix(buzz): simplify durable restart recovery

Co-authored-by: yetval <yetvald@gmail.com>

* test(buzz): use real relay response in recovery fixture

Co-authored-by: yetval <yetvald@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-25 17:39:30 -07:00
Leah Armstrong 889a153171 fix(buzz): anchor threaded replies without nesting (#124884)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-25 17:12:26 -07:00
Peter Steinberger 9b2831afd5 feat(buzz): authorize different senders in each room (#129655)
* feat(buzz): support room-scoped sender authorization

* fix(buzz): synchronize generated official channel catalog
2026-08-25 16:52:42 -07:00
xingzhou b0526f7be7 fix(buzz): bound relay information responses (#119182)
Reject malformed relay metadata and cancel oversized response streams at the existing 16 MiB provider boundary.

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-25 16:36:24 -07:00
Peter Steinberger 6b5b75aa01 fix(buzz): stop named account setup from replacing the existing bot identity (#129663)
* fix(buzz): reject named accounts before overwriting bot credentials

Preserve the requested account through channel setup so the existing single-account validator rejects unsupported named identities before configuration mutation. Preserve both plaintext credentials and SecretRefs.

Fixes #123200.

Co-authored-by: yu-xin-c <2182712990@qq.com>

Co-authored-by: atlas-maxjb <atlas@maximusjb.com>

* test(buzz): preserve environment-backed identity on rejected setup

Prove named --use-env setup fails before changing the existing bot credentials, disabled state, relay, or owner authentication tag.

Co-authored-by: yu-xin-c <2182712990@qq.com>
Co-authored-by: atlas-maxjb <atlas@maximusjb.com>

---------

Co-authored-by: atlas-maxjb <atlas@maximusjb.com>
Co-authored-by: yu-xin-c <2182712990@qq.com>
2026-08-25 16:32:28 -07:00
Peter Steinberger 234df15a6d chore: refresh dependencies after seven-day cooldown (#128414)
* build(deps): refresh dependencies after cooldown

Apply dependency, toolchain, action, image, and exact tool updates released by the inclusive 2026-08-16 seven-day cutoff. Adapt owner boundaries for the resulting CUA, logging, Teams, Markdown, native, and test-harness contract changes while retaining versions blocked by upstream compatibility constraints.

* fix(ui): align markdown renderer env typing

* fix(deps): align postcss and mistral peer contracts

* fix(deps): repair refreshed dependency contracts

* fix(deps): retain tslog startup budget

* fix(ci): verify Android tools with SHA-256

* fix(ci): fence Android SDK cache version
2026-08-24 03:01:54 -07:00
Peter Steinberger 992948356f fix(secrets): fail closed for configured references (#127669)
* fix(secrets): fail closed for configured references

Keep explicit SecretRefs authoritative across Gateway auth, onboarding, probes, channel credentials, outbound sends, and GitHub Copilot discovery/embeddings. Ambient credentials remain available only when no reference owns the surface.

* test(secrets): align gateway fallback expectations

* test(providers): remove load-sensitive stream timing

* test(xai): normalize stream capture failures

* fix(copilot): preserve direct auth precedence

* test(ollama): keep progressing streams alive

* test(models): mark resolved config fixtures

* fix(models): drop stale probe import
2026-08-21 18:00:28 -07:00
Peter Steinberger d5abaf4ab3 perf(test): advance Buzz reconnect backoff (#126649) 2026-08-20 04:53:17 -07:00
Peter Steinberger a4eba6c606 fix(channels): retire buses before shutdown (#126637) 2026-08-20 03:38:39 -07:00
Peter Steinberger 3378e07d50 refactor(plugin-sdk): promote shared runtime primitives (#126193)
* refactor(plugin-sdk): promote shared runtime primitives

* test(codex): keep one attempt tools owner
2026-08-19 01:10:18 -07:00
Josh Avant 97a53a9b35 feat: audit admitted channel participant identity (#122863)
* feat: audit admitted channel participant identity

* fix: preserve Telegram identity through thread recovery

* fix: signal held gateway process groups

* fix: keep audit evidence passive in collect routing

* fix: validate copied channel participant evidence

* fix: bind channel participant evidence to host ingress

* fix: honor Telegram proof credential roles

* fix: restart held Telegram proof through gateway

* fix: repair channel identity CI regressions

* test(matrix): bind thread routing owner

* fix: preserve direct DM SDK compatibility

* fix: bind channel provenance at host runtime

* test(feishu): provide channel context builder

* fix: defer record-bound channel runtime resolution

* fix: keep channel admission evidence core-private

* fix(audit): bind channel admission to plugin lifecycle

* fix(audit): bind ingress provenance to final context

* refactor(audit): split admission scope keys

* test(queue): cover combined metadata carriers

* refactor(audit): keep lifecycle helpers private

* fix(queue): preserve combined turn authority

* test(channels): provide ingress context builders

* test(channels): align integrated CI fixtures

* test(clickclack): resolve model-loop ingress

* docs: preserve channel participant evidence invariant
2026-08-14 08:57:01 -05:00
Patrick Erichsen 074d75d372 test(buzz): add opt-in thread QA coverage (#116081)
* test(buzz): add opt-in thread QA coverage

* fix(buzz): preserve QA conversation kind

---------

Co-authored-by: Dallin Romney <dallinromney@gmail.com>
2026-08-13 12:54:36 +08:00
Vincent Koc dabf55727b fix(ci): prevent channel add command test timeout (#122879)
* test(channels): isolate add env setup contracts

* test(channels): cover adapter env setup
2026-08-12 19:24:31 -07:00
Peter Steinberger 99d662473c fix(channels): fail-fast headless channel setup with plugin-declared env contracts (#122530)
* fix(channels): validate headless channel setup

* docs(channels): document headless provisioning

* fix(channels): repair setup metadata typing

* chore(channels): regenerate official channel catalog for env metadata

* fix(slack): keep mode-conditional env contract plugin-owned

Static --use-env declaration keeps only the unconditional SLACK_BOT_TOKEN;
socket-vs-HTTP conditional requirements (app token, signing secret) stay in
Slack's own setup validation so HTTP mode no longer demands an irrelevant
SLACK_APP_TOKEN.

* chore(sdk): regenerate api baselines and catalog after rebase

* fix(slack): align manifest env declaration with runtime contract

* chore(sdk): regenerate api baselines after rebase

* chore(sdk): regenerate api baselines after rebase

* chore(sdk): regenerate api baselines after rebase
2026-08-12 17:12:15 +00:00
Peter Steinberger 48639663b0 chore(release): prepare 2026.8.1 (#120375) 2026-08-07 18:44:12 -07:00
Peter Steinberger 10e60fa0ce refactor(plugins): shared legacy-state doctor migration and simple secret contracts (#120346)
* refactor(plugins): share legacy JSON doctor migration

* refactor(discord): share account token inspection cascade

* refactor(plugins): share simple channel secret contracts

* refactor(discord): keep token inspector private
2026-08-07 13:55:31 -07:00
Peter Steinberger f9d9d1225a refactor(channels): own the lifecycle status contract in SDK patch factories (#118795)
* refactor(sdk): add channel lifecycle patch factories

* refactor(channels): adopt lifecycle patches in a-m

* refactor(channels): adopt lifecycle patches in n-z

* refactor(runtime): lifecycle-own ambient registries

* test(slack): assert lifecycle factory fields

* fix(sdk): preserve lifecycle patch extras types

* test(zalouser): widen lifecycle status sink

* test(irc): avoid shadowed status patch

* fix(zalo): reuse account-agnostic media route

* fix(gateway): accept explicit channel ready recovery

* test(qa): assert terminal Slack block fact

* test(qa): restore Slack blocked lifecycle scenario

* test(gateway): lock explicit lifecycle recovery contract
2026-08-03 12:39:48 -07:00
Peter Steinberger 628672aaa1 test(buzz): consolidate lifecycle fixtures (#118316) 2026-08-02 19:42:22 -07:00
Peter Steinberger 0c32879d45 feat(channels): publish recorded lifecycle from bundled channel transitions (#118110)
* feat(channels): publish recorded lifecycle from bundled channel transitions

* chore: remove lifecycle changelog entry
2026-08-02 13:04:49 -07:00
Shakker c60887bd73 fix: refresh Buzz room targets after reconnect (#117927) 2026-08-02 10:30:32 +01:00
Shakker 6129fbf784 fix: invalidate removed Buzz mention members 2026-08-02 10:30:32 +01:00
Shakker c2d6ecee3c fix: align Buzz explicit mention semantics 2026-08-02 10:30:32 +01:00
Shakker 1b8c99fa4e test: split Buzz mention delivery coverage 2026-08-02 10:30:32 +01:00
Shakker ea099cfdf7 fix: preserve Buzz reply session threads 2026-08-02 10:30:32 +01:00
Shakker 3de2a752f5 refactor: keep Buzz mention helpers internal 2026-08-02 10:30:32 +01:00
Shakker d4490c6a9d fix: invalidate stale Buzz room targets 2026-08-02 10:30:32 +01:00
Shakker f4e332a72e fix: tighten Buzz mention disambiguation 2026-08-02 10:30:32 +01:00
Shakker 6d7e371b0e perf: keep Buzz plain sends on the fast path 2026-08-02 10:30:32 +01:00
Shakker fe6960342f fix: reject unresolved Buzz mention text 2026-08-02 10:30:32 +01:00
Shakker 4c6e1f0d4c fix: resolve non-ASCII Buzz member mentions 2026-08-02 10:30:32 +01:00
Shakker c8d5d8ea34 fix: satisfy strict Buzz mention resolution 2026-08-02 10:30:32 +01:00
Shakker 0ee44d551a feat: guide Buzz room targeting and mentions 2026-08-02 10:30:32 +01:00
Shakker 12b924c4d0 test: cover Buzz mention boundaries 2026-08-02 10:30:32 +01:00
Shakker 09bdcf3eb1 fix: resolve Buzz mentions on reply delivery 2026-08-02 10:30:32 +01:00
Shakker 8fb9dcd54e feat: emit native Buzz mention tags 2026-08-02 10:30:32 +01:00
Shakker c4d355133f feat: resolve Buzz room member mentions 2026-08-02 10:30:31 +01:00
Patrick Erichsen 213b43ff03 fix(channels): preserve human group session titles (#117680) 2026-08-01 17:00:04 -07:00
Peter Steinberger 568ea29d2e refactor(plugins): inherit shared package boundary settings (#117474) 2026-08-01 09:11:09 -07:00
Ayaan Gazali 11069c3df5 fix(channels): config validation rejects documented channels.<id>.configWrites on 13 channels (#117206) 2026-08-01 15:33:16 +08:00
Vincent Koc 6922ddd936 fix(qa): isolate runner discovery facades (#117203) 2026-08-01 13:40:11 +08:00
Yuval Dinodia e8d546c8da fix(buzz): reconnect silently skips retained inbound messages (#116925)
* fix(buzz): page reconnect history instead of dropping older messages

On reconnect the Buzz gateway asked the relay for a single capped page of
room history and treated EOSE as a complete recovery. Any backlog larger
than the per-room replay limit was never requested again, so those messages
never reached handleBuzzInbound, the agent, or the session transcript, and
nothing reported the loss.

The room subscription now records how much history its first page returned
and, when that page filled the limit, pages older history through the relay
until it is exhausted. Each page is dispatched through the existing bounded
replay queue and the next page waits for queue capacity, so recovery stays
memory bounded. A room whose backlog cannot be paged past a single
timestamp is now reported instead of dropped silently.

Membership tracking moves to room-membership-tracker.ts because buzz-bus.ts
was already at the 700 line ceiling.

* fix(buzz): hold dispatch capacity while a history page is in flight

Catch-up asked the replay queue whether capacity existed and then issued the
relay query, but nothing held those slots. Live room events arriving while
the query was in flight could consume them, so admitting the page afterwards
could report overflow, which closes the dispatch queue and drops every
queued message before forcing a reconnect. A busy room with slow inbound
handlers could repeat that instead of finishing recovery.

Capacity is now reserved rather than sampled. reserveCapacity resolves with a
reservation that owns its slots until released, page events are admitted
through that reservation, and the reservation is released once the page is
enqueued. Live enqueues keep the full pending limit and are never rejected
earlier because a reservation is outstanding. An overflow reported through a
reservation means the relay exceeded the page it was asked for, so it is
reported as a history error instead of tearing down the session.

* fix(buzz): bound reconnect history pages

* fix(buzz): preserve replay reservations

* test(buzz): cover catch-up settlement paths

* fix(buzz): drain saturated history ranges

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-01 08:28:03 +08:00
Peter Steinberger 9e4381eb1c refactor(channels): unify bundled channel setup contracts (#117106)
* refactor(channels): canonicalize bundled setup contracts

* test(matrix): use scoped environment fixtures
2026-07-31 16:57:29 -07:00
Shakker c5979d05ef fix: repair Buzz plugin packaging (#116865)
Restore standalone Buzz npm and ClawHub packaging by using the shipped QA runner SDK surface and generated dependency lock workflow.

Prepared head SHA: 58d0a52c61
Co-authored-by: Shakker <165377636+shakkernerd@users.noreply.github.com>
Reviewed-by: @shakkernerd
2026-07-31 15:32:16 +01:00
Shakker 5cd00cfbaa fix: reserve Buzz relay subscription capacity (#116799) 2026-07-31 13:40:34 +01:00
Shakker a382e6be8a fix: retain Buzz metadata changes during startup 2026-07-31 13:40:34 +01:00
Shakker ec72e23984 fix: resolve Buzz directory CI failures 2026-07-31 13:40:34 +01:00
Shakker 429e83bd23 fix: exclude archived Buzz rooms from peer snapshots 2026-07-31 13:40:34 +01:00
Shakker 8f3c611951 fix: reconnect Buzz rooms after membership notifications 2026-07-31 13:40:34 +01:00
Shakker b3c4ea0291 docs: explain Buzz archived room handling 2026-07-31 13:40:34 +01:00
Shakker bfa0b7e607 test: cover Buzz archived room subscription changes 2026-07-31 13:40:33 +01:00