Add a guarded early-eviction tier for large verified cache copies #15

Merged
ClaudiuSchuster merged 7 commits from oss-oo/cache-policy-rt20261009 into main 2026-10-09 06:21:51 +00:00
Owner

What this changes

A conservative early-eviction tier for large verified cache copies (owner
decision "A", 2026-10-09): verified CLEAN cache copies at or above 1 GiB age
out after a configurable short window (default 2 h) instead of waiting the
full 24 h cache-max-age. Small files keep the 24 h default.

  1. Mechanism — extends the existing pdrive-cache-age helper family (no
    parallel evictor): a second, shorter age tier that applies only to files
    at or above the fixed 1 GiB threshold AND verified clean — never dirty,
    pending, uploading, error or conflict-flagged. In-use protection via the
    existing activity clocks; when in doubt the helper skips (fail-safe =
    keep). Works on the cache directory only — mount options and the cache
    fingerprint are untouched.
  2. Automation — systemd/user/pdrive-cache-evict.timer (15 min,
    draft-recovery timer pattern) drives the guarded auto path; it is
    authorized by the saved preference and a no-op when the preference is off
    (double no-op at the 24 h choice). Carried by the installer (glob install
    • inventory/layout checks extended).
  3. Preference row (new) — Preferences gains one row, EN + DE: "Large
    verified cache copies: Keep 1 h / 2 h / 6 h / 24 h (default 2 h)",
    persisted in pdrive-cache.conf (single source of truth alongside the
    helper grammar), Apply/Save sensitivity per contract, activation on the
    next timer tick; running transfers unaffected. Threshold fixed at 1 GiB,
    documented as such.
  4. Surfacing — pdrive-state reports the tier (additive schema) and the
    Control Center cache card tooltip mentions the policy short form; no new
    cards or graphs.
  5. Docs — docs/OPERATIONS.md gains the full settings reference entry
    (access path, choices + default, persistence, activation timing, safety
    impact) and the cache section notes the tier; the TROUBLESHOOTING
    disk-usage expectation now mentions the early tier.

Evidence

  • Independent validation: ACCEPT-WITH-FINDINGS — 8/8 PASS (safety
    invariants, timer pattern, preference row, state/UI surfacing, installer
    coverage, docs, tests + gates, spec sweep). The two doc findings (wrong
    command example, stale TROUBLESHOOTING expectation) are fixed in this
    branch (1c2a181); the formatting finding is fixed at source (0c0ec49,
    prettier 3.5.3).
  • Rebase: branch was stacked on the pre-merge polish commit; rebased
    cleanly onto fresh main (8714697, v0.9.5) — git auto-skipped the
    already-merged base; the 5 round commits replayed without conflicts.
  • Gates: make check green on the rebased tree (twice, incl. after the
    formatting commit); git diff --check clean; changed Markdown passes
    prettier@3.5.3 --check.
  • Tests: new tests/test-cache-evict.sh (243 lines: threshold boundary,
    clean-only enforcement, in-use skip, policy-off no-op, tier arithmetic,
    timer enable/disable) plus cache-age, state, systemd, preferences and
    widget extensions.

Non-blocking findings (recorded; from the validation dossier)

  • In-use protection is timestamp-based (metadata ATime + data
    atime/mtime) with a small read-metadata→unlink race (TOCTOU): within the
    spec's "existing helper heuristics" allowance; the worst case is a
    re-download of provably clean data, never loss of dirty state.
  • No dedicated test leg for "vfs/stats OK but vfs/queue unavailable" (both
    fail together in scenario D) and no dedicated 1 h-choice scenario — same
    code path as covered scenarios (shared rc() helper, same grammar).

CI fix (run 40)

The first CI run failed in the new eviction test: its unreadable-policy leg
used a mode-0000 config file, which the CI container's root user can still
read (locally the checks run as a normal user). The leg now makes the config
path a directory, so the read fails with OSError for every user — the tested
invariant (unreadable policy ⇒ nothing is evicted) is unchanged. make check
green on the fixed tree.

