Commit Graph

16582 Commits

Author SHA1 Message Date
xingzhou 713b6151d1 fix(qa): preserve crabbox command output unicode (#110278)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 07:13:25 +01:00
dwc1997 8b03d5ce24 fix(elevenlabs): reject malformed base URL overrides (#105163)
* fix(elevenlabs): fall back to default base URL when config value is malformed

* fix(elevenlabs): reject malformed and non-http(s) base URL overrides

* fix(elevenlabs): redact configured URL from base URL validation errors

* fix(elevenlabs): preserve realtime WebSocket overrides

* test(elevenlabs): avoid stale realtime test overlap

* style(elevenlabs): format realtime URL assertion

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 07:08:45 +01:00
pick-cat 99046179a8 fix(vydra): bound stalled generated image download body reads (#109210)
* fix(vydra): bound dripping asset downloads with a wall-clock deadline

* fix(vydra): bound dripping non-2xx error bodies with wall-clock deadline

* fix(vydra): preserve bounded provider error metadata

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 07:05:07 +01:00
mushuiyu886 8178cf1038 fix(nostr): preserve reply event context (#110085) 2026-07-18 06:57:31 +01:00
Peter Steinberger 442c166122 refactor(sessions): replace ambient watch sentinels with provenance (#110428)
* refactor(sessions): store watch provenance in cursors

* style(docs): align database schema table

* refactor(state): use Kysely for watch migration

* style(state): remove redundant timestamp casts
2026-07-18 06:55:29 +01:00
Peter Steinberger ab0277946d fix(qa): isolate active memory migration (#110358) 2026-07-18 06:50:13 +01:00
Peter Steinberger d4d23fe954 fix(mattermost): preserve websocket posts across restarts (#110386)
* fix(mattermost): adopt durable ingress drain at the websocket chokepoint

Posted events processed detached from the websocket receive with only a
5-minute in-memory guard; a crash lost the post and reconnect never replays
it. Raw posted envelopes now journal durably (event_id = post.id per the
upstream Post model, lane per channel_id, one row per post) before handler
scheduling; dispatch runs through the core drain with deferred claims through
debounce, merged-flush fan-out adoption, gated-turn settlement, and 30d/20k
tombstones covering the old 5min/2k guard, which is deleted after its parity
test. post_edited stays excluded and cannot be swallowed by posted
tombstones. Cold-gap limitation stated: Mattermost cannot replay posts missed
while disconnected.

Autoreview blocked by codex sandbox network in the build stage; full manual
review performed (updated one websocket test asserting the pre-adoption
parsed-post contract to the raw-envelope contract). Part of #109657 wave 2.

* style(mattermost): keep ingress monitor type internal

* fix(mattermost): retry then loudly escalate a failed durable append

Landing autoreview caught a real loss path: a durable enqueue failure at the
websocket chokepoint was logged and swallowed — the raw envelope discarded,
the connection kept running against a broken store, and reconnect never
replays, so a transient SQLite failure silently lost the post. The append now
retries with short backoff for transient blips; a persistent failure
propagates and the websocket terminates loudly so the outage is
operator-visible instead of silently dropping every subsequent post.
Regression test covers both the absorbed-transient and escalation paths.

* style(mattermost): format rebased ingress handler

* docs(mattermost): document bounded auth-failure retries under deferred claims

* fix(mattermost): guard the drain pump against stop racing the async prune

stop() disposing before the startup pump finished pruning let the pump
lazily create a fresh undisposed drain and dispatch after shutdown. The pump
now re-checks running after the prune, and stop() disposes again after
awaiting the pump so a drain created mid-race is torn down. Regression test
blocks the prune across stop and asserts no dispatch.

* fix(mattermost): serialize durable admissions to preserve lane order

Concurrent websocket callbacks let a post in append-retry backoff be
overtaken by its successor, inverting same-channel arrival order in the
queue. Admissions now chain (order over latency, mirroring the iMessage
admission tail); regression proves a retried post still lands ahead of a
concurrently received one.

* test(mattermost): assert lane order via dispatch sequence

* fix(mattermost): stop() awaits in-flight admissions before disposal

* fix(mattermost): satisfy ingress lint checks

* fix(mattermost): honor envelope-level channel ids in the durable inspector

Posts can carry their channel id on the post, the event data, or the
broadcast envelope — the monitor dispatch honors all three, but the ingress
inspector and claim-side validator required the nested field, rejecting valid
posts as permanent and (via the storage-failure escalation) tearing down the
socket for a failure that never happened, losing posts reconnect cannot
replay. Both sites accept the three shapes; regression proves an
envelope-level post dispatches.
2026-07-18 06:43:27 +01:00
Shakker 3fd448c559 fix: keep browser asset build package-local 2026-07-18 06:42:27 +01:00
Shakker 643476f24d fix: derive generated asset watch exclusions 2026-07-18 06:42:27 +01:00
Shakker b118e9e913 fix: preserve generated asset mtimes 2026-07-18 06:42:27 +01:00
Peter Lee 893196483d fix(anthropic): add Fable 5 to Claude CLI catalog (#101453)
* fix(anthropic): add claude-fable-5 to CLI allowlist, aliases, labels, and context window

CLI path was missing claude-fable-5 across all four metadata layers while
the direct Anthropic provider path in register.runtime.ts already had full
support via isAnthropicFable5Model() / resolveAnthropicFixedContextWindow().

- CLAUDE_CLI_DEFAULT_ALLOWLIST_REFS: add claude-cli/claude-fable-5
- CLAUDE_CLI_MODEL_ALIASES: add fable/fable-5/claude-fable-5 mappings
- CLAUDE_CLI_CONTEXT_WINDOWS: add claude-fable-5 -> 1_000_000 (was falling back to 200K)
- CLAUDE_CLI_MODEL_LABELS: add Claude Fable 5 (Claude CLI)
- resolveClaudeCliImageMediaInput: add fable-5 to 2576 max-side tier

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(anthropic): route fable alias through context/model-ref canonicalization paths

* fix(agent): include claude-cli in fable-5/mythos-5 fixed context window resolution

* fix(anthropic): add claude-fable-5 to static CLI manifest catalog

* test(anthropic): cover fable-5 alias canonicalization in bare and provider-qualified forms

* style(anthropic): fix indentation in plugin manifest

* fix(anthropic): publish Fable CLI output limit

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 22:36:45 -07:00
Peter Steinberger 3e74534a70 fix(channels): keep healthy accounts running when credential files fail (#110360)
* fix(channels): isolate unavailable credential files

* fix(channels): complete credential file type contract

* fix(channels): preserve credential path handling

* test(channels): cover credential file edge cases

* fix(channels): ignore blank credential file paths

* test(secrets): keep empty credential files unavailable

* test(googlechat): keep temp cleanup plugin-local

* fix(channels): keep credential diagnostic internal

* chore: defer release note to release automation
2026-07-18 06:27:59 +01:00
Peter Steinberger 3997a996d4 fix(codex): bound app-server resume history (#110396)
* fix(codex): harden app-server resume protocol

* chore(codex): defer release note to release process

* fix(codex): align bounded resume checks
2026-07-18 06:25:17 +01:00
Peter Steinberger 1855f35d7d fix(whatsapp): preserve inbound messages across restarts (#110418)
* refactor(whatsapp): replay durable inbound through the shared drain

Accept-before-processing stays; the private startup replay loop and inline
complete/release bookkeeping move to the core drain. Drain-owned entries keep
their durable id so downstream failures release for replay, dedupe-claim
contention stays retryable instead of tombstoning, and undeliverable claims
still send configured read receipts. Rows tombstone at dispatch return
(pre-migration timing), not at adoption (#108656).

* fix(whatsapp): finish durable ingress drain adoption with serialized conversation lanes

Core durable ingress intentionally serializes claims by remote JID. Same-conversation bursts now merge as queued followups in the core reply lane after adoption; channel debouncing remains for control and retry paths, with merged fan-out and gated settlement.

Built on the durable drain branch base by @obviyus.

* fix(whatsapp): fail closed on persistence failure and guard prepared-inbound races

Landing autoreview caught two holes: the persistence-failure fallback
dispatched live, bypassing drain dedupe and lane serialization now that the
replay guard is deleted (duplicate replies / session races); and duplicate
pending rows could orphan or clobber preparedInboundByDurableId entries. The
append now retries transient failures with short backoff then drops loudly
(fail closed — the fallback traded a correctness race for availability
against an already-broken store); redeliveries neither clobber the first
delivery's in-flight preparation nor keep orphan entries. The old
fallback-contract test is repurposed to prove retry-then-durable-delivery.

* fix(whatsapp): dispose the durable drain when the close drain times out

The close timeout abandoned the graceful drain path before its finally could
dispose, so a successor monitor could pump the same account queue against a
still-live drain. The timeout wrapper now owns disposal; dispose is
idempotent so the graceful path's cleanup is unaffected.

* style(whatsapp): keep ingress internals unexported and drop a dead harness helper

* refactor(whatsapp): move durable payload serialization to its own module

The dead-export gate refused serializer/error exports whose only external
consumers were tests. The payload contract (Long-timestamp-preserving
serialize/deserialize + the permanent-error class) now lives in
durable-payload.ts with durable-receive as its production consumer; the dead
WhatsAppRetryableInboundError class is deleted (any non-permanent error is
retryable to the drain classifier, so test-support throws a plain Error).

* fix(whatsapp): guard prepared-map ownership and bound its growth

A duplicate pending delivery's finishPreparation deleted the first
delivery's kept entry (ownership guard now requires the deleter to be the
installer), and queue pruning could evict pending rows whose prepared-map
entries then lingered forever on a blocked lane (map now evicts oldest-first
at a bound above the queue's pending cap; dispatch already re-normalizes the
journaled payload when its entry is gone). Regression covers the duplicate
case.

* style(whatsapp): prune split leftovers and satisfy consistent-return lint

* style(whatsapp): satisfy type-aware lint across the drain monitor

Closed verdict shape for the retry result (queue enqueue's metadata generic
leaks any into the union), Promise.resolve-wrapped abandonment aggregators,
braced timeout executor, and the drain merged to a single const (lazy
closures above only run post-start, so const-after-use is TDZ-safe).

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-07-18 06:14:33 +01:00
Peter Steinberger bee40b9e8e fix(messaging): align lifecycle follow-ups (#110413) 2026-07-18 06:14:24 +01:00
xingzhou 40e7447546 fix(imessage): clear stop timeout after child closes (#108909)
* fix(imessage): clear stop timeout after child closes

* test(imessage): preserve timer spy types

* test(imessage): preserve writable end return contract

* docs(imessage): explain stop timer cleanup

Co-authored-by: zhang-guiping <zhang.guiping@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 05:53:33 +01:00
Peter Steinberger b2ea69c9f5 fix(imessage): prevent missed messages after gateway crashes (#110409)
* fix(imessage): adopt durable ingress drain with cursor advanced after append

The chat.db watcher advanced its ROWID cursor after yielding rows to an
in-memory pipeline; a crash between read and dispatch skipped those messages
forever. Raw rows now journal durably (event_id = message GUID, lane per
chat) at the monitor chokepoint, and the cursor advances only after the
durable append — mirroring Telegram's offset-after-spool contract. Dispatch
runs through the core drain with deferred claims, merged fan-out adoption,
and gated settlement; legacy catchup enters the same raw path. The
transitional GUID replay guard is deleted per the layering contract with
4h/10k tombstone parity; the permanent age fence and recovery caps are
untouched. Twin verdict: tapbacks are distinct rows with their own
ROWID/GUID; fresh-GUID stale backlog remains age-fence territory (upstream
imsg source cited in PR).

Autoreview blocked by codex sandbox network in the build stage; full manual
review performed. Part of the #109657 fleet adoption program (wave 2).

* fix(imessage): exempt operator-requested catchup rows from the live age fence

Landing review caught real message loss: legacy catchup accepts rows up to
its configured maxAge (120min default), but the unified durable path ran them
through the 15-minute live Push-flush fence — suppressing AND tombstoning
any catchup row older than 15 minutes, permanently losing history the
operator explicitly asked to replay. Catchup rows now carry provenance
through the journal payload and skip the live fence; the catchup query's own
maxAge window is their age gate. Regression test proves provenance survives
the durable round trip.

* test(imessage): resolve ingress rebase mocks

* docs(imessage): document the fence-suppression vs catchup overlap tradeoff

* fix(imessage): satisfy durable ingress lint gates
2026-07-18 05:51:29 +01:00
Peter Steinberger 4e0cc187a2 fix(msteams): preserve inbound activities before webhook ack (#110357)
* fix(msteams): adopt durable ingress drain with ack gated on activity append

Bot Framework webhooks acked before detached processing with no platform
retry, silently losing inbound activities on a crash. Dispatchable activities
(message + adaptiveCard/action invokes) now persist their raw JSON durably
(event_id = activity.id per the @microsoft/teams.api uniqueness contract,
lane = conversation.id) before the webhook 200; dispatch runs through the
core drain with deferred claims through debounce, merged-flush fan-out
adoption, gated-turn settlement, retry/dead-letter classification, and
30d/20k tombstones. Restart replay reconstructs proactive routing context.
No inbound replay guard existed; the outbound echo cache is untouched. Twin
check: messageUpdate/votes/consent/reactions run dedicated non-agent
workflows and are excluded from the journal.

Autoreview blocked by codex sandbox network in the build stage; full manual
review performed. Part of the #109657 fleet adoption program (wave 2).

* fix(msteams): close live-context races and double next() in drain dispatch

Three defects found in landing review: the live turn context could swap a
duplicate delivery's mutated activity in place of the journaled payload
(dispatch now always uses the journaled activity, live context is transport
surface only); the context registry installed entries after the durable
append, leaking them when the drain consumed the claim first (install now
precedes enqueue, tombstoned duplicates clean up, first delivery's context
wins); and a failed next() in the message handler was invoked a second time
from the catch fall-through (ran-flag guards it).

* fix(msteams): uninstall a failed append's live context before retry

Follow-up to the install-before-enqueue race fix: an enqueue rejection
bypassed cleanup, so a retry with the same activity id dispatched the failed
request's stale context. Uninstall is identity-guarded (only our context is
removed, never a concurrent redelivery's fresh install) and covers both the
throw and tombstoned-duplicate paths. Regression proves the retry's own
context dispatches.

* test(msteams): track the buffered dispatcher seam after main retired the settled variant

* test(msteams): resolve dispatch union before catch for promise lint

* test(msteams): explicit promise-returning mock for the promise-misuse lint

* test(msteams): type the ingress accept mock promise-returning

ReturnType<typeof vi.fn> types the implementation callback void-returning, so
every promise-returning accept mock tripped typescript(no-misused-promises)
in CI regardless of call-site shape.

* test(msteams): restore compact async mock now that its type permits promises

* test(msteams): extract gated-accept helper to stay under max-lines
2026-07-18 05:33:55 +01:00
xingzhou c6abd2e4d4 fix(elevenlabs): stop oversized streaming TTS audio (#109621)
* fix(elevenlabs): cap streamed TTS audio size

* fix(elevenlabs): avoid stream cap cancellation race

* fix(elevenlabs): release bounded stream reader locks

* fix(elevenlabs): release stream resources on early cleanup

* fix(elevenlabs): satisfy typed stream cleanup lint
2026-07-18 05:15:08 +01:00
Peter Steinberger 3659c85e53 fix(codex): distinguish available usage after limit errors (#110381) 2026-07-18 04:42:08 +01:00
Peter Steinberger 28c2f4c075 fix(codex): retire shared app-server client only when unclaimed (#110227) 2026-07-18 04:33:13 +01:00
Peter Steinberger 1aa0d73823 refactor(feishu): use shared cache pruning helper (#110326) 2026-07-18 04:26:26 +01:00
Peter Steinberger 258d83b989 fix(feishu): update lifecycle test runtime (#110361) 2026-07-18 04:19:36 +01:00
Peter Steinberger 31ed59bdf6 feat: keep main agents aware of group activity (#110332)
* feat(sessions): auto-watch group activity from main

* feat(sessions): allow watchers to read watched sessions

* fix(sessions): skip group watches for system turns

* fix(sessions): preserve watched session semantics

* fix(channels): propagate effective dm scope

* fix(sessions): canonicalize main watch identity

* fix(sessions): distinguish ambient group watches

* fix(sessions): revoke ineligible ambient watches

* chore: drop CHANGELOG edit (release generation owns it)
2026-07-18 04:06:58 +01:00
Peter Steinberger 0a5c2d127f test(qa): acknowledge kitchen sink plugin trust (#110335) 2026-07-18 03:47:43 +01:00
Peter Steinberger bd8c5399d8 fix: restore iMessage and WhatsApp channel test coverage (#110327)
* test(imessage): mock core turn dispatch for media policy coverage

PR #110095 missed this iMessage media-policy test file.

* test(imessage): mock core turn dispatch for last-route coverage

* test(whatsapp): mock core turn dispatch for broadcast coverage

* test(imessage): drop type-dead terminal-admission branch in media harness
2026-07-18 03:44:10 +01:00
Peter Steinberger 60ed910639 fix(diagnostics): own run activity listener lifecycle (#110312) 2026-07-18 03:29:06 +01:00
Peter Steinberger 53b53f1977 improve(agents): exact web_fetch output contract with cleaned result shape (#110223)
* feat: add web fetch output contract

* fix(agents): keep web_fetch contract schema module-local

* docs: refresh docs map for the web_fetch result section
2026-07-18 03:28:29 +01:00
Peter Steinberger d8f2645c2c refactor(memory-wiki): move compiled cache to plugin state (#110167)
* feat(plugin-sdk): prepare memory prompts asynchronously

* refactor(memory-wiki): move compiled cache to plugin state

* fix(plugin-sdk): export memory prompt preparer type

* refactor(plugin-sdk): keep prompt preparer type private

* test(memory-wiki): isolate compiled cache state

* chore(memory-wiki): satisfy changed gates

* fix(memory): preserve prepared prompts across context engines

* docs(plugin-sdk): refresh API baseline

* fix(memory): revalidate prepared prompt ownership

* fix(codex): propagate sandboxed memory context

* test(memory-wiki): seed durable vault identity

* refactor(memory-wiki): keep cache lifecycle internal

* fix(memory-wiki): harden compiled cache publication

* style(memory-wiki): format cache lifecycle changes

* test(memory-wiki): support extension test lib target

* style(memory-wiki): remove redundant catch

* refactor(memory-wiki): keep vault generation helper private
2026-07-18 03:05:03 +01:00
morluto cf63c83bf6 fix(qa-lab): close transport before gateway teardown (#106027)
* fix(qa-lab): close transport before gateway teardown

* test(qa-lab): bind teardown order to production plan

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 02:34:11 +01:00
ZOOWH 1c331b9b0f fix(clawrouter): sanitize attribution headers to ByteString (#106454)
* fix(clawrouter): sanitize bounded header ids

Co-authored-by: ZOOWH <xu.wenhan1@xydigit.com>

* fix(clawrouter): keep sanitized ids collision-resistant

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 02:12:53 +01:00
Leon-SK668 dcd8f962e3 fix(qqbot): add timeouts to API response reads (#103855)
* fix(qqbot): add timeouts to API response reads

* fix(qqbot): use guarded request deadlines

---------

Co-authored-by: Alix-007 <li.long15@xydigit.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 02:06:09 +01:00
Wynne668 bcc44ba1b1 fix(whatsapp): resolve abortPromise when stop signal already fired (#109903)
* fix(whatsapp): resolve abortPromise when stop signal already fired

waitForClose() races on abortPromise, but a pre-aborted gateway stop
signal never settled that promise because the abort listener was skipped.
Resolve abortPromise immediately when abortSignal.aborted is already true.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(whatsapp): resolve tsgo TS18048 and test mock in pre-aborted abortPromise fix

- Extract params.abortSignal to local const so tsgo can narrow the type
  through else-if control flow, fixing TS18048: possibly undefined
- Remove setupAbortController/ownerAcquireAbortController.abort() from
  the constructor's pre-aborted branch so openConnection() still works
  when the stop signal was already fired at construction time
- Use createSocketWithTransportEmitter() mock in the new test so
  shutdown() cleanup has sock.end() and ws.removeListener() available

* fix(whatsapp): preserve pre-aborted setup cancellation

* fix(whatsapp): unify connection abort handling

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 02:04:59 +01:00
Peter Steinberger 6f0f6af62e fix(discord): preserve gateway messages across dispatch crashes (#110274)
* fix(discord): adopt durable ingress drain for gateway messages

Gateway MESSAGE_CREATE events dispatched with only an in-memory/persistent
5-minute dedupe; a crash between receive and dispatch lost the message (live
sessions replay via RESUME, but session state is memory-only so a cold
restart re-IDENTIFYs — stated platform limitation: the drain closes the
receive->dispatch window, not cold downtime). Raw API messages now journal
durably (event_id = message snowflake, lane per channel/thread) before
normalization; dispatch runs through the core drain with deferred claims,
fan-out adoption, gated settlement, and 30d/5k tombstones. The persistent
guard is deleted after its RESUME duplicate-delivery parity test. Edits stay
outside the queue: only MessageCreateListener is registered, MESSAGE_UPDATE
never dispatches, so snowflake tombstones cannot swallow edit turns; a future
edit dispatcher must namespace its event ids.

Autoreview blocked by codex sandbox network in the build stage; full manual
review performed. Part of the #109657 fleet adoption program (wave 2).

* style(discord): keep drain-internal types and dispatcher unexported

* refactor(discord): move message dispatcher to its own module for the dead-export gate

* fix(discord): shutdown dispatch releases claims instead of tombstoning

Landing autoreview reproduced a real loss race: a dispatch entering after
dispatcher shutdown (or with an aborted signal) returned completed, so the
drain tombstoned a message that never ran and a restarted gateway skipped it
forever. Aborted-before-dispatch now returns failed-retryable so the claim
releases for replay. Test type imports of drain-internal types converted to
factory-derived types so the dead-export gate and typecheck agree.
2026-07-18 01:58:19 +01:00
Masato Hoshino cc0a977dd5 fix(memory-wiki): prevent source ingest content loss during concurrent vault writes (#104209)
* fix(memory-wiki): serialize source ingest with vault mutations

* test(memory-wiki): make ingest lock proof deterministic

* test(memory-wiki): type queue spy receiver

* test(memory-wiki): keep queue spy lint-safe

* style(memory-wiki): format ingest lock proof

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 01:47:01 +01:00
wangmiao0668000666 dc0285366e fix(msteams): bound probe token acquisition to request deadline (#106386)
* fix(msteams): bound probe token acquisition to request deadline

probeMSTeams() at extensions/msteams/src/probe.ts:75 and :89 awaited
tokenProvider.getAccessToken(...) for the Bot Framework and Microsoft
Graph token endpoints with no surrounding deadline. The Microsoft
Teams SDK does not carry an inherent timeout on these calls, so a
stalled Azure AD token endpoint pinned the probe indefinitely.

Wrap both awaits with withMSTeamsRequestDeadline (default
MSTEAMS_REQUEST_TIMEOUT_MS = 30_000), matching the pattern already
used by six other MS Teams call sites: attachments/bot-framework.ts:252,
attachments/graph.ts:258, monitor-handler/message-handler.ts:594/654/685/692,
attachments/download.ts:167, team-identity.ts:37.

The probe was the one missing site. No new helper, no SDK change.
The existing outer catch at probe.ts:138 and inner catch at probe.ts:110
convert the timeout into a ProbeMSTeamsResult with ok: false and a
structured error field.

Added probe.timeout.test.ts: real probeMSTeams() with vi.mock
injected never-resolving getBotToken/getGraphToken; asserts the call
returns within the 30s bound instead of hanging to the proof budget.

* test(msteams): drive probe timeout test with vi.useFakeTimers

The original probe.timeout.test.ts waited 90 seconds of wall-clock per
focused run (3 stalled cases racing against a real setTimeout budget).
Per ClawSweeper P2 (automation), this material deterministic CI cost can
slow or time out test shards.

Drive the withTimeout race (from @openclaw/fs-safe/dist/timing.js, uses
setTimeout + clearTimeout) via vi.useFakeTimers() so each stalled case
resolves in milliseconds. Add one new case that spies on withTimeout's
timeoutMs argument to assert the production default deadline is exactly
MSTEAMS_REQUEST_TIMEOUT_MS = 30_000, so the production contract is not
silently weakened by the fake-timer change.

Per-case wall-clock: 25ms / 3ms / 2ms / 1ms / 2ms (was: 30s / 30s / 30s /
2ms / n/a).

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

* fix(msteams): bound remaining token acquisition

* test(msteams): keep credential fixture unchanged

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 01:21:49 +01:00
Peter Steinberger 13c0e7492a fix(test): converge Slack harness state across module reloads (#110255)
* fix(test): converge Slack harness state across module reloads

Five reaction tests in monitor.tool-result.test.ts failed whenever a sibling
file's vi.resetModules() ran earlier in the same non-isolated worker: the
cached globalThis __slackClient kept routing reactions to the OLD test-helpers
module's mocks while tests asserted on the recreated module's fresh mocks —
reactions 'never fired' (replies survived via freshly injected runtime).
slackTestState is now a globalThis-backed singleton so every module
incarnation and the cached client share one state object. Also: reaction
assertions wait on the mock (reactions apply via detached debounce/queue
work), and stale Bolt handler registrations clear per test/stop so
waitForSlackEvent cannot match a previous provider's handler. Proven with six
consecutive full extensions/slack runs (was ~50% failure).

* style(slack): bracket global test-state access for underscore lint
2026-07-18 01:17:11 +01:00
Peter Steinberger ec8f6e5e03 feat(browser): add secure per-tab copilot panel (#109817)
* feat(browser): add copilot security contracts

* fix(gateway): expose verified client identity to handlers

* feat(browser): add secure per-tab copilot panel

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* refactor(browser): separate copilot gateway hint custody

* fix(browser): preserve legacy pairing parse shape

* fix(browser): harden copilot lifecycle custody

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): enforce copilot lifecycle boundaries

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* style(browser): format copilot sources

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): preserve copilot consent revocation

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* refactor(browser): split copilot custody owners

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(browser): normalize websocket array buffers

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* chore(protocol): regenerate Swift gateway models

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* refactor(browser): model copilot runtime entrypoints

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): honor extension build boundaries

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(gateway): assert targeted chat delivery

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(gateway): cover targeted delivery calls

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): declare copilot build dependencies

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(ci): clear browser copilot gate failures

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(ci): cover copilot lint exclusion

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): gate copilot on relay custody

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(browser): bound copilot relay frames

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

---------

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>
2026-07-18 01:00:23 +01:00
Peter Steinberger 601ffa2530 refactor(channels): move inbound turn execution into core (#110095)
* refactor(channels): centralize turn execution lifecycle

* refactor(extensions): adopt core channel turn plans

* test(channels): ratchet modern dispatch ownership

* chore(channels): drop stale max-lines exemption

* fix(channels): allow async delivery error cleanup

* test(channels): await async delivery cleanup

* test(channels): await delivery error callbacks

* fix(channels): preserve delivery error contract

* fix(plugin-sdk): preserve channel inbound declarations

* test(channels): exercise core delivery plans

* fix(channels): await delivery error cleanup

* fix(channels): preserve async cleanup contract

* refactor(channels): trim dispatch boilerplate

* fix(channels): mask observe-only dispatch results

* refactor(channels): delete unused dispatch exports

* fix(msteams): preserve resolver config overrides

* refactor(channels): keep Teams turn config internal

* test(plugins): drop retired Teams runtime export guard
2026-07-18 00:55:46 +01:00
mikasa ac6fa704e8 fix(imessage): bound drop diagnostic dedupe (#103512)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 00:53:35 +01:00
Dallin Romney 14caaf3d4c fix: make live harness planning QA fail closed (#109282)
* test(qa): prove live harness planning signals

* test(qa): satisfy scenario static checks

* test(qa): scope planning evidence per attempt

* test(qa): derive planning scenarios from coverage
2026-07-17 16:45:57 -07:00
Dallin Romney 82fa956d5a fix(qa): resolve profile channels through selected driver (#109350)
* fix(qa): keep generic profiles off channel-specific lanes

* fix(qa): resolve profile channels through selected driver
2026-07-17 16:42:18 -07:00
lzw112 61a74e780a fix(perplexity): send Search API date filters with official field names (#107046)
* fix(perplexity): send Search API date filters with official field names

* test(perplexity): cover date filter request body

* test(perplexity): simplify request capture

* style(perplexity): format request test

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 00:36:08 +01:00
Vito Cappello f4607b802f fix(llama-cpp): preserve runtime asset paths (#110233)
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
2026-07-17 16:36:05 -07:00
mushuiyu886 b42dc72851 fix(discord): Activity OAuth no longer holds failed Discord connections (#109869)
* fix(discord): avoid Activity OAuth stalls after API rejection

* test(discord): preserve status on cancel failure

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 00:24:40 +01:00
mikasa d03b015ff4 fix(feishu): bound sender name cache (#103513) 2026-07-18 00:11:51 +01:00
qingminlong 0f192e79d4 fix(parallel): reject invalid search counts (#105108)
* fix(parallel): reject invalid search counts

* fix(parallel): share strict count validation

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 00:11:45 +01:00
Dallin Romney a9dc393f7e test(qa): prove Codex auth product migration (#109291) 2026-07-17 16:10:23 -07:00
chengzhichao-xydt 40acbb05c9 fix(discord): honor caller abortSignal during 429 retry backoff (#109913)
* fix(discord): honor caller abortSignal during 429 retry backoff

* test(discord): prove 429 backoff abort through a real loopback server

* test(discord): make retry abort proof deterministic

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 00:09:43 +01:00
Peter Steinberger 781913025b improve: stream native sessions as hosts finish (#110211)
* perf: stream native session catalogs by host

* fix: satisfy session catalog CI contracts

* fix: retain changed-session refresh timing

* fix: keep catalog refresh helpers private
2026-07-17 23:59:57 +01:00