mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-23 09:07:46 +02:00
Tighten runtime feedback and interaction catchup
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
133457c2f4
commit
686e06c8ea
3 files changed
+30
-7
No files matched your search
@@ -15,4 +15,10 @@ describe("feedback export flush error classification", () => {
|
||||
it("does not classify ordinary feedback upload failures as database outages", () => {
|
||||
expect(isDatabaseConnectionUnavailableError(new Error("upstream returned 500"))).toBe(false);
|
||||
});
|
||||
|
||||
it("does not trust unrelated error messages that mention ECONNREFUSED", () => {
|
||||
expect(isDatabaseConnectionUnavailableError(
|
||||
new Error("feedback upload payload mentioned ECONNREFUSED in user content"),
|
||||
)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -86,8 +86,6 @@ const VITE_DEV_STATIC_PATHS = new Set([
|
||||
export function isDatabaseConnectionUnavailableError(err: unknown): boolean {
|
||||
const error = err as { code?: unknown; message?: unknown; cause?: unknown };
|
||||
if (error?.code === "ECONNREFUSED") return true;
|
||||
const message = typeof error?.message === "string" ? error.message : "";
|
||||
if (message.includes("ECONNREFUSED")) return true;
|
||||
return Boolean(error?.cause && isDatabaseConnectionUnavailableError(error.cause));
|
||||
}
|
||||
|
||||
|
||||
@@ -1068,6 +1068,13 @@ export function issueThreadInteractionService(db: Db) {
|
||||
|
||||
const now = new Date();
|
||||
const expired: IssueThreadInteraction[] = [];
|
||||
const supersededByComment = new Map<
|
||||
string,
|
||||
{
|
||||
comment: (typeof comments)[number];
|
||||
rowIds: string[];
|
||||
}
|
||||
>();
|
||||
for (const row of rows) {
|
||||
const interaction = hydrateInteraction(row) as RequestConfirmationInteraction;
|
||||
if (!shouldSupersedeRequestConfirmationOnUserComment(interaction)) continue;
|
||||
@@ -1078,26 +1085,38 @@ export function issueThreadInteractionService(db: Db) {
|
||||
}));
|
||||
if (!supersedingComment) continue;
|
||||
|
||||
const [updated] = await db
|
||||
const group = supersededByComment.get(supersedingComment.id);
|
||||
if (group) {
|
||||
group.rowIds.push(row.id);
|
||||
} else {
|
||||
supersededByComment.set(supersedingComment.id, {
|
||||
comment: supersedingComment,
|
||||
rowIds: [row.id],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const { comment, rowIds } of supersededByComment.values()) {
|
||||
const updatedRows = await db
|
||||
.update(issueThreadInteractions)
|
||||
.set({
|
||||
status: "expired",
|
||||
result: {
|
||||
version: 1,
|
||||
outcome: "superseded_by_comment",
|
||||
commentId: supersedingComment.id,
|
||||
commentId: comment.id,
|
||||
},
|
||||
resolvedByAgentId: null,
|
||||
resolvedByUserId: supersedingComment.authorUserId,
|
||||
resolvedByUserId: comment.authorUserId,
|
||||
resolvedAt: now,
|
||||
updatedAt: now,
|
||||
})
|
||||
.where(and(
|
||||
eq(issueThreadInteractions.id, row.id),
|
||||
inArray(issueThreadInteractions.id, rowIds),
|
||||
eq(issueThreadInteractions.status, "pending"),
|
||||
))
|
||||
.returning();
|
||||
if (updated) expired.push(hydrateInteraction(updated));
|
||||
expired.push(...updatedRows.map(hydrateInteraction));
|
||||
}
|
||||
|
||||
if (expired.length > 0) {
|
||||
|
||||
Reference in new issue
Block a user