Skip to content

fix(init): complete home preparation and keep it retryable - #509

Merged
ss-o merged 1 commit into
nextfrom
bug-448
Sep 3, 2026
Merged

fix(init): complete home preparation and keep it retryable#509
ss-o merged 1 commit into
nextfrom
bug-448

Conversation

@ss-o

@ss-o ss-o commented Sep 3, 2026

Copy link
Copy Markdown
Member

.zi-prepare-home recorded the home as ready before doing any work, and created the services directory only as a side effect of creating the snippets directory.

The defect

.zi-prepare-home() {
  [[ -n ${ZI[HOME_READY]} ]] && return
  ZI[HOME_READY]=1          # before anything is created
  ...
  if [[ ! -d ${ZI[SNIPPETS_DIR]} ]]; then
    ...
    command mkdir -p "${ZI[SERVICES_DIR]}"    # only reached when snippets/ is absent
  fi
}

A tree with snippets/ present and services/ missing, which a migration or a manual repair can leave behind, completes without creating the services directory and is still recorded as ready:

PROBE before: snippets=1 services=0
PROBE prepare rc=0
PROBE after:  services=0
PROBE HOME_READY=1

Service startup then places locks and FIFOs below a directory that does not exist, and ZI[HOME_READY]=1 stops any later call from repairing the layout.

The fix

Three changes, matching the acceptance criteria:

  • the services directory gets its own condition, independent of snippets
  • the required set is validated before readiness is recorded, naming the first missing directory
  • ZI[HOME_READY] is set only after that validation passes, so a failure stays retryable
PROBE partial-layout  rc=0  services=1
zi: home preparation incomplete, missing: .../zi/services
PROBE unwritable      HOME_READY=unset
PROBE retry           rc=0  services=1  HOME_READY=1

What is deliberately not required

$ZPFX/{bin,lib,share} and ZI[MAN_DIR] stay best-effort. They are user-facing install prefixes rather than Zi's own state, and the manual tree has always tolerated a creation failure through command mkdir 2>/dev/null -p. Promoting them to required would turn a read-only prefix into a startup failure for shells that work today, which is a bigger behaviour change than this issue asks for. The comment in the source says so.

Test

tests/home-preparation.zsh covers the partial layout, a required directory that cannot be created, the retry once the cause is removed, and the no-op on an already-ready home. It skips itself under root, where the permission case cannot hold, and restores permissions in its trap so cleanup works.

Against the previous function:

partial layout: the services directory was not created
not ok - home preparation is not complete, propagating or retryable    exit=1

Registered in zsh-n.yml, both path filters and a job. Full suite 25/25.

Closes #448

.zi-prepare-home set ZI[HOME_READY]=1 on its second line, before doing any
directory work, and created ZI[SERVICES_DIR] only inside the branch guarded on
ZI[SNIPPETS_DIR] being absent.

A tree with snippets/ present and services/ missing, which a migration or a
manual repair can leave behind, therefore completed without creating the
services directory and was still recorded as ready:

    PROBE before: snippets=1 services=0
    PROBE prepare rc=0
    PROBE after:  services=0
    PROBE HOME_READY=1

Service startup then places locks and FIFOs below a directory that does not
exist, and the flag prevents any later call from repairing the layout.

Give the services directory its own condition, validate the required set before
recording readiness, and set ZI[HOME_READY] only after that passes. A failure
now reports which directory is missing and leaves the flag unset, so a later
call retries.

$ZPFX and the manual directory stay best-effort. They are user-facing install
prefixes rather than Zi's own state, and the manual tree has always tolerated a
creation failure through `mkdir 2>/dev/null'. Treating them as required would
turn a read-only prefix into a startup failure for shells that work today.

tests/home-preparation.zsh covers the partial layout, a required directory that
cannot be created, the retry after the cause is removed, and the no-op on an
already-ready home. It skips itself under root, where the permission case cannot
hold. Against the previous function it reports `partial layout: the services
directory was not created'.

Closes #448
@ss-o
ss-o requested a review from a team as a code owner September 3, 2026 03:20
@ss-o
ss-o merged commit 3cfc8f6 into next Sep 3, 2026
91 checks passed
@ss-o
ss-o deleted the bug-448 branch September 3, 2026 03:27
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