tests: cron coverage and NO_REPLY delivery fixes (#53366)

* tools: extend seam audit inventory

* tools: audit cron seam coverage gaps

* test: add cron seam coverage tests

* fix: avoid marking NO_REPLY cron deliveries as delivered

* fix: clean up delete-after-run NO_REPLY cron sessions
This commit is contained in:
Tak Hoffman
2026-03-23 22:52:13 -05:00
committed by GitHub
parent 6142fc1d94
commit 50d996a6ec
8 changed files with 662 additions and 35 deletions

View File

@@ -13,7 +13,7 @@ const testRoot = path.join(repoRoot, "test");
const workspacePackagePaths = ["ui/package.json"];
const MAX_SCAN_BYTES = 2 * 1024 * 1024;
const compareStrings = (left, right) => left.localeCompare(right);
const HELP_TEXT = `Usage: node scripts/audit-seams.mjs [--help]
export const HELP_TEXT = `Usage: node scripts/audit-seams.mjs [--help]
Audit repo seam inventory and emit JSON to stdout.
@@ -22,7 +22,10 @@ Sections:
overlapFiles Production files that touch multiple seam families
optionalClusterStaticLeaks Optional extension/plugin clusters referenced from the static graph
missingPackages Workspace packages whose deps are not mirrored at the root
seamTestInventory High-signal seam candidates with nearby-test gap signals
seamTestInventory High-signal seam candidates with nearby-test gap signals,
including cron orchestration seams for agent handoff,
outbound/media delivery, heartbeat/followup handoff,
and scheduler state crossings
Notes:
- Output is JSON only.
@@ -531,7 +534,135 @@ function stemFromRelativePath(relativePath) {
return relativePath.replace(/\.(m|c)?[jt]sx?$/, "");
}
function describeSeamKinds(relativePath, source) {
function splitNameTokens(name) {
return name
.split(/[^a-zA-Z0-9]+/)
.map((token) => token.trim().toLowerCase())
.filter(Boolean);
}
function escapeForRegExp(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function hasImportSource(source, specifier) {
const escaped = escapeForRegExp(specifier);
return new RegExp(`from\\s+["']${escaped}["']|import\\s*\\(\\s*["']${escaped}["']\\s*\\)`).test(
source,
);
}
function hasAnyImportSource(source, specifiers) {
return specifiers.some((specifier) => hasImportSource(source, specifier));
}
function isCronProductionPath(relativePath) {
return relativePath.startsWith("src/cron/") && isProductionLikeFile(relativePath);
}
function describeCronSeamKinds(relativePath, source) {
if (!isCronProductionPath(relativePath)) {
return [];
}
const seamKinds = [];
const importsAgentRunner = hasAnyImportSource(source, [
"../../agents/cli-runner.js",
"../../agents/pi-embedded.js",
"../../agents/model-fallback.js",
"../../agents/subagent-registry.js",
"../../infra/agent-events.js",
]);
const importsOutboundDelivery = hasAnyImportSource(source, [
"../infra/outbound/deliver.js",
"../../infra/outbound/deliver.js",
"../infra/outbound/session-context.js",
"../../infra/outbound/session-context.js",
"../infra/outbound/identity.js",
"../../infra/outbound/identity.js",
"../cli/outbound-send-deps.js",
"../../cli/outbound-send-deps.js",
]);
const importsHeartbeat = hasAnyImportSource(source, [
"../auto-reply/heartbeat.js",
"../../auto-reply/heartbeat.js",
"../infra/heartbeat-wake.js",
"../../infra/heartbeat-wake.js",
]);
const importsFollowup = hasAnyImportSource(source, [
"./subagent-followup.js",
"../../agents/subagent-registry.js",
"../../agents/tools/agent-step.js",
"../../gateway/call.js",
]);
const importsSchedulerModules =
relativePath.startsWith("src/cron/service/") &&
hasAnyImportSource(source, [
"./jobs.js",
"./store.js",
"./timer.js",
"./state.js",
"../schedule.js",
"../store.js",
"../run-log.js",
]);
if (
importsAgentRunner &&
/\brunCliAgent\b|\brunEmbeddedPiAgent\b|\brunWithModelFallback\b|\bregisterAgentRunContext\b/.test(
source,
)
) {
seamKinds.push("cron-agent-handoff");
}
if (
importsOutboundDelivery &&
/\bdeliverOutboundPayloads\b|\bbuildOutboundSessionContext\b|\bresolveAgentOutboundIdentity\b/.test(
source,
)
) {
seamKinds.push("cron-outbound-delivery");
}
if (
importsHeartbeat &&
/\bstripHeartbeatToken\b|\bHeartbeat\b|\bheartbeat\b|\bnext-heartbeat\b/.test(source)
) {
seamKinds.push("cron-heartbeat-handoff");
}
if (
importsSchedulerModules &&
/\bensureLoaded\b|\bpersist\b|\barmTimer\b|\brunMissedJobs\b|\bcomputeJobNextRunAtMs\b|\brecomputeNextRuns\b|\bnextWakeAtMs\b/.test(
source,
)
) {
seamKinds.push("cron-scheduler-state");
}
if (
importsOutboundDelivery &&
/\bmediaUrl\b|\bmediaUrls\b|\bfilename\b|\baudioAsVoice\b|\bdeliveryPayloads\b|\bdeliveryPayloadHasStructuredContent\b/.test(
source,
)
) {
seamKinds.push("cron-media-delivery");
}
if (
importsFollowup &&
/\bwaitForDescendantSubagentSummary\b|\breadDescendantSubagentFallbackReply\b|\bexpectsSubagentFollowup\b|\bcallGateway\b|\blistDescendantRunsForRequester\b/.test(
source,
)
) {
seamKinds.push("cron-followup-handoff");
}
return seamKinds;
}
export function describeSeamKinds(relativePath, source) {
const seamKinds = [];
const isReplyDeliveryPath =
/reply-delivery|reply-dispatcher|deliver-reply|reply\/.*delivery|monitor\/(?:replies|deliver|native-command)|outbound\/deliver|outbound\/message/.test(
@@ -565,11 +696,12 @@ function describeSeamKinds(relativePath, source) {
}
if (
isReplyDeliveryPath &&
/blockStreamingEnabled|directlySentBlockKeys/.test(source) &&
/blockStreamingEnabled|directlySentBlockKeys|resolveSendableOutboundReplyParts/.test(source) &&
/\bmediaUrl\b|\bmediaUrls\b/.test(source)
) {
seamKinds.push("streaming-media-handoff");
}
seamKinds.push(...describeCronSeamKinds(relativePath, source));
return [...new Set(seamKinds)].toSorted(compareStrings);
}
@@ -593,17 +725,6 @@ async function buildTestIndex(testFiles) {
);
}
function splitNameTokens(name) {
return name
.split(/[^a-zA-Z0-9]+/)
.map((token) => token.trim().toLowerCase())
.filter(Boolean);
}
function escapeForRegExp(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function hasExecutableImportReference(source, importPath) {
const escapedImportPath = escapeForRegExp(importPath);
const suffix = String.raw`(?:\.[^"'\\\`]+)?`;
@@ -697,7 +818,7 @@ function findRelatedTests(relativePath, testIndex) {
});
}
function determineSeamTestStatus(seamKinds, relatedTestMatches) {
export function determineSeamTestStatus(seamKinds, relatedTestMatches) {
if (relatedTestMatches.length === 0) {
return {
status: "gap",
@@ -709,7 +830,13 @@ function determineSeamTestStatus(seamKinds, relatedTestMatches) {
if (
seamKinds.includes("reply-delivery-media") ||
seamKinds.includes("streaming-media-handoff") ||
seamKinds.includes("tool-result-media")
seamKinds.includes("tool-result-media") ||
seamKinds.includes("cron-agent-handoff") ||
seamKinds.includes("cron-outbound-delivery") ||
seamKinds.includes("cron-heartbeat-handoff") ||
seamKinds.includes("cron-scheduler-state") ||
seamKinds.includes("cron-media-delivery") ||
seamKinds.includes("cron-followup-handoff")
) {
return {
status: "partial",
@@ -765,22 +892,29 @@ async function buildSeamTestInventory() {
});
}
const args = new Set(process.argv.slice(2));
if (args.has("--help") || args.has("-h")) {
process.stdout.write(`${HELP_TEXT}\n`);
process.exit(0);
export async function main(argv = process.argv.slice(2)) {
const args = new Set(argv);
if (args.has("--help") || args.has("-h")) {
process.stdout.write(`${HELP_TEXT}\n`);
return;
}
await collectWorkspacePackagePaths();
const inventory = await collectCorePluginSdkImports();
const optionalClusterStaticLeaks = await collectOptionalClusterStaticLeaks();
const staticLeakClusters = new Set(optionalClusterStaticLeaks.map((entry) => entry.cluster));
const result = {
duplicatedSeamFamilies: buildDuplicatedSeamFamilies(inventory),
overlapFiles: buildOverlapFiles(inventory),
optionalClusterStaticLeaks: buildOptionalClusterStaticLeaks(optionalClusterStaticLeaks),
missingPackages: await buildMissingPackages({ staticLeakClusters }),
seamTestInventory: await buildSeamTestInventory(),
};
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
}
await collectWorkspacePackagePaths();
const inventory = await collectCorePluginSdkImports();
const optionalClusterStaticLeaks = await collectOptionalClusterStaticLeaks();
const staticLeakClusters = new Set(optionalClusterStaticLeaks.map((entry) => entry.cluster));
const result = {
duplicatedSeamFamilies: buildDuplicatedSeamFamilies(inventory),
overlapFiles: buildOverlapFiles(inventory),
optionalClusterStaticLeaks: buildOptionalClusterStaticLeaks(optionalClusterStaticLeaks),
missingPackages: await buildMissingPackages({ staticLeakClusters }),
seamTestInventory: await buildSeamTestInventory(),
};
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
const entryFilePath = process.argv[1] ? path.resolve(process.argv[1]) : null;
if (entryFilePath === fileURLToPath(import.meta.url)) {
await main();
}

View File

@@ -4,6 +4,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
import * as modelSelection from "../agents/model-selection.js";
import { runSubagentAnnounceFlow } from "../agents/subagent-announce.js";
import type { CliDeps } from "../cli/deps.js";
import { callGateway } from "../gateway/call.js";
import {
createCliDeps,
expectDirectTelegramDelivery,
@@ -407,6 +408,60 @@ describe("runCronIsolatedAgentTurn", () => {
});
});
it("does not mark NO_REPLY output as delivered when no direct send occurs", async () => {
await withTelegramAnnounceFixture(async ({ home, storePath, deps }) => {
mockAgentPayloads([{ text: "NO_REPLY" }]);
const res = await runTelegramAnnounceTurn({
home,
storePath,
deps,
delivery: { mode: "announce", channel: "telegram", to: "123" },
});
expect(res.status).toBe("ok");
expect(res.delivered).toBe(false);
expect(runSubagentAnnounceFlow).not.toHaveBeenCalled();
expect(deps.sendMessageTelegram).not.toHaveBeenCalled();
});
});
it("deletes the isolated cron session after NO_REPLY when deleteAfterRun is enabled", async () => {
await withTelegramAnnounceFixture(async ({ home, storePath, deps }) => {
mockAgentPayloads([{ text: "NO_REPLY" }]);
vi.mocked(callGateway).mockClear();
const res = await runCronIsolatedAgentTurn({
cfg: makeCfg(home, storePath, {
channels: { telegram: { botToken: "t-1" } },
}),
deps,
job: {
...makeJob({ kind: "agentTurn", message: "do it" }),
deleteAfterRun: true,
delivery: { mode: "announce", channel: "telegram", to: "123" },
},
message: "do it",
sessionKey: "cron:job-1",
lane: "cron",
});
expect(res.status).toBe("ok");
expect(res.delivered).toBe(false);
expect(deps.sendMessageTelegram).not.toHaveBeenCalled();
expect(callGateway).toHaveBeenCalledTimes(1);
expect(callGateway).toHaveBeenCalledWith(
expect.objectContaining({
method: "sessions.delete",
params: expect.objectContaining({
key: "agent:main:cron:job-1",
deleteTranscript: true,
emitLifecycleHooks: false,
}),
}),
);
});
});
it("fails when structured direct delivery fails and best-effort is disabled", async () => {
await expectStructuredTelegramFailure({
payload: { text: "hello from cron", mediaUrl: "https://example.com/img.png" },

View File

@@ -538,11 +538,12 @@ export async function dispatchCronDelivery(
});
}
if (synthesizedText.toUpperCase() === SILENT_REPLY_TOKEN.toUpperCase()) {
await cleanupDirectCronSessionIfNeeded();
return params.withRunSession({
status: "ok",
summary,
outputText,
delivered: true,
delivered: false,
...params.telemetry,
});
}

View File

@@ -0,0 +1,80 @@
import fs from "node:fs/promises";
import { describe, expect, it, vi } from "vitest";
import { setupCronServiceSuite, writeCronStoreSnapshot } from "../service.test-harness.js";
import type { CronJob } from "../types.js";
import { start, stop } from "./ops.js";
import { createCronServiceState } from "./state.js";
const { logger, makeStorePath } = setupCronServiceSuite({
prefix: "cron-service-ops-seam",
});
function createInterruptedMainJob(now: number): CronJob {
return {
id: "startup-interrupted",
name: "startup interrupted",
enabled: true,
createdAtMs: now - 86_400_000,
updatedAtMs: now - 30 * 60_000,
schedule: { kind: "cron", expr: "0 * * * *", tz: "UTC" },
sessionTarget: "main",
wakeMode: "next-heartbeat",
payload: { kind: "systemEvent", text: "should not replay on startup" },
state: {
nextRunAtMs: now - 60_000,
runningAtMs: now - 30 * 60_000,
},
};
}
describe("cron service ops seam coverage", () => {
it("start clears stale running markers, skips startup replay, persists, and arms the timer", async () => {
const { storePath } = await makeStorePath();
const now = Date.parse("2026-03-23T12:00:00.000Z");
const enqueueSystemEvent = vi.fn();
const requestHeartbeatNow = vi.fn();
const timeoutSpy = vi.spyOn(globalThis, "setTimeout");
await writeCronStoreSnapshot({
storePath,
jobs: [createInterruptedMainJob(now)],
});
const state = createCronServiceState({
storePath,
cronEnabled: true,
log: logger,
nowMs: () => now,
enqueueSystemEvent,
requestHeartbeatNow,
runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" as const })),
});
await start(state);
expect(logger.warn).toHaveBeenCalledWith(
expect.objectContaining({ jobId: "startup-interrupted" }),
"cron: clearing stale running marker on startup",
);
expect(enqueueSystemEvent).not.toHaveBeenCalled();
expect(requestHeartbeatNow).not.toHaveBeenCalled();
expect(state.timer).not.toBeNull();
const persisted = JSON.parse(await fs.readFile(storePath, "utf8")) as {
jobs: CronJob[];
};
const job = persisted.jobs[0];
expect(job).toBeDefined();
expect(job?.state.runningAtMs).toBeUndefined();
expect(job?.state.lastStatus).toBeUndefined();
expect((job?.state.nextRunAtMs ?? 0) > now).toBe(true);
const delays = timeoutSpy.mock.calls
.map(([, delay]) => delay)
.filter((delay): delay is number => typeof delay === "number");
expect(delays.some((delay) => delay > 0)).toBe(true);
timeoutSpy.mockRestore();
stop(state);
});
});

View File

@@ -0,0 +1,70 @@
import { describe, expect, it, vi } from "vitest";
import { createCronServiceState } from "./state.js";
describe("cron service state seam coverage", () => {
it("threads heartbeat and session-store dependencies into internal state", () => {
const nowMs = vi.fn(() => 123_456);
const enqueueSystemEvent = vi.fn();
const requestHeartbeatNow = vi.fn();
const runHeartbeatOnce = vi.fn();
const resolveSessionStorePath = vi.fn((agentId?: string) => `/tmp/${agentId ?? "main"}.json`);
const state = createCronServiceState({
nowMs,
log: {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
},
storePath: "/tmp/cron/jobs.json",
cronEnabled: true,
defaultAgentId: "ops",
sessionStorePath: "/tmp/sessions.json",
resolveSessionStorePath,
enqueueSystemEvent,
requestHeartbeatNow,
runHeartbeatOnce,
runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" as const })),
});
expect(state.store).toBeNull();
expect(state.timer).toBeNull();
expect(state.running).toBe(false);
expect(state.warnedDisabled).toBe(false);
expect(state.storeLoadedAtMs).toBeNull();
expect(state.storeFileMtimeMs).toBeNull();
expect(state.deps.storePath).toBe("/tmp/cron/jobs.json");
expect(state.deps.cronEnabled).toBe(true);
expect(state.deps.defaultAgentId).toBe("ops");
expect(state.deps.sessionStorePath).toBe("/tmp/sessions.json");
expect(state.deps.resolveSessionStorePath).toBe(resolveSessionStorePath);
expect(state.deps.enqueueSystemEvent).toBe(enqueueSystemEvent);
expect(state.deps.requestHeartbeatNow).toBe(requestHeartbeatNow);
expect(state.deps.runHeartbeatOnce).toBe(runHeartbeatOnce);
expect(state.deps.nowMs()).toBe(123_456);
});
it("defaults nowMs to Date.now when not provided", () => {
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(789_000);
const state = createCronServiceState({
log: {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
},
storePath: "/tmp/cron/jobs.json",
cronEnabled: false,
enqueueSystemEvent: vi.fn(),
requestHeartbeatNow: vi.fn(),
runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" as const })),
});
expect(state.deps.nowMs()).toBe(789_000);
nowSpy.mockRestore();
});
});

View File

@@ -0,0 +1,101 @@
import fs from "node:fs/promises";
import path from "node:path";
import { describe, expect, it, vi } from "vitest";
import { setupCronServiceSuite } from "../service.test-harness.js";
import { createCronServiceState } from "./state.js";
import { ensureLoaded, persist } from "./store.js";
const { logger, makeStorePath } = setupCronServiceSuite({
prefix: "cron-service-store-seam",
});
describe("cron service store seam coverage", () => {
it("loads, normalizes legacy stored jobs, recomputes next runs, and persists the migrated shape", async () => {
const { storePath } = await makeStorePath();
const now = Date.parse("2026-03-23T12:00:00.000Z");
await fs.mkdir(path.dirname(storePath), { recursive: true });
await fs.writeFile(
storePath,
JSON.stringify(
{
version: 1,
jobs: [
{
id: "legacy-current-job",
name: "legacy current job",
enabled: true,
createdAtMs: now - 60_000,
updatedAtMs: now - 60_000,
schedule: { kind: "every", everyMs: 60_000 },
sessionTarget: "current",
wakeMode: "next-heartbeat",
message: "legacy message-only payload",
provider: "telegram",
to: "123",
deliver: true,
state: {},
},
],
},
null,
2,
),
"utf8",
);
const state = createCronServiceState({
storePath,
cronEnabled: true,
log: logger,
nowMs: () => now,
enqueueSystemEvent: vi.fn(),
requestHeartbeatNow: vi.fn(),
runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" as const })),
});
await ensureLoaded(state);
const job = state.store?.jobs[0];
expect(job).toBeDefined();
expect(job?.sessionTarget).toBe("isolated");
expect(job?.payload.kind).toBe("agentTurn");
if (job?.payload.kind === "agentTurn") {
expect(job.payload.message).toBe("legacy message-only payload");
expect(job.payload.channel).toBeUndefined();
expect(job.payload.to).toBeUndefined();
expect(job.payload.deliver).toBeUndefined();
}
expect(job?.delivery).toMatchObject({
mode: "announce",
channel: "telegram",
to: "123",
});
expect(job?.state.nextRunAtMs).toBe(now);
const persisted = JSON.parse(await fs.readFile(storePath, "utf8")) as {
jobs: Array<Record<string, unknown>>;
};
const persistedJob = persisted.jobs[0];
expect(persistedJob?.message).toBeUndefined();
expect(persistedJob?.provider).toBeUndefined();
expect(persistedJob?.to).toBeUndefined();
expect(persistedJob?.deliver).toBeUndefined();
expect(persistedJob?.payload).toMatchObject({
kind: "agentTurn",
message: "legacy message-only payload",
});
expect(persistedJob?.delivery).toMatchObject({
mode: "announce",
channel: "telegram",
to: "123",
});
const firstMtime = state.storeFileMtimeMs;
expect(typeof firstMtime).toBe("number");
await persist(state);
expect(typeof state.storeFileMtimeMs).toBe("number");
expect((state.storeFileMtimeMs ?? 0) >= (firstMtime ?? 0)).toBe(true);
});
});

View File

@@ -0,0 +1,80 @@
import fs from "node:fs/promises";
import { describe, expect, it, vi } from "vitest";
import { setupCronServiceSuite, writeCronStoreSnapshot } from "../../cron/service.test-harness.js";
import { createCronServiceState } from "../../cron/service/state.js";
import { onTimer } from "../../cron/service/timer.js";
import type { CronJob } from "../../cron/types.js";
const { logger, makeStorePath } = setupCronServiceSuite({
prefix: "cron-service-timer-seam",
});
function createDueMainJob(params: { now: number; wakeMode: CronJob["wakeMode"] }): CronJob {
return {
id: "main-heartbeat-job",
name: "main heartbeat job",
enabled: true,
createdAtMs: params.now - 60_000,
updatedAtMs: params.now - 60_000,
schedule: { kind: "every", everyMs: 60_000, anchorMs: params.now - 60_000 },
sessionTarget: "main",
wakeMode: params.wakeMode,
payload: { kind: "systemEvent", text: "heartbeat seam tick" },
sessionKey: "agent:main:main",
state: { nextRunAtMs: params.now - 1 },
};
}
describe("cron service timer seam coverage", () => {
it("persists the next schedule and hands off next-heartbeat main jobs", async () => {
const { storePath } = await makeStorePath();
const now = Date.parse("2026-03-23T12:00:00.000Z");
const enqueueSystemEvent = vi.fn();
const requestHeartbeatNow = vi.fn();
const timeoutSpy = vi.spyOn(globalThis, "setTimeout");
await writeCronStoreSnapshot({
storePath,
jobs: [createDueMainJob({ now, wakeMode: "next-heartbeat" })],
});
const state = createCronServiceState({
storePath,
cronEnabled: true,
log: logger,
nowMs: () => now,
enqueueSystemEvent,
requestHeartbeatNow,
runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" as const })),
});
await onTimer(state);
expect(enqueueSystemEvent).toHaveBeenCalledWith("heartbeat seam tick", {
agentId: undefined,
sessionKey: "agent:main:main",
contextKey: "cron:main-heartbeat-job",
});
expect(requestHeartbeatNow).toHaveBeenCalledWith({
reason: "cron:main-heartbeat-job",
agentId: undefined,
sessionKey: "agent:main:main",
});
const persisted = JSON.parse(await fs.readFile(storePath, "utf8")) as {
jobs: CronJob[];
};
const job = persisted.jobs[0];
expect(job).toBeDefined();
expect(job?.state.lastStatus).toBe("ok");
expect(job?.state.runningAtMs).toBeUndefined();
expect(job?.state.nextRunAtMs).toBe(now + 60_000);
const delays = timeoutSpy.mock.calls
.map(([, delay]) => delay)
.filter((delay): delay is number => typeof delay === "number");
expect(delays).toContain(60_000);
timeoutSpy.mockRestore();
});
});

View File

@@ -0,0 +1,106 @@
import { describe, expect, it } from "vitest";
import {
HELP_TEXT,
describeSeamKinds,
determineSeamTestStatus,
} from "../../scripts/audit-seams.mjs";
describe("audit-seams cron seam classification", () => {
it("detects cron agent handoff and outbound delivery boundaries", () => {
const source = `
import { runCliAgent } from "../../agents/cli-runner.js";
import { runWithModelFallback } from "../../agents/model-fallback.js";
import { registerAgentRunContext } from "../../infra/agent-events.js";
import { deliverOutboundPayloads } from "../../infra/outbound/deliver.js";
import { buildOutboundSessionContext } from "../../infra/outbound/session-context.js";
export async function runCronIsolatedAgentTurn() {
registerAgentRunContext({});
await runWithModelFallback(() => runCliAgent({}));
await deliverOutboundPayloads({ payloads: [{ text: "done" }] });
return buildOutboundSessionContext({});
}
`;
expect(describeSeamKinds("src/cron/isolated-agent/run.ts", source)).toEqual([
"cron-agent-handoff",
"cron-outbound-delivery",
]);
});
it("detects scheduler-state seams in cron service orchestration", () => {
const source = `
import { recomputeNextRuns, computeJobNextRunAtMs } from "./jobs.js";
import { ensureLoaded, persist } from "./store.js";
import { armTimer, runMissedJobs } from "./timer.js";
export async function start(state) {
await ensureLoaded(state);
recomputeNextRuns(state);
await persist(state);
armTimer(state);
await runMissedJobs(state);
return computeJobNextRunAtMs(state.store.jobs[0], Date.now());
}
`;
expect(describeSeamKinds("src/cron/service/ops.ts", source)).toContain("cron-scheduler-state");
});
it("detects heartbeat, media, and followup handoff seams", () => {
const source = `
import { stripHeartbeatToken } from "../../auto-reply/heartbeat.js";
import { deliverOutboundPayloads } from "../../infra/outbound/deliver.js";
import { callGateway } from "../../gateway/call.js";
import { waitForDescendantSubagentSummary } from "./subagent-followup.js";
export async function dispatchCronDelivery(payloads) {
const heartbeat = stripHeartbeatToken(payloads[0]?.text ?? "", { mode: "heartbeat" });
await waitForDescendantSubagentSummary({ sessionKey: "agent:main:cron:job-1", timeoutMs: 1 });
await callGateway({ method: "agent.wait", params: { runId: "run-1" } });
return { heartbeat, mediaUrl: payloads[0]?.mediaUrl, sent: deliverOutboundPayloads };
}
`;
expect(describeSeamKinds("src/cron/isolated-agent/delivery-dispatch.ts", source)).toEqual([
"cron-followup-handoff",
"cron-heartbeat-handoff",
"cron-media-delivery",
"cron-outbound-delivery",
]);
});
it("ignores pure cron helpers without subsystem crossings", () => {
const source = `
import { truncateUtf16Safe } from "../../utils.js";
export function normalizeOptionalText(raw) {
if (typeof raw !== "string") return undefined;
return truncateUtf16Safe(raw.trim(), 40);
}
`;
expect(describeSeamKinds("src/cron/service/normalize.ts", source)).toEqual([]);
});
});
describe("audit-seams cron status/help", () => {
it("keeps cron seam statuses conservative when nearby tests exist", () => {
expect(
determineSeamTestStatus(
["cron-agent-handoff"],
[{ file: "src/cron/service.issue-regressions.test.ts", matchQuality: "path-nearby" }],
),
).toEqual({
status: "partial",
reason:
"Nearby tests exist (best match: path-nearby), but this inventory does not prove cross-layer seam coverage end to end.",
});
});
it("documents cron seam coverage in help text", () => {
expect(HELP_TEXT).toContain("cron orchestration seams");
expect(HELP_TEXT).toContain("agent handoff");
expect(HELP_TEXT).toContain("heartbeat/followup handoff");
});
});