Expand description
Machine-global registry of currently-active DevFlow project roots.
Gates::list_open (gates.rs) is scoped to one project_root, and every
caller inherits that scope — there is nowhere in this codebase that
answers “what is DevFlow doing across every project on this machine?”
without shelling out to ps and find (see 23-ORPHAN-FORENSICS.md).
This module is that answer: a (project_root, phase) pair is registered
on the same code path that already writes state.monitor_pid, so a
running phase cannot be missing from the registry.
Storage shape (23-03 revision, cross-AI review BLOCKER 4): one file
per (project_root, phase) under a roots/ subdirectory of the cache
dir, enumerated with read_dir. Registration writes only its own file —
there is no load-modify-write step and therefore no lost-update race to
defend. A corrupt or truncated entry costs one entry, never the whole
registry.
Structs§
- Registered
Root - A registered
(project_root, phase)pair — one DevFlow phase this machine is (or recently was) running.
Enums§
- Registry
Error - Errors produced by registry operations.
Functions§
- cache_
dir - Resolve the DevFlow cache directory. The ONLY env-reading function in
this module. Resolution order:
DEVFLOW_CACHE_DIR(test/override hook), thenXDG_CACHE_HOME/devflow, thenHOME/.cache/devflow. ReturnsNonewhen none of the three is set. - deregister
deregister_inagainst the resolved machine-global cache dir. Deregistration is best-effort observability cleanup, so any error (includingcache_dirresolving toNone) is swallowed — mirrors how every call site invokes this withlet _ =.- deregister_
in - Remove the entry file for
(project_root, phase), if present. With the per-file storage shape this is a singleremove_fileonentry_path_in— no load, no rewrite, and therefore no way to disturb a sibling entry belonging to another phase or another root. A missing file (never registered, or already deregistered) is treated as success rather than an error. - entry_
path_ in - The deterministic per-registration entry file path for
(project_root, phase). The digest is only a filename disambiguator — the authoritativeproject_rootlives inside the file itself, andload_roots_inreads it from there, so a digest collision costs at most one shadowed entry and never a wrong path. - load_
roots - Every registered root in the resolved machine-global cache dir. An empty
Vecwhencache_dirresolves toNone. - load_
roots_ in - Every registered root, sorted by
(project_root, phase)so output is deterministic (read_dirorder is not).read_dirs the roots directory, parsing each.jsonentry and skipping any that is unreadable or unparsable — exactly asGates::list_openalready skips unparsable gate files. Returns an emptyVecwhen the directory is absent. Never returnsResult; enumeration must degrade, not die. - prune_
missing prune_missing_inagainst the resolved machine-global cache dir.0whencache_dirresolves toNone.- prune_
missing_ in - Remove the entry file for every registered root whose
project_rootno longer exists on disk, plus every entry file that cannot be parsed at all (so unreadable files cannot accumulate forever), returning the number of files removed. Removal is per-fileremove_file; there is no rewrite of surviving entries, so pruning cannot disturb a registration written concurrently with it. Deliberately NOT called fromload_roots_in— that must stay side-effect-free so a read-only command cannot mutate machine state; callers invoke this explicitly. - register
- Register
(project_root, phase)into the resolved machine-global cache dir. A silentOk(())no-op whencache_dirresolves toNone— registration is best-effort observability, never a reason to fail a launch. - register_
in - Register
(project_root, phase)into the machine-global registry undercache_dir. Pure with respect to env. Creates the cache directory and the roots directory if absent (both private, mode0o700— T-23-33) and writes only this registration’s own file, atomically — there is no load step, no merge step, and no rewrite of any other entry. Re-registering the same pair simply overwrites its own file with a freshregistered_at. - roots_
dir_ in - The
roots/subdirectory of a cache dir, where per-registration entry files live.