// 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"); });