Folder model: persist the IMAP hierarchy delimiter instead of re-inferring it in parentOf() #66

Closed
opened 2026-07-01 21:18:15 +00:00 by JMR-dev · 0 comments
JMR-dev commented 2026-07-01 21:18:15 +00:00 (Migrated from github.com)

Origin: code review of PR #54. Reuse/altitude cleanup — nothing breaks today; the risk is silent drift.

Problem

parentOf() (FolderLabels.kt:64) re-infers the IMAP hierarchy separator via string arithmetic (the character before the displayName suffix of fullName), relying on an unenforced cross-layer invariant: displayName == fullName.substringAfterLast(separator), established three layers away in ImapClient.listFolders (ImapClient.kt:93-96) — which reads the authoritative JavaMail folder.separator, uses it once, and discards it. The delimiter is persisted on neither FetchedFolder, FolderEntity, nor Folder.

Verified: no current input breaks the inference (displayName is only ever produced by that one derivation, and Angus Mail already modified-UTF-7-decodes LIST names). But any future change to how displayName is derived — trimming, decoding at a different layer, a second construction site — makes fullName.endsWith(displayName) false, parentOf returns null, and colliding user folders silently degrade to the [fullPath] safety-net labels. No test would fail: FolderLabelsTest's fixture helper hard-codes the identical substringAfterLast('/') derivation.

Suggested fix

Carry the separator (or a precomputed parent path) through FetchedFolder → FolderEntity → Folder and have parentOf split on it. Needs a v12→v13 column migration — add its replay to the migration-test suite from #63.

Origin: code review of PR #54. Reuse/altitude cleanup — nothing breaks today; the risk is silent drift. ## Problem `parentOf()` (`FolderLabels.kt:64`) re-infers the IMAP hierarchy separator via string arithmetic (the character before the `displayName` suffix of `fullName`), relying on an unenforced cross-layer invariant: `displayName == fullName.substringAfterLast(separator)`, established three layers away in `ImapClient.listFolders` (`ImapClient.kt:93-96`) — which reads the authoritative JavaMail `folder.separator`, uses it once, and discards it. The delimiter is persisted on neither `FetchedFolder`, `FolderEntity`, nor `Folder`. Verified: no current input breaks the inference (displayName is only ever produced by that one derivation, and Angus Mail already modified-UTF-7-decodes LIST names). But any future change to how `displayName` is derived — trimming, decoding at a different layer, a second construction site — makes `fullName.endsWith(displayName)` false, `parentOf` returns null, and colliding user folders silently degrade to the `[fullPath]` safety-net labels. No test would fail: `FolderLabelsTest`'s fixture helper hard-codes the identical `substringAfterLast('/')` derivation. ## Suggested fix Carry the separator (or a precomputed parent path) through `FetchedFolder → FolderEntity → Folder` and have `parentOf` split on it. Needs a v12→v13 column migration — add its replay to the migration-test suite from #63.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: JMR-dev/LibreMail#66