Skip to content

A core change in b88be8a05..c41a34fd breaks the plugin-catalog card render — caught only by a test in another repo #3276

Closed

Description

@rbuergi

A core change in b88be8a05..c41a34fd breaks the plugin-catalog card render — and core CI cannot see it

Two tests go red when the core commit under test advances across this range, and are 6/6 green at the old end:

MeshWeaver.PluginCatalog.Test.CatalogRenderTest.Catalog_ListsPackagesFromGitSource_AsCards
MeshWeaver.PluginCatalog.Test.CatalogRenderTest.ALandedModule_PutsTheRestartNoteOnItsPackageCard
Good core b88be8a058689e216f0df20e795cde121da0a365
Bad core c41a34fd
Range 48 commits (git rev-list --count b88be8a05..c41a34fd = 48)
Subject under test src/MeshWeaver.PluginCatalog/ — this repo's code
Where the test lives Systemorph/MeshWeaver.Plugins, src/MeshWeaver.PluginCatalog.Test/CatalogRenderTest.cs

🚨 Why this is worth a ticket rather than a note

The test that catches it is in another repository, so nothing in this repo's CI runs it. MeshWeaver.PluginCatalog is compiled and shipped from here; its card-rendering behaviour is asserted only over in MeshWeaver.Plugins, by a job (Portal hosts) that checks core out at whatever MW_PLATFORM_REF names. So:

  • every one of these 48 commits was merged green here;
  • the breakage becomes visible only when a satellite deliberately advances its pin;
  • and it then presents as "my pin bump is red", which reads like the bumper's problem and is not.

This is the shape recorded in Doc/Architecture/ and in the fleet's own history as a test that is never executed before merge. The Dependent suites (MeshWeaver.Plugins) gate exists for exactly this class — worth checking whether it covers MeshWeaver.PluginCatalog.Test and, if it does, why this got through; if it does not, that is the actionable gap and it is bigger than the two tests.

How it surfaced

Found by the session landing MeshWeaver.Plugins#1268. It moved MW_PLATFORM_REF and the two node-repo-module-pack.yml@<sha> refs together b88be8a05 → c41a34fd, and the two tests went red. The landed workaround splits the pins (uses: on c41a34fd for the workflow definition, MW_PLATFORM_REF held at b88be8a05 for the source) — correct for unblocking a module move, and explicitly not a fix for this:

Whatever broke those two PluginCatalog tests among the 48 commits is still out there and will bite the next core-pin bump. That is a real follow-up, with a bisect as its whole job.

So the pin is held back today. It cannot stay held; the next bump meets this again.

What to do

  1. Bisect the 48. The range is small and the signal is binary, so this is a short job. Run the two tests against core commits in b88be8a05..c41a34fd — the Plugins Portal hosts lane already does exactly this, parameterised by MW_PLATFORM_REF.
  2. Fix the cause in src/MeshWeaver.PluginCatalog/ — or, if the behaviour change was deliberate, update the assertions in Plugins in the same change set and say so, since a deliberate change to card rendering that nobody told the dependent repo about is the same defect wearing a different hat.
  3. Close the visibility gap, which is the durable half: either the dependent-suites gate must cover MeshWeaver.PluginCatalog.Test, or this repo needs its own coverage of the catalog card render. Right now a change here can break a shipped surface and go green.

🚨 Do not "fix" this by relaxing the two assertions, and do not fix it by keeping the pin back — the second is what is happening now by necessity, and it converts a code defect into a permanent pin freeze.

Refs: Systemorph/MeshWeaver.Plugins#1268, #3259 (the repo tests one core and ships another — same family: what is tested and what is shipped are different objects).

