fix(loader): reject non-ttl cache forms on time vars at load, ttl-only by type (cje)#100
Merged
Merged
Conversation
…y by type (cje) Sheriff finding #5 [LAW:no-silent-failure]: a time var declaring cache: watch_file / depends_on / key / never passed the loader, then renderDsl silently coerced it to the default 1s TTL — the config's stated meaning replaced with no diagnostic. TimeVarDecl.cache narrows to TtlCacheDecl, so the illegal form is unrepresentable past the load boundary [LAW:types-are-the-program]. The loader's TIME_FIELDS uses a ttl-only OneOfPresentSchema sharing CACHE_SCHEMA's own ttl arm — one declaration source feeding both the validator and the emitted JSON schema (regenerated). The render-time 'ttl' in guard and the orphaned follow-up-ticket comment delete; the TTL mapping is total. Closes brandon-config-validation-cje.
There was a problem hiding this comment.
Z.ai Coding Agent Review
This PR restricts time-variable cache declarations to the ttl arm only, rejecting all other CacheDecl variants (watch_file, depends_on, key, never) at load time with a clear diagnostic instead of silently coercing them to the default TTL at render time.
The change is well-structured and law-compliant:
- [LAW:types-are-the-program]:
TimeVarDecl.cacheis narrowed fromCacheDecl | undefinedtoTtlCacheDecl | undefined, making non-ttl cache forms unrepresentable past the loader boundary. The runtimedeclareOnecase no longer needs a"ttl" in decl.cacheguard — the type guarantees the shape. - [LAW:one-source-of-truth]:
TtlCacheDeclis a single named interface thatCacheDeclcomposes from andTimeVarDeclnarrows to — not a parallel shape.TTL_ONLY_CACHE_SCHEMAreusesCACHE_SCHEMA.arms.ttldirectly. - [LAW:no-silent-failure]: The old code silently treated non-ttl cache forms as "use default 1s TTL." Now the loader rejects them with a diagnostic naming
ttlas the only supported key. - [LAW:single-enforcer]: The enforcement lives in the loader's
ttlOnlyCacheSpec, not duplicated in the runtime.
Tests cover all four rejected arms, an invalid ttl value, and a valid ttl pass-through. The JSON schema is kept in sync. No must-change items.
✅ Approved
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.
Summary
Sheriff finding #5 (law audit 2026-06-09), ticket brandon-config-validation-cje —
[LAW:no-silent-failure].A time variable declaring
cache: watch_file / depends_on / key / neverpassed the loader, thensrc/dsl/render.tsbypassedtoCachePolicyand silently treated the declaration as the default 1s TTL — the config's stated meaning replaced with a different one, no diagnostic, plus an orphaned 'follow-up ticket' comment promising remediation.Remediation (locked decision: reject at load, the zk5 parallel)
TimeVarDecl.cachenarrows toTtlCacheDecl(src/config/dsl-types.ts) — the ttl arm named once, composed intoCacheDecl; past the load boundary a non-ttl cache on a time var is unrepresentable[LAW:types-are-the-program].ttlOnlyCacheSpec()(src/config/loader/cache.ts) — a one-armOneOfPresentSchema<TtlCacheDecl>sharingCACHE_SCHEMA's own ttl arm (subset of the vocabulary, not a parallel grammar;PresentArmMapforces exactly the ttl arm at compile time). A non-ttl form is a load-time diagnostic naming ttl:Unknown time-variable cache key "watch_file". Expected exactly one of: ttl.parsefacet is the validator; thejsonfacet narrows the published schema —schema/cc-candybar.schema.jsonregenerated, the time arm's cacheanyOfcollapses to ttl, so editors flag the form at authoring time."ttl" inguard and the apologetic follow-up-ticket comment atsrc/dsl/render.ts— the TTL mapping is now total.Verification
ttlparses.pnpm typecheck,pnpm lint,pnpm check:schema,pnpm buildall clean."ttl" inistoCachePolicy's full-vocabulary handling for file/shell.