Address Greptile review feedback for decomposition PR

This commit is contained in:
Devin Foley committed 2026-05-27 23:32:59 -07:00
1 parent 32dbcc1da4
commit ac4dee8579
8 files changed
+174 -3

No files matched your search

@@ -23,4 +23,5 @@ ALTER TABLE "issue_plan_decompositions" ADD CONSTRAINT "issue_plan_decomposition
ALTER TABLE "issue_plan_decompositions" ADD CONSTRAINT "issue_plan_decompositions_owner_agent_id_agents_id_fk" FOREIGN KEY ("owner_agent_id") REFERENCES "public"."agents"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "issue_plan_decompositions" ADD CONSTRAINT "issue_plan_decompositions_owner_run_id_heartbeat_runs_id_fk" FOREIGN KEY ("owner_run_id") REFERENCES "public"."heartbeat_runs"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "issue_plan_decompositions_company_source_status_idx" ON "issue_plan_decompositions" USING btree ("company_id","source_issue_id","status");--> statement-breakpoint
CREATE INDEX "issue_plan_decompositions_active_owner_idx" ON "issue_plan_decompositions" USING btree ("company_id","owner_agent_id") WHERE "issue_plan_decompositions"."status" = 'in_flight';--> statement-breakpoint
CREATE UNIQUE INDEX "issue_plan_decompositions_source_revision_uq" ON "issue_plan_decompositions" USING btree ("company_id","source_issue_id","accepted_plan_revision_id");
@@ -10302,6 +10302,28 @@
"method": "btree",
"with": {}
},
"issue_plan_decompositions_active_owner_idx": {
"name": "issue_plan_decompositions_active_owner_idx",
"columns": [
{
"expression": "company_id",
"isExpression": false,
"asc": true,
"nulls": "last"
},
{
"expression": "owner_agent_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"where": "\"issue_plan_decompositions\".\"status\" = 'in_flight'",
"with": {}
},
"issue_plan_decompositions_source_revision_uq": {
"name": "issue_plan_decompositions_source_revision_uq",
"columns": [
@@ -18349,4 +18371,4 @@
"schemas": {},
"tables": {}
}
}
}
@@ -36,6 +36,9 @@ export const issuePlanDecompositions = pgTable(
table.sourceIssueId,
table.status,
),
activeOwnerIdx: index("issue_plan_decompositions_active_owner_idx")
.on(table.companyId, table.ownerAgentId)
.where(sql`${table.status} = 'in_flight'`),
sourceRevisionUq: uniqueIndex("issue_plan_decompositions_source_revision_uq").on(
table.companyId,
table.sourceIssueId,
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

@@ -3740,6 +3740,7 @@ describeEmbeddedPostgres("accepted plan decomposition", () => {
expect(record?.childIssues.map((child) => child.id).sort()).toEqual(
[...result.childIssueIds].sort(),
);
expect(record).not.toHaveProperty("requestedChildren");
expect(record?.childIssues.every((child) => typeof child.title === "string")).toBe(true);
});
});
+17 -2
View File
@@ -4414,9 +4414,24 @@ export function issueService(db: Db) {
const childIssueMap = new Map(childIssueRows.map((row) => [row.id, row]));
return rows.map((row) => {
const childIds = normalizeIssuePlanDecompositionChildIds(row.decomposition.childIssueIds);
const decomposition = row.decomposition;
const childIds = normalizeIssuePlanDecompositionChildIds(decomposition.childIssueIds);
return {
...row.decomposition,
id: decomposition.id,
companyId: decomposition.companyId,
sourceIssueId: decomposition.sourceIssueId,
acceptedPlanRevisionId: decomposition.acceptedPlanRevisionId,
acceptedInteractionId: decomposition.acceptedInteractionId,
status: decomposition.status,
requestFingerprint: decomposition.requestFingerprint,
requestedChildCount: decomposition.requestedChildCount,
childIssueIds: childIds,
ownerAgentId: decomposition.ownerAgentId,
ownerUserId: decomposition.ownerUserId,
ownerRunId: decomposition.ownerRunId,
completedAt: decomposition.completedAt,
createdAt: decomposition.createdAt,
updatedAt: decomposition.updatedAt,
acceptedPlanRevisionNumber: row.revisionNumber ?? null,
childIssues: childIds
.map((childId) => childIssueMap.get(childId) ?? null)
@@ -0,0 +1,129 @@
import { useState } from "react";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { useQueryClient } from "@tanstack/react-query";
import type { AcceptedPlanDecompositionSummary } from "@paperclipai/shared";
import { IssuePlanDecompositionsSection } from "@/components/IssuePlanDecompositionsSection";
import { queryKeys } from "@/lib/queryKeys";
import { storybookAgentMap } from "../fixtures/paperclipData";
const issueId = "issue-plan-decomposition-story";
const issueIdentifier = "PAP-6831";
function buildDecomposition(
overrides: Partial<AcceptedPlanDecompositionSummary>,
): AcceptedPlanDecompositionSummary {
return {
id: "decomposition-story-1",
companyId: "company-storybook",
sourceIssueId: issueId,
acceptedPlanRevisionId: "revision-story-1",
acceptedInteractionId: "interaction-story-1",
status: "completed",
requestFingerprint: "fingerprint-story-1",
requestedChildCount: 2,
childIssueIds: ["issue-child-1", "issue-child-2"],
ownerAgentId: "agent-codex",
ownerUserId: null,
ownerRunId: "run-story-1",
completedAt: "2026-05-28T06:22:00.000Z",
createdAt: "2026-05-28T06:18:00.000Z",
updatedAt: "2026-05-28T06:22:00.000Z",
acceptedPlanRevisionNumber: 7,
childIssues: [
{
id: "issue-child-1",
identifier: "PAP-6840",
title: "Harden accepted-plan wake routing",
status: "done",
priority: "medium",
assigneeAgentId: "agent-codex",
assigneeUserId: null,
},
{
id: "issue-child-2",
identifier: "PAP-6841",
title: "Add decomposition regression coverage",
status: "in_progress",
priority: "medium",
assigneeAgentId: "agent-qa",
assigneeUserId: null,
},
],
...overrides,
};
}
function HydratedSection({
decompositions,
}: {
decompositions: AcceptedPlanDecompositionSummary[];
}) {
const queryClient = useQueryClient();
const [ready] = useState(() => {
queryClient.setQueryData(queryKeys.issues.acceptedPlanDecompositions(issueId), decompositions);
return true;
});
if (!ready) return null;
return (
<div className="paperclip-story">
<main className="paperclip-story__inner">
<div className="mx-auto max-w-3xl rounded-2xl border border-border bg-background/95 p-6 shadow-sm">
<IssuePlanDecompositionsSection
issueId={issueId}
issueIdentifier={issueIdentifier}
agentMap={storybookAgentMap}
/>
</div>
</main>
</div>
);
}
const meta = {
title: "Issue Detail/Plan Decompositions",
component: HydratedSection,
args: {
decompositions: [],
},
parameters: {
layout: "fullscreen",
},
} satisfies Meta<typeof HydratedSection>;
export default meta;
type Story = StoryObj<typeof meta>;
export const InFlight: Story = {
args: {
decompositions: [
buildDecomposition({
status: "in_flight",
completedAt: null,
updatedAt: "2026-05-28T06:20:00.000Z",
childIssueIds: ["issue-child-1"],
childIssues: [
{
id: "issue-child-1",
identifier: "PAP-6840",
title: "Harden accepted-plan wake routing",
status: "done",
priority: "medium",
assigneeAgentId: "agent-codex",
assigneeUserId: null,
},
],
}),
],
},
};
export const Completed: Story = {
args: {
decompositions: [
buildDecomposition({}),
],
},
};