Repository navigation
v4.3 — Mostly repair, and one new thing
Mostly repair, and one new thing. v4.2 built the setup form and filled in the menu bar.
v4.3 is what three reviews of the shipped code found underneath, and most of it is one
mistake wearing different clothes: a file that existed but could not be opened was read
as a file that was not there. Nothing was lost on that read. The loss came on the next
write — saving needs permission on the folder, not the file, so the save succeeded exactly
where the read had failed, and replaced what it could not read with a blank start.
Six stores sat behind that mistake, and the rest of the release is the same theme in other
places: undo trusting a folder it had only glanced at, removal gates trusting verdicts that
had gone stale while a dialog was open, and cloud placeholders read as though their contents
were on disk.
On the v4 line, so it requires macOS 26 — coming from 3.x or 2.x, read the v4.0 section
first.
Go to
- Every Settings tab is a ⌘K destination, matched on the words of the controls inside
it. Typing "appearance" used to match nothing: the word lived only in Settings' own
search field, which you cannot reach without already having Settings open. The palette had
a single "Settings…" row, and it opened whichever tab you were last on. There are now ten,
one per tab, in the rail's own order, and each is matched on the folded-down vocabulary of
every control it holds — so "glass", "log level" or "accent" find the page that carries
them.
Files the app could have destroyed
- A file that exists but cannot be read is no longer mistaken for one that isn't there.
Six stores made this mistake, each with a guard that consulted only the decode result and
never the failure to open: your household (people.json), which person a document belongs
to (person-tags.json), Storage's per-root snapshots, the classifications the filing engine
has paid a model for, the log of people you have refused, and the filing corpus. The
consequences differed and were all silent — the first edit to a person replaced the entire
household with a folder-name seed; the first verdict overwrote every verdict already there;
one refusal wiped the record of everyone you had ever declined; the next analysis wrote one
root's snapshot over all twelve. Each store now tells the two apart, moves the bytes it
could not read aside under a name no later rescue can take, and refuses the write until
that has actually landed. The re-survey's write over an unreadablefiling-memory.jsonis
closed the same way. - A setting only a newer build understands survives your next edit of it. Five of the
persisted settings read tolerantly — anything unexpected falls back to the default, which is
right, because the app has to start whatever is on disk — and then wrote the live value back on
the next change. So a value this build could not interpret (a foreign type, or a raw value a
newer build introduced) read as the default and was overwritten by it the first time you touched
that setting. Five disabled providers became one on the next toggle; a sort order chosen in a
newer build vanished on the first edit after going back. The original is now kept beside the
setting before the default is used, and the log says so. The same read-then-overwrite shape is
closed for the pane bar's arrangement, where a control added by a newer build was dropped the first
time you edited the bar on an older one. - A key written on a person survives an edit. Notes and unknown keys sitting beside
peoplein the roster were already carried across a save; keys written on a person were
not. The model reads five fields, drops the rest, and the whole file is rewritten — so a
nickname, or a_whytyped next to the person it explains, was gone the first time
anybody edited anybody, silently, because what is left behind is still a well-formed roster. - An unreadable filing artifact suspends the classification cache instead of quietly
changing its key. Leaving an unreadable artifact out of the cache fingerprint mints a key
that can never occur again once the file is fixed — so every classification already paid
for became unreachable, and the same documents would be sent off and paid for a second
time. The fingerprint now reports itself unavailable and the cache is switched off for that
pass. It is also derived from the folder the artifacts actually came from, rather than a
field inside a file that can disagree with it.
Cloud files that are not on disk
- Offloaded Dropbox, OneDrive, Google Drive and Box files are recognised as placeholders.
The availability check asked iCloud's question —isUbiquitousItem, false for every
non-Apple File Provider — and so answered "the contents are here" for every other
provider's evicted file. Online, a filing survey opened them and made the provider download
your entire offloaded library. Offline, they were recorded as blank against a size and date
that do not change when a file is materialised, so they were written off permanently and
never revisited.
Undo and redo
- ⌘Z after copying a folder no longer destroys the work you did inside the copy. The
copy-undo compared a folder's own modification date and its immediate child count, which an
edit two levels down leaves untouched — so ⌘Z read the copy as pristine and trashed it,
with the edit inside, permanently on a volume with no Trash. It now records a digest of the
whole tree, takes that baseline the moment each copy lands rather than after the whole
batch, and ignores the.DS_Storethat merely opening the copy in Finder leaves behind. - Redoing a delete no longer trashes whatever has taken the path since. The redo
re-trashed by bare path, and being on its list means "the undo put our item back here" —
which stops being true the moment something replaces it. Delete a file, ⌘Z, let a different
file land on that path, ⌘⇧Z, and the replacement went to the Trash with no banner and no
log line. - A "press ⌘Z to undo" stops standing after the step it points at. The banner carries a flag
that retires the offer once anything else registers an undo, and the rename pass and the name
normalizer put the sentence in the text without setting it. So after either of them, running any
other operation left the offer on screen — by then pointing at that operation instead. The merge
banner had the opposite half missing: a merge that folded and trashed nothing registers no undo
at all, and still offered one, which sent ⌘Z at whatever you had done before the merge. - File operations run strictly in the order you asked for them. The serial queue's
prologue hopped off the main actor and back before claiming its slot, so two operations
starting together could chain onto the same predecessor and run concurrently. The worst
reachable form was a merge's own undo pair inverting: the folded files deleted back out of
the keeper before the original was restored.
Duplicates, merging and deleting
- Folder duplicate groups are judged file by file. The check that a folder had not changed
since the scan counted its contents by different rules than the scan used — counting the
.DS_Storethe scan ignored, and measuring a symlink's own bytes where the scan recorded
none. Any group holding either was refused as "changed since it was scanned", permanently,
because a rescan reproduces the same difference. The same constant offset could equally mask
a real loss, and a count-and-bytes rollup can never see a same-length rewrite inside a
folder about to be removed. - The Compare review checks what it is about to trash, and stops promising an undo it
cannot honour. For a folder — and Compare is the folder-only flow — the gate passed on
existence alone, so a file that landed in the right-hand folder while the review sat open
was trashed along with it. Its confirmation also read "Reversible with ⌘Z" unconditionally,
including on volumes with no Trash, where the copy is destroyed outright and nothing reaches
the undo manager. - Merging duplicates is safer to undo and safer to trash after. The merge held an undo
group open across every suspension, and undo grouping is global to the window, so an
unrelated operation finishing in that window was swallowed into the merge's step and came
back with one ⌘Z. The keeper was checked once, before a copy loop that can run for minutes,
and for a folder that check degenerated to "does it exist" — so a keeper emptied mid-merge
still had its redundant copy trashed, with the folded files nowhere. Edit ▸ Undo also
offered to reverse merges whose copies had been destroyed permanently. - The permanent-delete confirmation names what it is about to destroy. The app's one
unrecoverable dialog said "permanently delete these N items?" and discarded the list — and
for a single item showed only the basename, which is no help when the two candidates are
duplicate copies with the same name. - A dangling symlink is deleted instead of reported as already gone. The trash was gated
on an existence check that follows the link, so a symlink whose target had been deleted
answered "not there", and that branch had no else: no error, no banner, no place in the
removed count. You were told the delete succeeded and the link stayed where it was.
Verdicts that had gone stale
- The verified-copy offer re-checks both ends before it writes. Its guards count this
app's own writes and nothing else, and the dialog never expires — so a cloud daemon syncing
down a new version while the offer sat open was invisible, and confirming bulk-overwrote
with bytes that were never the ones hashed. syncre-checks its plan against disk before each write. The plan was drawn once at
scan time and then executed however long the[y/N]prompt sat there,--verifyincluded.
A file rewritten while you read the list was overwritten by the stale copy the plan picked.- An automation checks a row is still its file before moving it. The apply gated on
nothing more than a non-empty destination, and a dry-run report can sit on screen for
minutes. Anything that took a row's path in the meantime was moved in its place.
Filing
- A cloud filing pass stands down when it cannot price the model. The spend check read a
missing price as zero — and missing means "this build has no rate for that model id", which
a hand-set model reaches in ordinary use. Zero is the one substitute that fails every
consumer in the same direction: the estimate reads as free and the cap cannot bind. - "Try another folder" says no before it spends, not after. It routes to the paid tier — it
is the one click in the app whose whole point is asking the better model again — and it ran no
pre-flight at all: no estimate, no cap warning, and no refusal for a model this build has no rate
for. The hard lifetime and monthly caps still stopped the call, but only once it was already
assembled, and nothing on screen said so. The check now happens on the click: it stands down when
the caps are reached or the model has no known price, keeps the free on-device suggestion, and
says which of the two happened and where to change it. - "Try another folder" sends the page it already read. The re-ask went out with the file's
name and nothing else, even though the scan had already extracted its first page and was holding
it. A name-only answer is one the card refuses anyway, so that was a paid round trip that could
not change anything. Nothing extra is read from disk — the page was already in hand. - A file whose date cannot be read is asked again rather than answered from a stale verdict.
The classification cache keyed an unreadable modification date as1970-01-01and an unreadable
size as0 bytes— two values a real file can genuinely have. A document whose date stayed
unreadable while its contents changed therefore kept the same key and was served the old,
already-paid-for answer. Such a file is now simply left out of the cache in both directions. - A file whose scan never came back is no longer stuck. The in-flight set that "Read
scan" holds a file in was released only when the round trip returned, and the extractor has
no timeout — so a render that never came back left the file latched, every later attempt a
silent no-op, surviving any number of rescans. Switching provider now clears it. Separately,
"File recommended" can no longer be started twice.
The keyboard
- The Organize review card's ⏎ and ⌫ decide once, unmodified, and only when the card has
focus. This is the surface where ⏎ moves real bytes. Every modifier combination ran the
primary action — ⌘⏎, ⇧⏎, ⌥⏎ and ⌃⏎ each performed the copy or move. A held ⏎ launched four
copies of one row. ⌘⌫, ⌥⌫ and ⇧⌫ each irreversibly skipped a row. The keypad's Enter did
nothing while the hint row advertised ⏎. And neither key checked whether the card held
focus, so with Full Keyboard Access on, ⏎ aimed at the focused Skip button ran the copy — a
focused macOS button activates on Space, not Return. ↩ in a pane had the same modifier
problem and now shares the fix. - The filing walkthrough's ⏎, → and esc stay inside the card. They were window-level key
equivalents, which macOS consults before the first responder — so ⏎ typed into the lens
header's search field filed the document on screen, → skipped one with no way back, holding
either decided document after document, and an esc meant for the search field discarded
every approval. The walkthrough also has a voice in VoiceOver now; its decision surface
previously read as three unrelated siblings with nothing saying which file was being decided.
Renaming
- A case-only tidy lands on the cased name, and case-only renames work at all. Renaming
07. jul 2016.pdfto07. Jul 2016.pdfproduced07. Jul 2016 2.pdf— the
destination check compared case-sensitively on a volume that folds case, so the file
collided with itself and got a duplicate marker from nowhere, which the next scan preserves
as though you meant it. One layer down, the primitive resolved both paths through
realpath, which also folds case, and threw "source and destination are identical" — so
every case-only rename failed, the Rename field included: you could not renamefooto
Foo. A cohort rename that fails partway now rolls back whole instead of leaving two files
sharing a slot number.
Also
- The ⌘K results panel no longer paints dark notches at its corners, and the bulk difference
menu acts on rows as they are when you pick an item rather than when you right-clicked. - A symbolic link can be moved into the folder it points at. The check that stops a folder being
moved inside itself followed the link first, so an alias and its target read as one container and
an ordinary move was refused. - A folder name typed into "Create as" no longer follows you to a different destination. Pressing
"Try another folder" replaced the suggestion under the same card while the field kept what you
had typed, so "File here" could apply a name meant for one folder to another one entirely. synccloudrefuses an argument that names both a configured provider and a different folder on
disk, instead of silently picking one.- The Help book now covers what v4.2 added — the file clipboard, the Storage bars and the ⌘K
redesign shipped without ever being described in the book that describes the app.
Known limitations
- Browse's folder sidebar is built and reachable from nothing. It is not listed above
because nothing you can press opens it. It ships when something does.