WizardGating — pure, testable: Stage 1 always; 2 on .ti1; 3 on .ti1+.ti2; 4 on .ti3only (.ti2 alone never unlocks — #109/#110); 5 on .ti3 + .icc/.icm (#69). Forward gated, backward always; Stage 0 is a side-trip.
WizardViewModel — setTarget sanitises basename (/\.. rejected, no placeholder basenames — #60) and resolveSafeCwds the directory (#59); locked forward nav raises the warning banner; windowDidBecomeKey re-probes and falls back to deepestUnlocked when artefacts vanish (#151); restored stage is clamped on launch.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Implements issue #4 (M1) — navigation is disk, not buttons.
WizardState(Codable) +WizardStateStore—wizard_state.jsonviaAtomicFileWriter:currentStage(0–5),basename,cwd,printerName,sessionMode(profile/calibration),profileBasename.WizardGating— pure, testable: Stage 1 always; 2 on.ti1; 3 on.ti1+.ti2; 4 on.ti3only (.ti2alone never unlocks — #109/#110); 5 on.ti3+.icc/.icm(#69). Forward gated, backward always; Stage 0 is a side-trip.WizardViewModel—setTargetsanitises basename (/\..rejected, no placeholder basenames — #60) andresolveSafeCwds the directory (#59); locked forward nav raises the warning banner;windowDidBecomeKeyre-probes and falls back todeepestUnlockedwhen artefacts vanish (#151); restored stage is clamped on launch.RootView—NSWindow.didBecomeKeyNotification→windowDidBecomeKey().isEnablednow driven by artefact gating.Verified: 71/71 tests pass (gating matrix, forward/backward rules, persistence round-trip, corrupt-state fallback).
Closes #4