Skip to content

Commit 97934f0

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-4m2bvo
2 parents a5c3e1f + 2a728ba commit 97934f0

20 files changed

Lines changed: 230 additions & 1045 deletions

‎ui/scripts/__tests__/check-doc-component-types.test.ts‎

Lines changed: 18 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,22 +2096,17 @@ describe('objectui#7896 — every package README is inside the scan surface', ()
20962096
});
20972097
});
20982098

2099-
describe('wiring — the gate is reachable and a docs-only PR starts it', () => {
2100-
const workflowDir = path.join(repoRoot, '.github/workflows');
2101-
const workflowPath = path.join(workflowDir, 'repo-gates.yml');
2102-
const workflowFiles = fs.readdirSync(workflowDir).filter((f) => f.endsWith('.yml'));
2103-
2104-
/**
2105-
* A workflow's YAML with whole-line comments removed — these headers name each
2106-
* other's scripts in prose, and a scan that counted comments would report
2107-
* duplicate homes that no file has.
2108-
*/
2109-
const yamlOf = (file: string) =>
2110-
fs
2111-
.readFileSync(path.join(workflowDir, file), 'utf8')
2112-
.split('\n')
2113-
.filter((line) => !/^\s*#/.test(line))
2114-
.join('\n');
2099+
describe('wiring — the gate is reachable by name, and needs no install', () => {
2100+
// Retired with objectstack#25712: `has a workflow that gates pull requests,
2101+
// not just pushes`, `runs it in NO path-filtered workflow — the change that
2102+
// breaks it is docs-only`, `has exactly one home`, the install ORDER half of
2103+
// `needs no install`, and the header-count pin further down. Each read
2104+
// objectui's `repo-gates.yml`, this gate's only home, and that file runs
2105+
// nowhere under the monorepo: GitHub runs the root `.github/workflows/`
2106+
// alone, and no workflow there runs this gate. objectstack#25880 ports the
2107+
// `repo-gates.yml` gates (row 24 of the objectstack#25697 workflow roster)
2108+
// into the root `Lint UI` job and brings these pins back against that job, by
2109+
// path.
21152110

21162111
it('is exposed as a root package script', () => {
21172112
const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8')) as {
@@ -2120,46 +2115,9 @@ describe('wiring — the gate is reachable and a docs-only PR starts it', () =>
21202115
expect(pkg.scripts['check:doc-types']).toBe(`node ${SCRIPT}`);
21212116
});
21222117

2123-
it('has a workflow that gates pull requests, not just pushes', () => {
2124-
expect(fs.existsSync(workflowPath), 'a check nothing runs is not a gate').toBe(true);
2125-
const yaml = yamlOf('repo-gates.yml');
2126-
expect(yaml).toMatch(new RegExp(`run:\\s*node\\s+${SCRIPT.replace(/[.]/g, '\\.')}`));
2127-
expect(yaml).toMatch(/^\s*pull_request:/m);
2128-
expect(yaml).toMatch(/^\s*push:/m);
2129-
expect(yaml).toMatch(/^\s*merge_group:/m);
2130-
});
2131-
2132-
it('runs it in NO path-filtered workflow — the change that breaks it is docs-only', () => {
2133-
// The whole reason this is its own workflow. `ci.yml`'s type-check job
2134-
// excludes `content/**` from the diff that decides whether its gates run, so
2135-
// a PR editing only `content/docs/**` would start this gate nowhere.
2136-
expect(workflowFiles.length, 'the workflow directory scan returned implausibly few files').toBeGreaterThan(5);
2137-
for (const file of workflowFiles) {
2138-
const yaml = yamlOf(file);
2139-
if (!yaml.includes(SCRIPT)) continue;
2140-
expect(yaml, `${file} runs ${SCRIPT} behind a paths-ignore — a docs-only change would not start it`).not.toMatch(
2141-
/paths-ignore:/,
2142-
);
2143-
expect(yaml, `${file} runs ${SCRIPT} behind a paths filter — see objectui#3448`).not.toMatch(/^\s+paths:/m);
2144-
}
2145-
});
2146-
2147-
it('has exactly one home', () => {
2148-
expect(workflowFiles.filter((f) => yamlOf(f).includes(SCRIPT))).toEqual(['repo-gates.yml']);
2149-
});
2150-
2151-
it('needs no install, so it can afford to run unfiltered', () => {
2118+
it('needs no install: its import graph reaches no package', () => {
21522119
// The moment this needs `pnpm install` it stops being cheap enough to run on
21532120
// every PR shape, and the filter that follows is the hole.
2154-
// Since objectui#12214 the home is `repo-gates.yml`, ONE job that installs
2155-
// after its install-free gates: the property is now an ORDER -- this gate's
2156-
// step sits before the job's `pnpm install` -- and no longer an absence.
2157-
const yaml = yamlOf('repo-gates.yml');
2158-
const gateAt = yaml.indexOf(`run: node ${SCRIPT}`);
2159-
const installAt = yaml.indexOf('pnpm install');
2160-
expect(gateAt).toBeGreaterThan(-1);
2161-
expect(installAt === -1 || gateAt < installAt, 'the gate step moved below the install step').toBe(true);
2162-
21632121
// Walk the WHOLE static import graph, not just the gate's own first line.
21642122
// objectui#6092 converted this gate's entry guard to `./invoked-as.mjs`, a
21652123
// relative import — install-free, but not spelled `node:`. Asserting on the
@@ -2190,77 +2148,12 @@ describe('wiring — the gate is reachable and a docs-only PR starts it', () =>
21902148
expect(external, `the gate's import graph reaches a package, so it needs an install: ${external}`).toEqual([]);
21912149
});
21922150

2193-
/**
2194-
* objectui#7448. The header of this workflow described its scan surface as
2195-
* "184 pages (144 `.mdx` + 40 `.md`)". Every part of that had drifted by the
2196-
* time the card was worked — the gate's own verdict line reported 188 doc
2197-
* files, and the `.md` half of the split was four short — and NO check went
2198-
* red over the whole distance, because nothing fails on a stale number written
2199-
* in a comment. That is the same lesson `UNGATED_DOCS`'s header in
2200-
* `check-doc-snippet-types.mjs` records after both halves of its own copied
2201-
* count went stale ("a pointer to the list now rather than a copy of its
2202-
* length").
2203-
*
2204-
* Changing 184 to 188 would only have restarted that clock. This is what makes
2205-
* the class fail loudly instead: the header may state the population — which
2206-
* trees, which extensions — but never count it. `doc-fence-languages.yml`
2207-
* carries the twin of this pin in its own test file; one gate, one home, so
2208-
* each workflow's header is asserted beside its own gate rather than in a
2209-
* shared sweep that would own neither.
2210-
*
2211-
* Deliberately narrow, and narrow in the same place as the other two copies:
2212-
* a numeral qualifying a document-population noun, with at most two words
2213-
* allowed to sit between the two. Issue references (ruled out at the pattern
2214-
* level by the negative lookbehind, not by luck), `node-version`,
2215-
* `timeout-minutes` and "the fifth instance of the shape" are all numbers
2216-
* this header legitimately carries, and
2217-
* none of them rots when a page is added or deleted. It also means the header
2218-
* must not quote another header's stale literal verbatim — this pin cannot
2219-
* tell a quotation from a claim, and refusing both is the safe direction for a
2220-
* check on prose accuracy.
2221-
*
2222-
* ⭐ Those two intervening words are objectui#7888, and they are the sentence
2223-
* above implemented rather than a new rule. This pin and its twin in
2224-
* `check-doc-fence-languages.test.ts` both said "a numeral DIRECTLY
2225-
* qualifying" and both coded it as strict adjacency, so a single adjective
2226-
* defeated them. Measured: run verbatim over `check-links.yml`'s header as it
2227-
* stood on `origin/main` at `83fe6e741` — a header carrying TWO live drifted
2228-
* counts — the adjacent-only pattern reported ONE of them. It found the
2229-
* sentence about the files the published site is built from, and scored the
2230-
* one reading "holds 15 INTERNAL documents" clean — which was the count that
2231-
* had drifted furthest (15 against a measured 17), because an adjective sat
2232-
* between the numeral and the noun. The pattern below is the third copy's,
2233-
* carried here verbatim (objectui#7825, PR objectui#7885,
2234-
* `check-links-workflow.test.ts`), with the noun set unchanged; the word
2235-
* DIRECTLY is gone from the sentence above because keeping it would only have
2236-
* inverted the same gap between what this pin claims and what it does.
2237-
*
2238-
* Both twin headers were clean under BOTH patterns when this was carried
2239-
* across, so this closes a proven hole rather than a live violation.
2240-
*/
2241-
it('its header states the population and never counts it — no count can rot here', () => {
2242-
const header = headerComments(fs.readFileSync(workflowPath, 'utf8'));
2243-
2244-
// objectui#7901 — the floor first, or the assertion below is vacuous. The
2245-
// count half cannot distinguish a header that carries no counts from a
2246-
// header this pin has stopped reading; both score `[]`. Measured when this
2247-
// was added, so it is latent rather than live: the extraction returned 4312
2248-
// characters from this header, 10.8 times the floor. It read 4514 at 11.3
2249-
// before objectui#7967 made this extraction strip the `#` markers: 202 of
2250-
// those characters were markers, and none of them were prose.
2251-
expect(
2252-
header.length,
2253-
'doc-component-types.yml: the header prose this pin reads came back empty or near-empty, so it asserted over nothing',
2254-
).toBeGreaterThan(MIN_HEADER_PROSE);
2255-
2256-
const counts = documentCounts(header);
2257-
expect(
2258-
counts,
2259-
`doc-component-types.yml's header states a page count (${counts.join(', ')}). Nothing fails when ` +
2260-
'it drifts, so it will. State the population — or point at the gate\u2019s own verdict line, which ' +
2261-
'prints the live figure on every run — instead of copying a number into a comment (objectui#7448).',
2262-
).toEqual([]);
2263-
});
2151+
// The header-count pin (objectui#7448, widened by objectui#7888, floored by
2152+
// objectui#7901) retired with the pins above: it read `repo-gates.yml`'s
2153+
// header. The three controls below stay. They exercise `documentCounts` and
2154+
// `headerComments` on synthetic text and read no workflow, and once
2155+
// objectstack#25880 gives this gate a root home they are the controls of the
2156+
// pin that comes back against that file's header.
22642157

22652158
/**
22662159
* The positive control for the pin above — objectui#7914.

‎ui/scripts/__tests__/check-doc-example-ids.test.ts‎

Lines changed: 11 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -315,23 +315,17 @@ describe('this repository', () => {
315315
});
316316
});
317317

318-
describe('wiring — the gate is reachable and a docs-only PR starts it', () => {
319-
const workflowDir = path.join(repoRoot, '.github/workflows');
320-
const workflowFile = 'repo-gates.yml';
321-
const workflowPath = path.join(workflowDir, workflowFile);
322-
const workflowFiles = fs.readdirSync(workflowDir).filter((f) => f.endsWith('.yml'));
323-
324-
/**
325-
* A workflow's YAML with whole-line comments removed — these headers name each
326-
* other's scripts in prose, and a scan that counted comments would report
327-
* duplicate homes that no file has.
328-
*/
329-
const yamlOf = (file: string) =>
330-
fs
331-
.readFileSync(path.join(workflowDir, file), 'utf8')
332-
.split('\n')
333-
.filter((line) => !/^\s*#/.test(line))
334-
.join('\n');
318+
describe('wiring — the gate is reachable by name', () => {
319+
// Retired with objectstack#25712: `has a workflow that gates pull requests,
320+
// not just pushes`, `runs it in NO path-filtered workflow — the change that
321+
// breaks it is docs-only`, `has exactly one home`, `needs no install, so it
322+
// can afford to run unfiltered`, and `carries no population count in its
323+
// header`. Each read objectui's `repo-gates.yml`, this gate's only home, and
324+
// that file runs nowhere under the monorepo: GitHub runs the root
325+
// `.github/workflows/` alone, and no workflow there runs this gate.
326+
// objectstack#25880 ports the `repo-gates.yml` gates (row 24 of the
327+
// objectstack#25697 workflow roster) into the root `Lint UI` job and brings
328+
// these pins back against that job, by path.
335329

336330
it('is exposed as a root package script', () => {
337331
const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8')) as {
@@ -349,58 +343,4 @@ describe('wiring — the gate is reachable and a docs-only PR starts it', () =>
349343
expect(pkg.scripts['check:doc-example-readers']).toBe('node scripts/check-doc-example-shared-reader.mjs');
350344
expect(pkg.scripts['check:doc-types']).toBe('node scripts/check-doc-component-types.mjs');
351345
});
352-
353-
it('has a workflow that gates pull requests, not just pushes', () => {
354-
expect(fs.existsSync(workflowPath), 'a check nothing runs is not a gate').toBe(true);
355-
const yaml = yamlOf(workflowFile);
356-
expect(yaml).toMatch(new RegExp(`run:\\s*node\\s+${SCRIPT.replace(/[.]/g, '\\.')}`));
357-
expect(yaml).toMatch(/^\s*pull_request:/m);
358-
expect(yaml).toMatch(/^\s*push:/m);
359-
expect(yaml).toMatch(/^\s*merge_group:/m);
360-
});
361-
362-
it('runs it in NO path-filtered workflow — the change that breaks it is docs-only', () => {
363-
expect(workflowFiles.length, 'the workflow directory scan returned implausibly few files').toBeGreaterThan(5);
364-
for (const file of workflowFiles) {
365-
const yaml = yamlOf(file);
366-
if (!yaml.includes(SCRIPT)) continue;
367-
expect(yaml, `${file} runs ${SCRIPT} behind a paths-ignore — a docs-only change would not start it`).not.toMatch(
368-
/paths-ignore:/,
369-
);
370-
expect(yaml, `${file} runs ${SCRIPT} behind a paths filter`).not.toMatch(/^\s+paths:/m);
371-
}
372-
});
373-
374-
it('has exactly one home', () => {
375-
expect(workflowFiles.filter((f) => yamlOf(f).includes(SCRIPT))).toEqual([workflowFile]);
376-
});
377-
378-
it('needs no install, so it can afford to run unfiltered', () => {
379-
// Since objectui#12214 the home is `repo-gates.yml`, ONE job that installs
380-
// after its install-free gates: the property is now an ORDER -- this gate's
381-
// step sits before the job's `pnpm install` -- and no longer an absence.
382-
const yaml = yamlOf(workflowFile);
383-
const gateAt = yaml.indexOf('scripts/check-doc-example-ids.mjs');
384-
const installAt = yaml.indexOf('pnpm install');
385-
expect(gateAt).toBeGreaterThan(-1);
386-
expect(installAt === -1 || gateAt < installAt, 'the gate step moved below the install step').toBe(true);
387-
});
388-
389-
it('carries no population count in its header — a number in a comment has nothing that fails when it drifts', () => {
390-
const header = fs
391-
.readFileSync(workflowPath, 'utf8')
392-
.split('\n')
393-
.filter((line) => /^\s*#/.test(line))
394-
.map((line) => line.replace(/^\s*#\s?/, ''))
395-
.join('\n');
396-
397-
// The floor is what makes "no counts here" a reading rather than the absence
398-
// of one: an extraction that has stopped reading returns '' and passes.
399-
expect(header.length, 'the header extraction read nothing, so the pin below is vacuous').toBeGreaterThan(400);
400-
401-
const counts = [
402-
...header.matchAll(/(?<![#\w.])\d+(?:,\d{3})*\s+(?:[A-Za-z][\w-]*\s+){0,2}`?(?:\.mdx|\.md|documents?|pages?|docs?|files?|ids?|references?)\b/gi),
403-
].map((m) => m[0].replace(/\s+/g, ' ').trim());
404-
expect(counts).toEqual([]);
405-
});
406346
});

‎ui/scripts/__tests__/check-doc-example-types.test.ts‎

Lines changed: 13 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -531,70 +531,20 @@ describe('the sibling harness is imported, not forked', () => {
531531
* the YAML as text with whole-line comments removed — the headers in this
532532
* repository name other workflows and other scripts in prose.
533533
*/
534-
describe('wiring — the gate runs in CI, and in a workflow a docs-only pull request can start', () => {
534+
describe('wiring — the gate is reachable by name, and documented by command', () => {
535535
const GATE = 'scripts/check-doc-example-types.mjs';
536-
const SIBLING = 'scripts/check-doc-snippet-types.mjs';
537-
const HOME = 'repo-gates.yml';
538-
const workflowDir = path.join(repoRoot, '.github/workflows');
539-
const workflowFiles = fs.readdirSync(workflowDir).filter((f) => f.endsWith('.yml'));
540-
541-
const yamlOf = (file: string): string =>
542-
fs
543-
.readFileSync(path.join(workflowDir, file), 'utf8')
544-
.split('\n')
545-
.filter((line) => !/^\s*#/.test(line))
546-
.join('\n');
547-
548-
it('has a workflow that gates pull requests, not just pushes', () => {
549-
expect(workflowFiles, 'the workflow directory scan returned implausibly few files').toContain(HOME);
550-
const yaml = yamlOf(HOME);
551-
expect(yaml, 'a check nothing runs is not a gate — objectui#8757').toContain(GATE);
552-
expect(yaml).toContain('pull_request:');
553-
});
554-
555-
it('runs it in NO path-filtered workflow — an `@example` moves with the source it documents', () => {
556-
expect(workflowFiles.length, 'the workflow directory scan returned implausibly few files').toBeGreaterThan(5);
557-
for (const file of workflowFiles) {
558-
const yaml = yamlOf(file);
559-
if (!yaml.includes(GATE)) continue;
560-
expect(yaml, `${file} filters paths and would miss a change this gate exists to judge`).not.toMatch(
561-
/^\s*paths(-ignore)?:/m,
562-
);
563-
}
564-
});
565-
566-
it('lives in exactly one workflow — one gate, one home', () => {
567-
expect(workflowFiles.filter((f) => yamlOf(f).includes(GATE))).toEqual([HOME]);
568-
});
569-
570-
/**
571-
* The gate's exit `2` means THE GATE COULD NOT RUN — the packages are unbuilt
572-
* — and is neither green nor red. Invoked before its own build it would
573-
* return exactly that on every run, which is the counterfeit shape: a step
574-
* that runs, prints a page of text and judged nothing.
575-
*/
576-
it('is invoked AFTER the build, so a precondition exit is not a state CI can reach', () => {
577-
const yaml = yamlOf(HOME);
578-
const build = yaml.indexOf('turbo run build');
579-
const invoke = yaml.search(new RegExp(`run: node ${GATE.replace(/[.\\/]/g, '\\$&')}\\s*$`, 'm'));
580-
expect(build, 'the workflow must build the packages the covered examples import').toBeGreaterThan(-1);
581-
expect(invoke, 'the workflow must invoke the gate itself').toBeGreaterThan(-1);
582-
expect(build, 'invoked before its own build, the gate would exit 2 on every run').toBeLessThan(invoke);
583-
});
584536

585-
/**
586-
* Both gates block, so whichever is second is skipped when the first is red.
587-
* Ordering the newly wired gate FIRST would let it mask an established one —
588-
* the worse of the two directions, and the one this asserts against.
589-
*/
590-
it('is invoked AFTER the sibling blocking gate, so a new gate cannot mask an established one', () => {
591-
const yaml = yamlOf(HOME);
592-
const sibling = yaml.search(new RegExp(`run: node ${SIBLING.replace(/[.\\/]/g, '\\$&')}\\s*$`, 'm'));
593-
const invoke = yaml.search(new RegExp(`run: node ${GATE.replace(/[.\\/]/g, '\\$&')}\\s*$`, 'm'));
594-
expect(sibling, 'the sibling blocking gate must still be invoked').toBeGreaterThan(-1);
595-
expect(invoke).toBeGreaterThan(-1);
596-
expect(invoke).toBeGreaterThan(sibling);
597-
});
537+
// Retired with objectstack#25712: `has a workflow that gates pull requests,
538+
// not just pushes`, `runs it in NO path-filtered workflow`, `lives in exactly
539+
// one workflow — one gate, one home`, `is invoked AFTER the build`, and `is
540+
// invoked AFTER the sibling blocking gate`. Each read objectui's
541+
// `repo-gates.yml`, this gate's only home, and that file runs nowhere under
542+
// the monorepo: GitHub runs the root `.github/workflows/` alone, and no
543+
// workflow there runs this gate. objectstack#25880 ports the `repo-gates.yml`
544+
// gates (row 24 of the objectstack#25697 workflow roster) into the root `Lint
545+
// UI` job and brings these pins back against that job, by path. The alias
546+
// case at the bottom keeps its `package.json` half and drops the workflow
547+
// half for the same reason.
598548

599549
/**
600550
* objectui#3653's discipline, applied by hand here: the page that inventories
@@ -622,11 +572,10 @@ describe('wiring — the gate runs in CI, and in a workflow a docs-only pull req
622572
expect(row[0]).toContain(GATE);
623573
});
624574

625-
it('the root package.json alias and the workflow invoke the same script', () => {
575+
it('the root package.json alias invokes the gate', () => {
626576
const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8')) as {
627577
scripts: Record<string, string>;
628578
};
629579
expect(pkg.scripts['check:doc-examples']).toBe(`node ${GATE}`);
630-
expect(yamlOf(HOME)).toContain(`run: node ${GATE}`);
631580
});
632581
});

0 commit comments

Comments
 (0)