fix: address greptile feedback for blocker dependencies
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -10,6 +10,7 @@ CREATE TABLE "issue_relations" (
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "issue_relations" ADD CONSTRAINT "issue_relations_type_check" CHECK ("type" IN ('blocks'));--> statement-breakpoint
|
||||
ALTER TABLE "issue_relations" ADD CONSTRAINT "issue_relations_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "issue_relations" ADD CONSTRAINT "issue_relations_issue_id_issues_id_fk" FOREIGN KEY ("issue_id") REFERENCES "public"."issues"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "issue_relations" ADD CONSTRAINT "issue_relations_related_issue_id_issues_id_fk" FOREIGN KEY ("related_issue_id") REFERENCES "public"."issues"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
@@ -17,4 +18,4 @@ ALTER TABLE "issue_relations" ADD CONSTRAINT "issue_relations_created_by_agent_i
|
||||
CREATE INDEX "issue_relations_company_issue_idx" ON "issue_relations" USING btree ("company_id","issue_id");--> statement-breakpoint
|
||||
CREATE INDEX "issue_relations_company_related_issue_idx" ON "issue_relations" USING btree ("company_id","related_issue_id");--> statement-breakpoint
|
||||
CREATE INDEX "issue_relations_company_type_idx" ON "issue_relations" USING btree ("company_id","type");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "issue_relations_company_edge_uq" ON "issue_relations" USING btree ("company_id","issue_id","related_issue_id","type");
|
||||
CREATE UNIQUE INDEX "issue_relations_company_edge_uq" ON "issue_relations" USING btree ("company_id","issue_id","related_issue_id","type");
|
||||
|
||||
@@ -10,7 +10,7 @@ export const issueRelations = pgTable(
|
||||
companyId: uuid("company_id").notNull().references(() => companies.id),
|
||||
issueId: uuid("issue_id").notNull().references(() => issues.id, { onDelete: "cascade" }),
|
||||
relatedIssueId: uuid("related_issue_id").notNull().references(() => issues.id, { onDelete: "cascade" }),
|
||||
type: text("type").notNull(),
|
||||
type: text("type").$type<"blocks">().notNull(),
|
||||
createdByAgentId: uuid("created_by_agent_id").references(() => agents.id, { onDelete: "set null" }),
|
||||
createdByUserId: text("created_by_user_id"),
|
||||
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
||||
|
||||
@@ -819,6 +819,13 @@ export function issueService(db: Db) {
|
||||
}
|
||||
|
||||
if (deduped.length > 0) {
|
||||
const lockedIssueIds = [issueId, ...deduped].sort();
|
||||
await dbOrTx.execute(
|
||||
sql`SELECT ${issues.id} FROM ${issues}
|
||||
WHERE ${and(eq(issues.companyId, companyId), inArray(issues.id, lockedIssueIds))}
|
||||
ORDER BY ${issues.id}
|
||||
FOR UPDATE`,
|
||||
);
|
||||
const relatedIssues = await dbOrTx
|
||||
.select({ id: issues.id })
|
||||
.from(issues)
|
||||
|
||||
@@ -128,6 +128,8 @@ Paperclip fires automatic wakes in two scenarios:
|
||||
1. **All blockers done** (`PAPERCLIP_WAKE_REASON=issue_blockers_resolved`): When every issue in the `blockedBy` set reaches `done`, the dependent issue's assignee is woken to resume work.
|
||||
2. **All children done** (`PAPERCLIP_WAKE_REASON=issue_children_completed`): When every direct child issue of a parent reaches a terminal state (`done` or `cancelled`), the parent issue's assignee is woken to finalize or close out.
|
||||
|
||||
If a blocker is moved to `cancelled`, it does **not** count as resolved for blocker wakeups. Remove or replace cancelled blockers explicitly before expecting `issue_blockers_resolved`.
|
||||
|
||||
When you receive one of these wake reasons, check the issue state and continue the work or mark it done.
|
||||
|
||||
## Project Setup Workflow (CEO/Manager Common Path)
|
||||
|
||||
@@ -189,6 +189,8 @@ The response also includes `blockedBy` and `blocks` arrays showing first-class d
|
||||
}
|
||||
```
|
||||
|
||||
Blocker wake semantics are strict: `issue_blockers_resolved` only fires when every blocker reaches `done`. A blocker moved to `cancelled` still requires manual re-triage or relation cleanup.
|
||||
|
||||
---
|
||||
|
||||
## Worked Example: IC Heartbeat
|
||||
|
||||
Reference in New Issue
Block a user