Skip to content

Arming the container-lane refusal is blocked on the FINDING, not on a wave: a RID-specific asset for a RID the bundle does not target is not uncarried (#4367 follow-up) #4445

Closed

Description

@rbuergi

Follow-up to #4367 / #4444. Arm the CONTAINER lane's refusal for the two shapes a module bundle cannot carry — only after a measured container wave.

Where things stand after #4444

  • SDK path (module-pack --deps-closure): REFUSES (exit 2) a RID-specific MANAGED asset, or a native at a layout the loader does not probe, unless something the module names carries it. In the shared lane, the module declares that in its own csproj (MeshWeaverPackWith / MeshWeaverPackWithNative), and node-repo-module-pack.yml turns each item into --with / --with-native.
  • Container lane (memex build project → PrivateClosure): NAMES both shapes as warnings and does not refuse. Until fix(#4367): a dropped native or RID-specific managed asset REFUSES the pack — unless something named carries it #4444 this lane dropped them without a line: NativeContributions.DeclaredBy filtered out an unprobed native (from the image's native section, and from the shelf's runtimeTargets), and the shelf's RID-specific managed assets were read past (only runtime is read). The warnings use the SAME finding wording as the SDK path, so one grep measures both lanes:
    • which is NOT the layout the module loader probes
    • declares a RID-specific MANAGED asset the bundle does not carry

Why it was not armed in #4444

Nothing had ever printed on this lane, so there was nothing to measure. Arming a refusal with no measurement is the #3240 shape: it risks taking the fleet's container publishes down instead of the drops. #4367 was armed on a measurement for exactly this reason.

The criterion — a MEASUREMENT, not a judgement (the same shape as #4367)

  1. A full container-lane wave from every repo that publishes modules (MeshWeaver.Plugins, MeshWeaver.SocialMedia), on a platform pin that carries fix(#4367): a dropped native or RID-specific managed asset REFUSES the pack — unless something named carries it #4444's reporting, prints zero occurrences of either literal in its workspace-build logs. Record the run ids and the denominator: the number of container-built modules in the wave. As of 2026-09-15 that is 38 of Plugins' 41 bundles. The scheduled full wave is the one that can satisfy "full"; a push-triggered wave packs only the affected set.
  2. No live victim. For any occurrence that does exist, first move the module to "build": "sdk" and declare the carrier in its csproj (MeshWeaverPackWith / MeshWeaverPackWithNative), or drop the dependency.
  3. Then turn the builder's warning into a RED project result, with a test per shape and a negative control per shape. The refusal must name a step the module can take ON THIS LANE. Today the only such step is "build it on the sdk path", because the container builder reads no per-module pack additions. If the lane should carry these itself, that is a design change of its own.

🤖 Filed from Claude Code.

Activity

  1. added a commit that references this issue on Sep 15, 2026
  2. rbuergi commented on Sep 16, 2026

    @rbuergi
    ContributorAuthor

    The container-lane measurement this issue is gated on — one wave, and the two shapes answer differently

    Measured on MeshWeaver.Plugins main run
    35073843357

    (attempt 2, green, 2026-09-16 08:27–09:3xZ) — a full container-lane wave. 12 Module bundles jobs,
    4,153,659 bytes of log fetched and grepped for the two finding strings this issue names:

    finding count
    NOT the layout the module loader probes (unprobed native) 0
    declares a RID-specific MANAGED asset the bundle does not carry 6

    The six are ONE package, not six problems

    Every one is System.Security.Cryptography.ProtectedData, from the one global build job
    (Module bundles / Build the workspace, job 104732060403):

    [MeshWeaver.Blazor]              private closure: 'System.Security.Cryptography.ProtectedData' … : runtime
    [MeshWeaver.Azure.Blob]          private closure: 'System.Security.Cryptography.ProtectedData' … : runtime
    [MeshWeaver.SelfUpdate.Aks]      private closure: 'System.Security.Cryptography.ProtectedData' … : runtime
    [MeshWeaver.AI.AzureFoundry]     private closure: 'System.Security.Cryptography.ProtectedData' … : runtime
    [MeshWeaver.AI.OpenAI]           private closure: 'System.Security.Cryptography.ProtectedData' … : runtime
    [MeshWeaver.Mail.MicrosoftGraph] private closure: 'System.Security.Cryptography.ProtectedData' … : runtime
    

    So the six modules share one transitive dependency; closing it once closes all six.

    What that means for arming

    The halves are separately armable, and this measurement supports arming the native one now and
    holding the RID-specific one until ProtectedData is either declared (MeshWeaverPackWith) or
    exempted on the ground that its runtime asset is a Windows DPAPI implementation no Linux container
    loads.

    Scope — what this does NOT cover

    One repository and one wave. This issue's criterion names MeshWeaver.SocialMedia as well, and a
    single green wave is not the same as "a wave from every repo that publishes modules". Read the table
    as the Plugins half of the evidence, not the whole of it.

    Measured 2026-09-16 by Claude Opus 5 from the run's own job logs. Instrument note: my first pass
    reported a clean 0/0 from ZERO logs actually fetched — for id in $IDS does not word-split in zsh,
    so every fetch got one bogus id and the failure was swallowed. The counts above come from a run that
    asserts 12 logs and 4.15 MB were read; a fetch count is the only thing separating "no findings" from
    "no measurement".

  3. rbuergi commented on Sep 17, 2026

    @rbuergi
    ContributorAuthor

    The measurement this issue gates on — run, and it does NOT pass

    Scheduled full waves, read 2026-09-17. Recorded in Doc/Architecture/ModuleClosureAccounting via #4580 so it does not live only here.

    repo run / job modules with a derived closure unprobed native RID-specific managed
    MeshWeaver.Plugins 35051691749 / 104654803583 38 0 6
    MeshWeaver.SocialMedia 35178266255 / 105065263652 (pin 3.0.0-ci.8767) 1 (7 closure lines) 0 0

    The 38 matches this issue's own "38 of Plugins' 41 bundles". SocialMedia's figure is from the module job — its workspace job carries no closure lines at all, so that job's 0/0 has a denominator of 0 and is not evidence. The positive control for the native literal's zero is the other literal printing 6 times through the same reporter and the same shared wording.

    The six are one file, and they are not victims

    System.Security.Cryptography.ProtectedData at runtimes/win/lib/netstandard2.0/System.Security.Cryptography.ProtectedData.dll, through MeshWeaver.Blazor, MeshWeaver.Azure.Blob, MeshWeaver.SelfUpdate.Aks, MeshWeaver.AI.AzureFoundry, MeshWeaver.AI.OpenAI, MeshWeaver.Mail.MicrosoftGraph.

    The only RID paths anywhere in that wave's log are those six runtimes/win/ reports and the runtimes/linux-x64/ assets the bundles do carry. It is the Windows implementation of a package whose cross-platform façade under lib/netstandard2.0/ is already carried, in bundles that only ever load inside a Linux container. Omitting it is correct.

    So criterion 2's remedy cannot be applied, and criterion 1 cannot be met as written

    Moving these to "build": "sdk" does not help: DepsClosure has no target-RID comparison either, so the SDK lane refuses the same file — and there is no carrier to name, because a flat closure has neither a slot for a foreign-RID copy nor any need for one.

    What arming needs first is a correction to the finding itself: a RID-specific asset for a RID the bundle does not target is not an uncarried asset. That needs a target RID to compare against, which neither derivation is given today — a design change, deliberately not smuggled in with a bug fix, and the decision this issue now turns on.

  4. rbuergi commented on Sep 17, 2026

    @rbuergi
    ContributorAuthor

    Triage verdict 2026-09-17: do NOT arm — the blocker is the finding's definition, and nothing has changed in code

    Confirming today's measurement rather than repeating it, and recording the disposition so the issue is not
    re-read as "waiting for one more wave":

    • Criterion 1 cannot be met as written. The full waves measured this morning give 38 container-built
      modules with 0 unprobed-native findings and 6 RID-specific-managed findings, all one file
      (System.Security.Cryptography.ProtectedData at runtimes/win/lib/netstandard2.0/…).
    • Criterion 2's remedy does not exist for those six. DepsClosure has no target-RID comparison either,
      so moving them to "build": "sdk" refuses the same file, and a flat closure has no slot to carry a
      foreign-RID copy into.
    • Nothing has landed in code since. UncarriedAssetFindings.RidSpecificManaged /
      UnprobedNative (src/MeshWeaver.Plugin.Packaging/UncarriedAssetFindings.cs) are still produced from
      DepsClosure.cs:184/:193 with no RID comparison, and docs(#4445): the uncarried-asset finding is not scoped to the RID the bundle targets #4580 — the only change referencing this issue today
      — is documentation (Doc/Architecture/ModuleClosureAccounting).

    So the decision this now turns on is not "has a clean wave been observed": it is whether a RID-specific
    asset for a RID the bundle does not target counts as uncarried at all. That needs a target RID handed to
    both derivations — a design change, and the maintainer's call. The native half remains separately armable on
    its measured zero; the RID half must not be armed before the finding is corrected, or it refuses six correct
    bundles (the #3240 shape this issue exists to avoid).

    Re-titled so the title states the blocker instead of promising a wave.

    Read-only verification, 2026-09-17 by Claude Opus 5 (1M context).

  5. changed the title [-]Arm the container-lane refusal for uncarried RID-specific / unprobed-native assets — after a measured container wave (#4367 follow-up)[/-] [+]Arming the container-lane refusal is blocked on the FINDING, not on a wave: a RID-specific asset for a RID the bundle does not target is not uncarried (#4367 follow-up)[/+] on Sep 17, 2026
  6. added
    choreCI, build, dependencies, cleanup - no user-visible behaviour change
    area:buildCore subsystem: the build - manifests, bundles, bakes
    on Sep 20, 2026
  7. rbuergi commented on Sep 21, 2026

    @rbuergi
    ContributorAuthor

    Triage 2026-09-21: left open, chore, no severity

    Blocked on the FINDING, exactly as the title says — and that is a wait for evidence, not for work. The container lane now NAMES both shapes as warnings (#4444) where before it dropped them without a line; arming the refusal needs a measured container wave first, because nothing had ever printed on that lane and a refusal armed over an unmeasured population refuses the first legitimate case as readily as the first real one.

    This is the correct order and worth defending against the instinct to just arm it: the SDK path already refuses (exit 2), so the dangerous half is covered; the container lane's warnings use the same finding wording, so one grep measures both lanes; and the thing still unknown is the denominator — how many of the printed findings are genuine and how many are the shape this issue's own title calls out, "a RID-specific asset for a RID the bundle does not target is not uncarried". Arming before that distinction is made would refuse bundles that are fine.

    So the next action is a read, not a change: grep a container wave for

    which is NOT the layout the module loader probes
    declares a RID-specific MANAGED asset the bundle does not carry
    

    and classify what prints. If the population is empty, that is also an answer — it means the lane has nothing to refuse and the warnings can be promoted cheaply.

    No PR has been opened since #4580 and nothing is stale.

  8. rbuergi commented on Sep 22, 2026

    @rbuergi
    ContributorAuthor

    Re-measured today: the finding is STABLE across two consecutive scheduled waves, and the decision is unchanged — handed back with its exact shape

    Read-only, REST only, per-job logs (the run-level zip of an attempt-2 run omits the workspace job). Positive control first: both literals are emitted from one spelling, src/MeshWeaver.Plugin.Packaging/UncarriedAssetFindings.cs:23 (RID-specific managed) and :32-33 (unprobed native — split over a +, so a single-line grep of src/ finds only the doc quote; the rendered sentence is intact), reached on the container lane through tools/MeshWeaver.PluginTester/NativeContributions.cs:134,147 → ProjectBuild.ReportUncarried. #4444 is 25596ae0f4.

    repo scheduled run platform pin carries #4444 unprobed native RID-specific managed container-built denominator
    MeshWeaver.Plugins 35683069822 (2026-09-22 03:24Z; pack batches cancelled, workspace build success) 3.0.0-ci.9125 / core b9d7fa70be yes (merge-base --is-ancestor rc 0) 0 6 38 (`global build: 38 container entr(y
    MeshWeaver.Plugins 35557555989 (2026-09-21 03:26Z, success) 3.0.0-ci.9067 / 1a85d9b0f6 yes 0 6 (the identical six) 38
    MeshWeaver.SocialMedia 35683283380 (2026-09-22 03:28Z, success) 3.0.0-ci.9125 yes 0 0 0 — no container entries to compile; its one module is build sdk, so this zero is vacuous, not evidence

    The six are the one asset the thread already names — System.Security.Cryptography.ProtectedData at runtimes/win/lib/netstandard2.0/… — in MeshWeaver.Azure.Blob, SelfUpdate.Aks, AI.AzureFoundry, AI.OpenAI, Mail.MicrosoftGraph (5 bundles) and MeshWeaver.Blazor (a sibling ProjectReference in the same workspace, not one of the 41). That path exists only in package versions ≤ 6.0.0 (8.0.0+ ship no runtimes/ folder), which is worth knowing because a transitive floor bump would make the six vanish without deciding anything — and the next Windows-RID asset would print again.

    So criterion 1 is not satisfied, will not become satisfied by waiting, and arming as-is would refuse 5 of 38 correct bundles. The disposition from 2026-09-17 stands; the 2026-09-21 triage's "the next action is a read" had already been done twice. This is the third reading and it agrees.

    The seam, so the decision is about ONE thing

    DepsClosure.RidOf (src/MeshWeaver.Plugin.Build/DepsClosure.cs:488) already yields win for that entry. What neither derivation has is a comparand: nothing in MeshWeaver.Plugin.Build, Plugin.Packaging or PluginCatalog names a target RID (grep RuntimeIdentifier|TargetRid|linux-x64 over .cs in those three: one hit, RidOf itself). The decision is therefore exactly: what RID set does a module bundle target? Three answers, each with its code shape:

    option meaning code shape consequence for the six
    A. the host's RID, unknown at pack time (today's implicit answer) a bundle must be loadable wherever a portal runs keep reporting; arming needs a carrier for every RID — none exists (--with takes one file per slot) stay reported; the refusal can never be armed
    B. the fleet image's RID, declared once bundles are loaded only inside the portal container (linux-x64) a MeshWeaverPackTargetRids item (default: the image RID, declared in ONE place in core, never per-repo), handed to both derivations; a RID-specific asset whose RID is outside the set becomes a third, informational kind (UncarriedKind.NotTargetedRid) excluded from the count that arms the six become zero; arming refuses only a linux-x64-specific asset the bundle lacks
    C. multi-RID bundles carry runtimes/<rid>/… slots per targeted RID a packaging redesign (the flat closure has one slot per assembly name by design) carried, not reported

    B is the recommendation, because it states what is already true of every install this fleet has (bundles are pulled from the registry into Linux portal pods) and it is the only option under which the refusal can ever be armed. It is not taken here because it is a product statement, not a bug fix: it decides that a Windows or macOS dev host loading a bundle is out of scope — and I did not establish whether any host does that today (a Monolith on a developer's machine under Modules:RequirePrebuilt would be the case; a dev Monolith compiling from source is not).

    Owner: the maintainer. What it waits on: the one-line answer "a bundle targets the fleet image RID" (B), or not. On B, the change is one PR in core (target-RID item + third finding kind + a test per shape with a win asset on a linux target as the positive control and a linux-x64 one as the negative), then the SocialMedia side of criterion 1 still has a zero denominator and needs either a container-built module or an explicit statement that its lane has none to measure.

    Left chore, no severity.

  9. rbuergi commented on Oct 9, 2026

    @rbuergi
    ContributorAuthor

    Left open, waiting on evidence: arming the container-lane refusal needs a measured container wave with the finding stable (two waves stable as of 2026-09-22). Decision needed: the owner accepts the measured population as legitimate-or-not. Effort: about 1 h to arm.

  10. added 2 commits that reference this issue on Oct 11, 2026
  11. rbuergi commented on Oct 11, 2026

    @rbuergi
    ContributorAuthor

    Still owed (2026-10-11 19:56Z): #6508 merged at 18:52Z. Proving it is armed needs a Plugins module-pack run on main whose workspace-build.log prints uncarried-asset refusal — ENFORCED. That needs a tester at or after the build carrying #6508 (3.1.10570, in CD now) and the Plugins pin moving to it. No Plugins main catalog run has completed since 17:55Z: 12 are queued.

  12. rbuergi commented on Oct 12, 2026

    @rbuergi
    ContributorAuthor

    Closing: the container-lane refusal is armed, and a main run shows it.

    Plugins main run 38230221656 (head 7930910a3b, 2026-10-12 09:29Z, success), job Module bundles / Build the workspace (one global build) (114752560602) prints:

    09:47:14.391 [T001] uncarried-asset refusal — ENFORCED for bundle target RID linux-x64 (#4445)
    

    The same log shows the scoping #6508 introduced working as intended: a RID-specific asset for a RID the bundle does not target is left out with an info: line, not refused (for example System.Security.Cryptography.ProtectedData runtimes/win/… for MeshWeaver.Azure.Blob, MeshWeaver.Blazor, MeshWeaver.AI.OpenAI and MeshWeaver.Mail.MicrosoftGraph: "left out, correctly, and not a refusal"). All eight bundle batches built.

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

    area:buildCore subsystem: the build - manifests, bundles, bakeschoreCI, build, dependencies, cleanup - no user-visible behaviour changefeature:module-bundle-closureFeature: module bundle closure

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions