Skip to content

fix(cache): store database in per-schema-version directory#433

Merged
wan9chi merged 9 commits into
mainfrom
fix-cache-per-version-dir
Jun 9, 2026
Merged

fix(cache): store database in per-schema-version directory#433
wan9chi merged 9 commits into
mainfrom
fix-cache-per-version-dir

Conversation

@fengmk2

@fengmk2 fengmk2 commented Jun 9, 2026

Copy link
Copy Markdown
Member

The task cache was one shared cache.db keyed only by an in-DB user_version. An older vp build opening a database written by a newer build aborted with Unrecognized database version, so switching between branches that pin different Vite+ versions broke the cache.

Store the cache in a per-schema-version subdirectory (e.g. node_modules/.vite/task-cache/v13/) so incompatible builds use separate databases and stay warm across branch switches. An unrecognized database is now rebuilt instead of aborting, and a one-time sweep removes the legacy top-level cache files.

Closes voidzero-dev/vite-plus#1785


Note

Medium Risk
Changes where and how the SQLite task cache is created and cleaned, which affects all cached runs; behavior is simpler but users may retain orphaned legacy top-level cache files until they run cache clean.

Overview
Fixes branch switches between Vite+ versions that previously aborted with Unrecognized database version when an older build opened a newer cache.db.

The task cache now lives under a schema-version subdirectory (e.g. node_modules/.vite/task-cache/v13/). Session init writes only there; cache clean removes the whole task-cache tree (all versions plus any legacy top-level files). Opening the DB drops in-DB user_version migration and version-mismatch errors in favor of CREATE TABLE IF NOT EXISTS in that versioned folder, so each pinned version keeps an isolated warm cache and stale top-level cache.db files are never opened.

Test support: vtt list-dir --recursive finds archives under nested version dirs; new unit and e2e coverage covers version isolation and ignored legacy cache paths.

Reviewed by Cursor Bugbot for commit 1a1937f. Configure here.

fengmk2 added 4 commits June 9, 2026 14:16
The task cache was one shared cache.db keyed only by an in-DB user_version. An older vp build opening a database written by a newer build aborted with "Unrecognized database version", so switching between branches that pin different Vite+ versions broke the cache.

Store the cache in a per-schema-version subdirectory (e.g. task-cache/v13/) so incompatible builds use separate databases and stay warm across branch switches. An unrecognized database is now rebuilt instead of aborting, and a one-time sweep removes the legacy top-level cache files.

Closes voidzero-dev/vite-plus#1785
Use an exhaustive match for the database schema-version check instead of a loop with stacked ifs, and inline the version-set statement into the create arm.

Run the one-time legacy-layout cleanup lazily on first cache open rather than on every session startup, so commands that never touch the cache don't pay for it.

No behavior change.
Plants a pre-versioned top-level cache.db and an orphaned .tar.zst, then asserts the first run sweeps them and recreates the cache under the per-version subdirectory, with the second run hitting the migrated cache.
Assert on extension-filtered listings (the cache db left the top level and reappears nested) instead of snapshotting the literal v13 directory, so the test survives a CACHE_SCHEMA_VERSION bump.
@fengmk2

fengmk2 commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

@cursor review

@fengmk2

fengmk2 commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

@codex review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 30f24a6. Configure here.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@fengmk2 fengmk2 marked this pull request as ready for review June 9, 2026 08:23
@fengmk2 fengmk2 requested a review from wan9chi June 9, 2026 08:23
@fengmk2 fengmk2 self-assigned this Jun 9, 2026
fengmk2 added 2 commits June 9, 2026 16:57
The per-version cache directory already isolates incompatible schemas, so the in-database user_version is redundant: remove the PRAGMA query, the match/reset loop, and the legacy-layout sweep. load_from_path now just ensures the tables exist (CREATE TABLE IF NOT EXISTS).

A cache left by another version is harmlessly ignored (it lives in a directory this build never opens) and reclaimable via vp cache clean, which still wipes the whole task-cache base. Replace the migration e2e fixture with one asserting the leftover is ignored.
Fold the WAL pragma and the two CREATE TABLE IF NOT EXISTS statements into one execute_batch, so opening the cache is one SQLite call instead of three. On an existing database the IF NOT EXISTS creates are near-free no-ops; load_from_path runs once per process (OnceCell).
@fengmk2

fengmk2 commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 1a1937f. Configure here.

wan9chi and others added 2 commits June 9, 2026 23:52
The name collided with execute/mod.rs's `cache_base_path`, which means the
workspace root that cached relative paths anchor to. This field is the parent
of all `vN` version dirs, so `cache_root` is clearer and pairs with the
versioned sibling `cache_path` (cache_root.join("v13")).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
It is only referenced within the module (by cache_schema_dir_name), so the
`pub` was unnecessary.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

wan9chi commented Jun 9, 2026

Copy link
Copy Markdown
Member

wan9chi commented Jun 9, 2026

Copy link
Copy Markdown
Member

Merge activity

  • Jun 9, 4:00 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jun 9, 4:00 PM UTC: @wan9chi merged this pull request with Graphite.

@wan9chi wan9chi merged commit 7ed8c9d into main Jun 9, 2026
18 checks passed
@wan9chi wan9chi deleted the fix-cache-per-version-dir branch June 9, 2026 16:00
wan9chi added a commit that referenced this pull request Jun 9, 2026
## Why

`crates/vite_task` had two unrelated fields both named `cache_base_path`, which was a trap for anyone reading across the cache code:

- In [`session/mod.rs`](crates/vite_task/src/session/mod.rs), it meant the **cache directory** — the parent of all `vN` schema-version subdirs.
- In [`execute/mod.rs`](crates/vite_task/src/session/execute/mod.rs), it meant the **workspace root** — the directory that relative paths stored in cache entries (inputs, outputs, archives) are resolved against. It is literally set to `self.workspace_path`.

Same name, opposite halves of the cache machinery (where the cache lives vs. what cached paths point at).

## What

This PR renames the `execute` one to `workspace_root`, naming it for the value it actually holds and disambiguating it from the cache directory. The doc comment is updated to spell out the role. All 10 references (the `ExecutionContext` field and the `execute_spawn` parameter it feeds) are renamed.

