Skip to content

Commit dcf3eb4

Browse files
test(spec): the second api/ file group's test titles state each cited decision in words instead of a tracker number (stage 25) (#21975)
Part of #20749 Clause-②: no Stage 25 of this card: the next area of class (e), the test strings shipped under `packages/spec/src`, as ruled in `5902360492` on #20513. This stage takes the second and last name-ordered `api/` group: the 13 id-bearing test files directly under `packages/spec/src/api/` from `plugin-rest-api.handler-status-retirement.test.ts` to `zod-issues-to-fields.test.ts`. Those files carried 89 messages and 95 tracker ids, citing 43 records. All 95 now either state what their record decided, in words (form D), or are dropped where the title already says it. No needle sits in this group. Text only: no assertion, identifier, test count or code comment changes, and no file is renamed. With this stage, `api/` carries no tracker id in a test string. ## Census at the base (`5a22eb5619`) Instruments: `census10.cjs` (md5 `9d08602ab972b4b8643c90d64d40fa41`), `census.cjs` (md5 `6e42a45a926d375013c32d62f16a296e`), `census-wide.cjs` (md5 `c98410a19529c439adb0afbfb00026a2`) and `dirtable.cjs` (md5 `dda605c54745b4a60cc14c9a686e4eff`), byte-identical to the copies stages 10 to 24 used. A literal counts as a test title when its folded message is argument 0 of a `describe` / `it` / `test` call, `.each` / `.skip` / `.only` chains included. Everything else is an "other" string. The worktree was cut from `origin/main` at `5a22eb5619`, the claim's base and stage 24's landing. Both instruments read **371 messages / 392 ids in 84 files**, the seat's reading and stage 24's head reading. | directory | files | messages / ids | titles | other | |:--|--:|--:|--:|--:| | `system/` | 34 | 154 / 167 | 128 / 138 | 26 / 29 | | (files directly in `src/`) | 30 | 118 / 120 | 117 / 119 | 1 / 1 | | `api/` (this PR: all 13 files) | 13 | 89 / 95 | 86 / 92 | 3 / 3 | | `ui/` | 5 | 7 / 7 | 0 | 7 / 7 | | `ai/` | 1 | 2 / 2 | 0 | 2 / 2 | | `contracts/` | 1 | 1 / 1 | 0 | 1 / 1 | | **total** | **84** | **371 / 392** | **331 / 349** | **40 / 43** | The group reads **89 messages / 95 ids in 13 files**, the seat's figures file for file: | file (under `api/`) | messages / ids | titles | other | |:--|--:|--:|--:| | `plugin-rest-api.handler-status-retirement.test.ts` | 4 / 4 | 3 / 3 | 1 / 1 | | `plugin-rest-api.schema-refs.test.ts` | 2 / 2 | 2 / 2 | 0 | | `plugin-rest-api.test.ts` | 2 / 2 | 2 / 2 | 0 | | `protocol.test.ts` | 46 / 50 | 46 / 50 | 0 | | `registry-retirement.test.ts` | 2 / 2 | 1 / 1 | 1 / 1 | | `rest-api-config-dead-keys-retirement.test.ts` | 2 / 2 | 2 / 2 | 0 | | `rest-server.test.ts` | 19 / 19 | 18 / 18 | 1 / 1 | | `router.test.ts` | 1 / 1 | 1 / 1 | 0 | | `sortability.test.ts` | 3 / 4 | 3 / 4 | 0 | | `storage.test.ts` | 2 / 2 | 2 / 2 | 0 | | `validate-data.test.ts` | 3 / 3 | 3 / 3 | 0 | | `websocket.test.ts` | 1 / 1 | 1 / 1 | 0 | | `zod-issues-to-fields.test.ts` | 2 / 3 | 2 / 3 | 0 | | **13 files** | **89 / 95** | **86 / 92** | **3 / 3** | Five more test files sit in the same name range and carry no id (`query-adapter.test.ts`, `realtime-shared.test.ts`, `realtime.test.ts`, `retired-error-codes.test.ts`, `versioning.test.ts`). The three "other" strings are expect failure messages, rewritten and declared to the text-only tool: `plugin-rest-api.handler-status-retirement.test.ts:179` and `rest-server.test.ts:768` (template literals) and `registry-retirement.test.ts:89` (one leaf of a `+` chain). - **Controls.** Lit: `ui/notification.test.ts` (1 id) and `system/book.test.ts` (2 ids), outside the group, read the same at the base and at the head. Dark: `protocol.test.ts` reads 0 at the head while 65 of its lines still carry a number, every one of them a comment. Planted in a scratch tree: an id put into a `storage.test.ts` title reads 1 / 1 (`title:it`), and an id put into a `sortability.test.ts` comment reads 0. - **A wider pattern** (any `#` plus digits) reads the same as the gate pattern in all 13 files at the base, and 0 in all 13 at the head. - **At the head:** 282 messages / 297 ids in 71 files. The 13 files read 0 / 0, `api/` leaves the table, and no other file moved. ## How the area was chosen `api/` has no subdirectory, so it is taken in name-ordered file groups near the ~100-id bound, the rule stages 20 to 24 used. Stage 24's cut named this group at 95 ids, and this census reads 95, so no re-cut was needed. `protocol.test.ts` (50 ids) fits one PR and one text-only proof, so it is not split. **Named for the next stages** (cut from the head census, 282 / 297): - **`system/`**, 167 ids in 34 files (one of them in `system/constants/`), two stages: - **first group:** `auth-config.test.ts` through `metadata-form-declared-rows.pin.test.ts`, 18 files, 91 messages / 97 ids (`i18n-resolver.test.ts` alone 53 / 56); - **second group:** `metadata-form-zod-reconciliation.test.ts` through `worker.test.ts`, 16 files, 63 / 70. Its first file carries 17 "other" strings, its ledger `why` entries. - The files directly in `src/`, 120, one stage. - The needles: the three docblock needles, the kept `ui/component-props-unknown-members.pin.test.ts:322` and stage 22's two. One stage, with an at-tier review. The four colour literals stay, as stage 21 decided. ## What each id became - **10 literals (11 ids)** now state a decision in words. - **12 literals (16 ids)** get their subject back in words, where the number stood for a thing. - **67 literals (68 ids)** drop a number the title already explains. Every cited record was fetched with all its comments through REST, and its decision was read from its ruling, ACCEPT and landing comments: a keyword digest of every record, and full reads wherever the new words carry a decision. 43 records are cited: 36 answer 200 and 7 answer 404. Two more were read for context: #14478, whose ruling B #15677 executes, and PR #11426, #11006's landing. The seven that answer 404 were read from what landed, through the commits endpoint (this checkout is shallow), each commit found through the CHANGELOG entry or the commit list of `protocol.test.ts`: - **#6037**, from `18189983dd` (#6474): `DataProtocol.validateData` asks the write path for its verdict and persists nothing, #4633 ruling D; - **#6239**, from `f549a0d4ad` (#6526): `ViewProtocol`'s five viewId-addressed methods and ten schemas are retired; - **#6361**, from `90bbf25107` (#6866): the notification-list `cursor` is tombstoned on both halves (maintainer ruling 2026-08-07, option A); - **#9740**, from `11b779e0f9` (#9773): `MetadataProtocol.getMetaItemLayered` is declared, and the dead `'overlay'` `lockSource` arm is dropped; - **#9741**, from `2a29caa532` (#9804): `previewDrafts` / `state` are declared where the implementation enforces them, and `environmentId` is recorded as transport-level. Its changeset (`packages/spec/CHANGELOG.md:31798`) names it "maintainer ruling 2026-08-18", and `cccbe51bf7` cites "the #9741 ruling"; - **#11006**, from `cccbe51bf7` (#11426): `publishMetaItem` is declared as an optional member with `PublishMetaItemRequest` (maintainer ruling 2026-08-22, option B); - **#14691**, from `b3a63d32c9` (#14868): the ten inert `RestServerConfig` keys the liveness ledger recorded as `dead` are retired. **The same-id titles stage 24 listed in this group:** - **`[#5672]` x2** (`protocol.test.ts:508`, `:526`): #5672's maintainer ruling A (`5199159328`): one closed capability vocabulary, emitted in full by both discovery producers, with an absent capability `enabled: false` rather than a missing key. `:508` now reads "strips a capability key outside the closed vocabulary". The old verb was "rejects", but the body pins the opposite: the parse stays green and the key does not survive it. `:526` now reads "… (ruled: an absent capability is `enabled: false`, not a missing key)". - **`(#12038)` x5** (`:2575` to `:2686`): these five "declares the … body" describes are the describe-only transcriptions that the five-part ruling's implementation plan names (`5434804846`). None of them pins a lettered sub-ruling, so no letter is named; the title already says the decision, and only the number goes. - **`(#12038 1C)`** (`:2710`): now "GetPublishedMetaItemResponseSchema stays opaque (ruled: no shape frozen against the current type registry)", ruling 1C's own reason. Its children pin the `unknown` body. - **`(#19543, door ③)`** (`:2726`): door ③ is the AI-conversation list, which the schema name already names, and "declares the next-page signal" is that door's spec half (letter A, re-derivation `5825819437`). Only the number and the door label go. - **`(#15677)`** in `plugin-rest-api.test.ts:694` and `websocket.test.ts:712`: now "… durations carry their unit in the key name", #14478's ruling B (`5518649320`, population ruling `5548763981`), which #15677 executes for `api/`. In `router.test.ts:565` the title already shows the rename (`RouteDefinition.timeout → timeoutMs`), so only the number goes. **Stated in words:** | record | literal (under `api/`) | now reads | the decision | |:--|:--|:--|:--| | #14478 via #15677 | `plugin-rest-api.test.ts:694`, `websocket.test.ts:712` | "… durations carry their unit in the key name" | Ruling B: a `z.number()` duration key carries its unit in its name; the old spellings are `retiredKey()` tombstones. | | #5672 | `protocol.test.ts:508` | "strips a capability key outside the closed vocabulary" | Ruling A (2026-08-06): one closed vocabulary. | | #5672 | `protocol.test.ts:526` | "rejects a capability map that is missing part of the vocabulary (ruled: an absent capability is `enabled: false`, not a missing key)" | Ruling A: both producers emit the whole vocabulary. | | #9406 | `protocol.test.ts:1313` | "probes is opaque BY DECLARATION (ruled: modeled only once a consumer needs a field): …" | Maintainer ruling 2026-08-18 (`5322875103`): `probes` gets a deliberately opaque passthrough, upgraded to a modeled schema only when a consumer needs a field of it. | | #9343 | `protocol.test.ts:1383` | "PublishPackageDraftsResponseSchema published[].advisories (ruled: advisory findings ride each published element)" | Maintainer ruling 2026-08-17 (`5321046016`): `advisories` rides each `published[]` element, with no parallel top-level map. | | #9741 | `protocol.test.ts:1739` | "environmentId stays OUT of the meta-read request shape — transport-level by decision, not omission" | The 2026-08-18 ruling, as landed in `2a29caa532`: `environmentId` is the transport-level multi-kernel routing key. | | #12038 | `protocol.test.ts:2710` | "GetPublishedMetaItemResponseSchema stays opaque (ruled: no shape frozen against the current type registry)" | Ruling 1C (`5434804846`): a thin envelope with the body opaque, no union frozen against today's type registry. | | #6037 | `validate-data.test.ts:25` | "ValidateDataRequest — asks the write path for its verdict instead of predicting it" | What landed in `18189983dd`: the dry run stops predicting the write's verdict and asks for it. | | #6037 | `validate-data.test.ts:57` | "ValidateDataResponse — the verdict the write path would reach, persisting nothing" | The same commit: `validateData` reports the write path's verdict on candidate rows and persists nothing. | **Subject back in words** (12 literals): - "zero holders after #13823" becomes "zero holders after its retirement", and "[#13823] ADR-0087 registration" becomes "handlerStatus retirement — ADR-0087 registration", the form of the repo's other retirement registration describes (#13823 ruled remove, `5494755488`); - "the routes wired in #3899" becomes "the routes wired to the request-schema gate", the gate the file's header names; - "(#13155 — carries #5745 to the third verb)" becomes "(carries the declared = returned discipline to the third verb)", the discipline #7294 and #13155 name #5745 for; - "(#4717 — #4463 D3 on the response)" and "(#9176 — #4463 D3 on the publish door)" become "(advisory findings ride the 2xx response)" and "(advisory findings ride the 2xx on the publish door too)": #4463's D3 sends gating findings to 422 and lets advisory findings ride the 2xx; - "the #9612-gate class" becomes "the package-closure publish-gate class": #9612's gate judges a publish against the written package's closure; - "#10235 the #7865 anchor category" becomes "the unprovisioned injected-anchor category", the platform anchors injected into an external object whose storage the platform does not provision (#7865, ruling B); - the two "pre-#3689" storage shapes become shapes "from before the shared success envelope"; - "the #4052 non-repeat" becomes "the non-repeat of the retired `validateOnly` dry-run flag"; - "every #8055-shaped fixture" becomes "every malformed-flow-body fixture". **Dropped where already stated** (67 literals, 68 ids). A number goes only where the title already says its decision. Examples: the two `[#13823]` describes and the twelve `[#14691]` / `(#14691)` retirement titles ("REJECTS `patterns` with the retirement prescription — …", "the tombstones reject one key each, not the config — …"); `[#11983]` x3, `[#4579]` x2, `[#4939]`, `[#6361]`, `[#20294]` and `#3899 —`; the `#10235` prefixes on "resolveObjectSortability — the closed category set" and "wire validity — …"; the five "transport-level by the #9741 ruling" titles, which now read "transport-level by ruling"; the parenthesized `(#5745 — …)`, `(#7294 — …)`, `(#9406 — …)`, `(#10524 — …)` x2, `(#9726 — …)`, `(#9741 — …)` and `(#4717 — …)` pairs, which keep their words; and the tails `(#6239)`, `(#4286)`, `(#9740)`, `(#11006)` x2, `(#11678)` x3, `(#9426)`, `(#12005)` x3, `(#11679)` x2, `(#12004)` x2, `(#3718)`, `(#4572)`, `(#4579)`, `(#20294)`, `(#8124/#8055)`, the five `(#12038)` and the `(#4738, …)` aside in one expect message. The 404 numbers among them (#6239, #6361, #9740, #9741, #11006, #14691) go only where the title already states what landed. **No file is renamed.** ## Readers - **Needles:** none. The three declared strings are assertion failure messages (the second argument of `expect`), none is an expected value, and no title or message in the group is matched against a source docblock or another file's text. The one self-read in the group, `rest-api-config-dead-keys-retirement.test.ts:519`, reads its own file for the id-free describe title "tree-scoped absence", which this PR does not touch. - **Test-name filters:** none. No tracked script, workflow or package config passes `-t` / `--testNamePattern` to vitest; the one vitest `-t` hit is a README example under `packages/qa/dogfood` filtering its own fixture. - **Snapshots:** none. No `__snapshots__` directory is tracked under `packages/spec`, and none of the 13 files calls a snapshot matcher. - **Projects:** `rest-api-config-dead-keys-retirement.test.ts` is in the `repo` project (`packages/spec/vitest.repo-tests.json:31`); the other 12 run in `local`. The base-versus-head run below takes both projects. - **By substring:** every old literal, its id-bearing fragment and a window around each id (270 needles) was searched with `git grep` at the base, across the tracked tree outside its own file. No gate, doc, filter, snapshot, QA checklist entry or `scripts/check-*.mjs` self-test reads one. The 6 hits are sibling test titles: the two `(#15677)` describes in this group hit each other (both rewritten here), `client/src/client.test.ts:1134` shares "query.distinct (#4286)", and `metadata-protocol/src/protocol.validate-data.test.ts:102` shares "the #4052 non-repeat". ## Text-only proof Stage 10's scratch tool (`textonly10.cjs`, md5 `d5e4801dbb4329ab1984da91e92fc47c`) compares base and head file by file on three legs: 1. **Skeleton:** the full AST, with string pieces masked. It must be identical. 2. **Comments:** every comment, byte-equal. 3. **Strings:** each changed string leaf must sit in a test-call title position or on a declared line, must carry a tracker id before, and must carry no `#` plus digits after. This stage declares the three expect-message lines named above. - **Result:** 13 of 13 files SAME on all three legs, with the per-file counts predicted in writing before any edit. - **Totals:** 89 changed string leaves in 89 literals: 86 titles and 3 declared. The diff's `+` and `-` lines are exactly the 89 planned lines as multisets, and every file keeps its line count. - **Controls (14 of 14 as predicted on the first run, on scratch copies, each anchor hit once):** identifier rename DIFF; numeric literal DIFF; comment edit COMMENT DIFF; a non-title string given an id VIOLATION; a rewritten title given a new id VIOLATION; a title that was id-free at base edited VIOLATION; one title reverted to base SAME; an `it.each` row given an id VIOLATION; an undeclared expect message changed VIOLATION; a title re-split into a `+` chain DIFF; a declared expect message reverted to base SAME; a declared template expect message given a new id VIOLATION; a declared `+`-chain leaf given a new id VIOLATION; a template-literal title given a new id VIOLATION. - **Templates and tables:** no `.each` title and no `$name` placeholder changes. The two template literals change only their text after the `${…}` span. **Test counts:** the 13 files were run at the base, in a separate base worktree, and at the head, with `--project local --project repo`. Both sides read 509 tests in 13 files, all passed, with the same count and status sequence per file in 13 of 13. 250 full test names change, and each changed name equals the base name with the planned replacements applied: 0 mismatches. No full name repeats on either side, and no head name carries `#` plus digits (250 base names did). `router.test.ts:565` writes its arrow as a `→` escape; the plan's anchor there starts after the escape, so the comparison tool, which reads escapes literally, met none, and vitest prints "RouteDefinition.timeout → timeoutMs …" on both sides. ## Changeset: `skip-changeset` Measured, not assumed: - `npm pack --dry-run` of `@objectstack/spec` lists 2068 files. 0 of the 13 touched files are in it, and no `*.test.ts` at all. The controls `src/api/protocol.zod.ts`, `src/api/rest-server.zod.ts` and `dist/index.mjs` are in it. - In the built `dist/`, two new phrases and an old one each read in 0 files. The control `Unrecognized key` reads in 42. So this PR publishes nothing, and no changeset is added. ## Verification (at `c63eba0adf`) - `pnpm turbo run build` over all packages: 71 / 71, through the shared verify lock (`VERDICT command-exit 0`). - `@objectstack/spec`: - `vitest run --project local`: 619 files, 18480 passed, 1 todo. - `typecheck`: exit 0, including `check:test-typecheck` (52 files / 246 errors / 135 pinned signatures held). Its program holds all 13 group files, counted by path with `tsc --listFilesOnly -p tsconfig.test.json`. - `check:generated`: all 15 generated artifacts up to date, against the `dist/` the build above wrote. - **Gates:** `dispatch-gates --commands` derived 79 families: stage 24's 80 without `check:error-code-casing`, whose named sources this diff does not touch. All 79 exit 0. `--ran` reconciles: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN, every family with its exit code recorded. The same 79 derive from `origin/main` `230e4944b0` with this diff applied. The five roster families marked as sharing a directory with this diff (`check:meta-url-spelling`, `check:spec-changes`, `check:authz-resolver`, `check:error-code-casing`, `check:filter-alias-parity`) each exit 0. - **ESLint, a proven narrowing:** `--no-inline-config` over the 13 files reads 0 errors and 0 warnings. The population comes from ESLint's own config: 13 configured, 0 ignored. No file sets `parserOptions.project` or `projectService`, so no untouched file's verdict can move. - `check-governed-merges --test`: NOT governed, 178 changed lines (+89 / -89). - A control-byte scan over the 13 changed files finds none. ## `main` since the base Re-fetched just before this PR opened, `origin/main` was six commits past the base (`c9761cd2fb`: #21966, #21951, #21963, #21969, #21965, #21962). They touch 28 files, none of the 13 and none under `packages/spec/src/api/`, so `main` was not merged. The two `packages/spec/src` files they change (`data/datasource-credential-redaction.ts` and its test) read 0 / 0 in the census at `c9761cd2fb`: the one id they add is a code comment. `git merge-tree` onto `c9761cd2fb` is clean, and none of the 4 open PRs touches any of the 13 files. ## Acceptance notes - **Same-id test titles in this card's later stages** go with those stages: `system/book.test.ts:413` (`(#12038)`). - **Same-id test titles in other packages** stay: 97 lines in 15 packages (`runtime` 25, `objectql` 13, `lint` 12, `metadata-protocol` 12, `rest` 12, `client` 8, `metadata-core` 4, `qa/dogfood` 2, `service-automation` 2, `service-storage` 2, and one each in `examples/app-crm`, `examples/app-showcase`, `driver-sql`, `plugin-sharing` and `types`), each package's share under the #20513 lane children. - **Code comments with live ids** remain in these files and their sources, among them the `* #3899 —` header in `plugin-rest-api.schema-refs.test.ts`, the `* #8124 —` header in `zod-issues-to-fields.test.ts`, the `// [#5672] This fixture used to lead with …` comment above `protocol.test.ts:508`, and the `/** [#20294] … */` docblock in `rest-api-config-dead-keys-retirement.test.ts`. Code comments are not this card's share. --- _Generated by [Claude Code](https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent f76c622 commit dcf3eb4

