// Tests for the engine-native AgentTask marker (issue #745, umbrella #746 — Camunda 8.10 parity),
// including the defect-class regression guard: every deployed prompt-bearing `senior:*` agent task
// must carry `` alongside its ``,
// so the worker harness mints an engine-native AgentInstance for it. A newly-added agent task that
// forgets the marker never persists durable AgentHistory — so it fails CI here instead of silently
// drifting.
import { readFileSync, readdirSync } from "node:fs";
import { test } from "node:test";
import { dirname, join, relative } from "node:path";
import { fileURLToPath } from "node:url";
import { assert, assertEquals } from "#test-assert";
import { agentTaskTypesMissingExternalMarker, promptBearingTaskTypes } from "./job-types.ts";
const PROCESSES_DIR = join(dirname(fileURLToPath(import.meta.url)), "../../../resources/processes");
// urban deploys `resources/` recursively (every file at any depth), so a process
// model added under a subdirectory would still deploy — walk recursively here too,
// or the guard would miss it and let an unmarked agent task slip through.
function bpmnFiles(): string[] {
const walk = (dir: string): string[] =>
readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
const full = join(dir, entry.name);
if (entry.isDirectory()) return walk(full);
return entry.name.endsWith(".bpmn") ? [relative(PROCESSES_DIR, full)] : [];
});
return walk(PROCESSES_DIR).sort();
}
test("agentTaskTypesMissingExternalMarker flags a prompt-bearing agent task with no external marker", () => {
const xml = `
`;
assertEquals(agentTaskTypesMissingExternalMarker(xml), ["senior:feature"]);
});
test("agentTaskTypesMissingExternalMarker passes a marked agent task and ignores a plain host task", () => {
const xml = `
`;
assertEquals(agentTaskTypesMissingExternalMarker(xml), []);
});
test("DEFECT-CLASS GUARD: every deployed prompt-bearing agent task carries the external AgentTask marker", () => {
let anyAgentTasks = false;
for (const file of bpmnFiles()) {
const xml = readFileSync(join(PROCESSES_DIR, file), "utf8");
if (promptBearingTaskTypes(xml).length > 0) anyAgentTasks = true;
const missing = agentTaskTypesMissingExternalMarker(xml);
assert(
missing.length === 0,
`${file}: agent task(s) missing — ${missing.join(", ")}`,
);
}
// Sanity: the models really do declare agent tasks (guard is not vacuously green).
assert(anyAgentTasks, "the deployed models declare prompt-bearing agent tasks");
});