Skip to content

Commit a14f3e6

Browse files
test(floors, ui): one shared floor per ui package population, one catalog entry floor, all at about two thirds (#26576)
<!-- claude-projects-attribution: {"github_login":"os-steve"} --> _Requested by **Steve** · [project thread](https://claude.ai/code/project/chan_01FdL1XeUyvVNxLreh3F4Qi9?thread=cmsg_01FdL1XeUyvVNxLreh3F4Qi98CkpE4eCgM4NDygyDXH8Pt)_ Fixes #26521 Clause-②: no Metadata-protocol: none The ui half of #26444 (the parent stays open for its CLI and baseline halves). No changeset: every edit is to a test, a test helper, a repo-internal gate script under `ui/scripts/` or `ui/QUICK_REFERENCE.md`, none of which any package ships; the PR carries `skip-changeset`. ## 维护者速读 - 改了什么:ui 包数量的防空值底线原先在约 8 处各写一遍、都贴着今天的实测值;现在每个包总体只在 `ui/scripts/__tests__/helpers/ui-package-population.mjs` 写一次,取实测值约三分之二,两个门禁脚本的 `MIN_PACKAGES` 和全部测试点都读它;schema-catalog 的条目底线收成 `catalog-entry-floor.ts` 一处(原来 8 处三个值)。`ui/QUICK_REFERENCE.md` 删掉手写的「35 published packages」,测试改为拒绝手写数字。 - 为什么改:#26444 的规则:底线只防空扫描,不是普查;删一个包、一个目录条目不该让任何底线变红(#26343 删一个包改了五处底线)。 - 风险与回滚:只改测试、测试辅助、仓内门禁脚本和一行文档,不发布任何东西。底线变松但每条仍在清空总体时变红(下方 31 条断言实测)。回滚 = revert 本 PR。 - 先看:`ui/scripts/__tests__/helpers/ui-package-population.mjs`(实测表与五个底线)、`ui/examples/schema-catalog/test/catalog-entry-floor.ts`、`ui/scripts/__tests__/quick-reference-commands-4149.test.ts`(改写的那条测试)。 - 两分钟验证:`cd ui && pnpm exec vitest run scripts/__tests__/package-files-exist.test.ts scripts/__tests__/quick-reference-commands-4149.test.ts`,预期两文件全绿。 - 需要你做的:无,席位落地。 ## Why #26444's rule: an anti-vacuity floor refuses an empty scan; it is not a census. Floors set at today's measured value red on every legitimate deletion, and #26343 edited five floors to delete one ui package. Each floor now sits at about two thirds of its measurement and is written once per population. ## What changes **One floor per ui package population, written once.** New `ui/scripts/__tests__/helpers/ui-package-population.mjs` holds the anti-vacuity floors with the table they were measured from. It is an `.mjs` module rather than a `.ts` helper like its neighbours because the two gate scripts import it under plain `node`. Each floor is about two thirds of the value measured on `origin/main` `6a7c0fe3` (right after #26483 made `@object-ui/app-shell` private), the `vite-dts-wiring-ratchet` precedent: | floor | population | measured @ 6a7c0fe | floor | margin | |:---|:---|---:|---:|---:| | `UI_PUBLISHED_PACKAGE_FLOOR` | published packages (release group) | 36 | 24 | 12 | | `UI_WORKSPACE_MEMBER_FLOOR` | manifests under `packages/*`, `apps/*`, `examples/*` | 43 | 28 | 15 | | `UI_SIDE_EFFECTS_FALSE_FLOOR` | packages declaring `sideEffects: false` | 11 | 7 | 4 | | `UI_SIDE_EFFECTS_ARRAY_FLOOR` | packages declaring a `sideEffects` array | 17 | 11 | 6 | | `UI_TSC_BUILT_PACKAGE_FLOOR` | tsc-built packages | 11 | 7 | 4 | The card asked for one shared constant; the published-package floor is that constant and every site whose population is the published set or a superset of it reads it. Four sites count genuinely smaller or larger populations (the two `sideEffects` groups, the tsc-built packages, all workspace members); a 24 there would either red today (11, 17) or sit far under two thirds (43), so each of those has its own floor in the same module, still written once. See open question 1 in the report. Every site, its measured value and its margin: | site | was | measured | now | margin | |:---|---:|---:|---:|---:| | `check-node-esm-load.mjs` `MIN_PACKAGES` | 30 | 36 | published floor 24 | 12 | | `check-published-dist-tooling.mjs` `MIN_PACKAGES` | 30 | 36 | published floor 24 | 12 | | `package-files-exist` packages declaring `files` | 38 | 39 | published floor 24 | 15 | | `package-files-exist` `files` entries | 150 | 153 | 100 | 53 | | `package-files-exist` packages owing license text | 36 | 36 | published floor 24 | 12 | | `package-files-exist` packages declaring `exports` | 36 | 38 | published floor 24 | 14 | | `package-files-exist` `exports` targets | 130 | 150 | 100 | 50 | | `side-effects-declaration-consistency` declaring | 28 | 28 | false + array floors = 18 | 10 | | `side-effects-declaration-consistency` `false` | 11 | 11 | 7 | 4 | | `side-effects-declaration-consistency` array | 17 | 17 | 11 | 6 | | `check-dist-completeness` tsc-built packages | 11 | 11 | 7 | 4 | | `zero-test-member-exclusion-9106` members | 40 | 43 | member floor 28 | 15 | | `zero-test-member-exclusion-9106` members with a test script and files | 40 | 41 | member floor 28 | 13 | | `check-doc-links` `examples` READMEs | 3 | 3 | 2 | 1 | | `check-doc-links` `packages/*/README.md` | 35 | 39 | published floor 24 | 15 | | `quick-reference-commands-4149` published under `packages/` | exact prose | 35 | published floor 24 (anti-vacuity) | 11 | The two entry-count floors (`files` entries, `exports` targets) and the example-README floor count entries, not packages, so they stay local at two thirds of their own measurement. **`ui/QUICK_REFERENCE.md` drops its hand-written count.** The `packages/*` row now reads "The published `@object-ui/*` packages, plus the private ..." and still names the four private packages. Its test no longer requires the row to state `N published`; it refuses any `N published` / `N packages` figure in the row, keeps the anti-vacuity floor under the derived population, and keeps the private-package check (its failure text reworded for a row without a number). **One schema-catalog entry floor, in one place.** New `ui/examples/schema-catalog/test/catalog-entry-floor.ts` exports `CATALOG_ENTRY_FLOOR = 288` (432 entries measured, margin 144). It replaces the card's four sites (431 ×3, 423 ×1) and four more spellings of the same population the card did not list (`component-fixture-declared-keys.test.ts`, `allExamples().length > 400` ×3 and `entries.length > 400` ×1). The helper lives in the catalog package's own `test/` because a test there importing from `ui/scripts/` would read outside its package. **Per-type catalog floors in the same four files, fixed in place.** The same tests pin per-type censuses at exactly today's count, so deleting one badge or card demo would red them. Same defect class, same files, mechanical two-thirds edit, so they moved in place: | site | measured | now | margin | |:---|---:|---:|---:| | `catalog-authored-key-6805-6806` `scroll-area` nodes (`minNodes`) | 7 | 5 | 2 | | `catalog-authored-key-6805-6806` `badge` nodes (`minNodes`) | 40 | 27 | 13 | | `card-demo-content-6788` cards | 93 | 62 | 31 | | `card-demo-content-6788` card categories | 19 | 13 | 6 | | `badge-demo-label-6829` badges | 40 | 27 | 13 | | `badge-demo-label-6829` badge categories | 12 | 8 | 4 | | `component-fixture-declared-keys` select options | 66 | 44 | 22 | | `component-fixture-declared-keys` option categories | 7 | 5 | 2 | | `catalog-gallery-render` plugin categories | 13 | 9 | 4 | The plugin-category floor counts ui plugin packages with catalog entries, so retiring one plugin package would have redded it. ### Forced test edits - `ui/scripts/__tests__/check-node-esm-load.test.ts` "keeps a floor under both legs": it pinned `MIN_PACKAGES >= 30`, a ninth spelling of the population. It now pins `MIN_PACKAGES` to the shared floor and keeps `> 0`. - `ui/scripts/__tests__/quick-reference-commands-4149.test.ts`: rewritten as described above, because the card deletes the prose number it asserted. ## Tests At head `0c64d31a`, all under `scripts/pm/os-verify-lock.sh`: - The 14 touched or reading test files (the six `ui/scripts/__tests__` sites, `check-node-esm-load`, `check-published-dist-tooling`, `check-published-tsconfig-tooling-exclude`, and the five schema-catalog files): Test Files 14 passed (14), Tests 1143 passed (1143). VERDICT command-exit 0. - `pnpm --dir ui exec vitest run scripts/ --maxWorkers=2`: Test Files 178 passed, 2 skipped (180); Tests 5057 passed, 2 skipped. VERDICT command-exit 0. - `pnpm --dir ui type-check:scripts` (the program holding the new `.mjs` and every `ui/scripts` test): VERDICT command-exit 0. <details><summary>Emptied population: every floor still goes red (31 assertions)</summary> A one-shot mutation, restored from `HEAD` by a trap and confirmed by an empty `git diff HEAD` afterwards: at each of the 30 floor sites in the eleven test files the measured population was replaced by `0` (`expect.soft(0, "EMPTIED ...")`), so every floor is read against an empty population in one run. Result: Test Files 11 failed (11), and 31 assertions red, one per floor (the `minNodes` loop yields two). Examples from the log: - `EMPTIED packagesWithFiles.length: expected 0 to be greater than or equal to 24` - `EMPTIED members.length: expected 0 to be greater than or equal to 28` - `EMPTIED published.length: expected 0 to be greater than or equal to 24` (QUICK_REFERENCE) - `EMPTIED entries.length: expected 0 to be greater than or equal to 288` (×5) and `EMPTIED allExamples().length: ... 288` (×3) - `no plugin categories were derived, so this case would be vacuous: expected 0 to be greater than or equal to 9` The two gate scripts' own collapse refusal (fewer than `MIN_PACKAGES` published packages found) is covered by the existing `check-published-tsconfig-tooling-exclude` case that pads a fixture below `MIN_PACKAGES` and asserts the `scan-collapsed` finding naming the number; it is green at the new value. </details> <details><summary>Measurement method</summary> The measured values were read on `6a7c0fe3` by a throwaway mutation that turned each floor into `expect.soft(population).toBe(-1)` and read the actual values from the failures, restored from `HEAD` afterwards. `MIN_PACKAGES`' population was read by calling each script's own discovery (`discoverPackages(...).filter(not private)` and `discoverPublishedPackages`): 36 each. </details> ## Acceptance notes - **Deleting one ui package or one catalog entry reds no floor** above: every margin is at least 1 (the example-README floor, 3 → 2) and the package floors' margins are at least 4. - **Left as they are, deliberately.** `layout-props-conversion.test.tsx`: layout nodes 430 (447 measured) has a margin; `withClassName` 175 (182 measured) says in its own comment it is deliberately tighter after a ruled sweep; the 153 stack-node count is the census of a ruled `spacing` → `gap` rename, a transcription pin rather than an anti-vacuity floor (the class #26431 owns). `badge-demo-label-6829` `CONTAINER_CHILDREN_FLOOR` 600 (660 measured) and `catalog-authored-key-6805-6806` text-content 600 (659 measured) have margins. Exact `toHaveLength` pins on fixed demos are not floors. - `#26365` (plugin-ai retirement) edits the QUICK_REFERENCE count and `package-files-exist` floors too; whichever lands second merges main. After this PR it needs to touch neither. - The new helper sits under `ui/scripts/__tests__/helpers/` as the claim's file surface names; the two gate scripts importing from there is the one oddity, and the alternative (a sibling of `workspace-root.mjs` in `ui/scripts/`) is open question 2 in the report. ## Verification <details><summary>dispatch-gates: 20 derived, 20 run, 0 NOT MEASURED</summary> `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` at `0c64d31a` derived 20 families; each was run after the last commit with its exit code captured before any pipe: - exit 0: `check-closing-keyword-parity` (and `--self-test`), `check-comment-mask-corpus` (18349 files, 0 disagree), `check:cross-package-test-inputs`, `check:dispatcher-error-vocabulary`, `check:driver-memory-census`, `check:engine-double-contract`, `check:gitlink-declared`, `check:nul-bytes`, `check:published-files`, `check:query-options-erasure`, `check:refd-timer-probe`, `check:test-source-alias`, `check:tier-file-adoption`, `check:type-check-coverage`, `check:type-check-debt`, `check:undeclared-dep-imports`, `check:watch-hint-literal`, `check:where-matcher`, and `pnpm --dir ui exec vitest run scripts/` (above). - `--ran`: `20 derived famil(ies) accounted for — 20 run, 0 NOT-MEASURED (a DERIVED zero — all 20 recorded an exit code and none of them is 3)`. </details> - NOT MEASURED: `@object-ui/example-schema-catalog` `type-check` on built dependencies. A local `tsc -p tsconfig.test.json` without the `@object-ui/*` builds prints 171 errors, all unresolved-module noise from unbuilt packages (81 TS2307, 62 TS2882 and their implicit-any fallout); none names `catalog-entry-floor.ts` or an edited line. CI `Type Check UI` is the reading. - Every family CI runs is read from this PR's check runs; none was re-run locally to stand in for them. ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (not touched) - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` passes. (lint is CI's run) - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. (publishes nothing: `skip-changeset`) - [x] 6. `packages/spec` touched: n/a. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01ADHkmTNh6kDC6Lu2Yr7s5v --- _Generated by [Claude Code](https://claude.ai/code/session_01ADHkmTNh6kDC6Lu2Yr7s5v)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8e9abd9 commit a14f3e6

17 files changed

Lines changed: 220 additions & 98 deletions

‎ui/QUICK_REFERENCE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ pnpm changeset publish # Publish to npm (CI only)
8282

8383
| Path | Purpose |
8484
| --- | --- |
85-
| `packages/*` | 35 published packages (`@object-ui/*`), plus the private `vscode-extension`, `test-support` (test-only, never released), `runner` (workspace demo app, never released) and `app-shell` (the Console's shell and views, no longer published after 18.2.0) |
85+
| `packages/*` | The published `@object-ui/*` packages, plus the private `vscode-extension`, `test-support` (test-only, never released), `runner` (workspace demo app, never released) and `app-shell` (the Console's shell and views, no longer published after 18.2.0) |
8686
| `apps/console` | Full ObjectUI console app (Vite + React) |
8787
| `apps/site` | Public docs site at <https://www.objectui.org> (fumadocs) |
8888
| `examples/*` | Runnable examples and the schema catalog — see [`examples/README.md`](./examples/README.md) |

‎ui/examples/schema-catalog/test/badge-demo-label-6829.test.tsx‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ import { render } from '@testing-library/react';
119119
import '@object-ui/components';
120120
import { SchemaRenderer, toRenderableSchema } from '@object-ui/react';
121121
import { allExamples, getExample } from '../src/index.js';
122+
import { CATALOG_ENTRY_FLOOR } from './catalog-entry-floor.js';
122123

123124
type Json = Record<string, unknown>;
124125

@@ -245,10 +246,12 @@ const containers = entries.flatMap((entry) =>
245246
describe('catalog corpus: every `badge` node draws its authored `label` (objectui#6829 arm A)', () => {
246247
it('the walk is not vacuous — a broken collector would pass every case below', () => {
247248
// Floors, not equalities: catalog growth must not fail this file, only a
248-
// walk that stopped working.
249-
expect(entries.length).toBeGreaterThanOrEqual(431);
250-
expect(badges.length).toBeGreaterThanOrEqual(40);
251-
expect(new Set(badges.map((b) => b.where.split('/')[0])).size).toBeGreaterThanOrEqual(12);
249+
// walk that stopped working. About two thirds of the counts measured on
250+
// objectstack 6a7c0fe3 (40 badges in 12 categories), so deleting an entry
251+
// does not fail it either.
252+
expect(entries.length).toBeGreaterThanOrEqual(CATALOG_ENTRY_FLOOR);
253+
expect(badges.length).toBeGreaterThanOrEqual(27);
254+
expect(new Set(badges.map((b) => b.where.split('/')[0])).size).toBeGreaterThanOrEqual(8);
252255
// …and it sees the seven nodes this card is about, by location.
253256
expect(badges.map((b) => b.where)).toEqual(expect.arrayContaining(REAUTHORED_NODES));
254257
});

‎ui/examples/schema-catalog/test/card-demo-content-6788.test.tsx‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ import '@object-ui/components';
124124
import { SchemaRenderer, toRenderableSchema } from '@object-ui/react';
125125
import { CardSchema } from '@object-ui/types/zod';
126126
import { allExamples } from '../src/index.js';
127+
import { CATALOG_ENTRY_FLOOR } from './catalog-entry-floor.js';
127128

128129
type Json = Record<string, unknown>;
129130

@@ -213,11 +214,13 @@ function unreadKeys(node: Json, allowed: readonly string[]): string[] {
213214

214215
describe('catalog corpus: every `card` node authors keys `ui:card` reads (objectui#6788)', () => {
215216
it('the walk is not vacuous — a broken collector would pass every case below', () => {
216-
// Measured on d06059f24; these are floors, not equalities, so growth of
217-
// the catalog does not fail the file — only a walk that stopped working.
218-
expect(entries.length).toBeGreaterThanOrEqual(431);
219-
expect(cards.length).toBeGreaterThanOrEqual(93);
220-
expect(new Set(cards.map((c) => c.where.split('/')[0])).size).toBeGreaterThanOrEqual(19);
217+
// Floors, not equalities, so growth of the catalog does not fail the file —
218+
// only a walk that stopped working. About two thirds of the counts measured
219+
// on objectstack 6a7c0fe3 (93 cards in 19 categories), so deleting an entry
220+
// does not fail it either.
221+
expect(entries.length).toBeGreaterThanOrEqual(CATALOG_ENTRY_FLOOR);
222+
expect(cards.length).toBeGreaterThanOrEqual(62);
223+
expect(new Set(cards.map((c) => c.where.split('/')[0])).size).toBeGreaterThanOrEqual(13);
221224
});
222225

223226
it('every authored key is DECLARED by the shipped CardSchema', () => {

‎ui/examples/schema-catalog/test/catalog-authored-key-6805-6806.test.tsx‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ import { render } from '@testing-library/react';
117117
import '@object-ui/components';
118118
import { SchemaRenderer, toRenderableSchema } from '@object-ui/react';
119119
import { allExamples } from '../src/index.js';
120+
import { CATALOG_ENTRY_FLOOR } from './catalog-entry-floor.js';
120121

121122
type Json = Record<string, unknown>;
122123

@@ -150,7 +151,8 @@ const RENDERERS = [
150151
readKeys: ['type', 'orientation', 'height', 'width', 'className', 'children'],
151152
contentKey: 'children',
152153
issue: 'objectui#6805',
153-
minNodes: 7,
154+
// About two thirds of the 7 measured on objectstack 6a7c0fe3.
155+
minNodes: 5,
154156
},
155157
{
156158
type: 'badge',
@@ -161,7 +163,8 @@ const RENDERERS = [
161163
readKeys: ['type', 'label', 'variant', 'className', 'body'],
162164
contentKey: 'label',
163165
issue: 'objectui#6806',
164-
minNodes: 40,
166+
// About two thirds of the 40 measured on objectstack 6a7c0fe3.
167+
minNodes: 27,
165168
},
166169
] as const;
167170

@@ -256,8 +259,9 @@ const nodesOf = (type: string): Located[] =>
256259
describe('catalog corpus: every node authors keys ITS renderer reads (objectui#6805 + objectui#6806)', () => {
257260
it('the walk is not vacuous — a broken collector would pass every case below', () => {
258261
// Floors, not equalities: catalog growth must not fail this file, only a
259-
// walk that stopped working.
260-
expect(entries.length).toBeGreaterThanOrEqual(431);
262+
// walk that stopped working — and at about two thirds of the measured
263+
// counts, so deleting an entry does not fail it either.
264+
expect(entries.length).toBeGreaterThanOrEqual(CATALOG_ENTRY_FLOOR);
261265
for (const renderer of RENDERERS) {
262266
expect(nodesOf(renderer.type).length).toBeGreaterThanOrEqual(renderer.minNodes);
263267
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* The ONE anti-vacuity floor for the size of the catalog (`allExamples()`), read
3+
* by every test here that guards its own sweep against an empty corpus.
4+
*
5+
* A floor, not a census: it answers "did the collector find a corpus at all?",
6+
* so catalog growth never moves it and neither does deleting an entry. It sits
7+
* at about two thirds of the 432 entries measured on objectstack `origin/main`
8+
* `6a7c0fe3` (the `vite-dts-wiring-ratchet` precedent: measured 22, floor 15).
9+
* Before it existed the same population was pinned at three different values
10+
* across eight call sites, the tightest one entry under the measured count.
11+
*
12+
* Re-measure only when the corpus has shrunk to near it, and then move it to
13+
* about two thirds of the new reading. ⛔ Never raise it to track growth.
14+
*/
15+
export const CATALOG_ENTRY_FLOOR = 288;

‎ui/examples/schema-catalog/test/catalog-gallery-render.test.tsx‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ import { SchemaRenderer, SchemaRendererContext, toRenderableSchema } from '@obje
149149
import fs from 'node:fs';
150150
import path from 'node:path';
151151
import { allExamples } from '../src/index.js';
152+
import { CATALOG_ENTRY_FLOOR } from './catalog-entry-floor.js';
152153

153154
/**
154155
* The repo root, derived from THIS FILE's own location — never from
@@ -646,7 +647,7 @@ describe('objectui#4616 — every catalog entry renders in the docs gallery', ()
646647
* size and the registration set the sweep depends on.
647648
*/
648649
it('the corpus is populated and every package the census needs is loaded', () => {
649-
expect(entries.length).toBeGreaterThanOrEqual(423);
650+
expect(entries.length).toBeGreaterThanOrEqual(CATALOG_ENTRY_FLOOR);
650651
// One type per package below, chosen as the one the census actually needed.
651652
for (const type of [
652653
'dashboard',
@@ -1345,7 +1346,9 @@ describe('objectui#6025 — the gallery DECLARES the packages its entries need',
13451346
expect(
13461347
PLUGIN_CATEGORIES.length,
13471348
'no plugin categories were derived, so this case would be vacuous',
1348-
).toBeGreaterThanOrEqual(13);
1349+
// About two thirds of the 13 measured on objectstack 6a7c0fe3: retiring a
1350+
// plugin package (and its category) must not red an anti-vacuity floor.
1351+
).toBeGreaterThanOrEqual(9);
13491352

13501353
const undeclared = PLUGIN_CATEGORIES.map((category) => `@object-ui/${category}`).filter(
13511354
(pkg) => !HOST_PACKAGES.includes(pkg),

‎ui/examples/schema-catalog/test/component-fixture-declared-keys.test.ts‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ import {
8787
} from '@object-ui/types/zod';
8888
import { enumOptions } from '@object-ui/test-support';
8989
import { allExamples, getExample } from '../src/index.js';
90+
import { CATALOG_ENTRY_FLOOR } from './catalog-entry-floor.js';
9091

9192
type Json = Record<string, unknown>;
9293

@@ -280,7 +281,7 @@ describe('catalog corpus: no fixture hangs an action object off a handler key (o
280281
expect(handlers.map((h) => h.where)).toContain(
281282
'components-feedback-toaster/with-toast-trigger.children[0].onClick',
282283
);
283-
expect(entries.length).toBeGreaterThan(400);
284+
expect(entries.length).toBeGreaterThanOrEqual(CATALOG_ENTRY_FLOOR);
284285
});
285286

286287
it('every handler value in the corpus is a string expression, never an action object', () => {
@@ -565,7 +566,7 @@ describe('catalog corpus: every menubar item uses the declared MenuItem spelling
565566
]),
566567
);
567568
expect(items).toHaveLength(13);
568-
expect(allExamples().length).toBeGreaterThan(400);
569+
expect(allExamples().length).toBeGreaterThanOrEqual(CATALOG_ENTRY_FLOOR);
569570
});
570571

571572
it('the walker descends into submenu `children` — synthetic positive control', () => {
@@ -773,7 +774,7 @@ describe('catalog corpus: no overlay-menu item authors the undeclared `value` ke
773774
// below. 25 items = menubar 13 + basic-context-menu 5 + basic-dropdown-menu
774775
// 4 + with-icons 3.
775776
expect(items).toHaveLength(25);
776-
expect(allExamples().length).toBeGreaterThan(400);
777+
expect(allExamples().length).toBeGreaterThanOrEqual(CATALOG_ENTRY_FLOOR);
777778

778779
// One representative position per container shape, including the deeper
779780
// `menus[].items[]` nesting only `menubar` has.
@@ -935,11 +936,12 @@ describe('catalog corpus: no `select` option authors the undeclared `type` key (
935936

936937
it('the sweep reaches every select option in the corpus — non-vacuity', () => {
937938
// Floors, not equalities: catalog growth must not fail this file, only a
938-
// walker that stopped working. 66 options on 19 select nodes across 7
939-
// categories at `b6e83be6a`.
940-
expect(options.length).toBeGreaterThanOrEqual(66);
941-
expect(new Set(options.map((o) => o.where.split('/')[0])).size).toBeGreaterThanOrEqual(7);
942-
expect(allExamples().length).toBeGreaterThan(400);
939+
// walker that stopped working. About two thirds of the 66 options across 7
940+
// categories measured on objectstack 6a7c0fe3, so deleting an entry does
941+
// not fail it either.
942+
expect(options.length).toBeGreaterThanOrEqual(44);
943+
expect(new Set(options.map((o) => o.where.split('/')[0])).size).toBeGreaterThanOrEqual(5);
944+
expect(allExamples().length).toBeGreaterThanOrEqual(CATALOG_ENTRY_FLOOR);
943945

944946
// One representative position per authoring shape, including the two
945947
// nesting depths a shallow walker would silently miss: a select inside a

‎ui/scripts/__tests__/check-dist-completeness.test.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { describe, expect, it } from 'vitest';
22
import { uiTurboConfigPath } from '../workspace-root.mjs';
3+
import { UI_TSC_BUILT_PACKAGE_FLOOR } from './helpers/ui-package-population.mjs';
34
import fs from 'node:fs';
45
import os from 'node:os';
56
import path from 'node:path';
@@ -269,7 +270,9 @@ describe('this repository', () => {
269270
const tscPackages = discoverTscPackages(repoRoot) as Array<{ name: string; dir: string }>;
270271

271272
it('finds the tsc-built packages', () => {
272-
expect(tscPackages.length).toBeGreaterThanOrEqual(11);
273+
// A floor against an empty walk, not a census: about two thirds of the 11
274+
// measured on objectstack 6a7c0fe3, so retiring a package leaves it green.
275+
expect(tscPackages.length).toBeGreaterThanOrEqual(UI_TSC_BUILT_PACKAGE_FLOOR);
273276
});
274277

275278
it.each(tscPackages.map((p) => [p.name, p.dir] as const))(

‎ui/scripts/__tests__/check-doc-links.test.ts‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
stripCode,
2323
} from '../check-doc-links.mjs';
2424
import { GithubSlugger as VendoredSlugger, slug as vendoredSlug } from '../github-slug.mjs';
25+
import { UI_PUBLISHED_PACKAGE_FLOOR } from './helpers/ui-package-population.mjs';
2526

2627
/**
2728
* objectui#3479 — the behaviour test for `scripts/check-doc-links.mjs`.
@@ -514,16 +515,18 @@ describe('the repo it guards', () => {
514515
expect(scanned['README.md']).toBe(1);
515516
expect(scanned['CONTRIBUTING.md']).toBe(1);
516517
expect(scanned['ROADMAP.md']).toBe(1);
517-
// Three READMEs since the two host-console examples were deleted (#25922):
518-
// the index, hello-world and schema-catalog.
519-
expect(scanned['examples']).toBeGreaterThanOrEqual(3);
518+
// A floor against an empty scan, not a census: three READMEs today (the
519+
// index, hello-world and schema-catalog, measured on objectstack 6a7c0fe3),
520+
// so deleting one example leaves it green.
521+
expect(scanned['examples']).toBeGreaterThanOrEqual(2);
520522
expect(scanned['docs']).toBeGreaterThanOrEqual(15);
521523
expect(scanned['content/docs']).toBeGreaterThanOrEqual(100);
522-
// objectui#3622. 38 of the 39 package directories carry a README today
523-
// (`sdui-parser` does not), and this row is the only one whose path needs
524-
// expanding before anything is opened — so a floor here is also the floor
525-
// under `expandWildcard()`.
526-
expect(scanned['packages/*/README.md']).toBeGreaterThanOrEqual(35);
524+
// objectui#3622. This row is the only one whose path needs expanding before
525+
// anything is opened, so a floor here is also the floor under
526+
// `expandWildcard()`. Every published package carries a README, so the
527+
// shared published-package floor bounds it (39 READMEs measured on
528+
// objectstack 6a7c0fe3); deleting a package moves no floor.
529+
expect(scanned['packages/*/README.md']).toBeGreaterThanOrEqual(UI_PUBLISHED_PACKAGE_FLOOR);
527530
// objectui#4148. Both apps carry one today; the floor is 2 rather than the
528531
// exact count because this row exists precisely so the NEXT app is scanned
529532
// without anyone editing the table.

‎ui/scripts/__tests__/check-node-esm-load.test.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import fs from 'node:fs';
33
import os from 'node:os';
44
import path from 'node:path';
55
import { fileURLToPath } from 'node:url';
6+
import { UI_PUBLISHED_PACKAGE_FLOOR } from './helpers/ui-package-population.mjs';
67

78
import {
89
ESM_MODULE_EDGE,
@@ -448,7 +449,10 @@ describe('the load leg evaluates rather than resolves', () => {
448449

449450
describe('the gate cannot be green about nothing', () => {
450451
it('keeps a floor under both legs', () => {
451-
expect(MIN_PACKAGES).toBeGreaterThanOrEqual(30);
452+
// The package floor is the shared ui published-package floor, not a number of
453+
// its own: re-measuring the population moves it in one place for every reader.
454+
expect(MIN_PACKAGES).toBe(UI_PUBLISHED_PACKAGE_FLOOR);
455+
expect(MIN_PACKAGES).toBeGreaterThan(0);
452456
expect(MIN_LOADED).toBeGreaterThan(0);
453457
});
454458

0 commit comments

Comments
 (0)