Skip to content

perf: add mtime/lru_cache to uncached registry loaders#2153

Merged
Trecek merged 8 commits into
developfrom
perf-add-caching-to-uncached-registry-loaders/2138
May 7, 2026
Merged

perf: add mtime/lru_cache to uncached registry loaders#2153
Trecek merged 8 commits into
developfrom
perf-add-caching-to-uncached-registry-loaders/2138

Conversation

@Trecek
Copy link
Copy Markdown
Collaborator

@Trecek Trecek commented May 7, 2026

Summary

Four registry-loading functions re-read and re-parse YAML files from disk on every call with no caching. All four load static bundled assets that change only on package updates. This PR adds mtime-keyed dict caches to the three directory-scanning functions and @lru_cache(maxsize=1) to the single-file function, consistent with existing caching patterns in the codebase (DefaultRecipeRepository._get_list() in repository.py, _block_budgets() in rules_blocks.py).

Function Module Cache Strategy
load_all_experiment_types() recipe/experiment_type_registry.py mtime-keyed dict cache
load_all_methodology_traditions() recipe/methodology_tradition_registry.py mtime-keyed dict cache
list_migrations() migration/loader.py mtime-keyed dict cache
load_ml_sub_area_folding() recipe/methodology_venue_appendix.py @lru_cache(maxsize=1)

Closes #2138

Implementation Plan

Plan file: /home/talon/projects/autoskillit-runs/impl-20260507-014202-057975/.autoskillit/temp/make-plan/perf_add_caching_to_uncached_registry_loaders_plan_2026-05-07_015049.md

🤖 Generated with Claude Code via AutoSkillit

Token Usage Summary

Step Model count uncached output cache_read peak_ctx turns cache_write time
plan claude-sonnet-4-6 1 77 18.3k 521.7k 55.6k 73 47.9k 12m 2s
verify claude-sonnet-4-6 1 30 5.3k 455.4k 61.9k 99 35.0k 5m 16s
implement* MiniMax-M2.7-highspeed 1 1.4M 16.3k 1.2M 70.4k 96 80.3k 5m 18s
prepare_pr* MiniMax-M2.7-highspeed 1 88.9k 3.1k 235.3k 29.8k 20 15.3k 1m 16s
compose_pr* MiniMax-M2.7-highspeed 1 116.3k 2.5k 294.9k 29.8k 25 15.0k 1m 1s
review_pr claude-sonnet-4-6 2 162 71.0k 727.7k 80.4k 66 135.9k 14m 59s
resolve_review claude-opus-4-6 2 195 63.5k 8.5M 126.8k 250 199.7k 32m 37s
Total 1.6M 180.1k 12.0M 126.8k 529.2k 1h 12m

* Step used a non-Anthropic provider; caching behavior may differ.

Token Efficiency

Step LoC Changed cache_read/LoC cache_write/LoC output/LoC
plan 0
verify 0
implement 254 4712.8 316.1 64.0
prepare_pr 0
compose_pr 0
review_pr 0
resolve_review 109 78366.6 1832.3 583.0
Total 363 32986.1 1457.8 496.0

Model Usage Breakdown

Model steps uncached output cache_read cache_write time
claude-sonnet-4-6 2 107 23.6k 977.0k 82.9k 17m 19s
MiniMax-M2.7-highspeed 3 1.6M 21.8k 1.7M 110.6k 7m 35s

Trecek and others added 8 commits May 7, 2026 02:03
Add caching to four registry-loading functions that re-read and
re-parse YAML files on every call:

- load_ml_sub_area_folding(): @lru_cache(maxsize=1)
- list_migrations(): mtime-keyed dict cache
- load_all_experiment_types(): mtime-keyed dict cache
- load_all_methodology_traditions(): mtime-keyed dict cache

Cache keys use directory mtimes so stale entries are invalidated
when YAML files change. Tests added for all four caching behaviors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Addresses three review findings:
- Duplicate _dir_mtime in experiment_type_registry.py and
  methodology_tradition_registry.py extracted to _registry_utils.py
- OSError sentinel changed from 0.0 to -1.0 to avoid epoch-mtime
  collision with missing directories

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All four registry loaders now return copies of cached lists to prevent
caller mutation (e.g. in-place sort) from corrupting the cache.
load_ml_sub_area_folding returns an immutable tuple instead.

Test assertions updated: identity (is) → equality (==) + non-identity.
test_loader mtime invalidation uses os.utime instead of time.sleep.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…er dirs

0.0 is a valid mtime (epoch) that could collide with a real directory.
Use _MISSING_MTIME (-1.0) from _registry_utils for consistency and safety.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Consistent with experiment_type_registry and methodology_tradition_registry.
Adds OSError safety via the shared utility from _registry_utils.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ime tests

