Skip to content

Published Dist Gate #55

Published Dist Gate

Published Dist Gate #55

name: Published Dist Gate
# The artifact-level half of objectui#4846: no published package's `dist/` may
# contain tooling material (`__tests__/`, `__mocks__/`, `__benchmarks__/`,
# `*.test.*`, `*.spec.*`, `*.bench.*`, `*.stories.*`). The gate itself, and the
# reason a cheap static criterion is NOT usable, are documented at length in
# scripts/check-published-dist-tooling.mjs.
#
# ── Why this is a scheduled workflow and NOT a pull-request job ──────────────
#
# The only criterion that does not produce false reds is a criterion over the
# BUILT ARTIFACT, so the gate has to build all 39 published packages. This
# repository deliberately has no per-PR full-repo build — `ci.yml`'s `Build &
# E2E` builds `@object-ui/console` alone, and its `Type Check` gets only the
# DEPENDENCY CLOSURE out of turbo's `dependsOn: ["^build"]`, which is why leaf
# packages such as `@object-ui/plugin-designer` (one of the four that shipped
# tooling material in objectui#4836) are never built there.
#
# The 2026-08-16 ruling on objectui#4846 (comment 5307574139) placed the gate on
# the RELEASE path — `pnpm changeset:publish` runs it before a single tarball
# reaches npm, so a red gate cancels the publish — and allowed this nightly run
# in addition, so a regression surfaces the night it lands instead of waiting
# for the next release. ⛔ Do not add `pull_request` here: that is precisely the
# per-PR full-repo build the ruling rejected.
# `scripts/__tests__/check-published-dist-tooling.test.ts` fails if the gate is
# ever wired into a workflow that carries a `pull_request` trigger.
#
# This workflow is therefore an ALARM, not a merge blocker: it cannot make
# anyone's pull request red, so a slow or flaky run costs a second look and
# nothing else. The blocking copy is the one on the publish path.
on:
workflow_dispatch:
# Nightly at 03:41 UTC. Off the top of the hour because GitHub's scheduled
# queue is most congested — and most delayed — at :00, the same reasoning
# `check-links.yml` records for its weekly sweep.
schedule:
- cron: '41 3 * * *'
# Changes to the gate itself get a real run, because the gate's own unit tests
# (which DO run per-PR, inside the ordinary vitest suite) exercise its
# verdicts over synthetic file lists and cannot exercise a real build. Scoped
# by `paths` to the gate and its wiring, so this stays off every other pull
# request.
push:
branches: [main]
paths:
- 'scripts/check-published-dist-tooling.mjs'
- '.github/workflows/published-dist-gate.yml'
concurrency:
group: published-dist-gate-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
published-dist:
name: Published Dist Tooling Scan
runs-on: ubuntu-latest
# A full build of 39 published packages plus one `npm pack --dry-run` per
# package. Generous, because a timeout here reads as a gate failure and this
# workflow blocks nobody.
timeout-minutes: 60
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
submodules: true
- name: Enable Corepack and download the pinned pnpm
run: bash scripts/ci-setup-pnpm.sh
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version: '22.x'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
# No `pnpm build` step before this one, on purpose. The gate runs the
# build ITSELF and fails when it cannot, so that "there were no artifacts,
# therefore nothing was wrong" can never be this workflow's verdict — the
# vacuous shape objectui#4846 rejected by name. A published package that
# contributes no build output is reported as `no-build-output`, not
# skipped.
- name: Build every published package and scan its tarball
run: pnpm check:published-dist