refactor(config): config-surface reduction tranche 2 — purge tuning knobs behind built-in defaults#111382
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8e072ae6eb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| mode: z | ||
| .union([z.literal("off"), z.literal("restart"), z.literal("hot"), z.literal("hybrid")]) | ||
| .optional(), | ||
| debounceMs: z.number().int().min(0).optional(), | ||
| deferralTimeoutMs: z.number().int().min(0).optional(), | ||
| }) |
There was a problem hiding this comment.
Remove retired reload knobs from the config reference
After these properties are removed from the strict gateway.reload schema, the example and field descriptions in docs/gateway/configuration-reference.md:738-758 still instruct operators to set debounceMs and deferralTimeoutMs. Copying that documented configuration now causes validation to reject openclaw.json, so the gateway may not start until the advertised keys are removed.
Useful? React with 👍 / 👎.
| mode: z.union([z.literal("default"), z.literal("safeguard")]).optional(), | ||
| provider: z.string().optional(), | ||
| thinkingLevel: AgentThinkingLevelSchema.optional(), | ||
| reserveTokens: z.number().int().nonnegative().optional(), | ||
| keepRecentTokens: z.number().int().positive().optional(), |
There was a problem hiding this comment.
Update the compaction QA scenario before rejecting its knobs
When the goal-context-survives-compaction QA scenario runs, qa/scenarios/goals/goal-context-survives-compaction.yaml:19-25 still injects reserveTokens and reserveTokensFloor through gatewayConfigPatch; extensions/qa-lab/src/suite.ts:1771-1773 writes that patch into the gateway config. Since this object is strict, the gateway now rejects the scenario config during startup instead of exercising compaction, breaking that experiment until the scenario is rewritten to use supported controls.
Useful? React with 👍 / 👎.
8e072ae to
4c00afa
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4c00afa4bf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| richMessages: z.boolean().optional(), | ||
| timeoutSeconds: z.number().int().positive().optional(), | ||
| mediaGroupFlushMs: z | ||
| .number() | ||
| .int() | ||
| .min(10) | ||
| .max(60_000) | ||
| .optional() | ||
| .describe( | ||
| "Buffer window in milliseconds for Telegram media groups/albums before dispatching them as one inbound message. Default: 500.", | ||
| ), | ||
| pollingStallThresholdMs: z.number().int().min(30_000).max(600_000).optional(), | ||
| retry: RetryConfigSchema, | ||
| network: z |
There was a problem hiding this comment.
Remove retired retry blocks from channel docs
After retry is removed from both strict account schemas, docs/gateway/config-channels.md:200-205 and :333-338 plus docs/concepts/retry.md:44-69 still instruct operators to configure channels.telegram.retry and channels.discord.retry. Copying either documented example now makes config validation reject openclaw.json, potentially preventing Gateway startup.
Useful? React with 👍 / 👎.
| tabCleanup: z | ||
| .strictObject({ | ||
| enabled: z.boolean().optional(), | ||
| idleMinutes: z.number().int().nonnegative().optional(), | ||
| maxTabsPerSession: z.number().int().nonnegative().optional(), | ||
| sweepMinutes: z.number().int().positive().optional(), | ||
| }) |
There was a problem hiding this comment.
Remove retired browser cleanup fields from the reference
The strict browser.tabCleanup schema now accepts only enabled, but docs/gateway/configuration-reference.md:415-420 still presents idleMinutes, maxTabsPerSession, and sweepMinutes in its main browser example. Operators copying that reference receive unknown-key validation errors and may be unable to start the Gateway until those advertised fields are removed.
Useful? React with 👍 / 👎.
| triggers: z | ||
| .strictObject({ | ||
| enabled: z.boolean().optional(), | ||
| minIntervalMs: z.number().int().positive().optional(), | ||
| }) | ||
| .optional(), | ||
| retry: z | ||
| .strictObject({ | ||
| maxAttempts: z.number().int().min(0).max(10).optional(), | ||
| backoffMs: z.array(z.number().int().nonnegative()).min(1).max(10).optional(), | ||
| retryOn: z | ||
| .array(z.enum(["rate_limit", "overloaded", "network", "timeout", "server_error"])) | ||
| .min(1) | ||
| .optional(), | ||
| }) |
There was a problem hiding this comment.
Update the cron condition-watcher QA scenario
When cron-condition-watcher runs, qa/scenarios/scheduling/cron-condition-watcher.yaml:23-27 still injects cron.triggers.minIntervalMs: 250 through gatewayConfigPatch, which extensions/qa-lab/src/suite.ts:1771-1773 merges into the Gateway config. Because cron.triggers is strict and no longer accepts this key, the scenario now fails config validation instead of exercising quiet trigger ticks.
Useful? React with 👍 / 👎.
4c00afa to
c847403
Compare
c847403 to
9ab967c
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9ab967cfb7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| sendPolicy: SessionSendPolicySchema.optional(), | ||
| writeLock: z | ||
| .object({ | ||
| acquireTimeoutMs: z.number().int().positive().optional(), | ||
| staleMs: z.number().int().positive().optional(), | ||
| maxHoldMs: z.number().int().positive().optional(), | ||
| }) | ||
| .strict() | ||
| .optional(), | ||
| agentToAgent: z | ||
| .object({ | ||
| maxPingPongTurns: z.number().int().min(0).max(20).optional(), | ||
| }) | ||
| .strict() | ||
| .optional(), | ||
| threadBindings: z |
There was a problem hiding this comment.
Update the A2A mirror-dedupe QA scenario
When a2a-message-tool-mirror-dedupe runs, qa/scenarios/channels/a2a-message-tool-mirror-dedupe.yaml:13-19 still adds session.agentToAgent.maxPingPongTurns: 0 through gatewayConfigPatch, and extensions/qa-lab/src/suite.ts:1771-1773 writes that patch into the Gateway config. Because SessionSchema is strict and no longer accepts agentToAgent, Gateway startup fails validation before this channel-delivery scenario can exercise mirror deduplication.
Useful? React with 👍 / 👎.
| temporalDecay: z | ||
| .object({ | ||
| enabled: z.boolean().optional(), | ||
| halfLifeDays: z.number().int().positive().optional(), | ||
| }) | ||
| .strict() |
There was a problem hiding this comment.
Update the session-memory ranking QA scenario
During session-memory-ranking, qa/scenarios/memory/session-memory-ranking.yaml:63-78 calls config.patch with agents.defaults.memorySearch.query.hybrid.temporalDecay.halfLifeDays: 1; extensions/qa-lab/src/suite-runtime-gateway.ts:344-365 sends that mutation to the Gateway. The now-strict temporalDecay object accepts only enabled, so the patch is rejected and the scenario stops before proving that temporal decay ranks the current memory above the stale one.
Useful? React with 👍 / 👎.
|
Merged via squash.
|
What Problem This Solves
OpenClaw exposed a large set of internal numeric tuning knobs as public configuration even though their unset behavior already had stable built-in defaults. That widened the schema, docs, generated metadata, tests, and long-term compatibility surface without giving most operators a meaningful product choice.
This tranche removes 209 generated config paths after rebasing onto current
main:mainClawSweeper config-surface metric: 209 config/default paths removed. The committed baseline on
mainstill reports core 3007 because the newly addedui.prefs.sidebarLiveActivitypath had not yet been regenerated there; measuring the current schema gives the 3008 pre-change value above.Removed keys by subtree
Authentication, secrets, browser, and tools
auth.cooldownsand all children:billingBackoffHours,billingBackoffHoursByProvider,billingMaxHours,authPermanentBackoffMinutes,authPermanentMaxMinutes,failureWindowHours,overloadedProfileRotations,overloadedBackoffMs, andrateLimitedProfileRotations.secrets.resolutionandmaxProviderConcurrency,maxRefsPerProvider, andmaxBatchBytes.browser.remoteCdpTimeoutMs,remoteCdpHandshakeTimeoutMs,localLaunchTimeoutMs,localCdpReadyTimeoutMs,actionTimeoutMs, andcdpPortRangeStart.browser.tabCleanup.idleMinutes,maxTabsPerSession, andsweepMinutes;enabledremains.tools.loopDetection:genericRepeat,knownPollNoProgress,pingPong,windowSize,historySize,warningThreshold,unknownToolThreshold,criticalThreshold,globalCircuitBreakerThreshold,detectors, andpostCompactionGuard;enabledremains.Agent defaults and agent-list echoes
compaction.reserveTokens,reserveTokensFloor, andmaxHistoryShare.contextPruning.keepLastAssistants,softTrimRatio,hardClearRatio,minPrunableToolChars, plussoftTrim.maxChars,headChars, andtailChars.memorySearch.chunking.tokensandoverlap;memorySearch.sync.watchDebounceMsandintervalMinutes.memorySearch.query.hybrid.vectorWeight,textWeight, andcandidateMultiplier;mmr.lambda;temporalDecay.halfLifeDays.memorySearch.cache.maxEntries.cliBackends.*.reliability.outputLimits.maxTurnRawCharsandmaxTurnLines;watchdog.fresh.noOutputTimeoutMsandwatchdog.resume.noOutputTimeoutMs.runRetries.base,perProfile,min, andmax.These paths are removed from both
agents.defaultsandagents.list[]wherever those scopes support them.Gateway, sessions, cron, diagnostics, web, and messages
gateway.channelHealthCheckMinutes,channelStaleEventThresholdMinutes,channelMaxRestartsPerHour, and config-levelhandshakeTimeoutMs.gateway.reload.debounceMsanddeferralTimeoutMs.gateway.http.endpoints.chatCompletions.maxBodyBytes,maxImageParts, andmaxTotalImageBytes;gateway.http.endpoints.responses.maxBodyBytes.session.typingIntervalSeconds,session.agentToAgent.maxPingPongTurns, andsession.writeLock.acquireTimeoutMs,staleMs, andmaxHoldMs.cron.maxConcurrentRuns,cron.triggers.minIntervalMs, andcron.retry.maxAttempts,backoffMs, andretryOn.diagnostics.stuckSessionWarnMs,stuckSessionAbortMs, andmemoryPressureSnapshot; doctor also removes legacymemoryPressureBundle.web.heartbeatSeconds,web.reconnect.initialMs,maxMs,factor,jitter, andmaxAttempts, plusweb.whatsapp.keepAliveIntervalMs,connectTimeoutMs, anddefaultQueryTimeoutMs.messages.queue.debounceMsandmessages.statusReactions.timing.debounceMs,stallSoftMs,stallHardMs,doneHoldMs, anderrorHoldMs.ACP, MCP, worktrees, transcripts, hooks, and update
acp.stream.coalesceIdleMs,maxChunkChars,maxOutputChars,maxSessionUpdateChars, andhiddenBoundarySeparator; delivery mode, repeat suppression, and tag visibility remain.acp.maxConcurrentSessionsandacp.runtime.ttlMinutes.mcp.sessionIdleTtlMs.worktrees.cleanup.maxCountandmaxTotalSizeGb, then the emptyworktreesparent.transcripts.maxUtterances.hooks.maxBodyBytes.update.auto.stableDelayHours,stableJitterHours, andbetaCheckIntervalHours; channel, check-on-start, and auto-enabled settings remain.Bundled channels
timeoutSeconds,mediaGroupFlushMs,pollingStallThresholdMs,retry.attempts,retry.minDelayMs,retry.maxDelayMs,retry.jitter, anderrorCooldownMs.gatewayInfoTimeoutMs,gatewayReadyTimeoutMs,gatewayRuntimeReadyTimeoutMs,eventQueue.listenerTimeout,eventQueue.maxQueueSize,eventQueue.maxConcurrency, andretry.attempts,minDelayMs,maxDelayMs, andjitter. Doctor intentionally does not recurse into arbitrary provider settings.timeoutSeconds.Kept, with reason
skills.limits.*: documented mainstream operator control.gateway.auth.rateLimit.*: optional security policy without one universal default.messages.inbound.*debounce values: unset disables debounce, so removal would change the default behavior.agents.*.compaction.keepRecentTokens: configured values change the runtime checkpoint cut point.media.ttlHours: unset disables cleanup, so a built-in positive TTL would change retention.network.autoSelectFamily,network.dnsResultOrder, anddangerouslyAllowPrivateNetwork: policy/selection controls, not numeric tuning defaults.agents.defaultstyping controls: explicitly deferred to Phase 4.OPENCLAW_HANDSHAKE_TIMEOUT_MS: the config knob is removed, but the environment override remains.Why This Change Was Made
Runtime readers now use named built-in constants or their prior unset defaults. Current schemas, types, labels, help, docs, and generated metadata expose only the canonical surface, while legacy cleanup remains owned by doctor rather than steady-state runtime compatibility branches.
One global migration,
runtime.tuning-knobs-purge, strips root,agents.defaults, andagents.list[]echoes. Telegram, Discord, and ClickClack cleanup stays in their channel doctor contracts. The matching compatibility record isdoctor-runtime-tuning-knobs-purge, with a removal window ending 2026-09-18.User Impact
Named tradeoff: operators who explicitly tuned these tuning-only keys revert to the built-in defaults after running
openclaw doctor --fix. Behavior is unchanged for everyone who never set them.Strict current schemas intentionally reject the retired aliases; doctor is the sole migration owner. Mainstream feature switches, security policies, and settings whose unset state changes behavior remain available.
Evidence
src/config/dead-config-keys.test.ts,src/config/config.schema-regressions.test.ts,src/commands/doctor/shared/legacy-config-migrations.runtime.retired.test.ts, and Telegram/Discord/ClickClack doctor tests — all green after the final rebase.pnpm config:docs:check— green; generated docs baseline, channel metadata, and docs map regenerated.pnpm tsgo:core,pnpm tsgo:extensions:test, andpnpm check:test-types— green.pnpm deadcode:dependencies,pnpm deadcode:exports, andpnpm plugin-sdk:surface:check— green.pnpm format <changed files>andgit diff --check— green.CHANGELOG.mdis intentionally untouched.