Skip to content

feat(spec)!: retire the scheduled cache-warmup strategy — the cron it selected left in this same major (ADR-0049) - #17638

Draft
os-bill wants to merge 3 commits into
mainfrom
claude/issue-17157-cache-warmup-scheduled-retire
Draft

feat(spec)!: retire the scheduled cache-warmup strategy — the cron it selected left in this same major (ADR-0049)#17638
os-bill wants to merge 3 commits into
mainfrom
claude/issue-17157-cache-warmup-scheduled-retire

Conversation

@os-bill

@os-bill os-bill commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

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 emptyauthorable-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 = 6a5ab591773b4d0df382c7a3479f9b8d1c1dada4

########## 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 690f083f83) ##########
  occurrences of the retired member in the enum line: 1     ** mutation proven ON DISK
  occurrences of the injected prescription const:    0
  blob now = 813cf7828c9f4584c42d41da43a5675915e79933       ** 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 = 6a5ab591773b4d0df382c7a3479f9b8d1c1dada4  ** 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 minorcheck-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.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH


Generated by Claude Code

`CacheWarmup.strategy` no longer accepts `'scheduled'`, and its `.describe()`
stops promising "(cron)".

#16320 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. ADR-0049 enforce-or-remove.

An enum-VALUE narrowing is invisible to all four surface ratchets, so the
prescription hangs on the enum's own `error` map dispatched by `issue.input` —
the established route (`crypto.hash`, `managedBy: 'system'`,
`HotReloadConfig.stateStrategy`) — and the ADR-0087 D3 semantic entry
`cache-warmup-scheduled-strategy-retired` is the declaration. No D2 conversion
and no `RETIRED_KEYS_BY_MAJOR` entry: no authorable key changed, and `CacheWarmup`
is bound to no metadata type and embedded in no stack collection, so there is no
authored source and no stored row to rewrite.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH
…up enum

`gen:docs` — the only one of the 15 generated artifacts `check:generated`
proved stale. The four surface ratchets are byte-identical, as an enum-VALUE
narrowing predicts.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH
…up prescription

`check:doc-authoring` Rule 3: a refusal message is printed verbatim at an author
who has no tracker to resolve `#NNNN` with. The id moves to the adjacent `//`
comment; the string keeps ADR-0049 as its durable reference.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation protocol:system tests tooling labels Sep 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

3 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • 4 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 100 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 135 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8f751cdc5652afb7dcd8e906d0f281234fc886c3packageMentionDocs.

Which tree this was computed on

This run read content/docs from 8e4c4501d008fb9d665ce57cebb8775be4f1dbc7 — the merge of head c1708532137a8de0fdfb47b8500a3156dbeec48d into base 8f751cdc5652afb7dcd8e906d0f281234fc886c3, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 8e4c4501d008fb9d665ce57cebb8775be4f1dbc7 && git checkout 8e4c4501d008fb9d665ce57cebb8775be4f1dbc7
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8f751cdc5652afb7dcd8e906d0f281234fc886c3 c1708532137a8de0fdfb47b8500a3156dbeec48d && git checkout -B drift-repro 8f751cdc5652afb7dcd8e906d0f281234fc886c3 && git merge --no-ff c1708532137a8de0fdfb47b8500a3156dbeec48d

node scripts/docs-audit/affected-docs.mjs --json 8f751cdc5652afb7dcd8e906d0f281234fc886c3

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:system size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants