# 0.41.1 — 2026-07-27 — "Onboarding Gate"

## Added

- **Onboarding tour shows once per project**. New boolean in `.kandown/kandown.json` — `ui.onboardingCompleted` (defaults to `false`). The modal persists `true` the first time the user closes it (X, Esc, "Get started", or any dismissal), so a fresh open no longer triggers the tour on every reload. The "Show onboarding tour" button in Settings → Appearance re-opens it with `stepIndex = 0` whenever the user wants to see it again.
- **Architecture review capture** — `docs/architecture-review/2026-07-27-task-transition/` ships the HTML report + module prototype + Vitest matrix that produced the task transition policy. Date-stamped folder pattern: every future run gets its own.
- **Vitest infrastructure** — `vitest.config.ts`, `pnpm test`/`pnpm test:watch`/`pnpm test:coverage` scripts. `src/lib/__tests__/` and `src/cli/lib/__tests__/` are the only recognized roots so React / DOM never leak in.
- **Decision record (ADR 0001)** — `docs/adr/0001-dependency-gate-source.md` pins "the task transition gate has one source" so a future explore-architecture-review won't re-suggest the duplicates.

## Fixed

- **Phantom update banner from a stale long-lived daemon** — when the user upgrades the global package, the running daemon process keeps its in-memory `KANDOWN_VERSION = "<old>"` and its /api/update/check returns `updateAvailable: true` against the npm registry even though the freshly served web bundle is on the latest. `src/components/UpdateNotificationBanner.tsx` now treats the compiled-in `KANDOWN_VERSION` as ground truth and splits the banner into two honest states: "truly available" (real upgrade) vs "daemon is stale" (new web bundle served by old daemon → `kandown daemon refresh-all` restarts it and the banner clears).
- **Dependency gate duplicates were drifting across every interface.** The canonical rule now lives in `src/lib/dependencies.ts` as `resolveTransition` / `assertTransitionAllowed`; the web store, TUI, CLI, MCP and cascade paths are all funneled through it, so a CLI `kandown move t1 Done` is now correctly refused while t2 is still open instead of silently succeeding. Archived dependencies count as resolved; unknown ids and self-references never block. `kandown` MCP `move_task` returns a structured JSON-RPC error (`code: -32602`) when the gate refuses.

## Test

- 34 vitest assertions (28 unit + 6 CLI integration) lock the new module down: `pnpm test`.
