diff --git a/docs/observability.md b/docs/observability.md index 48333ca05..ebd00c4ce 100644 --- a/docs/observability.md +++ b/docs/observability.md @@ -25,7 +25,7 @@ qyl component to its OTel role, so contributors (human or agent) share one preci ## qyl components in OTel terms - **Instrumentation Library — generic:** [`Qyl.OpenTelemetry.AutoInstrumentation`](https://github.com/ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation) (`4.0.3`). A vendor-neutral, NativeAOT-ready **Automatic Instrumentation** library. Zero source changes: a `PackageReference` is the supported path. Packages: `.Hosting`, `.EntityFrameworkCore`, `.SqlClient`, `.DiagnosticListeners`, `.SourceGenerators`. Public surface: `QylActivitySource`, `QylActivityNames`, `QylAutoInstrumentationIds`, `QylAutoInstrumentationOptions` (per-signal enablement + header/URL redaction), `AddQylAutoInstrumentation(...)` (zero-config via `.Hosting`), and `AddQylAspNetCoreInstrumentation(...)` (opt-in server-span middleware). A single-owner-per-signal registry keeps the interceptor, middleware, and DiagnosticListener lanes from double-instrumenting the same operation. -- **Instrumentation Library — qyl domain:** [`internal/qyl.instrumentation`](../internal/qyl.instrumentation) (namespace `Qyl.Instrumentation`) + its generator. Provides ServiceDefaults (DI/health/endpoints/discovery/resilience) **and** instrumentation for domains the generic library cannot know about: **GenAI** (`Microsoft.Extensions.AI` `IChatClient`) and **agents** (`QylAgentActivityProcessor`, `AddQylAgentInventory`). Its `WebApplicationBuilder.Build()` interceptor composes the generic library in (diagnostic `QYL0138` errors if `Qyl.OpenTelemetry.AutoInstrumentation` is missing). +- **Instrumentation Library — qyl domain:** [`internal/qyl.instrumentation`](../internal/qyl.instrumentation) (namespace `Qyl.Instrumentation`) + its generator. Provides ServiceDefaults (DI/health/endpoints/discovery/resilience) **and** instrumentation for domains the generic library cannot know about: **GenAI** (`Microsoft.Extensions.AI` `IChatClient`) and **agents** (`QylAgentActivityProcessor`, `AddQylAgentInventory`). Its `WebApplicationBuilder.Build()` interceptor wires the ServiceDefaults at the build call site. - **Instrumentation Library — Agent Framework:** `ANcpLua.Agents.Instrumentation` — MAF-native, wraps agents in an `OpenTelemetryAgent` emitting `invoke_agent` / `execute_tool` spans (sensitive data off by default). - **Semantic Conventions:** `Qyl.OpenTelemetry.SemanticConventions` — the vocabulary the instrumentation libraries emit against. Not itself an instrumentation library. - **Backend (not an instrumentation library):** `qyl.collector` — OTLP ingest + DuckDB storage + REST API + dashboard. It *receives* signals; it instruments only itself (via `qyl.instrumentation`). diff --git a/docs/typespec-maf-prd.md b/docs/typespec-maf-prd.md index 262c109f5..ae364ba07 100644 --- a/docs/typespec-maf-prd.md +++ b/docs/typespec-maf-prd.md @@ -8,15 +8,6 @@ authoritative copy and all execution now live there: This stub remains so existing links into qyl don't 404. -## What stays in qyl - -The flagship depends on these qyl assets — they stay here, not in the new repo: - -- **`qyl.conformance`** — the runtime verifier (declared-vs-observed diff engine, - `conformant` gate). The flagship's PR-7 wires `qyl verify` against it. -- **`Qyl.Api.Contracts`** — the `TelemetryControlGraph` / `ConformanceReport` types - (published to nuget.org via `qyl-api-schema`) that the loop's reports round-trip through. - ## Status Campaign live: building `typespec-agent-framework` through the PRD's PR-0→~PR-8 diff --git a/eng/build/BuildVerify.cs b/eng/build/BuildVerify.cs index 0cb472dbc..ab796de37 100644 --- a/eng/build/BuildVerify.cs +++ b/eng/build/BuildVerify.cs @@ -2019,8 +2019,6 @@ void EnsureStorageIdentity( "AttributeKeyPrefix", "StartsWithOrdinal(QylCapabilityPrefix)", "Paths.Any(path.StartsWithIgnoreCase)", - "status_message", - "span.Status?.Message", "ProfileDataJson", "profile_data_json", "ProfileFrameType", diff --git a/internal/qyl.instrumentation.generators/ServiceDefaultsSourceGenerator.cs b/internal/qyl.instrumentation.generators/ServiceDefaultsSourceGenerator.cs index dcf8fcd71..d4b3366b4 100644 --- a/internal/qyl.instrumentation.generators/ServiceDefaultsSourceGenerator.cs +++ b/internal/qyl.instrumentation.generators/ServiceDefaultsSourceGenerator.cs @@ -138,9 +138,8 @@ private static void AppendBuildInterceptorMethod( // Wire qyl ServiceDefaults (conventions, generated service + health-check registration, and // default endpoints) at the single WebApplicationBuilder.Build() call site, then build the host. // The OTel ASP.NET Core server-span middleware is registered independently via - // AddQylAspNetCoreInstrumentation() (an IStartupFilter), so this interceptor no longer composes it - // and no longer contends with the OTel package for the Build() call site (the CS9153 collision that - // the old QylInterceptedAspNetCore.Build wrapper + opt-out property existed to work around). + // AddQylAspNetCoreInstrumentation() (an IStartupFilter); composing it here would contend with the + // OTel package for the Build() call site (CS9153 duplicate interceptor). sb.AppendLine($$""" // Intercepted call at {{displayLocation}} {{interceptAttribute}} diff --git a/packages/Qyl.Run.Host/Program.cs b/packages/Qyl.Run.Host/Program.cs index 3f50231de..cddb09749 100644 --- a/packages/Qyl.Run.Host/Program.cs +++ b/packages/Qyl.Run.Host/Program.cs @@ -7,8 +7,7 @@ // files), then blocks with the live TUI. The runner's own read-only resource state is exposed at // http://127.0.0.1:18888/runner/resources (+ /stream) for qyl.run.dashboard. // -// Note: resources are launched via `dotnet run --project `, so only .NET projects can be added -// today; launching the dashboard's Vite dev server (npm) is a separate, planned launcher capability. +// Note: resources are launched via `dotnet run --project `, so only .NET projects can be added. var app = QylAppBuilder.Create(args); app.AddCollector("collector", port: 5100, project: "services/qyl.collector"); diff --git a/packages/Qyl.Run/Internal/QylResourceRegistry.cs b/packages/Qyl.Run/Internal/QylResourceRegistry.cs index cdafdd94c..72eaf54a5 100644 --- a/packages/Qyl.Run/Internal/QylResourceRegistry.cs +++ b/packages/Qyl.Run/Internal/QylResourceRegistry.cs @@ -8,7 +8,7 @@ internal sealed class QylResourceRegistry(TimeProvider time) { // Broadcast fan-out: every subscriber (the Spectre TUI, an SSE endpoint, …) owns its own channel. // Publish records the latest state and mirrors the event into every subscriber's channel, so a second - // consumer never steals events from the first (the old single-reader channel could not be shared). + // consumer never steals events from the first. private readonly ConcurrentDictionary> _subscribers = new(); private readonly ConcurrentDictionary _latest = new(StringComparer.Ordinal); diff --git a/services/qyl.collector/Ingestion/OtlpConverter.cs b/services/qyl.collector/Ingestion/OtlpConverter.cs index 01a6d4e89..0579597bd 100644 --- a/services/qyl.collector/Ingestion/OtlpConverter.cs +++ b/services/qyl.collector/Ingestion/OtlpConverter.cs @@ -137,8 +137,6 @@ private static Dictionary ExtractAttributesFromProto return attributes; } - // CODE RED #4: OTLP span Events (including OTel exception events) and Links were dropped on ingest. - // Capture them here so ingest -> storage -> span-detail API preserves them. private static IReadOnlyDictionary ConvertSpanChildAttributes( RepeatedField protoAttributes) { diff --git a/services/qyl.collector/Mapping/Mappers.cs b/services/qyl.collector/Mapping/Mappers.cs index 092c427a6..80c328de4 100644 --- a/services/qyl.collector/Mapping/Mappers.cs +++ b/services/qyl.collector/Mapping/Mappers.cs @@ -119,7 +119,6 @@ private static SpanStatusCode MapStatus(byte statusCode) => _ => SpanStatusCode.Unset }; - // CODE RED #4: rehydrate the span's events (incl. exception events) and links from storage. private static IReadOnlyList MapEvents(string? eventsJson) { var stored = SpanChildStorage.DeserializeEvents(eventsJson); diff --git a/services/qyl.collector/Storage/DuckDbReaderExtensions.cs b/services/qyl.collector/Storage/DuckDbReaderExtensions.cs index 99b616e3a..c92282713 100644 --- a/services/qyl.collector/Storage/DuckDbReaderExtensions.cs +++ b/services/qyl.collector/Storage/DuckDbReaderExtensions.cs @@ -58,7 +58,6 @@ internal sealed partial record SpanStorageRow [DuckDbColumn(SqlType = "VARCHAR(256)")] public string? SchemaUrl { get; init; } - // CODE RED #4: previously dropped on ingest — status message + events (incl. exception events) + links. [DuckDbColumn(SqlType = "VARCHAR")] public string? StatusMessage { get; init; } [DuckDbColumn(SqlType = "JSON")] diff --git a/services/qyl.collector/Storage/SpanChildStorage.cs b/services/qyl.collector/Storage/SpanChildStorage.cs index 622cbb577..0b4438a4f 100644 --- a/services/qyl.collector/Storage/SpanChildStorage.cs +++ b/services/qyl.collector/Storage/SpanChildStorage.cs @@ -20,9 +20,8 @@ internal sealed class SpanLinkJson } /// -/// Serializes a span's events and links to JSON for the spans row. Previously OTLP span Events (including -/// OTel exception events) and Links were dropped on ingest (CODE RED #4); they are now persisted so the -/// span-detail API can return them. Each child's attributes reuse the same safe-attribute JSON as the span. +/// Serializes a span's events and links to JSON for the spans row. Each child's attributes reuse the +/// same safe-attribute JSON as the span. /// internal static class SpanChildStorage { diff --git a/services/qyl.dashboard/src/components/ui/download-button.tsx b/services/qyl.dashboard/src/components/ui/download-button.tsx index a574a82eb..a524865a0 100644 --- a/services/qyl.dashboard/src/components/ui/download-button.tsx +++ b/services/qyl.dashboard/src/components/ui/download-button.tsx @@ -41,7 +41,6 @@ export function DownloadButton>({ try { const data = getData(); if (data.length === 0) { - // Could show a toast here, but for now just skip return; } downloadData(data, format, filenamePrefix, columns); diff --git a/services/qyl.dashboard/src/pages/LogsPage.tsx b/services/qyl.dashboard/src/pages/LogsPage.tsx index 26562d271..0b750ccf5 100644 --- a/services/qyl.dashboard/src/pages/LogsPage.tsx +++ b/services/qyl.dashboard/src/pages/LogsPage.tsx @@ -518,8 +518,6 @@ export function LogsPage() { const currentGen = logsBufferRef.current.generation; if (currentGen !== lastGenerationRef.current) { lastGenerationRef.current = currentGen; - // With composite keys, we don't need to clear expanded state anymore! - // Just remeasure since indices may have shifted rowVirtualizer.measure(); } }, [logsVersion, rowVirtualizer]);