mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-22 16:51:28 +02:00
Apply the reviewed change for Handle incomplete task policies and preserve review limits. Validation: local typecheck/build and focused regression tests, passing exact-head CI, Greptile 5/5, and independent source review. The PR records full-suite evidence and any local environment limitations. Co-Authored-By: Paperclip <noreply@paperclip.ing>
46 lines
2.7 KiB
TypeScript
46 lines
2.7 KiB
TypeScript
import { randomUUID } from "node:crypto";
|
|
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
import { companies, createDb, issues } from "@paperclipai/db";
|
|
import { buildExecutionPolicy } from "../../../ui/src/lib/issue-execution-policy.ts";
|
|
import { normalizeIssueExecutionPolicy } from "../services/issue-execution-policy.js";
|
|
import { issueService } from "../services/issues.js";
|
|
import { getEmbeddedPostgresTestSupport, startEmbeddedPostgresTestDatabase } from "./helpers/embedded-postgres.js";
|
|
|
|
const support = await getEmbeddedPostgresTestSupport();
|
|
(support.supported ? describe : describe.skip)("edited execution policy persistence", () => {
|
|
let temporary: Awaited<ReturnType<typeof startEmbeddedPostgresTestDatabase>>;
|
|
let db: ReturnType<typeof createDb>;
|
|
beforeAll(async () => {
|
|
temporary = await startEmbeddedPostgresTestDatabase("paperclip-policy-persistence-");
|
|
db = createDb(temporary.connectionString);
|
|
}, 30_000);
|
|
afterAll(async () => { await temporary?.cleanup(); });
|
|
|
|
it.each(["reviewer", "monitor"] as const)("retains the independent review limit after removing the last %s", async (removed) => {
|
|
const companyId = randomUUID();
|
|
const issueId = randomUUID();
|
|
const original = normalizeIssueExecutionPolicy({
|
|
maxReviewRounds: 4,
|
|
...(removed === "monitor"
|
|
? { monitor: { nextCheckAt: "2099-01-01T00:00:00.000Z" } }
|
|
: { stages: [{ type: "review", participants: [{ type: "user", userId: "board-reviewer" }] }] }),
|
|
});
|
|
await db.insert(companies).values({ id: companyId, name: "Policy fixture", issuePrefix: `P${companyId.slice(0, 6)}` });
|
|
await db.insert(issues).values({ id: issueId, companyId, title: "Review limit fixture", executionPolicy: original });
|
|
const edited = buildExecutionPolicy({ existingPolicy: original, reviewerValues: [], approverValues: [] })!;
|
|
// The monitor editor removes this key after building the unchanged stages.
|
|
const { monitor: _removedMonitor, ...withoutMonitor } = edited;
|
|
const normalized = normalizeIssueExecutionPolicy(removed === "monitor" ? withoutMonitor : edited);
|
|
const service = issueService(db);
|
|
await service.update(issueId, { executionPolicy: normalized, companyGuard: companyId });
|
|
const saved = await service.getById(issueId);
|
|
expect(saved?.executionPolicy).toEqual({ mode: "normal", commentRequired: true, stages: [], maxReviewRounds: 4 });
|
|
|
|
const restored = normalizeIssueExecutionPolicy(buildExecutionPolicy({
|
|
existingPolicy: saved?.executionPolicy,
|
|
reviewerValues: ["user:board-reviewer"], approverValues: [],
|
|
}));
|
|
expect(restored).toMatchObject({ maxReviewRounds: 4, stages: [{ type: "review" }] });
|
|
});
|
|
});
|