fix(export-notes-json): stop silently dropping/duplicating notes with duplicate titles - #116
Conversation
… duplicate titles `exportNotesAsJson` listed each folder's note titles via `listNotes()`, then re-fetched each note a second time by title via `getNoteDetails(title, account)` / `getNoteContent(title, account)`. AppleScript's `note "<name>"` specifier resolves an ambiguous (duplicated) name deterministically to the same one note every time, so every loop iteration for a title with N duplicates re-fetched the *same* underlying note N times — even though the bulk listing one call earlier had already correctly deduped and counted N distinct notes by id. The export ended up with one note repeated N times (same id, same content) and the other N-1 real notes silently missing, with no error or count mismatch surfaced. The fix threads the ids already produced by the bulk AppleScript listing through the export loop and re-fetches by id (`getNoteById` / `getNoteContentById`) instead of by title — the same identity-safe pattern `searchNotes` and `deleteNoteById` already use elsewhere in this file. `listNotes()`'s public `string[]`-of-titles contract is unchanged. Added a regression test that reproduces the actual bug mechanism (two distinct notes sharing a title, with a mock that mirrors AppleScript's real ambiguous-name resolution) rather than one that merely queues mock responses in call order. Version bumped to 2.6.12 and CHANGELOG.md updated per this repo's release conventions (CONTRIBUTING.md). Fixes sweetrb#115 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…adings The [Unreleased] section had accumulated entries for two versions that already shipped (v2.6.10 2026-07-22, v2.6.11 2026-07-31), because nothing in the release path renames [Unreleased] to the version being cut — the `version` lifecycle script only syncs the plugin manifests. Entries for released code sitting under [Unreleased] misreport what a given install contains. Files each entry under the release that actually shipped it, and puts this PR's export-notes-json fix under [2.6.12]. Bullet text is untouched; only headings move. An empty [Unreleased] is deliberately kept at the top — dependabot-rebuild.yml hard-exits when that marker is missing.
|
Reviewed — merging. Excellent root-cause work, @draku. The diagnosis is the valuable part here: spotting that Two things I checked carefully and want to record:
Verified against a real 359-note library (4 accounts, 8 folders, 5 genuinely-duplicated titles), driving
The 5 duplicate titles correctly survive in both, since those are distinct notes that legitimately share a name. That's the bug reproduced and closed on real data, not just in the mock. Your regression test is the right shape too — mirroring AppleScript's ambiguous I pushed one follow-up commit ( Also worth noting: CI initially showed no checks at all on this PR — the first-time-contributor approval gate, not anything wrong with your branch. Approved and everything passes ( Shipping in 2.6.12. Thanks for the thorough writeup on #115 as well — the real-world examples ("Rust Package Registry", 8 notes collapsing to 1) made the impact immediately legible. |
|
Happy to help. Thx |
Description
export-notes-jsonsilently dropped and duplicated notes whenever two or more notes in the same account/folder shared an exact title.exportNotesAsJson()listed note titles per folder, then re-fetched each note a second time by title (getNoteDetails(title, account)/getNoteContent(title, account)). AppleScript'snote "<name>"specifier resolves an ambiguous (duplicated) name deterministically to the same one note every time, so every loop iteration for a title with N duplicates re-fetched the same underlying note N times — even though the bulk AppleScript listing one call earlier had already correctly deduped and counted N distinct notes by id. The export ended up with one note repeated N times (same id, same content) and the other N-1 real notes missing, with no error or count mismatch surfaced.The fix threads the ids already produced by the bulk listing through the export loop and re-fetches by id (
getNoteById/getNoteContentById) instead of by title — the same identity-safe patternsearchNotesanddeleteNoteByIdalready use elsewhere in this file.listNotes()'s publicstring[]-of-titles contract (used by thelist-notestool) is unchanged.Fixes #115.
Type of Change
Testing
pnpm test) — 519 passed, including a new regression test (exports both notes when two notes share an exact title) that reproduces the actual bug mechanism: a mock that mirrors AppleScript's real ambiguous by-name resolution, hand-verified to fail against the old title-based code and pass against the new id-based code.pnpm run lint)pnpm run typecheck && pnpm run format:check)pnpm run build)Checklist
src/**excluding tests, or the runtimedependenciesinpackage.json): version bumped at least a patch (2.6.11→2.6.12) + a CHANGELOG.md entry — therequire-version-bumpCI check enforces this (docs-only and test-only PRs are exempt)