* fix(gateway): align configured local credentials
* test(gateway): align local credential coverage
* chore(gateway): leave release note to release process
* feat(cron): bind agent turns to current sessions
* feat(commands): add loop chat command
* test(cron): cover session defaults and loop commands
* docs(cron): document current defaults and loops
* fix(commands): scope /loop status and stop by conversation name tag
* fix(commands): widen /loop conversation tag to 48 bits
* fix(commands): include disabled jobs in /loop status and stop
* docs(cron): regenerate docs map
* test(cron): split session-target default tests to satisfy max-lines
* refactor(infra): move exec approvals into the shared SQLite state DB
Delete the file-runtime exec-approvals store (exec-approvals.json + .lock
sidecar machinery) on both runtimes and make the reserved
exec_approvals_config singleton row canonical. Doctor owns the one-time
import with claim/verify/receipt discipline; runtime fails closed with a
doctor instruction while un-migrated legacy state exists. The wire CAS
contract, socket semantics, and gateway auth-token derivations are
unchanged. Kills the #113929 lock-contention bug class structurally and
nets around -2.9k lines.
* fix(infra): green CI gates and retire file-era exec approvals tests
Break the migration-type import cycle with a leaf contract, regenerate the
plugin-SDK API and native i18n baselines for the intentional surface change,
drop unused exports, and replace the macOS file-era approvals test suite with
SQLite-backed behavior coverage per the obsolete-internals test policy.
* chore: green max-lines ratchet, native i18n baseline, and unused-export scan
The policy/data-handling-redaction-disabled check could never emit a finding:
scanPolicyDataHandling records the sensitiveLoggingRedaction evidence with a
hardcoded value true, and the finding builder only fired on value !== true.
Redaction is unconditional in src/logging/redact.ts, which hardcodes tools mode
and reads only redactPatterns, so no config can turn it off.
Delete the check, its finding builder, check id, and the validateOnly fix class
that existed solely for it. Keep the public
dataHandling.sensitiveLogging.requireRedaction policy key: it is a policy.jsonc
contract, it still drives openclaw policy compare baseline strictness, and its
shape stays validated.
Make the key's satisfied status explicit instead of silent: the policy rule
declares satisfiedByInvariant pointing at the evidence source policy state
records (oc://openclaw.invariant/logging/redaction), which openclaw policy check
emits in dataHandling evidence and the attestation. A metadata test asserts every
rule names either its checks or its invariant, never both and never neither, and
that policy state actually emits the declared source.
Also drop the stale logging.redactSensitive entry from the policy config coverage
manifest; that config key is retired.
Sensitive log redaction became unconditional and `logging.redactSensitive`
was retired from the config schema, but the policy doctor still classified
`dataHandling.sensitiveLogging.requireRedaction` as an automatic repair that
would have written the retired key back into config.
Remove the automatic repair (check-id registration, patch branch, and the
`enableSensitiveLoggingRedaction` writer), drop the `logging.redactSensitive`
config target, and reclassify the check as `validateOnly`. The check keeps
evaluating the policy declaration against the redaction invariant; it just no
longer claims a fixable config target. Refresh the policy docs, the finding
fix hint, and a stale comment in `src/logging/redact.ts`.
* docs: correct retired cron/audit config keys, cron failure-alert default, memory recall default, and tool-search telemetry claims
- configuration-reference: cron block documented cron.webhook and cron.failureDestination, both retired by the config-surface reduction tranches (58452de711, edecdbd05e); the cron schema is strict so a copied snippet is rejected. Document only the live keys and note the doctor --fix migrations.
- configuration-reference: root-level audit block is retired; canonical path is logging.audit (src/config/zod-schema.root-shape.ts).
- configuration-reference: cron.failureAlert.after default is 2, not 3 (src/cron/service/failure-alerts.ts).
- memory-config: rememberAcrossConversations defaults on for personal installs (packages/memory-host-sdk/src/host/config-utils.ts), matching the canonical table earlier in the page.
- tool-search: telemetry records catalogSize, per-source counts, and search/describe/call counts, and only on tool_search_code results. No byte accounting exists in the runtime.
* docs: retire remaining references to removed cron, audit, and logging config keys
Sweep follow-up to the previous commit, covering the same bug class in the pages that still contradicted it.
- cron-jobs/cli-cron: global cron.failureDestination is retired; the destination fields now live on cron.failureAlert (src/config/zod-schema.root-shape.ts, merged by legacy-config-migrations.runtime.retired.ts:379). Per-job delivery.failureDestination bullets left intact.
- gateway/audit, cli/audit, gateway/protocol: root-level audit.* is retired; canonical path is logging.audit.*.
- logging: logging.redactSensitive is retired (dead-config-keys.test.ts:198; removed by legacy-config-migrations.runtime.tier-eval.ts:12). resolveConfigRedaction hardcodes DEFAULT_REDACT_MODE = tools, so redaction is unconditional. Also documented that redactPatterns replaces the defaults on the log path (redact.ts:419) while tool payloads always merge them.
- logging: consoleStyle accepts only pretty|json (zod-schema.root-shape.ts:106); compact remains the automatic non-TTY rendering style (logging/console.ts:40) but is no longer settable, and doctor maps a stored one to pretty.
- security: security --fix no longer touches redaction and the logging.redact_off audit check is retired (src/security/audit-loopback-logging.test.ts asserts it never fires).
* chore(docs): regenerate docs map after retired-key cleanup
* docs: sync heartbeat, memory, commitments, and system-prompt docs with current behavior
The heartbeat doc described a removed broad default prompt; the memory doc
claimed automatic distillation that does not run on a default install; the
commitments docs advertised a snoozed status nothing currently writes; the
system-prompt doc omitted the Promised Work and Proactive Sub-Agent
Orchestration sections.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(heartbeat): describe scheduled work accurately
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(channels): add channel-owned setup contracts
* test(channels): align legacy setup fixtures
* chore(channels): regenerate config and SDK baselines after rebase
* fix(update): run fresh doctor after current-process core changes
* fix(channels): align add pre-scan with execution precedence
* style(cli): format channels-cli test additions
* fix(channels): restore option-before-positional channel resolution via metadata arity scan
* fix(channels): keep help flags out of metadata arity escalation
* test(update): mock fresh post-update doctor in current-process suites
* style: format review fixes and correct entrypoint mock type
* fix(channels): register only modern contract options for dual-publishing plugins
* test(update): align downgrade suites with fresh-doctor child invocation
* docs(channels): record empty-contract and input-forwarding invariants
* fix(line): keep the shipped --token switch as a channel access token alias
* fix(signal): stop treating exact cross-family loopback endpoints as bind-aligned
* chore(config): regenerate docs config baselines after second rebase
* style: format rebased channels add tests
* fix(channels): enforce field-key and flag-name agreement in setup contracts
* fix(signal): detect container endpoints for bare --http-url setup
* fix(signal): ignore unconfigured accounts in transport collision checks
* fix(channels): validate negated setup flags in contract and normalizer
* fix(signal): preserve existing transport kind when setup detection is unreachable
* style(signal): use direct boolean check in collision guard
* style(signal): type test config literals
* docs(update): record two-read design of fresh-doctor validation gate
* fix(channels): satisfy post-rebase architecture gates
* docs: refresh channel setup map
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(onboard): survive inference owner drift and verify credentials route-aware
Guided onboarding crashed ("Could not start the CLI") on the openai-api-key
candidate when OPENAI_API_KEY was set and a Codex CLI login existed:
- owner revalidation resolved provider auth without the route model's
id/api, so the transport gate never applied and profile-first discovery
picked the Codex-imported ChatGPT OAuth profile instead of the env key
the probe ran with — a deterministic fingerprint mismatch
- that mismatch escaped the activation persistence path as a plain throw,
crashing the wizard ladder instead of moving to the next candidate
Owner re-resolution now carries resolved model transport facts (fail closed
when the model cannot be resolved), and all setup revalidation sites route
through one helper whose drift error activation maps to
{ ok: false, status: "auth" }.
* feat(onboard): prefer logged-in subscription CLIs over env API keys in setup ladder
* fix(onboard): promote codex only on verifiable ChatGPT OAuth tokens
* fix(onboard): surface detected AI candidates in the top auth-choice tier
* fix(onboard): name detected candidates and the current model clearly
* test(setup): mock model resolution in the bound-session lock test
* fix(system-agent): carry verified model transport facts