Skip to content

chore: hold every declared package to the workflow steps that ship it - #838

Merged
allxsmith merged 6 commits into
mainfrom
chore/710-release-wiring
Oct 1, 2026
Merged

allxsmith merged 6 commits into
mainfrom
chore/710-release-wiring

Conversation

@allxsmith

@allxsmith allxsmith commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Closes #710.

PNPM_PUBLISHED says which packages publish, and publishable-manifests.test.mjs holds that to the release configs. Nothing held it to the workflows that act on it, which is how #706 happened: the ESLint plugin was declared, CI was green, and it published nowhere.

This adds a release-wiring conformance check. For every package in PNPM_PUBLISHED it asserts:

  • a semantic-release step in ci.yml's publish job, matched on working-directory rather than the step name, since a copied step that was renamed but not retargeted still releases the package it came from;
  • <dir>/coverage in the Archive Coverage path list;
  • a leg in supply-chain.yml's consumer-sbom matrix, by the name a consumer installs;
  • a place in the verify-provenance job's npm install, which verify-attestation.mjs reads its roster back from.

Each message names the file, the package and the step to add. A renamed job or step is reported with the constant to update rather than passing.

The root declares no YAML dependency, so the workflows are read by a small indentation-based reader in the file, for the reason parseWorkspacePackages already gives. It reads block mappings, block sequences, and plain, quoted and literal scalars. Anything else reads as missing, and since the check only asserts presence, that fails the check rather than passing it.

scripts/release-wiring.test.mjs drives the rule on fixtures and runs it against the real workflows, including removing one package from each surface of the real files to show each one is really being read.

Also here: CONTRIBUTING.md said pnpm all doesn't run the conformance checks. It has since #686, so that sentence goes.

Not in this PR:

  • The measured closure table above consumer-sbom. It has no row for the plugin today, so asserting it would fail here. The row needs a measurement from a dispatch and lives in a workflow file, which is human-authored, so the assertion follows once the row lands.
  • The package rosters in SECURITY.md and the security guide. They are prose, and need a shape a check can read first.
  • Whether each leg succeeded on its last release run, which needs run history and reads better as its own alert.

pnpm all passes locally.

Summary by CodeRabbit

  • New Features
    • Added a conformance check that verifies published packages are represented across release, coverage, software bill of materials, and provenance workflows. Missing or invalid workflow entries are reported as violations.
  • Documentation
    • Updated contributor guidance by removing the note about running conformance checks after changes to the workspace configuration.

PNPM_PUBLISHED says which packages publish, and a test holds that to the
release configs, but nothing held it to the workflows that act on it. So a
package could be declared publishable and publish nowhere with CI green,
which is what #706 was.

The new release-wiring conformance check reads the roster and asserts, for
each package, a semantic-release step in ci.yml's publish job, its coverage
directory in Archive Coverage, a consumer-sbom matrix leg, and a place in
verify-provenance's npm install. Each message names the file, the package
and the step to add.

The release step is matched on its working directory, not its name, since
a copied step renamed but not retargeted still releases the package it was
copied from. The root declares no YAML dependency, so the workflows are read
by a small indentation reader in the file, for the reason
parseWorkspacePackages already gives. A shape it cannot read comes back as
missing, which fails the check rather than passing it.

Refs #710
@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 59 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: allxsmith/bestax/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 5730f729-0f1e-4c70-af6f-0fc536fa48be

📥 Commits

Reviewing files that changed from the base of the PR and between 11563d4 and 7c0df7c.

📒 Files selected for processing (3)
  • CONTRIBUTING.md
  • scripts/check-conformance.mjs
  • scripts/release-wiring.test.mjs

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: allxsmith/bestax/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 0ebc0c6a-f6a7-499c-bc00-7523d6314d4b

📥 Commits

Reviewing files that changed from the base of the PR and between a962259 and 11563d4.

📒 Files selected for processing (3)
  • CONTRIBUTING.md
  • scripts/check-conformance.mjs
  • scripts/release-wiring.test.mjs
