Skip to content

Commit a3ffc45

Browse files
test(spec): the first data/ file group's test titles state each cited decision in words instead of a tracker number (stage 15) (#21810)
Part of #20749 Clause-②: no Stage 15 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 first name-ordered file group directly under `packages/spec/src/data/`: the 20 test files from `aggregate-field-type-compatibility.test.ts` to `date-range-presets.test.ts`. They carried 94 messages and 102 tracker ids, citing 60 records. Every one of those ids now either states what its record decided, in words (form D), or is dropped where the title already says it. Text only: no assertion, identifier, test count or code comment changes. ## Census at the base (`0a3480311a`) Instruments: `census10.cjs` (md5 `9d08602ab972b4b8643c90d64d40fa41`), `census.cjs` (md5 `6e42a45a926d375013c32d62f16a296e`), `census-wide.cjs` (md5 `c98410a19529c439adb0afbfb00026a2`) and `dirtable.cjs` (md5 `dda605c54745b4a60cc14c9a686e4eff`). They are byte-identical to the copies stages 10 to 14 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. Both instruments read **1325 messages / 1406 ids in 282 files**, the seat's reading at `0a3480311a` (stage 14's head). | directory | files | messages / ids | titles | other | |:--|--:|--:|--:|--:| | `data/` (this PR: the first 20 files) | 95 | 468 / 501 | 445 / 475 | 23 / 26 | | `ui/` | 81 | 393 / 416 | 375 / 398 | 18 / 18 | | `api/` | 40 | 189 / 201 | 181 / 193 | 8 / 8 | | `system/` | 34 | 154 / 165 | 128 / 138 | 26 / 27 | | (files directly in `src/`) | 30 | 118 / 120 | 117 / 119 | 1 / 1 | | `ai/` | 1 | 2 / 2 | 0 | 2 / 2 | | `contracts/` | 1 | 1 / 1 | 0 | 1 / 1 | | **total** | **282** | **1325 / 1406** | **1246 / 1323** | **79 / 83** | The group reads **94 messages / 102 ids in 20 files**, the seat's figures, file for file: | file (under `data/`) | messages / ids | titles | other | |:--|--:|--:|--:| | `aggregate-field-type-compatibility.test.ts` | 4 / 4 | 4 / 4 | 0 | | `analytics-date-range-closed-vocabulary.test.ts` | 1 / 1 | 1 / 1 | 0 | | `analytics-date-range-two-bound-window.test.ts` | 3 / 3 | 3 / 3 | 0 | | `analytics-query-window-integer.test.ts` | 2 / 2 | 2 / 2 | 0 | | `analytics-strictness-batchd.test.ts` | 9 / 9 | 9 / 9 | 0 | | `analytics.test.ts` | 6 / 6 | 6 / 6 | 0 | | `api-derivation.test.ts` | 6 / 6 | 6 / 6 | 0 | | `api-methods-batch-conformance.test.ts` | 3 / 4 | 1 / 1 | 2 / 3 | | `authoring-key-lint.test.ts` | 2 / 2 | 2 / 2 | 0 | | `autonumber-format.test.ts` | 3 / 3 | 3 / 3 | 0 | | `autonumber-unanchored-boundary.test.ts` | 3 / 4 | 3 / 4 | 0 | | `bulk-write-hook-conformance.test.ts` | 2 / 2 | 2 / 2 | 0 | | `calendar-day.test.ts` | 2 / 2 | 2 / 2 | 0 | | `context-tokens.test.ts` | 1 / 1 | 1 / 1 | 0 | | `currency-mode-family-closure.pin.test.ts` | 2 / 2 | 2 / 2 | 0 | | `currency-precision-iso4217.test.ts` | 7 / 7 | 7 / 7 | 0 | | `data-engine.test.ts` | 20 / 25 | 20 / 25 | 0 | | `datasource-credential-redaction.test.ts` | 6 / 6 | 6 / 6 | 0 | | `datasource.test.ts` | 10 / 10 | 10 / 10 | 0 | | `date-range-presets.test.ts` | 2 / 3 | 2 / 3 | 0 | | **20 files** | **94 / 102** | **92 / 99** | **2 / 3** | - **Controls.** Lit, a title: `data/document.test.ts` reads 2 / 2 at the head. Lit, "other" strings: the two in `data/external-lookup-retirement.test.ts` (`:89`, `:130`) still read at the head. Dark: the file comment at `data/analytics-strictness-batchd.test.ts:4` (it names the strictness batch by its number) reads 0. Planted in a scratch copy of the head `data/calendar-day.test.ts`: an id put into a title reads 1 / 1, and an id put into a comment reads 0. - **A wider pattern** (any `#` plus digits) reads the same totals in 19 of the 20 files. In `aggregate-field-type-compatibility.test.ts` it reads one more, a decision-batch number at `:150` that sits beside a cited record in the same literal. The gate's pattern needs three to five digits, so it is not counted there. - **At the head:** 1231 messages / 1304 ids in 262 files. The 20 files read 0 / 0 on both patterns, and no other file moved. ## How the area was chosen `data/` has no subdirectory to split by (449 ids directly under it, `data/driver/` 52), so its stages take name-ordered file groups near the ~100-id bound, as stage 14's report proposed. This census reads the first group at exactly 102, the claim's figure, so the rule needed no re-cut. **Named for the next stages** (re-cut from the head census, 1231 / 1304; `data/` 374 / 399 left): - `data/` in four more stages, name-ordered: 1. `default-value-shape.test.ts` to `filter-comparand-shape.test.ts`: 20 files, 94 messages / 100 ids; 2. `filter-comparand-type.test.ts` to `filter-view-operator-parity.test.ts`: 20 files, 95 / 99; 3. `filter.test.ts` to `object.test.ts`: 17 files, 103 / 114. `object.test.ts` alone carries 42, so no cut lands nearer the bound; 4. `query-transport.test.ts` to `validation.test.ts` (11 files, 34 / 34) with `data/driver/` (7 files, 48 / 52): 86 ids. - `ui/` 416, about four stages. `api/` 201, two. `system/` 165, two. The files directly in `src/`, 120, one. - The three docblock needles (`ai/build-progress.test.ts:236`, `:237`, `contracts/approval-service.test.ts:274`), one stage with their docblocks. ## What each id became 24 literals (28 ids) now state a decision in words. 2 literals (2 ids) get their subject back in words where the number stood in for it. 69 literals (72 ids) drop a number the title already explains. (95 literals in 94 messages: the `sys_organization` reason string is one message over two lines.) Every cited record was read with its comments through REST: 55 answer 200. #6345, #8876, #9040, #10194 and #17014 answer 404, and their decisions were read from what landed: `e2798fa` (one driver vocabulary for start and migrate), `d634e66` (the username half of the URL userinfo grammar), `2420641` (a credential in the mongo `options` passthrough is refused), `2306a76` (`theme` / `analytics_cube` validated at the `/meta` write door) and `80aef80` (a one-day window for the one-day presets), each with its CHANGELOG entry. No cross-repo record is cited in this group. | record(s) | literal (under `data/`) | now reads | |:--|:--|:--| | #11152 | `aggregate-field-type-compatibility.test.ts:150` | "accepts `sum` / `avg` / `min` / `max` over booleans — numbers on every backend, a ruling that outranks the refused-by-default rule". The maintainer ruled that booleans aggregate as numbers on every backend; decision batch 80 held that ruling over batch 59's blanket refusal of unnamed pairs. That batch number went with the id. | | #4001 (3) | `analytics-strictness-batchd.test.ts:83`, `:248`, `:306` | "batch D, unknown keys refused — …" before "the doors the cube family is reachable through", "alias claims are true of the surfaces they point at" and "deliberate non-closures (re-verdicts, not omissions)". The campaign's decision: an unknown key is refused, not stripped. | | #3878 (2) | `analytics-strictness-batchd.test.ts:270`, `:297` | "matching the dispatcher's bespoke hint at the /analytics entry" and "the retired-envelope tombstones still fire". The body is the bare `AnalyticsQuery`; the `{ cube, query }` envelope was retired with tombstones, and the entry answers 400 with a hint at `where`. | | #18612 | `analytics.test.ts:314` | "a persisted cube heals at the door — the retired join `sql` / `relationship` are stripped (ADR-0087 D2)". | | #3391 | `api-derivation.test.ts:16` | "api-derivation — one table resolves the effective operations from six primitives". The server is the only adjudicator, through one derivation table. | | #3543 | `api-derivation.test.ts:286` | "vocabulary split — authors write six primitives, the wire speaks operations". The authored enum shrank; the wire vocabulary stayed byte-stable. | | #15873 | `api-methods-batch-conformance.test.ts:221` | A declared reason string: "(a ruling grants `update`; both are column-clamped per row by ADR-0092 D2)". Option (a), decision batch 64. | | #3786 | `authoring-key-lint.test.ts:37` | "lintAuthoredRecordKeys — an unknown authoring key is reported, not swallowed", the decision its source docblock records. | | #6555 | `autonumber-format.test.ts:23` | "DEFAULT_AUTONUMBER_FORMAT / resolveAutonumberFormat — one declared default both sides read". Route 3: `{0000}` became the contract default, and both fallbacks went away. | | #5038 | `bulk-write-hook-conformance.test.ts:114` | "records the after half as DELIVERED — the engine fires it once per row". | | #5574 | `bulk-write-hook-conformance.test.ts:119` | "records the before half as DELIVERED — the engine dispatches it per row too". | | #20126 | `currency-mode-family-closure.pin.test.ts:348` | "currency-mode family — the enumerating closure pin: `defaultCurrency` holds only under `fixed`". | | #19992 | `currency-precision-iso4217.test.ts:163` | "the removed `currencyConfig.precision` at rest: a stored row carrying the baked `precision: 2` is served canonical". | | #7918 | `currency-precision-iso4217.test.ts:224` | "… where the ISO 4217 width check used to refuse it". That check was the record's option A, later reversed. | | #3407, #6437 | `data-engine.test.ts:1185` | "DroppedFieldsEventSchema.reason — why a write dropped submitted fields, widened past the readonly pair". | | #6262, #6433, #6435 | `data-engine.test.ts:1198` | "primary_key is the value the engine reports when it strips a payload id it ruled is not an identifier", the schema's own wording of that strip on the bulk and the by-id paths. | | #8300 | `datasource-credential-redaction.test.ts:70` | "(the drift guard on the one credential-key definition)". | | #8876 | `datasource-credential-redaction.test.ts:232` | "— the username half of the same alignment". | | #8337 | `datasource-credential-redaction.test.ts:243` | "redactUrlCredentialQueryParams — the read half: a credential query parameter is never served back". | | #8153 | `datasource.test.ts:673` | "— unchanged by the managed-row credentialsRef allowance". The ruling allowed `external.credentialsRef`, and only it, on managed rows. | | #4614, #8793 | `date-range-presets.test.ts:14` | "date-range preset vocabulary — one source of truth, read by both the UI and the data side". | **Subject restored (2 ids):** #20126 at `currency-mode-family-closure.pin.test.ts:403` ("currency-mode closure controls — each rule can fail, and passes what it must") and #7918 at `currency-precision-iso4217.test.ts:311` ("carries the measured anchors — 0 digits for JPY, 2 for USD, 3 for KWD"). That literal moved from double to single quotes, since it no longer holds an apostrophe. **Dropped only (72 ids):** #1603, #2377, #3026, #3391, #3543, #3545, #3795 (9), #4001 (2), #4286, #4346 (2), #4538, #4583, #5586, #6345, #6555, #6560, #7178 (5), #7265, #7287 (2), #7802 (2), #8032, #8057 (2), #8153 (7), #8336, #8337, #9040, #10194, #10414, #13802, #16041, #16632, #17014, #17296, #17598 (2), #18278, #19992 (3), #20011, #20300 (2), #20550, #20600, #20808 (3), #21365 (2). - Each of these titles already states the decision it pins: for example "empty array → deny-all (flipped semantics)" for #3391, "accepts the BARE query string — the canonical ADR-0061 D1 spelling" for #7178, or "`currencyConfig.precision` is removed: refused with the prescription, whatever its value" for #19992. - **Small rewordings that carry no new claim:** `analytics-strictness-batchd.test.ts:307` reads "are CLOSED now" where it named the record; `autonumber-unanchored-boundary.test.ts:51` reads "(ruled: mixed content is out of contract)"; `datasource.test.ts:553` reads "(the happy path)". The circled part numbers after #17598 went with the id. - **The two `api-methods-batch-conformance.test.ts` reason strings** (`sys_api_key`, `sys_organization`) end "rather than hitting /batch." now. The table is read only through `!== undefined`, so no assertion reads their text. ## Readers - **Test-name filters:** none. A tracked-tree search for `-t` and `--testNamePattern` finds only `packages/qa/dogfood/README.md:142` (`-t "owner-scoped"`), which is unrelated. - **Snapshots:** none. No `__snapshots__` directory exists under `data/`, and no `.snap` file is tracked under `packages/spec`. - **Projects:** two touched files are listed in `packages/spec/vitest.repo-tests.json`: `api-methods-batch-conformance.test.ts` and `currency-mode-family-closure.pin.test.ts`. Both were run in the `repo` project at the base and at the head, and the other 18 in `local`. - **By substring:** every old literal, plus a window around each id (289 needles), was searched across the tracked tree outside its own file. No gate, doc, filter, snapshot or `scripts/check-*.mjs` self-test reads one. The 14 hits are: - **sibling titles in other lanes:** `service-analytics` `aggregate-nontemporal-measure-refusal.test.ts:344` and `objectql` `engine-autonumber-default-format.test.ts:248`; - **this card's later `data/` stage:** `data/driver/postgres.test.ts:169`, the same "placeholders are not resolved here" title, already in the census; - **comments, CHANGELOG, an audit ledger and liveness evidence:** `lint` `validate-dataset-measure-aggregates.test.ts:179`, `service-analytics` `dataset-compiler.ts:227`, `objectql` `engine.ts:6206` and `:6272`, `analytics.zod.ts:1002`, `docs/audits/2026-07-unknown-key-strictness-ledger.md:728`, two `packages/spec/CHANGELOG.md` entries and the `liveness/field.json:218` evidence string, which quotes the `engine.ts` comment. None reads a test title. - **Same-text titles named in stage 14's ACCEPT** (`(#15680)`, `(#5955)`, `#3896 close-out`): none falls in this group. ## 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. The declared lines are the three reason-string leaves in `api-methods-batch-conformance.test.ts`. - **Result:** 20 of 20 files SAME on all three legs, as predicted in writing before the run. - **Totals:** 95 changed literals, 92 titles and 3 declared. The diff's `+` and `-` lines are exactly the 95 planned lines, and every file keeps its line count. - **Controls (10 of 10 as predicted, 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; a declared string given a new id VIOLATION; an undeclared `expect` message changed VIOLATION; a title re-split into a `+` chain DIFF. **Test counts:** the 20 files were run at the base, in a separate base worktree, and at the head, with `--project local --project repo`. Both sides read 553 / 553 passed, with the same count and status sequence per file in 20 of 20. 291 full test names change, and each equals the base name with the planned replacements applied (0 mismatches). No full name repeats on either side. ## `main` merged in, once #21800 (the console pin bump) landed while this branch was being verified, and it rewrites the comment block at `:61-77` of `api-methods-batch-conformance.test.ts`. This PR edits only string literals in that file, more than 100 lines below the block, so `origin/main` (`18c2ddc1ec`, which also carries #21801) was merged in with a plain merge, no rebase, and no conflict. The PR's delta against `main` is still exactly the 20 files, +95 / -95. Every reading in this body was re-taken on the merged head `bf16ad1190`, against `18c2ddc1ec` as the base: the census (1325 / 1406 there, 1231 / 1304 here, unchanged by the two commits), the text-only proof and its controls (the three declared lines now sit at `:202`, `:230` and `:235`), the 20-file runs, the full build, the suite, the typecheck and the gates. Re-fetched just before this PR opened, `origin/main` was one commit further (`75ddcd1b41`, #21805, in `cloud-connection`, `metadata-core` and `runtime`). It touches no `packages/spec` path and no file here, so it was not merged. ## Changeset: `skip-changeset` Measured, not assumed: - `npm pack --dry-run` of `@objectstack/spec` lists 2068 files. 0 of the 20 touched files are in it, and no `*.test.ts` at all. Of `src/`, only the `*.zod.ts` sources ship: the controls `src/data/analytics.zod.ts`, `src/data/data-engine.zod.ts` and `dist/data/index.js` are in it. - In the built `dist/`, five new phrases and four old literals each read in 0 files. The control `Unrecognized key(s) on` reads in 42. So this PR publishes nothing, and no changeset is added. ## Verification (at `bf16ad1190`) - `pnpm turbo run build` over all packages: 71 / 71 (also 71 / 71 at the pre-merge head `89c4b300c2`). - `@objectstack/spec`: - `vitest run --project local`: 615 files, 18360 passed, 1 todo. - `typecheck` exit 0, including `check:test-typecheck` (52 files / 246 errors / 135 pinned signatures held). Its program holds all 20 touched files, counted with `tsc --listFilesOnly -p tsconfig.test.json`. - `check:generated`: all 15 generated artifacts up to date after the merge. - **Gates:** `dispatch-gates --commands` derived 79 families, the same set as stages 13 and 14, and all 79 exit 0. `--ran` reconciles: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN. - The five roster families whose rosters sit under a touched directory were also run, and each exits 0: `check:meta-url-spelling`, `check:spec-changes`, `check:authz-resolver`, `check:error-code-casing` and `check:filter-alias-parity`. - **ESLint, a proven narrowing:** `--no-inline-config` over the 20 files reads 0 errors and 0 warnings. The population comes from ESLint's own config: 20 configured, 0 ignored. No file sets `parserOptions.project` or `projectService`, so no untouched file's verdict can move. - `check-governed-merges --test`: NOT governed, 190 changed lines. ## Acceptance notes - **No needle in this group.** Every id was a title or a declared reason string; no expected value of an assertion over a source docblock was found. The three known needles are untouched. - **Same-id test titles in other packages** are their lanes' test-string shares. A search of `describe` / `it` / `test` lines outside `packages/spec` finds 156 lines citing ids this PR handled, in 79 files of 23 packages: `objectql` 73 (29 files), `rest` 18 (7), `runtime` 7 (4), `plugin-security` 6 (5), `cli` 6 (3), `lint` 6 (4), `service-datasource` 6 (3), `driver-sql` 4 (4), `platform-objects` 4 (2), `plugin-approvals` 3 (2), `service-automation` 3 (2), `driver-mongodb` 3 (1), `plugin-auth` 3 (1), `service-analytics` 3 (3), `metadata-core` 2 (1), `plugin-hono-server` 2 (1), and one each in `client`, `triggers`, `core`, `metadata-protocol`, `qa/dogfood`, `types` and `driver-memory`. - **Two spec test files outside `src/`** carry same-id titles: `packages/spec/scripts/file-description.test.ts:66` and `packages/spec/scripts/format-type.test.ts:85`. They are outside class (e) as ruled ("the test strings shipped under `src/`"). - **Numeric delivery fields:** `bulk-write-hook-conformance.test.ts:115-116` and `:129-130` assert `engineDeliveryIssue: 5038` / `5574`, numbers in the source contract table. They are not strings, the gate's pattern cannot see them, and they are not this card's share. - **Code comments still carry ids** in these files and their sources, for example the header of `analytics-strictness-batchd.test.ts` and the `SINGLE_RECORD_WRITE_ONLY` comments in `api-methods-batch-conformance.test.ts`. Comments are not this card's share, and none is touched here. --- _Generated by [Claude Code](https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent dd58618 commit a3ffc45

