fix(xtask): dev refresh aborts when devstack markers vanish mid-session
What
cargo xtask dev refresh aborts with Error: no devstack markers found — run cargo xtask dev start first when the SHA-256 staleness markers under .devstack/ are absent — which happens routinely mid-session when multiple cargo xtask / devstack processes run concurrently across projects on the same box (the markers get cleared out from under a running session).
Why it matters
refresh is the fast path (staleness-guided minimal rebuild, preserves DB data, no reseed). When it errors, the only recourse is cargo xtask dev start / dev reload, which rebuilds all service images and (for start) reseeds + rewrites .ports.env with new ports — a heavy, iteration-slowing fallback even when only one service's source changed. This bit the #880 (closed)/#886 (closed)/#888 (closed)/#889 (closed) prevention-gate work repeatedly: every "rebuild one service to pick up a code change" turned into a full reload.
Proposed direction
Make refresh robust to missing markers instead of aborting: treat "no markers" as "staleness unknown → conservatively rebuild what changed" (e.g. fall back to a content hash of each service's build inputs, or to a full staleness scan) rather than erroring out. At minimum, refresh should degrade to a correct rebuild decision without requiring a prior dev start. Optionally, harden marker persistence so concurrent sessions don't clobber each other's markers (per-session marker namespace, or store markers outside the churn-prone location).
Acceptance criteria
-
cargo xtask dev refreshnever errors solely because.devstack/markers are absent; it performs a correct (possibly conservative) rebuild/restart decision. - Concurrent
cargo xtask devinvocations across projects do not cause a running session's refresh to spuriously fail. - A single changed service is rebuilt+restarted by
refreshwithout a fulldev start/reseed/port-churn. - Behaviour documented in
docs/modules/ROOT/pages/local-dev.adoc.
Context
Discovered during the Wave-4 prevention-gate sweep (#880 (closed)/#886 (closed)/#888 (closed)/#889 (closed)). Workaround used throughout: cargo xtask dev reload (rebuild+restart all, preserve data) or dev start.