|
| 1 | +--- |
| 2 | +"@objectstack/spec": minor |
| 3 | +"@objectstack/metadata": patch |
| 4 | +--- |
| 5 | + |
| 6 | +feat(spec)!: retire the three inert outer keys of `MetadataManagerConfig.cache` — `enabled`, `ttlSeconds` (formerly `ttl`) and `maxSize` — read by nothing; `cache.databaseLoader` is the only live half (#15624, ADR-0049) |
| 7 | + |
| 8 | +<!-- adr-0087: registered metadata-manager-config-inert-cache-keys-retired --> |
| 9 | + |
| 10 | +**BREAKING** accept-set narrowing, landing after the v17.0.0 cut (the lockstep |
| 11 | +launch-window convention ships it as `minor`; the migration prescription is |
| 12 | +registered under protocol major 18, where `os migrate meta` users will look). |
| 13 | +ADR-0049 enforce-or-remove decides it: a declared-but-unenforced key with zero |
| 14 | +measured readers comes off, and the published reference page stops teaching it. |
| 15 | + |
| 16 | +`MetadataManagerConfig.cache` declared three outer knobs — `enabled` (default |
| 17 | +`true`), `ttlSeconds` (default 3600; spelled `ttl` until #14478) and `maxSize` |
| 18 | +("Max cache size in bytes") — beside the nested `databaseLoader` block, and |
| 19 | +**nothing read the outer three**. The only runtime consumer of the block is |
| 20 | +`MetadataManager` (`packages/metadata`), which hands `cache.databaseLoader` and |
| 21 | +nothing else to `new DatabaseLoader({ cache })`; a reader census over |
| 22 | +`packages/**` (tests and changelogs excluded) found no runtime reader of any |
| 23 | +outer key, while the same grep shape found the nested `cache?.databaseLoader` |
| 24 | +read twice — the control that makes the zero a measurement. An author writing |
| 25 | +`cache: { enabled: false }` or `cache: { ttlSeconds: 60 }` got a clean parse |
| 26 | +and a cache that behaved exactly as before, with no error and no warning, and |
| 27 | +the published reference page (`references/kernel/metadata-loader`) documented |
| 28 | +all three as if they configured something. |
| 29 | + |
| 30 | +**What is refused:** authoring `cache.enabled`, `cache.ttlSeconds`, `cache.ttl` |
| 31 | +or `cache.maxSize` on `MetadataManagerConfig`, with any value — directly, through |
| 32 | +`MetadataManagerOptions`, or through `MetadataPluginConfig.storage`. The nested |
| 33 | +object is not `.strict()`, so each key is a `retiredKey()` tombstone rather than |
| 34 | +a bare deletion (a deletion would have stripped it in silence — the same no-op |
| 35 | +one layer down): authoring it is a `tsc` error (`never`) and a parse error |
| 36 | +carrying the prescription, which names the live nested knob. |
| 37 | + |
| 38 | +**What stays, byte-identical:** the DatabaseLoader read-through cache under |
| 39 | +`cache.databaseLoader` — `enabled` (default `true`), `maxSize` (an entry count, |
| 40 | +default 500) and `ttlMs` (milliseconds, default 60000) — and every runtime |
| 41 | +path. Parsed configs no longer carry the two former defaults (`enabled: true`, |
| 42 | +`ttlSeconds: 3600`) that were materialized and never consulted. |
| 43 | + |
| 44 | +**The #14478 rename is folded in.** `cache.ttl` → `cache.ttlSeconds` was |
| 45 | +registered under this same unreleased major and never reached a published |
| 46 | +release, so it is absorbed by the removal: `cache.ttl`'s tombstone now |
| 47 | +prescribes deletion (naming `cache.databaseLoader.ttlMs`) instead of a rename to |
| 48 | +a key that is itself retired — an author upgrading from a published 17.x sees |
| 49 | +one hop. The nested `cache.databaseLoader.ttl` → `ttlMs` half of that rename is |
| 50 | +unchanged. |
| 51 | + |
| 52 | +## FROM → TO |
| 53 | + |
| 54 | +```ts |
| 55 | +// before — parsed green; no runtime ever read the three outer numbers |
| 56 | +new MetadataManager({ |
| 57 | + datasource: 'default', |
| 58 | + cache: { enabled: true, ttlSeconds: 3600, maxSize: 10_485_760, databaseLoader: { ttlMs: 60_000 } }, |
| 59 | +}); |
| 60 | + |
| 61 | +// after — delete the outer keys; the nested block is the cache that runs |
| 62 | +new MetadataManager({ |
| 63 | + datasource: 'default', |
| 64 | + cache: { databaseLoader: { enabled: true, maxSize: 500, ttlMs: 60_000 } }, |
| 65 | +}); |
| 66 | +``` |
| 67 | + |
| 68 | +**Migration.** Delete `cache.enabled`, `cache.ttlSeconds` / `cache.ttl` and |
| 69 | +`cache.maxSize`; nothing replaces them, because nothing ever consumed them. If |
| 70 | +you meant to switch the cache off, cap it or set its TTL, write |
| 71 | +`cache.databaseLoader.enabled` / `.maxSize` (entries) / `.ttlMs` (milliseconds) |
| 72 | +— those are honoured. No `os migrate meta` conversion runs on this surface: a |
| 73 | +`MetadataManager` config is not a stack collection member and never a stored |
| 74 | +row, so the chain has no seam for it; the D3 semantic entry |
| 75 | +`metadata-manager-config-inert-cache-keys-retired` carries the prescription |
| 76 | +into `spec-changes.json`, the upgrade guide and the `spec_changes` MCP tool. |
| 77 | + |
| 78 | +The retirement kit: `retiredKey()` tombstones on all three (and the absorbed |
| 79 | +`ttl`), `RETIRED_KEYS_BY_MAJOR[18]` entries for each, the D3 semantic entry |
| 80 | +above (the #14478 entry's outer half is re-worded from a rename to a deletion), |
| 81 | +negative pins asserting each prescription and a positive pin asserting the |
| 82 | +parse output no longer materializes the retired defaults, the published |
| 83 | +reference pages regenerated, and the hand-written docs page and this package's |
| 84 | +README (`@objectstack/metadata` ships `README.md`, hence its `patch`) no longer |
| 85 | +authoring `cache.enabled`. |
0 commit comments