From c0bef30895948e7f70804a2a304be437d2c612aa Mon Sep 17 00:00:00 2001 From: "Harol A. Reina H." Date: Sat, 3 Oct 2026 20:46:12 -0500 Subject: [PATCH 1/7] build(deps): cascade Verbara.Sdk 2.7.0 and Verbara.Sdk.Pro 2.17.0-pro --- Directory.Packages.props | 58 ++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 6edb74bf..52594908 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -21,9 +21,9 @@ - - - + + + + + + + diff --git a/tests/Verbara.Platform.Api.Tests/Observability/PrometheusScrapingEndpointTests.cs b/tests/Verbara.Platform.Api.Tests/Observability/PrometheusScrapingEndpointTests.cs new file mode 100644 index 00000000..a7f5b073 --- /dev/null +++ b/tests/Verbara.Platform.Api.Tests/Observability/PrometheusScrapingEndpointTests.cs @@ -0,0 +1,43 @@ +using System.Net; + +namespace Verbara.Platform.Api.Tests.Observability; + +/// +/// Guards the observable behaviour of app.MapPrometheusScrapingEndpoint(): a scrape of +/// /metrics must carry metric samples, not just a 200. Verbara.Sdk.OpenTelemetry 2.7.0 raised +/// OpenTelemetry to 1.19.1 while still pulling OpenTelemetry.Exporter.Prometheus.AspNetCore +/// 1.15.2-beta.1, whose serializer calls OpenTelemetry.Internal.MathHelper (gone in 1.19.1): +/// the exporter swallowed the failure and every scrape answered 200 with an empty body. +/// +public sealed class PrometheusScrapingEndpointTests : IClassFixture +{ + private readonly UnifiedPlatformApiFactory _factory; + + public PrometheusScrapingEndpointTests(UnifiedPlatformApiFactory factory) + { + _factory = factory; + } + + [Fact] + public async Task GetMetrics_ShouldReturnMetricSamples_WhenRequestsWereServed() + { + var client = _factory.CreateAuthenticatedClient(); + + // Serve a few requests so the ASP.NET Core hosting meter records + // http.server.request.duration samples for the scrape to export. + for (var i = 0; i < 3; i++) + (await client.GetAsync("/health")).Dispose(); + + using var response = await client.GetAsync("/metrics"); + var body = await response.Content.ReadAsStringAsync(); + + response.StatusCode.Should().Be(HttpStatusCode.OK); + body.Should().NotBeEmpty("a Prometheus scrape after served requests must carry samples"); + var sampleLines = body + .Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) + .Where(line => !line.StartsWith('#')) + .ToList(); + sampleLines.Should().NotBeEmpty("the body must hold at least one metric sample line"); + body.Should().Contain("http_server_request_duration_seconds"); + } +} From ec23cbdced93e3f796a9e1f695a3d863459c96fa Mon Sep 17 00:00:00 2001 From: "Harol A. Reina H." Date: Sat, 3 Oct 2026 21:10:34 -0500 Subject: [PATCH 6/7] docs(changelog): record the Prometheus exporter pin in the cascade entry --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2cfbc66..1ee890fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,10 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html). reported no `NU1605`/`NU1109`, so every third-party central pin stays where it was. Transitively, `OpenTelemetry` (not pinned here) resolves `1.19.1` instead of `1.17.0`; no package entered or left the graph. +- **`OpenTelemetry.Exporter.Prometheus.AspNetCore` pinned at `1.19.1-beta.1`** — Sdk `2.7.0` raises + `OpenTelemetry` to `1.19.1` but still pulls exporter `1.15.2-beta.1`, which calls a type `1.19.1` + removed, so `GET /metrics` answered `200` with an empty body; the pin restores the samples and a + `/metrics` test now guards them. Removed when the Sdk ships the aligned exporter (Sdk `2.8.0`). - **Behaviour Platform takes on — queued calls get an owner (H159).** Since Sdk `2.7.0` (Verbara.Sdk#377) the SDK connects a queued call only when the queue reports that a member took it, and emits one `CallConnectedEvent` per such call. A queue call answered by a Platform agent therefore @@ -35,8 +39,8 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html). bodies, so the wrapper compiled clean while answering `false`, dropping the outcome and raising nothing; four tests now lock the forwarding. Platform does not call any of them yet. - **Deliberately out of scope** (`Verbara.Sdk/ADR-0040` D4): `Microsoft.Extensions.TimeProvider.Testing` - stays at `10.10.0`, and neither `OpenTelemetry` nor `NATS.Client.Core` gains a direct pin. The second - hop, Sdk `2.8.0` (H142), is a separate change. decision_ref `Verbara.Sdk/ADR-0040`. + stays at `10.10.0`, and neither `OpenTelemetry` itself nor `NATS.Client.Core` gains a direct pin. + The second hop, Sdk `2.8.0` (H142), is a separate change. decision_ref `Verbara.Sdk/ADR-0040`. --- From 2df558fe592f8eb8397d3c8430c6a1c06336e7fb Mon Sep 17 00:00:00 2001 From: "Harol A. Reina H." Date: Sat, 3 Oct 2026 21:20:11 -0500 Subject: [PATCH 7/7] docs(changelog): the cascade adds one central pin --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ee890fc..e9c78701 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html). compatibility triple — **Verbara.Sdk `2.7.0` × Verbara.Sdk.Pro `2.17.0-pro` × Verbara.Platform (the next version cut from `main`)** — is what this entry records; per `Verbara.Sdk/ADR-0040` D3 the cascade rides alone and cuts no version of its own. **No floor moved:** `dotnet restore` - reported no `NU1605`/`NU1109`, so every third-party central pin stays where it was. Transitively, + reported no `NU1605`/`NU1109`, so every existing third-party central pin stays where it was (one is added, below). Transitively, `OpenTelemetry` (not pinned here) resolves `1.19.1` instead of `1.17.0`; no package entered or left the graph. - **`OpenTelemetry.Exporter.Prometheus.AspNetCore` pinned at `1.19.1-beta.1`** — Sdk `2.7.0` raises