Skip to content

Daemon as thin loop over --once #52

Closed

Description

@kridaydave

Make file-organizer-watch a thin wrapper that runs --once in a loop; document cron/systemd as the primary path. One simple mechanism instead of two.

Activity

  1. kridaydave commented on Oct 12, 2026

    @kridaydave
    OwnerAuthor

    Scope shrank with #109 (merge 77e64ad), which closed #95 by choosing option A: the daemon routes through the shared pass, so there is one pass and one history write path. What is left of this issue is the thin-wrapper half: file-organizer-watch is still its own cron-based daemon with catchup and scheduler-state.json, not a loop over --once, and cron/systemd is not documented as the primary path. Note that catchup reads scheduler-state.json and lives in the daemon, not the pass, so a thin loop needs somewhere for that state to go or it goes away.

  2. kridaydave commented on Oct 20, 2026

    @kridaydave
    OwnerAuthor

    Resolution

    The daemon keeps only the schedule. A tick now runs exactly what file-organizer-watch once <directory> --apply --source scheduled runs, and adds nothing a crontab line doesn't have: the 3-attempt retry wrapper is gone. A thrown pass is logged once and the schedule's next tick is the retry (082a118).

    What already existed and is now the whole story. Since #95 the daemon and a cron once line funnel into the same runOrganizePass with source: "scheduled", the same history row, the same rollback manifest, and the same per-directory tuning (the pass looks it up for the cron path; the daemon supplies it explicitly, which is what keeps legacy autoOrganize entries behaving). The two paths already produced byte-identical passes; the duplication was in the lifecycle wrapper around the tick, and the retry was the one piece of it that had no counterpart in the cron path.

    Deliberate choice: in-process shared pass, not spawning the once CLI child. "Runs --once in a loop" could be read as the daemon shelling out to the CLI per tick. Not taken: the pass module is already the one mechanism, so a child process would add bin-path resolution, stdout plumbing, and subprocess bookkeeping with zero semantic gain, and it would break the injectable-pass test seam. The tick body is now argument-for-argument the call the once CLI makes.

    Kept, on purpose. noOverlap plus the in-flight guard (real overlap protection across concurrent ticks and manual triggers), tuning supply for legacy entries, startup catchup with catchup_mode, and scheduler-state.json as daemon-only bookkeeping. The last two stay until the fog item on #92 (what scheduler-state is for once --once writes history) is decided; nothing here makes that decision.

    Proof. Real daemon in a sandbox home (HOME/XDG_CONFIG_HOME redirected, data inside the sandbox home): a */10 * * * * * watch organized the folder within 35 seconds, wrote 5 history rows all labelled scheduled (first carried filesProcessed: 3 and a rollback manifest id, the rest honest no-ops), and stamped scheduler-state.json with lastRunTime and the schedule. A second run with the path gate refusing the directory logged exactly one failure per tick at :20, :30, :40 with no re-attempts. Unit red-check: the new one-attempt test fails against the old retry code.

    Docs. cron/systemd as the primary path was already stated in README (shipped with #121); the daemon's module header and the watch CLI header now say it too, and describe the daemon as the convenience loop it is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions