Remove the third-party notice pointer from LICENSE. The README already links THIRD_PARTY_NOTICES.md, which remains packaged and unchanged. Licensee 9.16.0 changes from NOASSERTION to an exact MIT match. Reported by Ashley Wolf (@ashleywolf).
Repin the bundled runtime to fork release openclaw-v1.4.3-20261002-13311cf83e-webkit-fb1167ebf2. On top of 6a5d9c721f, module.registerHooks load and resolve hooks now receive valid URLs for packages Bun replaces with built-ins (the node_modules file URL where one exists, otherwise bun-builtin:), so hooks that parse the URL, such as tsx, no longer fail. WebKit is unchanged. Values come from the release manifest.
* fix(telegram): require explicit Mini App group owners
* fix(telegram): explain Mini App owner access recovery
* fix(telegram): separate Control UI and session dashboard commands
---------
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
An explicit original capture is part of the admitted repair contract. Propagate verification failures through Doctor maintenance before config or health repair, preserving best-effort discovery for older callers without a reference.
Exercise two valid continuations and four invalid retained-evidence states through the real executor and maintenance owner. Preserve retained bytes, refuse later effects, and join database closure before filesystem inspection.
Related: #144005
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(mxc): probe IsolationSession service for Windows readiness
Current Windows builds replaced the IsoEnvBroker service with the demand-started IsolationSession service, so the readiness check failed with "IsoEnvBroker service is not installed" on hosts that can run MXC. Probe IsolationSession instead and make the test fake host name-aware so probing a retired name fails.
* fix(mxc): send wire-compatible container config to MXC SDK 0.8.0
The plugin passes a raw ContainerConfig to spawnSandboxFromConfig, which forwards it unmapped to wxc-exec. wxc-exec 0.8.0 rejects filesystem.clearPolicyOnExit (an SDK-only alias) and processContainer.name (removed from the wire), so every MXC command failed with a configuration parse error after the 0.7.0 -> 0.8.0 bump.
Clear policy through lifecycle.preservePolicy, drop the removed name, and cap containerId at 64 characters because MXC now uses it as the AppContainer profile name. Add a Windows integration test that runs the pinned wxc-exec --dry-run against the generated config.
* fix(mxc): gate Windows readiness on the MXC host probe
A Windows service name is the wrong readiness signal: IsoEnvBroker was renamed to IsolationSession, and MXC ProcessContainer depends on neither. Run wxc-exec --probe on the executor the backend launches and activate only when MXC selects an isolation tier, passing its error through and logging its degradation warnings.
The SDK contract test also checks readiness against the pinned probe and finalizes exec tokens so dry runs leave no sandbox temp directories.
* docs(mxc): clarify sandbox readiness comments
* fix(mxc): document executor override recovery
Require the selected MXC executor to satisfy the 0.8.0 probe contract and explain recovery for older overrides. Cover rejection before backend registration and recovery with a compatible executor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The runtime harness mocks defaults, which now owns the pure native-model constructor. Forward that helper and move the unchanged runtime-plan factory into the existing fixture module to keep the oversized harness shrinking.
Scheduled main CI 37067275144 failed seven auth cases before their assertions. All 12 auth-failover and 8 session-permission cases now pass in 63.87 and 41.16 seconds respectively. Independent review and strict guards pass; production code, test order, assertions, and timeouts are unchanged.
Database identity is assigned during preparation. Spreading the captured execution snapshotted the getter too early and made durable session seeding fail admission. Delegate the mock getter to its retained owner.
Both trajectory writer cases pass in 49.54 seconds after the matching failures in scheduled main CI 37067275144. Independent review and strict guards pass; production admission remains unchanged.
Couple test-worker arguments to the executable selected by the shared subprocess helper and migrate its runtime-dependent callers. Repair command parsing, runtime pinning, worker observation, storage settlement, and cleanup-clock fixtures while preserving their contracts.
Fourteen scoped suites pass on Node 24 and Bun; the Bun readSync gap remains an unchanged stop. Refreshed proof covers 638 passed/1 existing skip on Node and 636 passed/3 existing skips on Bun. P2 review and exact-head ClawSweeper found no actionable defects. Production LOC delta is zero.
The first CI head exposed an inherited UI-validator fixture omission. After incorporating its existing main fix, exact-head CI passed, including the published-driver update job. No same-head retry or admin exception was used.
Add a count-neutral subscribeSessionChanges method on api.runtime.gateway backed by the core session row change stream, forwarding keyed invalidations so plugins can keep incremental projections fresh without polling. First consumer: the Workboard Sessions board.
Prepared metadata patches retain agent database workers after d6929f854d.
Await their existing close owner before conversation-registry fixture SQL and
public-sharing foreign writes, and settle public-sharing teardown. Preserve
all ownership, visibility, and race assertions.
Validation: both changed files passed three times (69 case executions), and
passed again in their full Linux owning configurations. The full configs ran
926 files with 11,413 passing cases and three failures in unchanged tests;
those files passed isolated controls (7/7, 5/5, 20/20). The search-scope control
remains close to its existing timeout and needs separate follow-up.
Check-changed, types, formatting, lint, boundary lint, and independent P2
review passed. Linux proof used Crabbox after Testbox capacity fallback.
Sibling cleanup can leave retained session-generation facts temporarily
unavailable while native metadata is publishing. Kill-tree discovery
recorded that readiness gap as a permanent error even after all five
selected descendants had been cancelled (CI 37061184155, TT1).
Forward the existing session read preparation through captured ancestor
bindings before discovery checks. Preserve known replacement fencing,
caller-authority failures, unknown write outcomes, and queued holds. Use
the same parent binding for resident and refreshed descendants so the
prepared-session flag is no longer dropped.
The native publication regression fails on original production and passes
with this fix. The concurrency file passes all 13 tests; six sibling files
pass 89 tests, with final publication, replacement, and accounting probes
rechecked. Core and core-test types, focused lint, and autoreview pass.
The full changed-check wrapper hits an unchanged stale Discord max-lines
baseline entry (removed by f0308b72d7 on newer main); all remaining
planned checks pass when run separately.
Production LOC: +23/-6 (net +17), needed to carry existing readiness and
preserve the revoked-generation boundary; tests/support: +50/-3.
Test cost: node scripts/run-vitest.mjs src/agents/subagents/registry/subagent-control.concurrency.test.ts --maxWorkers=1: 221.05s wall on the loaded macOS host, including compiled-worker preparation.
* feat(memory): resolve the memory audience in the host
Memory providers had to re-derive whether a caller acts for the agent
owner privately or for one conversation, walking spawn lineage through
session lookups.
When the memory slot owner registers providerRuntime, the host mints a
MemoryAudience (owner-private, or one exact conversation) from the
admitted turn entry and, for spawned children, the exact parent key,
session ID, lifecycle revision (or its recorded absence), and captured
owner bit of every hop. Memory Core and other legacy owners resolve no
audience: their turns take no session leases, read no lineage, and log
nothing new. Native, ACP, and realtime voice consult children record the trusted
spawning sender's owner status and parent incarnation so that lineage
survives session creation, reset, and rollover. The receipt stores the
parent session id as spawnedBySessionId, so navigation's parentSessionId
and sessions.list stay unchanged; a child of a parent without a lifecycle revision,
such as a channel-created group row, records that absence. Incomplete or
stale lineage yields no audience; only a spawned row without the owner
receipt predates the lineage receipts, and it logs a respawn
instruction. A parent without a stored row spawns as before. Spawn rechecks
a stored parent on the session read worker immediately before the child
commits. Parent rows are read on the session read worker, and every captured hop holds
a session generation lease, so currency checks stay synchronous and
read-free. Audiences are bound to their session, released when the
owning attempt or run ends, and delegated to same-agent children bound
to the child's current incarnation. The host checks currency before and
after opening a provider and around every provider call, and the guard
it passes to a provider includes audience currency. The memory slot
owner's own tools, Active Memory, and project recall also recheck it
before their effects; other plugin tools reach memory only through the
provider guard and do not fail on a stale audience.
Session authority, plugin tool contexts, hook contexts, and Codex
dynamic tools carry the audience. Native consumers cut over to it:
Active Memory trigger, deep, and summary recall (caches keyed by
audience; default deep-recall tools from the slot owner's
recallToolNames; trigger recall runs only while tool policy allows every
recall tool the provider declares), project recall, Memory Wiki,
post-compaction provider refresh, doctor memory status and recall/search
checks, and the status scan, which report provider health instead of
legacy index counters. Legacy owners keep their trigger-recall gate,
doctor and status ordering, and post-compaction sync without loading or
calling the slot plugin to decide.
* test(memory): consolidate memory audience tests
Fold the real session-owner audience test into the shared real-lineage
fixture, drop the spawn lineage unit test that the real-SQLite spawn tests
already cover, share spawn parameters, and remove cases that only mirrored
implementation (log text, mock passthrough, per-kind passthrough).
* test(talk): expect lineage receipts on consult children
A 2026.9.5 to 9.7 managed update whose activation Doctor failed left the candidate package active with the agent databases on the old schema; the new Gateway exited 78 and systemd parked on RestartPreventExitStatus=78, and the failure notice depended on the Gateway the update had just stopped, so the operator saw nothing for 3.5 hours (#163638). A Gateway that finds the updater own unfinished agent migration at start now runs the candidate Doctor before its recovery restart, reinspects schemas, and records explicit recovery guidance when a mismatch remains; managed-update outcomes are delivered durably from the next Gateway start. The pre-migration backup stays on disk for manual restore; a successful live migration remains the point of no return (repair forward, never roll databases back). Thanks @chffhc for the timeline.
Closes#163638
The "handles $outcome after the baseline fingerprint exhausts its time
budget" case gave swapStagedPackageInstall a 200 ms budget and relied on
real wall time: the baseline reader could expire before its walk reached
the stalled open, and the launcher capture and rollback verification
readers (each with their own 200 ms wall-clock deadline) could time out
under host load.
Freeze Date/setTimeout/clearTimeout for the case, wait for the stalled
open, then advance exactly the baseline budget. Only the baseline reader
expires; later readers start on the frozen clock. All outcome variants
and assertions are unchanged.
Fixes#163568. A cron agentTurn's stale timeout cleanup no longer aborts a later turn that now owns the same shared session. The cron invocation records its runId, and timeout cleanup skips cancellation when another turn occupies the session. A genuine timeout still cleans up.
* fix(codex): restore catalog lint checks
Extract file reconciliation without moving catalog lifecycle or publication ownership. Preserve the implementation introduced by Peter Steinberger in #163706; this commit is the subsequent extraction.
* chore(lint): remove obsolete Discord line-limit exemption
* fix(heartbeat): keep WebChat exec completions out of the heartbeat target
A background command finishing in a WebChat session wakes a heartbeat turn.
With an explicit heartbeat target (e.g. discord #heartbeat, cadence 0m), the
reply was sent to that channel instead of publishing into the session that
ran the command. When the pending queue is only exec completions and a
WebChat projection exists, deliver by projection only; target:none is still
respected and ordinary heartbeat output keeps its configured target.
* fix(heartbeat): document session-owned exec completion routing and cover mixed batches
Address review: the override uses the existing internal-projection eligibility
(not WebChat only), so say so in code and docs; document that a failed session
write retries on a later wake with no channel fallback; assert a genuine poll
writes nothing into the session; add a mixed-batch test that keeps the explicit
target.
* fix(heartbeat): keep restart continuations for Control UI sessions out of the heartbeat target
A turn interrupted by a Gateway restart resumes through a restart-sentinel
heartbeat wake. With an explicit heartbeat target, that continuation reply was
sent to the heartbeat channel. On a restart-sentinel wake, events carrying the
sentinel's task:restart-sentinel: context key now count as session-owned
alongside exec completions: they publish into the owning session through the
internal projection and join the publication idempotency key. The sentinel reads
the prefix from the shared constant.
* fix(heartbeat): retain restart occurrences until session publication commits
* test(heartbeat): name captured occurrence invariants
* test(heartbeat): split system-event admission coverage
* chore: remove stale Discord max-lines baseline entry
---------
Co-authored-by: Marvin <marvin@local>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
Commit aad3deb6d8 added retained-identity accounting to the real Control UI
performance validator. Vite already emits asset-manifest.json into its staged
output, but the scripts/ui fixture omitted it, so scheduled main CI run
37061184155 failed with ENOENT on Linux and Windows.
Inventory the fixture's finalized assets and compressed sidecars with their
paths, hashes, sizes, manifest version, and generation. Keep both real validator
subprocesses and their exit-zero assertions unchanged. No production changes.
Before: ui.test.ts had 1 failure and 29 passes on main 54db277b5b.
After: 30 passes; performance and base-comparison siblings pass 59 tests.
Changed-file checks and independent autoreview passed. Remote main 97eb729b25
was rechecked immediately before committing; the affected owners are unchanged.
Test cost: node scripts/run-vitest.mjs test/scripts/ui.test.ts --maxWorkers=1: 54.54 s wall (7.44 s tests; warm compiled-worker cache).
Replaces #159940 by @DonnieFi (the fork does not allow maintainer edits). Related #159862.
When a visible `sessions_spawn` child failed to start, the tool told the model only `error`, because the spawn adapter summarized the Gateway's structured `{ code, message }` error as the literal `error`. It now returns the real message from `Error`, string, or `{ message }` shapes, for example `send blocked by session policy. Session removed.` Cleanup behavior is unchanged, except that cleanup failures are logged instead of swallowed.
Proof: on a real isolated Gateway, the base returned `error. Session removed.` and the candidate returned the policy message. The regression test fails on base and passes here. In live gpt-5-mini runs (2 calls), the model received and reported the actual error.
Co-authored-by: Donnie Fiander <44792682+DonnieFi@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Route current canonical first-attempt core lint stripes to the existing
16-class with an unset or blacksmith backend, and retain that class for
hybrid fork rows. Preserve stripe coverage, cache authority, and hosted
fallbacks. OPENCLAW_CI_RUNNER_BACKEND=github remains the override; unset
uses the fast path without changing repository settings.
The same SDK-miss stripe-5 selection measured 157s on Linux versus
250-266s hosted. Workflow planning, preflight checkout shapes, changed
static checks, and P2 review passed.
The native macOS node catalog (anthropic.claude.sessions.list.v1/read.v1)
always read ~/.claude/projects, while the TypeScript scan honors
CLAUDE_CONFIG_DIR. Resolve the projects root once per entry point with the
same precedence (trimmed CLAUDE_CONFIG_DIR, else HOME/.claude) and share it
across list, read, read-lease store/lookup, and advertisement, so the
existing root-containment checks apply to the resolved root. Claude Desktop
metadata stays HOME/Library-scoped, matching the TS node commands.
Tests now inject an explicit environment instead of inheriting the runner's.
On Node 24 and 26, process.exit() joins V8's platform workers without
disposing the isolate. A concurrent Maglev or Sparkplug compile job parked
waiting for a main-thread GC then never finishes, so CLI commands, the hook
relay, or a stopping Gateway can sit at 0% CPU forever after printing their
output (nodejs/node#64274; fix pending in nodejs/node#66171).
Every OpenClaw executable entrypoint (CLI entry, Gateway/service index,
native hook relay, macOS node worker) now turns off Maglev and concurrent
Sparkplug at startup when it runs as main, matching Node 22's tiering and
the existing Vitest policy. Library imports keep stock V8; explicit
--maglev or --concurrent-sparkplug flags still win.
Testbox A/B (4 vCPU, Node 24.19, e2e CLI child replay, 8-way): 6/1019
hung with defaults, 0/1019 with the policy; re-enabling only Maglev hung
2/1019 and only concurrent Sparkplug 12/944, so both flags are needed.
The test ran the real base-comparison CLI six times through spawnSync inside
one 60 s deadline. On loaded hosts it took 25-45 s and sometimes exceeded the
deadline. A spawnSync timeout SIGTERMed only the CLI, so its Vite grandchild
kept writing into the temp tree and the finally rmSync failed with ENOTEMPTY,
masking the original ETIMEDOUT.
Run every subprocess through the command fixture, which joins the process
group before removing temp roots, and split the file into three 60 s contract
tests. Drop the separate within-budget run (control-ui-performance.test.ts owns
that threshold via --base-dist), link only vite/pako instead of the real repo
node_modules, and enable stage diagnostics so a deadline abort names the
stalled step.
* fix(test): align reply-entry fallback E2E with concise error copy
The reply-entry fallback E2E still expected the pre-#163381 rate-limit and
auth-failure copy, so its two OpenAI cases fail on main. Hourly main CI skips
src E2E files, so the break stayed invisible there.
Assert the new pinned rate-limit copy and the exported auth copy constant.
The anthropic-attempt count still catches the original fallbackConfigured
defect, which surfaced as "temporarily rate-limited" after a fallback attempt.
The non-OpenAI failures reported on 2026-10-01 were a separate, already-fixed
fixture gap: #161103 added reply-path thinking-catalog hydration that calls
preparedModelRuntimeConfigsMatch through the prepared-model-runtime module,
and the shared E2E mock lacked that export until #148089. No product change.
* fix(test): migrate Gateway E2E fixtures to keyed agent rosters
#162612 made ordinary config reads reject a populated agents.list, but the
dreaming restart-cleanup and WhatsApp login-authority E2E fixtures still wrote
legacy rosters to disk. Both Gateways now refuse to start (code 78 or
InvalidConfigError) before any assertion runs, which fails Gateway E2E shard
1/4 on main. Hourly main CI does not run these files.
Write the canonical shapes Doctor produces: a sole keyed main entry for the
WhatsApp fixture, and explicit ownership with main as the system agent for the
two-agent dreaming fixture. Assertions are unchanged.
Official Node 24 and Node 26 macOS binaries are built with
`-mmacosx-version-min=13.5` (LC_BUILD_VERSION minos 13.5), and Node's
BUILDING.md lists macOS >= 13.5 as its Tier 1 range. macOS does not
refuse to launch binaries with a newer minos, and the CLI and Gateway
run on macOS 12.7.6 with official Node 24 (nvm), so "macOS 11 through
13.4 no longer support the Node-based CLI or Gateway" overstated it.
Keep OpenClaw's unsupported stance for macOS below 13.5, and note that
features shipping their own native binaries can still fail there.
Co-authored-by: xXG0DLessXx <40996215+xXG0DLessXx@users.noreply.github.com>
The first session-notify case failed in whole-file runs with
"gateway request timeout for sessions.resolve". The local Gateway request
context creates its session-row projection lazily on the first request, so
cold module transform plus projection creation (8.1 s of a 9.5 s lookup,
measured) ran inside the in-process tool's 10 s request budget. Under load
the first case, and on a cold worker cache both positive cases, timed out.
The shared session-tools fixture now awaits projection readiness before the
test body, matching the fixture-hydration precedent from #150196 and the
sibling suite's handler preload. The positive notify cases hold real
projection startup behind a gate and advance the request timer past the
budget; with the fixture change reversed they fail with the original
timeout, and pass with it.
Fix red main introduced by d6929f854d (#163378): the Doctor fixture removed its state before native cleanup settled, breaking import receipt validation and subsequent shared-worker teardown.
Await the existing scoped session-state cleanup owner before restoring the environment and deleting the fixture root. Preserve every assertion.
Proof: five consecutive 15/15 runs on both Node 24 and Bun; full shared-worker commands config passes 543 files and 6,824 tests (four skipped); check-changed, independent P2 review, exact-head CI, and ClawSweeper pass.
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Gateway startup validation rejects a raw agents.list since the legacy
roster reads moved into Doctor (#162612), so the gateway-hosted exec
approval e2e failed with INVALID_CONFIG before any approval ran.
Convert the disk-written fixture to keyed agents.entries, keeping the
main agent's per-agent exec cleanupMs override and the helper agent.
Wait for the session metadata writer before admitting channel dispatch so cold
session database creation and registry publication cannot race the reader.
Keep best-effort error reporting in the tracked task and automatic maintenance
off the foreground path. Remove Telegram's duplicate local metadata wait.
Give the Tlon prefix fixture explicit automatic visible replies so it does not
lazily discover provider policy and retain a tsx FileCache Immediate on its fake
clock. The fixture still exercises the real shared dispatcher and send path.
Update behavior: no config, state format, schema, or updater changes.
The error-reporter callback type now represents its existing asynchronous
runtime contract, eliminating the corresponding cast in the failure test.
Production delta: +18/-27, net -9.
Proof on Hetzner cbx_01f79ceb725a: clean main bf2883a original five-file
CI group reproduced four cold admission/registry failures in 71.305s;
candidate passed all 83 tests in 68.009s. CI-merge focused suites passed
117 tests, and the held-writer regression failed original production.
Final nine-test recorder suite passed in 4.728s. All selected type, lint,
boundary, format and dead-export gates passed, retaining the initial lint
failures and their focused corrected runs. No CI rerun was requested.
Declare active Wiki cache files and bounded Teams delegated-token archive
resources while leaving retired migration inventories empty. Preserve
archive collision handling and refuse symlink sources before creating the
archive directory.
Extract the coherent migration resource declarations from Peter Steinberger's
#144005, with current-source reconciliation and regressions fixed by Jason
(Json). This does not complete or close the original recovery journey.
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(ui): gate system information at the shared reader
Preserve authorized host details and foreground discovery while suppressing
denied automatic reads. Retire cached and in-flight results when their
connection or read scope changes, and remove the separate header cache.
Co-authored-by: Patrick-Erichsen <20157849+Patrick-Erichsen@users.noreply.github.com>
* test(ui): advertise system information in browser fixtures
* test(ui): target catalog and sidebar requests precisely
---------
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Patrick-Erichsen <20157849+Patrick-Erichsen@users.noreply.github.com>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
* refactor(channels): deslop Slack and Matrix
Consolidate channel policy, routing and metadata handling with their existing
owners; unify Matrix recovery-key settlement and remove redundant wrappers,
types and state projections. Retire configuration migrations for shapes that
were already obsolete before July while preserving supported configuration,
persisted data, wire payloads, tool descriptions and visible UI.
Bound newly created Matrix pairing cooldown records to the existing sender
cap, and make the public compatibility chunker terminate for nonpositive
limits. Regression proof demonstrates both original failures. Shrink the
assertion-safety ratchet after removing ten unsafe casts.
* fix(doctor): guard retired Slack and Matrix config
Fixes#129054.
The `sessions_search` tool schema now requires a non-empty `query` (`minLength: 1`) with a concise description, so models are told up front instead of discovering it from an error, and a blank or whitespace query returns an actionable retry message. main already rejected blank queries at execution ("query must not be empty"); this adds the schema constraint and clearer guidance. Keyword searches are unchanged. The system prompt is unchanged; the tool schema grows by about 100 compact bytes. Time-range guidance from the original PR was deferred because live runs did not show the model using it.
Proof: baseline schema accepts an empty query, this change rejects it; an isolated Gateway rejects blank queries with the retry guidance and returns the same keyword results. Live gpt-5-mini runs emitted a non-empty query. Regression tests fail on main and pass here.
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>