13 files changed

Lines changed: 89 additions & 89 deletions

‎packages/spec/src/api/plugin-rest-api.handler-status-retirement.test.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ const WELL_FORMED = {
7070

7171
const PRESCRIPTION = /`RestApiEndpoint\.handlerStatus`.*was removed.*17/s;
7272

73-
describe('[#13823] RestApiEndpoint.handlerStatus retirement', () => {
73+
describe('RestApiEndpoint.handlerStatus retirement', () => {
7474
// All three former values, INCLUDING the documented default: the old
7575
// docblock's `@default 'implemented'` was prose only — the key never carried
7676
// a Zod `.default()`, so no built artifact materialised it and there is no
@@ -156,7 +156,7 @@ describe('[#13823] RestApiEndpoint.handlerStatus retirement', () => {
156156
});
157157
});
158158

159-
describe('[#13823] api/HandlerStatus + api/RouteCoverage{Entry,Report} def retirement', () => {
159+
describe('api/HandlerStatus + api/RouteCoverage{Entry,Report} def retirement', () => {
160160
/** The 6 names the three retired defs exported (3 schema consts + 3 types). */
161161
const RETIRED_NAMES = [
162162
'HandlerStatusSchema',
@@ -176,7 +176,7 @@ describe('[#13823] api/HandlerStatus + api/RouteCoverage{Entry,Report} def retir
176176

177177
// ── ABSENCE (every entry, not just ./api) ─────────────────────────────
178178
for (const name of RETIRED_NAMES) {
179-
expect(holdersOf(name), `${name} must have zero holders after #13823`).toEqual([]);
179+
expect(holdersOf(name), `${name} must have zero holders after its retirement`).toEqual([]);
180180
}
181181

182182
// ── SURVIVAL ──────────────────────────────────────────────────────────
@@ -205,7 +205,7 @@ describe('[#13823] api/HandlerStatus + api/RouteCoverage{Entry,Report} def retir
205205
});
206206
});
207207

208-
describe('[#13823] ADR-0087 registration', () => {
208+
describe('handlerStatus retirement — ADR-0087 registration', () => {
209209
it('declares the tombstoned key and the three removed defs under major 18, with the D3 entry', () => {
210210
expect(RETIRED_KEYS_BY_MAJOR[18]).toContain('api/RestApiEndpoint:handlerStatus');
211211
for (const def of ['api/HandlerStatus', 'api/RouteCoverageEntry', 'api/RouteCoverageReport']) {

‎packages/spec/src/api/plugin-rest-api.schema-refs.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ function resolvesToZodSchema(name: string): boolean {
5353
return !!candidate && typeof (candidate as { safeParse?: unknown }).safeParse === 'function';
5454
}
5555

56-
describe('#3899 — catalog schema references resolve and sit on the right methods', () => {
56+
describe('catalog schema references resolve and sit on the right methods', () => {
5757
it('every requestSchema names a Zod schema exported from @objectstack/spec/api', () => {
5858
for (const ep of allEndpoints()) {
5959
if (!ep.requestSchema) continue;
@@ -87,7 +87,7 @@ describe('#3899 — catalog schema references resolve and sit on the right metho
8787
}
8888
});
8989

90-
it('at least the routes wired in #3899 still declare their request schemas', () => {
90+
it('at least the routes wired to the request-schema gate still declare their request schemas', () => {
9191
// Anti-erosion floor: the gate above is vacuous if declarations are simply
9292
// deleted. These five are validated at their mounted routes.
9393
const declared = new Map(

‎packages/spec/src/api/plugin-rest-api.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ describe('plugin-rest-api.zod', () => {
541541
expect(paths).not.toContain('/preferences');
542542
});
543543

544-
it('declares no AI routes — this table cannot vouch for a Cloud/EE surface (#3718)', () => {
544+
it('declares no AI routes — this table cannot vouch for a Cloud/EE surface', () => {
545545
// DEFAULT_AI_ROUTES used to sit here declaring `/nlq`, `/suggest` and
546546
// `/insights`, and this test asserted its shape — three endpoints no repo
547547
// has ever mounted, checked for `toHaveLength(3)`. Shape is not
@@ -691,7 +691,7 @@ describe('plugin-rest-api.zod', () => {
691691
// than a bare unrecognized-key error, and the value survives at the same
692692
// magnitude. Asserting the message, not just `.toThrow()`: a bare throw stays
693693
// green when the schema throws for some unrelated reason.
694-
describe('RestApiEndpoint / RestApiPluginConfig durations carry their unit (#15677)', () => {
694+
describe('RestApiEndpoint / RestApiPluginConfig durations carry their unit in the key name', () => {
695695
const endpoint = {
696696
method: 'GET' as const, path: '/api/v1/discovery',
697697
handler: 'getDiscovery', category: 'discovery' as const,

‎packages/spec/src/api/protocol.test.ts‎

Lines changed: 46 additions & 46 deletions
Large diffs are not rendered by default.

‎packages/spec/src/api/registry-retirement.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const RETIRED_NAMES = [
5858
'ApiDiscoveryResponseSchema',
5959
] as const;
6060

61-
describe('[#4939] ApiRegistry family retired from `@objectstack/spec/api`', () => {
61+
describe('ApiRegistry family retired from `@objectstack/spec/api`', () => {
6262
it('exports none of the retired names', async () => {
6363
const api = await import('./index');
6464

@@ -86,7 +86,7 @@ describe('[#4939] ApiRegistry family retired from `@objectstack/spec/api`', () =
8686
expect(
8787
'ConflictResolutionStrategy' in api,
8888
'two independent ratchets pin this as a ./api export: spec/src/automation/' +
89-
'sync-retirement.test.ts (#4738, the fourth ConflictResolution relative) and, ' +
89+
'sync-retirement.test.ts (the fourth ConflictResolution relative) and, ' +
9090
'cross-repo, objectui offline-nav-performance-spec-parity.test.ts',
9191
).toBe(true);
9292

‎packages/spec/src/api/rest-api-config-dead-keys-retirement.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ describe('rest_api retirement — `api.documentation.enabled`, a tombstone insid
145145
});
146146
});
147147

148-
describe('rest_api retirement — `api.documentation.version` (#20294), a second tombstone inside the live block', () => {
148+
describe('rest_api retirement — `api.documentation.version`, a second tombstone inside the live block', () => {
149149
// The old authored spellings: a release number, a semver-looking protocol
150150
// version, and an empty string.
151151
for (const version of ['2.3.0', '17.4.0', '']) {
@@ -254,7 +254,7 @@ describe('rest_api retirement — ADR-0087 registration', () => {
254254
expect(step.conversionIds.filter((id) => /response-format|documentation-enabled/.test(id))).toEqual([]);
255255
});
256256

257-
it('[#20294] declares `documentation.version` under major 18 with its own family D3 entry, and no D2 conversion', () => {
257+
it('declares `documentation.version` under major 18 with its own family D3 entry, and no D2 conversion', () => {
258258
expect(RETIRED_KEYS_BY_MAJOR[18]).toContain('api/RestApiConfig:documentation.version');
259259
const step = MIGRATIONS_BY_MAJOR[18]!;
260260
const entry = step.semantic.find((e) => e.id === 'rest-api-documentation-version-retired');

‎packages/spec/src/api/rest-server.test.ts‎

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ describe('RestApiConfigSchema', () => {
7979
expect(config.enableDiscovery).toBe(false);
8080
});
8181

82-
it('[#11983] enableSearch defaults to true — search is ON unless opted out', () => {
82+
it('enableSearch defaults to true — search is ON unless opted out', () => {
8383
// Pinning the MATERIALIZED default (not just the declaration) is what makes
8484
// a later `.optional()` — which would hand `undefined` to the REST layer —
8585
// fail here rather than silently change the mount decision.
@@ -88,7 +88,7 @@ describe('RestApiConfigSchema', () => {
8888
expect(config.enableSearch).toBe(true);
8989
});
9090

91-
it('[#11983] enableSearch: false is the declared deployment-wide opt-out, and it SURVIVES the parse', () => {
91+
it('enableSearch: false is the declared deployment-wide opt-out, and it SURVIVES the parse', () => {
9292
// Before this key had a declared seat, this exact parse was the measured
9393
// trap: `RestApiConfigSchema` is not `.strict()`, so it STRIPPED the
9494
// undeclared key and any consumer of the parsed output silently got search
@@ -103,7 +103,7 @@ describe('RestApiConfigSchema', () => {
103103
expect(RestApiConfigSchema.parse({ enableSearch: true }).enableSearch).toBe(true);
104104
});
105105

106-
it('[#11983] enableSearch is authorable without a cast, and is a boolean (compile-time)', () => {
106+
it('enableSearch is authorable without a cast, and is a boolean (compile-time)', () => {
107107
// The declaration's REASON for existing: `objectstack.config.ts` authors
108108
// the key by name and `packages/rest`'s `normalizeConfig` reads it. Both go
109109
// through this input type, so this is the pin that says the key no longer
@@ -205,7 +205,7 @@ describe('CrudEndpointsConfigSchema', () => {
205205
expect(config.operations?.delete).toBe(false);
206206
});
207207

208-
it('[#14691] REJECTS `patterns` with the retirement prescription — the key never customized a route', () => {
208+
it('REJECTS `patterns` with the retirement prescription — the key never customized a route', () => {
209209
expect(() => CrudEndpointsConfigSchema.parse({
210210
patterns: {
211211
create: { method: 'POST', path: '/objects/{object}' },
@@ -221,14 +221,14 @@ describe('CrudEndpointsConfigSchema', () => {
221221
expect(config.dataPrefix).toBe('/objects');
222222
});
223223

224-
it('[#14691] REJECTS `objectParamStyle` — both former enum values, with the prescription', () => {
224+
it('REJECTS `objectParamStyle` — both former enum values, with the prescription', () => {
225225
for (const objectParamStyle of ['path', 'query']) {
226226
expect(() => CrudEndpointsConfigSchema.parse({ objectParamStyle }), objectParamStyle)
227227
.toThrow(/`crud\.objectParamStyle` was removed.*path segment.*Delete the key/s);
228228
}
229229
});
230230

231-
it('[#14691] the tombstones reject one key each, not the config — every live key still parses', () => {
231+
it('the tombstones reject one key each, not the config — every live key still parses', () => {
232232
const config = CrudEndpointsConfigSchema.parse({
233233
operations: { list: false },
234234
dataPrefix: '/records',
@@ -266,7 +266,7 @@ describe('MetadataEndpointsConfigSchema', () => {
266266
expect(config.enableCache).toBe(false);
267267
});
268268

269-
it('[#14691] REJECTS `cacheTtl` — including the negative value the old contract accepted', () => {
269+
it('REJECTS `cacheTtl` — including the negative value the old contract accepted', () => {
270270
for (const cacheTtl of [7200, 0, -1]) {
271271
expect(() => MetadataEndpointsConfigSchema.parse({ cacheTtl }), String(cacheTtl))
272272
.toThrow(/`metadata\.cacheTtl` was removed.*takes no TTL.*Delete the key/s);
@@ -290,7 +290,7 @@ describe('MetadataEndpointsConfigSchema', () => {
290290
expect(config.endpoints?.maintenance).toBe(true);
291291
});
292292

293-
it('[#14691] REJECTS `endpoints.schema` — it gated a route that does not exist', () => {
293+
it('REJECTS `endpoints.schema` — it gated a route that does not exist', () => {
294294
expect(() => MetadataEndpointsConfigSchema.parse({ endpoints: { schema: false } }))
295295
.toThrow(/`metadata\.endpoints\.schema` was removed.*does not exist.*Delete the key/s);
296296
});
@@ -386,12 +386,12 @@ describe('BatchEndpointsConfigSchema', () => {
386386
expect(config.operations).not.toHaveProperty('upsertMany');
387387
});
388388

389-
it('[#14691] REJECTS `operations.upsertMany` — it gated a route that was never built', () => {
389+
it('REJECTS `operations.upsertMany` — it gated a route that was never built', () => {
390390
expect(() => BatchEndpointsConfigSchema.parse({ operations: { upsertMany: false } }))
391391
.toThrow(/`batch\.operations\.upsertMany` was removed.*never built.*Delete the key.*'upsert'/s);
392392
});
393393

394-
it('[#14691] REJECTS `defaultAtomic` — atomicity is the per-request `options.atomic`', () => {
394+
it('REJECTS `defaultAtomic` — atomicity is the per-request `options.atomic`', () => {
395395
for (const defaultAtomic of [true, false]) {
396396
expect(() => BatchEndpointsConfigSchema.parse({ defaultAtomic }), String(defaultAtomic))
397397
.toThrow(/`batch\.defaultAtomic` was removed.*options\.atomic.*Delete the key/s);
@@ -400,27 +400,27 @@ describe('BatchEndpointsConfigSchema', () => {
400400
});
401401

402402
describe('RouteGenerationConfigSchema', () => {
403-
it('should accept the empty sub-object — and materialize nothing, every key being a tombstone (#14691)', () => {
403+
it('should accept the empty sub-object — and materialize nothing, every key being a tombstone', () => {
404404
const config = RouteGenerationConfigSchema.parse({});
405405

406406
expect(config).toEqual({});
407407
});
408408

409-
it('[#14691] REJECTS `includeObjects` / `excludeObjects` — the object declares its own exposure', () => {
409+
it('REJECTS `includeObjects` / `excludeObjects` — the object declares its own exposure', () => {
410410
expect(() => RouteGenerationConfigSchema.parse({ includeObjects: ['account', 'contact'] }))
411411
.toThrow(/`routes\.includeObjects` was removed.*Delete the key.*enable\.apiEnabled.*enable\.apiMethods/s);
412412
expect(() => RouteGenerationConfigSchema.parse({ excludeObjects: ['system_log'] }))
413413
.toThrow(/`routes\.excludeObjects` was removed.*Delete the key.*enable\.apiEnabled.*enable\.apiMethods/s);
414414
});
415415

416-
it('[#14691] REJECTS `nameTransform` — every former enum value, `none` included', () => {
416+
it('REJECTS `nameTransform` — every former enum value, `none` included', () => {
417417
for (const nameTransform of ['none', 'plural', 'kebab-case', 'camelCase']) {
418418
expect(() => RouteGenerationConfigSchema.parse({ nameTransform }), nameTransform)
419419
.toThrow(/`routes\.nameTransform` was removed.*Delete the key.*canonical id/s);
420420
}
421421
});
422422

423-
it('[#14691] REJECTS `overrides` — the per-object record turned nothing on or off', () => {
423+
it('REJECTS `overrides` — the per-object record turned nothing on or off', () => {
424424
expect(() => RouteGenerationConfigSchema.parse({
425425
overrides: {
426426
account: { enabled: true, basePath: '/accounts' },
@@ -473,7 +473,7 @@ describe('RestServerConfigSchema', () => {
473473
expect(config.routes).toEqual({});
474474
});
475475

476-
it('[#14691] a retired sub-object key is refused THROUGH the whole config, with its own prescription', () => {
476+
it('a retired sub-object key is refused THROUGH the whole config, with its own prescription', () => {
477477
// The tombstones live on the sub-schemas; this pins that composing them
478478
// under `RestServerConfigSchema` changes nothing — the same authored key is
479479
// refused at the whole-config parse with the same string.
@@ -697,7 +697,7 @@ describe('Integration Tests', () => {
697697
// tests were removed with the schemas (#4579, ADR-0049 enforce-or-remove).
698698
// The retirement itself is pinned below.
699699

700-
describe('[#4579] `RestServerConfig.openApi31` retirement', () => {
700+
describe('`RestServerConfig.openApi31` retirement', () => {
701701
it('REJECTS an authored openApi31 block, with the fix in the message', () => {
702702
// Tombstoned, not deleted: RestServerConfigSchema is not `.strict()`, so a
703703
// plain deletion would silently strip the key — the author's webhook
@@ -739,7 +739,7 @@ describe('[#4579] `RestServerConfig.openApi31` retirement', () => {
739739
// so the load-bearing pin is the compiler-API test below, with anti-vacuity
740740
// guards (a resolution failure would otherwise make every assertion pass
741741
// vacuously); sabotage-verified in the PR (re-adding an export turns it red).
742-
describe('[#4579] the OpenApi31 block schemas are not exported from any entry point', () => {
742+
describe('the OpenApi31 block schemas are not exported from any entry point', () => {
743743
const REMOVED_NAMES = [
744744
'OpenApi31ExtensionsSchema',
745745
'OpenApi31Extensions',
@@ -765,7 +765,7 @@ describe('[#4579] the OpenApi31 block schemas are not exported from any entry po
765765
expect(apiNames).toContain('RestApiConfigSchema');
766766

767767
for (const removed of REMOVED_NAMES) {
768-
expect(holdersOf(removed), `no entry may export ${removed} (#4579)`).toEqual([]);
768+
expect(holdersOf(removed), `no entry may export ${removed}`).toEqual([]);
769769
}
770770
});
771771

@@ -789,7 +789,7 @@ describe('[#4579] the OpenApi31 block schemas are not exported from any entry po
789789
// and removed; WebhookEvent(Schema) was first renamed OpenApiWebhookEvent(Schema)
790790
// (#4572) and then removed outright with the openApi31 block (#4579).
791791
// Pin: this module declares neither the bare names nor the renamed ones.
792-
it('does not re-expose the bare WebhookEvent/WebhookConfig names from ./api (#4572)', async () => {
792+
it('does not re-expose the bare WebhookEvent/WebhookConfig names from ./api', async () => {
793793
const restServer = await import('./rest-server.zod');
794794
expect('WebhookEventSchema' in restServer).toBe(false);
795795
expect('WebhookConfigSchema' in restServer).toBe(false);

‎packages/spec/src/api/router.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ describe('Integration Tests', () => {
562562
// than a bare unrecognized-key error, and the value survives at the same
563563
// magnitude. Asserting the message, not just `.toThrow()`: a bare throw stays
564564
// green when the schema throws for some unrelated reason.
565-
describe('RouteDefinition.timeout \u2192 timeoutMs (#15677)', () => {
565+
describe('RouteDefinition.timeout \u2192 timeoutMs', () => {
566566
const base = { method: 'GET' as const, path: '/api/test', handler: 'test_handler' };
567567

568568
it('REFUSES the retired `timeout` spelling with the rename in the message', () => {

‎packages/spec/src/api/sortability.test.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const OPPORTUNITY_LIKE = {
4242
},
4343
};
4444

45-
describe('#10235 resolveObjectSortability — the closed category set', () => {
45+
describe('resolveObjectSortability — the closed category set', () => {
4646
it('marks a formula column unsortable with the refusal-backed reason', () => {
4747
const { fields } = resolveObjectSortability(OPPORTUNITY_LIKE);
4848
expect(fields.expected_revenue).toEqual({
@@ -111,7 +111,7 @@ describe('#10235 resolveObjectSortability — the closed category set', () => {
111111
});
112112
});
113113

114-
describe('#10235 the #7865 anchor category — accepted, caveated, never refused', () => {
114+
describe('the unprovisioned injected-anchor category — accepted, caveated, never refused', () => {
115115
/** An ADR-0015 external object as the registry serves it: injected anchors present. */
116116
const EXTERNAL = {
117117
name: 'ext_customer',
@@ -167,7 +167,7 @@ describe('#10235 the #7865 anchor category — accepted, caveated, never refused
167167
});
168168
});
169169

170-
describe('#10235 wire validity — the projection parses under its own schema', () => {
170+
describe('wire validity — the projection parses under its own schema', () => {
171171
it.each([
172172
['oracle-shaped object', OPPORTUNITY_LIKE],
173173
['external object', {

‎packages/spec/src/api/storage.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ describe('FileDownloadUrlResponseSchema', () => {
634634
expect(resp.data.url).toBe('/api/v1/storage/_local/raw/eyJrIjoi.c2ln');
635635
});
636636

637-
it('should reject the bare pre-#3689 shape', () => {
637+
it('should reject the bare shape from before the shared success envelope', () => {
638638
expect(() =>
639639
FileDownloadUrlResponseSchema.parse({ url: 'https://cdn.example.com/f1.png' })
640640
).toThrow();
@@ -655,7 +655,7 @@ describe('RawUploadResponseSchema', () => {
655655
expect(resp.data.key).toBe('user/f1.png');
656656
});
657657

658-
it('should reject the pre-#3689 `{ ok, key }` shape', () => {
658+
it('should reject the `{ ok, key }` shape from before the shared success envelope', () => {
659659
expect(() => RawUploadResponseSchema.parse({ ok: true, key: 'user/f1.png' })).toThrow();
660660
});
661661

0 commit comments

Comments
 (0)