Found while executing #14478 (branch claude/issue-14478-duration-unit-in-key-name), which renamed MetadataManagerConfig.cache.ttl to cache.ttlSeconds under the maintainer's ruling. Out of scope there: the ruling renames the key; it does not ask whether anything reads it.
Measured on origin/main ca46f8f12 (2026-09-04)
packages/spec/src/kernel/metadata-loader.zod.ts declares, under cache:
enabled: z.boolean().default(true).describe('Enable caching')
ttl (now ttlSeconds): z.number().int().min(0).default(3600).describe('Cache TTL in seconds')
maxSize: z.number().int().min(0).optional().describe('Max cache size in bytes')
databaseLoader: { enabled, maxSize, ttl (now ttlMs) }
The only runtime consumer of the block is packages/metadata/src/metadata-manager.ts:618 and :648, both cache: this.config.cache?.databaseLoader — the nested databaseLoader object is handed to new DatabaseLoader({ cache }) and honoured there (database-loader.ts, ttl: cacheOpts?.ttlMs ?? 60_000). Nothing reads the outer cache.enabled, cache.ttlSeconds or cache.maxSize:
git grep -n "cache\.ttl\|cache?\.ttl\|cache\.enabled\|cache?\.enabled\|cache\.maxSize\|cache?\.maxSize" -- packages ':!*.test.ts' ':!*CHANGELOG*'
returns only the schema declaration itself; the three keys appear otherwise in packages/spec/src/kernel/metadata-loader.test.ts and packages/spec/src/system/registry-config.test.ts (the latter is a different schema, RegistryConfig, with its own cache.ttl). MetadataManagerConfig is not a governed liveness type, so no ledger row records this.
Why it is a defect and not a nit
An author who writes cache: { enabled: false } or cache: { ttlSeconds: 60 } on a MetadataManager gets a clean parse and a cache that behaves exactly as before — the outer block advertises three knobs the runtime does not deliver (declared but not enforced, the ADR-0049 class). The published reference page (content/docs/references/kernel/metadata-loader.mdx) documents all three as if they configured something. The databaseLoader sub-block is the only live half.
Candidate dispositions (a triage call, not made here)
- ADR-0049 enforce-or-remove: retire the three outer keys as
retiredKey() tombstones (the object is not strict) with a prescription pointing at cache.databaseLoader, registering the retirement; or
- wire them: make
cache.enabled gate the DatabaseLoader cache and give ttlSeconds / maxSize a real reader — only if a consumer for a second cache layer exists, which the measurement above did not find.
Refs #14478 (the rename that surfaced this).
Generated by Claude Code
Found while executing #14478 (branch
claude/issue-14478-duration-unit-in-key-name), which renamedMetadataManagerConfig.cache.ttltocache.ttlSecondsunder the maintainer's ruling. Out of scope there: the ruling renames the key; it does not ask whether anything reads it.Measured on
origin/mainca46f8f12(2026-09-04)packages/spec/src/kernel/metadata-loader.zod.tsdeclares, undercache:enabled: z.boolean().default(true).describe('Enable caching')ttl(nowttlSeconds):z.number().int().min(0).default(3600).describe('Cache TTL in seconds')maxSize: z.number().int().min(0).optional().describe('Max cache size in bytes')databaseLoader: { enabled, maxSize, ttl (now ttlMs) }The only runtime consumer of the block is
packages/metadata/src/metadata-manager.ts:618and:648, bothcache: this.config.cache?.databaseLoader— the nesteddatabaseLoaderobject is handed tonew DatabaseLoader({ cache })and honoured there (database-loader.ts,ttl: cacheOpts?.ttlMs ?? 60_000). Nothing reads the outercache.enabled,cache.ttlSecondsorcache.maxSize:returns only the schema declaration itself; the three keys appear otherwise in
packages/spec/src/kernel/metadata-loader.test.tsandpackages/spec/src/system/registry-config.test.ts(the latter is a different schema,RegistryConfig, with its owncache.ttl).MetadataManagerConfigis not a governed liveness type, so no ledger row records this.Why it is a defect and not a nit
An author who writes
cache: { enabled: false }orcache: { ttlSeconds: 60 }on aMetadataManagergets a clean parse and a cache that behaves exactly as before — the outer block advertises three knobs the runtime does not deliver (declared but not enforced, the ADR-0049 class). The published reference page (content/docs/references/kernel/metadata-loader.mdx) documents all three as if they configured something. ThedatabaseLoadersub-block is the only live half.Candidate dispositions (a triage call, not made here)
retiredKey()tombstones (the object is not strict) with a prescription pointing atcache.databaseLoader, registering the retirement; orcache.enabledgate the DatabaseLoader cache and givettlSeconds/maxSizea real reader — only if a consumer for a second cache layer exists, which the measurement above did not find.Refs #14478 (the rename that surfaced this).
Generated by Claude Code