The concurrent keyed sessions.create adoption assertion flaked once on CI
(run 31609081812) with the persisted row missing while all 16 creates
succeeded. Owner-path analysis (fenced create path, direct SQL read,
post-commit publication, async tails, sqlite target resolution) found no
reachable mechanism and the failure never reproduced locally (11 runs).
On mismatch the assertion now reports the case dir's sqlite files, the
resolved target path, and raw session_nodes rows so the next occurrence
identifies the writer/reader split instead of printing undefined.
* feat(slack): render live session cards as the default Slack progress mode
Slack streaming.mode default flips partial->progress.
Progress mode renders one live Block Kit session card with a status header, narration, plan, activity, diff stat, and elapsed time; it is edited in place and finalized to success or error with an Open in OpenClaw button when gateway.publicOrigin is set.
Final assistant text always delivers separately.
The shared progress compositor gains a success-only additive per-turn diffStat mirroring the task ledger fold.
resolveGatewayPublicOrigin is exported through the plugin SDK.
The diffs viewer URL falls back to publicOrigin.
The old rich/text progress render fork is deleted.
Native task cards remain unchanged and opt-in.
* chore(config): regenerate bundled channel config metadata
* refactor(slack): keep session card state type internal
* refactor(slack): split session-card and diff-stat owners under lint ceilings
* refactor(channels): reuse diff-stat type from its owner module
Import ChannelProgressDraftDiffStat from progress-draft-diffstat instead of
redeclaring it in the compositor, resolving the all-exports deadcode scan.
* chore(plugin-sdk): regenerate api baselines for channel barrels
Baselines drifted after the rebase reconciled them against main; regenerate to
match the branch's actual channel-message/channel-outbound surface.
* fix(slack): drop a session card that cannot terminalize after final delivery
If the final reply is delivered but the terminal card edit fails, the caller
now clears the stale card instead of leaving it stuck in its Working state
(mirrors the pre-card preview cleanup). Adds a transport-failure regression and
corrects three tests that asserted the prior ignore-the-result behavior.
Documents resolveGatewayPublicOrigin as a dependency-light runtime helper on the
config-contracts SDK subpath, which previously described a type-only surface.
Addresses ClawSweeper P2 (unfinalized card) and P1 (runtime SDK contract).
* fix(slack): suppress default tool messages under the default progress card
resolveChannelStreamingSuppressDefaultToolProgressMessages re-derived the stream
mode from config with an "off" default, unlike its sibling resolvers which take
a caller-resolved mode override. After this branch made progress the Slack
default, a default-config channel turn saw mode "off" and left a stray
"Using tool: X" plain message posting alongside the session card. Thread the
caller-resolved mode through (compositor passes params.mode; Slack dispatch passes
slackStreaming.mode), matching resolveChannelStreamingPreviewToolProgress.
Retarget the progress-session-card delivery-trace golden at an EMPTY Slack config
so it proves the real default path; the regenerated golden is byte-identical,
confirming defaults now yield the clean card sequence (one card post, separate
final text, one terminal update with the Open in OpenClaw button, no stray tool
message). Switch the dispatch delivery-mode mock to the real resolver so the card
tests exercise the true channel default (automatic), not a hand-rolled one.
* chore(plugin-sdk): regenerate api baselines for the streaming mode param
resolveChannelStreamingSuppressDefaultToolProgressMessages gained an optional
mode override; the changed signature reflows the surface hash of every barrel
that re-exports it, so regenerate the affected baselines.
* chore(config): regenerate config baselines
* feat(ui): expand session diff navigation
Release note: Make the session diff scope selectable from its header and let working-tree diffs reveal unchanged file context in bounded chunks.
* fix(ui): keep unchanged-line expander labels inside their row
Chromium's flex layout on button elements pins the label line box to the
button's vertical center, painting the gap count into the diff row above.
Grid centering avoids the quirk; skip rows also center-align their controls.
* fix(ui): revalidate diff snapshot before expanding unchanged lines
Addresses the ClawSweeper P2 stale collapsed-gap content finding by revalidating the target file patch before reading current file text.
* fix(logging): parse diagnostics.stability limit/sinceSeq as strict decimal
normalizeDiagnosticStabilityQuery is the only input boundary of the
diagnostics.stability gateway method (no protocol schema), and its
string branch used Number(): "0x10", "1e3", " 5 ", "+42" were
silently coerced instead of rejected, so malformed clients could
filter snapshots by unintended seq values. String params now require
strict decimal digits, matching the boundary's fail-closed contract.
* fix(logging): reject unsafe integers for numeric stability query inputs
Replace Number.isInteger with parseStrictNonNegativeInteger for the numeric path so MAX_SAFE_INTEGER + 1 (and larger) is rejected uniformly across string and number inputs. Add test cases for MAX_SAFE_INTEGER (accepted) and MAX_SAFE_INTEGER + 1 (rejected) for both limit and sinceSeq.
* fix(logging): use normalization-core parser import
---------
Co-authored-by: Altay <altay@hey.com>
* 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
* refactor(voice): promote realtime voice policy to talk owner
Move the exact-speech protocol (typed consult-call outcome instead of
string scraping), agent-proxy session instructions, and consult/wake-name/
barge-in policy defaults from the Discord plugin into src/talk, exported
additively via openclaw/plugin-sdk/realtime-voice. Wake-name enablement now
keys on a supportsActivationNameGating provider capability instead of a
hardcoded provider id. Follow-up to the voice split (#122479).
* fix(talk): bind exact-speech bypass to retained session state
Per ClawSweeper review on #122668: the protocol marker is untrusted model
tool-call text; only a parsed answer matching a currently retained
exact-speech text may select the privileged replay path. Unretained
marker calls route to a normal consult.
Keep readable native images when another attachment fails resolution.
Suppress only unresolved media facts across persisted and transient runner paths.
Co-authored-by: SunnyShu0925 <shu.zongyu@xydigit.com>
* feat(ai): continue stateful OpenAI SSE turns
Use the prior OpenAI Responses ID for native stateful HTTP/SSE turns, retry missing server state with full history in the same turn, and keep stateless/custom routes unchanged.
Co-authored-by: Markus Hartung <mail@hartmark.se>
* test(ai): assert Responses retry attempt metadata
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Make the process action enum authoritative for model-facing validation and direct executor calls, rejecting malformed actions before session lookup.
Refs #69582.
Punchcard-Session: clear-orchard-timber-c2
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: adone0 <vladyslav.yavorskyi@outlook.com>