Skip to content

CI shard hosts are dying and taking random tests down with them — 4 different tests failed across 4 runs of inert diffs while main stayed green #1242

Closed

Description

@rbuergi

Evidence (2026-08-11, all on main-synced branches, all green on main itself)

Four CI runs, on diffs that cannot affect any of the tests named, failing different tests every time:

PR diff run failing tests shards
#1219 one word in one .md 1 MeshWeaver.AI.Test.MeshPluginTest.FullCrudWorkflow_CreateGetUpdateDelete 3
#1219 same, after main sync 2 MeshWeaver.AI.Test.ScriptExecutionInUserHomeTest.Run_StreamsProgressTimely_NotBuffered · MeshWeaver.PathResolution.Test.HierarchicalBrowsingTests.Query_WithSkipAndLimit_ReturnsPaginatedResults 3, 4
#1238 one-line code default + .md 1 — GREEN —
#1238 previous + one word in the .md 2 MeshWeaver.Graph.Test.NodeTypeModelProbeTest.ProbeInstanceModel_SnapshotsContentTypeAndSchema · MeshWeaver.Hosting.Monolith.Test.SearchResultStormTest.CatalogSubscription_ContentUpdateStorm_AddsNoExtraRerenders 1, 2

The #1238 pair is the cleanest control available: the same branch went green, then red after a one-word documentation edit, on different tests in different shards.

main was green throughout — last five runs at the time of writing (9398713, dad8615, eb283c4, 56421a5, 9be51fc).

The signature

The shard failures are reported as:

##[error]Shard N: a test host exited non-zero (failure, crash, or timeout kill)

That is a killed or crashed test host, not an assertion. The tests named are whichever happened to be executing when the host died — which is why they differ every run and why they span unrelated assemblies (AI.Test, PathResolution.Test, Graph.Test, Hosting.Monolith.Test).

Why it matters

  • It reds PRs that cannot have caused it, so every author has to first prove innocence. Two separate PRs today spent a full CI cycle each on this.
  • It is indistinguishable at a glance from a real regression, which is corrosive: the correct response to a red PR (investigate, do not re-run) is exactly the wrong response here, and the rule that keeps real flakes honest ("a flake is a real race — do not re-run it away") makes this failure mode maximally expensive.
  • Re-running is the only current workaround, and it burns a full runner cycle plus the shared token budget.

Where I would look

  • Runner resource exhaustion — memory/CPU pressure killing the test host mid-run. Related known shape: the starved-job class where steps report zero duration.
  • Per-shard parallelism vs the runner size (the suite is configured parallelizeAssembly: false, maxParallelThreads: 1, so a host death is more likely environmental than contention inside one project).
  • Whether the shard step distinguishes "test failed" from "host died" in its summary — right now both surface as ##[error]<TestName>, which is what makes this read as a test failure. Reporting the host exit separately would make the class visible immediately.

Unverified: I have not reproduced a host death locally, and I have not checked runner metrics — this is entirely from CI logs.

🤖 Generated with Claude Code

Activity

  1. rbuergi commented on Aug 12, 2026

    @rbuergi
    ContributorAuthor

    Still happening 2026-08-12 — and now it is reddening main itself, four times in one morning

    The original report noted "main was green throughout". That is no longer true. Four post-merge runs on main failed today, every one carrying the host-death signature and each naming a different test in a different assembly:

    time (UTC) run merge failing test shard
    07:04 31572467193 #1258 Hosting.Monolith.Test.DynamicTypePreWarmerTest.RegressedType_ThatRebuildsAfterTheContentConverges_IsRetracted 2
    07:20 31573558342 #1262 FutuRe.Test.FutuReAnalysisTest.EuropeRe_AnnualReport_EmbeddedCharts_ShouldRenderViaPathResolution 2
    07:35 31574636901 #1255 AI.Test.SkillAutocompleteTest.Autocomplete_ListsBuiltInSkills_FromCatalog 3
    08:21 31577940567 #1260 ContentCollections.Test.NodeHubContentCollectionTest.CollectionNamedArea_RendersBrowserForFolder_AndContentFo… 2

    All four annotate as:

    Shard N: a test host exited non-zero (failure, crash, or timeout kill)
    A test host exited non-zero despite the trx gate (crashed or killed mid-run — completed-only results were published)
    

    Two things this adds to the original report:

    1. It is no longer PR-only. A red main is a different severity: the "compare against green main" move that currently lets an author prove innocence stops working when main itself is intermittently red.
    2. Shard 2 in three of four. The original table spread across shards 1–4, so this may be noise, but it is the first hint of clustering and worth checking against runner sizing before assuming uniformity.

    ⚠️ A counter-example from the same morning — do not let this issue become a blanket excuse

    PR #1256 is a markdown-only diff that reddened shards 3 and 4 in AI.Test — superficially an exact match for this issue, and I called it a flake and re-ran it. The re-run failed identically, which is what forced a real look:

    BuiltInSkillCatalogTest.EveryShippedSkillFile_LoadsAsASkillNode
    BuiltInSkillCatalogTest.SkillCatalog_LoadsEveryShippedFile_WithNoSkippedFile
    SkillMarkdownRoundTripTest.EveryBuiltInSkill_RoundTrips_SerializeThenParse_Lossless
    

    It was a genuine regression: the edited skill's front-matter description contained an unquoted : (…authoring a card: three rules…), so the YAML no longer parsed and the skill stopped loading. Verified both directions locally — with the colon exactly those three tests fail, without it all 8 pass.

    The discriminators that separate the two, in the order they are cheap to check:

    • Same tests twice ⇒ real. This issue names different victims each run; a repeat of the identical set is a bug.
    • a test host exited non-zero ⇒ this issue. A named assertion with Failed: N in the trx and no host-death line ⇒ real.
    • "markdown-only, therefore inert" is FALSE in this repo. content/ai/** ships as loadable skill nodes with tests over them, so a docs-shaped diff genuinely can break AI.Test. That assumption is what cost the extra cycle here.

    Worth folding into the issue body, since "inert diff" is the report's central premise and it has at least one real exception.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions