You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ci(module-pack): a caller can withhold packages from the hand-over (publish-withhold) - #6461
node-repo-module-pack.yml gets one optional input, publish-withhold: the names of the packages a publishing call must not hand to the registry. Their modules are still built, inspected and tested, and their bundle artifacts still reach the caller's gates. Only the hand-over is left out, and the receipt says publication: withheld.
Empty by default, so every existing caller behaves exactly as before.
Why
MeshWeaver.Plugins has published no module bundle, tag or seal since 2026-10-09T13:47Z. Its settle-locks job decides whether a main run may publish, and it decided for the whole tree: one package with an unsettled lock or an unstamped platform floor withheld all 78. A package merged in the last hour is in that state by definition (its floor is stamped by the main run that verified it, through a pull request, and then its lock settles through another), so under steady merging a commit with nothing waiting only appears in a quiet stretch of more than an hour.
Evidence, from Plugins main run 38099782041 (push, 45cff25a8e), job Settle manifest locks (main owns them):
Governance: its sources changed since its floor was stamped, so minMeshVersion 3.1.10484 is unverified for them
Hosting: its sources changed since its floor was stamped, so minMeshVersion 3.1.10486 is unverified for them
Store: its sources changed since its floor was stamped, so minMeshVersion 3.1.10487 is unverified for them
##[notice]45cff25a8e is NOT settled (22 lock(s) would move) — this run publishes, seals and tags nothing
and in the same run Tag module versions, publish-bake and publish-bake-previous-epoch concluded skipped while every gate was green.
The Plugins half decides per package and needs the lane to leave out exactly the modules of the packages that wait. publish is one boolean for the whole call, so the lane could not do that.
How
Plan step: a module whose entry's package is in the list (whole-line match, grep -qxF) gets need_publish=false and the fact withheld=true, whatever the ledger answered. Both publish modes read need_publish, so neither hands it over. No Published ledger record is written for it, so a later run still publishes it.
Receipt: published: false, publication: withheld.
Verdict (node-repo-pack-verify.py): the note names the withheld modules beside the superseded ones. No new failure condition.
The lane executes the list and does not derive it. Which packages wait, and that everything depending on a waiting package waits with it, is the caller's decision.
Tests
module-pack-batch.py --self-test: workflow_publish_withhold_problems asserts the input, the exact-name match, the plan line and both receipt lines against the real workflow, with five negative controls (hand-over left on, substring match, receipt says published, receipt does not name withheld, input missing).
node-repo-pack-verify.py --self-test: one published and one withheld is green and names the module; a run whose only leg was withheld says so; negative control with nothing withheld.
Run locally: both self-tests, check-workflow-shell.py, check-workflow-yaml-keys.py, check-workflow-timeouts.py, and dotnet build src/MeshWeaver.Documentation -c Release -warnaserror (0 warnings, 0 errors).
Not verified: the plan step has not run inside the lane yet. The first run that exercises it is the Plugins pull request that passes the input.
Order
This lands first. The Plugins pull request that passes publish-withhold cannot start a run before this is on main (an input the lane does not declare is refused at workflow start), which is the safe direction: the caller can never withhold on a lane that ignores the list.
…ublish-withhold)
The module lane's `publish` is one boolean for every module of the call. A caller whose
publication is decided per package (MeshWeaver.Plugins: a package whose lock is not settled,
or whose platform floor is not stamped for its sources, waits with its dependents) could
therefore only publish all of its modules or none, and one waiting package withheld the
whole tree: nothing was handed to the registry from Plugins main between 2026-10-09T13:47Z
and 2026-10-11.
`publish-withhold` takes the names of the packages a publishing call must not hand over.
Their modules are still built, inspected and tested and their bundles still reach the
caller's gates; the plan step turns only the hand-over off (exact match on the entry's
`package`), and the receipt says `publication: withheld`, which the lane's verdict names.
Empty by default, so every other caller is unchanged.
Guards: module-pack-batch.py --self-test asserts the input, the exact-name match, the plan
and both receipt lines, each with a negative control; node-repo-pack-verify.py --self-test
covers the verdict's note, with a negative control.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The reason will be displayed to describe this comment to others. Learn more.
Correct, and fixed in 309ef0c. Under publish-mode: staged a withheld module reached the staging step with need_publish=false and was recorded as "the module build ledger already serves this key", which is false for a key no registry serves.
The staging step now reads the withheld fact and takes its own branch before the ledger one. The record's reason says the caller withholds the package (publish-withhold), that the registry does not serve the key yet, and that a later run of the caller hands it over.
module-publication.py no longer asserts one cause for every record in its nothing-owed summary. It lists each record with the reason that record states. The per-record log line already printed rec.reason, so it now carries the right text too.
Guard: module-pack-batch.py --self-test asserts the staged branch against the real workflow, with a negative control that removes it and must be caught.
… own reason
Under publish-mode: staged, a withheld module reached the staging step with need_publish=false
and was recorded as "the module build ledger already serves this key" — false for a key no
registry serves, and the publication lane repeated it in its summary.
The staging step now reads the `withheld` fact and records that the caller withholds the
package and that the registry does not serve the key yet. The publication lane's
nothing-owed summary lists each record's own reason instead of asserting one for all.
module-pack-batch.py --self-test asserts the staged branch, with a negative control.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Report withheld modules when staged publishing has mixed receipts
.github/scripts/node-repo-pack-verify.py:238
A staged publishing call withholds only some packages, so its receipts contain both staged and withheld entries. This condition skips the withheld-reporting branch whenever staged is non-empty, and the following staged note does not include stood_down; the gate therefore passes while omitting every withheld module. Handle the staged case first and append stood_down, then use the all-stood-down branch for runs with no staged entries.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
node-repo-module-pack.ymlgets one optional input,publish-withhold: the names of the packages a publishing call must not hand to the registry. Their modules are still built, inspected and tested, and their bundle artifacts still reach the caller's gates. Only the hand-over is left out, and the receipt sayspublication: withheld.Empty by default, so every existing caller behaves exactly as before.
Why
MeshWeaver.Plugins has published no module bundle, tag or seal since 2026-10-09T13:47Z. Its
settle-locksjob decides whether a main run may publish, and it decided for the whole tree: one package with an unsettled lock or an unstamped platform floor withheld all 78. A package merged in the last hour is in that state by definition (its floor is stamped by the main run that verified it, through a pull request, and then its lock settles through another), so under steady merging a commit with nothing waiting only appears in a quiet stretch of more than an hour.Evidence, from Plugins main run 38099782041 (push,
45cff25a8e), jobSettle manifest locks (main owns them):and in the same run
Tag module versions,publish-bakeandpublish-bake-previous-epochconcludedskippedwhile every gate was green.The Plugins half decides per package and needs the lane to leave out exactly the modules of the packages that wait.
publishis one boolean for the whole call, so the lane could not do that.How
packageis in the list (whole-line match,grep -qxF) getsneed_publish=falseand the factwithheld=true, whatever the ledger answered. Both publish modes readneed_publish, so neither hands it over. NoPublishedledger record is written for it, so a later run still publishes it.published: false,publication: withheld.node-repo-pack-verify.py): the note names the withheld modules beside the superseded ones. No new failure condition.The lane executes the list and does not derive it. Which packages wait, and that everything depending on a waiting package waits with it, is the caller's decision.
Tests
module-pack-batch.py --self-test:workflow_publish_withhold_problemsasserts the input, the exact-name match, the plan line and both receipt lines against the real workflow, with five negative controls (hand-over left on, substring match, receipt says published, receipt does not namewithheld, input missing).node-repo-pack-verify.py --self-test: one published and one withheld is green and names the module; a run whose only leg was withheld says so; negative control with nothing withheld.check-workflow-shell.py,check-workflow-yaml-keys.py,check-workflow-timeouts.py, anddotnet build src/MeshWeaver.Documentation -c Release -warnaserror(0 warnings, 0 errors).Not verified: the plan step has not run inside the lane yet. The first run that exercises it is the Plugins pull request that passes the input.
Order
This lands first. The Plugins pull request that passes
publish-withholdcannot start a run before this is onmain(an input the lane does not declare is refused at workflow start), which is the safe direction: the caller can never withhold on a lane that ignores the list.Doc:
Doc/Architecture/ModuleBuildArchitecture→ Per-module deploy, item 4.Pairs-with: none — additive optional workflow input; no public type or member is removed.
Refs Systemorph/MeshWeaver.Plugins#3326
🤖 Generated with Claude Code