Commit Graph

16608 Commits

Author SHA1 Message Date
mushuiyu886 42e6972d35 fix(opencode): Zen GPT-5.6 models are missing from discovery (#110405)
* fix(opencode): add Zen GPT-5.6 models

* test(opencode): narrow GPT-5.6 policy fixture

* fix(opencode): align GPT-5.6 thinking levels

Co-authored-by: 杨浩宇0668001029 <yang.haoyu@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 11:14:05 +01:00
Peter Steinberger e7fe47d63f fix(browser): allow one retry after transient failures (#110607)
* fix(browser): soften transient retry guidance

* style(browser): format retry hint test

* chore: keep release note in PR body
2026-07-18 10:58:22 +01:00
Peter Steinberger a068d38b66 refactor(plugins)!: remove experimental workspaces plugin (#110416)
* refactor(plugins)!: remove experimental workspaces plugin

* fix(doctor): remove retired workspaces plugin state

* refactor(doctor): settle retired-workspaces cleanup before legacy-state detect

* chore(i18n): leave workflow-owned locale artifacts to the locale refresh

* ci: retrigger after GitHub scheduling outage
2026-07-18 10:56:37 +01:00
Peter Steinberger f14947d256 fix(codex): persist automatic compaction history (#110587)
* fix(codex): persist automatic compaction counts

* test(codex): stress compaction and restart recovery

* test(codex): bind compaction waves to fresh counts

* chore: keep Codex release note in PR
2026-07-18 10:37:25 +01:00
xingzhou 91ded68990 fix(vault): SecretRef resolution no longer hangs on stalled response bodies (#108970)
* fix(vault): keep request deadline through response body

* test(vault): use generic stalled-body fixture

* test(vault): mark fixture token synthetic

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 09:46:50 +01:00
Alix-007 bc77ef3398 fix(browser): time out relay WebSocket opening (#109114)
* fix(browser): time out relay WebSocket opening

* test(browser): resolve worker import at runtime

* test(browser): refresh relay worker mocks

Co-authored-by: Alix-007 <li.long15@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-18 09:36:46 +01:00
Alix-007 cc7bd4d95a fix(qa-lab): bound Node binary lookup (#109428) 2026-07-18 09:35:16 +01:00
Alix-007 78b4a4afed fix(qa-lab): bound WhatsApp auth archive extraction (#109501) 2026-07-18 09:33:38 +01:00
Chris Eckert 42be965eac improve(mattermost): restart only the changed account on config reload (#99312)
* improve(gateway): restart only the changed account on channel config reload

When a config change is scoped entirely to one channel account
(channels.{kind}.accounts.{accountId}[.*]), restart just that account
instead of the whole channel. Wholesale channel restarts disconnect every
account on the channel; on gateways running many accounts, each
account-scoped config write (adding an account, changing one account's
settings) briefly dropped every other account's connection.

The reload plan gains a restartChannelAccounts bucket populated only when
all of a channel's changed paths are account-scoped; any channel-global
path falls back to the existing wholesale restart, and a channel scheduled
for wholesale restart drops its per-account entries so each (channel,
account) pair restarts at most once. The executor runs per-account
restarts through the existing stopChannel/startChannel accountId parameter.

* fix(gateway): preserve account reload admission

* fix(gateway): scope surgical reloads to isolated plugins

* test(gateway): avoid preactivating reload snapshot

* docs(channels): define account reload isolation contract

* fix(gateway): preflight scoped account reloads

* fix(gateway): re-drain live scoped reload targets

* docs: refresh generated docs map

* fix(mattermost): align scoped reload with durable ingress

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 09:33:06 +01:00
Peter Lee 9a7d615dfc fix(agents): use fetchWithSsrFGuard in minimax-vlm.ts instead of raw fetch (#106163)
* fix(agents): use fetchWithSsrFGuard in minimax-vlm.ts instead of raw fetch

Replace raw fetch() with fetchWithSsrFGuard + withTrustedEnvProxyGuardedFetchMode
in minimaxUnderstandImage, aligning with all other agent network transport
paths (provider-transport-fetch, mcp-http-fetch, web-guarded-fetch, tools-manager).

This adds SSRF protection, redirect safety, debug capture, and proper
dispatcher lifecycle management. The ensureGlobalUndiciEnvProxyDispatcher
call is removed since guarded fetch handles proxy routing in trusted env-proxy
mode.

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

* fix(agents): preserve configured MiniMax origins in guarded-fetch migration

* fix(agents): resolve lint and type-suppression regressions in MiniMax VLM guarded-fetch tests

Replace as-any casts in vi.mock vi.importActual calls with generic type
parameters, and replace the opts:any parameter in the fetch-guard bridge
with an inline type. Add SSRF policy assertions covering default hosts,
custom public hosts, and explicitly-authorized loopback origins.

* fix(minimax-vlm): thread allowPrivateNetwork into guarded-fetch policy

Honor the explicit provider request private-network opt-out in the MiniMax
VLM guarded-fetch path. When an operator sets
models.providers.<id>.request.allowPrivateNetwork: false, skip the origin
exception for non-default hosts so the explicit denial is authoritative.

Also fix an invalid Vitest fn generic (two-parameter form -> function
signature) that caused check-test-types to fail.

* fix(agents): use canonical provider SSRF policy for MiniMax VLM

* fix(media): harden MiniMax VLM transport

Co-authored-by: Peter Lee <li.xialong@xydigit.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-18 09:29:24 +01:00
xingzhou 34440523cd fix(voice-call): ngrok tunnels no longer survive cleanup (#110122)
* fix(voice-call): ngrok tunnels no longer survive cleanup

* fix(voice-call): document bounded ngrok shutdown

* fix(voice-call): reap ngrok after startup timeout

* fix(voice-call): type ngrok process with ignored stdin

* fix(voice-call): compose ngrok timeout lifecycle
2026-07-18 09:09:29 +01:00
Peter Steinberger fcdf3954d7 fix(meetings): wait for audio bridge cleanup (#110548)
* fix(meetings): wait for audio bridge cleanup

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

* test(meetings): skip POSIX signal proof on Windows

---------

Co-authored-by: zhang-guiping <zhang.guiping@xydigit.com>
2026-07-18 09:00:19 +01:00
Peter Steinberger 307353dd1c fix(qa): complete gateway-less transport cleanup 2026-07-18 08:56:13 +01:00
Peter Steinberger 18a49b3a78 refactor(discord): authorize widgets by channel audience (#110522)
* refactor(discord): authorize widgets by channel audience

* docs: refresh Discord Activity map
2026-07-18 08:42:40 +01:00
Peter Steinberger d7de67ae02 feat: ask_user follow-ups — harness convergence, channel finalization + reactions, native cards, docked web panel (#110372)
* feat(ask-user): follow-up harness slice

* feat(ask-user): follow-up channels slice

* feat(ask-user): follow-up native slice

* feat(ui): dock question panel above composer with stepper and compact stream summaries

* docs: refresh follow-up integration maps

* test(ui): align terminal summary proof

* fix(infra): echo declared option answers in terminal status when free-text is allowed

* fix(infra): keep reaction answering when display labels are formatter-adjusted

* fix(agents): settle plain-text claims only after question registration commits

* fix(agents,apps): commit-ordered claim persistence, claim-aware prompt delivery, non-blocking question refresh

* fix(harness,infra): reaction-appropriate question copy, caller presentations honored

* fix(native,infra,agents): local-expiry eviction, value-addressed reactions, reserve-before-request

* fix(infra,android): dual-mode question resolver for compact callbacks; reset terminal retention on replayed pending

* fix(harness,discord): claim-aware prompt delivery in run helper; escape finalization labels

* fix(macos): merge transient-content visibility with question cards after main sync

* fix: repair ask user follow-up CI

* test: update limited bootstrap scope expectation

* fix: retain shared question card API

* chore: refresh native i18n inventory
2026-07-18 03:32:39 -04:00
Peter Steinberger 1ebfa066a5 fix(synology-chat): bound outgoing response deadlines (#110520)
Co-authored-by: Pick-cat <huang.ting3@xydigit.com>
2026-07-18 08:32:25 +01:00
Peter Steinberger a676afd54d fix(qa): release transport leases after gateway stop 2026-07-18 08:23:34 +01:00
Dave Morin 4b3ee5e7eb feat: let agents remember across private conversations (#100140)
* feat(memory): remember across private conversations

Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>

* chore(docs): regenerate config baseline

* fix(memory): restore recall configuration wiring

* fix(memory): scope recall transcript indexing

* test(memory): repair conversation recall fixtures

* test(memory): split session visibility coverage

* style(memory): format type imports

---------

Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 08:21:43 +01:00
mushuiyu886 bfc94ad3c5 fix(nostr): accept uppercase Bech32 keys in setup and DM targeting (#109878)
* fix(nostr): accept uppercase NSEC and NPUB inputs

* test(nostr): satisfy target resolver type check
2026-07-18 08:13:11 +01:00
Peter Steinberger 1f160696dc fix(vydra): preserve errors for broken response bodies (#110478)
Co-authored-by: Pick-cat <huang.ting3@xydigit.com>
2026-07-18 07:59:17 +01:00
mushuiyu886 ac75f0c17a fix(nostr): relay connection failures no longer report successful publishes (#110007)
* fix(nostr): fail over relay connection errors

* fix(nostr): preserve pool publish semantics
2026-07-18 07:53:55 +01:00
Peter Steinberger b116ae5a43 fix: stop mock Control UI QA from hanging in live suites (#110481)
* fix(qa): keep transcript boundary scenario mock-only

* fix(qa): filter scenario-pinned provider lanes

* test(qa): narrow transcript scenario execution type
2026-07-18 07:51:58 +01:00
pick-cat f7cc0ef838 fix(synology-chat): bound user_list fetches with a wall-clock deadline (#109111)
* fix(synology-chat): bound user_list fetches with a wall-clock deadline

* refactor(synology-chat): keep deadline internal

* style(synology-chat): format deadline proof

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 07:51:12 +01:00
Chris Eckert 1d5bf19df4 improve(diagnostics): surface run startup phases as session-correlated events (#107984)
* improve(diagnostics): surface run startup phases as session-correlated events

The embedded runner reports ordered startup milestones (workspace, auth,
context_engine, ..., model_call_started) through the private
onExecutionPhase callback, so they reach typing indicators and cron
watchdogs but never the diagnostic bus. External status surfaces that
already consume run.attempt / run.progress / model.call.* cannot see
where a turn is during startup — exactly the window that matters when a
run hangs before its first model call.

Wrap params.onExecutionPhase once at the runner entry so every phase
transition also emits a session-correlated run.execution_phase event
(runId, sessionId, sessionKey, closed EmbeddedAgentExecutionPhase +
provider/model/tool context). The event rides the async diagnostic lane
like the other high-frequency lifecycle events, so ordering against
model.call.* is preserved and no subscriber work runs on the hot path.
The wrapper tracks session rotation via onSessionIdChanged so
post-compaction phases carry the current session id. Stability records
project the milestone into their dedicated phase/provider/model fields.

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

* fix(diagnostics): preserve trusted phase observability

* chore(plugin-sdk): refresh diagnostic API baseline

* fix(diagnostics): publish execution phases to plugins

* refactor(logging): keep public diagnostic recorder path

* fix(plugin-sdk): keep deprecated budget exact

* fix(plugin-sdk): refresh diagnostic surface budget

* fix(diagnostics): preserve execution phase coverage

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 07:46:26 +01:00
mushuiyu886 a5cef86b5c fix(nostr): reject non-object profile imports (#110330) 2026-07-18 07:45:10 +01:00
mushuiyu886 f76f06b1ae fix(nostr): return relay event ids in send receipts (#110006) 2026-07-18 07:21:56 +01:00
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