A flat-YAML task tracker that is just files. No daemon, no database, no git hooks. diarie.dev

feat!: the store is a diarium — `diarium/` or `.diarium/`, posture on disk #12

Open voxpelli.com
targeting main from voxpelli/diarium-pair
Open opened by and assigned to voxpelli.com
targeting main from voxpelli/diarium-pair

Files decisions diarie-pos, diarie-loc and diarie-ids, and implements the first.

The store is named diarium, in exactly one of two forms: visible diarium/ or dotted .diarium/. Which one exists on disk IS the choice — no config key, no environment variable, nothing to resolve before the store can be found, and git mv flips it whenever, because the reader accepts both. Repos legitimately differ in posture the way myndigheter do; the statute fixes the register, the myndighet chooses whether it is a webbdiarium.

TRACKER_DIR is removed rather than renamed. A singular constant cannot answer "which of two forms is on disk", and leaving it as 'diarium' would have kept join(root, TRACKER_DIR, 'tasks') working on visible stores while silently missing dotted ones — this package's founding defect in a new coat. Resolution is now trackerDirIn(root), and the compiler found every call site.

Three failure modes the pair creates, each pinned by a test:

  • both forms present -> ETWOSTORES naming both paths. A precedence rule is how the losing store becomes a file nobody reads and everybody keeps editing.
  • a legacy .diarie/ -> named, with the git mv, and it HALTS the upward walk. Stepping over it to an ancestor diarium/ would read a real store belonging to someone else: exit 0, no warning, entirely the wrong backlog.
  • init beside a legacy store -> ELEGACY. The read side answers a legacy store with ENOSTORE, and a helpful caller answers ENOSTORE by running init; without this the project ends up with two backlogs and nothing pointing at the full one.

listTaskFiles now throws on an unproven root instead of returning an empty list — it stopped being total when the store dir stopped being a constant, and it is a public export.

migrate's overwrite guard checks every store name, not just the one the run would write, and gains --dotted to match init.

This repo adopts the dotted posture while the shipped default stays visible; that divergence is deliberate and recorded in diarie-pos's Revisions.

BREAKING CHANGE: TRACKER_DIR is removed from diarie/schema — use TRACKER_DIRS, TRACKER_LABEL, and trackerDirIn(root). The store is diarium/ or .diarium/; run git mv .diarie diarium (or .diarium) to migrate an existing store. TASKS_ROOT is now DIARIUM_ROOT, and a stale TASKS_ROOT is a hard EUSAGE rather than a silent ignore. New exit-1 codes: ETWOSTORES and ELEGACY.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

Commits 0