snapshot of https://github.com/marmelab/atomic-crm.git (main, 2026-09-18; blobs > 131072B omitted)
Some checks failed
✅ Check / 🔬 ESLint (push) Failing after 21s
✅ Check / 🏷️ Typecheck (push) Failing after 11s
✅ Check / 🔎 Test (push) Failing after 11s
✅ Check / e2e-test (push) Failing after 11s
✅ Check / 🔨 Build (push) Failing after 11s
🚀 Deploy / 🚀 Deploy (doc) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (demo) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (supabase) (push) Failing after 18s

This commit is contained in:
upstream-mirror
2026-09-18 01:48:50 +05:00
commit 93ecc1a6f8
787 changed files with 75240 additions and 0 deletions

View File

@@ -0,0 +1,180 @@
// Tests for block-duplicate-dispatch.mjs — the PreToolUse(Agent) gate that
// stops accidental duplicate dispatches. Two concerns:
// 1. planner: at most one per (caller, TICKETS_DIR).
// 2. developer/quality-reviewer/merger: debounce identical re-dispatches
// inside a short window (the async-runtime "Async agent launched" trap).
// A block is emitted via decisionBlock: exit 0 with {"decision":"block"} on
// stdout (NOT exit 2). An allowed dispatch exits 0 with no decision JSON.
import {
mkdtempSync,
mkdirSync,
readdirSync,
rmSync,
utimesSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { spawnSync } from "node:child_process";
import { describe, test, expect, beforeAll, afterAll } from "vitest";
import { sanitizePath } from "../lib/paths.mjs";
const HERE = dirname(fileURLToPath(import.meta.url));
const HOOK = join(HERE, "..", "block-duplicate-dispatch.mjs");
const SESSION_ID = "ab12cd34-1111-2222-3333-444455556666";
const CALLER = "orchestrator-agent-1";
let TMP;
let APP_DIR;
let breakerDir;
let env;
// Returns { blocked: boolean } — blocked when the decisionBlock JSON is printed.
// runInBackground defaults to false: in the real harness (post force-foreground)
// every pipeline dispatch carries run_in_background:false, and block-duplicate only
// debounces those. Pass `undefined` to simulate the malformed (absent) dispatch that
// force-foreground denies — block-duplicate must skip it (no marker).
const run = (
prompt,
subagentType,
agentId = CALLER,
runInBackground = false,
) => {
const tool_input = { subagent_type: subagentType, prompt };
// Pass the sentinel "absent" to OMIT the field (a default param can't express this:
// passing `undefined` still triggers the default). "absent" simulates the malformed
// dispatch force-foreground denies.
if (runInBackground !== "absent")
tool_input.run_in_background = runInBackground;
const r = spawnSync("node", [HOOK], {
input: JSON.stringify({
session_id: SESSION_ID,
agent_id: agentId,
tool_input,
}),
env,
encoding: "utf8",
});
return {
blocked: /"decision":"block"/.test(r.stdout || ""),
status: r.status,
};
};
// Backdate every marker so the next dispatch sees it as outside the debounce
// window (and a planner marker as stale).
const ageMarkers = (secondsAgo) => {
const when = Date.now() / 1000 - secondsAgo;
for (const f of readdirSync(breakerDir)) {
utimesSync(join(breakerDir, f), when, when);
}
};
beforeAll(() => {
TMP = mkdtempSync(join(tmpdir(), "block-dup-dispatch-test-"));
APP_DIR = join(TMP, "app");
const CRM_TMP_ROOT = join(TMP, "scratch");
breakerDir = join(CRM_TMP_ROOT, sanitizePath(APP_DIR), SESSION_ID, "breaker");
mkdirSync(breakerDir, { recursive: true });
env = { ...process.env, APP_DIR, CRM_TMP_ROOT };
});
afterAll(() => rmSync(TMP, { recursive: true, force: true }));
describe("block-duplicate-dispatch — planner", () => {
test("allows the first planner, blocks the second for the same TICKETS_DIR", () => {
const p = `TICKETS_DIR=${join(TMP, "tickets")}`;
expect(run(p, "planner").blocked).toBe(false);
expect(run(p, "planner").blocked).toBe(true);
});
test("allows a planner again once the marker is stale (>1h)", () => {
ageMarkers(2 * 60 * 60); // 2h
const p = `TICKETS_DIR=${join(TMP, "tickets")}`;
expect(run(p, "planner").blocked).toBe(false);
});
});
describe("block-duplicate-dispatch — reviewer/developer/merger debounce", () => {
test("blocks a second quality-reviewer for the same ticket within the window", () => {
const p = `ROLE: quality-reviewer\nTASK_ID: TASK-100\nWORKTREE_PATH: /wt`;
expect(run(p, "quality-reviewer").blocked).toBe(false);
expect(run(p, "quality-reviewer").blocked).toBe(true);
});
test("allows a reviewer for a different ticket", () => {
expect(
run(
`ROLE: quality-reviewer\nTASK_ID: TASK-200\nWORKTREE_PATH: /wt`,
"quality-reviewer",
).blocked,
).toBe(false);
});
test("allows the same reviewer again once outside the debounce window", () => {
ageMarkers(5 * 60); // 5 min — well past the 90s window
expect(
run(
`ROLE: quality-reviewer\nTASK_ID: TASK-100\nWORKTREE_PATH: /wt`,
"quality-reviewer",
).blocked,
).toBe(false);
});
test("debounces by ticket, not role: a merger for a fresh ticket is allowed", () => {
expect(
run(`ROLE: merger\nTASK_ID: TASK-300\nBRANCH_NAME: x`, "merger").blocked,
).toBe(false);
});
test("a different caller is not debounced against the first caller's marker", () => {
const p = `ROLE: developer\nTASK_ID: TASK-400\nWORKTREE_PATH: /wt`;
expect(run(p, "developer", "orchestrator-A").blocked).toBe(false);
expect(run(p, "developer", "orchestrator-B").blocked).toBe(false);
});
test("falls back to a prompt hash when there is no TASK_ID (SIMPLE flow)", () => {
const p = `ROLE: developer\nCHANGE_REQUEST: rename the button\nWORKTREE_PATH: /wt`;
expect(run(p, "developer").blocked).toBe(false);
expect(run(p, "developer").blocked).toBe(true); // identical prompt → duplicate
// A different change request is a distinct dispatch, not a duplicate.
expect(
run(
`ROLE: developer\nCHANGE_REQUEST: hide the export\nWORKTREE_PATH: /wt`,
"developer",
).blocked,
).toBe(false);
});
});
describe("block-duplicate-dispatch — pass-through", () => {
test("ignores roles outside the debounce set (documentator)", () => {
const p = `ROLE: documentator`;
expect(run(p, "documentator").blocked).toBe(false);
expect(run(p, "documentator").blocked).toBe(false); // never debounced
});
test("allows when no caller agent_id is present (can't scope a marker)", () => {
const r = run(
`ROLE: quality-reviewer\nTASK_ID: TASK-100\nWORKTREE_PATH: /wt`,
"quality-reviewer",
"",
);
expect(r.blocked).toBe(false);
});
});
describe("block-duplicate-dispatch — force-foreground retry (regression 8468cc06)", () => {
// A pipeline dispatch without run_in_background:false is DENIED by
// force-foreground-orchestrator-dispatch and re-issued. block-duplicate must NOT
// record a marker for the denied attempt, or the corrective retry would be wrongly
// rejected as a duplicate (this wedged planning for 60 min in a real run).
test("a rib-absent pipeline dispatch is skipped, so the rib:false retry is not a duplicate", () => {
const p = `TICKETS_DIR=${join(TMP, "tickets-ff")}`;
const FF = "ff-orch"; // unique caller: no marker collision with earlier tests
expect(run(p, "planner", FF, "absent").blocked).toBe(false); // denied form -> skipped, no marker
expect(run(p, "planner", FF, false).blocked).toBe(false); // the retry proceeds
expect(run(p, "planner", FF, false).blocked).toBe(true); // a genuine 2nd planner is still blocked
});
});