Commit 146c291
feat(spec)!: retire the
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>scheduled cache-warmup strategy — the cron it selected left in this same major (ADR-0049) (#17638)1 parent ea1da64 commit 146c291
7 files changed
Lines changed: 280 additions & 20 deletions
File tree
- .changeset
- content/docs/references/system
- packages/spec/src
- migrations
- entries/semantic
- system
Lines changed: 80 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
197 | 197 | | |
198 | 198 | | |
199 | 199 | | |
200 | | - | |
| 200 | + | |
201 | 201 | | |
202 | 202 | | |
203 | 203 | | |
| |||
220 | 220 | | |
221 | 221 | | |
222 | 222 | | |
223 | | - | |
| 223 | + | |
224 | 224 | | |
225 | 225 | | |
226 | 226 | | |
| |||
260 | 260 | | |
261 | 261 | | |
262 | 262 | | |
263 | | - | |
| 263 | + | |
264 | 264 | | |
265 | 265 | | |
266 | 266 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
83 | | - | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
84 | 88 | | |
85 | 89 | | |
86 | 90 | | |
| |||
Lines changed: 63 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6021 | 6021 | | |
6022 | 6022 | | |
6023 | 6023 | | |
| 6024 | + | |
| 6025 | + | |
| 6026 | + | |
| 6027 | + | |
| 6028 | + | |
| 6029 | + | |
| 6030 | + | |
| 6031 | + | |
| 6032 | + | |
| 6033 | + | |
| 6034 | + | |
| 6035 | + | |
| 6036 | + | |
| 6037 | + | |
| 6038 | + | |
| 6039 | + | |
| 6040 | + | |
| 6041 | + | |
| 6042 | + | |
| 6043 | + | |
| 6044 | + | |
| 6045 | + | |
| 6046 | + | |
| 6047 | + | |
| 6048 | + | |
| 6049 | + | |
| 6050 | + | |
| 6051 | + | |
| 6052 | + | |
| 6053 | + | |
| 6054 | + | |
| 6055 | + | |
| 6056 | + | |
| 6057 | + | |
| 6058 | + | |
| 6059 | + | |
| 6060 | + | |
| 6061 | + | |
| 6062 | + | |
| 6063 | + | |
| 6064 | + | |
| 6065 | + | |
| 6066 | + | |
| 6067 | + | |
| 6068 | + | |
| 6069 | + | |
| 6070 | + | |
| 6071 | + | |
| 6072 | + | |
| 6073 | + | |
| 6074 | + | |
| 6075 | + | |
| 6076 | + | |
| 6077 | + | |
| 6078 | + | |
| 6079 | + | |
| 6080 | + | |
| 6081 | + | |
| 6082 | + | |
6024 | 6083 | | |
6025 | 6084 | | |
6026 | 6085 | | |
| |||
0 commit comments