Repository navigation
ci: a wake lane's "upstream not sealed" is a WAIT, and the poll never retries it - #3747
Conversation
… retries it
Manufacturing#67 / Crm#66 — the nightly release poll is red in both repos, and
the shared lane's own diagnostic sends the reader to a mechanism that does not
exist on that trigger.
Two halves, measured on run 34184029469 (Manufacturing, schedule) and
34185317544 / 34245799929 (Crm, schedule + framework-released):
1. THE PROMISE. node-repo-gate.yml said "The upstream's own publish-bake for this
identity re-enables this run" and node-repo-publish-bake.yml's step summary
said the opposite — "the next scheduled run ... rebuilds once the upstream has
published", plus "the dependent-dispatch lane was removed deliberately". The
second is stale (the dispatch lane exists and works: Crm red 15:36Z, its
meshweaver-upstream-published wake green 16:01Z) and the first is false for a
POLL, which re-resolves a moving tag and therefore asks about a DIFFERENT
identity next time. Both lanes now say one true thing, under one title
("Upstreams not ready"), with a table naming how each trigger learned the
identity and which of them makes an unsealed upstream this repo's fault.
It still fails RED on every trigger. No exit-zero arm, no continue-on-error,
no if: about an input — the event changes what is SAID, never whether the
gate runs.
2. THE RECIPE. CiContentBake.md's "four parts" told a satellite to resolve the
TESTER on a release trigger and stopped there — written before MeshWeaver#3022
made the portal a second required image. A caller following it moves one half
of the wave and leaves platform-image-digest a literal, which the lanes refuse
as "the tester image and the platform image do NOT resolve one framework
identity". Part 3 now requires BOTH images from ONE tag, with the per-trigger
entitlement table (:main for the poll, never :latest — promote applies latest
to mw-plugin-test only) and the wait-vs-failure rule.
Also splits ABSENT from COULD-NOT-DETERMINE in the gate's Azure seed probe, the
way check-release-availability.sh already does: an unreadable share is a hold
naming the share, not a missing upstream publication.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Approval recommended
The changes are narrowly scoped to CI/docs diagnostics and consistency, with no confirmed functional regressions found in the updated logic.
Pull request overview
Updates the shared node-repo CI guidance and reusable workflows to correctly describe (and consistently report) the “upstream not sealed for this identity” condition as a WAIT—especially for scheduled release polls that do not retry the same identity—and to document/require resolving both wave images (tester + portal) together.
Changes:
- Rewrites the
node-repo-publish-bake.yml“Upstreams not ready” step summary + annotation to reflect trigger-specific semantics (pin wrong vs wave in flight vs schedule wait) and the actual wake mechanism. - Adds a shared
upstream_not_ready()diagnostic helper innode-repo-gate.ymland uses it for upstream-seed 404/“not sealed” failures; splits Azure probe “absent” vs “could-not-determine”. - Updates
CiContentBake.mdto require FOLLOW_RELEASE to resolve both tester+portal from one tag, documents which triggers may resolve which refs, and codifies the “WAIT but still RED” rule.
File summaries
| File | Description |
|---|---|
| src/MeshWeaver.Documentation/Data/Architecture/CiContentBake.md | Updates the CI content bake contract to resolve tester+portal from the same wave and documents trigger entitlement + “upstream not sealed” semantics. |
| .github/workflows/node-repo-publish-bake.yml | Aligns the “Upstreams not ready” diagnostics with measured behavior and clarifies what actually re-enables waiting runs. |
| .github/workflows/node-repo-gate.yml | Introduces a unified upstream-not-ready diagnostic helper and improves Azure seed probe error classification. |
Review details
Suppressed comments (1)
.github/workflows/node-repo-gate.yml:698
- This error annotation appends
This run's event was ..., but in a reusable workflow that value will beworkflow_calland doesn't help diagnose the caller trigger (push/schedule/dispatch). Removing it avoids confusion and shortens the annotation.
echo "::error title=Upstreams not ready — did not gate::upstream '$src' has no SEALED publication at $where for framework identity $IDENTITY. What re-enables it is the upstream's own publish-bake dispatching meshweaver-upstream-published for this identity — NOT the schedule poll, which re-resolves a moving tag and therefore asks about a different identity next time. This run's event was ${GITHUB_EVENT_NAME:-unknown}."
- Files reviewed: 3/3 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| echo "This run's event was \`${GITHUB_EVENT_NAME:-unknown}\`." | ||
| echo "" |
|
🔀 Merge-queue steward: re-queued alone (bisecting) — bisecting: your group of 3 pull requests failed on an uncatalogued assertion while this PR's own run was green; re-queued ALONE — if the solo build fails too, the PR stays out (group: #3746, #3739).
enqueued |
Fixes the shared half of MeshWeaver.Manufacturing#67 and MeshWeaver.Crm#66 — the nightly release poll is red in both repos and the shared lane's own diagnostic points the reader at a mechanism that does not exist on that trigger.
What was measured
schedule(run 34184029469)test-repos / Gate shard 1/1framework-identity: MISMATCH — the bake published under 's4e84d301…' but '/portal' resolves 's556a0d43…'— tester followed:latest, portal stayed a literalschedulememex build pluginupstream 'plugins' has no SEALED publication … for identity s4e84d301…→ exit 8schedule(run 34185317544)publish-bakes4e84d301…vssf456af88…meshweaver-framework-released(run 34245799929)publish-bakeUpstreams not ready— the lane resolved both by version (identity MATCH),pluginswas simply not sealed yetCrm's poll has been red 8 of the last 10 nights; Manufacturing's on both nights it has run.
1. The promise the lane could not keep
node-repo-gate.ymlrefused with "The upstream's own publish-bake for this identity re-enables this run."node-repo-publish-bake.yml's step summary for the same condition said the opposite:Both halves are wrong. The dispatch lane exists and works — measured on Crm 2026-09-08: the availability gate failed at 15:36Z and the
meshweaver-upstream-publishedwake for the same set succeeded at 16:01Z. And the poll does not retry the identity it failed on: it re-resolves a moving tag, so tomorrow's run asks about whatever has been promoted since.Both lanes now carry one statement under one title (
Upstreams not ready), with a table naming how each trigger learned the identity and which of them makes an unsealed upstream this repository's fault:push/pull_requestrepository_dispatchschedule🚨 It still fails RED on every trigger. No exit-zero arm, no
continue-on-error:, noif:asking about an input — the event changes what is said, never whether the gate runs. Verified by executing the function: exit 1, one::error title=Upstreams not ready, one step summary.The rejected alternative is written into the doc so it is not re-proposed: having the poll walk back to the newest identity that has a complete publication reads like a narrowing but is a fallback — an upstream that stops publishing would leave every dependent's poll green forever, the same trapdoor as falling back to the pin.
2. The recipe that produced the mixed pair
CiContentBake.md's "four parts a repo has ALL of them or it follows nothing" told a satellite to "on a release trigger resolve the digestMW_TEST_IMAGEcurrently points at" — and stopped there. That text predates MeshWeaver#3022, which made the portal a second required image. A caller following it faithfully moves one half of the wave and leavesplatform-image-digest:a literal → two CD waves in one bake → the MISMATCH above.Part 3 now requires both images from one tag, with the per-trigger entitlement table (
:mainfor the poll, never:latest—promotephase B applieslatesttomw-plugin-testonly, so the portal has no such tag), and the wait-vs-failure rule. MeshWeaver.Reinsurance#179 is the landed shape the two satellite PRs adopt.3. Also
The gate's Azure seed probe now splits absent from could-not-determine, the way
check-release-availability.shalready does — an unreadable share is a hold naming the share, not a missing upstream publication.exists=unknownused to be reported as "the upstream has not published".Denominator — 6 of 6 satellites read, 3 carry the defect
platform-image-digeston the release pathneeds.preflight.outputs.portal-image-digestneeds.preflight.outputs.{portal,bake-portal}-image-digestupstream-seed)Each ❌ was confirmed from the failing job's log, not inferred from the text: the same
framework-identity: MISMATCHon all three, all three resolving testers4e84d301…against their own older portal pin.That three repositories reached the identical defect independently is the reason the doc change matters more than the three workflow fixes: they were each following what this page told them to do.
Pairs-with: none — no public type or member is removed; this diff is two workflows and one doc page.
Verification
check-workflow-shell.py,check-workflow-yaml-keys.py,check-workflow-timeouts.py— all clean.run:block passesbash -nwith expressions neutralised.upstream_not_readyfunction executed standalone: exit 1, correct annotation, correct summary.