The `session` field was renamed to `cache_root` in the parent PR (#433), so after both PRs the two concepts read clearly:

| Field | Where | Meaning |
| --- | --- | --- |
| `cache_root` | session | parent of all `vN` cache dirs |
| `cache_path` | session | this build's versioned dir (`…/v13`) |
| `workspace_root` | execute | dir that cached relative paths anchor to |
| `cache_dir` | execute | where cache files (db, archives) are stored |

Pure rename + doc tidy; no behavior change. `cargo check -p vite_task` passes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
fengmk2 added a commit to voidzero-dev/vite-plus that referenced this pull request Jul 2, 2026
Release vite-plus v0.2.2: the Vite+ Beta release.

**Vite+ is now in Beta**: stable and ready for production adoption,
fully open source under MIT. Read the announcement to see what Vite+ is
about and where it is headed: [Announcing Vite+
Beta](https://voidzero.dev/posts/announcing-vite-plus-beta).

On top of the Beta milestone, this release brings cross-version upgrades
via `vp migrate`, an official Docker toolchain image on GHCR,
zero-config runner-aware `vp build` caching, and PGP-verified managed
Node.js downloads.

### Highlights

- **`vp migrate` upgrades existing Vite+ projects across versions**:
previous release notes told users not to run `vp migrate` for upgrades.
It now runs from the global CLI when the local one is older, re-pins
`vite-plus` and the `vite` -> `@voidzero-dev/vite-plus-core` alias
across dependencies, overrides/resolutions, and catalogs in every
workspace package, aligns `vitest` / `@vitest/*` by actual usage, and
defaults to a version-only upgrade (pass `--full` to also run the
first-time setup bucket: hooks, editor, agent files, lint migration)
([#1891](#1891)), by
@fengmk2
- **Official Vite+ Docker toolchain image**:
`ghcr.io/voidzero-dev/vite-plus` bundles `vp` plus a native build
toolchain on `debian:bookworm-slim` (amd64/arm64, non-root). Since `vp`
provisions the exact Node.js from `.node-version`, one image builds any
project, and a documented multi-stage build copies the resolved Node.js
into a small vp-free runtime stage
([#1944](#1944)), by
@fengmk2
- **Zero-config `vp build` caching via runner-aware Vite**: Vite reports
its inputs, outputs, and tracked env reads to the `vp` runner over the
new `@voidzero-dev/vite-task-client` IPC
([vite#22453](vitejs/vite#22453)), so `vp build`
caches correctly with no hand-written cache config: outputs are tracked
and restored automatically, and a changed `VITE_*` env var invalidates
the cache and is named in the cache-miss message
([#1774](#1774)), by
@wan9chi
- **PGP-verified Node.js downloads**: installing a managed Node.js now
verifies the release's clearsigned `SHASUMS256.txt.asc` against the
vendored Node.js release keyring (pure Rust, no `gpg` required) before
trusting any checksum, so a tampered archive is rejected before install;
unsigned sources (musl builds, custom mirrors) fall back to
checksum-only verification
([#1848](#1848)), by
@fengmk2

### Features

- `vp check`: a `check` block in `vite.config.ts` (`check.fmt` /
`check.lint`) can make plain `vp check` skip formatting or linting by
default, mirroring `--no-fmt` / `--no-lint`; standalone `vp fmt` / `vp
lint` and git hooks are unaffected, and a `note:` line keeps the
config-based skip discoverable
([#1981](#1981)), by
@fengmk2
- `vp env list-remote`: highlight installed versions (color, or a `*`
prefix when piped) and label the project-resolved `current` and global
`default` versions; `--json` gains `installed` / `current` / `default`
fields ([#1907](#1907)),
by @semimikoh
- `vpr` ships as a `vite-plus` package bin, so the `vp run` shorthand
works on clean installs without global PATH shims (Vercel build image,
generic CI runners)
([#1988](#1988)), by
@kvnwolf
- Vite Task: `dependsOn` can select tasks from dependency packages, e.g.
`dependsOn: [{ "task": "build", "from": "dependencies" }]`
([vite-task#479](voidzero-dev/vite-task#479)),
by @wan9chi
- Vite Task: a task's `env` / `untrackedEnv` glob patterns support `!`
negation (e.g. `["VITE_*", "!VITE_SECRET"]`)
([vite-task#425](voidzero-dev/vite-task#425)),
and an env-caused cache miss now names the variable inline, e.g. `cache
miss: env 'NODE_ENV' changed`
([vite-task#438](voidzero-dev/vite-task#438)),
by @wan9chi
- Upgrade upstream dependencies: vite `8.0.16 -> 8.1.2`, rolldown `1.1.1
-> 1.1.4`, oxlint `1.70.0 -> 1.72.0`, oxfmt `0.55.0 -> 0.57.0`,
oxlint-tsgolint `0.23.0 -> 0.24.0`, and the oxc toolchain `0.136.0 ->
0.138.0` ([#1924](#1924),
[#1989](#1989),
[#2000](#2000),
[#2009](#2009)), by
@voidzero-guard[bot]

### Fixes & Enhancements

- Windows: `vp run` no longer hangs CI when a `node_modules/.bin` `.cmd`
shim is routed through PowerShell; the npm/pnpm/yarn `.ps1` wrappers
read stdin and block forever on a non-TTY pipe, so the PowerShell
rewrite is now skipped when stdin is not an interactive terminal
([vite-task#491](voidzero-dev/vite-task#491),
via [#1973](#1973)), by
@fengmk2
- Vite Task: the task cache is stored in a per-schema-version directory
(e.g. `node_modules/.vite/task-cache/v13/`), so switching between
branches that pin different Vite+ versions no longer fails with
`Unrecognized database version`
([vite-task#433](voidzero-dev/vite-task#433)),
by @fengmk2
- Vite Task: env values in cache fingerprints are stored only as SHA-256
digests and env cache-miss details report names without values
([vite-task#455](voidzero-dev/vite-task#455));
prefix env assignments like `PATH=... command` now affect executable
lookup during planning
([vite-task#440](voidzero-dev/vite-task#440));
`package.json` / `pnpm-workspace.yaml` files with a UTF-8 BOM parse
correctly
([vite-task#424](voidzero-dev/vite-task#424)),
by @wan9chi
- `vp upgrade`: run the pinned pnpm with a managed Node.js LTS directly
instead of re-entering `vp install`, so an incompatible
session/project/system runtime can no longer make pnpm skip optional
native binaries and leave the upgraded CLI broken
([#1900](#1900)), by
@liangmiQwQ
- Global package installs: each install writes to an immutable
`packages/<name>#<uuid>` prefix that is activated via metadata after npm
succeeds, so an interrupted reinstall can no longer leave the active
package unavailable
([#1906](#1906)), and
stale interrupted-install directories are swept with file-lock
protection for concurrent installs
([#1945](#1945)), by
@liangmiQwQ
- `lazyPlugins()`: skip plugin factories only while config metadata is
being resolved instead of keying off `VP_COMMAND`, so builds spawned
under `vp run` / `vp exec` keep the user's plugins and `vp format` no
longer loads them
([#1939](#1939)), by
@fengmk2
- `vp migrate` (pnpm): add a direct `vite` devDep aliased to the core
override wherever `vite-plus` is depended on, so vitest's `vite` peer
binds to `@voidzero-dev/vite-plus-core` instead of pulling in a second
upstream vite that broke the `vp test` cache
([#1933](#1933)), by
@fengmk2
- `vp pack`: bundle `@tsdown/exe` and `@tsdown/css` into core so `--exe`
and CSS bundling work without a resolvable top-level `tsdown`; the
native `lightningcss` becomes an optional peer loaded lazily with an
actionable error
([#1919](#1919)), by
@fengmk2
- `vp env`: invalidate stale shim resolve cache entries when the
project's Node.js version source changes
([#1951](#1951)), by
@jong-kyung
- Node shim: when the project declares npm via `packageManager` /
`devEngines.packageManager`, child processes spawned from `node` resolve
the managed npm instead of the Node-bundled one
([#1938](#1938)); `vp env
which` reports bins linked by an intercepted `npm install -g` (e.g.
`tsc`) instead of "not found"
([#1968](#1968)); bins
with uppercase names (e.g. `vitePlus`) dispatch correctly
([#1963](#1963)), by
@liangmiQwQ
- `vp-setup`: pass the configured npm registry to the inner pnpm install
so setup works behind custom registries
([#1795](#1795)), by
@daflyinbed
- Native binding: declare the platform packages' true ABI floor
`engines.node >=20.0.0` so engine-strict package managers (pnpm) no
longer skip the optional native dependency and fail with `Cannot find
native binding` when a consumer's Node floor lands in a product-policy
gap ([#1993](#1993)), by
@fengmk2
- `vp create`: run `git init` without creating an initial commit, so
commitlint-configured templates no longer reject the hardcoded message
and template placeholders are not baked into history
([#2008](#2008)), by
@forehalo
- `vp staged --debug`: inline the bundled lint-staged version so debug
logging no longer crashes reading a `package.json` that does not exist
in the bundle
([#1925](#1925)), by
@rokuosan
- Installer: retry downloads truncated mid-body in
`HttpClient::get_bytes` (the platform-tarball path for `vp upgrade` and
the standalone installer)
([#1940](#1940)), and
clean up the temp dir when a package-manager install fails instead of
leaking `.tmpXXXX` directories
([#1949](#1949)), by
@shulaoda
- Windows/msys: normalize backslashes in the `env.fish` fallback path
([#1954](#1954)), by
@Aalivexy
- `install.ps1`: detect the missing VC++ runtime (`0xC0000135`) and
print VC++ Redistributable guidance instead of a generic failure;
interactive `irm | iex` installs keep the shell open
([#1962](#1962)), by
@cheezone
- `vp migrate`: preserve comments, key order, and trailing commas in
existing `.vscode` / `.zed` JSONC configs by patching the original text
instead of re-serializing it
([#1956](#1956)), by
@fengmk2
- Migration: link the git hook warning to the migration guide
([#1902](#1902)), by
@naokihaba
- `vp info` / `vp view`: use package-manager-native commands (`pnpm
view`, `bun info`, `yarn npm info`) instead of routing every lookup
through `npm view`
([#1895](#1895)), by
@jong-kyung
- Correct overused `ErrorConfig` error types across the codebase
([#1934](#1934)), by
@liangmiQwQ

### Refactor

- `vite_install`: centralize Yarn v1/berry branching with
`is_yarn_berry`
([#1897](#1897)), by
@jong-kyung

### Docs

- Document Vite Task automatic tracking (fs tracking and cache-reporting
tools), reusing the task cache with GitHub Actions cache, and
`dependsOn: [{ task, from: "dependencies" }]`
([#1992](#1992)), by
@wan9chi
- Rewrite the "Upgrading Vite+" guide: preview builds install through
the registry bridge as ordinary `0.0.0-commit.<sha>` npm versions, and
`vp migrate` is the recommended way to upgrade a project or move it onto
a preview build
([#1965](#1965)), by
@fengmk2
- Describe how to switch back to the release version from nightly
([#1887](#1887)), by
@situ2001
- Clarify Git hook tool migration
([#1901](#1901)), by
@naokihaba
- Add a global installation explanation
([#1915](#1915)), update
the `vp env` help output
([#1969](#1969)), and add
liangmiQwQ as a team member
([#1911](#1911)), by
@liangmiQwQ
- Fix package manager command examples
([#1937](#1937)) and the
`dependsOn` guide link
([#1883](#1883)), by
@jong-kyung
- Remove Fathom analytics from the uninstall docs
([#1946](#1946)), by
@mdong1909
- Center the README logo and fix its size
([#1878](#1878)), by @hyf0

### Chore

- Prevent Vite beta upgrades in the upstream-deps script
([#1879](#1879)),
stabilize flaky network-dependent tests
([#1923](#1923)), and bump
the ecosystem-ci bun-vite-template to the oxlint jsx-a11y fix
([#1898](#1898)), by
@fengmk2
- Pin snap-test install fixtures to a published `vite-plus` version so
release-branch CI can pass before the new version is published
([#2017](#2017)), by
@fengmk2
- Update the deprecated `VITE_PLUS_` env var prefixes to `VP_` in the
RFCs ([#1984](#1984)), by
@liangmiQwQ
- CI: skip full CI for docs-only PRs
([#1991](#1991)) and for
the docs deploy config
([#2015](#2015)), by
@wan9chi
- Update GitHub Actions
([#1904](#1904),
[#1977](#1977)),
claude-code-action to v1.0.158
([#1979](#1979)), and pnpm
to v10.34.4
([#1996](#1996)), by
@renovate[bot]
- Update oxc-project/security-action to v1.0.8
([#1918](#1918)), by
@fengmk2
- Refresh trusted stack stats on the docs homepage
([#1913](#1913),
[#1982](#1982)), by
@voidzero-guard[bot]

### Bundled Versions

| Tool | Version | Source |
| --- | --- | --- |
| vite | `8.1.2` |
[`ba31193`](vitejs/vite@ba31193)
|
| rolldown | `1.1.4` |
[`6cbd233`](rolldown/rolldown@6cbd233)
|
| tsdown | `0.22.3` | [npm](https://npmx.dev/package/tsdown/v/0.22.3) |
| vitest | `4.1.9` | [npm](https://npmx.dev/package/vitest/v/4.1.9) |
| oxlint | `1.72.0` | [npm](https://npmx.dev/package/oxlint/v/1.72.0) |
| oxlint-tsgolint | `0.24.0` |
[npm](https://npmx.dev/package/oxlint-tsgolint/v/0.24.0) |
| oxfmt | `0.57.0` | [npm](https://npmx.dev/package/oxfmt/v/0.57.0) |

### Upgrade

```bash
vp upgrade
```

New to Vite+? Start with the [Beta
announcement](https://voidzero.dev/posts/announcing-vite-plus-beta),
then create a project with `vp create` or bring an existing one over
with `vp migrate`.

### New Contributors

Welcome to our new contributors @rokuosan, @Aalivexy, @cheezone,
@daflyinbed, @forehalo, @kvnwolf! 🎉

**Full Changelog**:
v0.2.1...v0.2.2

---

Merging this PR will trigger the release workflow.

---------

Co-authored-by: voidzero-guard[bot] <278573678+voidzero-guard[bot]@users.noreply.github.com>
Co-authored-by: MK <fengmk2@gmail.com>
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.

Failed to initialize cache: Unrecognized database version: 13 error

2 participants