Archive every deletion via a bulk SQL retirement

`retireDeletedArtifacts` used to iterate `deleted.slice(0,
MAX_BASH_PROJECTED_FILES)` and emit no signal for paths past the cap
— a large `rm -r` would leave the 51st row onward visible in the
DocumentCenter with no indication anything was missed. The cap was
inherited from the registration path, where it bounds file-stat
round-trips; retirement is a pure metadata update with no filesystem
cost, so the cap was value-free safety theatre.

New DB surface `archiveWorkProductsByExternalPaths` runs a single
`UPDATE … SET status = 'archived' … WHERE external_id IN (…)
AND status <> 'archived' RETURNING id, external_id` per 500-path
chunk — one round-trip per chunk instead of one per path. The
projector feeds the full `deleted` list in, maps the returned ids
back to `retired` outcomes, and no deletion is left behind regardless
of the run's cleanup fan-out size.
This commit is contained in:
ZacharyZhang-NY committed 2026-04-19 17:23:07 -04:00
1 parent f0c4a66cc1
commit fe808d13a2
3 files changed
+78 -18

No files matched your search

+3
View File
@@ -100,6 +100,9 @@ export class AppDatabase extends AppDatabaseBase {
findWorkProductByExternalId(companyId: string, provider: string, externalId: string, workspaceId: string | null) { return this.documentsMod.findWorkProductByExternalId(companyId, provider, externalId, workspaceId); }
resolveWorkProductTarget(workProductId: string, companyId: string) { return this.documentsMod.resolveWorkProductTarget(workProductId, companyId); }
deleteWorkProduct(id: string, companyId: string) { return this.documentsMod.deleteWorkProduct(id, companyId); }
archiveWorkProductsByExternalPaths(input: Parameters<ReturnType<typeof import("./database/documents").buildDocumentMethods>["archiveWorkProductsByExternalPaths"]>[0]) {
return this.documentsMod.archiveWorkProductsByExternalPaths(input);
}
linkDocumentToTask(taskId: string, documentId: string, companyId: string, key: string) { return this.documentsMod.linkDocumentToTask(taskId, documentId, companyId, key); }
unlinkDocumentFromTask(taskId: string, key: string, companyId: string) { this.documentsMod.unlinkDocumentFromTask(taskId, key, companyId); }
listDocumentsForTask(taskId: string, companyId: string) { return this.documentsMod.listDocumentsForTask(taskId, companyId); }