Verified against a live install: vacuum reported "34.3 MiB freed (170.3 MiB
-> 136.0 MiB), 0 WAL frame(s) checkpointed" while the WAL grew from 67 MiB to
143 MiB. Net disk use barely moved, and the frame count was zero because the
checkpoint ran before the VACUUM, when there was nothing to fold.
Reordering is strictly better, but the commit message should not overstate it:
the live inflation happens because the daemon's other connections hold read
transactions and a TRUNCATE checkpoint waits on readers, so under a busy
daemon this can still move little. journal_size_limit stays the backstop --
the live WAL did fall back to its 64 MiB cap on its own afterwards.
The accompanying test deliberately does not assert on WAL size or frame count.
Measured both ways, a single-connection test reports frames=0 and a 0-byte WAL
under either ordering, because SQLite folds the log itself without a
concurrent reader to block it; an assertion there would pass on the bug and be
decoration. It asserts what is reliably true instead -- that a file-backed
vacuum reclaims space and leaves the database sound -- and the ordering
rationale plus the residual uncertainty are documented on vacuum() itself.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JFzNQyb4TWrCRWcnegqWxY
A corrupt database or an oversized cache previously left the user with no
answer but "delete the state directory and re-sync", which for a large
account means re-downloading everything to fix a problem that may have been
a few stale rows.
pdfs diagnose reports on paths, keyring, daemon, and mountpoint, and exits
non-zero if any check fails so it works in a health check. Every check is
written to run with no daemon, because that is the situation it gets run in:
a stopped daemon is reported as a finding rather than aborting the report.
Writability is tested by writing, since permission bits say nothing about a
full disk or a read-only remount.
pdfs cache inspect reports database size, reclaimable space, per-table row
counts, and cache usage; --deep adds SQLite's integrity check, opt-in because
it reads every page. The report distinguishes "checked and clean" from "not
checked" rather than letting an empty problem list imply a clean bill of
health it never gave.
pdfs cache vacuum checkpoints the WAL and compacts the database.
Deliberately no orphaned-cache-row pruning: ContentCache::reconcile already
rebuilds the index from what is on disk at every open, so a second pass here
would duplicate it against a worse view of the truth. The WAL is likewise
left to journal_size_limit, which already caps it -- a periodic checkpoint
would paper over a problem that no longer exists.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JFzNQyb4TWrCRWcnegqWxY
Mirror folders walked and uploaded every path under their root, so syncing a
project directory pushed node_modules/, target/, and .git/ to Drive -- quota
spent on files nobody wants there, and enough API traffic to invite rate
limiting.
Rules come from a .pdfsignore (or .protonignore) at the folder root, unioned
with an ignore_patterns list in config.json that defaults to the usual build,
VCS, and editor-leftover globs. Both are re-read at the start of every pass,
so edits apply without restarting the daemon.
The filter deliberately sits on the classification union in
classification_order(), not on walk_local alone. do_reconcile classifies
local | remote | baseline, so a file synced before a rule started matching it
is absent from local but present in the other two -- the "local deleted,
remote untouched" arm, which calls trash_nodes. Filtering only the walk would
have meant that adding a line to .pdfsignore silently trashed files on Drive
on the next pass. Ignored baseline rows are left in place so un-ignoring
re-adopts the existing remote file instead of re-uploading it.
guard_local_wipe takes a filtered baseline for the same reason: an ignored
path is absent from the walk by rule rather than by loss, and counting those
as missing would trip the guard on every pass once a rule covered the tree,
wedging that folder's sync permanently.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JFzNQyb4TWrCRWcnegqWxY
Remove the local proton-sdk path patch so the workspace builds from published crates, and document Fedora 44 build/runtime plus a local RPM spec.
Co-authored-by: Cursor <cursoragent@cursor.com>
relocate() called forget(), dropping the node's by_uid mapping, so
the re-enumeration assigned a fresh inode. The kernel had already
carried the renamed dentry onto the old one and holds it for the
entry TTL, so lookup/getattr/opendir resolved to an inode entries
no longer held and returned ENOENT — while readdir walked children
and reported the new inode. A renamed directory listed in its
parent but could not be entered until the TTL expired.
Rewrite the node in place and invalidate both parents' listings
instead. Also stops the moved node's DB row being deleted and
recreated on every move, which the B1 data-loss fix worked around