Skip to content

fix: a framework roll is FrameworkStale, not a phantom dependency drift - #2492

Merged
rbuergi merged 1 commit into
mainfrom
fix/bake-state-framework-roll-mislabel
Aug 27, 2026
Merged

rbuergi merged 1 commit into
mainfrom
fix/bake-state-framework-roll-mislabel

Conversation

@rbuergi

@rbuergi rbuergi commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

The finding

Investigating "prebuilt bundle adoption fails even when a correct bundle exists" across
Education#216 / SocialMedia#75 / Plugins#723. The single-predicate hypothesis is refuted — no
predicate declines a correct bundle. What is real is a mislabel that made three unrelated problems
look like one.

Measurement (memex-cloud, memex-portal-ai:3.0.0-rc8.ci.6028, 2026-08-27)

ShippedPrebuiltBundles: 79 prebuilt assembly(ies) from 34 shipped bundle(s) under
  /data/prebuilt-bundles/s66ba35f452e54574b804c25724edda75 are backed by the assembly store
  — 1 adopted now, 78 already current
DynamicTypePreWarmer: 273 dynamic NodeType(s) were NOT covered … (DependencyStale: the stamped
  dependency record no longer validates here (a bound module/toolchain dependency changed)) ×273
  • Adoption works: every bundle addressed to the live identity was adopted or already current.
  • grep -c 'dependency record mismatch' over 48 h of logs on both prod portals: 0. Zero
    DECLINED lines of any kind. The seeder's dependency gate has not declined a bundle in production.
  • The 273 are not baked by any bundle (partition content no CI bake covers). They are
    framework-stale, and they said so: AgenticBusiness/Menu and Claims/Claim carry
    compiledFrameworkVersion=sceaefc9…, !toolchain=mvid:bc0ed79d…, against a live s66ba35f… /
    mvid:f8a7cc07… — the value Store/Plugin stamped compiling on this image the same morning.

Why they were mislabeled

Classify checked the dependency record before the framework comparison, and the two are not
independent. !toolchain hashes the FullMvidAssemblies closure's impl MVIDs; FrameworkVersion
folds those same MVIDs — all 16 closure members are ContentSurfaceAssemblies members, and both sets
are pinned by FrameworkBuildIdentityTest. So a framework roll moves the record by construction,
the dependency check always wins the race, and FrameworkStale — "the ordinary every-deploy state …
ABI safety, not a bug" — is unreachable for any record-stamped type. 273/273 vs 0/273 is that
theorem showing up in a log.

Compounding it, the mismatch reason was computed and discarded: Describe printed one fixed
sentence, so the string naming which dependency moved never reached anyone.

The fix

  • A mismatch the framework identity already accounts for → FrameworkStale. Reaching
    DependencyStale now means the framework held still and a binding genuinely moved.
  • ClassifyDetailed returns the first mismatch; DependencyStale's detail names it.

The decline is unchanged. Both states are NeedsBake + WasHealthy, the dependency check still
preempts the bytes-win rule, IsAlreadyAdopted still requires Baked. Same NodeTypes rebuild at the
same time — only the name and the diagnostics change.

What this does and does not explain

Symptom Explained?
SocialMedia#75 — DependencyStale on 93/101 Yes. The ordinary framework roll, not a module drift. Its other pillar is also a misread: latestAssemblyCollection: "local" is FileSystemAssemblyStore.FileSystemCollectionName, set by PutWithLocation for adopted and compiled builds alike — never evidence of non-adoption.
Education#216 No — distinct. Identity matches, DECLINED: 0. Its own thread root-caused it: the 60 s Timeout in PackageInstaller.SeedPrebuiltAssemblies.
Plugins#723 No — distinct. Distribution-side: bundle version doesn't move on a platform-identity rebuild, so the pull side never fetches. Untouched here.
Edu/CourseCatalog gate failures No — distinct. On memex it is Ok, framework- and toolchain-current. compile=Ok render=ok tests=FAILED is downstream of loading.

Testing

dotnet build -c Release -warnaserror clean; MeshWeaver.Graph.Test 71/71 pass across
CompiledDependencyRecordTest, NodeTypeBakeStatusTest, FrameworkBuildIdentityTest,
LoadableBuildPredicateTest, NodeTypeCompileStateTest. Two new tests pin the framework-roll
attribution and the recovered reason.

🤖 Generated with Claude Code

