mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-14 01:50:39 +09:00
fix: address greptile feedback for blocker dependencies
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
467f3a749a
commit
4c01a45d2a
5 changed files with 14 additions and 2 deletions
|
|
@ -10,6 +10,7 @@ CREATE TABLE "issue_relations" (
|
||||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> 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_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_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
|
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_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_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 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),
|
companyId: uuid("company_id").notNull().references(() => companies.id),
|
||||||
issueId: uuid("issue_id").notNull().references(() => issues.id, { onDelete: "cascade" }),
|
issueId: uuid("issue_id").notNull().references(() => issues.id, { onDelete: "cascade" }),
|
||||||
relatedIssueId: uuid("related_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" }),
|
createdByAgentId: uuid("created_by_agent_id").references(() => agents.id, { onDelete: "set null" }),
|
||||||
createdByUserId: text("created_by_user_id"),
|
createdByUserId: text("created_by_user_id"),
|
||||||
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
||||||
|
|
|
||||||
|
|
@ -819,6 +819,13 @@ export function issueService(db: Db) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deduped.length > 0) {
|
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
|
const relatedIssues = await dbOrTx
|
||||||
.select({ id: issues.id })
|
.select({ id: issues.id })
|
||||||
.from(issues)
|
.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.
|
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.
|
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.
|
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)
|
## 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
|
## Worked Example: IC Heartbeat
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue