fix workspace finalize blocker attribution

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-06-17 17:06:04 +00:00
1 parent 9cf661cc22
commit 2634ccbe44
2 files changed
+39 -13

No files matched your search

+17 -2
View File
@@ -3215,7 +3215,7 @@ describeEmbeddedPostgres("issueService blockers and dependency wake readiness",
});
});
it("ignores unattributed pre-backfill workspace operations when checking blocker readiness", async () => {
it("keeps dependents blocked on unattributed workspace operations for the blocker workspace", async () => {
const {
companyId,
executionWorkspaceId,
@@ -3232,6 +3232,22 @@ describeEmbeddedPostgres("issueService blockers and dependency wake readiness",
startedAt: new Date("2026-05-23T22:00:00.000Z"),
});
await expect(svc.listWakeableBlockedDependents(blockerId)).resolves.toEqual([]);
await expect(svc.getDependencyReadiness(dependentId)).resolves.toMatchObject({
isDependencyReady: false,
pendingFinalizeBlockerIssueIds: [blockerId],
unresolvedBlockerIssueIds: [blockerId],
});
await db.insert(workspaceOperations).values({
companyId,
executionWorkspaceId,
issueId: null,
phase: "workspace_finalize",
status: "succeeded",
startedAt: new Date("2026-05-23T22:05:00.000Z"),
});
await expect(svc.listWakeableBlockedDependents(blockerId)).resolves.toEqual([
expect.objectContaining({
id: dependentId,
@@ -3241,7 +3257,6 @@ describeEmbeddedPostgres("issueService blockers and dependency wake readiness",
await expect(svc.getDependencyReadiness(dependentId)).resolves.toMatchObject({
isDependencyReady: true,
pendingFinalizeBlockerIssueIds: [],
unresolvedBlockerIssueIds: [],
});
});
+22 -11
View File
@@ -686,6 +686,9 @@ async function listPendingFinalizeBlockerIssueIds(
const blockerIssueIds = [...new Set(blockerWorkspacePairs.map((pair) => pair.blockerIssueId))];
const executionWorkspaceIds = [...new Set(blockerWorkspacePairs.map((pair) => pair.executionWorkspaceId))];
if (blockerIssueIds.length === 0 || executionWorkspaceIds.length === 0) return pending;
const blockerWorkspaceKeys = new Set(
blockerWorkspacePairs.map((pair) => `${pair.blockerIssueId}:${pair.executionWorkspaceId}`),
);
const rows = await dbOrTx
.select({
@@ -699,28 +702,36 @@ async function listPendingFinalizeBlockerIssueIds(
.where(
and(
eq(workspaceOperations.companyId, companyId),
inArray(workspaceOperations.issueId, blockerIssueIds),
inArray(workspaceOperations.executionWorkspaceId, executionWorkspaceIds),
or(inArray(workspaceOperations.issueId, blockerIssueIds), isNull(workspaceOperations.issueId)),
),
);
const latestByBlockerWorkspace = new Map<string, { phase: string; status: string; startedAt: Date }>();
for (const row of rows) {
if (!row.issueId || !row.executionWorkspaceId) continue;
const key = `${row.issueId}:${row.executionWorkspaceId}`;
const current = latestByBlockerWorkspace.get(key);
if (!current || row.startedAt > current.startedAt) {
latestByBlockerWorkspace.set(key, {
phase: row.phase,
status: row.status,
startedAt: row.startedAt,
});
if (!row.executionWorkspaceId) continue;
const keys = row.issueId
? [`${row.issueId}:${row.executionWorkspaceId}`]
: blockerWorkspacePairs
.filter((pair) => pair.executionWorkspaceId === row.executionWorkspaceId)
.map((pair) => `${pair.blockerIssueId}:${pair.executionWorkspaceId}`);
for (const key of keys) {
if (!blockerWorkspaceKeys.has(key)) continue;
const current = latestByBlockerWorkspace.get(key);
if (!current || row.startedAt > current.startedAt) {
latestByBlockerWorkspace.set(key, {
phase: row.phase,
status: row.status,
startedAt: row.startedAt,
});
}
}
}
for (const pair of blockerWorkspacePairs) {
const latest = latestByBlockerWorkspace.get(`${pair.blockerIssueId}:${pair.executionWorkspaceId}`);
if (!latest) continue; // no attributed ops recorded -> nothing to finalize for this blocker
if (!latest) continue; // no ops recorded -> nothing to finalize for this blocker
if (latest.phase === "workspace_finalize" && latest.status === "succeeded") continue;
pending.add(pair.blockerIssueId);
}