Move `import os` and `import time` from inside test method bodies to
module-level imports. Replace unreliable `time.sleep(0.05)` with
explicit `os.utime()` for deterministic mtime advancement in cache
invalidation tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use autouse fixture with yield to clear load_ml_sub_area_folding cache
in both setup and teardown, preventing cache state leakage to other tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…pe file count

Replace cross-package import of dir_mtime with inline try/except to
satisfy REQ-IMP-001 cross-package submodule import rule. Bump recipe/
file count exemption from 29 to 30 for _registry_utils.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Trecek Trecek added this pull request to the merge queue May 7, 2026
Merged via the queue into develop with commit b99ddb7 May 7, 2026
2 checks passed
@Trecek Trecek deleted the perf-add-caching-to-uncached-registry-loaders/2138 branch May 7, 2026 11:15
Trecek added a commit that referenced this pull request May 8, 2026
## Summary

Four registry-loading functions re-read and re-parse YAML files from
disk on every call with no caching. All four load static bundled assets
that change only on package updates. This PR adds mtime-keyed dict
caches to the three directory-scanning functions and
`@lru_cache(maxsize=1)` to the single-file function, consistent with
existing caching patterns in the codebase
(`DefaultRecipeRepository._get_list()` in `repository.py`,
`_block_budgets()` in `rules_blocks.py`).

| Function | Module | Cache Strategy |
|----------|--------|----------------|
| `load_all_experiment_types()` | `recipe/experiment_type_registry.py` |
mtime-keyed dict cache |
| `load_all_methodology_traditions()` |
`recipe/methodology_tradition_registry.py` | mtime-keyed dict cache |
| `list_migrations()` | `migration/loader.py` | mtime-keyed dict cache |
| `load_ml_sub_area_folding()` | `recipe/methodology_venue_appendix.py`
| `@lru_cache(maxsize=1)` |

Closes #2138

## Implementation Plan

Plan file:
`/home/talon/projects/autoskillit-runs/impl-20260507-014202-057975/.autoskillit/temp/make-plan/perf_add_caching_to_uncached_registry_loaders_plan_2026-05-07_015049.md`

🤖 Generated with [Claude Code](https://claude.com/claude-code) via
AutoSkillit
<!-- autoskillit:pipeline-signature
steps=prepare_pr,run_arch_lenses,compose_pr,annotate_pr_diff,review_pr
-->

## Token Usage Summary

| Step | Model | count | uncached | output | cache_read | peak_ctx |
turns | cache_write | time |

|------|-------|-------|----------|--------|------------|----------|-------|-------------|------|
| plan | claude-sonnet-4-6 | 1 | 77 | 18.3k | 521.7k | 55.6k | 73 |
47.9k | 12m 2s |
| verify | claude-sonnet-4-6 | 1 | 30 | 5.3k | 455.4k | 61.9k | 99 |
35.0k | 5m 16s |
| implement* | MiniMax-M2.7-highspeed | 1 | 1.4M | 16.3k | 1.2M | 70.4k
| 96 | 80.3k | 5m 18s |
| prepare_pr* | MiniMax-M2.7-highspeed | 1 | 88.9k | 3.1k | 235.3k |
29.8k | 20 | 15.3k | 1m 16s |
| compose_pr* | MiniMax-M2.7-highspeed | 1 | 116.3k | 2.5k | 294.9k |
29.8k | 25 | 15.0k | 1m 1s |
| **Total** | | | 1.6M | 45.5k | 2.7M | 70.4k | | 193.5k | 24m 55s |

\* *Step used a non-Anthropic provider; caching behavior may differ.*

## Token Efficiency

| Step | LoC Changed | cache_read/LoC | cache_write/LoC | output/LoC |
|------|-------------|----------------|-----------------|------------|
| plan | 0 | — | — | — |
| verify | 0 | — | — | — |
| implement | 254 | 4712.8 | 316.1 | 64.0 |
| prepare_pr | 0 | — | — | — |
| compose_pr | 0 | — | — | — |
| **Total** | **254** | 10646.7 | 761.8 | 179.0 |

## Model Usage Breakdown

| Model | steps | uncached | output | cache_read | cache_write | time |
|-------|-------|----------|--------|------------|-------------|------|
| claude-sonnet-4-6 | 2 | 107 | 23.6k | 977.0k | 82.9k | 17m 19s |
| MiniMax-M2.7-highspeed | 3 | 1.6M | 21.8k | 1.7M | 110.6k | 7m 35s |

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.

1 participant