Generated from cat-harness/skills/process/process-core/compiled-artefact-cache.md — do not edit here.

✎ Edit this page’s source

Compiled Artefact Cache

This skill documents the generalisable pattern for caching compiled artefacts (such as Lean caches and FHIR ASTs). It is the shared contract that specific implementations (e.g. lean-cache-restore and ig-ast-delta) adhere to.

The restore→build→contribute loop

The cache is not a maintenance chore but the output of every authoring session. Every session should leave the cache warmer than it found it:

restore  ──▶  draft / edit  ──▶  build  ──▶  contribute
   ▲                                              │
   └───────── next agent starts here ─────────────┘

Branch-based storage

Artefacts are stored on orphan branches named for their package and toolchain (e.g. lake-cache/<package>-<toolchain>). This keeps the repository clean while persisting large derived outputs across builds.

Validity checking (3-valued)

The validity of a cache is not a simple boolean. It relies on the CompiledInputsSchema defined in the content core’s schemas/materialization.ts. Validity is checked BEFORE use via compiledValidity() and returns one of three states:

  • valid: The cache matches the current inputs (e.g. toolchain, source revision, input digest). Restore and build.
  • stale-inputs: Identifies exactly which input changed. The cache cannot be used as-is; restore for the current toolchain instead, or build cold.
  • cannot-tell: The cache record lacks required input fields. Never a pass. Build cold or find the missing inputs first.

Exit code protocol

Scripts managing the cache must adhere to a standard exit code protocol. Branch on these codes rather than grepping the output:

CodeMeaningNext
0present / restored / publishedproceed
1miss — no such branchbuild cold, then contribute
2usage or environment errorstop the run, read the message, do not fallback to full build
3found but unusable (corrupt, won’t link, wrong toolchain)repair or reseed

Safety guards

When contributing a build back to the cache, it must be safe to run unconditionally. The contribution is refused unless it passes these guards:

  • Non-empty: There must actually be artefacts to cache.
  • Own-package: Artefacts must belong to the package itself, not just its dependencies.
  • Trace coverage: There must be sufficient metadata (e.g. >90% traced) for the build tool to use the cache effectively.
  • No-shrink: The new result must not be materially smaller than the incumbent cache, preventing partial builds from destroying a fuller cache.

For cold starts, seeding the cache uses a test-branch staging approach: the cache is seeded to a -test branch, and a restore is verified from a clean clone before touching production.

The warm-start principle: Cache the intermediates, not just the output

The core value of the cache is that an expensive step’s intermediate outputs survive across builds. The pattern is: a cache branch carries not just the final output but also the intermediate build artifacts that prevent the build system from re-deriving them:

cache typefinal outputintermediate artifactswhat they prevent
Lean.olean files.trace filesLake rebuild + eviction
FHIR ASTAST JSON + edgestxcache/ (tx.fhir.org expansions)Publisher re-hitting tx.fhir.org for every ValueSet

Owner decision (2026-10-01): input-cache/txcache/ goes on the fhir-ast branch alongside the AST files.

Preserving these intermediates is what makes subsequent incremental builds (such as those in ig-incremental-build.bpmn) fast.

Instantiations

AspectLean Cache (lean-cache-restore)FHIR AST (ig-ast-delta)
Artefacts.olean files, .trace filesPer-resource AST JSON, dependencies.json, txcache/
Inputs SchemaCompiledInputsSchemaCompiledInputsSchema
Key Inputstoolchain (Lean version), sourceRevisiontoolchain (Publisher version), sourceRevision, inputDigest
Storage Branchlake-cache/<package>-<toolchain>fhir-ast/<ig-package-id>
Service Scriptlake-cache.sh (9 verbs)ig-cache.sh (7 verbs)
Refreshed byan agent’s lake-cache.sh contributea reusable workflow of the IG layer, on a runner (the Publisher needs Java and a 10 GB heap), which each IG repository dispatches; a site build refuses an AST that is not valid (owner, 2026-10-14)
Cone EngineLake’s .trace-based dependency graphSUSHI’s fsh-index.json (forward: file → resource) + fsh-cone.ts (reverse: who uses this file) + AstPlanCli
Incrementallake build (only stale modules)IncrementalBuildCli (cone rebuild loop)

The file-to-resource mapping comes from the toolchain, not from us

Do not reimplement what the compiler already knows. SUSHI already writes fsh-generated/data/fsh-index.json on every run — the authoritative mapping from source .fsh file to output FHIR resource, with source locations. The AST exporter copies it into the AST directory; the incremental planner reads it there. No modification to SUSHI is needed.

fsh-cone (a Tool node, declared by the FHIR IG layer) provides the reverse half — who depends on a file — so a changed RuleSet- or Alias-only file (which produces no resource itself) can be traced to the resources it affects. These two maps together give the planner a complete cone.

Measured 2026-10-01 on the trust IG (678 resources):

plan inputavailableresult
No fsh-index.json, no fsh-usersoldfull build always
fsh-index.json onlynewincremental, 2 resources for a single-file change (0.3% cone)
fsh-index.json + fsh-usersnewincremental with RuleSet/Alias propagation

Timing (the trust IG, 678 resources, one CodeSystem changed)

build typetimevs cold
Cold full build22:281×
Warm full build (cached pkgs + tx)4:394.8×
Successive warm (everything cached)3:166.9×
Projected cone rebuild (2 resources)~15s~90×

Processes that run this skill

processstep(s) that name it
An IG site, built from the AST on its cache branchSeed the cache branch (ig-cache seed –push)

folio-assistant — code under the Apache License 2.0, documentation under CC BY 3.0. Generated schema and API references are rebuilt from source on every push to main.

deployed dev