Skip to content

perf(ci): cache dependencies, Jest transforms, and TSC build info + remove duplicate docs:sync#202

Merged
scottschreckengaust merged 9 commits into
mainfrom
fix/201-ci-caching
May 27, 2026
Merged

perf(ci): cache dependencies, Jest transforms, and TSC build info + remove duplicate docs:sync#202
scottschreckengaust merged 9 commits into
mainfrom
fix/201-ci-caching

Conversation

@scottschreckengaust
Copy link
Copy Markdown
Contributor

@scottschreckengaust scottschreckengaust commented May 27, 2026

Summary

Implements P0–P4 from issue #201 (CI optimization plan):

  1. P0: Cache node_modules (192MB, keyed on yarn.lock) and agent/.venv (125MB, keyed on uv.lock)
  2. P2: Cache Jest transforms via stable cacheDirectory (keyed on yarn.lock + SHA with restore-keys)
  3. P3: Cache TypeScript incremental build info (tsconfig.tsbuildinfo, keyed on source hashes)
  4. P4: Remove duplicate //docs:sync — already runs as a dependency of //docs:build

Also includes timing instrumentation (SECONDS + ::notice) to measure cache impact.

Measured results (from CI runs on this PR)

Step Cold (MISS) Warm (2/3 HIT) Expected (all HIT)
Install 78s 76s ~5-10s
Build 1024s 771s ~650-700s
Total ~19.5min ~15.2min ~12-13min

The ~4min improvement on the warm run came primarily from node_modules cache (yarn skips install) and Jest transform cache. The third run (all 3 caches hit) is in progress.

Cache strategy

