Skip to content

fix(vault): tolerate ErrVaultExists in concurrent first-run flow#526

Merged
ALRubinger merged 1 commit intomainfrom
worktree-vault-init-race
May 7, 2026
Merged

fix(vault): tolerate ErrVaultExists in concurrent first-run flow#526
ALRubinger merged 1 commit intomainfrom
worktree-vault-init-race

Conversation

@ALRubinger
Copy link
Copy Markdown
Owner

Summary

Surfaced by readiness review for #454 Test 6 (concurrent first-run singleton). Ten parallel CLI processes sharing `AILERON_VAULT_PASSPHRASE` all enter `promptCreateAndUnlock`, but only one wins the `vault.Init` race. Pre-fix the losers aborted with "creating vault: vault: already exists" — confusing UX that doesn't match the test's expected contract (one daemon spawned, calls succeed).

Fix

Treat `vault.ErrVaultExists` as success-ish in `promptCreateAndUnlock`: fall through to spawn + unlock with the passphrase the caller already has. The post-spawn `/v1/vault/unlock` validates the passphrase end-to-end — if the racing CLIs disagree, losers naturally surface a 401 ("wrong passphrase — try again"), which is the correct shape for "you and another process picked different passphrases."

Test plan

  • Regression test `TestEnsureVaultUnlocked_StoppedMissing_TolerateErrVaultExists` added; verified it fails before this fix ("creating vault: vault: already exists") and passes after.
  • `go test ./cmd/aileron/...` green.
  • Other state-machine tests untouched; single-CLI behavior unchanged.

🤖 Generated with Claude Code

Surfaced by #454 Test 6 readiness review: ten parallel CLI processes
sharing AILERON_VAULT_PASSPHRASE all enter promptCreateAndUnlock, and
only one wins the vault.Init race. The losers were aborting with
"creating vault: vault: already exists" — confusing UX that doesn't
match the contract the test expects (one daemon spawned, calls succeed).

Treat vault.ErrVaultExists as success-ish in promptCreateAndUnlock:
fall through to the spawn + unlock steps with the passphrase the
caller already has. The post-spawn /v1/vault/unlock validates the
passphrase end-to-end — if the racing CLIs disagree, the losers
naturally surface a 401, which is the right shape for "you and
another process picked different passphrases."

Concurrent racers with the same passphrase (the Test 6 case) now all
succeed, which is the desired behavior. Single-CLI invocations are
unchanged.

Adds TestEnsureVaultUnlocked_StoppedMissing_TolerateErrVaultExists
as the regression guard. Verified the test fails before this fix
("creating vault: vault: already exists") and passes after.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@railway-app
Copy link
Copy Markdown

railway-app Bot commented May 7, 2026

🚅 Deployed to the aileron-pr-526 environment in aileron

1 service not affected by this PR
  • docs

@codecov
Copy link
Copy Markdown

codecov Bot commented May 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.97%. Comparing base (16e1f5f) to head (4510843).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #526      +/-   ##
==========================================
- Coverage   81.98%   81.97%   -0.01%     
==========================================
  Files         235      235              
  Lines       23989    23989              
==========================================
- Hits        19667    19665       -2     
- Misses       3147     3148       +1     
- Partials     1175     1176       +1     
Flag Coverage Δ
integration 8.64% <ø> (ø)
unit 78.64% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ALRubinger ALRubinger merged commit d253ed9 into main May 7, 2026
10 checks passed
@ALRubinger ALRubinger deleted the worktree-vault-init-race branch May 7, 2026 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant