Skip to content

Success Cache

Leonard Ramminger edited this page Aug 9, 2026 · 1 revision

Success Cache

The success cache skips individual items inside a Lua step callback. It is designed for per-file tools: lint, format-check, static analysis, and similar workflows.

Shell-only steps do not use success cache unless you call the API from a Lua run function.

Opt-in API

Method Purpose
ctx.file_success_cached(path) Returns true if file was previously successful
ctx.cache_file_success(path) Mark file as successful
ctx.record_file_cache_miss(path) Mark file as failed (re-check next run)
ctx.success_cached(key) Generic string key check
ctx.cache_success(key) Mark generic key successful
ctx.record_cache_miss(key) Record generic key miss
ctx.get_cache_misses() Paths/keys that failed in the previous run

See Step Context for calling conventions.

Typical loop

run = function(ctx)
    local files = ctx.glob(config.patterns)
    local failed = 0

    for _, path in ipairs(files) do
        if ctx.file_success_cached(path) then
            goto continue
        end

        local code = run_lint_on(path)  -- or ctx:spawn + ctx:wait
        if code ~= 0 then
            ctx.record_file_cache_miss(path)
            failed = failed + 1
        else
            ctx.cache_file_success(path)
        end

        ::continue::
    end

    return failed > 0 and 1 or 0
end

File cache validation

file_success_cached returns true only when:

  1. A manifest exists at .cache/success/entries/<key>.manifest
  2. Manifest matches current step identity (name, phase, scope)
  3. Config hash and Beez version match
  4. File still exists
  5. File content hash matches stored file_hash
  6. Include tree hash matches stored inputs_hash (transitive #include "..." headers)

Changing a source file or its included headers invalidates that file's success entry.

Generic key cache

success_cached(key) / cache_success(key) store simpler entries without file content hashing. Useful for non-file units (generated artifact names, test case ids).

Miss tracking

Failed paths are accumulated in memory during the step. At step end, Beez writes:

.cache/success/misses/<name>__<phase>__<scope>.misses

Format:

config_hash=<hash>
version=<beez-version>
---
path/one.cpp
path/two.cpp

On the next run, ctx.get_cache_misses() returns the list from the previous run (loaded at session start). Re-check those files even if other files are cached.

The misses file is updated when the Lua callback finishes successfully or with failure (session finish()).

Storage layout

Path Content
.cache/success/entries/<key>.manifest Per-file or per-key success record
.cache/success/misses/<step>.misses Failure list for incremental retry

<key> is a content hash of step identity, config, version, kind (file or string), and path/key value.

Config and revisions

Step config is part of the fingerprint. Bump a revision when the tool or rules change without source changes:

configure_step("lint", {
    patterns = { "src/**/*.cpp" },
    lint_rev = "2",
})

Changing lint_rev invalidates all success entries for that step.

Worker duration

When you use ctx:wait(job) before cache_file_success(path), Beez attaches the worker duration to the entry for time-saved statistics.

Disable

beez lint --no-cache

Or cache.enabled = false in config.

Step cache vs success cache

Step cache Success cache
Granularity Whole step Per file or key
Declaration input/output/mutate on step API calls in callback
Best for Compile, code gen, link Lint, format-check, analyze
Can combine Yes: shell compile step + Lua lint step

Next steps

Clone this wiki locally