What problem would this solve?
A [email protected] job can run every week forever, exit 0 every time, and never deduplicate anything — because the run that seeded its hashfile was missing -d.
The self-describing hashfile stores -d as opt_run_dedupe (src/dbfile.c:1161, replayed at :1249), so a bare oans --hashfile=FILE correctly replays whatever the seeding run did. That's working as designed. But it also means the seeding run's -d is load-bearing for every future scheduled run, and the setup flow makes it easy to get wrong: docs/nas-quickstart.md and systemd/README.md walk the user through a first run to establish the hashfile, then systemctl enable --now [email protected]. If that first run was a deliberate read-only preview — which the man page actively encourages, "Without -d, oans reads, hashes, and prints the duplicate extents it found — useful for previewing what a dedupe run would do" — then the timer inherits run_dedupe = 0.
The resulting job is indistinguishable from a healthy one: it walks the tree, updates hashes, records a run in run_history, exits 0, and reclaims nothing. --history shows a growing list of runs with 0 B reclaimed, which also looks exactly like a healthy job on an already-deduped tree.
This is not a bug in the replay mechanism — it's a missing guard rail on a footgun the docs lead users toward.
Proposed solution
Warn when a replayed configuration is a no-op, at the point where it's replayed.
In apply_scan_config() (src/oans.c), when the run is a replay (no file arguments given) and the loaded sc->run_dedupe is 0:
WARNING: the stored configuration for /var/cache/oans/media.hash has no -d,
so this run will hash but not deduplicate.
Re-run once with -d and the paths to update it:
oans -rd --hashfile=/var/cache/oans/media.hash /srv/media
The message should print the concrete fix-up command, including the stored roots, since the whole point of a replay is that the user no longer remembers the arguments.
Complementary, cheaper documentation fixes worth doing regardless:
docs/nas-quickstart.md and systemd/README.md: state explicitly that the seeding run must include -d, and that a preview run without it will be the thing that gets replayed.
systemd/[email protected]: the comment above ExecStart explains that the hashfile is self-describing but doesn't warn that -d-ness comes from the seeding run. One added line.
Considered and rejected: having the systemd unit pass -d explicitly. It would fix this case but break the replay contract in a worse way — the unit would then silently override a user who deliberately configured a hash-only job, and -d on the command line would diverge from what the hashfile says it does. The warning keeps one source of truth.
Related: if #145 lands, a replayed no-op run is also a natural thing to reflect in --json (e.g. surfacing run_dedupe in the metrics), so a monitoring dashboard can show that a job is configured read-only rather than merely finding nothing.
Alternatives considered
- Documentation only. Helps the next user, does nothing for the person whose timer has been idling since they set it up. The warning is what reaches them.
- Refuse to run a replay without
-d. Too strong: a hash-only scheduled job is a legitimate configuration (keeping a hashfile warm so a later -d run is fast), and failing it would break working setups.
- Warn only when
run_history shows N runs with 0 reclaimed. More targeted in principle, but "0 reclaimed" is also what a correctly-working job on a clean tree looks like, so it would cry wolf. The run_dedupe flag is the unambiguous signal.
What problem would this solve?
A
[email protected]job can run every week forever, exit 0 every time, and never deduplicate anything — because the run that seeded its hashfile was missing-d.The self-describing hashfile stores
-dasopt_run_dedupe(src/dbfile.c:1161, replayed at:1249), so a bareoans --hashfile=FILEcorrectly replays whatever the seeding run did. That's working as designed. But it also means the seeding run's-dis load-bearing for every future scheduled run, and the setup flow makes it easy to get wrong:docs/nas-quickstart.mdandsystemd/README.mdwalk the user through a first run to establish the hashfile, thensystemctl enable --now [email protected]. If that first run was a deliberate read-only preview — which the man page actively encourages, "Without -d,oansreads, hashes, and prints the duplicate extents it found — useful for previewing what a dedupe run would do" — then the timer inheritsrun_dedupe = 0.The resulting job is indistinguishable from a healthy one: it walks the tree, updates hashes, records a run in
run_history, exits 0, and reclaims nothing.--historyshows a growing list of runs with0 Breclaimed, which also looks exactly like a healthy job on an already-deduped tree.This is not a bug in the replay mechanism — it's a missing guard rail on a footgun the docs lead users toward.
Proposed solution
Warn when a replayed configuration is a no-op, at the point where it's replayed.
In
apply_scan_config()(src/oans.c), when the run is a replay (no file arguments given) and the loadedsc->run_dedupeis 0:The message should print the concrete fix-up command, including the stored roots, since the whole point of a replay is that the user no longer remembers the arguments.
Complementary, cheaper documentation fixes worth doing regardless:
docs/nas-quickstart.mdandsystemd/README.md: state explicitly that the seeding run must include-d, and that a preview run without it will be the thing that gets replayed.systemd/[email protected]: the comment aboveExecStartexplains that the hashfile is self-describing but doesn't warn that-d-ness comes from the seeding run. One added line.Considered and rejected: having the systemd unit pass
-dexplicitly. It would fix this case but break the replay contract in a worse way — the unit would then silently override a user who deliberately configured a hash-only job, and-don the command line would diverge from what the hashfile says it does. The warning keeps one source of truth.Related: if #145 lands, a replayed no-op run is also a natural thing to reflect in
--json(e.g. surfacingrun_dedupein the metrics), so a monitoring dashboard can show that a job is configured read-only rather than merely finding nothing.Alternatives considered
-d. Too strong: a hash-only scheduled job is a legitimate configuration (keeping a hashfile warm so a later-drun is fast), and failing it would break working setups.run_historyshows N runs with 0 reclaimed. More targeted in principle, but "0 reclaimed" is also what a correctly-working job on a clean tree looks like, so it would cry wolf. Therun_dedupeflag is the unambiguous signal.