Skip to content

ci(lint): run the CLI's own check command against this repository - #5273

Merged
os-support-ai merged 1 commit into
mainfrom
claude/issue-5246-wire-pnpm-check-into-ci
Aug 18, 2026
Merged

ci(lint): run the CLI's own check command against this repository#5273
os-support-ai merged 1 commit into
mainfrom
claude/issue-5246-wire-pnpm-check-into-ci

Conversation

@os-support-ai

@os-support-aios-support-ai commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes#5246

The root check script is node packages/cli/dist/cli.js checkobjectui check, the command this repository ships, pointed at this repository's own tree. Grepping .github/workflows/** finds no caller. This adds one.

The ruling

Triage auto-adjudication on #5246, auto-adjudicated, maintainer veto window open:

Ruling: wire the root pnpm check (objectui check pointed at this repo) into CI as a blocking step on its ERROR arm, in the existing lint workflow. Decide nothing about the 47 warnings here — warnings stay non-blocking exactly as the command already behaves, and #5127 keeps owning the warning noise. "Drop the self-check instead" was considered and rejected: the command just surfaced 64 real errors (#5237), which is measured proof it gates something.

Premise to verify FIRST (dev, before wiring): confirm on current main that the exit code reflects errors only (47 warnings alone → exit 0; the #5245 evidence says this holds). If warnings turn out to affect the exit code, STOP and report the fork — do not suppress or reclassify warnings to get green.

Premise readings, taken before any YAML was written

This adds a blocking step. If it were red the moment it landed, main would be red for every other agent in the repo. All three readings were taken first, on origin/main at bc2922a82, with the CLI built from source.

1. pnpm check is exit 0 on current main. Measured, not assumed:

$ node packages/cli/dist/cli.js check
Object UI Schema Check
Analyzing 612 files...
... warnings only ...
✓ All checks passed
$ echo $?
0

errors 0 · exit 0 · warnings 46. One honest discrepancy: the card and the ruling both say 47 warnings; the count observed today is 46. Every one is the unknown-schema-type arm, 45 of them "module" in a package.json and one "unknown-component" in a schema-catalog fixture. The gap does not touch the ruling — the warning arm is non-blocking at any count — but the number in the card is one stale, so it is recorded rather than repeated.

2. #5245 is merged, not merely open. Checked live rather than taken from the card: PR #5245 has merged: true, merged_at 2026-08-18T20:22:07Z, base main. Issue #5237 is in state closed with state_reason: completed. The 0-error state this gate depends on is therefore on main, and this is not the wire-the-gate-before-the-fix-lands case.

3. The exit code reflects errors only. Confirmed two independent ways.

Empirically, the run above prints 46 warnings and exits 0 — warnings alone do not fail it. By source, packages/cli/src/commands/check.ts increments errors in exactly two places, both parse failures, and the only process.exit(1) is guarded by errors === 0; the unknown-schema-type arm is a bare console.log that touches no counter. The warning arm is not load-bearing on the exit code, so there is no fork to escalate.

Nothing was added to force green. No --quiet, no output filtering, no warning downgraded or reclassified. The warning arm stays exactly as it behaves today: printed, visible in the log, non-blocking. #5127 still owns it and remains open — whatever it settles changes what this step prints, never what it fails on.

What the change is

Two steps at the end of the existing lint job in .github/workflows/lint.yml, both carrying the same if: steps.relevant.outputs.should_run == 'true' guard as every neighbour:

- name: Build the CLI the self-check runsif: steps.relevant.outputs.should_run == 'true'run: pnpm --filter '@object-ui/cli...' build
- name: Verify the CLI's own check command passes on this repositoryif: steps.relevant.outputs.should_run == 'true'run: pnpm check

Scope is what the ruling authorised and nothing else: blocking on the ERROR arm. No --max-warnings-style strictness, no other job touched, no adjacent step tidied.

Why there is a build step, and why it is not turbo

The lint job installs but never builds, and the root script executes packages/cli/dist/cli.js. Without a build the step dies on a missing file — which is worse than no gate at all, because it is red for a reason that has nothing to do with the tree being judged, and the obvious repair from outside is to delete the step.

... is pnpm's dependency closure: the CLI plus every workspace package it depends on, in topological order, derived from the graph rather than listed here. The closure is a requirement, not tidiness — dist/cli.js imports @object-ui/types' built output at startup, which is why #5237's reproduce recipe builds that package first.

The first draft of this step used pnpm turbo run build --filter='@object-ui/cli', which is the in-repo convention and would usually be free given the Turbo cache the job already restores. It was changed after a measured failure. A turbo cache hit restores a task's recorded outputs, and an entry recorded with an empty output set replays as cache hit, replaying logs plus FULL TURBO while writing no dist/ at all:

@object-ui/types:build: cache hit, replaying logs cbd4ca5014f01cfc
Tasks: 1 successful, 1 total
Cached: 1 cached, 1 total
Time: 103ms >>> FULL TURBO
types/dist after: MISSING

pnpm check then died with ERR_MODULE_NOT_FOUND on @object-ui/types/dist/zod/index.zod.js — the exact import #5237 names. To be precise about the blast radius: this was observed in a local cache shared across parallel worktrees, and I cannot prove CI's cache can reach the same state. But a blocking gate must not be able to fail for a reason that lives in a cache rather than in the tree it is judging, and building through pnpm has no cache layer to replay. It costs 46 seconds cold.

Verification

Everything below was executed on 5870484f8, the head of this branch. What was reasoned about rather than run is named as such.

Executed — the exact commands the two steps run, in order, from a clean-checkout-equivalent tree (every packages/*/dist and every *.tsbuildinfo removed first, with the poisoned turbo cache still present on disk — the state that broke the turbo-based draft):

STEP 'Build the CLI the self-check runs' exit=0 # Scope: 9 of 47 workspace projects
STEP 'Verify the CLI's own check command' exit=0 # Analyzing 612 files... ✓ All checks passed
# warnings=46 errors=0

Executed — reverse verification, that the gate actually gates. Prediction recorded before running: exit 1, one error line, warnings unchanged at 46. Observed exactly that:

$ printf '{ "compilerOptions": }\n' ~ gate-probe-malformed.json
$ pnpm check ; echo $?
Analyzing 613 files...
x Invalid JSON in gate-probe-malformed.json: ValueExpected at line 1 column 22
Found 1 errors
1

Probe removed, re-run returns to exit 0 and git status clean. (~ above stands for the shell redirect, spelled out so the snippet survives issue rendering.) No rebuild question arises on either leg: the mutation was a data file in the scanned tree, not code in the package under test, so both legs ran the same freshly built binary.

Executed — YAML validity..github/workflows/lint.yml parses; the lint job now holds 11 steps, the last two being the ones above with the run lines as written.

Executed — the gates this diff derives.scripts/check-control-bytes.mjs exit 0, plus a raw scan of both changed files for control bytes: clean. scripts/check-changeset-presence.mjs exit 0 — "2 file(s) changed, 0 of them under the src/ of a package the release covers", so no changeset is owed and none was added. scripts/check-doc-links.mjs exit 0. And the five suites that pin these two files — lint-workflow, merge-queue-reporting, ci-cd-pipeline-doc, turbo-lint-inputs, check-changeset-presence5 files, 140 tests passed.

Reasoned about, not executed — the needs:/setup chain that proves dist/ exists when the step runs. GitHub Actions cannot run locally. The lint job has no needs:; it is the only job in the workflow, so the chain is purely the step order inside it: checkout → decide-whether-to-run → corepack → pnpm version → setup-node → lint coverage → Turbo cache → pnpm install --frozen-lockfilepnpm lintbuildcheck. The build step immediately precedes the check step and both carry the same should_run guard, so they run together or not at all. Node and pnpm are already set up four steps earlier, and dependencies are installed two steps earlier. Nothing between the build and the check removes dist/.

Reasoned about — the scan surface does not depend on the build. Worth stating because the build now runs before the check: the command's glob ignores dist/**, and no package dist in this repo contains a .json, .yaml or .yml file. Measured both ways — a run with two package dist directories present and a run with eight both report Analyzing 612 files... with byte-identical warning output. The repo has no submodules, so CI's submodules: true checkout adds nothing either.

Also changed

content/docs/guide/ci-cd-pipeline.md — the ## Lint (lint.yml) section enumerates that job's steps and states that it gates errors and not warnings. Adding a step without it would leave the page describing a job that no longer exists, which is the drift three separate suites in this repo already exist to prevent. The addition documents the new step and its errors-only split, and names #5127 as the owner of the warning arm. No count is quoted, for the reason the section's own --max-warnings paragraph gives.

Generated by Claude Code

The root `check` script is `node packages/cli/dist/cli.js check` — `objectui
check`, the command this repository ships, pointed at this repository's tree.
No workflow ran it. It exited 1 with 64 errors on `main`, and had done since
the first `tsconfig.json` grew a comment, until someone ran it by hand while
measuring something unrelated (#5237, fixed by #5245).
Adds two steps to the existing lint job: build the CLI and its workspace
dependency closure, then run `pnpm check`. Blocking on the ERROR arm only,
which is the command's existing behaviour rather than a setting chosen here —
a parse failure increments the error count, a non-zero count is the only thing
that exits 1, and the unknown-schema-type warnings print without touching the
exit code. No warning is promoted, reclassified or suppressed; #5127 still
owns that arm.
The build goes through pnpm rather than turbo deliberately. A turbo cache hit
restores a task's recorded outputs, and an entry recorded with an empty output
set replays as "cache hit, replaying logs" plus FULL TURBO while writing no
`dist/` — measured here, with the CLI then dying on ERR_MODULE_NOT_FOUND. A
blocking gate must not be able to fail for a reason that lives in a cache
rather than in the tree it is judging.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
@os-support-ai
os-support-ai marked this pull request as ready for review August 18, 2026 23:36
@os-support-ai
os-support-ai added this pull request to the merge queueAug 18, 2026
Merged via the queue into main with commit a369c2bAug 18, 2026
20 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-5246-wire-pnpm-check-into-ci branch August 18, 2026 23:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No workflow runs pnpm check, so the CLI's own command can sit red on main indefinitely — 64 errors went unnoticed until #5237

2 participants

@os-support-ai@claude