From d2fea9b400763b85012293350a90f53a3788cd43 Mon Sep 17 00:00:00 2001 From: Asgeir Frimannsson Date: Fri, 2 Oct 2026 10:14:14 +0200 Subject: [PATCH] Rename the cache-tm input to parse-cache The input caches kapi's parse cache, which has nothing to do with content memory. cache-tm stays as a deprecated alias: when a workflow sets it, it decides and the action prints a warning naming parse-cache. One step resolves the value and both conditions read it. The input description and the README now describe kapi 1.3: the project's context lives in kapi's workspace and moves through a context backend with kapi context pull, which this action leaves to kapi-action's context-sync input or the workflow's own step. The test workflow covers parse-cache: false, cache-tm: false, and cache-tm deciding over parse-cache. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01PWc9qYQJ93y88XrN6TkMvT --- .github/workflows/test.yml | 49 +++++++++++++++++++++++++++++ README.md | 14 +++++---- action.yml | 64 +++++++++++++++++++++++++++----------- 3 files changed, 103 insertions(+), 24 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7c331e6..1e99657 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -260,6 +260,55 @@ jobs: name: state-cache-restore-${{ matrix.os }} path: ${{ runner.temp }}/results + # parse-cache and its deprecated name cache-tm. The save job left a parse + # cache to restore, and no kapi command runs here, so whether the cache + # directory exists after setup shows which value the action acted on. When + # cache-tm is set, it decides. + test-parse-cache-input: + name: "Parse cache input (${{ matrix.case }})" + needs: test-state-cache-save + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - case: "parse-cache: false" + parse_cache: "false" + cache_tm: "" + restored: "false" + - case: "cache-tm: false" + parse_cache: "true" + cache_tm: "false" + restored: "false" + - case: "cache-tm: true over parse-cache: false" + parse_cache: "false" + cache_tm: "true" + restored: "true" + steps: + - uses: actions/checkout@v6 + + - name: Setup kapi + uses: ./ + with: + token: ${{ secrets.NEOKAPI_GITHUB_TOKEN }} + version: ${{ env.STATE_CACHE_KAPI_VERSION }} + plugins: "" + project-dir: test/fixture + parse-cache: ${{ matrix.parse_cache }} + cache-tm: ${{ matrix.cache_tm }} + + - name: Check whether the parse cache was restored + shell: bash + env: + WANT_RESTORED: ${{ matrix.restored }} + run: | + docs=test/fixture/.kapi/work/cache/docs + if [ "${WANT_RESTORED}" = "true" ]; then + test -s "${docs}/index.db" + else + test ! -e "${docs}" + fi + test-cache: name: "Cache hit (${{ matrix.os }})" runs-on: ${{ matrix.os }} diff --git a/README.md b/README.md index 4390ddd..30aec44 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,8 @@ The newest stable release, which `latest` installs, has no `kapi up`, so this ex | `plugins` | Newline- or comma-separated plugin refs to install, as the registry names them (`bowrain`, `okapi-bridge`; a `kapi-` prefix is stripped). Pass `''` to install nothing | `bowrain` | No | | `auth-token` | Bowrain server JWT, exported as `BOWRAIN_AUTH_TOKEN` | — | No | | `server` | Bowrain server URL, exported as `BOWRAIN_SERVER_URL` | — | No | -| `cache-tm` | Carry kapi's parse cache (`.kapi/work/cache/docs`) between runs with the job cache; see [Project parse cache](#project-parse-cache). Runs only when a `kapi.yaml` recipe (or legacy `*.kapi`) is present. Set `false` to disable | `true` | No | +| `parse-cache` | Carry kapi's parse cache (`.kapi/work/cache/docs`) between runs with the job cache; see [Project parse cache](#project-parse-cache). Runs only when a `kapi.yaml` recipe (or legacy `*.kapi`) is present. Set `false` to disable | `true` | No | +| `cache-tm` | Deprecated name of `parse-cache`. When set, it decides in place of `parse-cache`, and the action prints a warning | `''` | No | | `project-dir` | Directory holding the `kapi.yaml` project whose parse cache is carried between runs | `.` | No | ## Outputs @@ -105,7 +106,7 @@ image. 4. **Add to PATH** — makes `kapi` available to all subsequent steps. 5. **Configure auth** (optional) — exports `BOWRAIN_AUTH_TOKEN`/`BOWRAIN_SERVER_URL` when `auth-token` is set. 6. **Install plugins** — installs each ref in `plugins` (default: `bowrain`) via `kapi plugins install`, cached keyed on the plugin set + OS + arch. Refs use the registry names; a `kapi-` binary prefix is stripped (`kapi-bowrain` → `bowrain`). -7. **Restore the project parse cache** (when a `kapi.yaml` recipe, or legacy `*.kapi`, is present): restores `.kapi/work/cache/docs` from the job cache, and saves it again at job end under a key unique to the job and run attempt. See [Project parse cache](#project-parse-cache). Disable with `cache-tm: false`. +7. **Restore the project parse cache** (when a `kapi.yaml` recipe, or legacy `*.kapi`, is present): restores `.kapi/work/cache/docs` from the job cache, and saves it again at job end under a key unique to the job and run attempt. See [Project parse cache](#project-parse-cache) for what it leaves to `kapi context pull`. Disable with `parse-cache: false`. ## Caching @@ -113,14 +114,15 @@ The binary is cached keyed on version + OS + arch; plugins are cached keyed on t ### Project parse cache -kapi keeps the state it derives out of git, under `.kapi/work/` (the project's `.kapi/.gitignore` ignores `work/` and `filters.local.json`). With `cache-tm` on and a recipe in `project-dir`, the action restores one directory of it, `.kapi/work/cache/docs`, before your steps run, and `actions/cache` saves it again when the job ends. kapi records there how it parsed each source and target file, so a later run can replay a file instead of parsing it again. +kapi keeps what it derives from a checkout under `.kapi/`, out of git. With `parse-cache` on and a recipe in `project-dir`, the action restores one directory of it, `.kapi/work/cache/docs`, before your steps run, and `actions/cache` saves it again when the job ends. kapi records there how it parsed each source and target file, so a later run can replay a file instead of parsing it again. A restored parse cache does not change any result. kapi keys each entry by the file's path and content hash, the parse configuration, the recipe and the kapi build, and parses the file again when any of them differs. The test workflow checks this on every change: with the cache restored, `kapi status`, `kapi check`, `kapi check --ship` and `kapi up` must match a cold run exactly, in exit codes, output and every file written, and they must still match after the source changes. -Everything else under `.kapi/` stays out of the cache: +The project's context (its terms, voice profiles, content memory and recorded decisions) lives in kapi's workspace, outside git, and moves between machines through a context backend (kapi 1.3 and later). A runner starts with an empty workspace, so a job that needs the context runs `kapi context pull` before kapi works, and `kapi context push` after a run records something. setup-kapi runs neither command: [`kapi-action`](https://github.com/neokapi/kapi-action)'s `context-sync` input runs them around its command, or your workflow can run them as steps of its own. -- The content memory, terms, voice profile and unit-state record are committed under `.kapi/`, so the checkout already holds them, and kapi builds its local store from them. -- `.kapi/work/store.db` also holds stored targets and staged review decisions. Restored from an earlier run, it reports targets the checkout does not hold, and `kapi status`, `kapi check --ship` and `kapi up` report differently than they would on a cold run. +Everything else under `.kapi/work/` stays out of the cache: + +- `.kapi/work/store.db` holds this checkout's block cache and the targets a run wrote. Restored from an earlier run, it reports targets the checkout does not hold, and `kapi status`, `kapi check --ship` and `kapi up` report differently than they would on a cold run. - `.kapi/work/cache/extractions/` holds `kapi extract` batches for `kapi merge`, and `.kapi/work/cache/redaction/` and `.kapi/work/vault/` hold withheld original values. - `.kapi/work/cache/sync-cache.json` and `.kapi/work/cache/refs.json` hold server sync state, including a claim token. diff --git a/action.yml b/action.yml index a7bb2a1..82da3d5 100644 --- a/action.yml +++ b/action.yml @@ -30,20 +30,29 @@ inputs: description: "Bowrain server URL (exported as BOWRAIN_SERVER_URL)" required: false default: "" - cache-tm: + parse-cache: description: >- Carry kapi's parse cache (.kapi/work/cache/docs) between CI runs with the - job cache. kapi keeps the state it derives out of git, under .kapi/work/. - The content memory, terms and unit-state record are committed under - .kapi/, and kapi builds its local store from them in a fresh checkout, so - they need no cache. Only the parse cache is restored: each entry is keyed - by the file's content, the parse configuration, the recipe and the kapi - build, and kapi parses a file again when any of them differs. The store - and the rest of .kapi/work/ are never restored, because restoring them - changes what kapi status, kapi check and kapi up report. Runs only when a - kapi.yaml recipe (or legacy *.kapi) is present. Set 'false' to disable. + job cache. From kapi 1.3 the project's context (terms, voice profiles, + content memory and recorded decisions) lives in kapi's workspace outside + git and is shared through a context backend, and .kapi/ holds a cache of + what kapi derives from the checkout. A job fetches the context with + `kapi context pull`, through kapi-action's `context-sync` input or a step + of its own; this action restores only the parse cache. Each entry is + keyed by the file's content, the parse configuration, the recipe and the + kapi build, and kapi parses a file again when any of them differs. The + store and the rest of .kapi/work/ are never restored, because restoring + them changes what kapi status, kapi check and kapi up report. Runs only + when a kapi.yaml recipe (or legacy *.kapi) is present. Set 'false' to + disable. required: false default: "true" + cache-tm: + description: >- + Deprecated: use parse-cache. When set, it decides in place of + parse-cache, and the action prints a warning. + required: false + default: "" project-dir: description: "Directory holding the kapi.yaml project whose parse cache is carried between runs. Default: repository root." required: false @@ -190,12 +199,28 @@ runs: kapi plugins install ${args[@]+"${args[@]}"} "${plugin}" done <<< "${PLUGINS}" - # 11. Detect a kapi project: a committed kapi.yaml recipe (or legacy *.kapi). + # 11. Resolve whether to carry the parse cache. cache-tm is the deprecated + # name of parse-cache; a workflow that still sets it keeps its meaning. + - name: Resolve parse cache input + id: parse-cache + shell: bash + env: + INPUT_PARSE_CACHE: ${{ inputs.parse-cache }} + INPUT_CACHE_TM: ${{ inputs.cache-tm }} + run: | + ENABLED="${INPUT_PARSE_CACHE}" + if [ -n "${INPUT_CACHE_TM}" ]; then + echo "::warning title=setup-kapi::The cache-tm input is deprecated; use parse-cache instead." + ENABLED="${INPUT_CACHE_TM}" + fi + echo "enabled=${ENABLED}" >> "$GITHUB_OUTPUT" + + # 12. Detect a kapi project: a committed kapi.yaml recipe (or legacy *.kapi). # The parse cache is carried only for a project. The recipe is the # signal because .kapi/work/ is gitignored and absent from a checkout. - name: Detect kapi project id: detect-project - if: inputs.cache-tm != 'false' + if: steps.parse-cache.outputs.enabled != 'false' shell: bash env: PROJECT_DIR: ${{ inputs.project-dir }} @@ -207,7 +232,7 @@ runs: echo "found=false" >> "$GITHUB_OUTPUT" fi - # 12. Restore kapi's parse cache, and save it at job end. The key is unique + # 13. Restore kapi's parse cache, and save it at job end. The key is unique # to the job and run attempt, so actions/cache saves through its own # post step; the restore takes the newest cache for the same kapi # version, preferring the same ref. @@ -217,19 +242,22 @@ runs: # recipe and the kapi build, and parses again on any mismatch, so a # restored entry is either valid for the checkout or ignored. The rest # of .kapi/work/ stays out of the cache: - # - store.db holds stored targets and the unit working set; restored, - # it changes what kapi status, kapi check --ship and kapi up report. + # - store.db holds the checkout's block cache and the targets a run + # wrote; restored, it changes what kapi status, kapi check --ship + # and kapi up report. # - cache/extractions holds kapi extract batches that kapi merge reads. # - cache/redaction and vault/ hold withheld original values. # - cache/sync-cache.json and cache/refs.json hold server sync state, # including a claim token. - # The content memory, terms and unit-state record are committed under - # .kapi/ and come with the checkout. + # The project's context (terms, voice profiles, content memory and + # recorded decisions) lives in kapi's workspace outside the checkout. A + # job fetches it with `kapi context pull`, which this action leaves to + # kapi-action's context-sync input or the workflow's own step. # # The kapi version is part of the key because the parse cache keeps the # entries every build wrote; a new version starts from an empty cache. - name: Restore kapi parse cache - if: inputs.cache-tm != 'false' && steps.detect-project.outputs.found == 'true' + if: steps.parse-cache.outputs.enabled != 'false' && steps.detect-project.outputs.found == 'true' uses: actions/cache@v5 with: path: ${{ inputs.project-dir }}/.kapi/work/cache/docs