* fix: show sessions waiting for concurrency slots
* test: align queued session integration fixtures
* test: distinguish queued and reactivated followups
* fix: preserve queued state in workboard and android
* fix: project queued status through chat history
* test(ui): keep queued sidebar case under line cap
Autonomous self-learning captured junk (transcript fragments, resolved transients, one-off narratives). The experience-review and history-scan prompts now carry an explicit never-capture exclusion list from one shared constant; user-invoked /learn intentionally keeps its own bar, protected by a negative prompt assertion. Operator-notice follow-up: #125723.
Fixes#125710
Keep orphan reconciliation progressing when a preserved checkout has dangling linked-worktree metadata, while leaving snapshot safety checks unchanged.\n\nRefs #125719
* improve(ui): standardize fenced code collapse and wrapping
Every Markdown code fence now shares one behavior instead of the JSON-only
40-line disclosure: blocks longer than seven lines show a seven-line preview
with the exact hidden-line count, horizontal overflow stays inside the fence,
and a reversible wrap control appears only once a line measurably overflows.
User fences keep the bubble's own typography and carry no code chrome.
The collapsible markup is emitted only for hosts that own the code-block
lifecycle (codeBlockInteraction: interactive), and that lifecycle collapsed to
one click owner plus one initializer so a host cannot wire half of it. The chat
thread, detail panel, and caretaker surface all run it; the skills preview gets
the click owner its copy button had never been given. The scan is deferred and
coalesced because a Lit element ref commits before that render's children, and
detached ResizeObserver targets are released before each pass.
Also adds the interaction mode to the markdown cache key so a static host cannot
serve interactive markup from a sibling render, and drops the stylesheet rules
and selector guards the removed json-collapse markup owned.
* fix(ui): satisfy fenced code checks
Reuse the canonical realtime audio duration and OpenAI-compatible wire-format helpers while removing redundant state transitions and truncate payload construction. The production diff is net-negative.
Provider interruption policy and lifecycle ownership stay local to each provider; this does not introduce shared mutable assistant tracking or change behavior.
* feat(ui): show session info in the sidebar hovercard
The sidebar session hovercard now always opens and shows owner, created and updated times, PR chips with CI state and diff stats, plus a branch and changed-files fallback with “No PR yet”. The progress card renders below when present, and the gateway exposes changedFiles on session PR and branch snapshots.
* fix(ui): scope session hovercards to sidebar rows
Keep Markdown session links owned by their dedicated preview hovercard by limiting both lazy registration and runtime activation to sidebar session rows. Add browser coverage that fails when the competing sidebar hovercard steals the link trigger.
* perf(ui): keep session hovercard data out of startup
Reuse the sidebar’s existing session projection from the lazy hovercard runtime instead of publishing a separate startup-loaded registry. This removes the registry lifecycle and its implementation-only tests while keeping the browser ownership regression and restoring the Control UI startup bundle below budget.
Expose per-path removed and failed outcomes for offline agent deletion so scripted callers can detect manual cleanup. Keep unfinished deletion journals retryable until every path reaches a terminal state.
The startup marker now owns the first fresh store discovery and once-per-startup path tracking, while recovery keeps an independent fresh scan; this removes one scan without freezing deleted/restored stores or marking late rows in an existing path.
* feat(gateway): expose command lane diagnostics
* feat(ui): add live debug busyness overlay
* fix(ui): show newest events in debug overlay and update diagnostics call-list tests
* test(ui): add lane and status fixtures to the mocked dashboard
* feat(ui): add System busyness entry to the account menu
* fix(gateway/ui): bound lane diagnostics, append-only descriptor, fail-visible lanes load
Addresses ClawSweeper review findings on #125591: diagnostics.lanes moves to
the append-only tail of the descriptor table, the Control UI lanes request
fails visibly instead of masking errors, and the RPC exports only static
lane snapshots plus a bounded dynamic-session aggregate composed in the new
command-lane-diagnostics module.
* chore(protocol): regenerate Kotlin gateway methods for diagnostics.lanes
* test(gateway/ui): register diagnostics.lanes in the 2026.8 train and mock it in the debug e2e
* feat(ui): add sidebar Online presence section and Activity session feed
Adds a sidebar "Online" section (visible only when at least one other
identity is connected, idle users dimmed) that links into a new
session-feed default view on the existing Activity page: search, time
window, and per-person facets over day-grouped sessions, with a
per-person identity header (devices, viewing-now) when one person is
selected. Removes the dead footer viewer-facepile roster that the
sidebar-zone refactor (#112936) left unmounted.
Client-only; no gateway/protocol changes.
* test(ui): make activity capture date-boundary safe
* fix(ui): stop the model picker from nagging about refresh failures
A failed background catalog refresh rendered a "Couldn't refresh models"
banner plus a Retry button on top of a complete, working model list, and
replaced the composer trigger's model name with that error text. The
picker already keeps the last-known catalog and re-requests it on every
open, so the operator was being asked to press a button for something the
UI does by itself.
The error stays recorded on the host — it is what drops the stale
availability gate so the composer remains usable — but it is no longer
surfaced while there are models to show. Only a genuinely empty catalog
still says "Models unavailable". The new-session picker gains the chat
picker's open-triggers-revalidate behavior so re-opening it is the retry
there too, instead of dead-ending until a page reload.
Two adjacent simplifications in the same surface:
- Model rows reserve their provider-icon slot as an invisible stem, so
names line up with the provider heading label (same 34px stem grouped
and filtered, nothing shifts while typing).
- The "Using agent default" footer is gone: the default row already
carries a DEFAULT badge and the checkmark. Typing "default" in the
picker search now matches the default model instead.
Proof: scripts/capture-model-picker-proof.mts captures the open picker
against a mocked gateway; alignment delta 0px (was -24px), search
"default" matches the default row (was nothing), and a failed models.list
leaves no catalog-state element with all rows intact.
* fix(ci): register the model-picker proof script and await its picker revalidation
The unused-file scan needs every scripts/ entry point referenced, like the
sibling ui:proof:* recipes. The catalog-reconnect assertion also has to wait
for the picker's own metadata request instead of reading the log the moment
the rows render.
* test(ui): split model-catalog scenarios out of the new-session e2e file
The catalog-reconnect file hit the 1000-line cap. Its model-catalog metadata
failure/recovery pair is a separate surface from CLI-agent targets, terminal
start, and draft reconnect, so it moves to its own file rather than earning a
max-lines suppression.
* test(audit): give the pinned-reader contract test a realistic timeout
It adds a pinned-SHA git worktree and cold-compiles the audit and state
modules under tsx, which takes minutes on a contended runner. The 120s
default made it fail by construction; it timed out on an unrelated PR shard
while passing locally at ~55s.
* fix(errors): drop cause text the message already states
Cause-chain dedupe compared whole strings, so a wrapper that embeds its cause
verbatim printed it twice, and an errno detail was followed by its own bare
code. Skip any cause segment already contained in the accumulated message.
* test(backup): stop pinning the duplicated errno suffix
Both debug-view assertions required the bare code to follow the errno detail
that already names it. Assert the detail itself instead, so they pin the
message content rather than the redundancy.
* fix(errors): narrow cause dedupe to wrapper-embedded messages
Suppressing every contained segment also dropped trailing bare codes, which
cron, fs, and backup tests pin deliberately as this formatter's convention.
Restrict containment to cause messages so the wrapper duplication is fixed
without changing the code suffix, and restore the backup assertions.
* fix(auth): preserve WHAM classifications and failure recording
WHAM 401/403 state now drives accurate re-auth guidance, while inline hook failures are contained after persistence so recorded failures cannot escape or be masked.
* docs(plugin-sdk): define auth cooldown classifications
document the additive cooldown diagnostic contract and cover its canonical public-SDK projection.
* fix(auth): keep WHAM diagnostics source-compatible
keep cooldownReason canonical, persist exact WHAM diagnostics in optional cooldownClassification, and preserve operator guidance plus failure-hook containment.
* fix(auth): keep failover on canonical cooldown reasons
ensure optional WHAM diagnostics never drive scheduling and discard mismatched persisted reason/classification pairs.
Preserve operator approval terminal reasons through the harness, map denials and timeouts to Codex decline, and retain visible timeout evidence so the turn can continue instead of being killed.
The Telegram release-QA workflow embeds a SUT launcher that the repository
test suite extracts and syntax-checks with the local bash. Four `[[ -v ... ]]`
probes require Bash 4.2+, so the check failed under stock macOS Bash 3.2.
Replace them with `declare -p` and `${keep_env[$key]+x}`, which parse on
Bash 3.2 and are runtime-equivalent on the Ubuntu runners. Environment
preservation and boundary-mode behavior are unchanged.
Closes#125293
* fix(gateway): stop chat.startup from blocking on workspace icon discovery
chat.startup awaited workspace icon preparation before responding, so a
cold icon cache (up to the full favicon candidate list) delayed the first
chat-open response for every session. It now starts discovery eagerly and
returns without waiting for it.
That leaves the icon route's readiness 503. The route already awaits an
in-flight preparation, so the only way to reach 503 is having no cache
entry at all: an icon GET that beat its chat.startup across transports, or
a session whose snapshot aged out of the bounded cache. Neither is fixed by
the client asking again for the same missing snapshot, so the producer
answers instead. prepareSessionWorkspaceIcon() publishes cache entry and
waiting requests through one publication point, and a request that misses
waits up to two seconds for that publish before falling back to 503. The
race resolves into a 200 on the original request, and 503 now means only
what it says: nothing is preparing this session.
* fix(gateway): keep icon absence out of 503 and bound the publish wait
The publish waiter resolved with the snapshot promise itself, so `resolve`
adopted it and a workspace that publishes `null` reached the route as a falsy
value indistinguishable from an expired wait: the common no-icon race answered
503 instead of the stable 404. Waiters now carry a discriminated publication,
so timeout and published absence stay separate outcomes.
Admission is also bounded. Every authenticated unknown key used to create a
bucket, callback, timer, and held response for the full wait with no cap and no
disconnect cleanup, which accumulates once sidebar project groups render icons
for sessions that may never get a chat.startup. Waits are now capped per
session and per process, a saturated pool answers 503 immediately, and every
exit path releases the timer, the disconnect listener, and the slot together.
* fix(gateway): bound cached workspace icon waits
* fix(gateway): recover delayed workspace icons
* test(ui): assert workspace icon retry fallback
* fix(gateway): bound workspace icon recovery
* fix(gateway): satisfy workspace icon lint
* fix(ui): scope workspace icon recovery
---------
Co-authored-by: ClawSweeper <steipete+clawsweeper@gmail.com>
Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
Keep ambient main-session group notices working when direct messages use an isolated dmScope, while preserving explicit session watches and routed group topology.
Linux signal-zero probes succeed for zombie processes. Reclaim memory promotion and session usage locks only when their exact zombie owner is still current, and route shared test waits through the canonical zombie-aware PID helper.