fix(modules): collision gate false-positives on published static assets — ci.3958 boot refusal - #1680
Conversation
… published static assets are not collisions A published app's MapStaticAssets registers one endpoint per precompressed variant (identity/gzip/brotli) on the SAME (verb, pattern), disambiguated by content negotiation. The whole-table duplicate assertion therefore refused to serve on EVERY published deployment (ci.3958 crash-looped on memex-cloud) while passing every dev run, which has no precompressed variants. Module groups now stamp MeshModuleEndpointMetadata; FindRouteCollisions only flags duplicate groups involving at least one module-contributed endpoint — the #683 shadowing class the gate exists for — and names the module in the refusal. Regression pinned with the exact published static-asset shape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Fixes a production startup crash-loop caused by the module endpoint collision gate flagging legitimate duplicate static-asset endpoints that appear only in published deployments (precompressed identity/gzip/brotli variants), while preserving the original safety goal of detecting route shadowing involving module-contributed endpoints.
Changes:
- Introduce
MeshModuleEndpointMetadataand stamp it onto endpoints contributed viaMapMeshModuleEndpoints. - Narrow
FindRouteCollisionsto only treat duplicates as collisions when at least one endpoint in the duplicate group is module-contributed, and include the module name in the collision detail. - Add regression tests covering the published static-asset duplicate shape and module-vs-platform collision behavior; document the fix in What’s New.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| test/MeshWeaver.Hosting.Monolith.Test/ModuleEndpointContributionTest.cs | Adds regression tests for published static-asset duplicates and validates module endpoint marker + collision reporting. |
| src/MeshWeaver.Hosting.AspNetCore/MeshModuleEndpointMetadata.cs | Adds marker metadata type used to scope collision detection to module-contributed endpoints. |
| src/MeshWeaver.Hosting.AspNetCore/MeshModuleEndpointExtensions.cs | Stamps module marker metadata on contributed endpoints and updates collision detection + reporting to avoid static-asset false positives. |
| src/MeshWeaver.Documentation/Data/WhatsNew/2026-08-16-endpoint-gate-published-assets.md | Documents the startup fix for published deployments in What’s New. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Test Results (shard 0)919 tests 918 ✅ 10m 33s ⏱️ Results for commit aa8df0c. |
Test Results (shard 4)1 604 tests 1 598 ✅ 7m 5s ⏱️ Results for commit aa8df0c. |
Test Results (shard 5)1 371 tests 1 370 ✅ 5m 50s ⏱️ Results for commit aa8df0c. |
Test Results (shard 3) 11 files 11 suites 6m 9s ⏱️ Results for commit aa8df0c. |
Test Results (shard 1)2 148 tests 2 045 ✅ 6m 44s ⏱️ Results for commit aa8df0c. |
Test Results (shard 2)2 440 tests 2 436 ✅ 8m 14s ⏱️ Results for commit aa8df0c. |
Test Results 65 files 65 suites 44m 39s ⏱️ Results for commit aa8df0c. |
The incident
The first image carrying the endpoint-contribution hook (
3.0.0-rc3.ci.3958) crash-loops on every published deployment: memex-cloud's new pod refused to serve withmemex/atioz are still on ci.3909 only because their self-update poll hadn't fired yet.
Root cause
FindRouteCollisionsasserted the whole endpoint table for duplicate (verb, pattern). A published app'sMapStaticAssetslegitimately registers one endpoint per precompressed variant — identity/gzip/brotli — on the same route, disambiguated byAccept-Encodingcontent negotiation (the three anonymous parties in the[ | | ]groups). Dev runs have no precompressed variants, so every local run and CI test passed while every published deployment refused.Fix
The gate's design scope is the #683 class — a module contribution shadowing (or shadowed by) another route. So:
MeshModuleEndpointMetadata(moduleName)FindRouteCollisionsonly flags duplicate groups involving ≥1 module-contributed endpoint, and names the module in the refusalRegression pinned with the exact prod shape: 3× GET + 3× HEAD on one asset route with no module party → clean; the same route colliding with a module endpoint → still refuses. Plus a discovery test that contributed endpoints carry the marker.
Tests:
ModuleEndpointContributionTest— 4/4 green locally (Release).🤖 Generated with Claude Code