You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The YAML config editor (issue #95, merged via PR #96) saves with a plain write_text and no staleness check. Two failure modes for the user's only .profiles file:
Torn write — ProFiles crashing or losing power mid-save truncates the config file; the next launch falls back to defaults with no recovery copy.
Silent clobber — the editor's own header button "Open in OS" invites editing the file in an external editor. Any change made there between the editor's load and Save is overwritten without warning: the modal reports SAVED and the external edits are gone.
Evidence
src/profiles/server/routes/config.py:419 — config_path.write_text(payload.content, encoding="utf-8"): no temp-file + os.replace, and SaveRequest carries no baseline (hash/mtime) to detect that the file changed since it was loaded.
GET /api/config/content (src/profiles/server/routes/config.py:364-398) returns {filename, content, config_path, session_trial} — no version marker of any kind, so the client cannot implement the guard without a server change.
The external-edit path is a designed flow of the editor (header "Open in OS" is the sole openConfigFile() consumer per the feat(web): YAML config editor in the UI #96 design); Revert re-fetches, but Save never re-checks the disk state.
Proposed approach
Core: add an atomic write helper in profiles.core.config.io.yaml_io (write to a temp file in the same directory, then os.replace); route both /api/config/save and /api/config/save-as through it.
Staleness guard: extend GET /content to also return the file's content hash; SaveRequest gains an optional baseline hash; /save returns 409 when the on-disk file no longer matches the baseline the editor loaded. Optional field → older callers unaffected.
Web: on 409, offer "Reload disk version / Overwrite anyway" via the existing ConfirmDialog; pass the baseline on every save from ConfigEditorModal.
Scope M. No breaking change (baseline is optional; 409 only fires for clients that send it).
Alternatives considered
Live file watcher (client or server) — heavier machinery and still races at the save instant; a save-time check catches the actual data-loss moment. A watcher can be a follow-up if users hit concurrent editing often.
Backup-on-save (.profiles.bak) — mitigates loss after the fact but does not prevent the silent clobber, and adds directory clutter; the 409 guard prevents the loss instead.
Proposed during automated enhancement scan 2026-11-04
Activity