20 files changed

Lines changed: 95 additions & 95 deletions

‎packages/spec/src/data/aggregate-field-type-compatibility.test.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ describe('AGGREGATE_FIELD_TYPE_COMPATIBILITY — the ruled rows, resolved agains
7878
expect(sorted(AGGREGATE_FIELD_TYPE_COMPATIBILITY.count)).toEqual(sorted(FieldType.options));
7979
});
8080

81-
it('[#20808] `count_distinct`: every FieldType EXCEPT the JSON-stored ones', () => {
81+
it('`count_distinct`: every FieldType EXCEPT the JSON-stored ones', () => {
8282
expect(sorted(AGGREGATE_FIELD_TYPE_COMPATIBILITY.count_distinct))
8383
.toEqual(sorted(FieldType.options.filter((t) => !JSON_STORED.includes(t))));
8484
});
8585

86-
it('[#20808] the JSON-stored bucket IS the field-value structured-JSON class plus the multi-option types', () => {
86+
it('the JSON-stored bucket IS the field-value structured-JSON class plus the multi-option types', () => {
8787
// A type joining either class elsewhere is stored in a JSON column by every
8888
// SQL driver, and no two backends compare such values alike — so it reds
8989
// here until the count_distinct row records a decision.
@@ -147,7 +147,7 @@ describe('isAggregateCompatibleWithFieldType — the pairs the card is about', (
147147
}
148148
});
149149

150-
it('accepts `sum` / `avg` / `min` / `max` over booleans — #11152 (numbers on every backend), upheld by decision batch #80', () => {
150+
it('accepts `sum` / `avg` / `min` / `max` over booleans — numbers on every backend, a ruling that outranks the refused-by-default rule', () => {
151151
for (const fn of ['sum', 'avg', 'min', 'max'] as const) {
152152
expect(isAggregateCompatibleWithFieldType(fn, 'boolean')).toBe(true);
153153
expect(isAggregateCompatibleWithFieldType(fn, 'toggle')).toBe(true);
@@ -181,7 +181,7 @@ describe('isAggregateCompatibleWithFieldType — the pairs the card is about', (
181181
}
182182
});
183183

184-
it('[#20808] accepts `count_distinct` over every scalar-stored type — `formula`, `percent`, `select`, `lookup`, `file` included — and refuses the JSON-stored ones', () => {
184+
it('accepts `count_distinct` over every scalar-stored type — `formula`, `percent`, `select`, `lookup`, `file` included — and refuses the JSON-stored ones', () => {
185185
for (const t of FieldType.options) {
186186
expect(isAggregateCompatibleWithFieldType('count_distinct', t), t).toBe(!JSON_STORED.includes(t));
187187
}

‎packages/spec/src/data/analytics-date-range-closed-vocabulary.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const RETIRED_SPELLINGS = [
5757
'',
5858
];
5959

60-
describe('AnalyticsQuerySchema.timeDimensions[].dateRange — closed vocabulary (#16041)', () => {
60+
describe('AnalyticsQuerySchema.timeDimensions[].dateRange — closed vocabulary', () => {
6161
it('derives the string arm from date-range-presets.ts — no fourth copy of the list', () => {
6262
// The module header records the vocabulary once existed in three drifting
6363
// copies. The enum's options ARE the module's tuple, in its order.

‎packages/spec/src/data/analytics-date-range-two-bound-window.test.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ const REFUSED_ARITIES: ReadonlyArray<readonly unknown[]> = [
6060
['{7_days_ago}'], // one macro token is a bound, not a window
6161
];
6262

63-
describe('AnalyticsDateRangeSchema — the array arm is exactly two string bounds (#17598 ①)', () => {
63+
describe('AnalyticsDateRangeSchema — the array arm is exactly two string bounds', () => {
6464
it('accepts the two-bound windows the contract has always prescribed', () => {
6565
// The control. Without it a narrowing that refused EVERY array would pass
6666
// every refusal assertion below.
@@ -127,7 +127,7 @@ describe('AnalyticsDateRangeSchema — the array arm is exactly two string bound
127127
});
128128
});
129129

130-
describe('analyticsDateRangeRefusalMessage — each ORIGIN gets a true sentence (#17598 ②)', () => {
130+
describe('analyticsDateRangeRefusalMessage — each ORIGIN gets a true sentence', () => {
131131
it('states the schema origin only when the schema is where it was refused', () => {
132132
for (const input of [...REFUSED_ARITIES, 'Last 7 days', 42, null]) {
133133
const atSchema = analyticsDateRangeRefusalMessage(input, 'schema');
@@ -170,7 +170,7 @@ describe('analyticsDateRangeRefusalMessage — each ORIGIN gets a true sentence
170170
expect(analyticsDateRangeRefusalMessage({ start: '2026-01-01' }, 'schema')).toContain('received object');
171171
});
172172

173-
it('⭐ names the EMPTY bound the arm cannot refuse, at the bound that is empty (#18278)', () => {
173+
it('⭐ names the EMPTY bound the arm cannot refuse, at the bound that is empty', () => {
174174
// The premise, asserted rather than assumed: the tuple arm judges arity and
175175
// bound TYPE, never a bound's VALUE, so this window is ACCEPTED at the
176176
// schema door and refused PAST it — the residue

‎packages/spec/src/data/analytics-query-window-integer.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ const ACCEPTED: ReadonlyArray<[string, Record<string, unknown>]> = [
6767
];
6868

6969
for (const [name, schema, base] of DOORS) {
70-
describe(`[#21365] ${name} — the window is a non-negative integer`, () => {
70+
describe(`${name} — the window is a non-negative integer`, () => {
7171
for (const [label, window, key, code] of REFUSED) {
7272
it(`refuses ${label} at \`${key}\``, () => {
7373
const r = schema.safeParse({ ...base, ...window });
@@ -88,7 +88,7 @@ for (const [name, schema, base] of DOORS) {
8888
});
8989
}
9090

91-
describe('[#21365] the dataset selection holds the query\'s own declarations, not a copy', () => {
91+
describe('the dataset selection holds the query\'s own declarations, not a copy', () => {
9292
it('`limit` and `offset` on DatasetSelectionSchema are the AnalyticsQuerySchema instances', () => {
9393
expect(DatasetSelectionSchema.shape.limit).toBe(AnalyticsQuerySchema.shape.limit);
9494
expect(DatasetSelectionSchema.shape.offset).toBe(AnalyticsQuerySchema.shape.offset);

‎packages/spec/src/data/analytics-strictness-batchd.test.ts‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ const QUERY = { cube: 'batchd_probe', measures: ['count'] } as const;
8080
// ===========================================================================
8181
// 1. The doors — a parse must exist, or none of the rest means anything
8282
// ===========================================================================
83-
describe('#4001 batch D — the doors the cube family is reachable through', () => {
83+
describe('batch D, unknown keys refused — the doors the cube family is reachable through', () => {
8484
it('`defineCube()` is a real parse door — it throws on a malformed config', () => {
8585
expect(() => defineCube({ ...CUBE, notACubeKey: 1 } as never)).toThrow(/notACubeKey/);
8686
});
@@ -90,7 +90,7 @@ describe('#4001 batch D — the doors the cube family is reachable through', ()
9090
expect(reject(ObjectStackDefinitionSchema, stack)).toContain('publik');
9191
});
9292

93-
it('[#10194] `analytics_cube` now resolves the SAME schema at the saveMetaItem door', () => {
93+
it('`analytics_cube` now resolves the SAME schema at the saveMetaItem door', () => {
9494
// This pin used to assert the opposite — `getMetadataTypeSchema` answering
9595
// `undefined` — and its comment demanded that the ADR-0010 envelope
9696
// question be re-asked before the line was "fixed". It was: commit 2306a765c bound
@@ -128,7 +128,7 @@ describe('#4001 batch D — the doors the cube family is reachable through', ()
128128
// ===========================================================================
129129
// 2. Every closed site, at its own path, through its real carrier
130130
// ===========================================================================
131-
describe('#4001 batch D — closed sites reject unknown keys where they live', () => {
131+
describe('batch D — closed sites reject unknown keys where they live', () => {
132132
it('`Cube` — the top-level cube shape', () => {
133133
expect(reject(CubeSchema, { ...CUBE, publik: true })).toContain('publik');
134134
});
@@ -245,7 +245,7 @@ describe('#4001 batch D — closed sites reject unknown keys where they live', (
245245
// ===========================================================================
246246
// 3. The curation — each alias anchored to the declaration that makes it true
247247
// ===========================================================================
248-
describe('#4001 batch D — alias claims are true of the surfaces they point at', () => {
248+
describe('batch D, unknown keys refused — alias claims are true of the surfaces they point at', () => {
249249
it('`title` → `label` on Metric/Dimension, and `label` → `title` on Cube: each spelling is CORRECT on the other surface', () => {
250250
// The claims are structural: CubeSchema declares `title`, Metric/Dimension
251251
// declare `label`. If either declaration changes, this pins the alias table
@@ -267,7 +267,7 @@ describe('#4001 batch D — alias claims are true of the surfaces they point at'
267267
expect(reject(AnalyticsQuerySchema, { ...QUERY, orderBy: { stage: 'asc' } })).toContain('order');
268268
});
269269

270-
it('`filters` gets the wrong-layer prescription (`where`), matching the dispatcher\'s #3878 bespoke hint', () => {
270+
it('`filters` gets the wrong-layer prescription (`where`), matching the dispatcher\'s bespoke hint at the /analytics entry', () => {
271271
const issues = reject(AnalyticsQuerySchema, { ...QUERY, filters: { is_active: true } });
272272
expect(issues).toContain('where');
273273
});
@@ -285,7 +285,7 @@ describe('#4001 batch D — alias claims are true of the surfaces they point at'
285285
// ===========================================================================
286286
// 4. The REST wrapper still composes — strictness rides `.extend()` correctly
287287
// ===========================================================================
288-
describe('#4001 batch D — the strict base does not break the request wrapper', () => {
288+
describe('batch D — the strict base does not break the request wrapper', () => {
289289
it('a valid request body still parses through `AnalyticsQueryRequestSchema`', () => {
290290
accept(AnalyticsQueryRequestSchema, {
291291
...QUERY,
@@ -294,7 +294,7 @@ describe('#4001 batch D — the strict base does not break the request wrapper',
294294
});
295295
});
296296

297-
it('the #3878 tombstones still fire — `query` and `format` carry their migration text', () => {
297+
it('the retired-envelope tombstones still fire — `query` and `format` carry their migration text', () => {
298298
expect(reject(AnalyticsQueryRequestSchema, { ...QUERY, query: { measures: ['count'] } })).toContain('was removed from AnalyticsQueryRequest');
299299
expect(reject(AnalyticsQueryRequestSchema, { ...QUERY, format: 'csv' })).toContain('was removed from AnalyticsQueryRequest');
300300
});
@@ -303,8 +303,8 @@ describe('#4001 batch D — the strict base does not break the request wrapper',
303303
// ===========================================================================
304304
// 5. The shapes this batch deliberately did NOT close, with the reason
305305
// ===========================================================================
306-
describe('#4001 batch D — deliberate non-closures (re-verdicts, not omissions)', () => {
307-
it('`LocationValueSchema` / `AddressSchema` are CLOSED since #13802 — the batch-D `open` verdict was overruled', () => {
306+
describe('batch D, unknown keys refused — deliberate non-closures (re-verdicts, not omissions)', () => {
307+
it('`LocationValueSchema` / `AddressSchema` are CLOSED now — the batch-D `open` verdict was overruled', () => {
308308
// Batch D pinned these two as tolerant ("a phone's geolocation payload
309309
// carries `heading`/`speed`; a geocoder's address carries `district`") and
310310
// said the day the line went red, the decision would have been made

‎packages/spec/src/data/analytics.test.ts‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ describe('TimeUpdateInterval', () => {
6666
expect(TimeUpdateInterval.options).toEqual(DateGranularity.options);
6767
});
6868

69-
it('refuses each retired sub-day interval with the retirement prescription (#17296)', () => {
69+
it('refuses each retired sub-day interval with the retirement prescription', () => {
7070
// COST DIRECTION. The cheap narrowing is the enum alone: delete three
7171
// members and let zod answer its stock "invalid option". That parses
7272
// identically and tells an upgrading author nothing, so what is pinned
@@ -147,7 +147,7 @@ describe('MetricSchema', () => {
147147
// `expect(metric.filters).toHaveLength(1)`). The pin flips: the refusal must
148148
// carry the prescription — the fully-qualified key, the removal, and the
149149
// migration channel — not merely throw.
150-
it('rejects the removed `filters` key with the retirement prescription (#10414)', () => {
150+
it('rejects the removed `filters` key with the retirement prescription', () => {
151151
expect(() => MetricSchema.parse({
152152
label: 'Average Order Value',
153153
type: 'avg',
@@ -163,7 +163,7 @@ describe('MetricSchema', () => {
163163
// refused, the key-equal one included, and the refusal carries the
164164
// prescription. The full door-by-door pin lives in
165165
// `cube-member-inner-name-retirement.test.ts`.
166-
it('refuses the retired inner `name` with the prescription, whatever its value (#20300)', () => {
166+
it('refuses the retired inner `name` with the prescription, whatever its value', () => {
167167
for (const name of ['total_revenue', 'TotalRevenue', '']) {
168168
expect(() => MetricSchema.parse({ name, label: 'Total Revenue', type: 'sum', sql: 'amount' }), name)
169169
.toThrow(/`measures\.<metric>\.name` was removed in @objectstack\/spec 17\.5\.0.*the record key is the metric's name.*os migrate meta --from 17/s);
@@ -237,7 +237,7 @@ describe('DimensionSchema', () => {
237237

238238
// #20300 — the same flip as the metric's (see that block): the snake_case
239239
// check on the inner `name` pinned a value nothing read.
240-
it('refuses the retired inner `name` with the prescription, whatever its value (#20300)', () => {
240+
it('refuses the retired inner `name` with the prescription, whatever its value', () => {
241241
for (const name of ['product_category', 'ProductCategory']) {
242242
expect(() => DimensionSchema.parse({ name, label: 'Product Category', type: 'string', sql: 'category' }), name)
243243
.toThrow(/`dimensions\.<dimension>\.name` was removed in @objectstack\/spec 17\.5\.0.*the record key is the dimension's name.*os migrate meta --from 17/s);
@@ -311,7 +311,7 @@ describe('CubeJoinSchema', () => {
311311
* shape). The conversion is `retiredFromLoadPath`, so the AUTHORING funnel still
312312
* teaches the tombstone; the data-at-rest seams pin `includeRetired: true`.
313313
*/
314-
describe('a persisted cube heals at the door (#18612, ADR-0087 D2)', () => {
314+
describe('a persisted cube heals at the door — the retired join `sql` / `relationship` are stripped (ADR-0087 D2)', () => {
315315
/** What `CubeSchema.parse` itself emitted before this retirement. */
316316
const persisted = () => ({
317317
analyticsCubes: [{
@@ -532,7 +532,7 @@ describe('AnalyticsQuerySchema', () => {
532532
}
533533
});
534534

535-
it('should NOT default timezone -- absence means the engine resolves it (#4538)', () => {
535+
it('should NOT default timezone -- absence means the engine resolves it', () => {
536536
const query = AnalyticsQuerySchema.parse({
537537
measures: ['orders.count'],
538538
});

‎packages/spec/src/data/api-derivation.test.ts‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from './api-derivation';
1414
import { ApiMethod, API_OPERATION_ORDER, LEGACY_API_METHODS } from './object.zod';
1515

16-
describe('api-derivation (#3391)', () => {
16+
describe('api-derivation — one table resolves the effective operations from six primitives', () => {
1717
describe('three-state mode', () => {
1818
it('undefined apiMethods → unrestricted', () => {
1919
const eff = resolveEffectiveApiMethods({});
@@ -29,7 +29,7 @@ describe('api-derivation (#3391)', () => {
2929
expect(isApiOperationAllowed(eff, 'bulk')).toBe(true);
3030
});
3131

32-
it('empty array → deny-all (flipped semantics, #3391)', () => {
32+
it('empty array → deny-all (flipped semantics)', () => {
3333
const eff = resolveEffectiveApiMethods({ apiMethods: [] });
3434
expect(eff.mode).toBe('deny-all');
3535
for (const p of API_PRIMITIVES) expect(isApiOperationAllowed(eff, p)).toBe(false);
@@ -95,7 +95,7 @@ describe('api-derivation (#3391)', () => {
9595
expect(isApiOperationAllowed(resolveEffectiveApiMethods({ apiMethods: ['get'], trackHistory: false }), 'history')).toBe(false);
9696
});
9797

98-
it('restore/purge never derive (trash flag retired, #2377)', () => {
98+
it('restore/purge never derive (trash flag retired)', () => {
9999
const eff = resolveEffectiveApiMethods({ apiMethods: ['get', 'list', 'create', 'update', 'delete'] });
100100
expect(isApiOperationAllowed(eff, 'restore')).toBe(false);
101101
expect(isApiOperationAllowed(eff, 'purge')).toBe(false);
@@ -133,7 +133,7 @@ describe('api-derivation (#3391)', () => {
133133
});
134134
});
135135

136-
describe('legacy values are ignored — strip semantics (#3543)', () => {
136+
describe('legacy values are ignored — strip semantics', () => {
137137
it('a whitelist of ONLY legacy values resolves to deny-all', () => {
138138
const eff = resolveEffectiveApiMethods({ apiMethods: ['import'] });
139139
expect(eff.mode).toBe('deny-all');
@@ -159,7 +159,7 @@ describe('api-derivation (#3391)', () => {
159159
});
160160
});
161161

162-
describe('present-but-unreadable policy fails CLOSED (#3545)', () => {
162+
describe('present-but-unreadable policy fails CLOSED', () => {
163163
it('a non-array apiMethods resolves to deny-all, not unrestricted', () => {
164164
const eff = resolveEffectiveApiMethods({ apiMethods: 'get,list' as unknown as string[] });
165165
expect(eff.mode).toBe('deny-all');
@@ -283,7 +283,7 @@ describe('api-derivation (#3391)', () => {
283283
expect(overlap).toEqual([]);
284284
});
285285

286-
describe('vocabulary split (#3543)', () => {
286+
describe('vocabulary split — authors write six primitives, the wire speaks operations', () => {
287287
it('the authored enum is exactly the six primitives', () => {
288288
expect(ApiMethod.options).toEqual([...API_PRIMITIVES]);
289289
});

‎packages/spec/src/data/api-methods-batch-conformance.test.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ const SINGLE_RECORD_WRITE_ONLY: Record<string, string> = {
199199
"ADR-0092 D2's identity write guard admits). No console surface multi-selects " +
200200
'API keys — the grid renders no checkbox column because the object grants no ' +
201201
'delete affordance — and a promoted bulk revoke would fan out per row through ' +
202-
'the action runner rather than hitting /batch (#7802).',
202+
'the action runner rather than hitting /batch.',
203203
// #15873 — maintainer ruling 2026-09-07 (decision batch #64, option (a),
204204
// verbatim 「同意」): the data door admits `update` so an administrator can set
205205
// the four platform-owned columns (`require_mfa`, `parent_organization_id`,
@@ -227,12 +227,12 @@ const SINGLE_RECORD_WRITE_ONLY: Record<string, string> = {
227227
// both stand.
228228
sys_organization:
229229
'Administrators set the platform-owned columns through single-record PATCH ' +
230-
'and the derived update-mode import door (#15873 ruled `update`; both are ' +
230+
'and the derived update-mode import door (a ruling grants `update`; both are ' +
231231
'column-clamped per row by ADR-0092 D2). `bulk` — /batch and the *Many ' +
232232
'routes — is not granted: no console surface multi-selects organizations ' +
233233
'(the list view declares no bulk actions and the object grants no delete ' +
234234
'affordance), and a promoted bulk edit would fan out per row through the ' +
235-
'action runner rather than hitting /batch (#7802).',
235+
'action runner rather than hitting /batch.',
236236
};
237237

238238
/** Every `*.object.ts` under `packages/`, skipping build output and deps. */
@@ -292,7 +292,7 @@ function collectWhitelists(): Whitelist[] {
292292

293293
const WHITELISTS = collectWhitelists();
294294

295-
describe('apiMethods conformance — single-record writes imply batch (#3026)', () => {
295+
describe('apiMethods conformance — single-record writes imply batch', () => {
296296
it('scans a plausible number of declarations (guards a silently empty sweep)', () => {
297297
// A scan that matches nothing passes every assertion below vacuously — the
298298
// exact failure mode this file exists to prevent. Pin a floor instead.

0 commit comments

Comments
 (0)