Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ui/QUICK_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pnpm changeset publish # Publish to npm (CI only)

| Path | Purpose |
| --- | --- |
| `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) |
| `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) |
| `apps/console` | Full ObjectUI console app (Vite + React) |
| `apps/site` | Public docs site at <https://www.objectui.org> (fumadocs) |
| `examples/*` | Runnable examples and the schema catalog — see [`examples/README.md`](./examples/README.md) |
Expand Down
11 changes: 7 additions & 4 deletions ui/examples/schema-catalog/test/badge-demo-label-6829.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ import { render } from '@testing-library/react';
import '@object-ui/components';
import { SchemaRenderer, toRenderableSchema } from '@object-ui/react';
import { allExamples, getExample } from '../src/index.js';
import { CATALOG_ENTRY_FLOOR } from './catalog-entry-floor.js';

type Json = Record<string, unknown>;

Expand Down Expand Up @@ -245,10 +246,12 @@ const containers = entries.flatMap((entry) =>
describe('catalog corpus: every `badge` node draws its authored `label` (objectui#6829 arm A)', () => {
it('the walk is not vacuous — a broken collector would pass every case below', () => {
// Floors, not equalities: catalog growth must not fail this file, only a
// walk that stopped working.
expect(entries.length).toBeGreaterThanOrEqual(431);
expect(badges.length).toBeGreaterThanOrEqual(40);
expect(new Set(badges.map((b) => b.where.split('/')[0])).size).toBeGreaterThanOrEqual(12);
// walk that stopped working. About two thirds of the counts measured on
// objectstack 6a7c0fe3 (40 badges in 12 categories), so deleting an entry
// does not fail it either.
expect(entries.length).toBeGreaterThanOrEqual(CATALOG_ENTRY_FLOOR);
expect(badges.length).toBeGreaterThanOrEqual(27);
expect(new Set(badges.map((b) => b.where.split('/')[0])).size).toBeGreaterThanOrEqual(8);
// …and it sees the seven nodes this card is about, by location.
expect(badges.map((b) => b.where)).toEqual(expect.arrayContaining(REAUTHORED_NODES));
});
Expand Down
13 changes: 8 additions & 5 deletions ui/examples/schema-catalog/test/card-demo-content-6788.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ import '@object-ui/components';
import { SchemaRenderer, toRenderableSchema } from '@object-ui/react';
import { CardSchema } from '@object-ui/types/zod';
import { allExamples } from '../src/index.js';
import { CATALOG_ENTRY_FLOOR } from './catalog-entry-floor.js';

type Json = Record<string, unknown>;

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

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

it('every authored key is DECLARED by the shipped CardSchema', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ import { render } from '@testing-library/react';
import '@object-ui/components';
import { SchemaRenderer, toRenderableSchema } from '@object-ui/react';
import { allExamples } from '../src/index.js';
import { CATALOG_ENTRY_FLOOR } from './catalog-entry-floor.js';

type Json = Record<string, unknown>;

Expand Down Expand Up @@ -150,7 +151,8 @@ const RENDERERS = [
readKeys: ['type', 'orientation', 'height', 'width', 'className', 'children'],
contentKey: 'children',
issue: 'objectui#6805',
minNodes: 7,
// About two thirds of the 7 measured on objectstack 6a7c0fe3.
minNodes: 5,
},
{
type: 'badge',
Expand All @@ -161,7 +163,8 @@ const RENDERERS = [
readKeys: ['type', 'label', 'variant', 'className', 'body'],
contentKey: 'label',
issue: 'objectui#6806',
minNodes: 40,
// About two thirds of the 40 measured on objectstack 6a7c0fe3.
minNodes: 27,
},
] as const;

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

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

const undeclared = PLUGIN_CATEGORIES.map((category) => `@object-ui/${category}`).filter(
(pkg) => !HOST_PACKAGES.includes(pkg),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ import {
} from '@object-ui/types/zod';
import { enumOptions } from '@object-ui/test-support';
import { allExamples, getExample } from '../src/index.js';
import { CATALOG_ENTRY_FLOOR } from './catalog-entry-floor.js';

type Json = Record<string, unknown>;

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

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

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

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

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

// One representative position per authoring shape, including the two
// nesting depths a shallow walker would silently miss: a select inside a
Expand Down
5 changes: 4 additions & 1 deletion ui/scripts/__tests__/check-dist-completeness.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, expect, it } from 'vitest';
import { uiTurboConfigPath } from '../workspace-root.mjs';
import { UI_TSC_BUILT_PACKAGE_FLOOR } from './helpers/ui-package-population.mjs';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
Expand Down Expand Up @@ -269,7 +270,9 @@ describe('this repository', () => {
const tscPackages = discoverTscPackages(repoRoot) as Array<{ name: string; dir: string }>;

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

it.each(tscPackages.map((p) => [p.name, p.dir] as const))(
Expand Down
19 changes: 11 additions & 8 deletions ui/scripts/__tests__/check-doc-links.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
stripCode,
} from '../check-doc-links.mjs';
import { GithubSlugger as VendoredSlugger, slug as vendoredSlug } from '../github-slug.mjs';
import { UI_PUBLISHED_PACKAGE_FLOOR } from './helpers/ui-package-population.mjs';

/**
* objectui#3479 — the behaviour test for `scripts/check-doc-links.mjs`.
Expand Down Expand Up @@ -514,16 +515,18 @@ describe('the repo it guards', () => {
expect(scanned['README.md']).toBe(1);
expect(scanned['CONTRIBUTING.md']).toBe(1);
expect(scanned['ROADMAP.md']).toBe(1);
// Three READMEs since the two host-console examples were deleted (#25922):
// the index, hello-world and schema-catalog.
expect(scanned['examples']).toBeGreaterThanOrEqual(3);
// A floor against an empty scan, not a census: three READMEs today (the
// index, hello-world and schema-catalog, measured on objectstack 6a7c0fe3),
// so deleting one example leaves it green.
expect(scanned['examples']).toBeGreaterThanOrEqual(2);
expect(scanned['docs']).toBeGreaterThanOrEqual(15);
expect(scanned['content/docs']).toBeGreaterThanOrEqual(100);
// objectui#3622. 38 of the 39 package directories carry a README today
// (`sdui-parser` does not), and this row is the only one whose path needs
// expanding before anything is opened — so a floor here is also the floor
// under `expandWildcard()`.
expect(scanned['packages/*/README.md']).toBeGreaterThanOrEqual(35);
// objectui#3622. This row is the only one whose path needs expanding before
// anything is opened, so a floor here is also the floor under
// `expandWildcard()`. Every published package carries a README, so the
// shared published-package floor bounds it (39 READMEs measured on
// objectstack 6a7c0fe3); deleting a package moves no floor.
expect(scanned['packages/*/README.md']).toBeGreaterThanOrEqual(UI_PUBLISHED_PACKAGE_FLOOR);
// objectui#4148. Both apps carry one today; the floor is 2 rather than the
// exact count because this row exists precisely so the NEXT app is scanned
// without anyone editing the table.
Expand Down
6 changes: 5 additions & 1 deletion ui/scripts/__tests__/check-node-esm-load.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { UI_PUBLISHED_PACKAGE_FLOOR } from './helpers/ui-package-population.mjs';

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

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

Expand Down
62 changes: 62 additions & 0 deletions ui/scripts/__tests__/helpers/ui-package-population.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

/**
* ui-package-population -- the ONE place the size of the ui package population
* is written down, as anti-vacuity floors.
*
* import { UI_PUBLISHED_PACKAGE_FLOOR } from './helpers/ui-package-population.mjs';
* expect(published.length).toBeGreaterThanOrEqual(UI_PUBLISHED_PACKAGE_FLOOR);
*
* A floor here answers one question: "did the scan find a population at all,
* or did a lost workspace root, a broken glob or a renamed manifest field leave
* it reading nothing?" It is NOT a census. A census pinned at today's measured
* value goes red on every legitimate package deletion, and one deletion then
* edits a floor in every file that spelled the count (objectstack#26444 counted
* five for a single retirement). So each floor sits at about two thirds of the
* value measured below -- the `vite-dts-wiring-ratchet` precedent: measured 22,
* floor 15 -- and is written once, here, for every reader:
*
* - `scripts/check-node-esm-load.mjs` and `scripts/check-published-dist-tooling.mjs`
* (`MIN_PACKAGES`, the gates' own refusal to judge a collapsed scan);
* - `package-files-exist`, `side-effects-declaration-consistency`,
* `check-dist-completeness`, `zero-test-member-exclusion-9106`,
* `check-doc-links` and `quick-reference-commands-4149` under `scripts/__tests__/`.
*
* It is an `.mjs` module, not a `.ts` helper like its neighbours, because the two
* gate scripts above import it at run time under plain `node`.
*
* Re-measuring: a floor moves only when its population has shrunk to near it,
* and then to about two thirds of the new measurement, with the measurement and
* its commit recorded in the table below. ⛔ Never raise a floor to track growth:
* growth is routine and the floor's job is only to refuse an empty scan.
*
* Measured on objectstack `origin/main` `6a7c0fe3` (2026-10-27, right after
* `@object-ui/app-shell` became private):
*
* population measured floor margin
* published packages (release group) 36 24 12
* workspace members (packages/*, apps/*, examples/*) 43 28 15
* `sideEffects: false` declarers 11 7 4
* `sideEffects` array declarers 17 11 6
* tsc-built packages 11 7 4
*/

/**
* Packages that publish to npm: not `private: true`, in the changesets release
* group. Readers whose population is a superset of these (packages declaring
* `files` or `exports`, package directories carrying a README) read this floor
* too: if the published set is there, so is theirs.
*/
export const UI_PUBLISHED_PACKAGE_FLOOR = 24;

/** Every manifest under the three workspace globs, private ones included. */
export const UI_WORKSPACE_MEMBER_FLOOR = 28;

/** Packages declaring `"sideEffects": false`. */
export const UI_SIDE_EFFECTS_FALSE_FLOOR = 7;

/** Packages declaring `sideEffects` as an array of paths. */
export const UI_SIDE_EFFECTS_ARRAY_FLOOR = 11;

/** Packages whose build runs `tsc` (the `check-dist-completeness` population). */
export const UI_TSC_BUILT_PACKAGE_FLOOR = 7;
Loading
Loading