From 0842cb71eb63503fcaa1e1ce70875ec43c79e80d Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Wed, 17 Jun 2026 18:20:05 +0800 Subject: [PATCH] refactor(runtime): hide default constants --- src/auto-reply/reply/history-media.ts | 4 ++-- src/auto-reply/reply/session-transcript-replay.test.ts | 7 +++---- src/auto-reply/reply/session-transcript-replay.ts | 2 +- src/auto-reply/reply/typing-mode.ts | 2 +- src/commands/doctor/cron/store-migration.test.ts | 3 ++- src/commitments/config.ts | 2 +- src/commitments/runtime.test.ts | 3 ++- src/cron/normalize.test.ts | 3 ++- src/cron/run-log.test.ts | 5 +++-- src/cron/run-log.ts | 4 ++-- src/cron/service.jobs.test.ts | 3 ++- src/cron/service.jobs.top-of-hour-stagger.test.ts | 3 ++- src/cron/stagger.test.ts | 3 ++- src/cron/stagger.ts | 2 +- src/tasks/task-registry.audit.test.ts | 4 +++- src/tasks/task-registry.test.ts | 4 +++- src/tasks/task-retention.test.ts | 5 +++-- src/tasks/task-retention.ts | 4 ++-- 18 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/auto-reply/reply/history-media.ts b/src/auto-reply/reply/history-media.ts index d35f836ac93b..1a88cdb554d5 100644 --- a/src/auto-reply/reply/history-media.ts +++ b/src/auto-reply/reply/history-media.ts @@ -5,8 +5,8 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coe import type { MsgContext } from "../templating.js"; import type { HistoryEntry, HistoryMediaEntry } from "./history.types.js"; -export const RECENT_HISTORY_IMAGE_TTL_MS = 30 * 60_000; -export const RECENT_HISTORY_IMAGE_LIMIT = 4; +const RECENT_HISTORY_IMAGE_TTL_MS = 30 * 60_000; +const RECENT_HISTORY_IMAGE_LIMIT = 4; export type RecentInboundHistoryImage = { path: string; diff --git a/src/auto-reply/reply/session-transcript-replay.test.ts b/src/auto-reply/reply/session-transcript-replay.test.ts index cde69a122d0e..479904f8dc23 100644 --- a/src/auto-reply/reply/session-transcript-replay.test.ts +++ b/src/auto-reply/reply/session-transcript-replay.test.ts @@ -3,10 +3,9 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { - DEFAULT_REPLAY_MAX_MESSAGES, - replayRecentUserAssistantMessages, -} from "./session-transcript-replay.js"; +import { replayRecentUserAssistantMessages } from "./session-transcript-replay.js"; + +const DEFAULT_REPLAY_MAX_MESSAGES = 6; const j = (obj: unknown): string => `${JSON.stringify(obj)}\n`; diff --git a/src/auto-reply/reply/session-transcript-replay.ts b/src/auto-reply/reply/session-transcript-replay.ts index 81080f352c33..48227f1c4828 100644 --- a/src/auto-reply/reply/session-transcript-replay.ts +++ b/src/auto-reply/reply/session-transcript-replay.ts @@ -5,7 +5,7 @@ import path from "node:path"; import { CURRENT_SESSION_VERSION } from "../../config/sessions/version.js"; /** Tail kept so DM continuity survives silent session rotations. */ -export const DEFAULT_REPLAY_MAX_MESSAGES = 6; +const DEFAULT_REPLAY_MAX_MESSAGES = 6; type SessionRecord = { type?: unknown; diff --git a/src/auto-reply/reply/typing-mode.ts b/src/auto-reply/reply/typing-mode.ts index a22fdba8956d..60ab541c4327 100644 --- a/src/auto-reply/reply/typing-mode.ts +++ b/src/auto-reply/reply/typing-mode.ts @@ -18,7 +18,7 @@ export type TypingModeContext = { }; /** Group chats default to message-triggered typing to avoid noisy indicators. */ -export const DEFAULT_GROUP_TYPING_MODE: TypingMode = "message"; +const DEFAULT_GROUP_TYPING_MODE: TypingMode = "message"; /** Resolves the effective typing mode for the current auto-reply turn. */ export function resolveTypingMode({ diff --git a/src/commands/doctor/cron/store-migration.test.ts b/src/commands/doctor/cron/store-migration.test.ts index 37a50d3d110b..2c784191eca2 100644 --- a/src/commands/doctor/cron/store-migration.test.ts +++ b/src/commands/doctor/cron/store-migration.test.ts @@ -1,8 +1,9 @@ // Cron store migration tests cover doctor migration of persisted cron stores. import { describe, expect, it } from "vitest"; -import { DEFAULT_TOP_OF_HOUR_STAGGER_MS } from "../../../cron/stagger.js"; import { normalizeStoredCronJobs } from "./store-migration.js"; +const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000; + function makeLegacyJob(overrides: Record): Record { return { id: "job-legacy", diff --git a/src/commitments/config.ts b/src/commitments/config.ts index f2b27b32ebed..259a22402d5b 100644 --- a/src/commitments/config.ts +++ b/src/commitments/config.ts @@ -6,7 +6,7 @@ import type { OpenClawConfig } from "../config/config.js"; // heartbeat delivery limits. const DEFAULT_COMMITMENT_EXTRACTION_DEBOUNCE_MS = 15_000; const DEFAULT_COMMITMENT_BATCH_MAX_ITEMS = 8; -export const DEFAULT_COMMITMENT_EXTRACTION_QUEUE_MAX_ITEMS = 64; +const DEFAULT_COMMITMENT_EXTRACTION_QUEUE_MAX_ITEMS = 64; const DEFAULT_COMMITMENT_CONFIDENCE_THRESHOLD = 0.72; const DEFAULT_COMMITMENT_CARE_CONFIDENCE_THRESHOLD = 0.86; const DEFAULT_COMMITMENT_EXTRACTION_TIMEOUT_SECONDS = 45; diff --git a/src/commitments/runtime.test.ts b/src/commitments/runtime.test.ts index e6f7817c161e..8e1ad9659ec7 100644 --- a/src/commitments/runtime.test.ts +++ b/src/commitments/runtime.test.ts @@ -5,7 +5,6 @@ import path from "node:path"; import { afterEach, describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; import { captureEnv, setTestEnvValue } from "../test-utils/env.js"; -import { DEFAULT_COMMITMENT_EXTRACTION_QUEUE_MAX_ITEMS } from "./config.js"; import { configureCommitmentExtractionRuntime, drainCommitmentExtractionQueue, @@ -15,6 +14,8 @@ import { import { loadCommitmentStore } from "./store.js"; import type { CommitmentExtractionBatchResult, CommitmentExtractionItem } from "./types.js"; +const DEFAULT_COMMITMENT_EXTRACTION_QUEUE_MAX_ITEMS = 64; + const runEmbeddedAgentMock = vi.hoisted(() => vi.fn()); const resolveDefaultModelMock = vi.hoisted(() => vi.fn()); diff --git a/src/cron/normalize.test.ts b/src/cron/normalize.test.ts index bf1f6fe04bde..9855d6e3d2db 100644 --- a/src/cron/normalize.test.ts +++ b/src/cron/normalize.test.ts @@ -5,7 +5,8 @@ import { validateCronUpdateParams, } from "../../packages/gateway-protocol/src/index.js"; import { normalizeCronJobCreate, normalizeCronJobPatch } from "./normalize.js"; -import { DEFAULT_TOP_OF_HOUR_STAGGER_MS } from "./stagger.js"; + +const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000; function expectNormalizedAtSchedule(scheduleInput: Record) { const normalized = normalizeCronJobCreate({ diff --git a/src/cron/run-log.test.ts b/src/cron/run-log.test.ts index 8531acf41c1f..7dba7d86897a 100644 --- a/src/cron/run-log.test.ts +++ b/src/cron/run-log.test.ts @@ -6,8 +6,6 @@ import { describe, expect, it } from "vitest"; import { migrateLegacyCronRunLogsToSqlite } from "../commands/doctor/cron/legacy-run-log-migration.js"; import { appendCronRunLog, - DEFAULT_CRON_RUN_LOG_KEEP_LINES, - DEFAULT_CRON_RUN_LOG_MAX_BYTES, getPendingCronRunLogWriteCountForTests, readCronRunLogEntries, readCronRunLogEntriesPage, @@ -15,6 +13,9 @@ import { resolveCronRunLogPruneOptions, } from "./run-log.js"; +const DEFAULT_CRON_RUN_LOG_MAX_BYTES = 2_000_000; +const DEFAULT_CRON_RUN_LOG_KEEP_LINES = 2_000; + describe("cron run log", () => { it("resolves prune options from config with defaults", () => { expect(resolveCronRunLogPruneOptions()).toEqual({ diff --git a/src/cron/run-log.ts b/src/cron/run-log.ts index e1ccddde2449..ac07c5e83425 100644 --- a/src/cron/run-log.ts +++ b/src/cron/run-log.ts @@ -80,9 +80,9 @@ export function isInvalidCronRunLogJobIdError(err: unknown): boolean { const writesByTarget = new Map>(); /** Legacy byte cap kept for config parsing compatibility with older file-backed run logs. */ -export const DEFAULT_CRON_RUN_LOG_MAX_BYTES = 2_000_000; +const DEFAULT_CRON_RUN_LOG_MAX_BYTES = 2_000_000; /** Default SQLite row retention per cron job when no explicit keepLines value is configured. */ -export const DEFAULT_CRON_RUN_LOG_KEEP_LINES = 2_000; +const DEFAULT_CRON_RUN_LOG_KEEP_LINES = 2_000; /** Resolves configured run-log pruning limits while preserving legacy maxBytes parsing. */ export function resolveCronRunLogPruneOptions(cfg?: CronConfig["runLog"]): { diff --git a/src/cron/service.jobs.test.ts b/src/cron/service.jobs.test.ts index 7766444544a0..671a7f4fe2e2 100644 --- a/src/cron/service.jobs.test.ts +++ b/src/cron/service.jobs.test.ts @@ -8,9 +8,10 @@ import { recomputeNextRunsForMaintenance, } from "./service/jobs.js"; import type { CronServiceState } from "./service/state.js"; -import { DEFAULT_TOP_OF_HOUR_STAGGER_MS } from "./stagger.js"; import type { CronJob, CronJobPatch } from "./types.js"; +const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000; + function expectCronStaggerMs(job: CronJob, expected: number): void { expect(job.schedule.kind).toBe("cron"); if (job.schedule.kind === "cron") { diff --git a/src/cron/service.jobs.top-of-hour-stagger.test.ts b/src/cron/service.jobs.top-of-hour-stagger.test.ts index 895a344a65f4..271f36f56930 100644 --- a/src/cron/service.jobs.top-of-hour-stagger.test.ts +++ b/src/cron/service.jobs.top-of-hour-stagger.test.ts @@ -2,9 +2,10 @@ import crypto from "node:crypto"; import { describe, expect, it, vi } from "vitest"; import { computeJobNextRunAtMs } from "./service/jobs.js"; -import { DEFAULT_TOP_OF_HOUR_STAGGER_MS } from "./stagger.js"; import type { CronJob } from "./types.js"; +const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000; + function stableOffsetMs(jobId: string, windowMs: number) { const digest = crypto.createHash("sha256").update(jobId).digest(); return digest.readUInt32BE(0) % windowMs; diff --git a/src/cron/stagger.test.ts b/src/cron/stagger.test.ts index ee724353fd8d..51b655a04026 100644 --- a/src/cron/stagger.test.ts +++ b/src/cron/stagger.test.ts @@ -1,12 +1,13 @@ // Cron stagger tests cover deterministic schedule spreading across jobs. import { describe, expect, it } from "vitest"; import { - DEFAULT_TOP_OF_HOUR_STAGGER_MS, isRecurringTopOfHourCronExpr, normalizeCronStaggerMs, resolveCronStaggerMs, } from "./stagger.js"; +const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000; + describe("cron stagger helpers", () => { it("detects recurring top-of-hour cron expressions for 5-field and 6-field cron", () => { expect(isRecurringTopOfHourCronExpr("0 * * * *")).toBe(true); diff --git a/src/cron/stagger.ts b/src/cron/stagger.ts index 518901387fd0..5457895a4563 100644 --- a/src/cron/stagger.ts +++ b/src/cron/stagger.ts @@ -3,7 +3,7 @@ import { parseStrictNonNegativeInteger } from "../infra/parse-finite-number.js"; import type { CronSchedule } from "./types.js"; /** Default jitter window applied to recurring top-of-hour cron schedules. */ -export const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000; +const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000; function parseCronFields(expr: string) { return expr.trim().split(/\s+/).filter(Boolean); diff --git a/src/tasks/task-registry.audit.test.ts b/src/tasks/task-registry.audit.test.ts index 1d6dbef098f1..035e9c428c7f 100644 --- a/src/tasks/task-registry.audit.test.ts +++ b/src/tasks/task-registry.audit.test.ts @@ -7,7 +7,9 @@ import { summarizeTaskAuditFindings, } from "./task-registry.audit.js"; import type { TaskRecord } from "./task-registry.types.js"; -import { DEFAULT_TASK_RETENTION_MS, LOST_TASK_RETENTION_MS } from "./task-retention.js"; + +const DEFAULT_TASK_RETENTION_MS = 7 * 24 * 60 * 60_000; +const LOST_TASK_RETENTION_MS = 24 * 60 * 60_000; function createTask(partial: Partial): TaskRecord { return { diff --git a/src/tasks/task-registry.test.ts b/src/tasks/task-registry.test.ts index d2d899966f44..ffaa8cb317be 100644 --- a/src/tasks/task-registry.test.ts +++ b/src/tasks/task-registry.test.ts @@ -72,7 +72,9 @@ import { } from "./task-registry.maintenance.js"; import { configureTaskRegistryRuntime } from "./task-registry.store.js"; import type { TaskDeliveryState, TaskRecord } from "./task-registry.types.js"; -import { DEFAULT_TASK_RETENTION_MS, LOST_TASK_RETENTION_MS } from "./task-retention.js"; + +const DEFAULT_TASK_RETENTION_MS = 7 * 24 * 60 * 60_000; +const LOST_TASK_RETENTION_MS = 24 * 60 * 60_000; function createTaskRecord(params: Parameters[0]): TaskRecord { const task = createTaskRecordOrNull(params); diff --git a/src/tasks/task-retention.test.ts b/src/tasks/task-retention.test.ts index 58a4fd2b4a2e..22a8dde74a08 100644 --- a/src/tasks/task-retention.test.ts +++ b/src/tasks/task-retention.test.ts @@ -1,13 +1,14 @@ // Covers task retention pruning and stale-task cleanup windows. import { describe, expect, it } from "vitest"; import { - DEFAULT_TASK_RETENTION_MS, - LOST_TASK_RETENTION_MS, resolveEffectiveTaskCleanupAfter, resolveTaskCleanupAfter, resolveTaskRetentionMs, } from "./task-retention.js"; +const DEFAULT_TASK_RETENTION_MS = 7 * 24 * 60 * 60_000; +const LOST_TASK_RETENTION_MS = 24 * 60 * 60_000; + describe("task retention", () => { it("keeps lost tasks on a shorter retention window", () => { expect(resolveTaskRetentionMs("lost")).toBe(LOST_TASK_RETENTION_MS); diff --git a/src/tasks/task-retention.ts b/src/tasks/task-retention.ts index 1033dd44a3d4..92b06060ff51 100644 --- a/src/tasks/task-retention.ts +++ b/src/tasks/task-retention.ts @@ -2,8 +2,8 @@ import type { TaskRecord, TaskStatus } from "./task-registry.types.js"; /** Default retention for terminal task records before maintenance prunes them. */ -export const DEFAULT_TASK_RETENTION_MS = 7 * 24 * 60 * 60_000; -export const LOST_TASK_RETENTION_MS = 24 * 60 * 60_000; +const DEFAULT_TASK_RETENTION_MS = 7 * 24 * 60 * 60_000; +const LOST_TASK_RETENTION_MS = 24 * 60 * 60_000; export function resolveTaskRetentionMs(status: TaskStatus): number { return status === "lost" ? LOST_TASK_RETENTION_MS : DEFAULT_TASK_RETENTION_MS;