Skip to content

Define precise disableCache trigger points for uncacheable operations #482

Open

Description

@wan9chi

Problem

disableCache() currently has an imprecise contract in practice. Tool integrations can call it while configuring a server because the configuration may later lead to an uncacheable operation. That is too early.

The observed failure mode is Vite/Vitest: a task can create a Vite server for transforms or test execution without actually listening on a port or watching the filesystem. If disableCache() fires during server/config setup, cacheable tasks such as vitest run are reported as Not cached: the task opted out of caching even though no uncacheable operation happened.

Principle

disableCache() should be called immediately before the concrete operation that makes the task uncacheable, not when reading configuration that might eventually lead to such an operation.

Concrete examples:

  • Listening on a port should disable caching immediately before the listen/bind operation.
  • Observing the filesystem should disable caching immediately before the watcher starts observing paths.
  • Creating/configuring an object that might later listen or watch should not disable caching by itself.

Temporary workaround

PR #481 makes vite_task_client::Client::disable_cache() a no-op so false opt-outs stop affecting downstream task caching while the real fix is designed and shipped.

Real solution

Move the Vite/Vitest integration points to operation boundaries:

  • In Vite, call disableCache() from the HTTP server start/listen path immediately before binding a port.
  • In Vite, call disableCache() from the watcher start path immediately before filesystem observation begins.
  • Do not call disableCache() from generic server creation/config resolution paths.
  • Verify Vitest run without watch/API does not listen or watch and therefore remains cacheable.
  • Verify Vitest API/server mode and watch mode still opt out because they perform uncacheable operations.

After those semantics are implemented and covered, revert the vite-task client no-op workaround and restore disableCache() as an effective client request.

Activity

  1. added a commit that references this issue on Jun 21, 2026
  2. jasonkuhrt commented on Oct 24, 2026

    @jasonkuhrt
    Contributor

    Written by an AI agent (Claude) on behalf of @jasonkuhrt.

    A use case for the redesign, from a tool that knows the exact operation that makes its run uncacheable.

    We run Playwright suites as Vite Task tasks with a ratchet: a reporter skips the cases earlier runs on the branch already passed, so a re-push runs only what is still owed. A run that skipped cases exits 0 but is not a pass of the whole suite, so it must never be stored: a later cache hit would report every case passed on code where most of them never ran. A run that ran every case is an ordinary pass and should be stored and replayed.

    The reporter knows this at one point, in Playwright's onBegin, where it calls testRun.exclude on the settled cases. That fits the principle here: disable caching immediately before the operation that makes the run uncacheable.

    With disable_cache a no-op since #481, there is no way to say it, so these tasks are cache: false everywhere and can't replay a full pass either. Could the redesign keep a way for a process inside the task (here a reporter two processes below the task's command) to mark the current run as not to be stored, leaving lookup as it is? Happy to test a branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    read-write overlapCaching tasks that read and write the same paths

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions