Released platform selection
Crm follows MeshWeaver #3842: module repositories store no platform pins. Shared workflows
and their scripts follow main. Preflight asserts the existing credentials and variables,
then selects a retained sealed tester and portal image pair with the consumer resolver.
The resolver originated in Plugins #1581; Crm additionally requires the upstream Plugins
publication and the complete successful CD verdict before choosing that release. Both images must exist. Their resolved digests supply every existing gate
and publication input. Candidates that are unavailable or not sealed are reported and passed
over; an explicit incident freeze fails if its requested set cannot be used.
The MW_PLATFORM_REF repository variable is an optional incident freeze, not normal
configuration. No workflow SHA, platform SHA, release tag or image digest lives in this repo.
The compile-check lane's platform-ref: main selects scripts only. Crm builds no core
source; the selected image supplies its reference assemblies. Local script lookup validates
the explicit input of the relevant lane and refuses unknown expressions instead of silently
using main. Mutable script refs are fetched again; MW_PLATFORM_SCRIPTS remains the explicit
local override.
The wake names its own identity
A meshweaver-upstream-published event says that an upstream this repository declares —
upstream-sources: plugins — has just SEALED a publication for one framework identity, and it
carries both halves of that identity in its payload (client_payload.digest, the tester, and
client_payload.platform_image, the portal; MeshWeaver #3022). The bake must target that
identity: publishing under a newer one leaves the woken publication without this repository's
bundles, and the bake's own availability gate then fails by name —
upstream 'plugins' has no SEALED publication … for identity <id>, the same shape runs
34434016747 and 34434019610 produced above.
The bake-target step in preflight decides this, and it has exactly two branches: the identity
the wake NAMES, or the set this run resolved. Neither is written down anywhere; one is a value
the run computes, the other a fact the sender states. A payload carrying only one half is
refused RED rather than completed from the resolved set, because pairing an upstream's tester
with a portal resolved here composes two CD waves, which the shared lanes refuse by name.
meshweaver-framework-released has no branch: the resolver follows the release itself, so a
second answer to the same question inside one run would be the shape this conversion removed —
and since 2026-09-12 this repository does not subscribe to that event at all (next section).
The gates always take the resolved set. Only the bake follows the wake, and only when there is one.
The daily run is the full run (2026-09-12)
Maintainer decision, fleet-wide: assume upstream dependencies are backwards compatible; do not recompile and run all tests on every platform build; do the full run once a day.
meshweaver-framework-released is sent by the control instance on every green core build —
about sixty a day — and every one of them re-baked this whole repository: measured over the seven
days before the change, 17,201 billed minutes of dispatch runs here and roughly 15,000 minutes a
day across the six satellites, 30% of the bill, with a run superseded by the next dispatch never
cancelled (the release lane queues by design). The receiver was removed from ci.yml's
repository_dispatch.types; the resolver, the bake and every gate are unchanged.
What runs now:
- The daily
schedule(03:56 UTC) is the full run. It resolves the newest sealed platform set, waits for its seal, gates and bakes everything against it and publishes. Between two polls the previous day's bundles serve — the platform is assumed backwards compatible within a MAJOR (a module built against platform X serves on platform Y while the major is the same). meshweaver-upstream-publishedstill wakes this repository — an upstream's own content change must reach its dependents the same hour, and the bake still targets the identity the wake names.- A push to
mainand a manualworkflow_dispatchbehave as before.
A MAJOR platform bump is the one platform event that must trigger a full rebuild everywhere.
No automatic trigger carries it any more; for now it is a manual workflow_dispatch per
repository. Note that a manual run is gate-only today (publish-bake's condition names a push to
main, a dispatch and the poll), so after a MAJOR bump the next daily poll is what re-bakes and
publishes; letting the manual run publish is the follow-up.
Required checks still require evidence
The four content contexts keep their names. The fifth, Platform pins name one build, is
retired with the literals it policed: a context asserting that platform pins name one build,
in a repository that names no platform build at all, states the opposite of what it measures,
and the next reader satisfies it by reintroducing a pin.
What that job had become — a skip detector — is kept and widened as Every required gate actually ran, ported from MeshWeaver.Reinsurance, which has run it as a required context since
its own conversion. GitHub counts a SKIPPED required context as SATISFIED, so "the gate never
ran" and "the gate passed" are the same colour; the old job watched preflight alone and a skip
anywhere else was invisible to it. This one watches every gate, and a regression test executes
its actual shell for each gate skipped in turn, for an all-failed run (an honest verdict, which
blocks on its own context) and for a cancellation (whose trailing skips are the cancellation,
not a hole).
The ratchet has no inputs, so it has no conditions
Nothing pins the platform (scripts/check-shared-lanes.py) is its own job: no needs:, no
if:, no secret, no network. It reads this repository's own committed workflow files and
nothing else, so there is no external input for it to assert and nothing upstream that could
legitimately silence it. Run from inside preflight it inherited two conditions it does not need
and must not have — the fork exemption, so a fork PR reintroducing uses: …@<sha> met no
ratchet at all; and the live resolution, so on exactly the days the platform is unwell (an ACR
outage, a core API 5xx) the check that keeps the platform unpinned was the one that did not run.
The pin-set copy was gated the same way: its first step exits unless preflight succeeded, so
the checkout and the ratchet below it were never reached on either event either. The resolver's
offline self-test and the workflow wiring tests sit beside it for the same reason. A gate never
tests its own inputs, and this one has none.
The shared-lane guard covers both .yml and .yaml workflows. It refuses stored workflow
pins and incorrect script inputs. Workflow mutation tests cover missing resolution, mixed
image outputs and missing consumer dependencies. All prior permissions, secrets, content
scopes, triggers and publication conditions are preserved. The registry URL and publication
target variables used by existing jobs are now asserted early as well.
Preflight's 25-minute cap accommodates the resolver's existing 15-minute seal wait on release triggers plus its other checks. Other job caps stay unchanged. This is not an extension for a hanging build; a timeout still requires diagnosis.
A platform image is not a complete consumer release
On 2026-09-10, Crm run 34434019610 selected core CD 8240 while that CD run was still
packing and testing Plugins. Its image promotion, image verification and platform bake had
succeeded, but plugins-sealed=absent. Compile-check then received HTTP 404 for the Plugins
module set under framework identity sc7894b5af0202eca75c4394987c96477.
A consumer now requires both a completed successful CD run and successful Plugins bake/seal jobs, alongside the existing three platform jobs. Missing, pending, failed, cancelled or skipped upstream publication cannot become a candidate. The existing release-trigger wait also covers an upstream job that has not yet appeared; after the wait, incomplete candidates are passed over with a reason. An explicit freeze still refuses substitution.
The local regression covers each incomplete upstream verdict, an unfinished or unsuccessful whole run despite green jobs, the successful publication, and an upstream publication arriving before the final CD verdict. The ten new rejection cases failed against the old resolver.
Publication order and remaining limitation
Crm depends on the exact plugins publication; Reinsurance depends on plugins crm.
The delivery order is platform, Plugins, Crm, then Reinsurance. A sealed platform does not
prove a sealed Plugins publication. The existing upstream gates must find the exact identity
and fail if it is absent. Do not substitute another identity or rerun that failure without
new publication evidence.
A delayed dispatch can name an older identity than the newest platform preflight would
otherwise select, and the bake must follow the dispatch rather than the resolution. The
bake-target step in preflight is where that is decided; see "The wake names its own
identity" below. It does not close the fleet-wide delayed-dispatch work tracked in
Plugins #1565.
A PR run proves resolution and the compile, runtime and presentation gates. It does not
publish. After merge, verify a full scheduled or supported release-dispatch run completes
the bake and registers a matching sealed crm publication before advancing Reinsurance.
Production verification belongs on the Systemorph instance; a local manifest or green PR
is not proof that a portal adopted the changed publication.
Historical evidence retained from the pin workflow
Crm #66 recorded mixed tester and portal identities on release-triggered bakes. Run
34185317544 on 2026-09-08 reproduced that mismatch, while push runs still used the stored
pair. The old scheduled path also relied on moving tags whose availability differed between
image repositories. Resolving both images from one sealed release avoids independently
moving those inputs.
PR #77 moved Crm to 3.0.0-ci.8195, CD run 34353419069, so its publication could precede
Reinsurance. Reinsurance #184 had previously advanced first and failed because that identity
had no Crm seal; #185 backed that move out. This ordering requirement survives removal of pins.
Earlier 3.0.0-rc8.ci.6469 images were removed from ACR, producing manifest unknown on main
without a content change. A resolver must report unavailable artifacts and select a retained
sealed release rather than require another manual pin update.
Regular artifact cleanup follows the platform's 30-day policy. Supported official releases
and advertised fallbacks retain their complete required sets. MW major support follows the
underlying .NET lifetime; plugin support also requires continued support from collaborating
services or counterparties. The canonical policies are Doc/Architecture/SupportPolicy and
Doc/Architecture/ReleasedArtifactRetention. This change enables no cleanup or access-policy
change, and contains no client data or client records.