Skip to content

Keep notes readable after moving a folder with a backslash in its name - #259

Merged
BunsDev merged 2 commits into
mainfrom
notes-settlement-validate
Oct 16, 2026
Merged

BunsDev merged 2 commits into
mainfrom
notes-settlement-validate

Conversation

@BunsDev

@BunsDev BunsDev commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Part of #241 (finding 1: "A settlement journal can wedge every read").

What was wrong

Moving or renaming a folder that has a folder note goes through a journal, .modex/settlement.json. moveNodes() and settle() wrote that journal first. Only finishSettlement() checked it. Those checks refuse any path part that contains \, which Finder allows on macOS. Take a folder Personal/Notes/R\D with its note R\D.md:

  1. Modex wrote its journal.
  2. The reader refused the journal as "Invalid folder rename intent" before renaming anything.
  3. The journal stayed on disk, so every later read threw the same error, even after a restart.

Probe on main (f17608d):

move: Space could not read saved pages. Your file has been preserved. Invalid folder rename intent.
journal left: true
restart read: Space could not read saved pages. Your file has been preserved. Invalid folder rename intent.

Renaming the folder takes the same path. So does editing its page's title and then opening another page, because that settles the old page. The renderer ignores settle errors, so in that case the notes became unreadable with no visible cause.

What changed

The fix is in apps/desktop/src/main/engine/notes-store.ts.

  • Shared checks. The reader's checks moved, unchanged, into validSettlement(). The writer and the reader both call it.
  • Checked before writing. startSettlement() runs the checks first. If they fail, it writes nothing.
    • Move: Modex refuses with "A folder with a backslash (\) in its path can only be moved in Finder." Nothing on disk changes.
    • Rename or settle: the folder keeps its name on disk and its note keeps the new title. This matches how Modex already keeps a title that a file name cannot carry.
  • Bad journals are set aside. A journal can fail the checks: an invalid intent, a malformed move version, or unreadable JSON. finishSettlement() used to throw on every read in that case. Now it renames the file to .modex/settlement.invalid-<uuid>.json, logs that it did, and carries on with the folders as they are. This is safe: a reader refuses a journal before renaming anything, so no rename is half done. Read errors that carry an errno code other than ENOENT still throw.

Same probe after the fix:

move: A folder with a backslash (\) in its path can only be moved in Finder.
journal left: false
restart read: 1 pages

Regression tests

  • notes-tree.test.ts, "a move/rename of a folder with a backslash in its name leaves notes readable" (one test each):
    • Creates R\D/R\D.md and a child note the way Finder would, then moves or renames the folder through NotesStore.
    • Then reads through the same store and through two fresh stores, which stand in for a restart. Checks the tree, the folder's place and name, and the child's parent.
    • Checks that no journal is left behind.
  • notes-store.test.ts, "a folder rename journal with … is set aside instead of failing every read":
    • One case puts on disk a journal like the ones older versions wrote, with a backslash path. Another puts one with unreadable JSON.
    • Reads work through fresh stores and through the same store.
    • The folders are unchanged, and the journal is kept byte for byte under its new name.

All four tests failed on unmodified main and pass with the fix.

What I ran

  • Rebased onto 5efafc4 (Make Analytics look like the rest of Modex and fit the window #248). pnpm build: passed.
  • pnpm test:
    • Worktree scripts: 107/107. Core: 16/16.
    • Desktop: 1,441 tests, with 1,424 passing, 16 skipped, 0 failing and 1 cancelled. The cancelled test was demo.test.js "demo waits for a slow turn to reach approval before auto-answering", which reached its 5 s timeout while the machine was under heavy load. Run alone, it passed (3/3, 2.3 s). It does not touch notes.
    • pnpm stops after the first package that fails, so I ran the remaining steps separately. Desktop native and update checks: 21/21. Site: 10/10. Store-desktop: 16/16.
  • All notes test files (notes-tree, notes-store, notes-files, notes-projects, notes-migration): 76/76 pass.
  • pnpm --filter @modex/desktop typecheck: clean.

There is one new line in docs/status.md, under "On main, unreleased".

Coven-Harness: Claude Code / claude-opus-5-5

Before: moving or renaming a folder that has a folder note and a backslash
in its path (Finder allows one) wrote .modex/settlement.json, then the
reader refused it as "Invalid folder rename intent". The journal stayed, so
every later read of the notes threw, even after a restart.

After: the journal is checked with the same rules before it is written. A
move of such a folder is refused with a message to move it in Finder, and a
rename keeps the folder's name while its note carries the new title. A
journal that fails the checks (left by an earlier version, or unreadable)
is set aside as .modex/settlement.invalid-<id>.json with the folders left
as they are, instead of failing every read.

Coven-Harness: Claude Code / claude-opus-5-5
@vercel

vercel Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
modex Ready Ready Preview Oct 16, 2026 7:59am UTC

Request Review

@github-code-quality

github-code-quality Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Code coverage overview

Languages: TypeScript

TypeScript / code-coverage-agent

main bdc4bdf notes-settlement-val... 1d9b305 +/-
61% 61% 0%

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.


Updated October 16, 2026 08:33 UTC

…date

# Conflicts:
#	apps/desktop/src/main/engine/notes-store.ts
#	docs/status.md
@BunsDev
BunsDev merged commit b8ac801 into main Oct 16, 2026
13 checks passed
@BunsDev
BunsDev deleted the notes-settlement-validate branch October 16, 2026 08:33

This branch was successfully deployed

1 active deployment
Preview — 1d9b305e Deployed Oct 16, 2026 by vercel[bot]
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