Skip to content

A superseded-image-assembly entry has no staleness check — it survives the image rebuild that retires it #3223

Closed

Description

@rbuergi

The gap

superseded-image-assemblies (pack lane) / --superseded-image-assembly (build-project) drops an
image assembly from a container build's reference set, for the one case the shadow set structurally
cannot see: a type moving OUT of an image-shipped assembly into a module in the same repo, where the
ProjectReference edge that would have shadowed the stale copy is the edge the move deletes. See
Doc/Architecture/ModuleBuildArchitecture → "Moving a type OUT of an image-shipped assembly into a
module".

It fails closed on three inputs today: an empty name, a name the image does not carry, and a name the
run already builds from source.

It does not detect the fourth: an entry that has gone STALE. Once the pin moves onto an image
built after the move, that image's copy of the assembly no longer defines the conflicting types — but
the assembly still exists, so the "not carried by the image" check does not fire. The entry then
sits in the caller's workflow doing nothing, and nothing says so.

Why it matters rather than being untidy

A stale entry is not inert. It keeps dropping a real image assembly from the reference set, so the
day someone legitimately needs a different type from it, the compile fails with a CS0246 that
points at the consuming code and not at the stale declaration that caused it. And this exact shape —
an allow-style entry that outlives its reason with nothing to retire it — is a recurring defect
class here, not a hypothetical.

The durable check

Refuse the build when the image's copy of a superseded assembly defines none of the type names
this run's source defines. That is the precise statement of "there is nothing left to supersede":

  • the tester already reads the container's assemblies, so their type names are available as metadata;
  • the run's own source type names are available from the compilations it is about to make;
  • an empty intersection ⇒ the entry has done its job and must be removed, named in the error.

Ordering matters: the check needs the source's declared type names, so it belongs after the graph's
compilations are known rather than at option-validation time — which is why it was not folded into
the three cheap checks.

Deliberately not built with the original change: it is a second mechanism with its own failure modes,
and shipping it half-formed alongside a fix that unblocks a blocked pipeline would have been the
worse trade. Filed instead so the omission is visible.

Activity

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