`NodeTypeBakeStatus.Classify` checked the per-type dependency record BEFORE
comparing the record's framework identity to the live one, and the two are not
independent: the reserved `!toolchain` entry hashes the
`FrameworkBuildIdentity.FullMvidAssemblies` closure's implementation MVIDs, and
`FrameworkVersion` folds those SAME MVIDs (all 16 closure members are
`ContentSurfaceAssemblies` members — both sets are pinned by
`FrameworkBuildIdentityTest`). A framework roll therefore moves the record by
construction, the dependency check always fires first, and `FrameworkStale` —
documented as "the ordinary every-deploy state … ABI safety, not a bug" — became
unreachable for any record-stamped type.

Measured on memex-cloud 2026-08-27: 273 of 273 uncovered NodeTypes reported
`DependencyStale` ("a bound module/toolchain dependency changed") and ZERO
reported `FrameworkStale`, while the only thing that had changed was the image —
the types carried framework `sceaefc9…` / `!toolchain mvid:bc0ed79d…` against a
live `s66ba35f…` / `mvid:f8a7cc07…` (the value `Store/Plugin` stamped when it
compiled on this image the same morning).

Second defect, same line: the mismatch reason was computed and thrown away.
`Classify` asked `FindMismatch(…) is not null` and `Describe` printed one fixed
sentence, so the string that says WHICH dependency moved never reached an
operator. Three investigations across three repos (MeshWeaver.Education#216,
MeshWeaver.SocialMedia#75, MeshWeaver.Plugins#723) each read that sentence as
evidence of a module drift and went hunting one that did not exist.

- A record mismatch the framework identity already accounts for is classified
  `FrameworkStale`; reaching `DependencyStale` now means the framework held still
  and a binding genuinely moved.
- `ClassifyDetailed` returns the first mismatch, and `DependencyStale`'s detail
  names it instead of gesturing at it.

The DECLINE is unchanged. Both states are `NeedsBake` and `WasHealthy`, the
dependency check still preempts the bytes-win rule, and `IsAlreadyAdopted` still
requires `Baked` — exactly the same NodeTypes rebuild, at the same time. Only the
name and the diagnostics change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 27, 2026 08:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a misclassification/diagnostics problem in the NodeType bake-state reporting: after a framework roll, NodeTypes were being labeled as DependencyStale (suggesting a module/toolchain drift) even when the framework identity alone explains the dependency-record change. It also restores actionable detail by propagating the specific dependency mismatch string instead of discarding it.

Changes:

  • Reorders bake-state attribution so a dependency-record mismatch that coincides with a framework roll is reported as FrameworkStale, reserving DependencyStale for cases where the framework identity did not move.
  • Introduces ClassifyDetailed to preserve and surface the first dependency mismatch reason, and uses it in store-probing/reporting output.
  • Adds tests that pin the framework-roll classification and assert that mismatch diagnostics name the moved dependency; adds a WhatsNew entry documenting the user-visible reporting change.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
test/MeshWeaver.Graph.Test/CompiledDependencyRecordTest.cs Adds regression tests covering framework-roll attribution and mismatch-detail propagation.
src/MeshWeaver.Graph/Configuration/NodeTypeBakeStatus.cs Implements ClassifyDetailed, fixes classification attribution, and improves DependencyStale/FrameworkStale diagnostics.
src/MeshWeaver.Documentation/Data/WhatsNew/2026-08-27-bake-state-names-the-framework-roll.md Documents the corrected stale-state reporting and improved drift diagnostics.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

1 001 tests   809 ✅  6m 13s ⏱️
    7 suites  192 💤
    7 files      0 ❌

Results for commit c31b992.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

1 078 tests   1 078 ✅  17m 1s ⏱️
    8 suites      0 💤
    8 files        0 ❌

Results for commit c31b992.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

    7 files      7 suites   10m 39s ⏱️
4 404 tests 4 401 ✅ 3 💤 0 ❌
4 998 runs  4 995 ✅ 3 💤 0 ❌

Results for commit c31b992.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

1 379 tests   1 379 ✅  6m 21s ⏱️
    6 suites      0 💤
    6 files        0 ❌

Results for commit c31b992.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

849 tests   845 ✅  6m 30s ⏱️
  8 suites    4 💤
  8 files      0 ❌

Results for commit c31b992.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

1 579 tests   1 578 ✅  9m 46s ⏱️
    9 suites      1 💤
    9 files        0 ❌

Results for commit c31b992.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results

    45 files      45 suites   56m 31s ⏱️
10 288 tests 10 088 ✅ 200 💤 0 ❌
10 884 runs  10 684 ✅ 200 💤 0 ❌

Results for commit c31b992.

@rbuergi
rbuergi merged commit c567c3d into main Aug 27, 2026
24 checks passed
@rbuergi
rbuergi deleted the fix/bake-state-framework-roll-mislabel branch August 28, 2026 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants