From 1a1e7bc07c3ff65b71d4ac2235f9eb8ade9d0672 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 25 Aug 2026 06:37:37 +0000 Subject: [PATCH] =?UTF-8?q?test(ci):=20pin=20the=20`skip-changeset`=20phan?= =?UTF-8?q?tom=20=E2=80=94=20nothing=20wires=20it,=20and=20the=20page=20ke?= =?UTF-8?q?eps=20denying=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The label object was re-minted in this repository (auto-created by being applied by name) and is now being read as a mechanism: a triage comment on #6243 instructed a PR to carry it, the developer refused, and the refusal was upheld on PR #6260. A test cannot see GitHub's label data, so it does not try. It pins the two halves that live in the tree: no read of the name under .github/ or scripts/ (option B landing without a decision), and the page keeping its denial plus the alternative to reach for instead. Also corrects a claim on that page that had become false: it reported a point-in-time labels-API reading from 2026-08-08 saying the label did not exist. It does. A reading nothing in the tree can keep true is replaced by the durable invariant, and the third assertion pins that it is not restored. --- content/docs/guide/ci-cd-pipeline.md | 26 +++-- scripts/__tests__/ci-cd-pipeline-doc.test.ts | 99 ++++++++++++++++++++ 2 files changed, 118 insertions(+), 7 deletions(-) diff --git a/content/docs/guide/ci-cd-pipeline.md b/content/docs/guide/ci-cd-pipeline.md index 619dfc5966..d09e841200 100644 --- a/content/docs/guide/ci-cd-pipeline.md +++ b/content/docs/guide/ci-cd-pipeline.md @@ -1266,18 +1266,30 @@ its major; it sets `OBJECTUI_ALLOW_MAJOR=1`. `pnpm test` asserts the same reposi the rule survives this workflow being skipped. > **A changeset IS now required, by `changeset-presence.yml` — but there is still no -> `skip-changeset` label.** Until [#3387](https://github.com/objectstack-ai/objectui/issues/3387) +> `skip-changeset` mechanism.** Until [#3387](https://github.com/objectstack-ai/objectui/issues/3387) > nothing in CI asked whether a PR had added one, and this note said so at length, because the > opposite had been documented for months: a second workflow inventory at `.github/WORKFLOWS.md` > — unpinned, therefore free to drift — gave a "Changeset Check" workflow its own numbered > section, failing any PR touching `packages/` without a `.changeset/*.md` and skippable with a > `skip-changeset` or `dependencies` label. None of it existed; -> [#3724](https://github.com/objectstack-ai/objectui/issues/3724) deleted the page. The label -> still does not exist (checked against the labels API, 2026-08-08 — of the two names only -> `dependencies` exists, applied by the auto-labeler and read by no gate), and the real gate has -> no label escape hatch by design: its exemption is a changeset with an **empty frontmatter**, -> which lives in the repository where the next reader finds it, rather than a label that vanishes -> from history. +> [#3724](https://github.com/objectstack-ai/objectui/issues/3724) deleted the page. +> +> ⚠️ **The label object came back, and it still does nothing.** This note used to report a +> point-in-time labels-API reading (2026-08-08: of the two names only `dependencies` existed). +> That reading has since expired — a `skip-changeset` label now exists in this repository's +> label set, because GitHub mints a label the first time one is applied by name, so a single +> API call that applies it is enough to create it. By 2026-08-25 it sat on **seven** pull +> requests, carrying the default grey `ededed` and an empty description that tell an +> auto-minted label apart from a curated one. +> [#4912](https://github.com/objectstack-ai/objectui/issues/4912) tracks deleting the object. +> +> ⛔ **Whether or not you can still see it in the picker, applying it declares nothing** — no +> gate in this repository reads it. The real gate has no label escape hatch by design: its +> exemption is a changeset with an **empty frontmatter**, which lives in the repository where +> the next reader finds it, rather than a label that vanishes from history. The name is wired +> in the `objectstack` sibling, not here, which is how it reaches agents that then look for it +> in this repo. If you were told to apply it, the instruction is wrong; declare an empty +> changeset instead. > > The three real things with adjacent names each do something different, and none of them > subsumes another. `changeset-guard.yml` reads pending changesets and rejects a `major` bump. diff --git a/scripts/__tests__/ci-cd-pipeline-doc.test.ts b/scripts/__tests__/ci-cd-pipeline-doc.test.ts index 63ef34bbac..7aa6c744bc 100644 --- a/scripts/__tests__/ci-cd-pipeline-doc.test.ts +++ b/scripts/__tests__/ci-cd-pipeline-doc.test.ts @@ -212,6 +212,105 @@ describe('ci-cd-pipeline.md — workflow inventory', () => { expect(doc).not.toMatch(/size-check\.yml/); expect(workflowFiles).not.toContain('size-check.yml'); }); + + /** + * objectui#4912: `skip-changeset` is the other phantom that deleted page left behind, and + * unlike `size-check.yml` it did not stay dead. The label *object* was re-minted in this + * repository's label set — GitHub creates a label the first time one is applied by name, so + * one API call that applies it is enough — and by 2026-08-25 it sat on seven pull requests, + * carrying the default grey `ededed` and the empty description that tell an auto-minted + * label apart from a curated one. It is now actively read as a mechanism: a triage comment + * on objectui#6243 instructed a PR to carry it, the developer refused on the grounds + * recorded above, and the refusal was upheld on PR #6260. That is the exact harm #4912 + * predicted, arriving after the card was filed. + * + * ⛔ What these two cases can and cannot see, said plainly because the boundary is the whole + * design of this file: **a label lives in GitHub's data, not in the tree, so nothing here + * can assert the label object is gone.** Deleting it is an administrative act, and a test + * that reached for the labels API would put a network call and a credential in a suite that + * deliberately has neither. The pins below are therefore not restatements of "the label does + * nothing" — that needs no pin. They hold the two things that *are* ours and that a future + * commit could change without anyone noticing. + */ + it('never wires the phantom `skip-changeset` label into a workflow or a gate', () => { + // Option B of #4912 — give the changeset gates a labelled skip path — was declined by + // #3724 and again by the #4912 ruling: the presence gate has no bypass by design, and its + // exemption is an empty-frontmatter changeset, which lives in the repo where the next + // reader finds it rather than in a label that vanishes from history. So a read of this + // name appearing under `.github/` or `scripts/` is that declined option landing without a + // decision. The name IS wired in the `objectstack` sibling (lint.yml, pr-automation.yml, + // check-empty-changeset.mjs), which is how it reaches agents who then look for it here — + // copying that wiring across is precisely what this catches. + const selfPath = path.resolve(fileURLToPath(import.meta.url)); + const offenders: string[] = []; + + function scan(dir: string): void { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + if (entry.name === 'node_modules' || entry.name === '.turbo') continue; + scan(full); + } else if (entry.isFile() && path.resolve(full) !== selfPath) { + // This file is the one legitimate mention: it records the history above. + if (fs.readFileSync(full, 'utf8').includes('skip-changeset')) { + offenders.push(path.relative(repoRoot, full)); + } + } + } + } + + for (const root of ['.github', 'scripts']) scan(path.join(repoRoot, root)); + + expect( + offenders.sort(), + `these files under .github/ or scripts/ mention \`skip-changeset\`:\n` + + offenders.map((f) => ` - ${f}`).join('\n') + + `\n\nNo gate in this repository reads that label and none is supposed to. If this is a ` + + `workflow or script that now honours it, that is objectui#4912 option B — a labelled ` + + `bypass on a changeset gate that deliberately has none — and it was declined twice ` + + `(#3724, and the #4912 ruling). Land the decision to reverse those before the code. ` + + `To declare that a PR publishes nothing, add a changeset with empty frontmatter; that ` + + `is the mechanism, and it is the one content/docs/guide/ci-cd-pipeline.md documents.`, + ).toEqual([]); + }); + + it('keeps the page denying `skip-changeset` rather than describing it', () => { + // `ci-cd-pipeline.md` is where a contributor looks up "how do I declare this PR publishes + // nothing", so the page is the surface that decides whether the next reader believes the + // label. Unlike the `size-check.yml` pin, absence is the wrong assertion here: the page + // has to keep NAMING the label in order to deny it, or the phantom is simply undocumented + // again. So the denial itself is what gets pinned. + // + // Blockquote markers are stripped before matching — the whole passage is a `>` block, and + // its sentences wrap across lines, so a raw substring search would silently never match + // and this pin would be vacuously green. + const prose = doc.replace(/^[ \t]*>[ \t]?/gm, '').replace(/\s+/g, ' '); + + expect( + prose, + 'content/docs/guide/ci-cd-pipeline.md must keep stating that nothing reads the ' + + '`skip-changeset` label. The label object exists in this repository (auto-minted by ' + + 'being applied, objectui#4912) and agents are being told to use it, so a page that ' + + 'stops denying it leaves the label as the most authoritative-looking answer in reach.', + ).toContain('no gate in this repository reads it'); + + expect( + prose, + 'the page must keep telling the reader what to do INSTEAD of the label — a denial with ' + + 'no alternative sends them back to the label. The real exemption is a changeset with ' + + 'empty frontmatter.', + ).toContain('declare an empty changeset instead'); + + // The 2026-08-08 labels-API reading this note used to carry ("the label still does not + // exist") had expired by the time #4912 was worked: the object had been re-minted. A + // point-in-time API reading is not a fact this repository can keep true, and restating one + // is how the page came to assert something false about the very phantom it documents. + expect( + prose, + 'do not put a point-in-time labels-API reading back on this page. Nothing in the tree ' + + 'can keep it true, and the last one was false within weeks (objectui#4912).', + ).not.toContain('checked against the labels API'); + }); }); /**