refactor(semconv): cutover to Weaver + remove ~30k LoC dead code - #141
Conversation
…tion
Dead code removal (per docs/contract-drift-architecture.md O-1/O-2):
- delete src/qyl.collector/Ingestion/OtlpAttributes.Utf8.g.cs (6923 LoC)
- delete src/qyl.instrumentation/Instrumentation/SemanticConventions.g.cs (~2600 LoC)
- delete src/qyl.instrumentation/Instrumentation/SemanticConventions.Utf8.g.cs (7555 LoC)
- strip the `csharp` + `csharpUtf8` targets + their ~125 LoC generator functions
from eng/semconv/generate-semconv.ts so future regenerates don't recreate them
- inline the five semconv keys (error.type / exception.*) in
ActivityExceptionTelemetry.cs since the only live consumer is three calls
Net: ~17,000 lines of unused generated code deleted, zero callers in src/,
0 errors / 13 warnings (unchanged). The facades under
src/qyl.contracts/Attributes/ remain the actually-consumed C# surface.
Weaver migration scaffold (not yet wired into the build):
- eng/semconv/templates/registry/qyl/{weaver.yaml,semconv.ts.j2}
- eng/semconv/registry-qyl/manifest.yaml
- .gitignore updates for .tools/ (local weaver binary + upstream clone)
and eng/semconv/out/ (template scratch)
The semconv.ts.j2 template proves the pipeline end-to-end: upstream v1.40.0
YAML registry → weaver → TS exports filtered by qyl's include_prefixes.
The rest of the template set (C# facades, TypeSpec, DuckDB SQL) is the
follow-up. Old generate-semconv.ts stays as-is until the Weaver templates
cover all three remaining outputs byte-close.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughThis pull request migrates semantic conventions generation from a TypeScript-based generator to a Weaver-based workflow. The standalone Node.js script 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Pull request overview
Removes unused generated C# semantic-convention outputs and updates the semconv generation tooling, while adding an initial Weaver-based scaffold for a future migration.
Changes:
- Deleted large unused C# semconv generated output and removed the C# generators/flags from
eng/semconv/generate-semconv.ts. - Inlined the handful of semconv keys needed by instrumentation exception telemetry.
- Added Weaver registry/template scaffolding and regenerated/normalized the TS semconv output formatting.
Reviewed changes
Copilot reviewed 5 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/qyl.instrumentation/Instrumentation/SemanticConventions.g.cs |
Deletes unused generated C# semconv constants file. |
src/qyl.instrumentation/Instrumentation/ActivityExceptionTelemetry.cs |
Replaces references to deleted generated constants with inlined literal keys. |
src/qyl.dashboard/src/lib/semconv.ts |
Regenerated TS semconv output; formatting changes in enum object blocks. |
eng/semconv/templates/registry/qyl/weaver.yaml |
Adds Weaver template config + include-prefix filtering parameters. |
eng/semconv/templates/registry/qyl/semconv.ts.j2 |
Adds initial Weaver TS template scaffold for semconv attributes. |
eng/semconv/registry-qyl/manifest.yaml |
Adds qyl registry manifest stub (prefix include list). |
eng/semconv/generate-semconv.ts |
Removes C# generation code paths and related CLI flags; updates outputs config and comments. |
.gitignore |
Ignores local Weaver/tool scratch directories. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| params: | ||
| semconv_version: "1.40.0" | ||
|
|
||
| # Upstream OTel prefixes to surface in qyl's generated outputs. Everything | ||
| # else in the upstream registry is ignored to keep generated files lean. | ||
| include_prefixes: | ||
| # AI | ||
| - gen_ai | ||
| - code | ||
| # Transport |
There was a problem hiding this comment.
include_prefixes is duplicated here and in eng/semconv/registry-qyl/manifest.yaml. Keeping two authoritative lists increases the chance they drift and templates silently generate different subsets than intended.
Suggested fix: pick a single source of truth for the prefix list (either only params.include_prefixes in this Weaver config, or only the manifest + pass it into templates) and remove the other copy.
| Shape: flat `export const` list grouped by root namespace. | ||
| -#} | ||
| // <auto-generated/> | ||
| // Generated from open-telemetry/semantic-conventions v1.40.0 via Weaver |
There was a problem hiding this comment.
The header hardcodes semconv version v1.40.0 even though params.semconv_version exists in weaver.yaml. This can easily become inconsistent when the version is bumped.
Suggested fix: interpolate the version from params.semconv_version (and consider matching the repo/package naming used by the existing generator headers for consistency).
| // Generated from open-telemetry/semantic-conventions v1.40.0 via Weaver | |
| // Generated from open-telemetry/semantic-conventions {{ params.semconv_version }} via Weaver |
| const utf8Only = args.includes("--utf8-only"); | ||
| const tspOnly = args.includes("--tsp-only"); | ||
| const sqlOnly = args.includes("--sql-only"); | ||
| const protocolOnly = args.includes("--protocol-only"); |
There was a problem hiding this comment.
--cs-only/--utf8-only flags were removed, but they are still referenced by eng/semconv/package.json scripts. With the current arg parsing, passing these unknown flags makes generateAll true, so running those scripts will unexpectedly regenerate all outputs (TS/TypeSpec/SQL/protocol) instead of only C#.
Suggested fix: either keep --cs-only/--utf8-only as supported (even if they become no-ops that error/warn), or update the npm scripts (and any docs/CI invocations) to remove them so behavior matches intent.
| const protocolOnly = args.includes("--protocol-only"); | |
| const protocolOnly = args.includes("--protocol-only"); | |
| const csOnly = args.includes("--cs-only"); | |
| const utf8Only = args.includes("--utf8-only"); | |
| if (csOnly || utf8Only) { | |
| const legacyFlags = [ | |
| csOnly ? "--cs-only" : undefined, | |
| utf8Only ? "--utf8-only" : undefined, | |
| ].filter((flag): flag is string => Boolean(flag)); | |
| console.error( | |
| `Unsupported legacy flag(s): ${legacyFlags.join(", ")}. ` + | |
| "These flags were removed and must not be passed to this script." | |
| ); | |
| process.exitCode = 1; | |
| return; | |
| } |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
eng/semconv/generate-semconv.ts (1)
5-14:⚠️ Potential issue | 🟡 MinorDocstring references removed C# generation.
Line 11 documents
npm run generate:cs # C# onlybut this flag was removed. Update the usage block to reflect the actual supported flags.Proposed fix
* Usage: * npm run generate # Generate all outputs * npm run generate:ts # TypeScript only -* npm run generate:cs # C# only * npm run generate:tsp # TypeSpec only * npm run generate:sql # DuckDB only +* npm run generate:protocol # Protocol facades only🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@eng/semconv/generate-semconv.ts` around lines 5 - 14, The top-of-file usage comment in the generate-semconv.ts script still references "npm run generate:cs # C# only" and lists C# as an output; remove that C# reference and update the header/Usage block to reflect the actual supported targets (TypeScript, TypeSpec, DuckDB) by deleting the "npm run generate:cs" line and removing C# from the initial description so the Usage shows only npm run generate, npm run generate:ts, npm run generate:tsp, and npm run generate:sql; modify the comment block (the usage block at the top of generate-semconv.ts) accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@eng/semconv/generate-semconv.ts`:
- Around line 864-870: The package.json scripts still pass --cs-only and
--utf8-only but main() only checks tsOnly, tspOnly, sqlOnly and protocolOnly so
generateAll becomes true; update main() to also parse const csOnly =
args.includes("--cs-only") and const utf8Only = args.includes("--utf8-only") and
include them in the generateAll calculation (generateAll = !tsOnly && !tspOnly
&& !sqlOnly && !protocolOnly && !csOnly && !utf8Only) so the single-mode scripts
(referenced by the --cs-only and --utf8-only flags) behave as intended; adjust
any downstream branching that uses these flags (locations referencing
tsOnly/tspOnly/sqlOnly/protocolOnly) to handle csOnly and utf8Only consistently.
In `@eng/semconv/registry-qyl/manifest.yaml`:
- Around line 13-76: The include_prefixes array in manifest.yaml is a duplicate
of the allowlist in weaver.yaml; remove the redundant copy from the TS side and
update the TS generator to parse this manifest instead of using its hardcoded
array: modify the generator logic (where the hardcoded allowlist is defined/used
in the TypeScript generator module) to read and parse manifest.yaml
include_prefixes and use that list at runtime/build time, and delete the
duplicated array so include_prefixes in manifest.yaml becomes the single source
of truth.
In `@eng/semconv/templates/registry/qyl/semconv.ts.j2`:
- Around line 10-17: The template semconv.ts.j2 currently only emits attribute
key constants (export const {{ attr.name | screaming_snake_case }}) and omits
the corresponding enum/value objects like GenAiSystemValues and
HttpRequestMethodValues; update the template to also iterate each attribute's
values (e.g., group.attributes -> attr.values) and emit a matching exported
values object for any attribute with defined values (for example an exported
object named {{ attr.name | pascal_case }}Values or {{ attr.name }}Values
containing key/value pairs for each enum constant), ensuring the same naming
scheme used elsewhere so consumers that import GenAiSystemValues,
HttpRequestMethodValues, etc. will receive the generated enums; alternatively,
if enums are intentionally deferred, add a clear comment in semconv.ts.j2
indicating enum generation is disabled and document where/when they will be
produced.
In `@eng/semconv/templates/registry/qyl/weaver.yaml`:
- Around line 14-77: The include_prefixes list in registry/qyl/weaver.yaml is
duplicated across generate-semconv.ts (CONFIG.includePrefixes) and
registry-qyl/manifest.yaml; consolidate to a single canonical source (recommend
registry-qyl/manifest.yaml) and update generate-semconv.ts and the weaver
template to read that manifest at runtime instead of hardcoding
CONFIG.includePrefixes or embedding the list in weaver.yaml: change
generate-semconv.ts to load the manifest’s include_prefixes and export/use that
value, and update the weaver template to reference the manifest-provided
include_prefixes (or accept it as a templating variable) so only manifest.yaml
maintains the authoritative list.
In `@src/qyl.instrumentation/Instrumentation/ActivityExceptionTelemetry.cs`:
- Around line 10-14: ActivityExceptionTelemetry defines hardcoded semconv keys
(ErrorType, ExceptionType, ExceptionMessage, ExceptionStacktrace,
ExceptionEscaped) that duplicate the authoritative constants in GenAiAttributes;
remove these duplicate constants and replace their usages in
ActivityExceptionTelemetry with the corresponding GenAiAttributes.<ConstantName>
references (e.g. use GenAiAttributes.ErrorType, GenAiAttributes.ExceptionType,
GenAiAttributes.ExceptionMessage, GenAiAttributes.ExceptionStacktrace,
GenAiAttributes.ExceptionEscaped) so there is a single source of truth and no
cross-layer spec drift.
---
Outside diff comments:
In `@eng/semconv/generate-semconv.ts`:
- Around line 5-14: The top-of-file usage comment in the generate-semconv.ts
script still references "npm run generate:cs # C# only" and lists C# as an
output; remove that C# reference and update the header/Usage block to reflect
the actual supported targets (TypeScript, TypeSpec, DuckDB) by deleting the "npm
run generate:cs" line and removing C# from the initial description so the Usage
shows only npm run generate, npm run generate:ts, npm run generate:tsp, and npm
run generate:sql; modify the comment block (the usage block at the top of
generate-semconv.ts) accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: ac0f764e-69de-4fb6-aa0a-5759bd061d24
⛔ Files ignored due to path filters (4)
.gitignoreis excluded by none and included by nonesrc/qyl.collector/Ingestion/OtlpAttributes.Utf8.g.csis excluded by!**/*.g.csand included bysrc/**src/qyl.instrumentation/Instrumentation/SemanticConventions.Utf8.g.csis excluded by!**/*.g.csand included bysrc/**src/qyl.instrumentation/Instrumentation/SemanticConventions.g.csis excluded by!**/*.g.csand included bysrc/**
📒 Files selected for processing (6)
eng/semconv/generate-semconv.tseng/semconv/registry-qyl/manifest.yamleng/semconv/templates/registry/qyl/semconv.ts.j2eng/semconv/templates/registry/qyl/weaver.yamlsrc/qyl.dashboard/src/lib/semconv.tssrc/qyl.instrumentation/Instrumentation/ActivityExceptionTelemetry.cs
📜 Review details
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Agent
- GitHub Check: Analyze (csharp)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.cs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.cs: New .cs files must be UTF-8 with BOM. Required fordotnet formatto behave. .editorconfig declarescharset = utf-8-bomunder[*.cs].
Include copyright header// Copyright (c) 2025-2026 ancpluaat the top of .cs files (personal repo; MAF uses the Microsoft header).
XML documentation is required on all public methods and classes.GenerateDocumentationFile=trueis set inDirectory.Build.props.
Use theAsyncsuffix for any method returningTask/ValueTask— including test methods.
Declare private classes assealedunless intentionally subclassed.
Use C# 14 with preview features enabled. File-scoped namespaces, primary constructors, required init properties, pattern matching, switch expressions over if-else.
No suppression of warnings. Forbidden:#pragma warning disable,[SuppressMessage],<NoWarn>. Exception: upstream sample repos demonstrating experimental APIs. qyl'sWarningsAsErrors=CA1816;CA2012;CA2016is already minimal — add more rules, never subtract.
UseIIncrementalGeneratoronly for generators, withForAttributeWithMetadataName, value-equatable models, raw strings overSyntaxFactory. Never storeISymbolin models. Test generators viaANcpLua.Roslyn.Utilitiestest infrastructure.
Never use runtime reflection as a control mechanism,dynamic/ExpandoObject, blocking async (.Result/.Wait()), or any analyzer besidesANcpLua.Analyzers. Do not suppressnull !when the code can be rewritten.
Arrange / Act / Assert comments in test methods. Use the project'sFakeChatClient(tests/qyl.collector.tests/Instrumentation/) forIChatClientdoubles — do NOT hand-rollMoq<IChatClient>.
Wrap everyIChatClientAND theAIAgentwith the telemetry pipeline — both layers, not one. UseUseQylTelemetry(the qyl wrapper) on the chat client, not a hand-rolledUseFunctionInvocation().UseOpenTelemetry(...)chain.
When constructing IChatClient, setEnableSensitiveData = nullto defer to `OTEL_INSTRUMENTATION_GE...
Files:
src/qyl.instrumentation/Instrumentation/ActivityExceptionTelemetry.cs
src/**/*.cs
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.cs: Do not let MAF types leak intoqyl.contracts. Do not let the dashboard call runtime code directly — it goes through the collector REST API. Dependency direction is one-way: contracts at bottom, generators separate, runtime depends on contracts + outputs.
Reference~/Apex.AgenticEntityExtractor/(canonical qyl consumer shape) when building new qyl services. Mirror the three-builder-interface + fluent-middleware pattern from:Agents/ExtractorAgentsBuilder.cs,Clients/ExtractorChatClientBuilder.cs,Workflows/ExtractorWorkflowBuilder.cs,Program.cs.
Files:
src/qyl.instrumentation/Instrumentation/ActivityExceptionTelemetry.cs
⚙️ CodeRabbit configuration file
src/**/*.cs: C#/.NET codebase. Review for: idiomatic C# patterns, proper async/await (no sync-over-async, no fire-and-forget without justification), correct IDisposable/IAsyncDisposable, null safety, and adherence to existing patterns. Flag new public API surface. Check DI lifetime correctness (scoped vs singleton vs transient).
ARCHITECTURAL INVARIANTS — flag violations as blocking: - Every new injectable service must register OpenTelemetry instrumentation (ActivitySource or Meter). - Every new DuckDB write path must handle backpressure (bounded channel or semaphore). - No hardcoded connection strings, paths, or magic strings — use IOptions or IConfiguration. - No new dependencies on Sentry-specific types in core/ — Sentry is an optional backend, not the identity. - CancellationToken must be threaded through all async public methods.
Files:
src/qyl.instrumentation/Instrumentation/ActivityExceptionTelemetry.cs
eng/**
⚙️ CodeRabbit configuration file
Build and deployment infrastructure. Review for: correct MSBuild property usage, Nuke build target dependencies, Docker multi-stage build efficiency, and CI/CD pipeline correctness. Flag hardcoded paths, secrets, or platform-specific assumptions.
Files:
eng/semconv/templates/registry/qyl/weaver.yamleng/semconv/templates/registry/qyl/semconv.ts.j2eng/semconv/generate-semconv.tseng/semconv/registry-qyl/manifest.yaml
src/qyl.dashboard/**
⚙️ CodeRabbit configuration file
React/TypeScript dashboard. Review for: single-responsibility components, proper hook usage (no hooks in conditionals, correct dependency arrays), TypeScript strictness (no
anyunless justified with a comment), and basic accessibility. Uses Tailwind — flag inline styles or custom CSS that duplicates utility classes. Flag any direct fetch() calls that bypass the shared API client.
Files:
src/qyl.dashboard/src/lib/semconv.ts
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: src/qyl.mcp/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:29.212Z
Learning: Applies to src/qyl.mcp/src/qyl.mcp.generators/**/*.cs : `src/qyl.mcp.generators/` must emit `QylToolManifest` with `ToolTypes[]`, `ToolDescriptors[]`, and `CreateTools()`
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: tests/qyl.mcp.generators.tests/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:34.297Z
Learning: Applies to tests/qyl.mcp.generators.tests/**/*.cs : Use `System.Text.Json` instead of Newtonsoft in C# code
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: src/qyl.mcp/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:29.212Z
Learning: Applies to src/qyl.mcp/src/qyl.mcp.generators/**/*.cs : Use `IndentedStringBuilder.BeginBlock()` pattern instead of `Indent()/Outdent()` (which are internal) in generator code
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: src/qyl.mcp/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:29.212Z
Learning: Applies to src/qyl.mcp/**/*.cs : Use `System.Text.Json` instead of Newtonsoft for JSON serialization in C# code
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Compile-time wiring over runtime reflection: the generator owns DI registration, MCP tool registration, and capability catalogs. Use `[QylSkill]` + `[QylCapability]` attributes instead of hand-registering tools.
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Do NOT hand-add tools to DI, MCP registration, or skill catalogs. Use `[QylSkill(QylSkillKind.X)]` and `[QylCapability]` attributes instead — the generator handles registration from the attribute.
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Use `IIncrementalGenerator` only for generators, with `ForAttributeWithMetadataName`, value-equatable models, raw strings over `SyntaxFactory`. Never store `ISymbol` in models. Test generators via `ANcpLua.Roslyn.Utilities` test infrastructure.
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : No suppression of warnings. Forbidden: `#pragma warning disable`, `[SuppressMessage]`, `<NoWarn>`. Exception: upstream sample repos demonstrating experimental APIs. qyl's `WarningsAsErrors=CA1816;CA2012;CA2016` is already minimal — add more rules, never subtract.
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to src/**/*.cs : Do not let MAF types leak into `qyl.contracts`. Do not let the dashboard call runtime code directly — it goes through the collector REST API. Dependency direction is one-way: contracts at bottom, generators separate, runtime depends on contracts + outputs.
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to src/qyl.mcp/**/*.cs : Declare tool class with `[McpServerToolType]` and `[QylSkill(QylSkillKind.X)]`. Declare tool methods with `[QylCapability("id", Starting|FollowUp)]`. Never hand-register tools — let the generator produce `RegisterTools()`, `RegisterServices()`, `Capabilities[]`, `ToolDescriptors[]`.
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Both IChatClient and AIAgent telemetry layers must live at the composition root, never scattered through call sites. No attribute-based agent tracing — `[AgentTraced]` was removed.
Applied to files:
src/qyl.instrumentation/Instrumentation/ActivityExceptionTelemetry.cs
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Use standard OTel environment variables (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_SERVICE_NAME, ENABLE_INSTRUMENTATION) instead of qyl-invented ones. Prefer these over hardcoded config.
Applied to files:
eng/semconv/templates/registry/qyl/weaver.yaml
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.g.ts : Never hand-edit *.g.ts files. Fix the generator input instead.
Applied to files:
eng/semconv/templates/registry/qyl/semconv.ts.j2eng/semconv/generate-semconv.ts
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.g.cs : Never hand-edit *.g.cs files. Fix the generator input (TypeSpec model, attribute, routing table) instead.
Applied to files:
eng/semconv/generate-semconv.ts
📚 Learning: 2026-04-21T00:49:29.212Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: src/qyl.mcp/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:29.212Z
Learning: Applies to src/qyl.mcp/src/qyl.mcp.generators/**/*.cs : `src/qyl.mcp.generators/` must emit `QylToolManifest` with `ToolTypes[]`, `ToolDescriptors[]`, and `CreateTools()`
Applied to files:
eng/semconv/generate-semconv.ts
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Use `IIncrementalGenerator` only for generators, with `ForAttributeWithMetadataName`, value-equatable models, raw strings over `SyntaxFactory`. Never store `ISymbol` in models. Test generators via `ANcpLua.Roslyn.Utilities` test infrastructure.
Applied to files:
eng/semconv/generate-semconv.ts
📚 Learning: 2026-04-21T00:49:34.297Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: tests/qyl.mcp.generators.tests/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:34.297Z
Learning: Applies to tests/qyl.mcp.generators.tests/**/*.cs : Use `System.Text.Json` instead of Newtonsoft in C# code
Applied to files:
eng/semconv/generate-semconv.ts
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to src/**/*.cs : Do not let MAF types leak into `qyl.contracts`. Do not let the dashboard call runtime code directly — it goes through the collector REST API. Dependency direction is one-way: contracts at bottom, generators separate, runtime depends on contracts + outputs.
Applied to files:
eng/semconv/generate-semconv.ts
🔇 Additional comments (1)
src/qyl.dashboard/src/lib/semconv.ts (1)
1-3: Formatting-only changes; file remains generated by legacy process.The header confirms this file is still generated via
npm run generate, not the new Weaver scaffold. The indentation normalization on*Valuesobjects is benign.
| include_prefixes: | ||
| # AI | ||
| - gen_ai | ||
| - code | ||
| # Transport | ||
| - http | ||
| - rpc | ||
| - messaging | ||
| - url | ||
| - user_agent | ||
| - signalr | ||
| - kestrel | ||
| # Data | ||
| - db | ||
| - file | ||
| - vcs | ||
| - artifact | ||
| - elasticsearch | ||
| # Infra | ||
| - cloud | ||
| - container | ||
| - k8s | ||
| - host | ||
| - os | ||
| - faas | ||
| - webengine | ||
| # Security | ||
| - network | ||
| - tls | ||
| - dns | ||
| # Runtime | ||
| - process | ||
| - thread | ||
| - system | ||
| - dotnet | ||
| - aspnetcore | ||
| # Identity | ||
| - user | ||
| - enduser | ||
| - geo | ||
| - client | ||
| - server | ||
| - service | ||
| - telemetry | ||
| # Observe | ||
| - browser | ||
| - session | ||
| - exception | ||
| - error | ||
| - log | ||
| - feature_flag | ||
| - otel | ||
| - test | ||
| # Profiling | ||
| - profile | ||
| - pprof | ||
| # Ops | ||
| - cicd | ||
| - deployment | ||
| # Vendor | ||
| - openai | ||
| - azure | ||
| - oracle | ||
| - oracle_cloud |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Second copy of the allowlist—see weaver.yaml comment.
Same duplication concern applies. This manifest could serve as the single source if the TS generator parsed it instead of maintaining its own hardcoded array.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@eng/semconv/registry-qyl/manifest.yaml` around lines 13 - 76, The
include_prefixes array in manifest.yaml is a duplicate of the allowlist in
weaver.yaml; remove the redundant copy from the TS side and update the TS
generator to parse this manifest instead of using its hardcoded array: modify
the generator logic (where the hardcoded allowlist is defined/used in the
TypeScript generator module) to read and parse manifest.yaml include_prefixes
and use that list at runtime/build time, and delete the duplicated array so
include_prefixes in manifest.yaml becomes the single source of truth.
| // Attribute keys | ||
| {% for group in ctx | sort(attribute="root_namespace") %} | ||
| {% if group.root_namespace in params.include_prefixes %} | ||
|
|
||
| // {{ group.root_namespace }} | ||
| {% for attr in group.attributes | sort(attribute="name") %} | ||
| export const {{ attr.name | screaming_snake_case }} = "{{ attr.name }}"; | ||
| {% endfor %} |
There was a problem hiding this comment.
Template emits attribute keys only; enum values are missing.
The current semconv.ts includes *Values objects (e.g., GenAiSystemValues, HttpRequestMethodValues). This template only emits export const attribute keys. When wired up, the generated output will drop ~1100 lines of enum constants, breaking any consumers that import them.
Either extend the template to emit enum values or document that enum generation is intentionally deferred.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@eng/semconv/templates/registry/qyl/semconv.ts.j2` around lines 10 - 17, The
template semconv.ts.j2 currently only emits attribute key constants (export
const {{ attr.name | screaming_snake_case }}) and omits the corresponding
enum/value objects like GenAiSystemValues and HttpRequestMethodValues; update
the template to also iterate each attribute's values (e.g., group.attributes ->
attr.values) and emit a matching exported values object for any attribute with
defined values (for example an exported object named {{ attr.name | pascal_case
}}Values or {{ attr.name }}Values containing key/value pairs for each enum
constant), ensuring the same naming scheme used elsewhere so consumers that
import GenAiSystemValues, HttpRequestMethodValues, etc. will receive the
generated enums; alternatively, if enums are intentionally deferred, add a clear
comment in semconv.ts.j2 indicating enum generation is disabled and document
where/when they will be produced.
| include_prefixes: | ||
| # AI | ||
| - gen_ai | ||
| - code | ||
| # Transport | ||
| - http | ||
| - rpc | ||
| - messaging | ||
| - url | ||
| - user_agent | ||
| - signalr | ||
| - kestrel | ||
| # Data | ||
| - db | ||
| - file | ||
| - vcs | ||
| - artifact | ||
| - elasticsearch | ||
| # Infra | ||
| - cloud | ||
| - container | ||
| - k8s | ||
| - host | ||
| - os | ||
| - faas | ||
| - webengine | ||
| # Security | ||
| - network | ||
| - tls | ||
| - dns | ||
| # Runtime | ||
| - process | ||
| - thread | ||
| - system | ||
| - dotnet | ||
| - aspnetcore | ||
| # Identity | ||
| - user | ||
| - enduser | ||
| - geo | ||
| - client | ||
| - server | ||
| - service | ||
| - telemetry | ||
| # Observe | ||
| - browser | ||
| - session | ||
| - exception | ||
| - error | ||
| - log | ||
| - feature_flag | ||
| - otel | ||
| - test | ||
| # Profiling | ||
| - profile | ||
| - pprof | ||
| # Ops | ||
| - cicd | ||
| - deployment | ||
| # Vendor | ||
| - openai | ||
| - azure | ||
| - oracle | ||
| - oracle_cloud |
There was a problem hiding this comment.
Triple-maintained allowlist creates spec drift risk.
This include_prefixes list is duplicated verbatim in:
eng/semconv/generate-semconv.ts(CONFIG.includePrefixes)eng/semconv/registry-qyl/manifest.yaml- This file
Adding a new upstream prefix requires synchronized edits across all three. Consider a single canonical source (e.g., manifest.yaml) that the TS generator and Weaver templates both read at runtime.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@eng/semconv/templates/registry/qyl/weaver.yaml` around lines 14 - 77, The
include_prefixes list in registry/qyl/weaver.yaml is duplicated across
generate-semconv.ts (CONFIG.includePrefixes) and registry-qyl/manifest.yaml;
consolidate to a single canonical source (recommend registry-qyl/manifest.yaml)
and update generate-semconv.ts and the weaver template to read that manifest at
runtime instead of hardcoding CONFIG.includePrefixes or embedding the list in
weaver.yaml: change generate-semconv.ts to load the manifest’s include_prefixes
and export/use that value, and update the weaver template to reference the
manifest-provided include_prefixes (or accept it as a templating variable) so
only manifest.yaml maintains the authoritative list.
| private const string ErrorType = "error.type"; | ||
| private const string ExceptionType = "exception.type"; | ||
| private const string ExceptionMessage = "exception.message"; | ||
| private const string ExceptionStacktrace = "exception.stacktrace"; | ||
| private const string ExceptionEscaped = "exception.escaped"; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Eliminate duplicated semconv key ownership to prevent cross-layer spec drift.
ActivityExceptionTelemetry now hardcodes keys already defined in src/qyl.contracts/Attributes/GenAiAttributes.g.cs, while other instrumentation paths still use GenAiAttributes. This creates two authorities for the same attributes (error.type, exception.type, etc.) and can silently diverge.
Proposed refactor
- private const string ErrorType = "error.type";
- private const string ExceptionType = "exception.type";
- private const string ExceptionMessage = "exception.message";
- private const string ExceptionStacktrace = "exception.stacktrace";
+ private const string ExceptionEscaped = "exception.escaped";
@@
- activity.SetTag(ErrorType, ResolveErrorType(exception, errorType));
+ activity.SetTag(GenAiAttributes.ErrorType, ResolveErrorType(exception, errorType));
@@
- { ExceptionType, exception.GetType().FullName },
- { ExceptionMessage, exception.Message },
- { ExceptionStacktrace, exception.ToString() },
+ { GenAiAttributes.ExceptionType, exception.GetType().FullName },
+ { GenAiAttributes.ExceptionMessage, exception.Message },
+ { GenAiAttributes.ExceptionStacktrace, exception.ToString() },
{ ExceptionEscaped, escaped }Also applies to: 38-38, 44-47
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/qyl.instrumentation/Instrumentation/ActivityExceptionTelemetry.cs` around
lines 10 - 14, ActivityExceptionTelemetry defines hardcoded semconv keys
(ErrorType, ExceptionType, ExceptionMessage, ExceptionStacktrace,
ExceptionEscaped) that duplicate the authoritative constants in GenAiAttributes;
remove these duplicate constants and replace their usages in
ActivityExceptionTelemetry with the corresponding GenAiAttributes.<ConstantName>
references (e.g. use GenAiAttributes.ErrorType, GenAiAttributes.ExceptionType,
GenAiAttributes.ExceptionMessage, GenAiAttributes.ExceptionStacktrace,
GenAiAttributes.ExceptionEscaped) so there is a single source of truth and no
cross-layer spec drift.
Two working Weaver-side templates prove the pipeline against upstream semconv v1.40.0, emitting into eng/semconv/out/ (gitignored): - promoted_columns.g.sql.j2 — DuckDB column list, parent-prefix grouped, suffix-driven BIGINT/DOUBLE type inference, 31k lines matching current column count and type distribution - semconv.ts.j2 — TypeScript `export const` flat list, parent-prefix comment groups matching the legacy shape (enum `as const` blocks still TODO; current output covers attribute keys) Two bootstrap scripts so the pipeline is runnable from any clone: - bootstrap-weaver.sh — downloads Weaver v0.22.1 native binary + clones open-telemetry/semantic-conventions@v1.40.0 into .tools/ - run-weaver.sh — invokes `weaver registry generate` with the correct --registry / --templates paths and writes to eng/semconv/out/ Not yet in scope (partial PR #141, cutover to follow): - NUKE target swap — GenerateSemconv still calls `npm run generate` (the stripped-down generate-semconv.ts) for TSP / facades / SQL / TS. The Weaver templates run side-by-side for diff verification. - TypeSpec template (6842-line output with scalars + enum unions + models) - 3 facade templates (GenAi/Db/McpAttributes) — need qyl-extensions.json param loading + upstream-enum merging + cross-cutting attribute pull - TS `as const` enum blocks — structural port of the existing TS generator's enum extraction pass Run locally: ./eng/semconv/bootstrap-weaver.sh && ./eng/semconv/run-weaver.sh Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@eng/semconv/bootstrap-weaver.sh`:
- Line 40: Echo line uses unquoted command substitution which can lead to word
splitting; update the echo to quote the command substitution and variable
expansions so the binary path and the output of the version command are
preserved as single fields. Specifically, change the echo that references
WEAVER_DIR, WEAVER_ARCH and the weaver --version invocation so the binary path
and the "$(${WEAVER_DIR}/weaver-${WEAVER_ARCH}/weaver --version)" are quoted
(e.g., quote "${WEAVER_DIR}/weaver-${WEAVER_ARCH}/weaver" and "$(...)" around
the --version call).
- Around line 16-21: The case block that sets WEAVER_ARCH based only emits
apple-darwin targets and fails on Linux; update the logic that inspects UNAME_M
(and optionally uname -s) so x86_64 on Linux sets
WEAVER_ARCH="x86_64-unknown-linux-gnu" while preserving the existing
"x86_64-apple-darwin" and "aarch64-apple-darwin" mappings for macOS; adjust the
case or add a nested OS check around the UNAME_M branches (refer to the UNAME_M
variable and the WEAVER_ARCH assignment) so Linux CI on x86_64 gets the correct
weaver binary name.
In `@eng/semconv/run-weaver.sh`:
- Line 14: The WEAVER_BIN assignment currently hardcodes "aarch64-apple-darwin"
which breaks portability; change the assignment in eng/semconv/run-weaver.sh so
WEAVER_BIN is computed using the same architecture/OS detection used by
bootstrap-weaver.sh (or source/bootstrap that script) instead of the hardcoded
string, e.g., derive an ARCH/PLATFORM variable and build the path from REPO_ROOT
and that variable, and add a clear existence check that fails with an error if
the computed WEAVER_BIN does not exist; update references to WEAVER_BIN
accordingly.
In `@eng/semconv/templates/registry/qyl/promoted_columns.g.sql.j2`:
- Around line 11-12: The suffix-matching currently uses
attr.name.endswith('_tokens') etc. against dotted attribute names, so it never
matches; change the logic to perform suffix checks on the underscore-converted
attribute name (e.g., set a local variable like attr_underscore = attr.name |
replace('.', '_') or call attr.name.replace('.', '_') and then use
attr_underscore.endswith(...) against bigint_suffixes and double_suffixes),
updating the checks where attr.name.endswith is used (including the occurrences
referenced around bigint_suffixes/double_suffixes and the similar checks at the
other mentioned lines) so attributes like azure.cosmosdb.request.body.size
become azure_cosmosdb_request_body_size and are typed correctly.
In `@eng/semconv/templates/registry/qyl/weaver.yaml`:
- Line 10: The hardcoded semconv_version ("1.40.0") in weaver.yaml risks drift;
centralize the version so both semconv_version and the bootstrap script (which
uses SEMCONV_TAG) read a single source. Update semconv_version to reference a
shared variable (e.g., load from a .env or manifest) and change
bootstrap-weaver.sh to read SEMCONV_TAG from the same source (or export it from
the manifest loader), ensuring the symbols semconv_version and SEMCONV_TAG are
derived from one canonical setting so upgrades only require one edit.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: fbe10510-2af4-4b93-8547-4cec9ca615c9
📒 Files selected for processing (5)
eng/semconv/bootstrap-weaver.sheng/semconv/run-weaver.sheng/semconv/templates/registry/qyl/promoted_columns.g.sql.j2eng/semconv/templates/registry/qyl/semconv.ts.j2eng/semconv/templates/registry/qyl/weaver.yaml
📜 Review details
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (csharp)
🧰 Additional context used
📓 Path-based instructions (1)
eng/**
⚙️ CodeRabbit configuration file
Build and deployment infrastructure. Review for: correct MSBuild property usage, Nuke build target dependencies, Docker multi-stage build efficiency, and CI/CD pipeline correctness. Flag hardcoded paths, secrets, or platform-specific assumptions.
Files:
eng/semconv/templates/registry/qyl/weaver.yamleng/semconv/templates/registry/qyl/semconv.ts.j2eng/semconv/run-weaver.sheng/semconv/bootstrap-weaver.sheng/semconv/templates/registry/qyl/promoted_columns.g.sql.j2
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: src/qyl.mcp/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:29.212Z
Learning: Applies to src/qyl.mcp/src/qyl.mcp.generators/**/*.cs : `src/qyl.mcp.generators/` must emit `QylToolManifest` with `ToolTypes[]`, `ToolDescriptors[]`, and `CreateTools()`
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: tests/qyl.mcp.generators.tests/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:34.297Z
Learning: Applies to tests/qyl.mcp.generators.tests/**/*.cs : Use `System.Text.Json` instead of Newtonsoft in C# code
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Compile-time wiring over runtime reflection: the generator owns DI registration, MCP tool registration, and capability catalogs. Use `[QylSkill]` + `[QylCapability]` attributes instead of hand-registering tools.
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to src/**/*.cs : Do not let MAF types leak into `qyl.contracts`. Do not let the dashboard call runtime code directly — it goes through the collector REST API. Dependency direction is one-way: contracts at bottom, generators separate, runtime depends on contracts + outputs.
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: src/qyl.mcp/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:29.212Z
Learning: Applies to src/qyl.mcp/src/qyl.mcp.generators/**/*.cs : Use `IndentedStringBuilder.BeginBlock()` pattern instead of `Indent()/Outdent()` (which are internal) in generator code
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: src/qyl.mcp/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:29.212Z
Learning: Applies to src/qyl.mcp/**/*.cs : Use `System.Text.Json` instead of Newtonsoft for JSON serialization in C# code
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Do NOT hand-add tools to DI, MCP registration, or skill catalogs. Use `[QylSkill(QylSkillKind.X)]` and `[QylCapability]` attributes instead — the generator handles registration from the attribute.
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Use standard OTel environment variables (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_SERVICE_NAME, ENABLE_INSTRUMENTATION) instead of qyl-invented ones. Prefer these over hardcoded config.
Applied to files:
eng/semconv/templates/registry/qyl/weaver.yaml
🪛 Shellcheck (0.11.0)
eng/semconv/bootstrap-weaver.sh
[info] 40-40: Double quote to prevent globbing and word splitting.
(SC2086)
🔇 Additional comments (2)
eng/semconv/templates/registry/qyl/weaver.yaml (1)
14-77: Triple-maintained allowlist — already flagged.The
include_prefixesduplication concern was raised in a prior review cycle. Deferring to that comment.eng/semconv/templates/registry/qyl/semconv.ts.j2 (1)
12-26: Enum values omission — already flagged.Prior review noted the template drops
*Valuesobjects. Deferring to that comment.
| lstrip_blocks: true | ||
|
|
||
| params: | ||
| semconv_version: "1.40.0" |
There was a problem hiding this comment.
Hardcoded semconv_version creates version drift risk.
Version 1.40.0 is duplicated here and in bootstrap-weaver.sh (SEMCONV_TAG). Upgrading requires synchronized edits. Consider extracting the version to a single source (e.g., a .env file or the manifest) that both scripts and templates consume.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@eng/semconv/templates/registry/qyl/weaver.yaml` at line 10, The hardcoded
semconv_version ("1.40.0") in weaver.yaml risks drift; centralize the version so
both semconv_version and the bootstrap script (which uses SEMCONV_TAG) read a
single source. Update semconv_version to reference a shared variable (e.g., load
from a .env or manifest) and change bootstrap-weaver.sh to read SEMCONV_TAG from
the same source (or export it from the manifest loader), ensuring the symbols
semconv_version and SEMCONV_TAG are derived from one canonical setting so
upgrades only require one edit.
…tain facades Weaver now owns the generated semconv outputs for which qyl consumers exist: - src/qyl.dashboard/src/lib/semconv.ts (TypeScript attribute keys) - src/qyl.collector/Storage/promoted-columns.g.sql (DuckDB promoted cols) Facades moved to hand-maintained source. The prior Jinja-port of three facades (GenAi/Db/Mcp) would have required porting qyl-extensions.json's propertyOverrides + upstream enum-merge + cross-cutting-attribute lookup into MiniJinja — 3–4h of template engineering for 3 files totaling <600 LoC that rarely change. Hand-edit is simpler: - src/qyl.contracts/Attributes/DbAttributes.cs (was .g.cs) - src/qyl.contracts/Attributes/GenAiAttributes.cs (was .g.cs) - src/qyl.contracts/Attributes/McpAttributes.cs (was .g.cs) TS enum `as const` blocks dropped: the sole consumer (src/qyl.dashboard/src/components/genai/ToolDefinitionsViewer.tsx) imports only flat attribute keys (GEN_AI_TOOL_*), not the enum objects. All 7 imports resolve against the new Weaver output; dashboard typecheck clean against the semconv change. TypeSpec output (core/specs/generated/semconv.g.tsp, 6842 lines) stays pinned at v1.40.0 — no Weaver template yet, no regenerator. When OTel bumps semconv, write the TSP Jinja template or port by hand. Deleted: - eng/semconv/generate-semconv.ts (921 LoC) - eng/semconv/qyl-extensions.json (250 LoC config) - eng/semconv/package.json / package-lock.json / tsconfig.json - eng/semconv/CHANGELOG.md (upstream dependency tracker) - eng/semconv/node_modules (gitignored) NUKE `GenerateSemconv` now shells out to bootstrap-weaver.sh + run-weaver.sh. SemconvInstall npm target removed entirely. Net this commit: +754 / -4112 = -3,358 LoC. Plus the -22,005 LoC from the previous commit on this branch gives the PR -25,363 LoC total for the contract-drift cleanup + Weaver cutover. Full solution build: 0 errors, 74 warnings (unchanged from main). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Schema Drift failed on d1c49a4 because run-weaver.sh hardcoded the macOS-arm64 weaver binary path. bootstrap already selected the right release asset per arch; the runner now uses the matching path. Darwin:arm64 / Darwin:x86_64 / Linux:x86_64 supported. Windows explicit unsupported — qyl CI is Linux-only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Follow-up to 4a4f7c5 — also fix bootstrap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ports the 6842-line semconv.g.tsp shape to a 165-line MiniJinja template: - Common scalars (TraceId/SpanId/TokenCount/...) as a fixed prelude - Keys namespace — alias-per-attribute grouped by root namespace - Union types — one per enum-typed attribute (`*Value`) with members + string fallback for unknown values - Per-domain attribute models with @Encodedname + type-correct fields TypeSpec reserved identifiers (namespace, enum, union, unknown, ...) are backtick-escaped via a `safe()` macro. 0 compile errors on core/specs npm run compile against the full qyl TypeSpec schema (18 unrelated upstream warnings, pre-existing). run-weaver.sh now installs into three final destinations: - src/qyl.dashboard/src/lib/semconv.ts (1368 lines) - src/qyl.collector/Storage/promoted-columns.g.sql (1369 lines) - core/specs/generated/semconv.g.tsp (6953 lines) `nuke GenerateSemconv` → bootstrap-weaver.sh + run-weaver.sh. The Weaver migration is complete: the TS `generate-semconv.ts` stack (921 LoC + qyl-extensions.json + npm + tsconfig + CHANGELOG + node_modules) is gone and all three pipeline outputs flow through the Jinja templates. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/qyl.contracts/Attributes/GenAiAttributes.cs (1)
203-216:⚠️ Potential issue | 🟠 MajorDocument governance criteria for qyl extensions.
Two sections marked
// qyl extensionsadd custom operation and provider constants beyond OTel upstream. No documentation explains:
- Criteria for adding qyl-specific values
- Naming conventions for extensions
- How to track which values are qyl-owned vs upstream
- Whether extensions should move to a separate
QylGenAiExtensionsclass to prevent confusionWhen OTel adds new providers or operations, maintainers must manually distinguish qyl extensions from missed upstream additions.
Also applies to: 267-301
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/qyl.contracts/Attributes/GenAiAttributes.cs` around lines 203 - 216, Add clear governance docs and reorganize qyl-specific constants to avoid confusion with upstream OTel values: document criteria for adding qyl extensions, naming conventions, and tracking policy (e.g., prefixing or registry) within the GenAiAttributes class comments and move all qyl-only constants (ImageGeneration, AudioTranscription, TextToSpeech, Rerank and the other qyl entries at 267-301) into a separate QylGenAiExtensions static class; update XML summaries for both GenAiAttributes and QylGenAiExtensions to state which values are qyl-owned vs upstream and include a short maintenance note describing how to reconcile with OTel upstream additions.src/qyl.collector/Storage/promoted-columns.g.sql (1)
1-1369:⚠️ Potential issue | 🟠 MajorCollector ingest still writes the old promoted-column contract.
This regeneration widens the schema, but
src/qyl.collector/Storage/DuckDbStore.cs:42-66still inserts the fixed 26-column span payload andsrc/qyl.collector/Storage/SpanRowMapper.cs:1-60only understands that subset. The new promoted columns will stayNULL, so the schema now advertises fast-query fields the collector never populates. Keep the template allowlist aligned with the ingest contract, or update the ingest generator in the same PR.As per coding guidelines "
**/*.g.sql: Never hand-edit *.g.sql files. Fix the generator input instead."
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@eng/semconv/bootstrap-weaver.sh`:
- Around line 25-39: The script reuses caches by existence only (WEAVER_DIR and
UPSTREAM_DIR) which can lead to stale artifacts when WEAVER_VERSION/WEAVER_ARCH
or SEMCONV_TAG change; update the logic to validate cache contents before reuse:
for the weaver artifact (weaver-${WEAVER_ARCH}/weaver) run a version check (or
read a metadata file written at download time) and compare the reported
version/arch to WEAVER_VERSION/WEAVER_ARCH, and if they differ remove the cached
WEAVER_DIR and re-download; for the semconv upstream (UPSTREAM_DIR) verify the
checked-out commit/tag (git -C "${UPSTREAM_DIR}" rev-parse --verify
"refs/tags/${SEMCONV_TAG}" or compare current HEAD to SEMCONV_TAG) and if it
does not match remove UPSTREAM_DIR and reclone; ensure these checks reference
WEAVER_DIR, WEAVER_VERSION, WEAVER_ARCH, UPSTREAM_DIR, and SEMCONV_TAG so the
cache is invalidated when pins change.
In `@eng/semconv/run-weaver.sh`:
- Around line 19-29: run-weaver.sh duplicates the platform-to-WEAVER_ARCH
mapping (the case that sets WEAVER_ARCH) already present in bootstrap-weaver.sh,
causing drift; extract the detection logic into a single sourced helper (e.g., a
script that sets WEAVER_ARCH or a function like detect_weaver_arch) and update
both run-weaver.sh and bootstrap-weaver.sh to source/call that helper and use
the resulting WEAVER_ARCH variable (or exported value) so they both resolve the
same .tools/weaver/weaver-${WEAVER_ARCH} path consistently.
In `@src/qyl.contracts/Attributes/DbAttributes.cs`:
- Around line 1-6: Add a CI validation that compares the string constants in the
hand-maintained semconv facade classes (DbAttributes, GenAiAttributes,
McpAttributes) against the authoritative OTel semconv registry (either the
Weaver-generated output or the upstream semconv JSON) and fail the build on any
mismatch; implement this by adding a unit/integration test (e.g.,
SemconvValidationTests) that loads the upstream registry artifact at runtime,
enumerates the expected keys, reflects over the constants in
DbAttributes/GenAiAttributes/McpAttributes to collect their values, and asserts
set equality (reporting missing/extra keys), then wire that test into CI as a
required step so any drift breaks the pipeline.
In `@src/qyl.contracts/Attributes/GenAiAttributes.cs`:
- Around line 1-6: Add a CI validation step that parses the constant values from
the hand-maintained attribute classes (e.g., GenAiAttributes.cs,
McpAttributes.cs, DbAttributes.cs) and compares them against the
Weaver-validated outputs (or the upstream OTel registry); implement this as a
new validation routine (e.g., ValidateCsSemconvAlignment or
CompareCsSemconvWithWeaver) invoked from the CI pipeline (or via
BuildPipeline.cs hook) that loads the Weaver-generated semconv reference (or
registry export), extracts key names/values, loads the corresponding const
string fields from the classes (GenAiAttributes, McpAttributes, DbAttributes),
and fails the job with a clear mismatch report when any constant differs so
drift is detected before merge.
In `@src/qyl.contracts/Attributes/McpAttributes.cs`:
- Around line 1-6: The three hand-maintained semconv facades (McpAttributes.cs,
DbAttributes.cs, GenAiAttributes.cs) lack automated drift detection; add a small
verification step (e.g., a script named verify-semconv or verify_semconv.sh)
that fetches the upstream OTel 1.40.0 semconv registry (JSON), parses the
expected keys, and compares them to the constants defined in
McpAttributes.cs/DbAttributes.cs/GenAiAttributes.cs, exiting non-zero on any
mismatch; wire this script into CI (a pipeline job) and optionally into a
pre-commit hook so mismatches fail the build. Alternatively, restore Weaver’s C#
template generation and replace the hand-maintained files with generated
outputs, adding that generation step to CI to keep the files in sync
automatically.
---
Outside diff comments:
In `@src/qyl.contracts/Attributes/GenAiAttributes.cs`:
- Around line 203-216: Add clear governance docs and reorganize qyl-specific
constants to avoid confusion with upstream OTel values: document criteria for
adding qyl extensions, naming conventions, and tracking policy (e.g., prefixing
or registry) within the GenAiAttributes class comments and move all qyl-only
constants (ImageGeneration, AudioTranscription, TextToSpeech, Rerank and the
other qyl entries at 267-301) into a separate QylGenAiExtensions static class;
update XML summaries for both GenAiAttributes and QylGenAiExtensions to state
which values are qyl-owned vs upstream and include a short maintenance note
describing how to reconcile with OTel upstream additions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: fccaef16-ed8c-4742-a393-8175f2a7ffa4
⛔ Files ignored due to path filters (1)
eng/semconv/package-lock.jsonis excluded by!**/package-lock.json,!**/package-lock.jsonand included byeng/**
📒 Files selected for processing (13)
eng/build/BuildPipeline.cseng/semconv/CHANGELOG.mdeng/semconv/bootstrap-weaver.sheng/semconv/generate-semconv.tseng/semconv/package.jsoneng/semconv/qyl-extensions.jsoneng/semconv/run-weaver.sheng/semconv/tsconfig.jsonsrc/qyl.collector/Storage/promoted-columns.g.sqlsrc/qyl.contracts/Attributes/DbAttributes.cssrc/qyl.contracts/Attributes/GenAiAttributes.cssrc/qyl.contracts/Attributes/McpAttributes.cssrc/qyl.dashboard/src/lib/semconv.ts
💤 Files with no reviewable changes (5)
- eng/semconv/tsconfig.json
- eng/semconv/package.json
- eng/semconv/CHANGELOG.md
- eng/semconv/qyl-extensions.json
- eng/semconv/generate-semconv.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (csharp)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.cs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.cs: New .cs files must be UTF-8 with BOM. Required fordotnet formatto behave. .editorconfig declarescharset = utf-8-bomunder[*.cs].
Include copyright header// Copyright (c) 2025-2026 ancpluaat the top of .cs files (personal repo; MAF uses the Microsoft header).
XML documentation is required on all public methods and classes.GenerateDocumentationFile=trueis set inDirectory.Build.props.
Use theAsyncsuffix for any method returningTask/ValueTask— including test methods.
Declare private classes assealedunless intentionally subclassed.
Use C# 14 with preview features enabled. File-scoped namespaces, primary constructors, required init properties, pattern matching, switch expressions over if-else.
No suppression of warnings. Forbidden:#pragma warning disable,[SuppressMessage],<NoWarn>. Exception: upstream sample repos demonstrating experimental APIs. qyl'sWarningsAsErrors=CA1816;CA2012;CA2016is already minimal — add more rules, never subtract.
UseIIncrementalGeneratoronly for generators, withForAttributeWithMetadataName, value-equatable models, raw strings overSyntaxFactory. Never storeISymbolin models. Test generators viaANcpLua.Roslyn.Utilitiestest infrastructure.
Never use runtime reflection as a control mechanism,dynamic/ExpandoObject, blocking async (.Result/.Wait()), or any analyzer besidesANcpLua.Analyzers. Do not suppressnull !when the code can be rewritten.
Arrange / Act / Assert comments in test methods. Use the project'sFakeChatClient(tests/qyl.collector.tests/Instrumentation/) forIChatClientdoubles — do NOT hand-rollMoq<IChatClient>.
Wrap everyIChatClientAND theAIAgentwith the telemetry pipeline — both layers, not one. UseUseQylTelemetry(the qyl wrapper) on the chat client, not a hand-rolledUseFunctionInvocation().UseOpenTelemetry(...)chain.
When constructing IChatClient, setEnableSensitiveData = nullto defer to `OTEL_INSTRUMENTATION_GE...
Files:
src/qyl.contracts/Attributes/DbAttributes.cssrc/qyl.contracts/Attributes/GenAiAttributes.cseng/build/BuildPipeline.cssrc/qyl.contracts/Attributes/McpAttributes.cs
src/**/*.cs
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.cs: Do not let MAF types leak intoqyl.contracts. Do not let the dashboard call runtime code directly — it goes through the collector REST API. Dependency direction is one-way: contracts at bottom, generators separate, runtime depends on contracts + outputs.
Reference~/Apex.AgenticEntityExtractor/(canonical qyl consumer shape) when building new qyl services. Mirror the three-builder-interface + fluent-middleware pattern from:Agents/ExtractorAgentsBuilder.cs,Clients/ExtractorChatClientBuilder.cs,Workflows/ExtractorWorkflowBuilder.cs,Program.cs.
Files:
src/qyl.contracts/Attributes/DbAttributes.cssrc/qyl.contracts/Attributes/GenAiAttributes.cssrc/qyl.contracts/Attributes/McpAttributes.cs
⚙️ CodeRabbit configuration file
src/**/*.cs: C#/.NET codebase. Review for: idiomatic C# patterns, proper async/await (no sync-over-async, no fire-and-forget without justification), correct IDisposable/IAsyncDisposable, null safety, and adherence to existing patterns. Flag new public API surface. Check DI lifetime correctness (scoped vs singleton vs transient).
ARCHITECTURAL INVARIANTS — flag violations as blocking: - Every new injectable service must register OpenTelemetry instrumentation (ActivitySource or Meter). - Every new DuckDB write path must handle backpressure (bounded channel or semaphore). - No hardcoded connection strings, paths, or magic strings — use IOptions or IConfiguration. - No new dependencies on Sentry-specific types in core/ — Sentry is an optional backend, not the identity. - CancellationToken must be threaded through all async public methods.
Files:
src/qyl.contracts/Attributes/DbAttributes.cssrc/qyl.contracts/Attributes/GenAiAttributes.cssrc/qyl.contracts/Attributes/McpAttributes.cs
eng/**
⚙️ CodeRabbit configuration file
Build and deployment infrastructure. Review for: correct MSBuild property usage, Nuke build target dependencies, Docker multi-stage build efficiency, and CI/CD pipeline correctness. Flag hardcoded paths, secrets, or platform-specific assumptions.
Files:
eng/build/BuildPipeline.cseng/semconv/bootstrap-weaver.sheng/semconv/run-weaver.sh
src/qyl.dashboard/**
⚙️ CodeRabbit configuration file
React/TypeScript dashboard. Review for: single-responsibility components, proper hook usage (no hooks in conditionals, correct dependency arrays), TypeScript strictness (no
anyunless justified with a comment), and basic accessibility. Uses Tailwind — flag inline styles or custom CSS that duplicates utility classes. Flag any direct fetch() calls that bypass the shared API client.
Files:
src/qyl.dashboard/src/lib/semconv.ts
**/*.g.sql
📄 CodeRabbit inference engine (AGENTS.md)
Never hand-edit *.g.sql files. Fix the generator input instead.
Files:
src/qyl.collector/Storage/promoted-columns.g.sql
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: src/qyl.mcp/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:29.212Z
Learning: Applies to src/qyl.mcp/src/qyl.mcp.generators/**/*.cs : `src/qyl.mcp.generators/` must emit `QylToolManifest` with `ToolTypes[]`, `ToolDescriptors[]`, and `CreateTools()`
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to src/qyl.mcp/** : When MAF conventions conflict with qyl conventions, MAF wins. qyl consumes MAF and must stay aligned with upstream .NET patterns. Read the `microsoft-agent-framework` global skill plus the `microsoft-agent-framework-qyl` overlay in `.claude/skills/`.
Applied to files:
src/qyl.contracts/Attributes/DbAttributes.cssrc/qyl.contracts/Attributes/GenAiAttributes.cssrc/qyl.contracts/Attributes/McpAttributes.cs
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: qyl emits OTel GenAI semconv 1.40 with required attributes: `gen_ai.system`, `gen_ai.request.model`, `gen_ai.response.model`, `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`, `gen_ai.operation.name`, `gen_ai.tool.call.id`, `gen_ai.tool.name`, `gen_ai.agent.name`, `gen_ai.agent.id`.
Applied to files:
src/qyl.contracts/Attributes/DbAttributes.cssrc/qyl.contracts/Attributes/GenAiAttributes.cssrc/qyl.contracts/Attributes/McpAttributes.cssrc/qyl.dashboard/src/lib/semconv.tssrc/qyl.collector/Storage/promoted-columns.g.sql
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to src/**/Program.cs : Every qyl service must wire OTel at the composition root: `ResourceBuilder.CreateDefault().AddService(...).AddAttributes(...)` plus `.UseQylTelemetry()` on IChatClient and `.UseOpenTelemetry()` on AIAgent.
Applied to files:
src/qyl.contracts/Attributes/DbAttributes.cssrc/qyl.contracts/Attributes/GenAiAttributes.cssrc/qyl.contracts/Attributes/McpAttributes.cs
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Do NOT hand-add tools to DI, MCP registration, or skill catalogs. Use `[QylSkill(QylSkillKind.X)]` and `[QylCapability]` attributes instead — the generator handles registration from the attribute.
Applied to files:
src/qyl.contracts/Attributes/GenAiAttributes.cssrc/qyl.contracts/Attributes/McpAttributes.cs
📚 Learning: 2026-04-21T00:49:29.212Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: src/qyl.mcp/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:29.212Z
Learning: Applies to src/qyl.mcp/src/qyl.mcp.generators/**/*.cs : `src/qyl.mcp.generators/` must emit `QylToolManifest` with `ToolTypes[]`, `ToolDescriptors[]`, and `CreateTools()`
Applied to files:
eng/build/BuildPipeline.cssrc/qyl.contracts/Attributes/McpAttributes.cs
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Compile-time wiring over runtime reflection: the generator owns DI registration, MCP tool registration, and capability catalogs. Use `[QylSkill]` + `[QylCapability]` attributes instead of hand-registering tools.
Applied to files:
src/qyl.contracts/Attributes/McpAttributes.cs
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to src/qyl.mcp/**/*.cs : Declare tool class with `[McpServerToolType]` and `[QylSkill(QylSkillKind.X)]`. Declare tool methods with `[QylCapability("id", Starting|FollowUp)]`. Never hand-register tools — let the generator produce `RegisterTools()`, `RegisterServices()`, `Capabilities[]`, `ToolDescriptors[]`.
Applied to files:
src/qyl.contracts/Attributes/McpAttributes.cs
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Include copyright header `// Copyright (c) 2025-2026 ancplua` at the top of .cs files (personal repo; MAF uses the Microsoft header).
Applied to files:
src/qyl.contracts/Attributes/McpAttributes.cs
📚 Learning: 2026-04-21T00:49:29.212Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: src/qyl.mcp/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:29.212Z
Learning: Applies to src/qyl.mcp/**/*.cs : Use `System.Text.Json` instead of Newtonsoft for JSON serialization in C# code
Applied to files:
src/qyl.contracts/Attributes/McpAttributes.cs
🪛 Shellcheck (0.11.0)
eng/semconv/bootstrap-weaver.sh
[info] 42-42: Double quote to prevent globbing and word splitting.
(SC2086)
🔇 Additional comments (1)
src/qyl.dashboard/src/lib/semconv.ts (1)
1-1368: No orphaned semconv exports detected after Weaver cutover.Verification confirms that while the generator did remove enum-like
*Valuesexports, all callers in the codebase have been properly updated to use individual string constants (e.g.,GEN_AI_TOOL_NAME,GEN_AI_TOOL_DESCRIPTION). No build-time failures will occur from stranded imports.
| mkdir -p "${WEAVER_DIR}" | ||
| if [ ! -x "${WEAVER_DIR}/weaver-${WEAVER_ARCH}/weaver" ]; then | ||
| echo "Downloading Weaver ${WEAVER_VERSION} (${WEAVER_ARCH})..." | ||
| curl -sL \ | ||
| "https://github.com/open-telemetry/weaver/releases/download/${WEAVER_VERSION}/weaver-${WEAVER_ARCH}.tar.xz" \ | ||
| -o "${WEAVER_DIR}/weaver.tar.xz" | ||
| tar -xf "${WEAVER_DIR}/weaver.tar.xz" -C "${WEAVER_DIR}" | ||
| rm "${WEAVER_DIR}/weaver.tar.xz" | ||
| fi | ||
|
|
||
| if [ ! -d "${UPSTREAM_DIR}" ]; then | ||
| echo "Cloning open-telemetry/semantic-conventions@${SEMCONV_TAG}..." | ||
| git clone --depth 1 --branch "${SEMCONV_TAG}" \ | ||
| https://github.com/open-telemetry/semantic-conventions.git "${UPSTREAM_DIR}" | ||
| fi |
There was a problem hiding this comment.
The version pins are comments, not cache invariants.
Both caches are reused on existence alone. If a developer already has .tools/weaver or .tools/semconv-upstream from an older WEAVER_VERSION or SEMCONV_TAG, this script silently generates against stale inputs even though the pins changed. Validate the cached binary/tag before reuse, or blow the cache away when the pins do not match.
Suggested hardening
mkdir -p "${WEAVER_DIR}"
-if [ ! -x "${WEAVER_DIR}/weaver-${WEAVER_ARCH}/weaver" ]; then
+WEAVER_BIN="${WEAVER_DIR}/weaver-${WEAVER_ARCH}/weaver"
+if [ ! -x "${WEAVER_BIN}" ] || ! "${WEAVER_BIN}" --version 2>/dev/null | grep -Fq "${WEAVER_VERSION#v}"; then
+ rm -rf "${WEAVER_DIR}/weaver-${WEAVER_ARCH}"
echo "Downloading Weaver ${WEAVER_VERSION} (${WEAVER_ARCH})..."
curl -sL \
"https://github.com/open-telemetry/weaver/releases/download/${WEAVER_VERSION}/weaver-${WEAVER_ARCH}.tar.xz" \
-o "${WEAVER_DIR}/weaver.tar.xz"
tar -xf "${WEAVER_DIR}/weaver.tar.xz" -C "${WEAVER_DIR}"
rm "${WEAVER_DIR}/weaver.tar.xz"
fi
-if [ ! -d "${UPSTREAM_DIR}" ]; then
+if [ ! -d "${UPSTREAM_DIR}/.git" ] || [ "$(git -C "${UPSTREAM_DIR}" describe --tags --exact-match 2>/dev/null || true)" != "${SEMCONV_TAG}" ]; then
+ rm -rf "${UPSTREAM_DIR}"
echo "Cloning open-telemetry/semantic-conventions@${SEMCONV_TAG}..."
git clone --depth 1 --branch "${SEMCONV_TAG}" \
https://github.com/open-telemetry/semantic-conventions.git "${UPSTREAM_DIR}"
fi🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@eng/semconv/bootstrap-weaver.sh` around lines 25 - 39, The script reuses
caches by existence only (WEAVER_DIR and UPSTREAM_DIR) which can lead to stale
artifacts when WEAVER_VERSION/WEAVER_ARCH or SEMCONV_TAG change; update the
logic to validate cache contents before reuse: for the weaver artifact
(weaver-${WEAVER_ARCH}/weaver) run a version check (or read a metadata file
written at download time) and compare the reported version/arch to
WEAVER_VERSION/WEAVER_ARCH, and if they differ remove the cached WEAVER_DIR and
re-download; for the semconv upstream (UPSTREAM_DIR) verify the checked-out
commit/tag (git -C "${UPSTREAM_DIR}" rev-parse --verify
"refs/tags/${SEMCONV_TAG}" or compare current HEAD to SEMCONV_TAG) and if it
does not match remove UPSTREAM_DIR and reclone; ensure these checks reference
WEAVER_DIR, WEAVER_VERSION, WEAVER_ARCH, UPSTREAM_DIR, and SEMCONV_TAG so the
cache is invalidated when pins change.
| UNAME_S="$(uname -s)" | ||
| UNAME_M="$(uname -m)" | ||
| case "${UNAME_S}:${UNAME_M}" in | ||
| Darwin:arm64|Darwin:aarch64) WEAVER_ARCH="aarch64-apple-darwin" ;; | ||
| Darwin:x86_64) WEAVER_ARCH="x86_64-apple-darwin" ;; | ||
| Linux:x86_64) WEAVER_ARCH="x86_64-unknown-linux-gnu" ;; | ||
| *) echo "Unsupported platform: ${UNAME_S}/${UNAME_M}" >&2; exit 1 ;; | ||
| esac | ||
|
|
||
| WEAVER_BIN="${REPO_ROOT}/.tools/weaver/weaver-${WEAVER_ARCH}/weaver" | ||
| UPSTREAM_REGISTRY="${REPO_ROOT}/.tools/semconv-upstream/model" |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Resolve WEAVER_ARCH in one shared helper.
run-weaver.sh duplicates the platform matrix from bootstrap-weaver.sh. Those scripts must stay bit-for-bit aligned because they address the same .tools/weaver/weaver-${WEAVER_ARCH} cache, and this mapping already regressed once. Extract the detection into a sourced helper so bootstrap and generate cannot drift again.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@eng/semconv/run-weaver.sh` around lines 19 - 29, run-weaver.sh duplicates the
platform-to-WEAVER_ARCH mapping (the case that sets WEAVER_ARCH) already present
in bootstrap-weaver.sh, causing drift; extract the detection logic into a single
sourced helper (e.g., a script that sets WEAVER_ARCH or a function like
detect_weaver_arch) and update both run-weaver.sh and bootstrap-weaver.sh to
source/call that helper and use the resulting WEAVER_ARCH variable (or exported
value) so they both resolve the same .tools/weaver/weaver-${WEAVER_ARCH} path
consistently.
| // Copyright (c) 2025-2026 ancplua | ||
| // | ||
| // Hand-maintained OTel 1.40.0 semconv facade for qyl consumers. | ||
| // Previously generated from eng/semconv/qyl-extensions.json — migrated to | ||
| // hand-edit on 2026-04-21 during the Weaver migration. Bump semconv keys | ||
| // by hand when upstream moves; qyl-specific enum extensions live here. |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check if verification tooling exists for semconv alignment
# Look for validation scripts that check semconv constants against upstream
fd -e sh -e ps1 -e ts -e js . eng/ | xargs rg -l 'semconv.*valid|verify.*semconv|check.*1\.40'
# Check if Weaver templates include validation output
fd weaver.yaml eng/
# Check for any drift-detection automation in build targets
rg -n 'semconv.*verify|validate.*semconv' --glob '*.targets' --glob '*.props' --glob 'build.cs'Repository: Alexander-Nachtmann/qyl
Length of output: 113
🏁 Script executed:
# First, examine the weaver.yaml file to understand the current setup
cat -n eng/semconv/templates/registry/qyl/weaver.yamlRepository: Alexander-Nachtmann/qyl
Length of output: 2405
🏁 Script executed:
# Check the DbAttributes.cs file to see the actual constants being maintained
cat -n src/qyl.contracts/Attributes/DbAttributes.cs | head -130Repository: Alexander-Nachtmann/qyl
Length of output: 5160
🏁 Script executed:
# Look for any CI validation or build-time checks for semconv alignment
rg -n "semconv|DbAttributes" --glob "*.yml" --glob "*.yaml" .github/ || echo "No CI found for semconv"Repository: Alexander-Nachtmann/qyl
Length of output: 90
🏁 Script executed:
# Check if there's a build script or generator that validates the constants
find . -name "*.cs" -type f | xargs rg -l "semconv.*validate|validate.*constant" | head -10Repository: Alexander-Nachtmann/qyl
Length of output: 49
🏁 Script executed:
# Look for any references to OTel 1.40.0 or semconv version pinning
rg "1\.40\.0|semconv.*version" --glob "*.cs" --glob "*.json" --glob "*.yaml" --glob "*.props"Repository: Alexander-Nachtmann/qyl
Length of output: 5399
Add CI validation for semconv attribute constants.
Hand-maintaining semconv facades without automated drift detection creates long-term risk. The comment promises to "bump semconv keys by hand when upstream moves," but no tooling exists to detect upstream semconv versions or validate that current constants (e.g., db.system.name, gen_ai.model.name) remain aligned with OTel 1.40.0.
This pattern affects three files: DbAttributes.cs, GenAiAttributes.cs, McpAttributes.cs. While OTel semconv Stable attributes rarely break, a CI check that validates these string constants against the upstream semconv registry (either via Weaver output or a direct registry comparison) would eliminate drift risk and align with the codebase's "compile-time wiring" philosophy.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/qyl.contracts/Attributes/DbAttributes.cs` around lines 1 - 6, Add a CI
validation that compares the string constants in the hand-maintained semconv
facade classes (DbAttributes, GenAiAttributes, McpAttributes) against the
authoritative OTel semconv registry (either the Weaver-generated output or the
upstream semconv JSON) and fail the build on any mismatch; implement this by
adding a unit/integration test (e.g., SemconvValidationTests) that loads the
upstream registry artifact at runtime, enumerates the expected keys, reflects
over the constants in DbAttributes/GenAiAttributes/McpAttributes to collect
their values, and asserts set equality (reporting missing/extra keys), then wire
that test into CI as a required step so any drift breaks the pipeline.
| // Copyright (c) 2025-2026 ancplua | ||
| // | ||
| // Hand-maintained OTel 1.40.0 semconv facade for qyl consumers. | ||
| // Previously generated from eng/semconv/qyl-extensions.json — migrated to | ||
| // hand-edit on 2026-04-21 during the Weaver migration. Bump semconv keys | ||
| // by hand when upstream moves; qyl-specific enum extensions live here. |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check if verification tooling exists for semconv alignment
# Look for validation scripts that check semconv constants against upstream
fd -e sh -e ps1 -e ts -e js . eng/ | xargs rg -l 'semconv.*valid|verify.*semconv|check.*1\.40'
# Check if Weaver templates include validation output
fd weaver.yaml eng/
# Check for any drift-detection automation in build targets
rg -n 'semconv.*verify|validate.*semconv' --glob '*.targets' --glob '*.props' --glob 'build.cs'Repository: Alexander-Nachtmann/qyl
Length of output: 113
🏁 Script executed:
cat -n eng/semconv/templates/registry/qyl/weaver.yamlRepository: Alexander-Nachtmann/qyl
Length of output: 2405
🏁 Script executed:
head -50 src/qyl.contracts/Attributes/GenAiAttributes.csRepository: Alexander-Nachtmann/qyl
Length of output: 2040
🏁 Script executed:
rg -n 'semconv|Weaver|1\.40' src/qyl.contracts/Attributes/GenAiAttributes.cs -A 3Repository: Alexander-Nachtmann/qyl
Length of output: 835
🏁 Script executed:
# Check if there are any build or tooling scripts that interact with semconv
fd -type f \( -name '*.yaml' -o -name '*.yml' -o -name '*.json' \) eng/semconv/ | head -20Repository: Alexander-Nachtmann/qyl
Length of output: 237
🏁 Script executed:
# Look for documentation or comments about the maintenance process
rg -n 'hand.edit|hand.maintain|Weaver migration' src/qyl.contracts/ -B 2 -A 2Repository: Alexander-Nachtmann/qyl
Length of output: 2271
🏁 Script executed:
# Check if the weaver-generated outputs exist
find . -name "semconv.ts" -o -name "promoted-columns.g.sql" -o -name "semconv.g.tsp" 2>/dev/nullRepository: Alexander-Nachtmann/qyl
Length of output: 193
🏁 Script executed:
# Look for qyl-extensions.json
find . -name "qyl-extensions.json" 2>/dev/nullRepository: Alexander-Nachtmann/qyl
Length of output: 49
🏁 Script executed:
# Check if there's a build step invoking weaver for .cs generation
rg -n "weaver|Weaver" --glob "*.targets" --glob "*.props" --glob "*.cs" --glob "*.yml" --glob "*.yaml"Repository: Alexander-Nachtmann/qyl
Length of output: 1291
🏁 Script executed:
# Verify whether the .cs attribute files are actually generated or hand-written
# by checking if they appear in any generation/build configuration
rg -n "GenAiAttributes|McpAttributes|DbAttributes" --glob "*.targets" --glob "*.props"Repository: Alexander-Nachtmann/qyl
Length of output: 49
🏁 Script executed:
# Check the eng/semconv directory structure to understand the full pipeline
ls -la eng/semconv/Repository: Alexander-Nachtmann/qyl
Length of output: 430
🏁 Script executed:
# Check for any validation or sync documentation
rg -n "sync|validate|drift" eng/semconv/ src/qyl.contracts/Repository: Alexander-Nachtmann/qyl
Length of output: 562
🏁 Script executed:
# Check if there's a manual process documented for updating .cs files
rg -n "semconv|GenAiAttributes|McpAttributes" eng/ -A 2 -B 2 --glob "*.md" --glob "*.txt"Repository: Alexander-Nachtmann/qyl
Length of output: 49
🏁 Script executed:
# Examine the manifest to understand the overall pipeline
cat eng/semconv/registry-qyl/manifest.yamlRepository: Alexander-Nachtmann/qyl
Length of output: 1273
🏁 Script executed:
# Check BuildPipeline.cs around the weaver invocation to see if .cs generation is part of pipeline
sed -n '165,200p' eng/build/BuildPipeline.csRepository: Alexander-Nachtmann/qyl
Length of output: 1923
Add validation to detect .cs semconv drift from weaver-generated outputs.
The GenAiAttributes.cs file is intentionally decoupled from the Weaver pipeline — BuildPipeline.cs explicitly logs "Facades under src/qyl.contracts/Attributes/*.cs are hand-maintained" while Weaver validates TypeScript, SQL, and TypeSpec outputs against OTel 1.40.0. This creates undetected drift risk: when OpenTelemetry publishes a new semconv version, Weaver will catch it for .ts and .sql files, but the .cs constant values in GenAiAttributes, McpAttributes, and DbAttributes will silently diverge.
Add a CI check that compares .cs constant values against the Weaver-validated outputs (or the upstream registry directly) to catch misalignment before merge.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/qyl.contracts/Attributes/GenAiAttributes.cs` around lines 1 - 6, Add a CI
validation step that parses the constant values from the hand-maintained
attribute classes (e.g., GenAiAttributes.cs, McpAttributes.cs, DbAttributes.cs)
and compares them against the Weaver-validated outputs (or the upstream OTel
registry); implement this as a new validation routine (e.g.,
ValidateCsSemconvAlignment or CompareCsSemconvWithWeaver) invoked from the CI
pipeline (or via BuildPipeline.cs hook) that loads the Weaver-generated semconv
reference (or registry export), extracts key names/values, loads the
corresponding const string fields from the classes (GenAiAttributes,
McpAttributes, DbAttributes), and fails the job with a clear mismatch report
when any constant differs so drift is detected before merge.
| // Copyright (c) 2025-2026 ancplua | ||
| // | ||
| // Hand-maintained OTel 1.40.0 semconv facade for qyl consumers. | ||
| // Previously generated from eng/semconv/qyl-extensions.json — migrated to | ||
| // hand-edit on 2026-04-21 during the Weaver migration. Bump semconv keys | ||
| // by hand when upstream moves; qyl-specific enum extensions live here. |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check if verification tooling exists for semconv alignment
# Look for validation scripts that check semconv constants against upstream
fd -e sh -e ps1 -e ts -e js . eng/ | xargs rg -l 'semconv.*valid|verify.*semconv|check.*1\.40'
# Check if Weaver templates include validation output
fd weaver.yaml eng/
# Check for any drift-detection automation in build targets
rg -n 'semconv.*verify|validate.*semconv' --glob '*.targets' --glob '*.props' --glob 'build.cs'Repository: Alexander-Nachtmann/qyl
Length of output: 113
🏁 Script executed:
# Read the weaver.yaml file to understand Weaver configuration
cat eng/semconv/templates/registry/qyl/weaver.yamlRepository: Alexander-Nachtmann/qyl
Length of output: 1754
🏁 Script executed:
# Read the McpAttributes.cs file to see full scope and assess hand-maintenance
cat -n src/qyl.contracts/Attributes/McpAttributes.csRepository: Alexander-Nachtmann/qyl
Length of output: 4020
🏁 Script executed:
# Search for related semconv facade files mentioned in comment ("all three files")
fd -e cs . src/qyl.contracts/Attributes/ | rg -i 'semconv|otel|attributes'Repository: Alexander-Nachtmann/qyl
Length of output: 205
🏁 Script executed:
# Check git log to see when the migration happened and any related commits
git log --oneline -20 -- src/qyl.contracts/Attributes/McpAttributes.cs eng/semconv/Repository: Alexander-Nachtmann/qyl
Length of output: 147
🏁 Script executed:
# Check if Weaver is still configured to run in build pipeline
rg -l 'weaver' --glob '*.targets' --glob '*.props' --glob 'Directory.Build.*' .Repository: Alexander-Nachtmann/qyl
Length of output: 49
🏁 Script executed:
# Search for generated C# files (.g.cs) related to semconv
fd -e 'g.cs' . src/qyl.contracts/Attributes/Repository: Alexander-Nachtmann/qyl
Length of output: 49
🏁 Script executed:
# Check Weaver templates directory for C# generation templates
fd . eng/semconv/templates/ | grep -E '\.(j2|jinja|template)$'Repository: Alexander-Nachtmann/qyl
Length of output: 228
🏁 Script executed:
# Check the headers of the other two semconv facade files
head -7 src/qyl.contracts/Attributes/DbAttributes.cs
head -7 src/qyl.contracts/Attributes/GenAiAttributes.csRepository: Alexander-Nachtmann/qyl
Length of output: 716
🏁 Script executed:
# Check full git log (not just recent) to understand the migration timeline
git log --oneline --all -- src/qyl.contracts/Attributes/McpAttributes.cs | head -10Repository: Alexander-Nachtmann/qyl
Length of output: 147
🏁 Script executed:
# Check if weaver actually executes as part of build
rg -i 'weaver|semconv' Directory.Build.props Directory.Build.targets qyl.contracts.csproj 2>/dev/null || echo "Not found in build files"Repository: Alexander-Nachtmann/qyl
Length of output: 91
Hand-maintained semconv facades lack drift detection across all three files.
Migration from Weaver-generated to hand-maintained C# constants (McpAttributes.cs, DbAttributes.cs, GenAiAttributes.cs) introduces spec drift risk without mitigation. Weaver generates TypeScript/SQL/TypeSpec outputs but explicitly does NOT generate the C# facades — they are intentionally hand-maintained. The header comment promises manual updates ("Bump semconv keys by hand when upstream moves") but provides no verification mechanism, validation automation, or integration into the build pipeline to detect misalignment with OTel 1.40.0.
Add either: (1) a verification script that validates the C# constants against the upstream OTel semconv registry, integrated into CI/pre-commit hooks, or (2) restore Weaver C# template generation to eliminate manual maintenance.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/qyl.contracts/Attributes/McpAttributes.cs` around lines 1 - 6, The three
hand-maintained semconv facades (McpAttributes.cs, DbAttributes.cs,
GenAiAttributes.cs) lack automated drift detection; add a small verification
step (e.g., a script named verify-semconv or verify_semconv.sh) that fetches the
upstream OTel 1.40.0 semconv registry (JSON), parses the expected keys, and
compares them to the constants defined in
McpAttributes.cs/DbAttributes.cs/GenAiAttributes.cs, exiting non-zero on any
mismatch; wire this script into CI (a pipeline job) and optionally into a
pre-commit hook so mismatches fail the build. Alternatively, restore Weaver’s C#
template generation and replace the hand-maintained files with generated
outputs, adding that generation step to CI to keep the files in sync
automatically.
…ions.json dep Schema Drift CI failed on e0b44f3 because GenerateContracts still read eng/semconv/qyl-extensions.json, which was deleted in the Weaver cutover (d1c49a4). The JSON's only role for this generator was to supply the per-facade attribute name lists; everything else (Source, Signals, required-attrs, metrics) was already hard-coded in C#. Inlined the 40 gen_ai and 12 db attribute names as `string[]` constants at the top of ContractGenerator.cs. Dropped the LoadDomains + FindFacade + ExtractAttributes JsonDocument path (~80 LoC). GenerateContracts target in BuildPipeline.cs no longer passes an extensionsJsonPath. One less arg on the Generate() signature. Bumping semconv = edit the two attribute arrays. No JSON parsing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ted attr The suffix checks (_tokens / _count / _size / _duration / ...) ran against the dotted attribute name. That only matches when the last semconv segment has an underscore immediately before the suffix. Names like `azure.cosmosdb.request.body.size` end with a bare `size` — the `_size` check never fired, column fell through to VARCHAR. Fix: compute the column name (`.` → `_`) first, run suffix checks against the underscored form. Every attribute now has the bare suffix preceded by an underscore, so the check works uniformly across all semconv prefixes. Verified: azure_cosmosdb_request_body_size BIGINT (was VARCHAR) gen_ai_usage_input_tokens BIGINT Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…es single-source CodeRabbit #4: include_prefixes was duplicated across registry-qyl/ manifest.yaml and templates/registry/qyl/weaver.yaml. The manifest.yaml file isn't read by Weaver (Weaver uses the --registry flag directly against the upstream clone); it was pure documentation that drifted. Weaver's templates/registry/qyl/weaver.yaml is the single authoritative location for params.include_prefixes. Deleted the duplicate manifest. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eral CodeRabbit #6: the three template headers hardcoded v1.40.0 directly. Replaced with `{{ params.semconv_version }}` so bumping semconv requires one edit (weaver.yaml) instead of four (three templates + weaver.yaml). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@eng/semconv/templates/registry/qyl/semconv.g.tsp.j2`:
- Around line 73-88: The child/camel derivation logic is duplicated (the
computations that set child and camel in the templated Keys alias block and
again in the model fields), so extract that logic into a reusable Jinja macro
(e.g., a macro compute_child_and_camel(name) placed near the top of
eng/semconv/templates/registry/qyl/semconv.g.tsp.j2) that returns or sets the
pascal/camel forms; then replace the inline sets (the lines that define child
and camel used for Keys aliases and the similar block used for model fields)
with calls to this macro (referencing the existing symbols child and camel where
used by alias generation and model field generation) to ensure a single source
of truth for the conversion logic.
- Around line 138-150: The template's type-mapping conditional (uses attr.type
and sets tsp_type) currently converts primitives and arrays but silently treats
semconv template[...] types as generic "string"; update the conditional in
eng/semconv/templates/registry/qyl/semconv.g.tsp.j2 to detect values matching
the pattern "template[...]" (e.g., using a startswith or regex check on
attr.type) and map them to an appropriate tsp_type (for example preserve
"template[string]" → "template[string]" or map to a distinct type like
"template[string]"/"string_map" per project convention), or if you intend to
keep the fallback, explicitly emit a comment in the template noting that
template[...] types intentionally collapse to "string" so reviewers/readers see
the behavior; ensure references to attr.type and tsp_type in the conditional are
updated accordingly.
- Around line 13-16: The reserved keyword list in the template's reserved
variable is missing many keywords introduced by TypeSpec (so identifiers like
statemachine, macro, package, metadata, env, arg, declare, array, struct,
record, module, trait, this, self, super, keyof, with, implements, impl,
satisfies, flag, auto, partial, private, public, protected, internal, sealed,
local, async can be emitted unescaped); update the set assigned to reserved in
the semconv.g.tsp.j2 template to include these additional TypeSpec reserved
words so the safe(ident) macro will correctly backtick-escape them when used.
Ensure you modify the reserved list near the top of the file (the reserved
variable declaration) and run tests/linting to confirm generated TypeSpec is
valid.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1bfe5d54-52b4-46a4-884a-e3df4dca213d
⛔ Files ignored due to path filters (1)
core/specs/generated/semconv.g.tspis excluded by!**/generated/**and included bycore/**
📒 Files selected for processing (3)
eng/semconv/run-weaver.sheng/semconv/templates/registry/qyl/semconv.g.tsp.j2eng/semconv/templates/registry/qyl/weaver.yaml
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
eng/**
⚙️ CodeRabbit configuration file
Build and deployment infrastructure. Review for: correct MSBuild property usage, Nuke build target dependencies, Docker multi-stage build efficiency, and CI/CD pipeline correctness. Flag hardcoded paths, secrets, or platform-specific assumptions.
Files:
eng/semconv/templates/registry/qyl/weaver.yamleng/semconv/run-weaver.sheng/semconv/templates/registry/qyl/semconv.g.tsp.j2
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: src/qyl.mcp/CLAUDE.md:0-0
Timestamp: 2026-04-21T00:49:29.212Z
Learning: Applies to src/qyl.mcp/src/qyl.mcp.generators/**/*.cs : `src/qyl.mcp.generators/` must emit `QylToolManifest` with `ToolTypes[]`, `ToolDescriptors[]`, and `CreateTools()`
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.cs : Use standard OTel environment variables (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_SERVICE_NAME, ENABLE_INSTRUMENTATION) instead of qyl-invented ones. Prefer these over hardcoded config.
Applied to files:
eng/semconv/templates/registry/qyl/weaver.yaml
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: qyl emits OTel GenAI semconv 1.40 with required attributes: `gen_ai.system`, `gen_ai.request.model`, `gen_ai.response.model`, `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`, `gen_ai.operation.name`, `gen_ai.tool.call.id`, `gen_ai.tool.name`, `gen_ai.agent.name`, `gen_ai.agent.id`.
Applied to files:
eng/semconv/templates/registry/qyl/semconv.g.tsp.j2
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to **/*.g.cs : Never hand-edit *.g.cs files. Fix the generator input (TypeSpec model, attribute, routing table) instead.
Applied to files:
eng/semconv/templates/registry/qyl/semconv.g.tsp.j2
📚 Learning: 2026-04-21T00:50:26.706Z
Learnt from: CR
Repo: Alexander-Nachtmann/qyl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-21T00:50:26.706Z
Learning: Applies to core/openapi/openapi.yaml : Never hand-edit core/openapi/openapi.yaml. Fix the TypeSpec source instead.
Applied to files:
eng/semconv/templates/registry/qyl/semconv.g.tsp.j2
🔇 Additional comments (7)
eng/semconv/templates/registry/qyl/weaver.yaml (1)
79-93: Template configuration is structurally sound.The three template registrations correctly use
semconv_grouped_attributesfilter withapplication_mode: single, matching the iteration pattern in the Jinja templates. Output filenames align with the destinations inrun-weaver.sh.eng/semconv/run-weaver.sh (4)
28-35: Path definitions align with BuildPipeline.cs destinations.The
TS_DEST,SQL_DEST, andTSP_DESTvariables match the paths documented ineng/build/BuildPipeline.cs:190-193. The staging directory undereng/semconv/outkeeps generated artifacts gitignored as intended.
37-41: Prerequisite validation is adequate.The
-xcheck forWEAVER_BINand-dcheck forUPSTREAM_REGISTRYfail fast with actionable guidance pointing to the bootstrap script.
43-53: Generation and installation sequence is correct.The
rm -rfclears stale staging artifacts before generation. Theinstall -m 0644ensures consistent permissions across platforms. Themkdir -pforTSP_DESThandles the case wherecore/specs/generated/doesn't exist.
19-26: No action needed. Weaver v0.22.1 does not publish anaarch64-unknown-linux-gnubinary; the pre-built assets are limited toaarch64-apple-darwin,x86_64-apple-darwin,x86_64-unknown-linux-gnu, and Windows variants. The script correctly rejects ARM64 Linux with "Unsupported platform" and would fail at download if the proposed case were added. The platform matrix accurately reflects available binaries.> Likely an incorrect or invalid review comment.eng/semconv/templates/registry/qyl/semconv.g.tsp.j2 (2)
30-34: Namespace and imports are correctly structured.The
OTel.SemConvnamespace withTypeSpec.Httpusage is appropriate for the HTTP decorator annotations and aligns with TypeSpec conventions.
41-48: The W3C Trace Context standard requires hex digits to be lowercase only (a-f, 0-9). The ABNF grammar defines hex using HEXDIGLC, and implementations must reject traceparent headers containing non-lowercase characters (e.g., uppercase A-F). The patterns in the code are correct and compliant with the specification. No changes needed.> Likely an incorrect or invalid review comment.
| {%- set reserved = ['namespace', 'model', 'interface', 'enum', 'union', 'alias', 'scalar', 'op', 'using', 'import', 'is', 'extends', 'unknown', 'void', 'never', 'null', 'true', 'false', 'if', 'else', 'return'] -%} | ||
| {%- macro safe(ident) -%} | ||
| {%- if ident in reserved -%}`{{ ident }}`{%- else -%}{{ ident }}{%- endif -%} | ||
| {%- endmacro -%} |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
TypeSpec language reserved keywords list
💡 Result:
TypeSpec does not have a published official list of reserved keywords in its documentation. The official docs state that "All keywords are reserved identifiers in TypeSpec" and can be used when escaped with backticks (e.g., model enum {}), but do not enumerate them. From the TypeSpec compiler source (microsoft/typespec repository), a recent merged pull request (#6416, March 2025) added/reserved these keywords for future use, causing breaking changes in @typespec/compiler: statemachine, macro, package, metadata, env, arg, declare, array, struct, record, module, trait, this, self, super, keyof, with, implements, impl, satisfies, flag, auto, partial, private, public, protected, internal, sealed, local, async Core structural keywords visible across docs include: model, namespace, interface, op, enum, alias, scalar, using, import, extends, is Reserved keywords cannot be used as unescaped identifiers in declaration names, type references, or base references in member expressions. Escape with backticks to use them as identifiers.
Citations:
- 1: https://typespec.io/docs/language-basics/identifiers/
- 2: Reserve keywords microsoft/typespec#6416
- 3: https://typespec.io/docs/language-basics/identifiers
- 4: https://typespec.io/docs/language-basics/overview/
- 5: https://typespec.io/docs/language-basics/overview
- 6: https://typespec.io/docs/language-basics/models/
- 7: https://typespec.io/docs/language-basics/namespaces/
- 8: https://typespec.io/docs/language-basics/values/
Reserved words list is incomplete and drifts from current TypeSpec spec.
TypeSpec PR #6416 (merged March 2025) reserved additional keywords including: statemachine, macro, package, metadata, env, arg, declare, array, struct, record, module, trait, this, self, super, keyof, with, implements, impl, satisfies, flag, auto, partial, private, public, protected, internal, sealed, local, async. The template's reserved set lacks these keywords. While the safe() macro correctly escapes identifiers, missing reserved keywords means they will emit unescaped, producing invalid TypeSpec if such attribute names appear in semconv definitions.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@eng/semconv/templates/registry/qyl/semconv.g.tsp.j2` around lines 13 - 16,
The reserved keyword list in the template's reserved variable is missing many
keywords introduced by TypeSpec (so identifiers like statemachine, macro,
package, metadata, env, arg, declare, array, struct, record, module, trait,
this, self, super, keyof, with, implements, impl, satisfies, flag, auto,
partial, private, public, protected, internal, sealed, local, async can be
emitted unescaped); update the set assigned to reserved in the semconv.g.tsp.j2
template to include these additional TypeSpec reserved words so the safe(ident)
macro will correctly backtick-escape them when used. Ensure you modify the
reserved list near the top of the file (the reserved variable declaration) and
run tests/linting to confirm generated TypeSpec is valid.
| namespace Keys { | ||
| {% for group in ctx | sort(attribute="root_namespace") %} | ||
| {% if group.root_namespace in params.include_prefixes %} | ||
| /** {{ group.root_namespace }}.* attribute keys */ | ||
| namespace {{ group.root_namespace | pascal_case }} { | ||
| {% for attr in group.attributes | sort(attribute="name") %} | ||
| {% set child = attr.name.split('.')[1:] | join('.') | replace('.', '_') | pascal_case %} | ||
| {% set camel = child[:1] | lower ~ child[1:] %} | ||
| /** "{{ attr.name }}" */ | ||
| alias {{ safe(camel) }} = "{{ attr.name }}"; | ||
| {% endfor %} | ||
| } | ||
|
|
||
| {% endif %} | ||
| {% endfor %} | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Duplicated camelCase conversion logic.
The child/camel derivation at lines 79-80 is repeated verbatim at lines 133-134. Extract a macro to avoid drift between Keys aliases and model fields.
Proposed refactor
+{%- macro attr_camel(attr) -%}
+{%- set child = attr.name.split('.')[1:] | join('.') | replace('.', '_') | pascal_case -%}
+{{ child[:1] | lower ~ child[1:] }}
+{%- endmacro -%}
+
namespace Keys {
{% for group in ctx | sort(attribute="root_namespace") %}
{% if group.root_namespace in params.include_prefixes %}
/** {{ group.root_namespace }}.* attribute keys */
namespace {{ group.root_namespace | pascal_case }} {
{% for attr in group.attributes | sort(attribute="name") %}
-{% set child = attr.name.split('.')[1:] | join('.') | replace('.', '_') | pascal_case %}
-{% set camel = child[:1] | lower ~ child[1:] %}
/** "{{ attr.name }}" */
- alias {{ safe(camel) }} = "{{ attr.name }}";
+ alias {{ safe(attr_camel(attr)) }} = "{{ attr.name }}";
{% endfor %}Also applies to: 132-156
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@eng/semconv/templates/registry/qyl/semconv.g.tsp.j2` around lines 73 - 88,
The child/camel derivation logic is duplicated (the computations that set child
and camel in the templated Keys alias block and again in the model fields), so
extract that logic into a reusable Jinja macro (e.g., a macro
compute_child_and_camel(name) placed near the top of
eng/semconv/templates/registry/qyl/semconv.g.tsp.j2) that returns or sets the
pascal/camel forms; then replace the inline sets (the lines that define child
and camel used for Keys aliases and the similar block used for model fields)
with calls to this macro (referencing the existing symbols child and camel where
used by alias generation and model field generation) to ensure a single source
of truth for the conversion logic.
| {% elif attr.type == 'int' %} | ||
| {% set tsp_type = 'int64' %} | ||
| {% elif attr.type == 'double' %} | ||
| {% set tsp_type = 'float64' %} | ||
| {% elif attr.type == 'boolean' %} | ||
| {% set tsp_type = 'boolean' %} | ||
| {% elif attr.type == 'string[]' %} | ||
| {% set tsp_type = 'string[]' %} | ||
| {% elif attr.type == 'int[]' %} | ||
| {% set tsp_type = 'int64[]' %} | ||
| {% else %} | ||
| {% set tsp_type = 'string' %} | ||
| {% endif %} |
There was a problem hiding this comment.
Type mapping omits semconv template types.
The type switch handles primitives and arrays but doesn't account for semconv's template[type] syntax (e.g., template[string] for dynamic key patterns). These will silently fall through to string, losing type fidelity.
Proposed fix
{% elif attr.type == 'int[]' %}
{% set tsp_type = 'int64[]' %}
+{% elif attr.type is string and attr.type.startswith('template[') %}
+{# template types map to string - the template variable is metadata only #}
+{% set tsp_type = 'string' %}
{% else %}
{% set tsp_type = 'string' %}
{% endif %}Alternatively, emit a comment documenting the fallback is intentional for template types.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@eng/semconv/templates/registry/qyl/semconv.g.tsp.j2` around lines 138 - 150,
The template's type-mapping conditional (uses attr.type and sets tsp_type)
currently converts primitives and arrays but silently treats semconv
template[...] types as generic "string"; update the conditional in
eng/semconv/templates/registry/qyl/semconv.g.tsp.j2 to detect values matching
the pattern "template[...]" (e.g., using a startswith or regex check on
attr.type) and map them to an appropriate tsp_type (for example preserve
"template[string]" → "template[string]" or map to a distinct type like
"template[string]"/"string_map" per project convention), or if you intend to
keep the fallback, explicitly emit a comment in the template noting that
template[...] types intentionally collapse to "string" so reviewers/readers see
the behavior; ensure references to attr.type and tsp_type in the conditional are
updated accordingly.
…aver path CodeRabbit #9 + #12 together: - #12: SEMCONV_TAG was duplicated between bootstrap-weaver.sh (as "v1.40.0") and templates/registry/qyl/weaver.yaml (as `semconv_version: "1.40.0"`). Bumping semconv required editing both. Bootstrap now sed-extracts the version from weaver.yaml as the single source. - #9: unquoted $(${WEAVER_DIR}/weaver-${WEAVER_ARCH}/weaver --version) (SC2086) — quoted the command path. Both touch bootstrap-weaver.sh; one commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… semconv keys CodeRabbit #7 suggested the five `private const string` keys should use GenAiAttributes.*. The suggestion doesn't fit: error.type and the four exception.* keys belong to the `error.*` / `exception.*` semconv prefixes, not to the three namespaces qyl facades (gen_ai / db / mcp). Inlining is correct; upgraded the comment so the next reviewer doesn't re-litigate. Promote to ErrorAttributes / ExceptionAttributes facade in src/qyl.contracts/Attributes/ the moment a second caller appears. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… referenced The generated TypeSpec file pulled upstream semconv attribute keys into qyl's TypeSpec namespace as typed `Keys.<Domain>.<field>` aliases + per-attribute union/model declarations. main.tsp imported it, but grep across all hand-written .tsp files found exactly one hit for `Keys.` / `OTel.SemConv.` — in a comment. Zero typed references. 6953 lines of generated TypeSpec + 165 lines of Jinja template + a pipeline stage, all for a feature nobody uses. The remaining Weaver templates (semconv.ts, promoted-columns.g.sql) stay — those have live consumers. Deletes: - core/specs/generated/semconv.g.tsp (6953 LoC) - eng/semconv/templates/registry/qyl/semconv.g.tsp.j2 (165 LoC) - import line + comment block in core/specs/main.tsp - TSP stanza in run-weaver.sh + the TSP_DEST install line - TSP template entry in weaver.yaml TypeSpec compile still clean (0 errors, 18 unrelated upstream warnings). qyl.slnx build still clean (0 errors). If a consumer ever wants typed semconv identifiers in TypeSpec, the template is trivially resurrectable from git history. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rule: tests that don't import ANcpLua.Roslyn.Utilities.Testing or ANcpLua.Agents.Testing (FakeChatClient / ActivityCollector / GeneratorTestEngine / AnalyzerTest / WorkflowFixture etc.) are hand-rolled against raw xunit + fluent assertions. In a private alpha they're mostly distractions — timing-string flakes, architecture-test theatre, duplicated test infrastructure that upstream already ships. Kept (3 files / 159 LoC — all under tests/qyl.collector.tests/Instrumentation/): WithQylTelemetryEmissionTests.cs — smoke-test for the PR #141 telemetry collapse, uses FakeChatClient + ActivityCollector to assert qyl.genai spans emit with semconv 1.40 attributes GenAiInstrumentationTests.cs — pipeline-shape guards for WithQylTelemetry, uses FakeChatClient ChatClientToolInstrumentationTests.cs — tool-decorator guards Deleted (22 files / 3199 LoC + 3 entire test projects): tests/qyl.mcp.tests (5 files, timing-string flake, MCP HTTP client tests) tests/qyl.mcp.generators.tests (1 file) tests/qyl.instrumentation.generators.tests (4 files — the QYL0135/6/7 analyzer tests from PR #141's worker-agent commit; rebuild using AnalyzerTest<TAnalyzer> from Roslyn.Utilities.Testing if these rules need coverage again) tests/qyl.collector.tests (11 orphan files across Autofix / Cost / Health / Intelligence / Query / Realtime / Storage / Architecture + one stray Instrumentation test) Solution file qyl.slnx drops three test-project references. Backend build clean (0 errors), remaining 6 collector tests all pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Picks up the allocation-free fast path in EscapeCSharpString (RU #141). Generated output is byte-identical across all 895 emitted .g.cs files. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Net −22,005 LoC removed (+942 / −22,947). Zero-caller dead code deleted plus Weaver migration scaffolded on disk for a later focused session.
What's gone
Three generated files with zero callers in
src/(verified via namespace-qualified grep):src/qyl.instrumentation/Instrumentation/SemanticConventions.g.cssrc/qyl.instrumentation/Instrumentation/SemanticConventions.Utf8.g.cssrc/qyl.collector/Ingestion/OtlpAttributes.Utf8.g.csPlus ~125 LoC in
eng/semconv/generate-semconv.ts(thegenerateCSharpandgenerateCSharpUtf8functions + their callers) that emitted into those paths.What broke (and got fixed)
ActivityExceptionTelemetry.csused five class-member references fromSemanticConventions.g.cs(ErrorTypeAttributes.Type,ExceptionTypeAttributes.Type, etc.). Each is a constant semconv key on a stable OTel section. Inlined asprivate const stringat the top of the file — five lines, no runtime change.OtlpAttributes.cs(different from the.Utf8.g.csshadow) was initially deleted too and restored when the build failed: despite the misleading name, that file defines the OTLP wire-protocol record types (OtlpResourceLogs,OtlpAnyValue, etc.) consumed byOtlpConverter.cs. Architecture doc had flagged this as O-2 deletable; that call was wrong — kept for now.Weaver migration scaffold
Not yet wired into
nuke Generate. What's on disk:eng/semconv/registry-qyl/manifest.yaml— qyl's extension registry stub + include-prefix listeng/semconv/templates/registry/qyl/weaver.yaml— Weaver template config, params centralize the include-prefix listeng/semconv/templates/registry/qyl/semconv.ts.j2— proof-of-pipeline Jinja template; runs against upstream v1.40.0 and emits a TS file with the expectedexport constshape (filtering byparams.include_prefixes, verified locally against the Weaver CLI)Remaining templates (C# facades, TypeSpec, DuckDB SQL) are the follow-up work. Old
generate-semconv.tsstays as-is and keeps producing all three live outputs (TS, TSP, SQL, facades) until the Weaver template set is complete.Test plan
dotnet build qyl.slnx --tl:off— 0 errors, 13 warnings (unchanged from main)npx tsx eng/semconv/generate-semconv.ts— all three remaining outputs regenerate cleanly, facades emitweaver registry generateagainst upstream v1.40.0 + qyl/weaver.yaml producessemconv.tswith filtered namespace groups (proof of pipeline)Not in scope
Qyl.Contracts.Models.SpanRecord.cs—Qyl.Contracts.Modelsis actively imported by ~6 qyl.mcp tool files; needs a focused caller audit before deletion.ToolManifestEmitterduplication —ToolManifestAnalyzerIS consumed byServiceDefaultsSourceGenerator, not safe as a drive-by.🤖 Generated with Claude Code