Skip to content

fix: vault rename data integrity, manual order persistence, name validation#55

Merged
rogerdigital merged 2 commits into
mainfrom
fix/vault-rename-data-integrity
Jun 25, 2026
Merged

fix: vault rename data integrity, manual order persistence, name validation#55
rogerdigital merged 2 commits into
mainfrom
fix/vault-rename-data-integrity

Conversation

@rogerdigital

Copy link
Copy Markdown
Owner

Pre-release hardening found during a code audit. Four data-integrity fixes; no user-facing behavior changes beyond closing these gaps.

1. Folder rename/move lost child records and manual order (data loss)

Obsidian fires a single rename event for the folder itself when a folder is renamed or moved — not one per child file. The old handler only updated tree-expansion/selection state, so:

  • The file index kept stale child records (keyed by old paths).
  • manualOrder entries under the old path became stale and were pruned on the next manual-mode render, silently discarding the user's sort for the whole moved folder.

Fix: FileIndex.renameFolder() rewrites every record at or under the old path (path + parentPath); matching manualOrder entries are rewritten via the existing renameNestedPath helper. Added 4 tests (nested files, count preservation, no-op, shared-name-prefix guard).

2. Pending manual-order save dropped on close

scheduleSaveOrder debounces the save by 500ms, but onClose only cleared the timer — it never flushed. Reordering then closing the leaf within 500ms lost the change on next load.

Fix: onClose flushes the pending save synchronously before the view is torn down.

3. Inconsistent new-file placement in manual order

The create handler appended new files to manualOrder inline, which contradicted initializeManualOrder's reconcile (which places missing files at their seed-sorted position). The resulting order depended on whether files were created before or after the last manual session.

Fix: removed the inline append; reconcile now owns new-file placement consistently with its design.

4. Names with path separators / .. created files at unintended locations

Inline create/rename only stripped leading/trailing slashes, so a name like a/b/c or foo/../bar silently created deeply nested paths or escaped the target folder.

Fix: reject names containing /, \, or .. with a Notice.

Verification

  • npm run build
  • npm run lint
  • npm test — 116 tests / 18 suites ✅ (added 4 FileIndex.renameFolder tests)

Known follow-ups (not in this PR, low frequency)

  • Mid-drag vault events can interrupt an active manual drag (DragSortManager teardown).
  • DragSortManager attaches anonymous row listeners without matching removal (relied on by DOM teardown).

These are pre-existing and rare; safe to address separately.

Obsidian emits a single rename event for the folder itself when a folder
is renamed or moved, not for each child file. The previous handler only
updated tree-expansion and selection state, leaving the file index with
stale child records and the manual order with stale paths that the next
manual-mode render would prune — silently losing the user's sort for the
entire moved folder.

Add FileIndex.renameFolder to rewrite every record at or under the old
path to its new location (path + parentPath), and rewrite matching
manualOrder entries via the existing renameNestedPath helper. Added tests
covering nested files, record-count preservation, no-op, and
shared-name-prefix guards.
Three data-safety improvements bundled (same file):

1. onClose now flushes a pending manual-order save instead of just
   clearing the debounce timer. Previously a reorder followed by quickly
   closing the leaf within the 500ms window dropped the save, losing the
   user's most recent sort on next load.

2. The create handler no longer appends new files to manualOrder inline.
   That append contradicted initializeManualOrder's reconcile, which
   places missing files at their seed-sorted position — so ordering
   depended on whether files were created before or after the last manual
   session. Reconcile now owns new-file placement consistently.

3. Inline create/rename rejects names containing '/', '\', or '..'. A
   typed or pasted name with path separators previously created files at
   unintended nested locations or escaped the target folder.
@rogerdigital
rogerdigital merged commit 67492ed into main Jun 25, 2026
1 check passed
@rogerdigital
rogerdigital deleted the fix/vault-rename-data-integrity branch June 25, 2026 03:49
@rogerdigital rogerdigital mentioned this pull request Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant