Repository navigation
fix(compile): a release request answered by a delivery hold records why (#6832) - #6835
Conversation
…hy (#6832) A release request (an install's, or the forced one a recycle stamps) on a module NodeType whose partition tracks no source lands on the untracked-module gate, which keeps the last build serving (StaleAdopted) by design (#3583). BuildDeliveryHold.Settle cleared CompilationError because the held record is Ok, and that was the only place the gate's reason went: the request read as handled, no build was produced, and nothing on the record said why. Every hold now writes NodeTypeDefinition.DeliveryHoldReason (gate, both module versions and fingerprints, the fix); a compile of the live source or a fresh adoption clears it. The member is operational (masked on sync, mirrored on the compile state). The declined-bundle reason no longer claims the files are the stale side. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Diagnostic accuracy, JSON-safe test reads, and coverage of clearing an existing hold reason need correction.
5 open findings
Prebuilt adoption notices omit the blocking compile gate reason · New Declined bundle version is not tracked in stale decline metadata · New Raw CLR payload check rejects valid JSON-shaped definitions · New Completion predicate and return reject JSON-shaped node definitions · New Control does not verify clearing an existing delivery hold reason · New
What changed in this PR
Records why a NodeType release request produces a delivery hold rather than a new build, preserving the explanation even when the previous build remains usable.
Changes:
- Adds operational
DeliveryHoldReasonstate. - Writes hold explanations and clears them after compilation or adoption.
- Adds regression coverage and documents the diagnostic.
| File | Description |
|---|---|
| test/MeshWeaver.Compiler.Pipeline.Test/UntrackedModuleContentNeverCompilesHereTest.cs | Corrects assertion explanation text. |
| test/MeshWeaver.Compiler.Pipeline.Test/AHeldReleaseRequestSaysWhyTest.cs | Tests held requests and tracked compilation. |
| src/MeshWeaver.Mesh.Contract/NodeTypeOperationalContent.cs | Masks hold reasons from authored sync content. |
| src/MeshWeaver.Graph.Contract/NodeTypeDefinition.cs | Declares the hold-reason field. |
| src/MeshWeaver.Documentation/Data/Architecture/NodeTypeCompilation.md | Documents hold diagnostics and remedies. |
| src/MeshWeaver.Compiler.Pipeline/PrebuiltAssemblySeeder.cs | Revises refusal wording and clears prior reasons. |
| src/MeshWeaver.Compiler.Pipeline/NodeTypeCompileState.cs | Mirrors operational hold state. |
| src/MeshWeaver.Compiler.Pipeline/NodeTypeCompilationHelpers.cs | Maintains reasons across adoption and compilation. |
| src/MeshWeaver.Compiler.Pipeline/BuildDeliveryHold.cs | Records reasons when settling holds. |
🧠 Review effort: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Test Results 20 files - 6 20 suites - 6 1h 0m 42s ⏱️ +45s Results for commit cfa0c36. ± Comparison against base commit cab0ae9. This pull request removes 369 and adds 19 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
…-bundle wording; test reads content via ContentAs (#6832 review) - ApplyAdoptedSourceStamp's RequirePrebuilt branch passes the gate reason to the incompatible / too-far-behind notices written to DeliveryHoldReason, as the stale-but-serving branch already did. - UntrackedPartitionParkReason no longer claims the record's module versions say which side of a declined bundle is newer (AdoptedModuleVersion describes the last accepted build, not the declined one). - AHeldReleaseRequestSaysWhyTest reads NodeTypeDefinition via ContentAs, and the tracked control is seeded with a hold reason (observed right before the request) so its final BeNull proves the compile CLEARS it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Approval recommended
The diagnostic-state changes have no unresolved blocking findings; tests were not executed during this review.
0 open findings
5 resolved since last review
Control does not verify clearing an existing delivery hold reason Completion predicate and return reject JSON-shaped node definitions Raw CLR payload check rejects valid JSON-shaped definitions Declined bundle version is not tracked in stale decline metadata Prebuilt adoption notices omit the blocking compile gate reason
🧠 Review effort: Balanced

Refs #6832
What was wrong
The records in the issue (read on the company instance:
Google/AccountisStaleAdopted, adopted module 1.3.1 over current 1.5,requestedReleaseBy: system-security,requestedReleaseAt == lastReleaseRequestHandledAt, nocompilationError, and no_GitSyncamong the partition's children) show what happened:CompiledSources). It stamped the request as handled and flipped the record toPending.recyclestamps) skips this step, as Force-release is silently discarded: the compile watcher re-adopts the prebuilt bundle instead of compiling, so there is no verb that forces a build of the live source #2818 intends.DispatchOrParkthen reached the untracked-module gate (Bundles are baked for ONE framework identity per run, so a portal's GitSynced sources stay days behind main (or its types go unadopted) — options 1-4 undecided #3583). The type is module content and its partition tracks no source on that mesh, so the gate does not compile it. The type still had a usable build, soSettleAsHoldkept that build serving asStaleAdopted.BuildDeliveryHold.SettleclearedCompilationErrorbecause the held record isOk. That field was the only place the gate's reason went. The handled request therefore produced no build, and nothing on the record said why.Settled with code, per the brief:
StaleAdopted(NodeTypeCompilationHelpers, theRequestedReleaseForcebranch beforeSeedForTypes). It then meets the delivery gates.NodeTypeCompilation.mddocuments that "RequestedReleaseForcedoes NOT bypass" the untracked-module gate.Pendingflip happens on the same write. The missing piece was the outcome's reason, not the attempt.The fix
NodeTypeDefinition.DeliveryHoldReason. It is masked by the sync seams (NodeTypeOperationalContent.MemberNames) and mirrored onNodeTypeCompileState.BuildDeliveryHold.Settlebranches and theRequirePrebuiltbranches ofApplyAdoptedSourceStamp. It names the refusing gate, both module versions and fingerprints, and the fix.ApplyCompileSuccess, a fresh seeder adoption and the adoption stamp clear it.UntrackedPartitionParkReasonno longer claims the files are the stale side. In this incident the bundle was the older side.Doc/Architecture/NodeTypeCompilation, section "A module's content this mesh does not TRACK…", gains a "the hold says why" paragraph.Test (deterministic, real mesh, real GitHub tracking seam)
AHeldReleaseRequestSaysWhyTest.AReleaseRequestAnsweredByAHold_RecordsWhy_AndACompileClearsIthas three arms:StaleAdopted: the type is held, andDeliveryHoldReasonnames the gate, the partition, the fix and 1.3.1.Compiled, a new MVID) and the reason is null.It sits beside
UntrackedModuleContentNeverCompilesHereTest, which uses the same gate scaffolding, inMeshWeaver.Compiler.Pipeline.Test.Negative control: removing only
DeliveryHoldReason = ServingNotice(pending, reason)fromBuildDeliveryHold.Settlemakes the test fail:With the line restored it passes:
passed (2s 958ms) total: 1 failed: 0.Related suites are green locally (Release,
-warnaserrorbuilds,0 Error(s)):What this does NOT do
It does not make those types serve their 1.5 code on the company instance. That needs one of the following, and neither is a core code change:
c003e001for these packages. The second report shows Personal 1.1.1's only bake cancelled at the 45-minute cap.Recycle post-roll
Recycle these addresses so their next handled request writes the reason (no new build is expected until a bundle lands):
AppleMusic/Music,AppleWeather/Weather,Google/Account,HomeAssistant/Home,ICloud/Calendar,Personal/PersonalApp.Pairs-with: none — only adds a member to a record; no public type or member removed.
Mirror-sync: none — no i18n catalog change.
🤖 Generated with Claude Code