Skip to content

publish-all rewrites the tree with format and rebuild *before* require-green-ci checks the pre-format commit — the gate's own docstring names the divergence it then creates #949

Description

@sroussey

What

The restored gate (#916, b214ea6fd) is good and it works — see the reinstatement proof at the bottom. This is one ordering residual in the chain around it.

package.json:56:

"publish-all": "bun run format && bun run rebuild && bun run require-green-ci && bun run bunset && bun run publish-login && bun run publish-workspaces",

format is oxlint --fix && oxfmt "{packages,providers,examples}/*/src/**/*.{js,ts,tsx,json}" — it writes to source. rebuild regenerates dist. Both run before the gate. require-green-ci then resolves git rev-parse HEAD and asks GitHub about that SHA:

$ sed -n '44,47p' scripts/require-green-ci.ts
  const head = spawnSync("git", ["rev-parse", "HEAD"], { encoding: "utf8" });
  if (head.status !== 0) fail(`Could not read HEAD: ${head.stderr.trim()}`);
  const sha = head.stdout.trim();

So the run it checks covers the commit as it was before format touched it, while publish-workspaces packs the working tree. The script knows:

$ sed -n '84,93p' scripts/require-green-ci.ts
  const dirty = spawnSync("git", ["status", "--porcelain"], { encoding: "utf8" });
  if (dirty.status === 0 && dirty.stdout.trim() !== "") {
    // Not fatal — `publish-all` runs `format` and `rebuild` ahead of this, so a
    // dirty tree is expected. But the run above tested the commit, not the tree
    // about to be packed, and that difference is worth naming.
    console.warn(
      `⚠ Working tree is not clean; the run above tested ${sha.slice(0, 7)}, not what is on disk.`
    );
  }

A console.warn inside a release script that runs unattended and is followed immediately by bunset (commit = true, tag = true, push = true, release = true in .bunset.toml) is not a control. It is the same shape as the comment-counts that #906 replaced with a ratchet.

Why it matters

The gate's own docstring states the principle it is then arranged to violate:

"the commit is what consumers install, not the working tree"

Under the current ordering the thing checked and the thing published are, by construction, two different trees whenever format has anything to do — which is exactly the case an unattended release cannot distinguish from the clean one. The severity is bounded (oxfmt is whitespace, oxlint --fix is autofixes) but the guarantee is unbounded in the wrong direction: oxlint --fix applies rule autofixes to source, and nothing re-runs a test after it.

This is not the 0.4.7 failure returning. It is the one seam the replacement left, and it costs two characters to close.

Proposed fix

Pick one:

  1. Reorderbun run require-green-ci && bun run format && bun run rebuild && bun run bunset && …. The gate then reads the commit while it still is the commit. format before the gate buys nothing anyway: format-check has run in CI since 509724031 (.github/workflows/test.yml:95-96), so a commit that is green is already formatted, and format at publish time is a no-op on exactly the commits the gate lets through.
  2. Or make the dirty-tree check fatal rather than a warning, with the same WORKGLOW_SKIP_CI_GATE=1 escape the rest of the script uses.

Option 1 is strictly better: it removes the divergence instead of refusing to publish through it, and it makes format at publish time redundant, which is the honest reading of what CI now covers.

Extend PublishGate.test.ts with the ordering assertion it already has the shape for — it asserts require-green-ci comes before bunset; add that it comes before format.

The gate itself is verified — reinstated and measured

$ python3 -c "...replace 'bun run rebuild && bun run require-green-ci && bun run bunset'
                   with  'bun run rebuild && bun run bunset' in package.json"
$ bunx vitest run packages/test/src/test/util/PublishGate.test.ts
 FAIL  src/test/util/PublishGate.test.ts > the release gate on publish-all > checks the commit's CI run before it publishes
 AssertionError: expected 'bun run format && bun run rebuild && …' to contain 'require-green-ci'
 FAIL  src/test/util/PublishGate.test.ts > the release gate on publish-all > gates before it bumps, not after
 Test Files  1 failed (1)

The ratchet fails when the defect it was written for is reinstated. #902 is closed for the right reason.

Measured on origin/main @ 2d36880 (0.6.0). Found during the 2026-09-14 review of packages/.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions