P4-5: Pinning, eviction policy and free-space management #48

Open
opened 2026-09-10 18:10:10 +00:00 by Cordy · 0 comments
Owner

Depends on P4-4. Platform-independent — testable on the Pi runner.

Goal

Decide what stays local and what gets evicted, so the folder honours a disk budget without ever
losing data or evicting something the user is about to need.

Files

  • Create: internal/vfs/evict.go, internal/vfs/evict_test.go
  • Modify: internal/config/config.go (disk budget setting)

The rules

Eviction is never data loss — and this is the property that makes the whole feature safe.
Dehydrating discards a local copy of content that exists on the server. So:

  • Never evict a file with unsynced local changes. If sync_state is anything other than
    synced, it stays. Evicting a pending upload destroys the only copy of the user's work.
  • Never evict PinAlways.
  • Never evict while a file is open. Check for open handles; skip if uncertain.
  • Verify before discarding. Confirm the server has the current content — matching ETag and
    size — immediately before dehydrating. If the check fails for any reason, keep the file. The
    cost of being wrong is asymmetric: keeping a file wastes disk, evicting one wrongly loses work.

Eviction order for PinAuto files, once the budget is exceeded: least-recently-used, oldest
first. Track access time on hydration and on read.

Configuration

  • maxLocalBytes — soft disk budget for hydrated content. Default: unset (evict only on
    explicit request).
  • evictAfterDays — optionally dehydrate untouched files after N days. Default: off.
  • Both policy-controllable (P3-1), so an organisation can standardise a fleet's disk usage.

Defaults are conservative on purpose. Silently deleting local copies from under a user is
alarming even when technically safe. Make the aggressive behaviour opt-in.

"Free up space"

A user-triggered action: dehydrate everything eligible, now. Report how much was reclaimed. This
is the operation people actually reach for, and it should feel instant and safe.

Steps

  • Implement the eligibility check with all four "never evict" rules.
  • Implement LRU ordering and the budget calculation.
  • Implement "free up space".
  • Write failing tests: a file with pending changes is never evicted; PinAlways is never
    evicted; an open file is never evicted; an ETag mismatch aborts eviction for that file;
    LRU picks the right victims; the budget is respected.
  • Write the adversarial test: mark a file as having unsynced changes, run eviction under
    extreme budget pressure, assert the file still exists with its content intact.
  • Commit: git commit -s -m "feat(vfs): pin-aware eviction and disk budget"

Acceptance criteria

  • No eviction path can discard content the server does not already have.
  • All four never-evict rules hold under test.
  • Defaults do not evict anything without explicit user action.
  • Runs entirely on the Pi runner against FakePlaceholderFS.
Depends on P4-4. Platform-independent — testable on the Pi runner. ## Goal Decide what stays local and what gets evicted, so the folder honours a disk budget without ever losing data or evicting something the user is about to need. ## Files - Create: `internal/vfs/evict.go`, `internal/vfs/evict_test.go` - Modify: `internal/config/config.go` (disk budget setting) ## The rules **Eviction is never data loss** — and this is the property that makes the whole feature safe. Dehydrating discards a *local copy* of content that exists on the server. So: - **Never evict a file with unsynced local changes.** If `sync_state` is anything other than synced, it stays. Evicting a pending upload destroys the only copy of the user's work. - **Never evict `PinAlways`.** - **Never evict while a file is open.** Check for open handles; skip if uncertain. - **Verify before discarding.** Confirm the server has the current content — matching ETag and size — immediately before dehydrating. If the check fails for any reason, keep the file. The cost of being wrong is asymmetric: keeping a file wastes disk, evicting one wrongly loses work. **Eviction order** for `PinAuto` files, once the budget is exceeded: least-recently-used, oldest first. Track access time on hydration and on read. ## Configuration - `maxLocalBytes` — soft disk budget for hydrated content. Default: unset (evict only on explicit request). - `evictAfterDays` — optionally dehydrate untouched files after N days. Default: off. - Both policy-controllable (P3-1), so an organisation can standardise a fleet's disk usage. **Defaults are conservative on purpose.** Silently deleting local copies from under a user is alarming even when technically safe. Make the aggressive behaviour opt-in. ## "Free up space" A user-triggered action: dehydrate everything eligible, now. Report how much was reclaimed. This is the operation people actually reach for, and it should feel instant and safe. ## Steps - [ ] Implement the eligibility check with all four "never evict" rules. - [ ] Implement LRU ordering and the budget calculation. - [ ] Implement "free up space". - [ ] Write failing tests: a file with pending changes is never evicted; `PinAlways` is never evicted; an open file is never evicted; an ETag mismatch aborts eviction for that file; LRU picks the right victims; the budget is respected. - [ ] **Write the adversarial test:** mark a file as having unsynced changes, run eviction under extreme budget pressure, assert the file still exists with its content intact. - [ ] Commit: `git commit -s -m "feat(vfs): pin-aware eviction and disk budget"` ## Acceptance criteria - No eviction path can discard content the server does not already have. - All four never-evict rules hold under test. - Defaults do not evict anything without explicit user action. - Runs entirely on the Pi runner against `FakePlaceholderFS`.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/cairn-desktop#48
No description provided.