fix(cache): persist offline bundled fallback so format-stale caches don't rebuild every call (#140)#142
Merged
Conversation
…on't rebuild every call When the only cached command-model is format-stale (rejected by the format_version gate added in #139) and NetBox is unreachable, resolution fell back to the bundled schema and rebuilt it (~180ms) on every invocation, and tab-completion returned nothing for the profile until the first online command. Persist the bundled fallback under the profile via CacheStore.save( record_fetch=False) — no fetch timestamp, so the TTL fast-path still refetches once NetBox is reachable, but the next offline invocation hits _find_any_cached and completion surfaces a format-current entry immediately. Bumps version to 1.6.3. Closes #140 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
_validate_profile raises ValueError (not OSError) for a profile name outside _PROFILE_RE — and names aren't validated at config time. Suppress it too so the offline bundled fallback honors its non-fatal contract and still returns the in-memory model. Adversarial-review finding on #142. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Owner
Author
|
Adversarial review pass done (feature-dev:code-reviewer). Core claims verified: self-heals online, no-sidecar entry never served as fresh, no rebuild on repeat offline calls, completion recovers. One sub-threshold finding applied — |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #140.
Problem
Follow-up from #139 (v1.6.2), which added
CommandModel.format_versionand madeCacheStore.load()reject entries older thanMODEL_FORMAT_VERSIONso a one-time rebuild picks up new model metadata after an upgrade.The online path self-heals immediately. But when the only cached entry is format-stale-but-hash-fresh and NetBox is unreachable:
_find_any_cachedrejects the stale entry, the fetch fails, and resolution falls to_load_bundled_command_model()— rebuilding from the bundled schema (~180ms) on every invocation, because nothing re-saved on the offline branch.completion/cache_probehas no rebuild fallback, so tab-completion returns nothing for that profile until the first online command rewrites the cache — a brief completion blackout.Bounded and self-healing (no crash, no loop), but wasteful. Found by adversarial review of #139.
Fix
Persist the bundled fallback under the profile via a new
CacheStore.save(..., record_fetch=False):_find_any_cached(cheap JSON load) instead of re-parsing the bundled schema.cache_probenow surfaces a format-current entry.fetched_atsidecar is written, the TTL fast-path keeps distrusting the entry and attempts a real fetch once NetBox is reachable;_build_and_cachethen saves under the live hash.contextlib.suppress(OSError)); the in-memory model is still returned.Tests
test_save_without_record_fetch_writes_no_sidecar— store-level: model persisted, no sidecar,load_fetched_atisNone.test_offline_format_stale_cache_persists_bundled_fallback— end-to-end: stale entry + offline → bundled persisted (distinct hash, no timestamp, visible tocache_probe); second offline call served from_find_any_cached("using cached schema").Full suite (1364 passed), ruff, and
mypy --strictall green. Version bumped to 1.6.3 with CHANGELOG entry.🤖 Generated with Claude Code