feat(tcg): publish the Telemetry Capability Graph as an OTel LogRecord (First-Light step 3) - #14
Conversation
…d (First-Light step 3)
New Qyl.OpenTelemetry.AutoInstrumentation.Publishing package — the runtime open-exchange channel
(North Star pillar 3). AddQylTelemetryCapabilityGraphPublisher() registers a hosted service that emits
the TCG once at host startup via ILogger (event qyl.telemetry_capability_graph, body = TCG JSON,
attributes qyl.tcg.schema_version + qyl.tcg.capability_count). When the app has OpenTelemetry logging +
an OTLP exporter wired, it becomes a true OTLP LogRecord; the exporter stays app-owned and the package
takes NO OpenTelemetry SDK dependency (narrow Microsoft.Extensions.{Hosting,Logging,DependencyInjection}
.Abstractions + core).
Proven end-to-end by demos/Qyl.RealTcgPublishingDemo + tools/verify-tcg-publishing-demo.py: an OTel log
processor captures a LogRecord that matches the binary's own TCG (60 capabilities, schema 0.1.0-draft).
- Publishing package + PublicAPI baselines; CPM adds Microsoft.Extensions.Hosting.Abstractions; project
and demo registered in the slnx.
- Exchange spec publication-channel 2 + AGENTS.md status updated (First-Light steps 1-3 shipped).
Verified: full solution build 0/0; tcg-publishing-demo-ok; public-api-baseline-ok; package-layout-ok;
generator-snapshots-ok.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📜 Recent review details⏰ Context from checks skipped due to timeout. (2)
🧰 Additional context used📓 Path-based instructions (3)src/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/**📄 CodeRabbit inference engine (AGENTS.md)
Files:
**⚙️ CodeRabbit configuration file
Files:
⚙️ CodeRabbit configuration file
Files:
src/**/*.cs⚙️ CodeRabbit configuration file
Files:
🧠 Learnings (1)📓 Common learnings🪛 ast-grep (0.44.0)tools/verify-tcg-publishing-demo.py[error] 19-27: Command coming from incoming request (subprocess-from-request) 🔇 Additional comments (3)
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds a publishing package that emits the telemetry capability graph as an OpenTelemetry ChangesTCG runtime publishing
🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@demos/Qyl.RealTcgPublishingDemo/Program.cs`:
- Around line 82-87: The Attribute helper in Program.cs is converting attribute
values with parameterless ToString(), which can vary by current culture. Update
the string conversion inside Attribute(LogRecord record, string key) to use
invariant formatting so values like qyl.tcg.capability_count are compared
consistently across cultures.
In
`@src/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/QylTelemetryCapabilityGraphPublishing.cs`:
- Around line 45-63: Honor the startup cancellation token in
QylTelemetryCapabilityGraphPublishing.StartAsync before logging the
qyl.telemetry_capability_graph event. Add an early cancellation check at the
start of StartAsync and return a canceled Task when the provided
CancellationToken is already canceled, so the _logger.Log call only runs for a
host that is actually starting.
In `@tools/verify-tcg-publishing-demo.py`:
- Around line 19-26: Bound the subprocess call in the verifier so `dotnet run`
cannot hang indefinitely: update the `subprocess.run` invocation in
`verify_tcg_publishing_demo.py` to use a timeout, and handle
`subprocess.TimeoutExpired` by failing the verification while surfacing any
captured stdout and stderr. Keep the behavior localized to the `completed =
subprocess.run(...)` block and make sure the timeout failure path reports enough
output to diagnose a stalled demo run.
🪄 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 Plus
Run ID: 29bf3016-15c1-4f0a-a3d2-8b5ce52c5c57
📒 Files selected for processing (11)
AGENTS.mdDirectory.Packages.propsQyl.OpenTelemetry.AutoInstrumentation.slnxdemos/Qyl.RealTcgPublishingDemo/Program.csdemos/Qyl.RealTcgPublishingDemo/Qyl.RealTcgPublishingDemo.csprojdocs/TELEMETRY_CAPABILITY_GRAPH.mdsrc/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/PublicAPI.Shipped.txtsrc/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/PublicAPI.Unshipped.txtsrc/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/Qyl.OpenTelemetry.AutoInstrumentation.Publishing.csprojsrc/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/QylTelemetryCapabilityGraphPublishing.cstools/verify-tcg-publishing-demo.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**
⚙️ CodeRabbit configuration file
AGENTS.md
**: # Coverage ledgerThis ledger tracks current AOT auto-instrumentation coverage. It is not a scorecard and not a
history diary. Use it to decide what is implemented, what is verified, and what is intentionally
outside this substrate.Architecture contract
Current substrate:
- .NET 10 managed runtime libraries,
- Roslyn source generators,
- source-visible
[InterceptsLocation]interceptors,DiagnosticListenerandActivitypayload consumption,- build/buildTransitive package assets,
[ModuleInitializer]bootstrap.Forbidden product mechanisms:
- CLR profiler attach,
- startup hooks,
- runtime IL rewriting or ReJIT,
- dynamic plugin loading,
- reflection-based instrumentation dispatch.
Contract classification
Source of truth:
docs/contracts/otel-dotnet-auto-60.upstream.yamlplusdocs/contracts/qyl-aot-ownership.yamlGenerated outputs:
docs/generated/qyl-aot-contract.resolved.yamldocs/generated/qyl-aot-contract.schema.jsonsrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/InstrumentationContract.csdocs/coverage-matrix.mdCurrent classification:
Slice Count Binding Total contract items 60 InstrumentationContract.TotalCountImplemented signal promises 33 Implemented by a declared qyl lane; source-interceptor coverage is tracked separately in the generated matrix. Unsupported NativeAOT parity/dynamic signal promises 4 Classic ASP.NET/WCF/dynamic parity items retained with explicit unsupported status. Global environment controls 7 Read by QylAutoInstrumentationOptions.Instrumentation options 16 Read by QylAutoInstrumentationOptions; raw query/statement values remain behind upstream opt-in flags.Verified behavior
Area Evidence Package layout tools/verify-package-layout.pyvalidates analyzer/build/buildTransitive assets and forbids profiler/reflection tokens in package assets.ProjectReference dogfo...
Files:
Directory.Packages.propssrc/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/PublicAPI.Shipped.txtQyl.OpenTelemetry.AutoInstrumentation.slnxsrc/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/PublicAPI.Unshipped.txtsrc/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/Qyl.OpenTelemetry.AutoInstrumentation.Publishing.csprojsrc/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/QylTelemetryCapabilityGraphPublishing.csdemos/Qyl.RealTcgPublishingDemo/Qyl.RealTcgPublishingDemo.csprojtools/verify-tcg-publishing-demo.pydemos/Qyl.RealTcgPublishingDemo/Program.csdocs/TELEMETRY_CAPABILITY_GRAPH.mdAGENTS.md
⚙️ CodeRabbit configuration file
**: Operating principles (solo-dev, agentic SDLC — reviews are advisory, agents act on them):
- LAZY: one self-contained, correct review beats ten partial ones. Every finding is
definitive — concrete evidence with file:line, a concrete fix, no "consider maybe",
no open or ambiguous questions back to the author. If you cannot decide a point
from the diff plus repo context, stay silent on it. Never cite a source, API, or
version you have not verified; an unverifiable claim is a dropped claim.- IMPATIENT: never stall a PR. There are no compatibility obligations here — internal
and dogfooding code has NO public-API contract; removing shims, breaking signatures,
and deleting dead paths are normal, desirable changes. Do not flag backward
compatibility, deprecation ceremony, or migration paths. (SemVer applies only to
commercially sold libraries — this repo has none.)- EGO: hold the bar of the best reviewer on the market — flag real correctness,
security, data-loss, and structural problems precisely; produce zero noise.
Files:
Directory.Packages.propssrc/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/PublicAPI.Shipped.txtQyl.OpenTelemetry.AutoInstrumentation.slnxsrc/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/PublicAPI.Unshipped.txtsrc/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/Qyl.OpenTelemetry.AutoInstrumentation.Publishing.csprojsrc/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/QylTelemetryCapabilityGraphPublishing.csdemos/Qyl.RealTcgPublishingDemo/Qyl.RealTcgPublishingDemo.csprojtools/verify-tcg-publishing-demo.pydemos/Qyl.RealTcgPublishingDemo/Program.csdocs/TELEMETRY_CAPABILITY_GRAPH.mdAGENTS.md
**/*.csproj
📄 CodeRabbit inference engine (AGENTS.md)
Do not hand-maintain
<Version>or<PackageVersion>in project files; the package version is CI-owned and derived from the latestv*tag.
Files:
src/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/Qyl.OpenTelemetry.AutoInstrumentation.Publishing.csprojdemos/Qyl.RealTcgPublishingDemo/Qyl.RealTcgPublishingDemo.csproj
**/*.cs
📄 CodeRabbit inference engine (AGENTS.md)
Use stable OpenTelemetry attributes with bounded values: prefer route templates over raw paths, avoid raw text in span names, redact query-string values by default, gate
db.query.textbehind the upstream flags, and keepQYL_CONFORMANCE_ENABLED=1as the conformance switch.
Files:
src/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/QylTelemetryCapabilityGraphPublishing.csdemos/Qyl.RealTcgPublishingDemo/Program.cs
src/**/*.cs
⚙️ CodeRabbit configuration file
src/**/*.cs: Zero-code instrumentation runtime: this code runs inside EVERY request of host
applications. Top priorities, in order: (1) allocations and boxing on hot paths —
flag closures, LINQ, params arrays, string concat in listener/semantic-tag code;
(2) tag cardinality — any attribute value that is unbounded (raw URLs, user input,
exception messages) explodes at scale; (3) Activity/Meter lifecycle — undisposed
listeners, leaked subscriptions, double-Start/Stop; (4) thread safety of shared
listener state. PublicAPI.Shipped/Unshipped.txt are analyzer-managed: edits must
come from the analyzer flow, and API breaks are fine (internal product, no
compatibility contract).
Files:
src/Qyl.OpenTelemetry.AutoInstrumentation.Publishing/QylTelemetryCapabilityGraphPublishing.cs
AGENTS.md
📄 CodeRabbit inference engine (CLAUDE.md)
AGENTS.md: Document agent implementations with clear descriptions of purpose, inputs, outputs, and examples in AGENTS.md
Include structured metadata (purpose, inputs, outputs, examples) for each agent implementation
Provide executable examples for each agent to demonstrate usage
Files:
AGENTS.md
{CLAUDE.md,AGENTS.md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep
CLAUDE.mdas a symlink to this file, and editAGENTS.mdonly.
Files:
AGENTS.md
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-29T09:30:00.151Z
Learning: Keep this repository separate from semantic-convention package generation, the old CLR-profiler/OpenTelemetry auto-instrumentation substrate, and unrelated compile-time tracing experiments in the `experiment/` and `spike/` trees.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-29T09:30:00.151Z
Learning: Do not reintroduce legacy substrate mechanisms into product code or package assets: CLR profiler attach, startup hooks, runtime IL rewriting, ReJIT, `AssemblyLoadContext` plugin loading, `qyl install` deployment flows, `gate.sh` attach flows, or reflection-based instrumentation dispatch.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-29T09:30:00.151Z
Learning: Runtime `DiagnosticListener` lanes must remain; missing values stay missing and must never be synthesized.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-29T09:30:00.151Z
Learning: Build the Telemetry Capability Graph and self-host telemetry only from the accepted mechanisms in this repo: ordinary compiled C#, source-generated interceptors, build-transitive assets, module-initializer activation, BCL telemetry primitives, and public diagnostic payloads.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-29T09:30:00.151Z
Learning: Keep EFCore code isolated in `Qyl.OpenTelemetry.AutoInstrumentation.EntityFrameworkCore`, SqlClient code isolated in `Qyl.OpenTelemetry.AutoInstrumentation.SqlClient`, hosting/bootstrap code isolated in `Qyl.OpenTelemetry.AutoInstrumentation.Hosting`, and shared runtime helpers in `Qyl.OpenTelemetry.AutoInstrumentation`.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-29T09:30:00.151Z
Learning: Keep README user-facing and operational, keep CHANGELOG synthetic and useful for continuation, and describe current-tree behavior rather than old PR state or ceremonial progress claims.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-29T09:30:00.151Z
Learning: Use the narrowest verifier that covers the changed surface, and route validation through the prescribed Python, `dotnet build`, or smoke-test commands for that surface.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-29T09:30:00.151Z
Learning: For file changes, commit and push the intended scope, and avoid accidental remote history rewrites.
🪛 ast-grep (0.44.0)
tools/verify-tcg-publishing-demo.py
[error] 18-25: Command coming from incoming request
Context: subprocess.run(
["dotnet", "run", "--project", str(PROJECT), "-c", "Release", "-v", "quiet"],
cwd=ROOT,
env=env,
capture_output=True,
text=True,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(subprocess-from-request)
🔇 Additional comments (4)
docs/TELEMETRY_CAPABILITY_GRAPH.md (2)
3-5: LGTM!
84-93: LGTM!AGENTS.md (2)
46-55: LGTM!
159-160: LGTM!
… invariant attribute formatting Address CodeRabbit review on #14: - verify-tcg-publishing-demo.py: bound `dotnet run` with timeout=600 and fail on TimeoutExpired with captured output — a hung run-once demo must fail fast rather than pin the shared self-hosted runner. - TelemetryCapabilityGraphPublisher.StartAsync: return Task.FromCanceled when the startup token is already canceled (IHostedService convention; internal-only, no public API change). - RealTcgPublishingDemo Attribute(): format attribute values with CultureInfo.InvariantCulture so values compared as strings are culture-stable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#37) verify-tcg-publishing-demo.py shipped with First-Light step 3 (#14) and is referenced by docs/TELEMETRY_CAPABILITY_GRAPH.md, but was never registered in the goal orchestrator's COMMANDS — a verifier that never ran anywhere. Registered as 'tcg publishing demo' next to 'webapi aot demo' (same class: container-free demo verifier, so it runs in the PR-time validation floor, not only post-merge). Verified: --only "tcg publishing demo" → tcg-publishing-demo-ok. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
First-Light step 3 — the runtime open-exchange channel (North Star pillar 3). A qyl binary can now publish its Telemetry Capability Graph as a real OpenTelemetry
LogRecordat host startup, so any OTLP backend ingests the full declared surface on boot.New package
Qyl.OpenTelemetry.AutoInstrumentation.Publishing:AddQylTelemetryCapabilityGraphPublisher()registers a hosted service that emits the TCG once at startup viaILogger— eventqyl.telemetry_capability_graph, body = TCG JSON, attributesqyl.tcg.schema_version+qyl.tcg.capability_count.LogRecord. The exporter stays app-owned and the package takes no OpenTelemetry SDK dependency (narrowMicrosoft.Extensions.{Hosting,Logging,DependencyInjection}.Abstractions+ core).Proof
demos/Qyl.RealTcgPublishingDemoattaches an OTel log processor (exactly where an OTLP exporter sits) and asserts the capturedLogRecordmatches the binary's own TCG — 60 capabilities, schema0.1.0-draft. Gated bytools/verify-tcg-publishing-demo.py.Verification
dotnet build …slnx→ 0 warnings / 0 errorsverify-tcg-publishing-demo.py→tcg-publishing-demo-okverify-public-api-baseline.py→public-api-baseline-ok(new package baseline)verify-package-layout.py→package-layout-okverify-generator-snapshots.py→generator-snapshots-okSmoketest note (honest): the package-consumer smoketest passes in a normal checkout (verified on
mainthis session), but trips adotnet pack-inside-a-/tmp-git-worktree quirk in my local build (the HostingDiagnosticListenersProjectReference fails to flow into the nuspec when packed from a worktree). This PR touches none of the core/Hosting/DiagnosticListeners consumer path, and CI checks out normally (no worktree) — so CI'ssmokelegs are the clean confirmation.🤖 Generated with Claude Code