Skip to content

Commit a5dac82

Browse files
committed
fix(db): carry locked through the reconcile and start suffixes at (1)
Two review findings, both real. `locked` was hardcoded false on the workflow insert. `workflow_folder` has a `locked` column and the app still enforces the lock feature against `folder.locked`, so a stranded locked folder would have come back unlocked. 0272 carries `f.locked` through for exactly this reason; this now matches it. `workspace_file_folders` has no such column — file folders have never been lockable — so the file pass still writes false. Name dedup started at ' (2)', skipping a free ' (1)'. 0272 enumerates `generate_series(1, 10000)` and the app's own dedup produces "New folder (1)", "New folder (2)", ..., so starting at (2) was inconsistent with both. Fixtures extended to cover both: a stranded locked folder must arrive locked, a stranded unlocked one must stay unlocked (proving the value is copied rather than blanket-set), and a collision with a free ' (1)' must take it. Still idempotent across three consecutive runs. The single row stranded in production is an archived, unlocked canary folder, so neither bug would have bitten on today's run — but this file is meant to be re-runnable and ships to self-hosted rolling deploys.
1 parent e339a38 commit a5dac82

1 file changed

Lines changed: 13 additions & 6 deletions

File tree

packages/db/migrations/0275_folder_cutover_post_drain_reconcile.sql

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,17 @@
2222
-- `folder` are touched; every row already mirrored is left exactly as it is.
2323
--
2424
-- Names are deduplicated against the FIRST FREE suffix rather than a row number, because the
25-
-- target name may already be taken by a row this block is not inserting. Only ACTIVE rows are
26-
-- deduplicated — the partial unique index ignores soft-deleted rows, so an archived folder
25+
-- target name may already be taken by a row this block is not inserting. Suffixes start at
26+
-- ' (1)' to match 0272 and the app's own dedup, which both produce "New folder (1)",
27+
-- "New folder (2)", ... — starting at (2) would skip a legitimately free name. Only ACTIVE rows
28+
-- are deduplicated: the partial unique index ignores soft-deleted rows, so an archived folder
2729
-- keeps its original name and reappears under it if restored.
2830
--
31+
-- `locked` is carried over from `workflow_folder` rather than defaulted, exactly as 0272 does.
32+
-- The lock feature is still enforced against `folder.locked`, so defaulting a stranded locked
33+
-- folder to false would silently unlock it. `workspace_file_folders` has no such column — file
34+
-- folders have never been lockable — so the file pass writes false.
35+
--
2936
-- Rows are inserted in depth order so a parent always lands before its children: the
3037
-- self-referencing FK `folder_parent_id_folder_id_fk` is checked immediately, and the
3138
-- `folder_parent_resource_type_match` trigger reads the parent row. A child inserted before
@@ -64,7 +71,7 @@ BEGIN
6471
FROM "workflow_folder" s
6572
JOIN tree t ON t.id = s."parent_id"
6673
)
67-
SELECT s."id", s."name", s."user_id", s."workspace_id", s."parent_id",
74+
SELECT s."id", s."name", s."user_id", s."workspace_id", s."parent_id", s."locked",
6875
s."sort_order", s."created_at", s."updated_at", s."archived_at" AS deleted_at
6976
FROM "workflow_folder" s
7077
JOIN tree t ON t.id = s."id"
@@ -73,7 +80,7 @@ BEGIN
7380
LOOP
7481
candidate := rec."name";
7582
IF rec.deleted_at IS NULL THEN
76-
suffix := 1;
83+
suffix := 0;
7784
WHILE EXISTS (
7885
SELECT 1 FROM "folder" f
7986
WHERE f."workspace_id" = rec."workspace_id"
@@ -89,7 +96,7 @@ BEGIN
8996

9097
INSERT INTO "folder" (id, resource_type, name, user_id, workspace_id, parent_id, locked, sort_order, created_at, updated_at, deleted_at)
9198
VALUES (rec."id", 'workflow', candidate, rec."user_id", rec."workspace_id", rec."parent_id",
92-
false, rec."sort_order", rec."created_at", rec."updated_at", rec.deleted_at)
99+
rec."locked", rec."sort_order", rec."created_at", rec."updated_at", rec.deleted_at)
93100
ON CONFLICT (id) DO NOTHING;
94101
END LOOP;
95102

@@ -114,7 +121,7 @@ BEGIN
114121
LOOP
115122
candidate := rec."name";
116123
IF rec."deleted_at" IS NULL THEN
117-
suffix := 1;
124+
suffix := 0;
118125
WHILE EXISTS (
119126
SELECT 1 FROM "folder" f
120127
WHERE f."workspace_id" = rec."workspace_id"

0 commit comments

Comments
 (0)