Activity

  1. rbuergi commented on Sep 4, 2026

    @rbuergi
    ContributorAuthor

    Bisected: c521f929e — the catalog's landing stopped rendering cards on purpose

    Case 2 of the two: a deliberate behaviour change, not a regression in src/MeshWeaver.PluginCatalog/.

    Both ends reproduced first, then the range narrowed

    A fresh MeshWeaver.Plugins clone at main (which still holds MW_PLATFORM_REF = b88be8a05), built
    with -p:MeshWeaverRoot= pointed at a real core worktree — never the default sibling, which would
    have measured the stale primary checkout.

    core commit CatalogRenderTest + RestartRequiredCardTest
    b88be8a058689e216f0df20e795cde121da0a365 the "good" end Passed! 2/2
    a2b312d9f 97ad19cc1^1 — main immediately before the merge Passed! 2/2
    97ad19cc1 the merge of #3258 (c521f929e) Failed! 2/2
    c41a34fd the "bad" end Failed! 2/2

    The 48 commits are 13 merges on the first-parent path; sandwiching the candidate merge pins it to
    one. Independent corroboration that needs no test run: c521f929e is the only commit of the 48
    that touches src/MeshWeaver.PluginCatalog/ at all
    —
    git diff --stat b88be8a05..c41a34fd -- src/MeshWeaver.PluginCatalog/ is one file,
    CatalogLayoutAreas.cs, +366/−45.

    The mechanism

    Both tests render new LayoutAreaReference(CatalogLayoutAreas.CatalogArea) — no parameters — and
    wait for the returned StackControl to carry /pkg-* sub-areas.

    c521f929e made that page the category landing. RenderFromSource now reads the area reference
    first and branches on a CatalogPlan; the landing branch composes nothing but the source's manifest
    listing and calls BuildLanding, whose areas are source + categories (holding cat-1…cat-n and
    all). The commit says so in its own words — "The landing's CatalogPlan.Packages is EMPTY by
    construction — that is the statement 'read no install record for this page'"
    — and the flat list
    moved behind ?all=true, which is where the landing's own "All packages" tile navigates.

    So the tests do not fail an assertion; they wait 60 s for a card on a page that no longer has one and
    fail as a timeout. The failure text is exactly that: "Last of 5 emission(s) was: StackControl { … }"
    — the page renders fine, it just has no pkg- area.

    Why "deliberate" and not "regression"

    c521f929e shipped with core-side coverage of the new shape:
    test/Memex.Portal.Shared.Test/CatalogCategoryFirstTest.cs (350 lines, added by the same commit) —
    the landing renders tiles and no card while an install record exists on the mesh, a category page
    renders exactly its members with the installed one reading as installed, and an empty catalog renders
    the localized empty state, all through the real GetRemoteStream render path. It even names this
    repo's test in a comment. So point 3 of this issue is already half-satisfied: core is not without
    coverage of the catalog card render — it gained it in the very commit that broke the dependent.

    The visibility gap is real, but it is not the one this issue assumed

    worth checking whether the Dependent suites (MeshWeaver.Plugins) gate covers
    MeshWeaver.PluginCatalog.Test and, if it does, why this got through

    It does not exist. dependent-suites.yml landed on 2026-09-03 08:46 (b37225497, #3103) and was
    withdrawn the same morning at 09:56 (7c27f3e95) on a maintainer directive — "none of the
    top-level repos should have any dependency to anyone else"; "it must be event based"
    — because it
    put a context on every core PR that only Plugins could turn green. c521f929e landed at 20:14 that
    evening, ten hours after the withdrawal. Measured, not remembered: no Dependent suites job exists
    in any core workflow, and gh api repos/Systemorph/MeshWeaver/commits/main/check-runs lists no such
    context. AGENTS.md still instructed you to read it — that stale sentence is fixed in the PR below,
    because an absent required context reads as green.

    And the Cross-repo pair (public surface) gate could not have seen this either: it fires on public
    types and members leaving, and c521f929e removed nothing. It passed on #3258, correctly.

    The actual shape, which no existing mechanism covers

    A public method's BEHAVIOUR changing behind an UNCHANGED signature. RenderFromSource has the
    same name and the same parameters before and after; it simply answers differently. No surface
    detector can see that, by construction.

    The documented answer is the event-based one — "a shape-1…6 break surfaces as a red release-follow
    run in the dependent's repository, minutes after the platform published"
    . That is over-claimed for
    a dependent that pins.
    MeshWeaver.Plugins pins core deliberately (its own #1255), and its
    platform-ref job resolves the same MW_PLATFORM_REF on a repository_dispatch release event as
    on a pull request — the event changes what is baked, not what src/ compiles against. So the
    release-follow run rebuilds Plugins against the commit it already used, and a break introduced after
    the pin is invisible to it until a human bumps the pin. That is why this presented as "my pin bump
    is red"
    , and why it took 48 commits to surface.

    That is not an argument for unpinning — the pin was bought with a real incident. It is an argument
    for saying it out loud: for a dependent that pins, the pin bump IS the integration test, and the
    cost of a break scales with how long the pin sat.

    What is being done

    • Systemorph/MeshWeaver.Plugins#1315 — the two tests open the ?all=true page, which is where
      cards live now. Nothing is relaxed: the same two cards are still required to render, and the
      restart note is still required to reach one of them through
      ModuleLandingService.ActivationChanged while the area is subscribed. The id is a literal and
      not CatalogLayoutAreas.AllParam, because that constant does not exist at the pin this repo
      currently holds — which is what lets the fix land before the pin moves instead of with it.
    • this repo — the doc/AGENTS half (PR linked below): shape 7 in CrossRepoPairGate.md, the
      pinned-dependent correction, and AGENTS.md no longer telling you to read a check that was
      withdrawn.

    🚦 Can MW_PLATFORM_REF move forward?

    Yes, once #1315 merges — these two tests are no longer a reason to hold it. Measured with
    -c Release -warnaserror --no-incremental, one project per invocation:

    core b88be8a05 (today's pin)   0 Warning(s)  0 Error(s)   Passed!  Failed: 0, Passed: 2
    core c41a34fd  (the far end)   0 Warning(s)  0 Error(s)   Passed!  Failed: 0, Passed: 2
    

    The second line also rules out a second break in the range: the fixed tests are green at the far
    end, not merely at the near one. Scope note — this measures MeshWeaver.PluginCatalog.Test only;
    the rest of the Portal hosts lane at c41a34fd is the pin-bump PR's own job to prove, and that PR
    is owned elsewhere. The pin was not touched here.

  2. rbuergi commented on Sep 4, 2026

    @rbuergi
    ContributorAuthor

    This is now the critical path for at least four other fixes — measured 2026-09-04

    Filing this as priority context, not new analysis. MeshWeaver.Plugins is holding MW_PLATFORM_REF at b88be8a058689e216f0df20e795cde121da0a365 because of this issue — Plugins#1268 split its pins deliberately (uses: refs forward for the workflow definition, MW_PLATFORM_REF held back for the source) precisely because advancing the source across these 48 commits reddens the two CatalogRenderTest cases.

    What that held pin now blocks, verified by ancestry against the live pin rather than inferred:

    Plugins MW_PLATFORM_REF = b88be8a05868
    
      #3252  BellQuery / PlatformAddressee   NOT at the pin ❌
      #3270  OutputCurrency                  NOT at the pin ❌
    
    blocked work why
    #3156 / #3216 / #3238 — the notification bell's READER half Plugins#1297 is written and verified green against core main, but CI on the pin is red with CS0117: 'NotificationService' does not contain a definition for 'BellQuery' / 'PlatformAddressee'. Core landed the write side; the reader cannot compile until the pin moves.
    #3249 — the stale-cell indicator's toolbar adoption CodeViews.IsOutputStale lives in Plugins; OutputCurrency() is not at the pin.
    Plugins#1295 its server-side isGlobalAdmin field is 7 hits on core main, 0 at the pin.
    #3244 its option 2 wants the instance to adopt from a sealed publication; sequencing already recorded there.

    So the cost of this issue is no longer "two red tests on a pin bump" — it is that four landed core fixes cannot reach the portal, and the two notification issues had to be REOPENED today after the write half alone was mistaken for the whole fix.

    🚨 The tempting shortcut is to bump the pin and accept two red tests, or to relax the two assertions. Both are wrong for the same reason: Portal hosts is a REQUIRED context in Plugins, so a knowingly-red pin bump either blocks every subsequent Plugins PR or gets the assertions weakened to unblock it — and the second permanently removes the only coverage core has of the catalog card render, which is what let 48 commits merge green in the first place.

    The bisect is the unlock, and it is a short job: 48 commits, a binary signal, ~6 steps.

    Nothing here changes the diagnosis in the issue body; it changes the priority.

  3. rbuergi commented on Sep 4, 2026

    @rbuergi
    ContributorAuthor

    Fixed and merged — the pin is free

    Systemorph/MeshWeaver.Plugins#1315 is merged (df7950df). MW_PLATFORM_REF is no longer held
    by these two tests.

    The bisect, restated with its evidence

    core commit the two tests
    b88be8a05 — the held pin good end 2 passed
    a2b312d9f = 97ad19cc1^1 main immediately before the merge 2 passed
    97ad19cc1 — the merge of #3258, commit c521f929e 2 FAILED
    c41a34fd bad end 2 FAILED

    c521f929e is also the only commit of the 48 that touches src/MeshWeaver.PluginCatalog/.
    Deliberate behaviour change, not a regression: the catalog landing now renders category tiles
    and, by construction, no package card; the flat list moved behind ?all=true. It shipped with
    core-side coverage of the new shape in the same commit
    (test/Memex.Portal.Shared.Test/CatalogCategoryFirstTest.cs), so this repo is not without
    coverage of the catalog render — that premise in the description is out of date.

    The fix relaxes nothing: the same two cards are still required to render, and the restart note is
    still required to reach one of them through ModuleLandingService.ActivationChanged. Only the page
    they open moved. The id is a literal rather than CatalogLayoutAreas.AllParam (which does not exist
    at the held pin), so it is green against both cores and could land before the pin moves.

    🚦 Can the pin move? Yes — measured wider than the two tests

    core b88be8a05   0 Warning(s) 0 Error(s)   Passed! 2/2
    core c41a34fd    0 Warning(s) 0 Error(s)   Passed! 2/2
    

    and the whole Portal hosts graph — all 48 suites plus their closure, one solution,
    -c Release -warnaserror -p:ShouldUnsetParentConfigurationAndPlatform=false
    — builds clean against
    c41a34fd: 0 Warning(s) 0 Error(s). So there is no compile break anywhere in the 48, and the
    green-at-the-far-end test run rules out a second behavioural break in these two. Scope kept honest:
    that measures compilation of the other 47 suites, not their execution — the pin-bump PR still owns
    that, and the pin was not touched here.

    The visibility gap — corrected, and it is not what the description assumed

    ⚠️ Residual — do not lose this

    The documentation half is #3285 (shape 7 in CrossRepoPairGate.md + the pinned-dependent
    correction). Its own checks were 27/27 green, but the merge queue dequeued it on an unrelated
    fleet-wide failure: four satellites opened a rest-not-graphql shared-rule block that core's
    .github/shared-rules.json does not declare, which has AGENTS.md shared rule blocks red on core
    main since 07:37Z and is blocking every core merge. #3285 needs re-arming once that is fixed in
    the repo the error names.

    Closing this: the break is bisected, the cause is named, the fix is merged, and the pin is free.

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