Skip to content

ZenNotes 2.69.1 - #936

Merged
adibhanna merged 8 commits into
mainfrom
v2.69.1
Oct 13, 2026
Merged

adibhanna merged 8 commits into
mainfrom
v2.69.1

Conversation

@adibhanna

@adibhanna adibhanna commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

ZenNotes 2.69.1, desktop only.

Fix

  • On Windows, a rename onto another note's (or attachment's) name could replace that file (6d750154). The "is the destination the file itself?" guards compared fs.stat().ino as a JS number; a Windows file id is 64 bits and two neighbouring files round to one number once the id's reuse count passes 31. Every guard now goes through main/same-file.ts (bigint stats, device and inode): note, asset and folder renames, the sidecar mover, a workflow rename's cleanup and the MCP server's rename. Six new tests report Node's Windows ids and fail on the old guards. Found by the windows-11-arm job on main after 2.69.0 was tagged; the guard dates from 2.55 ([Bug] Creating new note and changing the titel does not work #839).

  • Convert Table to Database could offer an earlier heading's name in a long note (ba74c54f): headingAbove() took syntaxTree(state).length >= pos for "parsed that far", but noteMarkdown's outer tree spans the whole note while its body parse is short. It asks ensureSyntaxTree(state, pos, 50) now. Found while reading the CI backlog.

  • MCP list_tasks / toggle_task miss tasks in ordered lists and quotes (a2b4bfe7): the MCP copy of TASK_LINE_RE was bullets-only while the app's matches 1., 1) and > - [ ]. Now the same lines, with a parity test. Found by the new hazard scan's synced-copies check.

Tests

  • Five CI failures on main since September fixed at their causes (65d30daf): partial-parse reads in the task rollup, incremental parsing and code-block search tests; a cold import and a slow runner (two timeouts); a port race in test-app-core-browser.mjs (Ubuntu's "Exercise the installed editor in Chrome"). Then, on this PR, that step timed out once more for a different reason, read before re-running: a cold Chrome took 26 s to open DevTools against a 30 s wait; it gets 90 s (86e98b49).

Release workflow

  • release.yml starts on v[0-9]* instead of v* (c35ae438): every boundary viewer publish since 2.63.0 built a whole desktop release onto the viewer pre-release.

Also

  • What's New: the 2.69.1 highlight (15dc5229); version bump (e2317078).

Gates on this head: a2b4bfe7: typecheck 8/8 and test:run 6/6 with no turbo cache (shared-domain 1,994, app-core 3,221, quicklook 15, desktop 1,147), fresh build:prod green, npm audit --omit=dev --audit-level=high clean. Pack: Developer ID signed, deep strict codesign OK, bundled zn v0.7.1 in a drwxr-xr-x Resources/zn-cli, the Quick Look extension; packaged launch check: page target and drawn app in 1.5 s, version 2.69.1. Smoke suites vim-editor (12), sidebar-vim (12) and editor-improvements (19) pass on the first run. ci-sweep.py v2.69.0: two failures, both explained; hazard-scan.py --since v2.69.0: clean.

…replaces that note

Renaming a note, an asset or a folder first asks whether the destination already exists, and lets it through only when the destination is the file itself, which is how a case-only rename looks on a case-insensitive disk. That question compared fs.stat().ino as a JS number. A Windows file id is 64 bits, a reuse count above the record number, and once that count passes 31, two files saved one after the other round to the same number. The guard then took the other note for the one being renamed, and the rename replaced it. The MCP server's rename and the shared sidecar mover asked the same way; a workflow rename's cleanup did too, and kept the old file instead of removing it.

Every one of these guards now compares bigint stats (device and inode) through main/same-file.ts, the way cloud sync and the CLI's vault check already did. Six tests report the ids Node gives on Windows, the full id from a bigint stat and a rounded number otherwise, and fail on the old guards with the symptom CI showed: note and folder renames for the desktop and the MCP server, an asset rename, and a workflow rename.

CI caught the note case once, on the windows-11-arm job on main after 2.69.0 was tagged (vault.test.ts, "says when another note already has the name": the rename resolved). The guard dates from 2.55 (#839). The Go server and zn compare with os.SameFile, which reads the whole id, and are not affected.
…p release

release.yml fired on tags matching "v*", and the share viewer's boundary tags start with a v too (viewer-2.69.0-viewer.h5e7ef0f99f145d0a). Publishing a viewer draft creates its tag, so every viewer publish since 2.63.0 ran the whole desktop release: about 45 runner-minutes, two notarizations, and every installer and update feed uploaded onto the viewer pre-release. The desktop's own release and its assets were never touched; only the viewer pre-releases carry the extra files.

Desktop tags are a v and a digit, so the trigger is now "v[0-9]*". The manual rebuild path (workflow_dispatch with a tag) is unchanged. Removing the stray files from the old viewer pre-releases is left for its own decision.
What's New opens on the first launch after the update with one highlight: on Windows, renaming a note or an attachment to a name another one already has always stops and says so, instead of sometimes replacing the other file. An update from 2.68.0 shows the 2.69.0 highlights after it.
… in a long note too

Convert to database offers a name from the nearest heading above the table, read from the syntax tree when the parse has reached the table and by a line scan otherwise. "Has reached" was syntaxTree(state).length >= pos, but noteMarkdown's outer tree spans the whole note even while its body parse is still short of the table. In a long note, converting a table before the background parse got there offered an earlier heading's name. It asks ensureSyntaxTree now, which parses up to the table within 50 ms or returns no tree, and then the line scan answers.

The name was always editable before saving, so nothing was written under the wrong name unseen. A new test cuts the first parse short with a clock that moves 30 ms per read; it failed on the old check ("Early" for "Roadmap").
…and a port race stop

Five failures on main since September had no cause written down. None is a product bug, and each has its fix:

- task-rollup.test.ts read syntaxTree(state), the tree from creation after a 20 ms parse budget, which a slow runner left partial (macOS 09-14, Windows 10-08). An empty transaction picks up the tree ensureSyntaxTree finished.
- The incremental parsing tests in cm-markdown-language.test.ts ran out of an update's 20 ms budget ("no block at 634", Windows 09-23). A frozen clock lets the update's own parse, the one that reuses blocks, finish.
- search-codeblock.test.ts read code tokens before the first parse reached the code block (macOS 10-02). It forces the parse, as cm-math-render.test.ts does.
- The first note relocation test pays for the store's cold import (Windows 10-09), and workflow-apply's serialization test ran 4 to 6 times slower on one runner (Windows 09-16). Those two get longer timeouts.
- test-app-core-browser.mjs closed each port before asking for the next, so the API server and Chrome could get the same one, and /json/list then answered with the app's HTML. That is the Ubuntu "Exercise the installed editor in Chrome" failure the release runbook listed as a known flake. The three ports are now read while every listener is still open.
* the table, it does not delete files.
*/
import { syntaxTree } from '@codemirror/language'
import { ensureSyntaxTree, syntaxTree } from '@codemirror/language'
…p does

The app's Tasks view reads task lines with @shared/tasklists' TASK_LINE_RE: bullets, ordered lists (`1. [ ]`, `1) [ ]`) and quoted tasks (`> - [ ]`). The MCP server scanned with its own copy, commented "kept in sync" but bullets only, so list_tasks never showed an ordered or quoted task, toggle_task could not reach one, and every task below one in the same note got a different index than the app counts. The copy now matches the same lines; toggling still changes only the character inside the brackets, so ordered numbers and quote markers stay as written.

Two tests: the scanner sees exactly the lines the shared regex matches in a note with every shape, and an ordered and a quoted task toggle in place. Both failed on the old copy. The Go server's and zn's task regexes still differ from the app's (no quoted tasks; the server also has no `1)`), which is theirs to fix in their repos.
On 2.69.1's release PR, Ubuntu's "Exercise the installed editor in Chrome" failed with "Chrome startup: The operation was aborted due to timeout". The ports were distinct this time (server 35179, preview 42673, DevTools 34861), so it was not the port race fixed in 65d30da: Chrome printed nothing for 20 seconds after launch and opened DevTools about 26 seconds in, against a 30 second wait. The same step on the previous push finished the whole browser check in 21 seconds. Chrome's startup wait is now 90 seconds; the servers keep 30.
@adibhanna
adibhanna merged commit 86e98b4 into main Oct 13, 2026
10 checks passed
@adibhanna
adibhanna deleted the v2.69.1 branch October 13, 2026 19:05
@adibhanna
adibhanna restored the v2.69.1 branch October 13, 2026 19:05
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.

2 participants