## What this changes A conservative early-eviction tier for large verified cache copies (owner decision "A", 2026-10-09): verified CLEAN cache copies at or above 1 GiB age out after a configurable short window (default 2 h) instead of waiting the full 24 h cache-max-age. Small files keep the 24 h default. 1. **Mechanism** — extends the existing `pdrive-cache-age` helper family (no parallel evictor): a second, shorter age tier that applies only to files at or above the fixed 1 GiB threshold AND verified clean — never dirty, pending, uploading, error or conflict-flagged. In-use protection via the existing activity clocks; when in doubt the helper skips (fail-safe = keep). Works on the cache directory only — mount options and the cache fingerprint are untouched. 2. **Automation** — `systemd/user/pdrive-cache-evict.timer` (15 min, draft-recovery timer pattern) drives the guarded auto path; it is authorized by the saved preference and a no-op when the preference is off (double no-op at the 24 h choice). Carried by the installer (glob install + inventory/layout checks extended). 3. **Preference row (new)** — Preferences gains one row, EN + DE: "Large verified cache copies: Keep 1 h / 2 h / 6 h / 24 h (default 2 h)", persisted in `pdrive-cache.conf` (single source of truth alongside the helper grammar), Apply/Save sensitivity per contract, activation on the next timer tick; running transfers unaffected. Threshold fixed at 1 GiB, documented as such. 4. **Surfacing** — `pdrive-state` reports the tier (additive schema) and the Control Center cache card tooltip mentions the policy short form; no new cards or graphs. 5. **Docs** — `docs/OPERATIONS.md` gains the full settings reference entry (access path, choices + default, persistence, activation timing, safety impact) and the cache section notes the tier; the TROUBLESHOOTING disk-usage expectation now mentions the early tier. ## Evidence - **Independent validation:** ACCEPT-WITH-FINDINGS — 8/8 PASS (safety invariants, timer pattern, preference row, state/UI surfacing, installer coverage, docs, tests + gates, spec sweep). The two doc findings (wrong command example, stale TROUBLESHOOTING expectation) are fixed in this branch (`1c2a181`); the formatting finding is fixed at source (`0c0ec49`, prettier 3.5.3). - **Rebase:** branch was stacked on the pre-merge polish commit; rebased cleanly onto fresh `main` (`8714697`, v0.9.5) — git auto-skipped the already-merged base; the 5 round commits replayed without conflicts. - **Gates:** `make check` green on the rebased tree (twice, incl. after the formatting commit); `git diff --check` clean; changed Markdown passes `prettier@3.5.3 --check`. - **Tests:** new `tests/test-cache-evict.sh` (243 lines: threshold boundary, clean-only enforcement, in-use skip, policy-off no-op, tier arithmetic, timer enable/disable) plus cache-age, state, systemd, preferences and widget extensions. ## Non-blocking findings (recorded; from the validation dossier) - In-use protection is timestamp-based (metadata ATime + data atime/mtime) with a small read-metadata→unlink race (TOCTOU): within the spec's "existing helper heuristics" allowance; the worst case is a re-download of provably clean data, never loss of dirty state. - No dedicated test leg for "vfs/stats OK but vfs/queue unavailable" (both fail together in scenario D) and no dedicated 1 h-choice scenario — same code path as covered scenarios (shared `rc()` helper, same grammar). ## CI fix (run 40) The first CI run failed in the new eviction test: its unreadable-policy leg used a mode-0000 config file, which the CI container's root user can still read (locally the checks run as a normal user). The leg now makes the config path a directory, so the read fails with OSError for every user — the tested invariant (unreadable policy ⇒ nothing is evicted) is unchanged. `make check` green on the fixed tree.
Extend the cache-age helper family with a second, shorter age tier:
verified clean VFS copies of at least 1 GiB age out after 1, 2, 6 or 24
hours (default 2) instead of the full retention. The new
pdrive-cache-evict worker releases a copy only when the running service
names the live namespace, its rclone metadata proves Dirty explicitly
false with full present ranges, the data file matches the metadata
size, it is not queued or uploading, and no access clock shows recent
activity; anything doubtful stays on disk and the whole pass is a no-op
without RC evidence. pdrive-cache-age gains the large/default value
grammar, an evict-large manual action and timer alignment; the
retention file keeps its strict two-key grammar across both writers.
Add pdrive-cache-evict.timer/service following the draft-recovery unit
pattern: a hardened oneshot dispatched through the fixed pdrive-service
cache-evict-auto action, firing about every fifteen minutes. The
preference stays authoritative — saving 24 h disables the tier and stops
the timer, and the pass itself no-ops at 24 h even if the timer fires.
The installer enables the timer with the existing units, the uninstaller
disposes of it, and the unit-inventory and install-layout checks cover
the new files.
pdrive-state adds the additive configuration fields
large_clean_age_seconds and large_clean_age_valid (absent key means the
2-hour default; invalid values fall back with a false validity flag).
The Preferences dialog gains one Local cache row with 1/2/6/24 h
choices, EN+DE strings, Save sensitivity gating on effective change and
a helper-backed save through pdrive-cache-age large. The cache card's
Retention value carries the tier short form as hover text.
Add the Preferences settings-reference row (access path, choices and
default, helper persistence, activation timing and the clean-verified-
only safety contract), the early-eviction subsection under VFS-cache
retention, the cache card hover reference, the restore-repair timer
list, and a note that the tier deliberately stays off the mount option
list so the VFS cache fingerprint never changes.
The bare pdrive-cache-age large form is a usage error, not a display
path: status shows the large-copy value. State in the troubleshooting
cache-usage symptom that verified copies of at least 1 GiB follow the
shorter early tier (2 hours by default) so a vanished large copy has
the right explanation.
Format the operations reference to prettier style
Some checks failed
Checks / Functional checks (pull_request) Failing after 1m2s
0c0ec490aa
Make the unreadable-policy test leg independent of the running user
All checks were successful
Checks / Functional checks (pull_request) Successful in 1m24s
5d21fd24d5
ClaudiuSchuster deleted branch oss-oo/cache-policy-rt20261009 2026-10-09 06:21:51 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
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
OSS-Singularity/proton-drive-linux!15
No description provided.