Files
openclaw/src/config/schema.help.quality.test.ts
Vincent Koc 5d53b61d9e fix(browser): honor profile attachOnly for loopback CDP (#31429)
* config(browser): allow profile attachOnly field

* config(schema): accept profile attachOnly

* browser(config): resolve per-profile attachOnly

* browser(runtime): honor profile attachOnly checks

* browser(routes): expose profile attachOnly in status

* config(labels): add browser profile attachOnly label

* config(help): document browser profile attachOnly

* test(config): cover profile attachOnly resolution

* test(browser): cover profile attachOnly runtime path

* test(config): include profile attachOnly help target

* changelog: note profile attachOnly override

* browser(runtime): prioritize attachOnly over loopback ownership error

* test(browser): cover attachOnly ws-failure ownership path
2026-03-02 00:49:57 -08:00

797 lines
26 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { FIELD_HELP } from "./schema.help.js";
import { FIELD_LABELS } from "./schema.labels.js";
const ROOT_SECTIONS = [
"meta",
"env",
"wizard",
"diagnostics",
"logging",
"update",
"browser",
"ui",
"auth",
"models",
"nodeHost",
"agents",
"tools",
"bindings",
"broadcast",
"audio",
"media",
"messages",
"commands",
"approvals",
"session",
"cron",
"hooks",
"web",
"channels",
"discovery",
"canvasHost",
"talk",
"gateway",
"memory",
"plugins",
] as const;
const TARGET_KEYS = [
"memory.citations",
"memory.backend",
"memory.qmd.searchMode",
"memory.qmd.scope",
"memory.qmd.includeDefaultMemory",
"memory.qmd.mcporter.enabled",
"memory.qmd.mcporter.serverName",
"memory.qmd.command",
"memory.qmd.mcporter",
"memory.qmd.mcporter.startDaemon",
"memory.qmd.paths",
"memory.qmd.paths.path",
"memory.qmd.paths.pattern",
"memory.qmd.paths.name",
"memory.qmd.sessions.enabled",
"memory.qmd.sessions.exportDir",
"memory.qmd.sessions.retentionDays",
"memory.qmd.update.interval",
"memory.qmd.update.debounceMs",
"memory.qmd.update.onBoot",
"memory.qmd.update.waitForBootSync",
"memory.qmd.update.embedInterval",
"memory.qmd.update.commandTimeoutMs",
"memory.qmd.update.updateTimeoutMs",
"memory.qmd.update.embedTimeoutMs",
"memory.qmd.limits.maxResults",
"memory.qmd.limits.maxSnippetChars",
"memory.qmd.limits.maxInjectedChars",
"memory.qmd.limits.timeoutMs",
"agents.defaults.memorySearch.provider",
"agents.defaults.memorySearch.fallback",
"agents.defaults.memorySearch.sources",
"agents.defaults.memorySearch.extraPaths",
"agents.defaults.memorySearch.experimental.sessionMemory",
"agents.defaults.memorySearch.remote.baseUrl",
"agents.defaults.memorySearch.remote.apiKey",
"agents.defaults.memorySearch.remote.headers",
"agents.defaults.memorySearch.remote.batch.enabled",
"agents.defaults.memorySearch.remote.batch.wait",
"agents.defaults.memorySearch.remote.batch.concurrency",
"agents.defaults.memorySearch.remote.batch.pollIntervalMs",
"agents.defaults.memorySearch.remote.batch.timeoutMinutes",
"agents.defaults.memorySearch.local.modelPath",
"agents.defaults.memorySearch.store.path",
"agents.defaults.memorySearch.store.vector.enabled",
"agents.defaults.memorySearch.store.vector.extensionPath",
"agents.defaults.memorySearch.query.hybrid.enabled",
"agents.defaults.memorySearch.query.hybrid.vectorWeight",
"agents.defaults.memorySearch.query.hybrid.textWeight",
"agents.defaults.memorySearch.query.hybrid.candidateMultiplier",
"agents.defaults.memorySearch.query.hybrid.mmr.enabled",
"agents.defaults.memorySearch.query.hybrid.mmr.lambda",
"agents.defaults.memorySearch.query.hybrid.temporalDecay.enabled",
"agents.defaults.memorySearch.query.hybrid.temporalDecay.halfLifeDays",
"agents.defaults.memorySearch.cache.enabled",
"agents.defaults.memorySearch.cache.maxEntries",
"agents.defaults.memorySearch.sync.onSearch",
"agents.defaults.memorySearch.sync.watch",
"agents.defaults.memorySearch.sync.sessions.deltaBytes",
"agents.defaults.memorySearch.sync.sessions.deltaMessages",
"models.mode",
"models.providers.*.auth",
"models.providers.*.authHeader",
"gateway.reload.mode",
"gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback",
"gateway.controlUi.allowInsecureAuth",
"gateway.controlUi.dangerouslyDisableDeviceAuth",
"cron",
"cron.enabled",
"cron.store",
"cron.maxConcurrentRuns",
"cron.retry",
"cron.retry.maxAttempts",
"cron.retry.backoffMs",
"cron.retry.retryOn",
"cron.webhook",
"cron.webhookToken",
"cron.sessionRetention",
"cron.runLog",
"cron.runLog.maxBytes",
"cron.runLog.keepLines",
"session",
"session.scope",
"session.dmScope",
"session.identityLinks",
"session.resetTriggers",
"session.idleMinutes",
"session.reset",
"session.reset.mode",
"session.reset.atHour",
"session.reset.idleMinutes",
"session.resetByType",
"session.resetByType.direct",
"session.resetByType.dm",
"session.resetByType.group",
"session.resetByType.thread",
"session.resetByChannel",
"session.store",
"session.typingIntervalSeconds",
"session.typingMode",
"session.mainKey",
"session.sendPolicy",
"session.sendPolicy.default",
"session.sendPolicy.rules",
"session.sendPolicy.rules[].action",
"session.sendPolicy.rules[].match",
"session.sendPolicy.rules[].match.channel",
"session.sendPolicy.rules[].match.chatType",
"session.sendPolicy.rules[].match.keyPrefix",
"session.sendPolicy.rules[].match.rawKeyPrefix",
"session.agentToAgent",
"session.agentToAgent.maxPingPongTurns",
"session.threadBindings",
"session.threadBindings.enabled",
"session.threadBindings.idleHours",
"session.threadBindings.maxAgeHours",
"session.maintenance",
"session.maintenance.mode",
"session.maintenance.pruneAfter",
"session.maintenance.pruneDays",
"session.maintenance.maxEntries",
"session.maintenance.rotateBytes",
"session.maintenance.resetArchiveRetention",
"session.maintenance.maxDiskBytes",
"session.maintenance.highWaterBytes",
"approvals",
"approvals.exec",
"approvals.exec.enabled",
"approvals.exec.mode",
"approvals.exec.agentFilter",
"approvals.exec.sessionFilter",
"approvals.exec.targets",
"approvals.exec.targets[].channel",
"approvals.exec.targets[].to",
"approvals.exec.targets[].accountId",
"approvals.exec.targets[].threadId",
"nodeHost",
"nodeHost.browserProxy",
"nodeHost.browserProxy.enabled",
"nodeHost.browserProxy.allowProfiles",
"media",
"media.preserveFilenames",
"audio",
"audio.transcription",
"audio.transcription.command",
"audio.transcription.timeoutSeconds",
"bindings",
"bindings[].agentId",
"bindings[].match",
"bindings[].match.channel",
"bindings[].match.accountId",
"bindings[].match.peer",
"bindings[].match.peer.kind",
"bindings[].match.peer.id",
"bindings[].match.guildId",
"bindings[].match.teamId",
"bindings[].match.roles",
"broadcast",
"broadcast.strategy",
"broadcast.*",
"commands",
"commands.allowFrom",
"hooks",
"hooks.enabled",
"hooks.path",
"hooks.token",
"hooks.defaultSessionKey",
"hooks.allowRequestSessionKey",
"hooks.allowedSessionKeyPrefixes",
"hooks.allowedAgentIds",
"hooks.maxBodyBytes",
"hooks.transformsDir",
"hooks.mappings",
"hooks.mappings[].action",
"hooks.mappings[].wakeMode",
"hooks.mappings[].channel",
"hooks.mappings[].transform.module",
"hooks.gmail",
"hooks.gmail.pushToken",
"hooks.gmail.tailscale.mode",
"hooks.gmail.thinking",
"hooks.internal",
"hooks.internal.handlers",
"hooks.internal.handlers[].event",
"hooks.internal.handlers[].module",
"hooks.internal.load.extraDirs",
"messages",
"messages.messagePrefix",
"messages.responsePrefix",
"messages.groupChat",
"messages.groupChat.mentionPatterns",
"messages.groupChat.historyLimit",
"messages.queue",
"messages.queue.mode",
"messages.queue.byChannel",
"messages.queue.debounceMs",
"messages.queue.debounceMsByChannel",
"messages.queue.cap",
"messages.queue.drop",
"messages.inbound",
"messages.inbound.byChannel",
"messages.removeAckAfterReply",
"messages.tts",
"channels",
"channels.defaults",
"channels.defaults.groupPolicy",
"channels.defaults.heartbeat",
"channels.defaults.heartbeat.showOk",
"channels.defaults.heartbeat.showAlerts",
"channels.defaults.heartbeat.useIndicator",
"gateway",
"gateway.mode",
"gateway.bind",
"gateway.auth.mode",
"gateway.tailscale.mode",
"gateway.tools.allow",
"gateway.tools.deny",
"gateway.tls.enabled",
"gateway.tls.autoGenerate",
"gateway.http",
"gateway.http.endpoints",
"browser",
"browser.enabled",
"browser.cdpUrl",
"browser.headless",
"browser.noSandbox",
"browser.profiles",
"browser.profiles.*.driver",
"browser.profiles.*.attachOnly",
"tools",
"tools.allow",
"tools.deny",
"tools.exec",
"tools.exec.host",
"tools.exec.security",
"tools.exec.ask",
"tools.exec.node",
"tools.agentToAgent.enabled",
"tools.elevated.enabled",
"tools.elevated.allowFrom",
"tools.subagents.tools",
"tools.sandbox.tools",
"web",
"web.enabled",
"web.heartbeatSeconds",
"web.reconnect",
"web.reconnect.initialMs",
"web.reconnect.maxMs",
"web.reconnect.factor",
"web.reconnect.jitter",
"web.reconnect.maxAttempts",
"discovery",
"discovery.wideArea.enabled",
"discovery.mdns",
"discovery.mdns.mode",
"canvasHost",
"canvasHost.enabled",
"canvasHost.root",
"canvasHost.port",
"canvasHost.liveReload",
"talk",
"talk.voiceId",
"talk.voiceAliases",
"talk.modelId",
"talk.outputFormat",
"talk.interruptOnSpeech",
"meta",
"env",
"env.shellEnv",
"env.shellEnv.enabled",
"env.shellEnv.timeoutMs",
"env.vars",
"wizard",
"wizard.lastRunAt",
"wizard.lastRunVersion",
"wizard.lastRunCommit",
"wizard.lastRunCommand",
"wizard.lastRunMode",
"diagnostics",
"diagnostics.otel",
"diagnostics.cacheTrace",
"logging",
"logging.level",
"logging.file",
"logging.consoleLevel",
"logging.consoleStyle",
"logging.redactSensitive",
"logging.redactPatterns",
"update",
"ui",
"ui.assistant",
"plugins",
"plugins.enabled",
"plugins.allow",
"plugins.deny",
"plugins.load",
"plugins.load.paths",
"plugins.slots",
"plugins.entries",
"plugins.entries.*.enabled",
"plugins.entries.*.apiKey",
"plugins.entries.*.env",
"plugins.entries.*.config",
"plugins.installs",
"auth",
"auth.cooldowns",
"models",
"models.providers",
"models.providers.*.baseUrl",
"models.providers.*.apiKey",
"models.providers.*.api",
"models.providers.*.headers",
"models.providers.*.models",
"models.bedrockDiscovery",
"models.bedrockDiscovery.enabled",
"models.bedrockDiscovery.region",
"models.bedrockDiscovery.providerFilter",
"models.bedrockDiscovery.refreshInterval",
"models.bedrockDiscovery.defaultContextWindow",
"models.bedrockDiscovery.defaultMaxTokens",
"agents",
"agents.defaults",
"agents.list",
"agents.defaults.compaction",
"agents.defaults.compaction.mode",
"agents.defaults.compaction.reserveTokens",
"agents.defaults.compaction.keepRecentTokens",
"agents.defaults.compaction.reserveTokensFloor",
"agents.defaults.compaction.maxHistoryShare",
"agents.defaults.compaction.identifierPolicy",
"agents.defaults.compaction.identifierInstructions",
"agents.defaults.compaction.memoryFlush",
"agents.defaults.compaction.memoryFlush.enabled",
"agents.defaults.compaction.memoryFlush.softThresholdTokens",
"agents.defaults.compaction.memoryFlush.prompt",
"agents.defaults.compaction.memoryFlush.systemPrompt",
] as const;
const ENUM_EXPECTATIONS: Record<string, string[]> = {
"memory.citations": ['"auto"', '"on"', '"off"'],
"memory.backend": ['"builtin"', '"qmd"'],
"memory.qmd.searchMode": ['"query"', '"search"', '"vsearch"'],
"models.mode": ['"merge"', '"replace"'],
"models.providers.*.auth": ['"api-key"', '"token"', '"oauth"', '"aws-sdk"'],
"gateway.reload.mode": ['"off"', '"restart"', '"hot"', '"hybrid"'],
"approvals.exec.mode": ['"session"', '"targets"', '"both"'],
"bindings[].match.peer.kind": ['"direct"', '"group"', '"channel"', '"dm"'],
"broadcast.strategy": ['"parallel"', '"sequential"'],
"hooks.mappings[].action": ['"wake"', '"agent"'],
"hooks.mappings[].wakeMode": ['"now"', '"next-heartbeat"'],
"hooks.gmail.tailscale.mode": ['"off"', '"serve"', '"funnel"'],
"hooks.gmail.thinking": ['"off"', '"minimal"', '"low"', '"medium"', '"high"'],
"messages.queue.mode": [
'"steer"',
'"followup"',
'"collect"',
'"steer-backlog"',
'"steer+backlog"',
'"queue"',
'"interrupt"',
],
"messages.queue.drop": ['"old"', '"new"', '"summarize"'],
"channels.defaults.groupPolicy": ['"open"', '"disabled"', '"allowlist"'],
"gateway.mode": ['"local"', '"remote"'],
"gateway.bind": ['"auto"', '"lan"', '"loopback"', '"custom"', '"tailnet"'],
"gateway.auth.mode": ['"none"', '"token"', '"password"', '"trusted-proxy"'],
"gateway.tailscale.mode": ['"off"', '"serve"', '"funnel"'],
"browser.profiles.*.driver": ['"clawd"', '"extension"'],
"discovery.mdns.mode": ['"off"', '"minimal"', '"full"'],
"wizard.lastRunMode": ['"local"', '"remote"'],
"diagnostics.otel.protocol": ['"http/protobuf"', '"grpc"'],
"logging.level": ['"silent"', '"fatal"', '"error"', '"warn"', '"info"', '"debug"', '"trace"'],
"logging.consoleLevel": [
'"silent"',
'"fatal"',
'"error"',
'"warn"',
'"info"',
'"debug"',
'"trace"',
],
"logging.consoleStyle": ['"pretty"', '"compact"', '"json"'],
"logging.redactSensitive": ['"off"', '"tools"'],
"update.channel": ['"stable"', '"beta"', '"dev"'],
"agents.defaults.compaction.mode": ['"default"', '"safeguard"'],
"agents.defaults.compaction.identifierPolicy": ['"strict"', '"off"', '"custom"'],
};
const TOOLS_HOOKS_TARGET_KEYS = [
"hooks.gmail.account",
"hooks.gmail.allowUnsafeExternalContent",
"hooks.gmail.hookUrl",
"hooks.gmail.includeBody",
"hooks.gmail.label",
"hooks.gmail.model",
"hooks.gmail.serve",
"hooks.gmail.subscription",
"hooks.gmail.tailscale",
"hooks.gmail.topic",
"hooks.internal.entries",
"hooks.internal.installs",
"hooks.internal.load",
"hooks.mappings[].allowUnsafeExternalContent",
"hooks.mappings[].deliver",
"hooks.mappings[].id",
"hooks.mappings[].match",
"hooks.mappings[].messageTemplate",
"hooks.mappings[].model",
"hooks.mappings[].name",
"hooks.mappings[].textTemplate",
"hooks.mappings[].thinking",
"hooks.mappings[].transform",
"tools.alsoAllow",
"tools.byProvider",
"tools.exec.approvalRunningNoticeMs",
"tools.links.enabled",
"tools.links.maxLinks",
"tools.links.models",
"tools.links.scope",
"tools.links.timeoutSeconds",
"tools.media.audio.attachments",
"tools.media.audio.enabled",
"tools.media.audio.language",
"tools.media.audio.maxBytes",
"tools.media.audio.maxChars",
"tools.media.audio.models",
"tools.media.audio.prompt",
"tools.media.audio.scope",
"tools.media.audio.timeoutSeconds",
"tools.media.concurrency",
"tools.media.image.attachments",
"tools.media.image.enabled",
"tools.media.image.maxBytes",
"tools.media.image.maxChars",
"tools.media.image.models",
"tools.media.image.prompt",
"tools.media.image.scope",
"tools.media.image.timeoutSeconds",
"tools.media.models",
"tools.media.video.attachments",
"tools.media.video.enabled",
"tools.media.video.maxBytes",
"tools.media.video.maxChars",
"tools.media.video.models",
"tools.media.video.prompt",
"tools.media.video.scope",
"tools.media.video.timeoutSeconds",
"tools.profile",
] as const;
const CHANNELS_AGENTS_TARGET_KEYS = [
"agents.defaults.memorySearch.chunking.overlap",
"agents.defaults.memorySearch.chunking.tokens",
"agents.defaults.memorySearch.enabled",
"agents.defaults.memorySearch.model",
"agents.defaults.memorySearch.query.maxResults",
"agents.defaults.memorySearch.query.minScore",
"agents.defaults.memorySearch.sync.onSessionStart",
"agents.defaults.memorySearch.sync.watchDebounceMs",
"agents.defaults.workspace",
"agents.list[].tools.alsoAllow",
"agents.list[].tools.byProvider",
"agents.list[].tools.profile",
"channels.bluebubbles",
"channels.discord",
"channels.discord.token",
"channels.imessage",
"channels.imessage.cliPath",
"channels.irc",
"channels.mattermost",
"channels.msteams",
"channels.signal",
"channels.signal.account",
"channels.slack",
"channels.slack.appToken",
"channels.slack.botToken",
"channels.slack.userToken",
"channels.slack.userTokenReadOnly",
"channels.telegram",
"channels.telegram.botToken",
"channels.telegram.capabilities.inlineButtons",
"channels.whatsapp",
] as const;
const FINAL_BACKLOG_TARGET_KEYS = [
"browser.evaluateEnabled",
"browser.remoteCdpHandshakeTimeoutMs",
"browser.remoteCdpTimeoutMs",
"browser.snapshotDefaults",
"browser.snapshotDefaults.mode",
"browser.ssrfPolicy",
"browser.ssrfPolicy.allowPrivateNetwork",
"browser.ssrfPolicy.dangerouslyAllowPrivateNetwork",
"browser.ssrfPolicy.allowedHostnames",
"browser.ssrfPolicy.hostnameAllowlist",
"diagnostics.enabled",
"diagnostics.otel.enabled",
"diagnostics.otel.endpoint",
"diagnostics.otel.flushIntervalMs",
"diagnostics.otel.headers",
"diagnostics.otel.logs",
"diagnostics.otel.metrics",
"diagnostics.otel.sampleRate",
"diagnostics.otel.serviceName",
"diagnostics.otel.traces",
"gateway.remote.password",
"gateway.remote.token",
"skills.load.watch",
"skills.load.watchDebounceMs",
"talk.apiKey",
"ui.assistant.avatar",
"ui.assistant.name",
"ui.seamColor",
] as const;
describe("config help copy quality", () => {
function expectOperationalGuidance(
keys: readonly string[],
guidancePattern: RegExp,
minLength = 80,
) {
for (const key of keys) {
const help = FIELD_HELP[key];
expect(help, `missing help for ${key}`).toBeDefined();
expect(help.length, `help too short for ${key}`).toBeGreaterThanOrEqual(minLength);
expect(
guidancePattern.test(help),
`help should include operational guidance for ${key}`,
).toBe(true);
}
}
it("keeps root section labels and help complete", () => {
for (const key of ROOT_SECTIONS) {
expect(FIELD_LABELS[key], `missing root label for ${key}`).toBeDefined();
expect(FIELD_HELP[key], `missing root help for ${key}`).toBeDefined();
}
});
it("keeps labels in parity for all help keys", () => {
for (const key of Object.keys(FIELD_HELP)) {
expect(FIELD_LABELS[key], `missing label for help key ${key}`).toBeDefined();
}
});
it("covers the target confusing fields with non-trivial explanations", () => {
expectOperationalGuidance(
TARGET_KEYS,
/(default|keep|use|enable|disable|controls|selects|sets|defines)/i,
);
});
it("covers tools/hooks help keys with non-trivial operational guidance", () => {
expectOperationalGuidance(
TOOLS_HOOKS_TARGET_KEYS,
/(default|keep|use|enable|disable|controls|set|sets|increase|lower|prefer|tune|avoid|choose|when)/i,
);
});
it("covers channels/agents help keys with non-trivial operational guidance", () => {
expectOperationalGuidance(
CHANNELS_AGENTS_TARGET_KEYS,
/(default|keep|use|enable|disable|controls|set|sets|increase|lower|prefer|tune|avoid|choose|when)/i,
);
});
it("covers final backlog help keys with non-trivial operational guidance", () => {
expectOperationalGuidance(
FINAL_BACKLOG_TARGET_KEYS,
/(default|keep|use|enable|disable|controls|set|sets|increase|lower|prefer|tune|avoid|choose|when)/i,
);
});
it("documents option behavior for enum-style fields", () => {
for (const [key, options] of Object.entries(ENUM_EXPECTATIONS)) {
const help = FIELD_HELP[key];
expect(help, `missing help for enum key ${key}`).toBeDefined();
for (const token of options) {
expect(help.includes(token), `missing option ${token} in ${key}`).toBe(true);
}
}
});
it("explains memory citations mode semantics", () => {
const help = FIELD_HELP["memory.citations"];
expect(help.includes('"auto"')).toBe(true);
expect(help.includes('"on"')).toBe(true);
expect(help.includes('"off"')).toBe(true);
expect(/always|always shows/i.test(help)).toBe(true);
expect(/hides|hide/i.test(help)).toBe(true);
});
it("includes concrete examples on path and interval fields", () => {
expect(FIELD_HELP["memory.qmd.paths.pattern"].includes("**/*.md")).toBe(true);
expect(FIELD_HELP["memory.qmd.update.interval"].includes("5m")).toBe(true);
expect(FIELD_HELP["memory.qmd.update.embedInterval"].includes("60m")).toBe(true);
expect(FIELD_HELP["agents.defaults.memorySearch.store.path"]).toContain(
"~/.openclaw/memory/{agentId}.sqlite",
);
});
it("documents cron deprecation, migration, and retention formats", () => {
const legacy = FIELD_HELP["cron.webhook"];
expect(/deprecated|legacy/i.test(legacy)).toBe(true);
expect(legacy.includes('delivery.mode="webhook"')).toBe(true);
expect(legacy.includes("delivery.to")).toBe(true);
const retention = FIELD_HELP["cron.sessionRetention"];
expect(retention.includes("24h")).toBe(true);
expect(retention.includes("7d")).toBe(true);
expect(retention.includes("1h30m")).toBe(true);
expect(/false/i.test(retention)).toBe(true);
const token = FIELD_HELP["cron.webhookToken"];
expect(/token|bearer/i.test(token)).toBe(true);
expect(/secret|env|rotate/i.test(token)).toBe(true);
});
it("documents session send-policy examples and prefix semantics", () => {
const rules = FIELD_HELP["session.sendPolicy.rules"];
expect(rules.includes("{ action:")).toBe(true);
expect(rules.includes('"deny"')).toBe(true);
expect(rules.includes('"discord"')).toBe(true);
const keyPrefix = FIELD_HELP["session.sendPolicy.rules[].match.keyPrefix"];
expect(/normalized/i.test(keyPrefix)).toBe(true);
const rawKeyPrefix = FIELD_HELP["session.sendPolicy.rules[].match.rawKeyPrefix"];
expect(/raw|unnormalized/i.test(rawKeyPrefix)).toBe(true);
});
it("documents session maintenance duration/size examples and deprecations", () => {
const pruneAfter = FIELD_HELP["session.maintenance.pruneAfter"];
expect(pruneAfter.includes("30d")).toBe(true);
expect(pruneAfter.includes("12h")).toBe(true);
const rotate = FIELD_HELP["session.maintenance.rotateBytes"];
expect(rotate.includes("10mb")).toBe(true);
expect(rotate.includes("1gb")).toBe(true);
const deprecated = FIELD_HELP["session.maintenance.pruneDays"];
expect(/deprecated/i.test(deprecated)).toBe(true);
expect(deprecated.includes("session.maintenance.pruneAfter")).toBe(true);
const resetRetention = FIELD_HELP["session.maintenance.resetArchiveRetention"];
expect(resetRetention.includes(".reset.")).toBe(true);
expect(/false/i.test(resetRetention)).toBe(true);
const maxDisk = FIELD_HELP["session.maintenance.maxDiskBytes"];
expect(maxDisk.includes("500mb")).toBe(true);
const highWater = FIELD_HELP["session.maintenance.highWaterBytes"];
expect(highWater.includes("80%")).toBe(true);
});
it("documents cron run-log retention controls", () => {
const runLog = FIELD_HELP["cron.runLog"];
expect(runLog.includes("cron/runs")).toBe(true);
const maxBytes = FIELD_HELP["cron.runLog.maxBytes"];
expect(maxBytes.includes("2mb")).toBe(true);
const keepLines = FIELD_HELP["cron.runLog.keepLines"];
expect(keepLines.includes("2000")).toBe(true);
});
it("documents approvals filters and target semantics", () => {
const sessionFilter = FIELD_HELP["approvals.exec.sessionFilter"];
expect(/substring|regex/i.test(sessionFilter)).toBe(true);
expect(sessionFilter.includes("discord:")).toBe(true);
expect(sessionFilter.includes("^agent:ops:")).toBe(true);
const agentFilter = FIELD_HELP["approvals.exec.agentFilter"];
expect(agentFilter.includes("primary")).toBe(true);
expect(agentFilter.includes("ops-agent")).toBe(true);
const targetTo = FIELD_HELP["approvals.exec.targets[].to"];
expect(/channel ID|user ID|thread root/i.test(targetTo)).toBe(true);
expect(/differs|per provider/i.test(targetTo)).toBe(true);
});
it("documents broadcast and audio command examples", () => {
const audioCmd = FIELD_HELP["audio.transcription.command"];
expect(audioCmd.includes("whisper-cli")).toBe(true);
expect(audioCmd.includes("{input}")).toBe(true);
const broadcastMap = FIELD_HELP["broadcast.*"];
expect(/source peer ID/i.test(broadcastMap)).toBe(true);
expect(/destination peer IDs/i.test(broadcastMap)).toBe(true);
});
it("documents hook transform safety and queue behavior options", () => {
const transformModule = FIELD_HELP["hooks.mappings[].transform.module"];
expect(/relative/i.test(transformModule)).toBe(true);
expect(/path traversal|reviewed|controlled/i.test(transformModule)).toBe(true);
const queueMode = FIELD_HELP["messages.queue.mode"];
expect(queueMode.includes('"interrupt"')).toBe(true);
expect(queueMode.includes('"steer+backlog"')).toBe(true);
});
it("documents gateway bind modes and web reconnect semantics", () => {
const bind = FIELD_HELP["gateway.bind"];
expect(bind.includes('"loopback"')).toBe(true);
expect(bind.includes('"tailnet"')).toBe(true);
const reconnect = FIELD_HELP["web.reconnect.maxAttempts"];
expect(/0 means no retries|no retries/i.test(reconnect)).toBe(true);
expect(/failure sequence|retry/i.test(reconnect)).toBe(true);
});
it("documents metadata/admin semantics for logging, wizard, and plugins", () => {
const wizardMode = FIELD_HELP["wizard.lastRunMode"];
expect(wizardMode.includes('"local"')).toBe(true);
expect(wizardMode.includes('"remote"')).toBe(true);
const consoleStyle = FIELD_HELP["logging.consoleStyle"];
expect(consoleStyle.includes('"pretty"')).toBe(true);
expect(consoleStyle.includes('"compact"')).toBe(true);
expect(consoleStyle.includes('"json"')).toBe(true);
const pluginApiKey = FIELD_HELP["plugins.entries.*.apiKey"];
expect(/secret|env|credential/i.test(pluginApiKey)).toBe(true);
const pluginEnv = FIELD_HELP["plugins.entries.*.env"];
expect(/scope|plugin|environment/i.test(pluginEnv)).toBe(true);
});
it("documents auth/model root semantics and provider secret handling", () => {
const providerKey = FIELD_HELP["models.providers.*.apiKey"];
expect(/secret|env|credential/i.test(providerKey)).toBe(true);
const bedrockRefresh = FIELD_HELP["models.bedrockDiscovery.refreshInterval"];
expect(/refresh|seconds|interval/i.test(bedrockRefresh)).toBe(true);
expect(/cost|noise|api/i.test(bedrockRefresh)).toBe(true);
const authCooldowns = FIELD_HELP["auth.cooldowns"];
expect(/cooldown|backoff|retry/i.test(authCooldowns)).toBe(true);
});
it("documents agent compaction safeguards and memory flush behavior", () => {
const mode = FIELD_HELP["agents.defaults.compaction.mode"];
expect(mode.includes('"default"')).toBe(true);
expect(mode.includes('"safeguard"')).toBe(true);
const historyShare = FIELD_HELP["agents.defaults.compaction.maxHistoryShare"];
expect(/0\\.1-0\\.9|fraction|share/i.test(historyShare)).toBe(true);
const identifierPolicy = FIELD_HELP["agents.defaults.compaction.identifierPolicy"];
expect(identifierPolicy.includes('"strict"')).toBe(true);
expect(identifierPolicy.includes('"off"')).toBe(true);
expect(identifierPolicy.includes('"custom"')).toBe(true);
const flush = FIELD_HELP["agents.defaults.compaction.memoryFlush.enabled"];
expect(/pre-compaction|memory flush|token/i.test(flush)).toBe(true);
});
});