Skip to content

ci: core publishes ONE event and finishes — withdraw notify-dependents; the release wave is memex's, subscribers are the Deployment records - #3185

Merged
rbuergi merged 2 commits into
mainfrom
ci/release-wave-is-memex-event
Sep 3, 2026
Merged

rbuergi merged 2 commits into
mainfrom
ci/release-wave-is-memex-event

Conversation

@rbuergi

@rbuergi rbuergi commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Core publishes ONE event and finishes — the release wave is memex's

Maintainer directive (2026-09-03): "None of the top-level repos should have any dependency to anyone else. It must be event based: (1) memex issues an event that something has a new version; (2) GitHub subscribes to this and triggers the build. Core publishes an event and finishes."

What was measured before touching anything

  • memex never dispatched. FrameworkReleaseBroadcaster (src/MeshWeaver.GitSync) has existed since 2026-08-23 with no caller in core or in MeshWeaver.Plugins (grep, both trees; the in-mesh call site carried a comment explaining why a since-retired NuGet-floor lane could not compile the reference). Loki, namespace="memex-cloud" (ci.7621), last 48 h: no Dispatched, release broadcast or FrameworkReleaseBroadcaster line at all.
  • Every repository_dispatch the satellites received came from core's own CI — notify-dependents (Education/Reinsurance/SocialMedia at 07:21Z and 07:28Z today) — or from a sibling's meshweaver-upstream-published (node-repo-publish-bake.yml's dispatch-dependents, 23:15–23:53Z). Two independent emitters for one event is exactly the coupling the rule forbids.
  • The inbox watcher on memex-cloud was refused on every background delivery ([PlatformBuilds] results thread failed: … AccessContext must never be null … hub=Hosting/PlatformBuilds, 2026-09-03 04:22Z, 05:21Z, 06:06Z, 06:53Z, 07:39Z, 07:41Z) — so even a wired hop would not have fired. Fixed in the pair PR below.

What this PR does (core)

  1. Withdraws the core dispatcher. main-cd.yml notify-dependents job, the reusable .github/workflows/notify-dependents.yml, and release-packages.yml's package-release variant are deleted; delivery-verdict no longer lists the leg. The DEPENDENT_DISPATCH_APP_* secrets stay in preflight because plugins-modules/plugins-bake still read the Plugins content tree with them (content-app-id) — the assertion text now says so instead of calling them "the release wave's sender". notify-platform-update — the signed build fact POSTed into Hosting/PlatformBuilds — is the ONE event core emits; the header block above it is rewritten to the event design.
  2. Guards it. PlatformReleaseNotifyGuard.CoreDispatchesToNoRepository scans every .github/workflows/*.yml for a repository_dispatch SENDER (/dispatches POST, a dispatch action, createDispatchEvent, an event_type payload; receivers do not count) and refuses any outside a two-entry ledger of reusable workflow_call lanes — node-repo-publish-bake.yml (meshweaver-upstream-published) and node-repo-tag-modules.yml (meshweaver-modules-published) — each asserted to run only as a reusable lane, i.e. in the CALLING satellite's context. A ledgered file that stops sending fails too. TheDispatchDetector_FiresOnEachSendingForm_AndIsSilentOnProse pins the detector.
  3. Retires the config seam. FrameworkBroadcastOptions.Subscribers / SubscribersEnvKeyPrefix and FrameworkReleaseBroadcaster.BroadcastToConfigured are removed; the chart no longer renders FrameworkBroadcast__Subscribers__0..3 and values.aks.yaml no longer declares the slots. The subscriber set is DATA IN THE MESH — every repository a Hosting/Deployment record on the control instance serves as a registry source (pluginRepos[].isRegistrySource), derived by the Hosting module's PlatformBuildInboxWatcher (pair PR) and passed to Broadcast(subscribers, version). The broadcaster's empty-set warning on the control instance now names the records, not a config key (FrameworkBroadcastEmptySubscribersGuard updated); ReleaseDeliveryChainGuard drops joint 2 (a guard asserting a key nothing reads is a false control) and its documented-source test asserts the records.
  4. Docs. ContinuousDeliveryContract.md (the release-EVENT section rewritten: one emitter, the event names, the subscriber source, what core does, the measured history), RepositoryDependencyDirection.md, CrossRepoPairGate.md (§ "The dependent reacts to core's events" — the transitional-emitter sentence replaced), CiContentBake.md, ModuleBuildArchitecture.md (release-follow), ReleaseEventBus.md, ChartOwnershipAndRunnerPool.md, .claude/skills/new-repo. What's New (Category: Feature): A platform release reaches plugin repositories through memex.

The contract, exactly (maintainer, 2026-09-03 09:05Z: "end of github pipeline must call memex, which must register release and publish event")

  1. Every pipeline ENDS with one call to memex. Core's already does (notify-platform-update → Hosting/PlatformBuilds/_Inbox). The shared lane node-repo-publish-bake.yml now does too: its dispatch-dependents job (read every installed repo's ci.yml, POST to their /dispatches) is deleted and replaced by register-publication — the lane's LAST job — which POSTs the HMAC-signed publication record (event: bundle-publication: source, identity, commit, tester image + digest, portal image, version, run) into the same inbox, RED (never skipped, never a warning) when webhook-url/webhook-secret are missing or the inbox refuses. The node-repo-tag-modules.yml announce step (meshweaver-modules-published to a hand-listed set) is deleted as well. Retired inputs/secrets (dispatch-dependents, dispatch-app-*, dispatch-token) stay DECLARED and ignored so callers pinned to an earlier lane still validate; each caller passes webhook-url + webhook-secret when it moves its pin (the lane names them RED until then).
  2. The receivers accept memex's event shape. For meshweaver-upstream-published with client_payload.version and no image, both images now resolve from the version tag exactly as for a framework release (memex emits the identity by name); the legacy image-carrying payload still works for a lane pinned before this change.
  3. FrameworkReleaseBroadcaster.Broadcast(...) takes an optional payload (merged over version/source), so the watcher can name the publishing source, identity, image, platform_image on a bundle-publication event.
  4. Guards: PlatformReleaseNotifyGuard.CoreDispatchesToNoRepository now has NO ledger — a dispatch sender in ANY workflow under .github/workflows fails; UpstreamBuildGateGuard.TheLaneEndsByRegisteringWithMemex_AndDispatchesToNobody pins the lane's call (signed, RED, unconditional on inputs, no /dispatches, no event_type).
  5. Docs: the three sentences + the diagram (pipeline → POST inbox → register node → broadcast → subscriber CI) in ContinuousDeliveryContract.md, ModuleBuildArchitecture.md (new "The release: the pipeline ends by calling memex"), CrossRepoPairGate.md, RepositoryDependencyDirection.md, Deployment.md (new "How a release reaches the fleet"), and the registration nodes named: Hosting/PlatformBuilds/<version>, Hosting/Publications/<identity>/<source>.

The transitional TWO-PRODUCER state, named: with Plugins now receiving meshweaver-framework-released from memex, the Plugins repo's own release-follow run bakes and seals its bundles for the released identity — while core CD's plugins-modules / plugins-bake-image / plugins-bake jobs still produce the same publication in-line. Two producers of one publication is the next removal: core's three jobs go once Plugins' event-driven bake is observed sealing for a release — measured by the registry serving Plugins bundles for an identity that the Plugins repo's run (not core CD) produced (the sealed publication's run / repo fields, and the Hosting/Publications/<identity>/Plugins registration once the watcher writes it). Until then the two producers race to the same content-addressed key; the ledger's claim/wait protocol keeps that from double-building, and nothing consumes the wrong bytes.

Named follow-ups (not in this PR set): the Plugins watcher REGISTERING those nodes and handling event: bundle-publication (register + meshweaver-upstream-published, dependency-scoped through the registry's package requires graph so a publication cannot wake its own upstream); each node repo passing webhook-url/webhook-secret at its pin bump; and — once Plugins receives the platform event and publishes its own bundles on it — removing core CD's plugins-bake job, which then is a second producer of the same publication.

Verification

  • dotnet build test/MeshWeaver.Documentation.Test -c Release -warnaserror → 0 warnings, 0 errors (compiles MeshWeaver.GitSync).
  • dotnet test MeshWeaver.Documentation.Test -c Release --no-build (whole project — the ratchets): see the CI run; local .trx attached in the log of this branch's session.
  • check-workflow-timeouts.py --root . → 0 violations; check-workflow-shell.py → 0 live findings; actionlint main-cd.yml release-packages.yml → exit 0.
  • PROOF THE MEMEX HOP FIRES (2026-09-03, memex-cloud, after Plugins#1241 landed 08:58Z): Loki namespace="memex-cloud" —
    09:23:43Z [PlatformBuilds] release broadcast for 3.0.0-rc9.ci.7658: 3 dispatched, 1 NOT notified (Systemorph/education (401: … (and the same for ci.7657 at 09:23:47Z and ci.7655 at 09:23:52Z — the previously undeleted inbox backlog drained by the identity fix). Satellite side, all at 09:23:44–09:23:54Z with NO core CD promote in that window (CD runs were pending/queued/cancelled): repository_dispatch: meshweaver-framework-released runs on MeshWeaver.Plugins (33738591658/…98801/…605857 — Plugins is now IN the wave; core's never included it), MeshWeaver.Reinsurance (33738592702/…), MeshWeaver.Crm (33738600156/…); none on SocialMedia (not yet on the record — Systemorph/Memex#173 adds it). The one failure is the stale Systemorph/education name (fix(graph): eliminate the compile-flake population (single compile driver + complete terminal write + search ordering) #173 fixes the record).
  • Sequence: this PR was a DRAFT until the memex hop was observed firing after Systemorph/MeshWeaver.Plugins#1241 lands on memex-cloud — a [PlatformBuilds] release broadcast for <version>: N subscriber(s) dispatched. line in Loki and a repository_dispatch run on a satellite whose payload carries source: memex. Only then does core stop dispatching; otherwise the satellites would stop sealing bundles and every portal's self-update would hold.

Deliberately not here

  • The Deployments/memex-cloud record (Systemorph/Memex) still carries the four FrameworkBroadcast__Subscribers__N extras (now inert) and names Education by its pre-rename URL (Systemorph/education — a POST to a renamed repo answers 301, which HttpClient does not re-POST, so that dispatch reports NOT notified until the record says MeshWeaver.Education). Both are Memex-repo edits.
  • SocialMedia was served by memex-cloud (the Posts app) but not named on Deployments/memex-cloud — the record was incomplete, not SocialMedia out of scope. Systemorph/Memex#173 adds it as a registry source, so it is in memex's wave under the mesh-derived set. Manufacturing stays out (no publish-bake yet, Manufacturing#31/Portal fixes #48). The record IS the subscriber list: adding a repository to the wave = adding it to the record.
  • Sequencing with Systemorph/Memex#173 (the record/overlay PR, draft): it drops the four FrameworkBroadcast__Subscribers__N overlay keys. Merged BEFORE this PR, the blank-guard on the next memex-cloud deploy would refuse the render (live non-empty → rendered ""); merged AFTER, Memex's config-key-coverage is red only until it lands (the chart no longer renders the key). So: this PR first, the Memex PR immediately after.
  • meshweaver-upstream-published (satellite → its dependents, sent by the reusable publish-bake lane in the satellite's context) is a repo-to-repo edge the registry could also emit; out of scope here and ledgered explicitly.
  • [InboxAnchor] anchoring Hosting/PlatformBuilds FAILED (memex-cloud 07:14Z, a 60 s SubscribeRequest timeout, after which the anchor gives up until restart) is a separate defect.

Pairs-with: Systemorph/MeshWeaver.Plugins#1241

🤖 Generated with Claude Code
Claude-Session: https://claude.ai/code/session_01G4xPnGYEbdu8AVvR5jytyj

…s; the release wave is memex's, its subscribers the Deployment records

Maintainer, 2026-09-03: none of the top-level repos depends on another; memex
issues the event that something has a new version, GitHub subscribes, core
publishes an event and finishes. The GitHub→GitHub `notify-dependents` fan-out
(main-cd, release-packages, the reusable) is deleted; the signed build fact
POSTed into Hosting/PlatformBuilds is the one event core emits, and
PlatformReleaseNotifyGuard.CoreDispatchesToNoRepository refuses a
repository_dispatch sender in any workflow core runs on its own behalf (the two
reusable satellite-context lanes are the ledger). The FrameworkBroadcast:
Subscribers config seam (BroadcastToConfigured, the chart's four slots) is
retired: the subscriber set is data in the mesh — the Hosting/Deployment
records' registry-source mounts, derived by the Plugins-side inbox watcher —
and the broadcaster's empty-set warning names the records. Docs rewritten to
the event design; What's New entry.

Pairs-with: Systemorph/MeshWeaver.Plugins#1241

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G4xPnGYEbdu8AVvR5jytyj
Copilot AI lite review requested due to automatic review settings September 3, 2026 08:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

It makes high-impact CI/CD release-chain changes (removing core cross-repo dispatch and shifting subscriber sourcing) that warrant careful human verification of the end-to-end release wave behavior.

Pull request overview

This PR updates MeshWeaver’s release-notification architecture so core CD emits only the signed build-fact POST into memex (Hosting/PlatformBuilds) and never directly dispatches into other repositories, while memex becomes the sole release-wave dispatcher based on Hosting/Deployment records (and the legacy subscriber config seam is removed).

Changes:

  • Removes core-side repository_dispatch fan-out (notify-dependents) and adds a test guard that refuses any reintroduction outside a small allowlist of reusable satellite-context workflows.
  • Retires FrameworkBroadcast:Subscribers configuration and updates the broadcaster + tests to treat subscribers as mesh data (derived from Hosting/Deployment registry sources).
  • Updates docs, chart templates, and “What’s New” to reflect the new event flow and subscriber source.
File summaries
File Description
test/MeshWeaver.Documentation.Test/ReleaseDeliveryChainGuard.cs Updates the “release delivery chain” ledger now that subscribers are no longer a config key.
test/MeshWeaver.Documentation.Test/PlatformReleaseNotifyGuard.cs Adds/updates guard asserting core workflows do not send repository_dispatch, with a small sender allowlist.
test/MeshWeaver.Documentation.Test/FrameworkBroadcastEmptySubscribersGuard.cs Updates expectations for the empty-subscriber warning to point to Hosting/Deployment records instead of config slots.
src/MeshWeaver.GitSync/FrameworkReleaseBroadcaster.cs Removes the “configured subscribers” seam and updates empty-set warning text to the mesh-data subscriber source.
src/MeshWeaver.GitSync/FrameworkBroadcastOptions.cs Updates options documentation to reflect that subscribers are no longer configuration.
src/MeshWeaver.Documentation/Data/WhatsNew/2026-09-03-a-platform-release-reaches-plugin-repositories-through-memex.md Adds a What’s New entry describing the new release event flow.
src/MeshWeaver.Documentation/Data/Architecture/RepositoryDependencyDirection.md Updates architecture guidance to reflect “no dispatcher” in core.
src/MeshWeaver.Documentation/Data/Architecture/ReleaseEventBus.md Updates the fan-out row and troubleshooting joints to the new subscriber source.
src/MeshWeaver.Documentation/Data/Architecture/ModuleBuildArchitecture.md Notes that repository_dispatch release-follow is memex-emitted, with schedule as fallback.
src/MeshWeaver.Documentation/Data/Architecture/CrossRepoPairGate.md Updates narrative on event direction and who emits the release-wave dispatch.
src/MeshWeaver.Documentation/Data/Architecture/ContinuousDeliveryContract.md Rewrites the “release EVENT” section to the new one-emitter design and documents history.
src/MeshWeaver.Documentation/Data/Architecture/CiContentBake.md Updates bake-follow guidance to reflect memex-emitted event and schedule fallback.
src/MeshWeaver.Documentation/Data/Architecture/ChartOwnershipAndRunnerPool.md Updates chart ownership notes for the removed subscriber slots.
deploy/helm/templates/memex-portal/config.yaml Removes rendering of FrameworkBroadcast__Subscribers__0..3 and documents retirement.
deploy/aks/values.aks.yaml Removes the subscriber-slot values from the baseline AKS values file.
.github/workflows/release-packages.yml Removes the package-release notify-dependents dispatch job and documents why.
.github/workflows/notify-dependents.yml Deletes the reusable workflow that performed cross-repo dispatch from core.
.github/workflows/main-cd.yml Removes notify-dependents job and updates “release wave” design docs in-file + preflight messaging.
.claude/skills/new-repo/SKILL.md Updates repo-creation guidance to the memex-emitted event + schedule fallback model.
Review details
  • Files reviewed: 19/19 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +465 to +469
no credential that could reach a satellite's CI. `PlatformReleaseNotifyGuard.CoreDispatchesToNoRepository`
(`test/MeshWeaver.Documentation.Test`) fails the build if a `/dispatches` POST, a dispatch action or
an `event_type` payload returns to any workflow core runs on its own behalf; the one ledgered sender
is the reusable `node-repo-publish-bake.yml`, which runs in the CALLING satellite's context and wakes
that satellite's dependents (`meshweaver-upstream-published`).
Comment on lines +135 to +141
- **No dispatcher.** Core sends `repository_dispatch` to no repository. `notify-dependents.yml` was
withdrawn on 2026-09-03 (maintainer: *"core publishes an event and finishes"*): the release wave is
emitted by memex from the build fact core POSTs into `Hosting/PlatformBuilds`, to the repositories
the `Hosting/Deployment` records name as registry sources. `PlatformReleaseNotifyGuard.CoreDispatchesToNoRepository`
refuses a `/dispatches` POST in any workflow core runs on its own behalf; the reusable
`node-repo-publish-bake.yml` is the one ledgered sender, and it runs in the CALLING satellite's
context (a satellite waking its own dependents).
@github-actions

github-actions Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

243 tests  ±0   243 ✅ ±0   2m 18s ⏱️ +20s
  1 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 1a1ac98. ± Comparison against base commit e7f1d69.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

448 tests  ±0   448 ✅ ±0   59s ⏱️ -1s
  1 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 1a1ac98. ± Comparison against base commit e7f1d69.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

340 tests  ±0   338 ✅ ±0   40s ⏱️ -5s
  3 suites ±0     2 💤 ±0 
  3 files   ±0     0 ❌ ±0 

Results for commit 1a1ac98. ± Comparison against base commit e7f1d69.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

    4 files  ±0      4 suites  ±0   1m 36s ⏱️ +10s
1 315 tests +1  1 315 ✅ +1  0 💤 ±0  0 ❌ ±0 
1 316 runs  +1  1 316 ✅ +1  0 💤 ±0  0 ❌ ±0 

Results for commit 1a1ac98. ± Comparison against base commit e7f1d69.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

2 188 tests  ±0   2 188 ✅ ±0   2m 29s ⏱️ -4s
    3 suites ±0       0 💤 ±0 
    3 files   ±0       0 ❌ ±0 

Results for commit 1a1ac98. ± Comparison against base commit e7f1d69.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

578 tests  ±0   386 ✅ ±0   2m 38s ⏱️ +2s
  3 suites ±0   192 💤 ±0 
  3 files   ±0     0 ❌ ±0 

Results for commit 1a1ac98. ± Comparison against base commit e7f1d69.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

   15 files  ±0     15 suites  ±0   10m 43s ⏱️ +22s
5 112 tests +1  4 918 ✅ +1  194 💤 ±0  0 ❌ ±0 
5 113 runs  +1  4 919 ✅ +1  194 💤 ±0  0 ❌ ±0 

Results for commit 1a1ac98. ± Comparison against base commit e7f1d69.

♻️ This comment has been updated with latest results.

…cation instead of dispatching; no ledger of senders

Maintainer, 2026-09-03 09:05Z: "end of github pipeline must call memex, which
must register release and publish event". node-repo-publish-bake.yml's
dispatch-dependents job (read every installed repo's ci.yml, POST to their
/dispatches) is replaced by register-publication — one signed POST of the
bundle-publication record into the control instance's inbox, RED when
unprovisioned or refused, the lane's last job; node-repo-tag-modules.yml's
announce step goes the same way. Receivers resolve a memex-emitted
meshweaver-upstream-published from client_payload.version; the broadcaster
takes an optional payload so the watcher can name source/identity/images.
PlatformReleaseNotifyGuard has no ledger — a dispatch sender in any workflow
fails; UpstreamBuildGateGuard pins the lane's call. Docs carry the contract
(three sentences + diagram) and the registration nodes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G4xPnGYEbdu8AVvR5jytyj
@rbuergi
rbuergi marked this pull request as ready for review September 3, 2026 09:31
@rbuergi
rbuergi added this pull request to the merge queue Sep 3, 2026
Merged via the queue into main with commit 8fffa38 Sep 3, 2026
45 of 47 checks passed
rbuergi added a commit that referenced this pull request Sep 3, 2026
Copilot review. The reference pointed at /issues/3185; #3185 is the PR that made the
release wave memex's. GitHub would redirect, but the URL should say what the thing is.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G4xPnGYEbdu8AVvR5jytyj
@rbuergi rbuergi mentioned this pull request Sep 6, 2026
6 of 26 tasks
@rbuergi
rbuergi deleted the ci/release-wave-is-memex-event branch September 13, 2026 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants