fix(catalog): version the .cache wire format so parser changes auto-invalidate#19
Merged
Merged
Conversation
…nvalidate The catalog cache used to be stale-checked by source-XML mtime only. When a parser change reshapes the in-memory Template / Data / Class without touching the XML, on-disk caches stayed "fresh" and got loaded verbatim — silently feeding the new mythy binary the old parser's output. Anyone upgrading mythy needed to manually wipe Templates/*.cache to see the fix take effect, including during normal development. Wrap every cache file with a small versioned header (magic string + schema version int) ahead of the gob-encoded Template, both written by SaveCache and verified by LoadCache. Any mismatch — wrong magic, wrong version, or any decode failure — routes to ErrCacheStale and the caller falls back to ParseTemplate, which writes a fresh cache. parserSchemaVersion starts at 1 and gets bumped from now on whenever a PR changes how pkg/catalog/ encodes a Template. Pre-versioning caches (bare *Template gob) decode into the new wrapper as malformed data and are correctly rejected — confirmed by test. Closes #5 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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 #5.
What changed
pkg/catalog/cache.gowraps the on-disk gob payload with a tiny header:SaveCachealways emits the wrapper.LoadCacheverifies the magic and version before unwrapping; any mismatch routes toErrCacheStale. The pre-existing source-XML-mtime check is kept — it still catches the "I edited the catalog by hand" case independently of the schema version.Bumping policy
parserSchemaVersionis a constant at the top ofcache.go, currently1. The doc comment spells out the rule: any PR that changes howpkg/catalog/encodes aTemplate(struct field added, dropped, semantics-rewritten, or any load-time pass mutates the result) bumps the version. Reviewers should treat unbumpedpkg/catalog/diffs as suspicious.Backwards compatibility
Pre-versioning caches encoded a bare
*Templatedirectly. After this PRLoadCachetries to decode them into the newcacheFilewrapper and gets a gob error or a malformed wrapper; either way it returnsErrCacheStaleand the caller regenerates. Verified byTestLoadCacheRejectsLegacyUnwrappedFormat.Tests
TestLoadCacheRejectsLegacyUnwrappedFormat— writes a bare*Template(the pre-fix format), assertsLoadCachereturnsErrCacheStale.TestLoadCacheRejectsWrongSchemaVersion— writes a wrapper withparserSchemaVersion + 1, asserts the same.TestCacheRoundTrip/TestCacheStaleOnMtime/TestLoadCacheResolvesTypedefsForStaleCachespass unchanged through the new wrapper.Live verification
Pre-PR cache on disk:
~/gridsociety/thytronic-templates/us/NV10P-EB0-u.cache(1931115 bytes, mtime 13:13, written by an older mythy build). After running any mythy command with this PR's binary, the cache regenerates: same path, mtime advanced, size grew by 91 bytes (the wrapper header), and subsequent invocations load the new-format cache without re-parsing. The migration is silent.🤖 Generated with Claude Code