refactor(cron): replace store-load double casts with raw-boundary record types

ensureLoaded cast persisted rows through `as unknown as CronJob[]` and then
back to `Record<string, unknown>` per item, which mislabeled unvalidated data
as CronJob. Treat the rows as raw records at the store boundary and apply a
single trusted CronJob cast only after getInvalidPersistedCronJobReason passes,
preserving the normalize/validate/quarantine flow. Drops two redundant casts
and two lines with no behavior change.

Fixes #91314

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit e9e494c7fe)
This commit is contained in:
ly-wang19
2026-06-08 18:44:40 +08:00
committed by Vincent Koc
parent 22bda60cbe
commit 303873e835

View File

@@ -104,13 +104,13 @@ export async function ensureLoaded(
previousJobsById.set(job.id, job);
}
const loaded = await loadCronJobsStoreWithConfigJobs(state.deps.storePath);
const loadedJobs = (loaded.store.jobs ?? []) as unknown as CronJob[];
// Persisted cron rows are validated lazily, so treat them as raw records at the
// store boundary and only trust the CronJob shape after validation below.
const loadedJobs = (loaded.store.jobs ?? []) as unknown as Record<string, unknown>[];
const jobs: CronJob[] = [];
const quarantinedConfigJobs: QuarantinedCronConfigJob[] = [...loaded.invalidConfigRows];
for (const [index, job] of loadedJobs.entries()) {
const decodedRaw = job as unknown as Record<string, unknown>;
const rawConfigJob = loaded.configJobs[index] ?? structuredClone(decodedRaw);
const raw = decodedRaw;
for (const [index, raw] of loadedJobs.entries()) {
const rawConfigJob = loaded.configJobs[index] ?? structuredClone(raw);
const sourceIndex = loaded.configJobIndexes[index] ?? index;
const runtimeEntry = loaded.configJobRuntimeEntries[index];
// Accept old `jobId` rows at the raw boundary only; the in-memory store
@@ -129,11 +129,8 @@ export async function ensureLoaded(
"cron: job has invalid persisted sessionTarget; run openclaw doctor --fix to repair",
);
}
const hydrated =
normalized && typeof normalized === "object" ? (normalized as unknown as CronJob) : job;
const invalidReason = getInvalidPersistedCronJobReason(
hydrated as unknown as Record<string, unknown>,
);
const hydratedRaw = normalized ?? raw;
const invalidReason = getInvalidPersistedCronJobReason(hydratedRaw);
if (invalidReason) {
const quarantineEntry: QuarantinedCronConfigJob = {
sourceIndex,
@@ -157,6 +154,8 @@ export async function ensureLoaded(
warnInvalidPersistedCronJob({ state, raw, index: sourceIndex, reason: invalidReason });
continue;
}
// Validated above, so the raw record is now a trusted CronJob.
const hydrated = hydratedRaw as unknown as CronJob;
jobs.push(hydrated);
invalidateStaleNextRunOnScheduleChange({ previousJobsById, hydrated });
}