mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-21 00:05:49 +02:00
fix: exclude terminal children from helper cap
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
1a17cbf232
commit
071edbf019
2 files changed
+63
-2
No files matched your search
@@ -34,6 +34,7 @@ import { instanceSettingsService } from "../services/instance-settings.ts";
|
||||
import {
|
||||
clampIssueListLimit,
|
||||
deriveIssueCommentRunLogAttribution,
|
||||
MAX_CHILD_ISSUES_CREATED_BY_HELPER,
|
||||
ISSUE_LIST_MAX_LIMIT,
|
||||
issueService,
|
||||
} from "../services/issues.ts";
|
||||
@@ -3677,6 +3678,62 @@ describeEmbeddedPostgres("issueService.create workspace inheritance", () => {
|
||||
|
||||
expect(child.requestDepth).toBe(MAX_ISSUE_REQUEST_DEPTH);
|
||||
});
|
||||
|
||||
it("counts only non-terminal children toward the helper child limit", async () => {
|
||||
const companyId = randomUUID();
|
||||
const parentIssueId = randomUUID();
|
||||
|
||||
await db.insert(companies).values({
|
||||
id: companyId,
|
||||
name: "Paperclip",
|
||||
issuePrefix: `T${companyId.replace(/-/g, "").slice(0, 6).toUpperCase()}`,
|
||||
requireBoardApprovalForNewAgents: false,
|
||||
});
|
||||
await db.insert(issues).values({
|
||||
id: parentIssueId,
|
||||
companyId,
|
||||
title: "Recurring coordinator",
|
||||
status: "in_progress",
|
||||
priority: "high",
|
||||
});
|
||||
|
||||
const terminalChildren = Array.from(
|
||||
{ length: MAX_CHILD_ISSUES_CREATED_BY_HELPER },
|
||||
(_, index) => ({
|
||||
id: randomUUID(),
|
||||
companyId,
|
||||
parentId: parentIssueId,
|
||||
title: `Terminal child ${index + 1}`,
|
||||
status: index % 2 === 0 ? "done" as const : "cancelled" as const,
|
||||
priority: "medium" as const,
|
||||
}),
|
||||
);
|
||||
const activeChildren = Array.from(
|
||||
{ length: MAX_CHILD_ISSUES_CREATED_BY_HELPER - 1 },
|
||||
(_, index) => ({
|
||||
id: randomUUID(),
|
||||
companyId,
|
||||
parentId: parentIssueId,
|
||||
title: `Active child ${index + 1}`,
|
||||
status: "todo" as const,
|
||||
priority: "medium" as const,
|
||||
}),
|
||||
);
|
||||
await db.insert(issues).values([...terminalChildren, ...activeChildren]);
|
||||
|
||||
const { issue: finalActiveChild } = await svc.createChild(parentIssueId, {
|
||||
title: "Final active child",
|
||||
status: "todo",
|
||||
});
|
||||
|
||||
expect(finalActiveChild.parentId).toBe(parentIssueId);
|
||||
await expect(svc.createChild(parentIssueId, {
|
||||
title: "Over active limit",
|
||||
status: "todo",
|
||||
})).rejects.toThrow(
|
||||
`Parent issue already has the maximum ${MAX_CHILD_ISSUES_CREATED_BY_HELPER} active child issues for this helper`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describeEmbeddedPostgres("issueService blockers and dependency wake readiness", () => {
|
||||
|
||||
@@ -6595,9 +6595,13 @@ export function issueService(db: Db) {
|
||||
const [{ childCount }] = await db
|
||||
.select({ childCount: sql<number>`count(*)::int` })
|
||||
.from(issues)
|
||||
.where(and(eq(issues.companyId, parent.companyId), eq(issues.parentId, parent.id)));
|
||||
.where(and(
|
||||
eq(issues.companyId, parent.companyId),
|
||||
eq(issues.parentId, parent.id),
|
||||
notInArray(issues.status, ["done", "cancelled"]),
|
||||
));
|
||||
if (childCount >= MAX_CHILD_ISSUES_CREATED_BY_HELPER) {
|
||||
throw unprocessable(`Parent issue already has the maximum ${MAX_CHILD_ISSUES_CREATED_BY_HELPER} child issues for this helper`);
|
||||
throw unprocessable(`Parent issue already has the maximum ${MAX_CHILD_ISSUES_CREATED_BY_HELPER} active child issues for this helper`);
|
||||
}
|
||||
|
||||
const {
|
||||
|
||||
Reference in new issue
Block a user