Skip to content

Commit 146c291

Browse files
os-billclaude
andauthored
feat(spec)!: retire the scheduled cache-warmup strategy — the cron it selected left in this same major (ADR-0049) (#17638)
Part of #17157 `CacheWarmup.strategy` no longer accepts `'scheduled'`, and its `.describe()` stops promising `(cron)`. #16320 (PR #17146) deleted `CacheWarmup.schedule` — the cron key this enum member selected — and declined the member itself as *"a value, not a position this ruling names"*. That is a statement about that ruling's **scope**, not a finding that the value was sound. After the deletion the member declared a warmup cadence with **no key left to configure it and no engine that has ever run one**, while its own `.describe()` still promised `(cron)`. ADR-0049 enforce-or-remove. ## The four prerequisite readings, re-measured on `origin/main` at `690f083f83` — one is FALSIFIED | # | claim | reading on `main` | verdict | |:--|:--|:--|:--| | 1 | the enum + describe still stand at `cache.zod.ts:199-200` | they stand, at **`:179-180`** — the card's numbers were taken on PR #17146's branch | ✅ (line numbers moved) | | 2 | `CacheWarmupSchema` has zero consumers outside its declaring file | **zero runtime consumers**, 6 non-runtime files — see below | ✅ | | 3 | #16320 landed; `CacheWarmup.schedule` is gone from `main` | gone; only the tombstone comment remains in the shape | ✅ | | 4 | the D3 ledger entry `cache-warmup-schedule-retired` exists and says what the card quotes | **no such entry exists** — see below | ❌ **falsified** | **#4 in full.** `git grep -rn "cache-warmup-schedule-retired"` on `main` returns **exactly one** hit: `packages/spec/src/cron-typed-positions-retirement.test.ts:212`, inside `NEVER_REGISTERED_IDS` — a list of ids that pin test **asserts ABSENT**. #16320 landed as a bare deletion (`直接删`, maintainer ruling 2026-09-10) with *no* `RETIRED_KEYS_BY_MAJOR` entry, *no* D2 conversion and *no* D3 semantic entry. The statements the card quotes are real, but they live in the **tombstone comment** in `cache.zod.ts` and in the ADR-0058 D7 ledger comment in `packages/qa/dogfood` — not in a D3 ledger entry. The card's argument survives intact; only its citation was wrong. **#2 with its lit control reproduced** (the card's zeros were all taken beside one, so the control is re-measured too): ``` $ git grep -l -P '\bCacheWarmupSchema\b' -- . ':!packages/spec/src/system/cache.zod.ts' \ ':!packages/spec/api-surface/**' ':!packages/spec/authorable-surface/**' | wc -l 6 ``` …and all six are non-runtime: the generated reference page's import line, `declaration-map/system.json`, `export-origins/system.json`, the ADR-0058 D7 ledger comment in `packages/qa/dogfood`, the #16320 pin test, and this package's own `system/cache.test.ts`. **Zero runtime readers.** ``` $ git grep -l -P '\bConnectorSchema\b' -- . ':!…surfaces…' | grep -v connector.zod.ts | wc -l 46 # lit control — the sweep sees consumers when there are any ``` (The card measured 48 for the control on #17146's branch; 46 on `main`. It is emphatically lit either way.) `CacheWarmup` is also bound to **no** metadata type and embedded in **no** stack collection: `git grep -n 'DistributedCacheConfigSchema|CacheWarmupSchema' -- packages/spec/src/stack.zod.ts packages/spec/src/kernel/` exits **1**. So there is no authored source and no stored row anywhere that has ever carried this value, and `os migrate meta` has nothing to list. ## The retirement mechanism — established, not invented The card is right that there is **no value-level analogue of `retiredKey()`**, and none is invented here. The repo's established mechanism for an enum-VALUE retirement is the **enum's own `error` map, dispatched on `issue.input`** — three precedents on this tree: | precedent | site | |:--|:--| | `object.managedBy: 'system'` | `data/object.zod.ts` (`MANAGED_BY_SYSTEM_RETIRED`) | | `HookBodyCapability` `'crypto.hash'` (#4391) | `data/hook-body.zod.ts` (`CRYPTO_HASH_RETIRED`) | | `HotReloadConfig.stateStrategy` `'disk'` / `'distributed'` | D3 entry `hot-reload-inert-state-strategies-retired` | `.claude/skills/spec-property-retirement` §2 names it outright as the only route that applies when the def survives and only its value set shrinks. Only the value that **used to be legal** gets the "was removed" sentence; `strategy: 'sheduled'` keeps zod's own enum message. Registration follows the same precedents: an **ADR-0087 D3 semantic entry** (`cache-warmup-scheduled-strategy-retired`), *not* a D2 conversion (no source to rewrite) and *nothing* in `RETIRED_KEYS_BY_MAJOR` (no authorable key changed). The prescription deliberately carries **no `os migrate meta` sentence** — promising a listing the tool cannot produce would be the very defect this card is about; the house pin (`retired-key-migrate-sentence.test.ts`) judges only prescriptions that name the command. ## ⭐ The instrument — the negative leg, both legs quoted **An enum-value narrowing is invisible to all four ratchets**, and this branch confirms it by measurement, not by argument: after `pnpm --filter @objectstack/spec build`, `git status --porcelain` was **empty** — `authorable-surface/system.json` still carries `system/CacheWarmup:strategy` byte-for-byte (it keys on the *position*, which is untouched), and `api-surface/`, `json-schema.manifest/` and the D7 ledger likewise. **A green CI run is therefore not evidence this retirement works.** The pin tests in `system/cache.test.ts` are the only instrument, so both legs are shown. Resolution path: `cache.test.ts` imports `./cache.zod` — the **source**, not `dist/` — so no build interposes between the mutation and the reading. ``` HEAD blob = 6a5ab59 ########## AFTER LEG (retirement in place, HEAD) ########## AFTER EXIT=0 Test Files 1 passed (1) Tests 36 passed (36) ########## BEFORE LEG (schema reverted to origin/main 690f083) ########## occurrences of the retired member in the enum line: 1 ** mutation proven ON DISK occurrences of the injected prescription const: 0 blob now = 813cf78 ** differs from the HEAD blob BEFORE EXIT=1 FAIL |local| src/system/cache.test.ts > CacheWarmupSchema > refuses `strategy: 'scheduled'` and answers with the retirement prescription AssertionError: expected [Function] to throw an error Test Files 1 failed (1) Tests 1 failed | 35 passed (36) ########## RESTORE ########## blob restored = 6a5ab59 ** identical to the HEAD blob git diff HEAD (must be empty): [end] ``` **Before: accepted. After: refused.** The mutation is proved on disk by blob hash *and* by a grep anchored on the exact text that moved (an editor's exit code is not evidence); the restore is proved by `git diff HEAD` being empty, not by an exit code; and the script carried `trap … EXIT INT TERM` throughout. The two neighbouring assertions pass in **both** legs, deliberately — they are controls, not the instrument: a typo (`'sheduled'`) must **not** be told it "was removed" (or the error map matches everything and the pin above proves nothing), and `'eager'` / `'lazy'` / the `'lazy'` default must still parse. ## Changeset level `minor`, on `@objectstack/spec`. Removing a published enum member **is breaking**; under the launch-window rule it ships as `minor` — `check-changeset-no-major.mjs` refuses `major`, and breaking-ness is carried by the **BREAKING** banner plus the ADR-0087 disposition (an `adr-0087: registered cache-warmup-scheduled-strategy-retired` marker in the changeset body). The level is **committed**, so the gate — which reads via `git show HEAD:PATH` — sees it. `node scripts/check-changeset-no-major.mjs --base origin/main` and `node scripts/check-adr-0087-registration.mjs --base origin/main` both exit 0 on this branch. ## Verification — all readings at `c170853213`, the final commit | run | verdict | |:--|:--| | `pnpm --filter @objectstack/spec build && … typecheck && … test` (under the shared verify lock) | `VERDICT command-exit 0`; **473 test files, 13428 tests passed** | | `pnpm --filter @objectstack/spec check:generated` | 15/15 green. One was stale on the first pass — `check:docs` — regenerated with `gen:docs` (the reference page's enum cell); `check:authorable-surface`, `check:api-surface`, `check:spec-changes`, `check:upgrade-guide` were green **without** regeneration, which is the ratchet-invisibility result above | | `pnpm lint` (repo-wide, `eslint . --no-inline-config`) | exit 0 — no narrowing claimed, the full scan ran | | `node scripts/pm/dispatch-gates.mjs --ran` | **108 derived, 108 run, 0 UNRUN** | Of the 108, **7 returned `PREREQUISITE NOT MET` (exit 3, or exit 1 with an explicit "nothing was measured" verdict) and are recorded as NOT MEASURED, never as green**: `check:doc-formula-expressions`, `check:doc-security-posture`, `check:skill-examples`, `check:docs-transcript-drift`, `check:dual-build-cjs-loads`, `check:lean-entry-closure`, `check:type-check-debt`. Every one refuses for the same reason — it reads **built sibling packages** that this worktree has not built — and none reads a file this diff touches. CI builds the farm and decides them. **One gate found a real defect in this branch and is fixed in `c170853213`:** `check:doc-authoring` Rule 3 flagged `#16320` inside the customer-facing prescription string. A refusal message is printed verbatim at an author who has no tracker to resolve `#NNNN` with, so the id moved to the adjacent `//` comment and the string keeps **ADR-0049** as its durable reference. Gate now green. ## Sibling repo `git grep 'CacheWarmup' ../objectui` → no hits. The Console Pin Gate is not in play. ## Not in scope The larger family question — whether `CacheWarmup` / `DistributedCacheConfig.warmup` should exist at all — is the ADR-0049 family-level decision the card names and is deliberately untouched here. `Part of #17157` rather than `Fixes`, since this closes the enum member and not that question. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH --- _Generated by [Claude Code](https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent ea1da64 commit 146c291

7 files changed

Lines changed: 280 additions & 20 deletions

File tree

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
"@objectstack/spec": minor
3+
---
4+
5+
feat(spec)!: retire the `scheduled` cache-warmup strategy — the cron it selected left in this same major, and nothing ever warmed on a cadence (ADR-0049)
6+
7+
<!-- adr-0087: registered cache-warmup-scheduled-strategy-retired -->
8+
9+
**BREAKING** in the accept-set sense, landing in the launch window as `minor` (the
10+
lockstep convention: `major` is refused by `check-changeset-no-major`, and breaking-ness
11+
is carried by this banner plus the ADR-0087 disposition above).
12+
13+
`CacheWarmup.strategy` no longer accepts `'scheduled'`.
14+
15+
| | before | after |
16+
|:--|:--|:--|
17+
| accept set | `'eager' \| 'lazy' \| 'scheduled'` | `'eager' \| 'lazy'` |
18+
| describe | `… lazy (on first access), scheduled (cron)` | `… lazy (on first access)` |
19+
| a document writing it | parsed green | **refused**, with the prescription |
20+
21+
**The one-line fix:** write `strategy: 'eager'` (warm at startup) or `strategy: 'lazy'`
22+
(warm on first access). For a warmup on a **cadence**, declare a `job` — that is the one
23+
cron slot this platform evaluates:
24+
25+
```ts
26+
defineStack({
27+
jobs: [{ name: 'warm_config_cache', schedule: { expression: '0 * * * *' }, handler: 'warmConfigCache' }],
28+
});
29+
```
30+
31+
## Why
32+
33+
`cron-typed-positions-retired` (17.x → 18, #16320) deleted `CacheWarmup.schedule`, the
34+
cron key this enum member selected, and left the member standing on the reading that it is
35+
"a value, not a position the ruling names". That was a statement about that ruling's
36+
**scope**, not a finding that the value was sound. After the deletion the member declared a
37+
warmup cadence with **no key left to configure it and no engine that has ever run one**,
38+
while its own `.describe()` still promised `(cron)` — ADR-0049 declared-not-enforced, in
39+
the form Prime Directive 10 names outright: a capability advertised that the runtime does
40+
not deliver.
41+
42+
Nothing on the platform reads `CacheWarmupSchema`: outside its declaring file it resolves
43+
to the generated reference page's import line, the `declaration-map` / `export-origins`
44+
catalogues, the ADR-0058 D7 ledger comment and two of this package's own test files — zero
45+
runtime consumers, measured beside a lit control (`ConnectorSchema`, 46 files, same sweep).
46+
So **no runtime behaviour changes**: no warmup has ever run on a schedule, before or after.
47+
What changes is that the contract stops promising it.
48+
49+
## The retirement kit
50+
51+
- the member leaves `z.enum(['eager','lazy','scheduled'])` and the `.describe()` stops
52+
saying `(cron)` (`system/cache.zod.ts`)
53+
- the prescription hangs on **the enum's own `error` map, dispatched by `issue.input`** —
54+
the established route for an enum-VALUE retirement (`crypto.hash` on
55+
`HookBodyCapability`, `object.managedBy: 'system'`, `HotReloadConfig.stateStrategy`).
56+
There is no value-level analogue of `retiredKey()` and none is invented here. Only the
57+
value that **used to be legal** gets the "was removed" sentence; `strategy: 'sheduled'`
58+
keeps zod's own enum message, which already lists the legal values
59+
- an **ADR-0087 D3 semantic entry**, `cache-warmup-scheduled-strategy-retired` — a semantic
60+
entry rather than a D2 conversion because there is **no source to rewrite**: `CacheWarmup`
61+
is bound to no metadata type and embedded in no stack collection, so no authored document
62+
and no stored row has ever carried this value, and `os migrate meta` has nothing to list.
63+
That is also why the prescription carries **no `os migrate meta` sentence** — it would
64+
promise a listing the tool cannot produce, which is the very defect this card is about
65+
- **nothing in `RETIRED_KEYS_BY_MAJOR`** — no authorable *key* changed — and **no
66+
`retiredKey()` tombstone**, which tombstones keys, not values
67+
- pin tests (`system/cache.test.ts`): the refusal and its prescription, a **lit control**
68+
that a typo is *not* told it "was removed", and that the surviving members and the
69+
`'lazy'` default still parse. `cron-typed-positions-retirement.test.ts`'s warmup fixture
70+
moves to `'eager'`, since a fixture must be well-formed under the current schema
71+
72+
## ⚠️ The four surface ratchets are byte-identical across this change, and that is correct
73+
74+
An enum-VALUE narrowing moves no position, no exported name and no expression-typed slot:
75+
`authorable-surface/` keys on **positions** (`system/CacheWarmup:strategy` stays — the key
76+
is untouched), the ADR-0058 D7 ledger on **expression-typed slots**, and `api-surface/` /
77+
`json-schema.manifest/` on **names**. None of them reads a def's *value set*, so none of
78+
them can fail on this change — the `crypto.hash` precedent measured exactly this. The pin
79+
tests above are therefore not a formality: they are the only instrument this retirement
80+
has, and a green CI run on its own says nothing about whether the value is gone.

‎content/docs/references/system/cache.mdx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ Cache warmup strategy
197197
| Property | Type | Required | Description |
198198
| :--- | :--- | :--- | :--- |
199199
| **enabled** | `boolean` | optional (default: `false`) | Enable cache warmup |
200-
| **strategy** | `Enum<'eager' \| 'lazy' \| 'scheduled'>` | optional (default: `"lazy"`) | Warmup strategy: eager (at startup), lazy (on first access), scheduled (cron) |
200+
| **strategy** | `Enum<'eager' \| 'lazy'>` | optional (default: `"lazy"`) | Warmup strategy: eager (at startup), lazy (on first access) |
201201
| **patterns** | `string[]` | optional | Key patterns to warm up (e.g., "user:*", "config:*") |
202202
| **concurrency** | `number` | optional (default: `10`) | Maximum concurrent warmup operations |
203203

@@ -220,7 +220,7 @@ Distributed cache configuration with consistency and avalanche prevention
220220
| **encryption** | `boolean` | optional (default: `false`) | Enable encryption for cached data |
221221
| **consistency** | `Enum<'write_through' \| 'write_behind' \| 'write_around' \| 'refresh_ahead'>` | optional | Distributed cache consistency strategy |
222222
| **avalanchePrevention** | `{ jitterTtl?: object; circuitBreaker?: object; lockout?: object }` | optional | Cache avalanche and stampede prevention |
223-
| **warmup** | `{ enabled: boolean; strategy: Enum<'eager' \| 'lazy' \| 'scheduled'>; patterns?: string[]; concurrency: number }` | optional | Cache warmup strategy |
223+
| **warmup** | `{ enabled: boolean; strategy: Enum<'eager' \| 'lazy'>; patterns?: string[]; concurrency: number }` | optional | Cache warmup strategy |
224224

225225
### Nested Shape: `DistributedCacheConfig.tiers[number]`
226226

@@ -260,7 +260,7 @@ Rule defining when and how cached entries are invalidated
260260
| Property | Type | Required | Description |
261261
| :--- | :--- | :--- | :--- |
262262
| **enabled** | `boolean` | optional (default: `false`) | Enable cache warmup |
263-
| **strategy** | `Enum<'eager' \| 'lazy' \| 'scheduled'>` | optional (default: `"lazy"`) | Warmup strategy: eager (at startup), lazy (on first access), scheduled (cron) |
263+
| **strategy** | `Enum<'eager' \| 'lazy'>` | optional (default: `"lazy"`) | Warmup strategy: eager (at startup), lazy (on first access) |
264264
| **patterns** | `string[]` | optional | Key patterns to warm up (e.g., "user:*", "config:*") |
265265
| **concurrency** | `number` | optional (default: `10`) | Maximum concurrent warmup operations |
266266

‎packages/spec/src/cron-typed-positions-retirement.test.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,11 @@ const EXPORT_WELL_FORMED = {
8080
const STATE_WELL_FORMED = { id: 'sched_001', flowName: 'daily_report', createdAt: '2026-01-01T00:00:00Z' };
8181
const SYNC_WELL_FORMED = { strategy: 'incremental' as const, direction: 'bidirectional' as const, batchSize: 500 };
8282
const CONNECTOR_WELL_FORMED = { name: 'sap_erp', label: 'SAP ERP', type: 'saas' as const, syncConfig: SYNC_WELL_FORMED };
83-
const WARMUP_WELL_FORMED = { enabled: true, strategy: 'scheduled' as const, patterns: ['config:*'] };
83+
// [#17157] was `strategy: 'scheduled'` — that enum member was itself retired one card
84+
// later, in this same major, precisely because the cron key stripped below was its
85+
// only referent. A fixture must be well-formed under the CURRENT schema, so it now
86+
// carries `eager`; what this file pins is the absence of `schedule`, unchanged.
87+
const WARMUP_WELL_FORMED = { enabled: true, strategy: 'eager' as const, patterns: ['config:*'] };
8488
const CACHE_WELL_FORMED = {
8589
enabled: true,
8690
tiers: [{ name: 'l1', type: 'memory' as const }],
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
import type { SemanticMigration } from '../../types.js';
4+
5+
export const entry: SemanticMigration = {
6+
id: 'cache-warmup-scheduled-strategy-retired',
7+
// No backticks in `surface` — build-upgrade-guide.ts renders it inside a code
8+
// span AND a table cell.
9+
surface:
10+
"CacheWarmup.strategy — the value 'scheduled' left the warmup-strategy enum "
11+
+ '(packages/spec/src/system/cache.zod.ts), and the enum describe stopped promising '
12+
+ '"scheduled (cron)". The key itself, DistributedCacheConfig.warmup.strategy, is '
13+
+ 'unchanged and still authorable',
14+
replacement:
15+
"'eager' to warm at startup or 'lazy' to warm on first access — the two strategies "
16+
+ 'the vocabulary ever described without pointing outside itself. There is no '
17+
+ 'replacement for the cadence: a warmup on a schedule is a job. Declare a `job` with '
18+
+ 'schedule.expression (system/job.zod.ts) whose handler does the warming — that is '
19+
+ 'the one cron slot this platform evaluates, and it is the slot #16320 deliberately '
20+
+ 'kept when it deleted the other seven',
21+
reason:
22+
'ADR-0049 enforce-or-remove, closing the residue #16320 left inside the schema it had '
23+
+ 'just edited. That card deleted CacheWarmup.schedule — the cron key this enum member '
24+
+ 'selected — and declined the member itself on the reading that it is "a value, not a '
25+
+ "position this ruling names\". That is a statement about the ruling's SCOPE, not a "
26+
+ 'finding that the value was sound: after the deletion the member declared a warmup '
27+
+ 'cadence with no key left to configure it, no engine that has ever run one, and a '
28+
+ '.describe() still promising "(cron)" — ADR-0049 declared-not-enforced in the form '
29+
+ 'Prime Directive 10 names outright, a capability advertised that the runtime does '
30+
+ 'not deliver. Re-measured on main at 690f083f83 with a lit control rather than '
31+
+ 'inherited from the card: CacheWarmupSchema has zero runtime consumers outside its '
32+
+ 'declaring file (six files reference it — the generated reference page import, the '
33+
+ 'declaration-map and export-origins catalogues, the ADR-0058 D7 ledger comment and '
34+
+ 'two spec test files — while the control, ConnectorSchema, resolves to 46 files), '
35+
+ 'and no cache-warmup engine exists anywhere on the platform. Bookkeeping follows the '
36+
+ "hot-reload-inert-state-strategies-retired and crypto.hash precedents: an enum-VALUE "
37+
+ 'narrowing puts nothing in RETIRED_KEYS_BY_MAJOR (no authorable KEY changed) and '
38+
+ 'leaves the four surface ratchets byte-identical (no def changed, and they key on '
39+
+ "positions and names, never on a def's value set), so the prescription hangs on the "
40+
+ "enum's own error map dispatched by issue.input — telling the author of a TYPO that "
41+
+ 'their value "was removed" would misinform. It is a SEMANTIC entry rather than a D2 '
42+
+ 'conversion because there is no source to rewrite: CacheWarmup is bound to no '
43+
+ 'metadata type and embedded in no stack collection, so no authored document and no '
44+
+ 'stored row has ever carried this value, and os migrate meta has nothing to list. '
45+
+ 'Route 3 of the retirement playbook, the #4834 / #11825 shape: this entry IS the '
46+
+ 'declaration. ADR-0049, ADR-0087, #17157, #16320.',
47+
acceptanceCriteria:
48+
"No configuration passes strategy: 'scheduled' to CacheWarmupSchema or to "
49+
+ 'DistributedCacheConfigSchema.warmup. TypeScript callers cannot: '
50+
+ "CacheWarmup['strategy'] is now 'eager' | 'lazy', so the literal is a compile error "
51+
+ 'at the authoring site. Callers that arrive as JSON get a parse REFUSAL — not the '
52+
+ 'silent strip #16320 left for the schedule key beside it, because a narrowed enum '
53+
+ 'rejects rather than drops — carrying the prescription, which names the job route. '
54+
+ 'Concretely, check two places. (1) Any host or deployment config embedding a '
55+
+ 'DistributedCacheConfig: a warmup block selecting the retired strategy now fails to '
56+
+ 'parse where it previously parsed green; change it to eager or lazy. (2) Anything '
57+
+ 'that was waiting on the cadence to take effect: it never did. No warmup has ever '
58+
+ 'run on a schedule on this platform, so migrating the value changes no runtime '
59+
+ 'behaviour whatsoever — what changes is that the contract stops promising it. If a '
60+
+ 'scheduled warmup is genuinely wanted, it comes back through the ENFORCE leg of '
61+
+ 'ADR-0049: the engine first, the declaration with it, never as a bare enum row '
62+
+ 'again.',
63+
};

‎packages/spec/src/migrations/registry.ts‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6021,6 +6021,65 @@ const step18: MigrationStep = {
60216021
+ 'value, so no source rewrite ships and `objectstack migrate meta` has '
60226022
+ 'nothing to visit.',
60236023
},
6024+
{
6025+
id: 'cache-warmup-scheduled-strategy-retired',
6026+
// No backticks in `surface` — build-upgrade-guide.ts renders it inside a code
6027+
// span AND a table cell.
6028+
surface:
6029+
"CacheWarmup.strategy — the value 'scheduled' left the warmup-strategy enum "
6030+
+ '(packages/spec/src/system/cache.zod.ts), and the enum describe stopped promising '
6031+
+ '"scheduled (cron)". The key itself, DistributedCacheConfig.warmup.strategy, is '
6032+
+ 'unchanged and still authorable',
6033+
replacement:
6034+
"'eager' to warm at startup or 'lazy' to warm on first access — the two strategies "
6035+
+ 'the vocabulary ever described without pointing outside itself. There is no '
6036+
+ 'replacement for the cadence: a warmup on a schedule is a job. Declare a `job` with '
6037+
+ 'schedule.expression (system/job.zod.ts) whose handler does the warming — that is '
6038+
+ 'the one cron slot this platform evaluates, and it is the slot #16320 deliberately '
6039+
+ 'kept when it deleted the other seven',
6040+
reason:
6041+
'ADR-0049 enforce-or-remove, closing the residue #16320 left inside the schema it had '
6042+
+ 'just edited. That card deleted CacheWarmup.schedule — the cron key this enum member '
6043+
+ 'selected — and declined the member itself on the reading that it is "a value, not a '
6044+
+ "position this ruling names\". That is a statement about the ruling's SCOPE, not a "
6045+
+ 'finding that the value was sound: after the deletion the member declared a warmup '
6046+
+ 'cadence with no key left to configure it, no engine that has ever run one, and a '
6047+
+ '.describe() still promising "(cron)" — ADR-0049 declared-not-enforced in the form '
6048+
+ 'Prime Directive 10 names outright, a capability advertised that the runtime does '
6049+
+ 'not deliver. Re-measured on main at 690f083f83 with a lit control rather than '
6050+
+ 'inherited from the card: CacheWarmupSchema has zero runtime consumers outside its '
6051+
+ 'declaring file (six files reference it — the generated reference page import, the '
6052+
+ 'declaration-map and export-origins catalogues, the ADR-0058 D7 ledger comment and '
6053+
+ 'two spec test files — while the control, ConnectorSchema, resolves to 46 files), '
6054+
+ 'and no cache-warmup engine exists anywhere on the platform. Bookkeeping follows the '
6055+
+ "hot-reload-inert-state-strategies-retired and crypto.hash precedents: an enum-VALUE "
6056+
+ 'narrowing puts nothing in RETIRED_KEYS_BY_MAJOR (no authorable KEY changed) and '
6057+
+ 'leaves the four surface ratchets byte-identical (no def changed, and they key on '
6058+
+ "positions and names, never on a def's value set), so the prescription hangs on the "
6059+
+ "enum's own error map dispatched by issue.input — telling the author of a TYPO that "
6060+
+ 'their value "was removed" would misinform. It is a SEMANTIC entry rather than a D2 '
6061+
+ 'conversion because there is no source to rewrite: CacheWarmup is bound to no '
6062+
+ 'metadata type and embedded in no stack collection, so no authored document and no '
6063+
+ 'stored row has ever carried this value, and os migrate meta has nothing to list. '
6064+
+ 'Route 3 of the retirement playbook, the #4834 / #11825 shape: this entry IS the '
6065+
+ 'declaration. ADR-0049, ADR-0087, #17157, #16320.',
6066+
acceptanceCriteria:
6067+
"No configuration passes strategy: 'scheduled' to CacheWarmupSchema or to "
6068+
+ 'DistributedCacheConfigSchema.warmup. TypeScript callers cannot: '
6069+
+ "CacheWarmup['strategy'] is now 'eager' | 'lazy', so the literal is a compile error "
6070+
+ 'at the authoring site. Callers that arrive as JSON get a parse REFUSAL — not the '
6071+
+ 'silent strip #16320 left for the schedule key beside it, because a narrowed enum '
6072+
+ 'rejects rather than drops — carrying the prescription, which names the job route. '
6073+
+ 'Concretely, check two places. (1) Any host or deployment config embedding a '
6074+
+ 'DistributedCacheConfig: a warmup block selecting the retired strategy now fails to '
6075+
+ 'parse where it previously parsed green; change it to eager or lazy. (2) Anything '
6076+
+ 'that was waiting on the cadence to take effect: it never did. No warmup has ever '
6077+
+ 'run on a schedule on this platform, so migrating the value changes no runtime '
6078+
+ 'behaviour whatsoever — what changes is that the contract stops promising it. If a '
6079+
+ 'scheduled warmup is genuinely wanted, it comes back through the ENFORCE leg of '
6080+
+ 'ADR-0049: the engine first, the declaration with it, never as a bare enum row '
6081+
+ 'again.',
6082+
},
60246083
{
60256084
id: 'cbp-master-detail-required-forced',
60266085
surface: 'object.fields.<master>.required on a `master_detail` reference under '

0 commit comments

Comments
 (0)