💤 Files with no reviewable changes (1)
  • CONTRIBUTING.md

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

The conformance runner adds a release-wiring check for packages in PNPM_PUBLISHED. The check validates release steps, coverage paths, consumer-SBOM matrix entries, and provenance install commands. New tests cover workflow parsing and missing or invalid wiring.

Changes

Release Wiring Conformance

Layer / File(s) Summary
Workflow and command readers
scripts/check-conformance.mjs, scripts/release-wiring.test.mjs
New helpers parse supported block-style YAML structures and extract package names from npm install commands. Tests cover YAML traversal, scalar handling, and command parsing.
Release workflow validation
scripts/check-conformance.mjs, scripts/release-wiring.test.mjs
The check validates each package’s semantic-release step, archived coverage path, consumer-SBOM matrix entry, and provenance install command. Tests cover missing, misplaced, ambiguous, commented, and unreadable workflow entries.
Check registration and repository validation
scripts/check-conformance.mjs, scripts/release-wiring.test.mjs, CONTRIBUTING.md
The check reads the published-package roster, reports invalid package manifests, and is registered for standard selection. Repository-level tests exercise workflow mutations. The contributor instructions about running conformance checks after workspace edits are removed.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Other · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant Runner as Conformance runner
  participant Check as checkReleaseWiring
  participant Roster as PNPM_PUBLISHED
  participant CI as ci.yml
  participant SupplyChain as supply-chain.yml
  participant Validator as releaseWiringViolations
  Runner->>Check: Run release-wiring check
  Check->>Roster: Read published packages
  Check->>CI: Read CI workflow
  Check->>SupplyChain: Read supply-chain workflow
  Check->>Validator: Validate packages against workflow wiring
  Validator-->>Runner: Return violations
Loading

Merge Risk: ⚪ Minimal · up to 11563

The change validates declared packages against release and supply-chain workflow rosters without changing publishing behavior. No merge-blocking issue remains; merge after normal checks pass.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: enforcing workflow coverage for every declared package.
Description check ✅ Passed The description provides a detailed change summary, affected workflow surfaces, linked issue, testing information, scope exclusions, and local validation results. It does not use the template headings…
Linked Issues check ✅ Passed Issue #710 requires a check for every package in PNPM_PUBLISHED across four workflow surfaces. releaseWiringViolations checks the publish job semantic-release step by working-directory, the un…
Out of Scope Changes check ✅ Passed The changed files support issue #710. check-conformance.mjs implements and registers the check. release-wiring.test.mjs tests the check. The CONTRIBUTING.md edit removes outdated instructions ab…
Docstring Coverage ✅ Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 2 files.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://8c0e4926.bestax.pages.dev

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review — 0 blocking · 3 advisory

# Severity Area Finding Location
1 🔵 Advisory Robustness Archive Coverage is located with .find over every job's steps, so a second step by that name added earlier in the file would become the one validated while the real archive step goes unchecked. scripts/check-conformance.mjs:4446
2 🔵 Advisory Robustness npmInstallNames misses an npm install nested in an if/for/while compound, and skips the whole line when a trailing comment contains an apostrophe (tokenize throws). Both fail closed — verified empirically. scripts/check-conformance.mjs:4350
3 🔵 Advisory API The coverage assertion couples "declared in PNPM_PUBLISHED" to "produces a jest coverage directory". A future published package with no test suite would be told to add a path entry that never exists. scripts/check-conformance.mjs:4461

Overall: Sound, and unusually well evidenced for a check of this kind. The design decision that carries it — match the release step on working-directory rather than the step name, and let any shape the hand-rolled reader cannot parse read as missing — is the right polarity, and I confirmed it holds on the real files rather than only on fixtures. The riskiest part is the bespoke YAML reader, since it is a second parser of a format nothing else in scripts/ parses; I exercised it against both real workflows and it reproduced the publish job's step list, working directories, literal run: blocks, the with.path block scalar, and the strategy.matrix.include legs correctly. A human should focus on whether the four asserted surfaces are the right four — the PR body names three deliberate exclusions (the closure table, the SECURITY.md rosters, per-run success) and I verified the first: supply-chain.yml:86-89 genuinely has no eslint-plugin row, so asserting it today would red this PR.

Residual risk:

  • Presence, not effect. An if: false, a continue-on-error: true, or a --dry-run on a Semantic Release (<pkg>) step satisfies the check. Verified: injecting if: false into the bulma-ui release step still returns 0 violations. The header comment states this contract explicitly ("It asserts that the wiring exists, not that it is correct"), so it is accepted rather than missed — but it is the way #706 could recur in a shape this check cannot see.
  • Word-match false pass on surface 1 (open). The release-step filter is a word match for semantic-release over the comment-stripped run:. A step with working-directory: <pkg> whose script merely mentions the word outside a command position — echo "semantic-release will run" — would register that package as released. The symmetric case is already closed on surface 4 (there is a test that a name in an echo is not an install); surface 1 has the plugin-path test (@semantic-release/npm) but no echo test. Contrived, and it needs a deliberate workflow edit, so not posted as a finding.
  • Reader shapes fail closed, confirmed. Folded (>), flow ([a, b], {k: v}) and alias (*x) values return null from yamlScalar, and a flow-style matrix produces the single "no legs could be read" violation rather than a pass — pinned by tests and re-checked by hand.
  • Shell-parse gaps fail closed, confirmed. npm install a && npm install b yields both names (tokenize splits && into two operator words), if true; then npm install a; fi yields nothing, and an install line whose trailing comment holds an apostrophe yields nothing. Each miss produces a violation, never a silent pass. The spurious captures I could find (a --prefix value is read as a package name) can only mask a real gap if a package were literally named after a flag value.
  • Surfaces outside the diff. Asserting a fifth surface (the measured closure table) is blocked on a measurement that must land in a human-authored workflow file, and the roster prose in SECURITY.md has no machine-readable shape yet. Both are named in the PR body and neither is regressed here.
  • Environment note, not a finding. Locally version-regression fails (shallow clone, --allow-untagged territory) and a block of scripts/*.test.mjs assertions fail on an absent bulma-ui/dist. Both are pre-existing and unrelated; all 29 release-wiring tests and every other conformance check pass on this branch.

🏄 Clean little set on this one — the reader paddles out, actually catches the real workflows instead of just the fixtures, and every wipeout it can have dumps it on the safe side of the break. Good to go.

…first

The coverage step is found by name across every job, and taking the first
match meant a second step by that name earlier in ci.yml was validated
while the one that really archives coverage went unchecked. More than one
now fails the check, naming the jobs they are in.

The release steps have no such hole, since they are collected rather than
looked up, so a duplicate adds a directory instead of displacing one. A
test pins that. npmInstallNames also names its known misses, both of which
read as not installed.

Refs #710
@allxsmith

Copy link
Copy Markdown
Owner Author

On the three advisories:

  1. A second Archive Coverage step. Taken, in 11563d4. The check now gathers every step by that name across ci.yml's jobs. None reports the missing step as before, more than one is a violation naming the jobs (it won't guess which one keeps coverage), and exactly one is validated. Two new cases put a decoy before the real step, in the same job and in an earlier one, and both passed silently before the fix. The other lookups have no equivalent hole: release steps are collected into a set by working directory, and the SBOM legs and provenance installs are unions over every item, so a duplicate can add but never displace.
  2. npmInstallNames limits. No behaviour change, since both fail closed. A comment beside it now names them: an install nested in if/for/while, and a line whose trailing comment has an unpaired quote, both read as not installed.
  3. Coverage assumed for every published package. Kept. The repo's coverage policy already requires a jest suite with thresholds for every package, so a published package with no coverage directory is the thing worth hearing about.

@allxsmith

Copy link
Copy Markdown
Owner Author

deep-review: fresh. 11563d4 changes how the Archive Coverage step is found; review the check as it stands now.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review (verify) — 0 resolved · 0 open

# Severity Area Finding Location
— — — No open threads to settle — the prior deep review posted zero inline comments. —

Overall: This pass settled threads and reviewed no commits. The earlier deep review (marked claude-deep-review, submitted 2026-09-30T02:14Z) raised 0 blocking findings and 3 advisories, and advisories are summary rows by construction — so it left no inline threads behind, and a verify pass has nothing to re-examine. Nothing was resolved and nothing remains open.

For the maintainer — the steer asked for a run this one could not give. The deep-review: fresh comment was read (it arrived as this run's focus), but the run was still dispatched in verify mode, so 11563d4a has not been reviewed by anyone. Per CLAUDE.md a fresh steer stays selected once it is the newest triage+ deep-review: comment, so removing and re-adding the deep-review label should start a genuine fresh pass over the current code. Re-adding a label that is already present emits no labeled event — it has to come off first.

Residual risk: Not assessed — a verify pass raises no findings and re-reviews no code, so the residual-risk hunt from the prior review stands unchanged and un-rechecked against 11563d4a. The three advisories answered in the comment above (duplicate Archive Coverage step, npmInstallNames shell-parse gaps, coverage assumed for every published package) were not re-verified here; the first is the one 11563d4a claims to close, and confirming that claim is exactly what the fresh run is for.

🏄 Nothing to settle out here, dude — the last session left a totally clean lineup, no loose threads bobbing around. But that "fresh" call got routed to the verify break, so the new commit's wave is still unridden. Pop the label off and back on and let a real session paddle out.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://fe275024.bestax.pages.dev

@allxsmith

Copy link
Copy Markdown
Owner Author

deep-review: fresh

11563d4 changes how the Archive Coverage step is found, so review the check as it stands now.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://047c9d85.bestax.pages.dev

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review — 0 blocking · 4 advisory

# Severity Area Finding Location
1 🔵 Advisory Robustness The ambiguity branch refuses to check coverage at all when two steps share the name — even when both list every directory. Verified: adding a second complete Archive Coverage step to the real ci.yml returns the ambiguity violation, not a pass. Deliberate ("will not guess"), and it fails loudly, but it means the only legal shape is exactly one such step. scripts/check-conformance.mjs:4461
2 🔵 Advisory Robustness Presence, not effect (the header comment's own contract): if: false, continue-on-error: true and --dry-run on a Semantic Release (<pkg>) step all satisfy surface 1. Verified empirically against the real ci.yml. scripts/check-conformance.mjs:4430
3 🔵 Advisory API The coverage assertion still couples "declared in PNPM_PUBLISHED" to "produces a jest coverage directory". A future published package with no test suite would be told to add a path entry for a directory that never exists. scripts/check-conformance.mjs:4478
4 🔵 Advisory Correctness Comment imprecision, safe direction: the new npmInstallNames "known misses" note says an install nested in if/for/while reads as not installed, but if true; then npm install a && npm install b; fi yields ["b"] — the miss is the first command after then/do, not every nested install. The note understates coverage, so nothing fails open. scripts/check-conformance.mjs:4346

Overall: Sound, and 11563d4a closes the hole the previous pass flagged cleanly — the coverage step is now collected across every job and more than one is a violation naming the jobs, which strictly dominates the old .find() (a decoy earlier in the file used to be validated while the real archive step went unchecked; it now reds). I re-ran this rather than reading it: all 32 tests in scripts/release-wiring.test.mjs pass, pnpm check:conformance is green on all 23 checks including release-wiring, and eslint/prettier are clean on both changed files. I also swept the rest of the check for the same class of defect the steer names — a lookup that silently validates the wrong thing — and the remaining by-key lookups (ciJobs.get('publish'), supplyJobs.get('consumer-sbom'), supplyJobs.get('verify-provenance'), and yamlMap's first-wins on duplicate keys) are all keyed on identifiers whose duplicates GitHub's own workflow parser rejects, so there is no second instance of the hole. The human should focus on advisory 1 — whether "exactly one Archive Coverage step, forever" is the constraint you want ci.yml held to.

Residual risk:

  • Duplicate-name hole elsewhere — refuted. Release steps are collected into a Set of working directories, so a duplicate adds a directory rather than displacing one; the new test two release steps for one directory do not stand in for a missing one pins it, and the sbom legs and the provenance install roster are collected the same way. The only remaining by-name lookup is the coverage step, which this commit converts from "take the first" to "report them all".
  • Word-match false pass on surface 1 (narrowed, still open). The filter is /(^|\s)semantic-release(\s|$)/ over the comment-stripped run:. I retested the two shapes I named last time against the real publish job: echo "semantic-release will run" does not match (the opening quote is not whitespace), and a plain-scalar trailing comment is stripped by yamlScalar. What still passes is a trailing comment inside a run: | block (shellCode strips only whole-line comments) and a bare unquoted echo semantic-release. Both need a deliberate, nonsensical edit to a human-authored workflow, so not posted.
  • Reader shapes fail closed — re-confirmed on the real file. A flow-sequence path: produces five "has no <dir>/coverage" violations; a renamed coverage step produces the "update COVERAGE_STEP" message; folded/flow/alias values return null from yamlScalar. A column-0 line inside a run: | block would break the job map — and that too fails closed, because publish would then be unfindable.
  • npmInstallNames misses fail closed — re-confirmed. if true; then npm install a; fi reads as nothing, for p in a b; do npm install $p; done reads as nothing, and a trailing comment holding an apostrophe reads as nothing (tokenize throws, so the line is skipped). Every miss becomes a violation, never a silent pass. npm install --prefix /tmp/x a still captures /tmp/x as a name, which can only mask a real gap if a package were literally named after a flag value.
  • Surfaces not asserted (open, and named in the PR body). The measured closure table above consumer-sbom has no eslint-plugin row — re-read at supply-chain.yml:86-89 and confirmed, so asserting it today would red this PR; and the SECURITY.md rosters have no machine-readable shape. Neither is regressed here.
  • Environment note, not a finding. 18 of 999 scripts/*.test.mjs assertions fail locally on an absent bulma-ui/dist (constants-subpath, color-tuple-css, helper-prop-collisions, publishable-manifests, eslint-plugin-docs). Pre-existing and unrelated — every release-wiring test passes.

🏄 Last set had one rip current and this commit roped it off — no more quietly checking the decoy wave while the real one closes out behind you. Every wipeout it can still take dumps it on the safe side of the break. Good to go.

@allxsmith

Copy link
Copy Markdown
Owner Author

On the fresh review's advisories:

  1. Exactly one Archive Coverage step. Kept on purpose. Two steps by that name, even two complete ones, leave the check unable to say which one keeps coverage, so it says so and names the jobs rather than guessing. Renaming one is a one-word fix, and it's the shape ci.yml has today.
  2. Presence, not effect. As the header says, the check asserts that the wiring exists, not that it's correct. A step disabled with if: false or --dry-run is a deliberate edit to a human-authored workflow, and review catches it there.
  3. Coverage assumed for every published package. Kept, for the reason in the earlier reply: the repo's coverage policy requires a jest suite with thresholds for every package.
  4. The npmInstallNames comment. Fixed in the latest commit. The note now says the miss is an install that directly follows a shell keyword such as if, then or do, and that later commands in the same body are read.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://302d02cc.bestax.pages.dev

@allxsmith allxsmith added the needs-human-review Loop converged (or contested): awaiting owner review + manual merge label Sep 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📸 Story screenshots at handoff — 7959e7c

No Storybook stories map to this PR's changed files — nothing to screenshot. (workflow run)

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://99b7835a.bestax.pages.dev

@allxsmith
allxsmith merged commit d965980 into main Oct 1, 2026
13 checks passed
@allxsmith
allxsmith deleted the chore/710-release-wiring branch October 1, 2026 03:02
@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 5.19.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 1.14.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 2.25.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 4.2.13 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

deep-review needs-human-review Loop converged (or contested): awaiting owner review + manual merge released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nothing ties a publishable package to its release wiring, so #706 can repeat silently

1 participant