fix: exclude terminal children from helper cap

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Codex EngineerandPaperclip committed 2026-08-17 16:03:41 +02:00
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", () => {
+6 -2
View File
@@ -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 {