Cache Key Size Restore-keys Invalidates when
node_modules node-modules-{os}-{hash(yarn.lock)} 192MB None Lockfile changes
agent/.venv agent-venv-{os}-{hash(agent/uv.lock)} 125MB None Python deps change
Jest transforms jest-{os}-{hash(yarn.lock)}-{sha} 2MB Prefix match Per-commit; falls back to prior
TSC build info tsc-{os}-{hash(src/**)} <1MB Prefix match Source file changes

Other changes

  • cdk/package.json: adds "cacheDirectory": "<rootDir>/.jest-cache" (moves Jest cache off tmpfs — also fixes local /tmp ENOSPC)
  • .gitignore: adds .jest-cache
  • mise.toml: removes redundant //docs:sync from tasks.build

Test plan

  • Cold run: all caches MISS, timings match baseline (~78s install, ~1024s build)
  • Warm run (2/3 hit): node_modules+venv HIT, jest MISS — build drops by ~253s
  • Third run: all 3 caches HIT — validates full cache benefit
  • Mutation detection still works (no false positives)
  • Verify TSC cache reduces compile step on subsequent source-unchanged runs

Refs #201

🤖 Generated with Claude Code

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

scottschreckengaust and others added 2 commits May 27, 2026 05:18
Adds actions/cache for node_modules (keyed on yarn.lock) and
agent/.venv (keyed on uv.lock). Includes timing instrumentation
via SECONDS and ::notice annotations to measure cache-hit vs cold
install performance across runs.

Expected: Install step drops from ~75s (cold) to ~5s (cache hit).

Refs #201

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sets cacheDirectory to <rootDir>/.jest-cache (off tmpfs, persists
locally) and caches it in CI via actions/cache keyed on yarn.lock +
commit SHA with restore-keys fallback for cross-branch reuse.

Expected: test step drops from ~90s to ~40-50s on cache hit since
ts-jest skips re-transpiling unchanged source files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@scottschreckengaust scottschreckengaust changed the title perf(ci): cache node_modules and agent .venv in build workflow perf(ci): cache node_modules, agent .venv, and Jest transforms in build workflow May 27, 2026
scottschreckengaust and others added 2 commits May 27, 2026 05:37
No-op commit to trigger a second CI run where caches are warm.
Compare Install/Build timing annotations with the prior cold run.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previous warm run missed jest cache (cold run was still saving).
Now all three caches are fully saved. This run validates full hit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@scottschreckengaust scottschreckengaust marked this pull request as ready for review May 27, 2026 14:45
@scottschreckengaust scottschreckengaust requested a review from a team as a code owner May 27, 2026 14:45
- Caches cdk/tsconfig.tsbuildinfo and cli/tsconfig.tsbuildinfo keyed
  on source file hashes with restore-keys fallback. Enables tsc
  incremental compilation to skip unchanged files (~10-20s savings).

- Removes redundant `//docs:sync` from root tasks.build — already
  runs as a dependency of `//docs:build` (~5s wasted per build).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@scottschreckengaust scottschreckengaust changed the title perf(ci): cache node_modules, agent .venv, and Jest transforms in build workflow perf(ci): cache dependencies, Jest transforms, and TSC build info + remove duplicate docs:sync May 27, 2026
Comment thread mise.toml
@krokoko
Copy link
Copy Markdown
Contributor

krokoko commented May 27, 2026

Thanks for pushing this forward — solid incremental step on #201 (P0/P2/P3/P4). CI is meaningfully faster on warm runs without changing the mutation gate. A few notes for the thread; nothing blocking from my side.

What looks good

  • Caching strategy is sensible: lockfile-keyed node_modules / agent/.venv (no broad restore-keys on deps), Jest transform cache with a stable cacheDirectory, and TSC tsbuildinfo for CDK/CLI.
  • Removing duplicate //docs:sync from root tasks.build is correct — //docs:build already depends on :sync in docs/mise.toml (and docs/package.json runs sync before Astro build). Saves ~5s per build with no behavior change.
  • Mutation detection unchanged; checks are green on the latest run (~12m38s for build (agentcore) vs ~14.5m baseline in perf(ci): build.yml optimization plan — parallelism, caching, and redundancy removal #201).

Measured impact (expectations)

Area PR expectation Practical takeaway
Wall time ~12–13 min all caches warm ~2 min improvement so far — good, but still short of #201’s “<6 min” target
Install ~5–10s on cache hit Warm run still ~76s — install always runs (yarn install --check-files, uv sync, prek install); cache avoids re-download but not full install work
Build Large drop when Jest + deps warm Matches data (~4 min saved cold → warm) — main win is here
P1 parallelism Not in this PR Biggest remaining wall-time win is still splitting serial jobs (#201)

Potential gaps (low risk, worth awareness)

  1. Install never short-circuits on cache hit — conservative for correctness; caps install savings until we optionally skip/trim install when both dep caches hit.
  2. Dep cache keys are lockfile-onlypackage.json / resolutions / mise Python version changes without yarn.lock / uv.lock bumps could serve a stale tree (rare; fix = lockfile bump or manual cache bust).
  3. TSC restore-keys: tsc-${{ runner.os }}- — on exact-key miss, any prior OS tsbuildinfo may restore (cross-branch/SHA). tsc usually recovers, but this is the highest theoretical stale-build risk; cache key also omits tsconfig*.json and test paths. Open test-plan item to confirm compile savings is worth validating.
  4. Jest restore-keys across SHAs — usually safe (content-keyed transforms); edge case only on unusual ts-jest/config changes without lockfile bump.
  5. TSC savings may be smaller than estimated if incremental tsbuildinfo benefit is limited without explicit incremental in tsconfig — worth a glance at warm-run ::notice timings.
  6. Fork PRs may not reuse base-repo caches — external contributors often see cold runs (no regression).
  7. Cache churn — ~320MB+ per entry, four saves per job; occasional LRU misses after lockfile changes.

Suggested follow-ups (optional, post-merge)

Happy to approve once the above is acknowledged — nice work on measurable CI wins without touching the self-mutation contract.

v4.2.3 runs on Node 20 which is deprecated and will be forced to
Node 24 starting June 2, 2026.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@scottschreckengaust
Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review — all fair points. Addressing each:

Gap 1 (Install never short-circuits): Intentional. yarn install --check-files with a warm node_modules is fast (~5-10s for integrity checks) but not zero. We could conditionally skip it on exact cache hit, but the risk of stale/corrupted deps isn't worth the ~5s save. The real install time on warm runs is dominated by uv sync and prek install, not yarn.

Gap 2 (Lockfile-only keys): Agreed this is the correct tradeoff. Any meaningful dep change should bump the lockfile. Manual cache bust via GitHub UI handles edge cases.

Gap 3 (TSC restore-keys breadth): Valid — I'll add tsconfig.json to the hashFiles glob to tighten it. If we see no measurable compile savings on the next warm run (via ::notice), happy to drop the TSC cache entirely since the risk/reward is marginal.

Gap 5 (TSC incremental without incremental: true): Good catch — tsc --build mode implies incremental, but only if the tsconfig project references are set up for it. The CDK tsconfig uses --build in the compile script, so .tsbuildinfo should be generated. Will confirm from next run.

Gaps 4/6/7: All acknowledged, no action needed.

Squash commits: Will squash the three empty "trigger CI" commits on merge.

Node 20 deprecation: Already addressed — the latest commit upgrades actions/cache from v4.2.3 (Node 20) to v5.0.5 (Node 24 compatible). The deprecation warning should be gone on the current run.

P1 (parallelism) is already drafted in PR #203 — a ~20-line mise.toml change that achieves the same 3x speedup via DAG dependencies without GHA restructuring.

scottschreckengaust and others added 2 commits May 27, 2026 16:29
Tightens the cache key to invalidate when tsconfig.json or
tsconfig.dev.json change, not just source files. Prevents stale
.tsbuildinfo from surviving config changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ensures tsc generates .tsbuildinfo for incremental compilation.
While `tsc --build` implies incremental, being explicit guarantees
the behavior regardless of invocation mode.

Verified locally:
  CDK compile: 16s cold → 0.16s incremental (99% faster)
  CLI compile: 4s cold → 0.14s incremental (97% faster)

Also adds *.tsbuildinfo to .gitignore.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@scottschreckengaust
Copy link
Copy Markdown
Contributor Author

Updates addressing review feedback:

Gap 3 resolved (commit aae6820): TSC cache key now includes tsconfig.json and tsconfig.dev.json in hashFiles() — config changes properly invalidate the cache.

Gap 5 resolved (commit 137abd7): Added explicit "incremental": true to both cdk/tsconfig.json and cli/tsconfig.json. Verified locally:

Package Cold compile Incremental (warm) Speedup
CDK 16s 0.16s 99%
CLI 4s 0.14s 97%

Also added *.tsbuildinfo to .gitignore.

actions/cache upgrade (commit 8792f8e): v4.2.3 → v5.0.5 (Node 24 compatible) — resolves the deprecation warning.

Ready for re-review when convenient.

@krokoko
Copy link
Copy Markdown
Contributor

krokoko commented May 27, 2026

thanks !
will approve once build is green

@scottschreckengaust
Copy link
Copy Markdown
Contributor Author

Good catch on the wording — but it's already covered! The cache key includes both:

hashFiles('cdk/src/**', 'cdk/tsconfig.json', 'cdk/tsconfig.dev.json', 'cli/src/**', 'cli/tsconfig.json')

cli/tsconfig.json is in there. My comment was just imprecise — both packages are handled.

@scottschreckengaust scottschreckengaust added this pull request to the merge queue May 27, 2026
Merged via the queue into main with commit 7736a0a May 27, 2026
6 checks passed
@scottschreckengaust scottschreckengaust deleted the fix/201-ci-caching branch May 27, 2026 17:00
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.

2 participants