You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(folders): close the findings from auditing the whole release landing unit
Audited as the unit that actually ships — #6014 (pinning), #6025 (workflow folders onto the
generic table), #6037 (the engine) and this branch together against `main`, rather than this
branch against `staging`.
Authorization
- `PUT /api/folders/reorder` still operated on archived folders. `getFolderLockStatus` skips
archived rows, so `assertFolderMutable` there was a guaranteed no-op — meaning a locked folder
became freely reparentable the moment its parent was deleted. This branch closed exactly that
hole on `PUT /api/folders/[id]` and left its sibling open, then widened reorder to three
resource trees. Reordering an archived folder is also wrong on its own terms:
`collectArchivedSubtreeIds` walks the cascade by parent, so moving a branch out of an archived
subtree silently drops it from that folder's restore
Data loss in the purge
- `batchDeleteByWorkspaceAndTimestamp` forwarded its eligibility predicate only into the SELECT,
never the DELETE. The `folder` target runs through it, so a restore committing between the two
statements had its folder hard-deleted anyway — taking the placement of the children the
restore had just brought back. The workflow purge re-checks for precisely this reason and the
knowledge-base sweep gained the same guard earlier in this branch; `folder` had neither. The
wrapper now re-asserts eligibility on the DELETE for every caller
Wire boundary
- `toPinnedItemApi` had no return type, so `pinned_item.resource_type` — plain `text` by design,
against a closed contract enum — was never checked. Annotating it surfaced the real hole
immediately: during a rolling deploy an older pod can read a pin a newer one wrote, and
returning it would fail response validation and take the WHOLE list down rather than the one
row. Unknown kinds are now narrowed out explicitly at the boundary instead of surviving by
accident on a filter whose stated job is something else
Interaction
- The knowledge-base FOLDER move still compared against the snapshot taken when the menu opened.
The resource move on that page and both Tables handlers were fixed earlier in this branch; this
was the last one
Operational
- 0274's "re-run after drain" instruction needed a precondition. Cleanup hard-deletes from
`folder` but never from `workspace_file_folders`, so a re-run after a purge would reinstate
every purged file folder as a soft-deleted phantom whose files are already gone. Retention is
far longer than any drain, so running it promptly is sufficient — but the instruction said
nothing about ordering
Accuracy
- Four comments named symbols that do not exist or no longer apply: `useFolderCreateWithDedup`
(never existed — it is `nextUntitledFolderName`), `collectActiveSubtreeIds`,
`restoreFolderCascade` as the live restore path, and a claim that a server
`createSearchParamsCache` reads the shared folder param. The shared param doc also now admits
Files declares its own `?folderId=` rather than claiming to be the single declaration
- `FOLDER_RESOURCES.file` is unreachable at runtime — `servedFolderResourceTypeSchema` does not
serve `'file'` — and a reader would reasonably assume otherwise. Says so, and says what routing
file folders through the generic engine would bypass
- `pinnedItem.resourceType`'s inline comment was missing `'folder'`
- `folders.test.ts` fixtures still carried `color` and `isExpanded`, both deliberately dropped
from the generic table — pre-consolidation rows masquerading as folders
- `getFolders` in the folder cache had one caller, in its own file
0 commit comments