0193b31aad
Reported by svos-dev after parallelising four vault reads in SVOS's systemd wrapper. Reproduced here and it is worse than reported: four concurrent secret get calls for distinct items returned empty strings with exit code 0, zero of four succeeding against their one of four. No error, no timeout, no diagnostic. The shape is the problem, not the race. A caller treating an empty optional secret as 'not configured' degrades silently and never learns otherwise - it cost SVOS the ability to page the operator while the process logged a clean startup line. Root cause is session establishment, not item reads. Every invocation runs bw unlock, and concurrent unlocks against the shared appdata dir invalidate each other. The damage then surfaces downstream as an empty listing or an empty item body, which is why a per-call lock is useless: by the time the read runs the session it holds is already dead. So the lock wraps the whole command instead. Three changes. The command-level lock makes concurrent callers queue. cmd_get now refuses an empty value rather than printing it, since a stored secret is never legitimately zero-length. And find() no longer coerces empty stdout to '[]' - that turned a broken read into a confident 'no such secret', the same silent-wrong-answer shape one layer up. Verified: four parallel reads of four real items now return all four correctly, serialised at the honest ~17s each. A name that genuinely does not exist still fails loudly, so the guard did not simply mute the negative case. Also replaces the copy at ~/.local/bin/secret with a symlink to this file. It was a plain copy in sync by luck, and every edit here silently left the live tool behind.