From e5b965717fea09d744ad8c6d7cd7dfb5e960f5fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20B=C3=BCrgi?= <6334612+rbuergi@users.noreply.github.com> Date: Wed, 7 Oct 2026 19:31:24 +0200 Subject: [PATCH 1/2] ci(#5212): DOTNET_TieredPGO=0 in every emitting CI job and lane; chart renders it from a record TEMPORARY STOPGAP (maintainer decision, policy tiered-pgo-off-5212) for the .NET 10 JIT miscompile in #5212: Tier-1 + Dynamic PGO drops a type check in an inlined guarded devirtualisation on Roslyn's MetadataWriter path, after which every in-process Emit NREs. Remove when the runtime fix ships. - dotnet-test.yml: job env on test, doc-gate, platform-compat. - node-repo-{compile-check,gate,module-pack,publish-bake}.yml: job env on every job that compiles, bakes or runs satellite tests, plus -e DOTNET_TieredPGO=0 on each emitting `docker run` (the runner env does not cross into the container). Covers satellites whatever tester pin they hold, which #890's runtimeconfig half cannot. - chart: memex-portal-config renders DOTNET_TieredPGO when a record's extraPortalConfig sets it (envFrom -> process env), so the Memex records can carry it. - PolicyNotProse register row + NodeTypeCompilation "environment half" paragraph. Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/dotnet-test.yml | 24 +++++++++++++++++ .github/workflows/node-repo-compile-check.yml | 8 ++++++ .github/workflows/node-repo-gate.yml | 12 ++++++++- .github/workflows/node-repo-module-pack.yml | 27 ++++++++++++++++++- .github/workflows/node-repo-publish-bake.yml | 18 +++++++++++-- .../helm/templates/memex-portal/config.yaml | 13 +++++++++ .../Data/Architecture/NodeTypeCompilation.md | 20 ++++++++++++++ .../Data/Architecture/PolicyNotProse.md | 1 + 8 files changed, 119 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dotnet-test.yml b/.github/workflows/dotnet-test.yml index 952d66ce65..c5523a16b8 100644 --- a/.github/workflows/dotnet-test.yml +++ b/.github/workflows/dotnet-test.yml @@ -861,6 +861,14 @@ jobs: # projects. 20 min is ~1.5x the slowest observed shard (14m36s) with the rebalanced # weights, so a shard that hits this is stuck, not slow. timeout-minutes: 20 + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix ships. + # The .NET 10 Tier-1 JIT under Dynamic PGO drops a type check in an inlined guarded + # devirtualisation on Roslyn's MetadataWriter.PopulateNestedClassTableRows / + # getConsolidatedTypeParameters path, after which every in-process Emit NREs. The + # runtimeconfig half (false, #890) covers hosts built from THIS tree; + # this env covers every process the job launches, whatever pin it was built at. + env: + DOTNET_TieredPGO: "0" runs-on: ubuntu-latest strategy: # Don't cancel sibling shards when one fails — we want every shard's @@ -1891,6 +1899,14 @@ jobs: # Same wall-clock contract as plugin-gate: depends on `build` like the shards, so it runs # CONCURRENTLY with them; while it stays under the slowest shard it costs the PR nothing. timeout-minutes: 12 + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix ships. + # The .NET 10 Tier-1 JIT under Dynamic PGO drops a type check in an inlined guarded + # devirtualisation on Roslyn's MetadataWriter.PopulateNestedClassTableRows / + # getConsolidatedTypeParameters path, after which every in-process Emit NREs. The + # runtimeconfig half (false, #890) covers hosts built from THIS tree; + # this env covers every process the job launches, whatever pin it was built at. + env: + DOTNET_TieredPGO: "0" outputs: failure: ${{ steps.gate.outputs.failure }} steps: @@ -2087,6 +2103,14 @@ jobs: if: ${{ !cancelled() && needs.build.result == 'success' }} runs-on: ubuntu-latest timeout-minutes: 10 + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix ships. + # The .NET 10 Tier-1 JIT under Dynamic PGO drops a type check in an inlined guarded + # devirtualisation on Roslyn's MetadataWriter.PopulateNestedClassTableRows / + # getConsolidatedTypeParameters path, after which every in-process Emit NREs. The + # runtimeconfig half (false, #890) covers hosts built from THIS tree; + # this env covers every process the job launches, whatever pin it was built at. + env: + DOTNET_TieredPGO: "0" permissions: contents: read actions: read diff --git a/.github/workflows/node-repo-compile-check.yml b/.github/workflows/node-repo-compile-check.yml index e94f3f20b1..2fb96d5cf5 100644 --- a/.github/workflows/node-repo-compile-check.yml +++ b/.github/workflows/node-repo-compile-check.yml @@ -259,6 +259,14 @@ jobs: name: Compile every NodeType (vs core) runs-on: ${{ vars.MW_RUNNER_DOCKER || 'ubuntu-latest' }} timeout-minutes: 20 + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix ships. + # The .NET 10 Tier-1 JIT under Dynamic PGO drops a type check in an inlined guarded + # devirtualisation on Roslyn's MetadataWriter.PopulateNestedClassTableRows / + # getConsolidatedTypeParameters path, after which every in-process Emit NREs. The + # runtimeconfig half (false, #890) covers hosts built from THIS tree; + # this env covers every process the job launches, whatever pin it was built at. + env: + DOTNET_TieredPGO: "0" # 🚨 A job-level `permissions:` in a workflow_call lane is a DEMAND on every caller, not a # grant (MeshWeaver#3933 took MeshWeaver.Plugins down for five hours with one `id-token: # write` here). Both scopes below sit inside GitHub's RESTRICTED default (contents / packages / diff --git a/.github/workflows/node-repo-gate.yml b/.github/workflows/node-repo-gate.yml index c6af4dbd8b..b5943eb0f0 100644 --- a/.github/workflows/node-repo-gate.yml +++ b/.github/workflows/node-repo-gate.yml @@ -942,6 +942,13 @@ jobs: # needs more is STUCK, not slow. timeout-minutes: 45 env: + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix ships. + # The .NET 10 Tier-1 JIT under Dynamic PGO drops a type check in an inlined guarded + # devirtualisation on Roslyn's MetadataWriter.PopulateNestedClassTableRows / + # getConsolidatedTypeParameters path, after which every in-process Emit NREs. The + # runtimeconfig half (false, #890) covers hosts built from THIS tree; + # this env covers every process the job launches, whatever pin it was built at. + DOTNET_TieredPGO: "0" # The self-hosted runner is non-root: setup-dotnet cannot write /usr/share/dotnet there. # EMPTY on ubuntu-latest, which setup-dotnet reads as unset — the default path is unchanged. # No step here runs setup-dotnet today; the line is the rule, uniform with module-pack. @@ -2198,7 +2205,10 @@ jobs: if [ "$MODE" = volume ]; then "$DOTNET" "$HOST_DIR/mw-plugin-test.dll" "$@" else - docker run --rm --init --user "$(id -u):$(id -g)" -e HOME=/tmp "${EXT_V[@]}" \ + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix + # ships. Same switch as the job env, carried INTO the container (the runner env does not + # cross `docker run`). + docker run --rm --init --user "$(id -u):$(id -g)" -e HOME=/tmp -e DOTNET_TieredPGO=0 "${EXT_V[@]}" \ -v "$HOST_DIR:/host:ro" -v "$REPO_MOUNT:/repo" "${TESTER_MOUNTS[@]}" "${DUMP_ARGS[@]}" \ --entrypoint dotnet "$PLATFORM_REF" /host/mw-plugin-test.dll "$@" fi diff --git a/.github/workflows/node-repo-module-pack.yml b/.github/workflows/node-repo-module-pack.yml index f6ff21294b..df7d585707 100644 --- a/.github/workflows/node-repo-module-pack.yml +++ b/.github/workflows/node-repo-module-pack.yml @@ -1730,6 +1730,14 @@ jobs: # `workspace-runner` (inputs): a Docker-capable label — the compiler is the platform image. runs-on: ${{ inputs.workspace-runner }} timeout-minutes: 30 + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix ships. + # The .NET 10 Tier-1 JIT under Dynamic PGO drops a type check in an inlined guarded + # devirtualisation on Roslyn's MetadataWriter.PopulateNestedClassTableRows / + # getConsolidatedTypeParameters path, after which every in-process Emit NREs. The + # runtimeconfig half (false, #890) covers hosts built from THIS tree; + # this env covers every process the job launches, whatever pin it was built at. + env: + DOTNET_TieredPGO: "0" # Inherit for the same reason as `prepare`: OIDC is a caller-selected capability, while basic # callers must remain able to grant `actions: read` without also granting an identity token. steps: @@ -1954,8 +1962,11 @@ jobs: echo "global build: ${#projects[@]} container entr(y|ies) in ONE workspace — ${projects[*]}" # AS THE RUNNER'S UID (a root-owned /out is unwritable to later steps); HOME=/tmp keeps # runtime probes off read-only image paths. No --extra-refs, ever, on this lane. + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix + # ships. Same switch as the job env, carried INTO the container (the runner env does not + # cross `docker run`). docker run --rm --init --platform linux/amd64 \ - --user "$(id -u):$(id -g)" -e HOME=/tmp \ + --user "$(id -u):$(id -g)" -e HOME=/tmp -e DOTNET_TieredPGO=0 \ -v "$GITHUB_WORKSPACE:/repo:ro" \ -v "$tester_app:/tester:ro" \ -v "$out:/out" \ @@ -2086,6 +2097,13 @@ jobs: runs-on: ${{ inputs.runner }} timeout-minutes: 45 env: + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix ships. + # The .NET 10 Tier-1 JIT under Dynamic PGO drops a type check in an inlined guarded + # devirtualisation on Roslyn's MetadataWriter.PopulateNestedClassTableRows / + # getConsolidatedTypeParameters path, after which every in-process Emit NREs. The + # runtimeconfig half (false, #890) covers hosts built from THIS tree; + # this env covers every process the job launches, whatever pin it was built at. + DOTNET_TieredPGO: "0" # The self-hosted runner is non-root: setup-dotnet cannot write /usr/share/dotnet there. # EMPTY on ubuntu-latest, which setup-dotnet reads as unset — the default path is unchanged. DOTNET_INSTALL_DIR: ${{ inputs.runner != 'ubuntu-latest' && '/home/runner/.dotnet' || '' }} @@ -4383,6 +4401,13 @@ jobs: runs-on: ${{ inputs.runner }} timeout-minutes: 45 env: + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix ships. + # The .NET 10 Tier-1 JIT under Dynamic PGO drops a type check in an inlined guarded + # devirtualisation on Roslyn's MetadataWriter.PopulateNestedClassTableRows / + # getConsolidatedTypeParameters path, after which every in-process Emit NREs. The + # runtimeconfig half (false, #890) covers hosts built from THIS tree; + # this env covers every process the job launches, whatever pin it was built at. + DOTNET_TieredPGO: "0" # The self-hosted runner is non-root: setup-dotnet cannot write /usr/share/dotnet there. # EMPTY on ubuntu-latest, which setup-dotnet reads as unset — the default path is unchanged. DOTNET_INSTALL_DIR: ${{ inputs.runner != 'ubuntu-latest' && '/home/runner/.dotnet' || '' }} diff --git a/.github/workflows/node-repo-publish-bake.yml b/.github/workflows/node-repo-publish-bake.yml index cd1fad7f72..499f9439c8 100644 --- a/.github/workflows/node-repo-publish-bake.yml +++ b/.github/workflows/node-repo-publish-bake.yml @@ -574,6 +574,14 @@ jobs: # refuses an expression here because a caller-supplied bound cannot be proven by reading the file). # Measured 2026-09-02 the bake runs ~20 min; past 45 it is stuck, not slow. timeout-minutes: 45 + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix ships. + # The .NET 10 Tier-1 JIT under Dynamic PGO drops a type check in an inlined guarded + # devirtualisation on Roslyn's MetadataWriter.PopulateNestedClassTableRows / + # getConsolidatedTypeParameters path, after which every in-process Emit NREs. The + # runtimeconfig half (false, #890) covers hosts built from THIS tree; + # this env covers every process the job launches, whatever pin it was built at. + env: + DOTNET_TieredPGO: "0" outputs: # Read by dispatch-dependents below: a run that baked NOTHING (already sealed) publishes # nothing and therefore wakes nobody. @@ -1701,8 +1709,11 @@ jobs: # shape since #2922). `--app /app --shared-frameworks /usr/share/dotnet/shared` makes the # bake's reference set the portal's /app plus its IMPLEMENTATION frameworks — what the # portal's own runtime compile sees — and keys every bundle to the portal's identity. + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix + # ships. Same switch as the job env, carried INTO the container (the runner env does not + # cross `docker run`). # shellcheck disable=SC2086 # EXT_MODULE_ARGS is a flag list built above; word-splitting is the point - docker run --rm --init --user "$(id -u):$(id -g)" -e HOME=/tmp "${EXT_V[@]}" \ + docker run --rm --init --user "$(id -u):$(id -g)" -e HOME=/tmp -e DOTNET_TieredPGO=0 "${EXT_V[@]}" \ -v "$HOST_DIR:/host:ro" -v "$REPO_MOUNT:/repo" -v "$BAKE:/bake" \ --entrypoint dotnet "$PLATFORM_REF" /host/mw-plugin-test.dll compile /repo \ --app /app --shared-frameworks /usr/share/dotnet/shared \ @@ -1741,8 +1752,11 @@ jobs: # only a genuinely incompatible one — or none at all — becomes `Unservable`, said at # Critical. A named verdict replaces an unreadable compile failure, and NOTHING that # passes today starts failing: adoption is the path that already carries every gate. + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix + # ships. Same switch as the job env, carried INTO the container (the runner env does not + # cross `docker run`). # shellcheck disable=SC2086 - docker run --rm --init --user "$(id -u):$(id -g)" -e HOME=/tmp \ + docker run --rm --init --user "$(id -u):$(id -g)" -e HOME=/tmp -e DOTNET_TieredPGO=0 \ -e Modules__RequirePrebuilt=true "${EXT_V[@]}" \ -v "$HOST_DIR:/host:ro" -v "$REPO_MOUNT:/repo" -v "$BAKE:/bake" \ --entrypoint dotnet "$PLATFORM_REF" /host/mw-plugin-test.dll /repo --app /app \ diff --git a/deploy/helm/templates/memex-portal/config.yaml b/deploy/helm/templates/memex-portal/config.yaml index 17cf7c3385..aa5d5511b5 100644 --- a/deploy/helm/templates/memex-portal/config.yaml +++ b/deploy/helm/templates/memex-portal/config.yaml @@ -813,6 +813,19 @@ data: {{- if and (hasKey .Values.config.memex_portal "Hosting__TriageAssignments__Enabled") (not (kindIs "invalid" $triageAssignmentsOn)) (ne ($triageAssignmentsOn | toString | trim) "") }} Hosting__TriageAssignments__Enabled: "{{ $triageAssignmentsOn | toString | trim }}" {{- end }} + # ---- Runtime JIT switch: Tiered PGO OFF — TEMPORARY STOPGAP (#5212) -------------------------- + # Policy tiered-pgo-off-5212; remove when the .NET runtime fix ships. The .NET 10 Tier-1 JIT + # under Dynamic PGO can drop a type check in an inlined guarded devirtualisation on Roslyn's + # MetadataWriter.PopulateNestedClassTableRows / getConsolidatedTypeParameters path; from then on + # every in-process NodeType Emit in that replica NREs (Doc/Architecture/NodeTypeCompilation, + # "The defect, in one listing"). The runtime reads DOTNET_TieredPGO from the process environment, + # which this ConfigMap feeds through envFrom. Set from a Deployment record's extraPortalConfig + # (`DOTNET_TieredPGO: "0"`); rendered only when the key is PRESENT and non-empty, so an instance + # that does not set it keeps the runtime default rather than a chart-chosen one. + {{- $tieredPgo := .Values.config.memex_portal.DOTNET_TieredPGO }} + {{- if and (hasKey .Values.config.memex_portal "DOTNET_TieredPGO") (not (kindIs "invalid" $tieredPgo)) (ne ($tieredPgo | toString | trim) "") }} + DOTNET_TieredPGO: "{{ $tieredPgo | toString | trim }}" + {{- end }} # Control instance only: the deployments the ONE org webhook's pull-request and check events are # forwarded to over the control lane (comma-separated ids; Hosting:PrEvents:ForwardTo). {{- if .Values.config.memex_portal.Hosting__PrEvents__ForwardTo }} diff --git a/src/MeshWeaver.Documentation/Data/Architecture/NodeTypeCompilation.md b/src/MeshWeaver.Documentation/Data/Architecture/NodeTypeCompilation.md index 09ca6f3cc9..eb59b89710 100644 --- a/src/MeshWeaver.Documentation/Data/Architecture/NodeTypeCompilation.md +++ b/src/MeshWeaver.Documentation/Data/Architecture/NodeTypeCompilation.md @@ -2202,6 +2202,26 @@ one: the defect is in the .NET 10 JIT, not in this repository, and the switch is measurement on a runtime that fixes it — the arm above, re-run. The portal hosts live in MeshWeaver.Plugins and need the same property there. +**The environment half — policy [`tiered-pgo-off-5212`](../PolicyNotProse), tracked in +[#5212](https://github.com/Systemorph/MeshWeaver/issues/5212).** The runtimeconfig property reaches only +hosts BUILT from this tree at or after the commit that added it; a satellite lane runs the tester and the +portal image at whatever pin it holds, and the portal hosts are built in MeshWeaver.Plugins. So the same +switch is also set as `DOTNET_TieredPGO=0`, which the runtime reads from the process environment and which +wins over the runtimeconfig: + +- **Core CI** — job `env` on the `test`, `doc-gate` and `platform-compat` jobs of `dotnet-test.yml`. +- **Satellite lanes** — job `env` on `node-repo-compile-check` (its `dotnet build` compiler server), + `node-repo-gate` (`gate`), `node-repo-module-pack` (`build-workspace`, `pack`, `tests`) and + `node-repo-publish-bake` (`publish-bake`), plus `-e DOTNET_TieredPGO=0` on every `docker run` that + emits, because the runner's environment does not cross into a container. +- **Portals** — `DOTNET_TieredPGO: "0"` in each portal Deployment record's `extraPortalConfig`, rendered by + the chart into the `memex-portal-config` ConfigMap (fed to the container through `envFrom`) only when the + key is present. A record change reaches a running instance only through a Reconcile, and only on the + next process start. + +Every one of these carries a comment naming #5212 and is removed when the runtime fix ships, together with +the runtimeconfig property — after the split arm above is re-run on that runtime. + ### Framework-version freezing A compiled NodeType DLL references the MeshWeaver framework assemblies present diff --git a/src/MeshWeaver.Documentation/Data/Architecture/PolicyNotProse.md b/src/MeshWeaver.Documentation/Data/Architecture/PolicyNotProse.md index e753e1a2c5..35770c9b3b 100644 --- a/src/MeshWeaver.Documentation/Data/Architecture/PolicyNotProse.md +++ b/src/MeshWeaver.Documentation/Data/Architecture/PolicyNotProse.md @@ -131,6 +131,7 @@ written. | `module-live-update-default` | A module update goes live IN THE RUNNING PROCESS by default — each module in its own collectible load context; an update loads N+1, recycles the hubs bound to N and unloads N — with no flag, no opt-in, no governed activity and no approval. A restart is taken only when a module DECLARES `restartRequired` with a reason (a guard fails a module that blocks a live swap without the declaration) or when the live swap FAILS at runtime; then N keeps serving, the reason is recorded by name, and the automatic, approval-free self-update restart loads N+1. Modules update independently of the platform: platform contracts resolve from the running platform and are never bundled, admission is the declared floor against the running platform, and an image's module copy is only a boot baseline a newer generation supersedes live. Restart-required is legitimate ONLY for genuinely boot-time infrastructure — the declaration is `[assembly: ModuleRestartRequired(ModuleBootCategory., "")]`, a closed list; the guard (`ModuleLiveUpdateGuard`) fails any other category and any undeclared blocker. **Owed:** running the guard over every shipped module, the declarations, and the bundled-platform-assembly refusal in MeshWeaver.Plugins (slice 3). Manual: [Live Module Update](../LiveModuleUpdate). | in force | 2026-10-05 | maintainer | | `platform-semver-versioning` | Platform builds and images are versioned as plain SemVer `..`. The patch is the monotonic CD run number, so the old `3.0.0-ci.` notation and the new one share ONE lineage, and the cut-over can never roll backwards. The minor is bumped deliberately; the major only on a declared break (the same-major-is-compatible roll rule). Main builds carry no pre-release label. Images carry the floating tags `-latest` and `.-latest`, moved forward only by the arm step. A deployment record follows a version PATTERN resolved against the registry (`3.*`), never a floating tag. The new notation starts at line 3.1 (`PlatformReleaseOrder.SemVerEraStart`). Readers land first, then the records' patterns, then the minter. Manual: [Platform Versioning (SemVer)](../PlatformVersioning). | in force | 2026-10-06 | maintainer | | `stale-adoption-bound` | A NodeType build the source has moved past keeps serving (`StaleAdopted`, same module MAJOR) only while it is at most N MINOR versions behind the current source; past N it is refused like a MAJOR bump, named on the node and logged at Error, and within N every judgement and `/health`'s live record census say how far behind it is. N is `Modules:StaleAdoptionMaxMinorVersionsBehind`, default 5; negative disables. The default value is settled on [Systemorph/Memex#668](https://github.com/Systemorph/Memex/issues/668). Manual: [Node Type Compilation](../NodeTypeCompilation). | proposed | — | — | +| `tiered-pgo-off-5212` | TEMPORARY STOPGAP for a .NET runtime defect, stated as one: every process that runs an in-process Roslyn `Emit` runs with `DOTNET_TieredPGO=0` — the CI test, doc-gate and platform-compat jobs, the satellite lanes that compile or bake (`node-repo-{compile-check,gate,module-pack,publish-bake}.yml`, carried INTO each emitting `docker run`), and every portal through its Deployment record's `extraPortalConfig` (rendered by the chart's `memex-portal-config` ConfigMap). It complements the runtimeconfig half (`false`, #890), which reaches only hosts built from this tree. Every place it is set names #5212 and is removed when the runtime fix ships — with the split-arm measurement re-run on that runtime, never on faith. Root cause tracked in [#5212](https://github.com/Systemorph/MeshWeaver/issues/5212) and upstream in dotnet/runtime. Manual: [Node Type Compilation](../NodeTypeCompilation). | in force | 2026-10-07 | maintainer | | `whatsnew-cadence` | A What's New entry is written per RELEASE, not per change. A merge updates its doc page and mints no dated file. | in force | 2026-09-20 | maintainer | | `issue-taxonomy-scope` | Classification covers OPEN issues only. Closed issues are not classified, not counted, and appear in no query. | in force | 2026-09-20 | maintainer | | `release-blocker-gate` | A release may not be cut while any `sev:B` or `sev:H` bug is open in the seven repositories that carry the taxonomy; `sev:M` and `sev:L` never gate a cut. Enforced by the `release.cut` standard in the Governance package. | in force | 2026-09-20 | maintainer | From e7fcf1e038d667c519cb032c5358032f0961d1c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20B=C3=BCrgi?= <6334612+rbuergi@users.noreply.github.com> Date: Wed, 7 Oct 2026 20:47:48 +0200 Subject: [PATCH 2/2] ci(#5212): DOTNET_TieredPGO=0 on the build job too (Roslyn compiler server emits in-process) Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/dotnet-test.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/dotnet-test.yml b/.github/workflows/dotnet-test.yml index c5523a16b8..fc72d9ca92 100644 --- a/.github/workflows/dotnet-test.yml +++ b/.github/workflows/dotnet-test.yml @@ -658,6 +658,12 @@ jobs: # must hold the build too, and `!cancelled()` alone would read a skipped need as fine. if: ${{ !cancelled() && needs.precheck.outputs.skip != 'true' && needs.stage-gate.result == 'success' }} timeout-minutes: 25 + # 🚨 TEMPORARY STOPGAP (#5212, policy tiered-pgo-off-5212) — remove when the runtime fix ships. + # `dotnet build` of the whole solution launches a long-lived Roslyn compiler server that + # emits in-process, so it is exposed to the same Tier-1 JIT defect as the test shards (see + # the `test` job's env); `` in a runtimeconfig does not configure that process. + env: + DOTNET_TieredPGO: "0" runs-on: ubuntu-latest outputs: # THE MAIN THE SUITES TEST AGAINST, resolved HERE — as the suites START. A run held at the stage