feat(tcg): Telemetry Capability Graph — First-Light steps 1–2 (+ precompilation experiment lane) - #12
Conversation
…end-to-end Roslyn #83088 (merged 2026-05-20, main=5.9.0) ships the experimental two-phase pre-compilation API. SDK 10.0.301 and all stable nuget toolsets lack it; the dnceng nightly Microsoft.Net.Compilers.Toolset 5.9.0-1.26324.7 carries it (grep-verified). Isolated spike (spike/): pre-compilation phase emits a marker into the initial compilation from AdditionalTextsProvider only; standard phase binds it via GetTypeByMetadataName. Consumer app references both generated types -> green build is end-to-end proof. QYLSPIKE002 confirms cross-phase visibility; runtime prints count=1. GATE 0 PASSED. Confound noted for Phase 8 (nightly compiler vs SDK control). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eparable H2 merit) Isolated real-data ablation (experiment/contract-precompilation/, outside the slnx) of the two-phase RegisterPreCompilationSourceOutput contract. Pre-compilation phase emits qyl's 37 contract capabilities as Qyl.Generated.Contract.* symbols from the resolved-YAML projection; standard phase binds them via GetTypeByMetadataName and runs deterministic compile-time semconv inference over user DTOs (CustomerId->customer.id, +4). Reproducer asserts the result. Verdict DREAMING by the mission's own 5-way-AND GENIUS bar (only 'compile-time-only coverage' holds): generator LOGIC roughly doubles (parser + two-phase + emit->compile->bind-back + polyfill) and gains a hard dependency on the unshipped main-only RSEXPERIMENTAL007 compiler; listeners do not shrink (~95% runtime value extraction, only 3 static-semantic attrs); the contract has a single internal consumer so the API's unique power (symbols into the initial compilation / cross-generator visibility) buys qyl nothing. Decisive: every real win is SEPARABLE from the API -- H2 needs only standard-phase analysis; the maintenance win is a ~20-line Python change. The phase boundary pushed every win into the standard phase => 'pre-compilation bought nothing' trigger fired. Production code untouched; package-layout + contract-invariants verifiers re-run green. Bare nightly compiler builds core runtime 0/0 (floor not broken by the compiler itself). Full verifier suite not re-run; production generator not refactored in place (H1 is an argued projection, stated as such). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…em OUT of prod slnx) slnx-sync flagged these 4 csproj as unregistered. They MUST stay out of the production Qyl.OpenTelemetry.AutoInstrumentation.slnx: they reference the dnceng nightly feed + experimental Microsoft.Net.Compilers.Toolset that only their local nuget.config carries, so the whole-repo build/gate (root nuget.config, NU1507 single-feed-as-error) would fail to restore them and break the floor. Register them in dedicated isolated solutions instead — both build green (Spike.slnx, Experiment.slnx); production slnx unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…omposition (#83088) Reframe from the user: the DREAMING verdict scoped to today's 1->1 Qyl; the real value of RegisterPreCompilationSourceOutput is COMPOSITION (cross-generator visibility) under a future 1->N semantic-platform architecture. Built it to test the claim honestly. experiment/semantic-platform/: one producer (SemanticContractProducer) pre-comp-emits a shared [QylSemanticBinding] contract from an additional file into the initial compilation; two independent consumers (OTel keyed by semconv attribute, Logging keyed by property name) bind it via the shared compilation WITHOUT referencing the producer. Green build + divergent output = real 1->N composition. Adversarially verified (4-lens workflow): composition genuine (dual-gate, no side channels); post-init cannot read the additional file so #83088 is genuinely required; RegisterDeclarationOutput (#81395) absent from the nightly (count 0) so DTO-derived shared contracts (the headline vision) remain blocked; pre-comp may not read syntax/compilation (confirmed). Applied review fixes: top-level type scoping, incrementality + property-access caveats documented. Honest boundary: #83088 publishes ADDITIONAL-FILE-derived contracts cross-generator (built, Pattern B); DTO-inference -> N generators (Pattern C) needs unmerged #81395; user-annotation (Pattern A) needs no experimental API. Composition value is real but unshipped; 1->1 DREAMING verdict unchanged for today. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…a live Activity Upgrade the OTel consumer to emit the OrderTelemetry.Record(activity, value) shape: pure activity.SetTag from the shared semantic contract — no reflection, no IL rewrite, no profiler. Fixture now drives it against a live System.Diagnostics.Activity (ActivitySource + listener) and prints the tags actually set: customer.id/order.id/tenant.id. Telemetry compiled INTO the app. Standard-phase generation needs NO experimental API (qyl already does this via interceptors); the producer's #83088 contract only supplied the property->attribute mapping cross-generator. Isolated tree; production files untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n QylContractRegistry Productize the in-place precompilation refactor: QylAutoInstrumentationGenerator emits the implemented-signal key set as the QylContractRegistry symbol via RegisterPreCompilationSourceOutput, binds it back in the standard phase (GetTypeByMetadataName), and applies the gate in EmitInterceptors. TryGet* in-process lookups deleted from InstrumentationContract (ImplementedSignalKeys is the source). Toolchain forced to the Roslyn 5.9.0 nightly repo-wide (dnceng feed + source mapping) since the API is main-only (RSEXPERIMENTAL007) — the non-shippable cost, accepted for dogfood. Updated verify-contract-invariants.py to assert the new mechanism (RegisterPreCompilationSourceOutput / QylContractRegistry / GetTypeByMetadataName) instead of the deleted TryGet* helpers — the prior green was passing only on the deletion comment naming the methods. Validated green: SourceGenerators (0/0), core runtime, snapshot fixture; verify-generator-snapshots (interceptor output unchanged — behavior-preserving) and verify-contract-invariants both pass. Full demo/AOT/container gate not yet re-run under the nightly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…umer
Fold the semantic-platform pair into the production SourceGenerators project:
- QylSemanticContractProducer: reads *.qyl-semantic-contract.tsv, pre-comp-emits the shared
[QylSemanticBinding] attribute + attribute-decorated partials of user types into the initial
compilation (RegisterPreCompilationSourceOutput), so any generator can bind the contract.
- QylSemanticTelemetryGenerator: first consumer — binds the contract in its standard phase and
emits per-type {Type}Telemetry.Record(Activity?, value) = pure SetTag, no reflection, AOT-safe.
Both inert without a contract file, so the existing demos/packages are unaffected (verified: the
snapshot fixture generates nothing new until opted in). Fixture opts in via OrderRequest +
app.qyl-semantic-contract.tsv; 3 new verified snapshots added; verify-generator-snapshots and
verify-contract-invariants both green.
Within qyl's own assembly the producer/consumer split is redundant (a single standard-phase
generator would do); it exists to publish the contract across the generator boundary for external
consumers (the 1->N platform). Standard-phase telemetry generation itself needs no experimental API.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…orth Star First-Light step 1 of the self-describing observability substrate. - TelemetryCapabilityGraphGenerator bakes the 60-capability TCG into the core assembly as QylTelemetryCapabilityGraph.Json, gated to core (mirrors SemConvRegistryGenerator). Each capability is tagged with provenance (compile-time / runtime / control / unsupported) — the distinction a sampling consumer cannot recover. - docs/schema/telemetry-capability-graph.schema.json (JSON Schema 2020-12) + docs/TELEMETRY_CAPABILITY_GRAPH.md exchange spec (provenance vocabulary, semver/forward-compat, OTLP resource-log publication mapping, consumer patterns); validated against the emitted artifact. - AGENTS.md reframed to the self-describing-observability North Star with operational invariants preserved. Full solution build 0 warnings / 0 errors; generator-snapshots-ok. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Light step 2) Makes step 1's generated manifest consumable without an OTel SDK dependency and without emitting new runtime telemetry (no OTLP-fixture risk) — the 'queryable surface' channel. - QylTelemetryCapabilityGraph public static accessor: Json / SchemaVersion / CapabilityCount. - Generator now emits SchemaVersion + CapabilityCount consts; generated holder renamed to Internal.QylTelemetryCapabilityGraphData (the public type takes the QylTelemetryCapabilityGraph name). - PublicAPI.Unshipped baseline updated; AGENTS.md + exchange spec status synced to steps 1-2 shipped. public-api-baseline-ok; generator-snapshots-ok; full solution build 0 warnings / 0 errors. 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 (4)
📜 Recent review details⏰ Context from checks skipped due to timeout. (1)
🧰 Additional context used📓 Path-based instructions (5)**⚙️ CodeRabbit configuration file
Files:
⚙️ CodeRabbit configuration file
Files:
src/Qyl.OpenTelemetry.AutoInstrumentation/**📄 CodeRabbit inference engine (AGENTS.md)
Files:
src/**/*.cs⚙️ CodeRabbit configuration file
Files:
AGENTS.md📄 CodeRabbit inference engine (CLAUDE.md)
Files:
{AGENTS.md,CLAUDE.md}📄 CodeRabbit inference engine (AGENTS.md)
Files:
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds ChangesProduction: Telemetry Capability Graph
GATE-0 spike: RegisterPreCompilationSourceOutput two-phase proof
experiment/contract-precompilation: TSV-driven contract with compile-time semconv inference
experiment/semantic-platform: 1-producer N-consumer semantic binding demo
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 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: 15
🤖 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 `@docs/schema/telemetry-capability-graph.schema.json`:
- Around line 59-90: The schema is incorrectly using closed enums for the
Telemetry Capability Graph fields, which breaks the open-ended contract and
same-major compatibility. Update the `signal`, `lane`, `status`,
`payloadAccess`, and `provenance` properties in
`telemetry-capability-graph.schema.json` to allow additional future values
instead of hard-coding fixed `enum` members, while preserving the current
documented defaults and the “unknown” mapping behavior for `provenance`. Keep
the property definitions aligned with the contract so new manifest values
validate without needing schema changes.
In `@experiment/contract-precompilation/Qyl.Contract.Consumer/Program.cs`:
- Around line 22-24: Remove the DTO instantiations from Program.Main since they
do not affect standard-phase discovery; the generator already sees all source
types through InferBindings and EnumerateSourceTypes in
ContractPreCompilationGenerator. Keep the harness focused on the precompilation
experiment by avoiding constructor-coupled runtime touches of OrderRequest and
ShipmentEvent, and leave the source types present only through their
declarations.
In
`@experiment/contract-precompilation/Qyl.Contract.Generator/ContractPreCompilationGenerator.cs`:
- Line 95: The short-row guards in ContractPreCompilationGenerator are silently
skipping malformed TSV input, which can hide corruption and produce incomplete
output. In the parsing logic around the row-length checks in the generator,
replace the bare continue behavior with diagnostic reporting that includes the
offending line number and then abort generation on malformed qyl-contract.tsv or
semantic-seeds.tsv input. Use the existing parsing flow in
ContractPreCompilationGenerator to surface a hard failure instead of letting
ContractRegistry.CapabilityCount or inferred bindings be generated from partial
data.
In
`@experiment/semantic-platform/Qyl.Consumer.Logging/LoggingConsumerGenerator.cs`:
- Around line 57-64: The Collect logic in LoggingConsumerGenerator is accepting
arbitrary Property strings and later generating value.{prop}, which can turn
invalid contract rows into compile errors. Update the binding discovery in
Collect to resolve each prop against the current type symbol first, and only add
entries for readable instance properties on type. Keep the attribute parsing and
bindings.Add flow, but filter out unresolved or non-readable properties before
generating the log scope accessors.
In `@experiment/semantic-platform/Qyl.Consumer.OTel/OTelConsumerGenerator.cs`:
- Around line 39-41: The helper class name in OTelConsumerGenerator currently
uses only the last segment of t.TypeFqn, so different types with the same leaf
name generate duplicate {simple}Telemetry classes in Qyl.Generated.OTel. Update
the naming logic in the generator to derive a unique helper name from the full
metadata name (or otherwise partition the generated namespace) before emitting
the public static class declaration, so Foo.OrderRequest and Bar.OrderRequest no
longer collide.
- Around line 66-74: `Collect` in `OTelConsumerGenerator` is accepting binding
names from the attribute payload without verifying they exist on the target
type, which can generate invalid `value.{prop}` accesses. Update the
`type.GetAttributes()` binding collection so each `prop` is resolved against
`type` as a readable instance property before adding it to `bindings`, and skip
any unresolved or non-readable properties to prevent bad generated code.
In
`@experiment/semantic-platform/Qyl.Semantic.Producer/SemanticContractProducer.cs`:
- Around line 51-52: The binding generator currently assumes every contract is a
class, so struct and record struct entries produce invalid partial declarations.
Update SemanticContractProducer.BuildPartial and related contract handling to
carry the declaration kind from the contract metadata and emit the matching
partial form, or explicitly reject non-class rows before AddSource. Use the
existing QylSemanticBindingAttribute and BuildPartial symbols to locate the
generator path and ensure the emitted source matches the contract type.
- Around line 37-39: The aggregation in SemanticContractProducer.Parse currently
uses string.Concat(texts), which can merge the last line of one
semantic-contract.tsv with the first line of the next when a trailing newline is
missing. Fix the input assembly in the Parse flow so each file’s content is
separated by a newline boundary before parsing, preserving row boundaries across
multiple files while keeping the rest of the grouping and AddSource logic
unchanged.
In `@spike/Directory.Build.props`:
- Around line 2-3: The spike-wide build policy is being blanked out by the
inheritance stop, which removes repo-wide warnings-as-errors and analyzer
settings for every child project under spike/. Restore inherited props in
Directory.Build.props so the subtree still follows the repo build floor, and
then disable only the specific analyzer/AOT/trim rules needed for the probe.
Keep the spike isolated through solution membership or per-project overrides
rather than a blanket stop, using the existing Directory.Build.props inheritance
behavior as the fix point.
In `@spike/Qyl.Spike.Generator/PreCompilationSpikeGenerator.cs`:
- Around line 27-33: The success-path diagnostic in PreCompilationSpikeGenerator
is still emitted as a warning, which violates the clean-build floor; update
CrossPhaseOk so the probe’s resolved-path reporting is not a warning. In
PreCompilationSpikeGenerator, either change the DiagnosticDescriptor severity
for QYLSPIKE002 to Info/Hidden or remove the success diagnostic emission
entirely, and make sure the reporting logic around the line that emits
QYLSPIKE002 uses the adjusted severity or no report on success.
In
`@src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylAutoInstrumentationGenerator.cs`:
- Around line 75-109: The generator in QylAutoInstrumentationGenerator is using
an experimental pre-compilation Roslyn flow in the production path, which should
not be part of the checked-in incremental generator. Remove the
RegisterPreCompilationSourceOutput / EmitContractRegistrySource registry path
from this main generator and keep that contract-registry experiment isolated
under the experiment/spike area, leaving the standard SyntaxProvider, Collect,
and RegisterSourceOutput pipeline intact in QylAutoInstrumentationGenerator.
In
`@src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticContractProducer.cs`:
- Around line 33-40: The contract aggregation in QylSemanticContractProducer
currently concatenates all TSV texts with string.Concat(texts), which can merge
the last row of one *.qyl-semantic-contract.tsv file into the first row of the
next when a file lacks a trailing newline. Update the PreCompilationSourceOutput
callback in QylSemanticContractProducer to join the collected texts with an
explicit line separator before passing the combined content to ParseContract,
preserving file boundaries and row integrity.
In
`@src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticTelemetryGenerator.cs`:
- Around line 40-61: CollectBoundTypes currently stores raw property names from
attributes and later emits them as value.{property}, so invalid or renamed
properties become broken generated code. In QylSemanticTelemetryGenerator,
resolve each captured property name against the target type symbol while
building BoundType, verify it maps to a readable instance property, and
reject/report any binding that does not resolve instead of carrying the raw
string through to emission.
- Around line 90-99: The generated helper type name in
QylSemanticTelemetryGenerator is not globally unique because it uses
bound.SimpleName inside the fixed Generated namespace, which can produce
duplicate telemetry classes for different bound types with the same simple name.
Update the name generation logic in QylSemanticTelemetryGenerator so the emitted
class name is derived from the fully qualified type name in bound.TypeFqn (using
a sanitized/encoded form) instead of bound.SimpleName, while keeping the Record
method and tag emission behavior unchanged.
In `@tools/verify-precompilation-experiment.py`:
- Around line 50-54: The skip logic in verify-precompilation-experiment.py is
too broad and can hide restore/config regressions; update the failure
classification in the build result handling to inspect both build.stdout and
build.stderr, and only return the roslyn nightly feed unreachable skip for the
actual feed-unreachable case. Tighten the regex/condition around the existing
re.search check so NU1xx and Unable to find package messages that come from
version pin or source configuration failures still fall through to the failure
path, while keeping the precompilation-experiment-skip path for genuine feed
outages.
🪄 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: 95a44c01-612f-4a4c-b731-f798387815a1
⛔ Files ignored due to path filters (4)
experiment/contract-precompilation/Qyl.Contract.Consumer/qyl-contract.tsvis excluded by!**/*.tsvexperiment/contract-precompilation/Qyl.Contract.Consumer/semantic-seeds.tsvis excluded by!**/*.tsvexperiment/semantic-platform/Qyl.Platform.Fixture/semantic-contract.tsvis excluded by!**/*.tsvtests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/Fixture/app.qyl-semantic-contract.tsvis excluded by!**/*.tsv
📒 Files selected for processing (58)
AGENTS.mdDirectory.Build.propsDirectory.Packages.propsdocs/TELEMETRY_CAPABILITY_GRAPH.mddocs/experiments/precompilation-verdict.mddocs/schema/telemetry-capability-graph.schema.jsonexperiment/contract-precompilation/Directory.Build.propsexperiment/contract-precompilation/Directory.Packages.propsexperiment/contract-precompilation/Experiment.slnxexperiment/contract-precompilation/Qyl.Contract.Consumer/Dtos.csexperiment/contract-precompilation/Qyl.Contract.Consumer/Program.csexperiment/contract-precompilation/Qyl.Contract.Consumer/Qyl.Contract.Consumer.csprojexperiment/contract-precompilation/Qyl.Contract.Generator/ContractPreCompilationGenerator.csexperiment/contract-precompilation/Qyl.Contract.Generator/Polyfills.csexperiment/contract-precompilation/Qyl.Contract.Generator/Qyl.Contract.Generator.csprojexperiment/contract-precompilation/nuget.configexperiment/semantic-platform/Directory.Build.propsexperiment/semantic-platform/Directory.Packages.propsexperiment/semantic-platform/Platform.slnxexperiment/semantic-platform/Qyl.Consumer.Logging/LoggingConsumerGenerator.csexperiment/semantic-platform/Qyl.Consumer.Logging/Polyfills.csexperiment/semantic-platform/Qyl.Consumer.Logging/Qyl.Consumer.Logging.csprojexperiment/semantic-platform/Qyl.Consumer.OTel/OTelConsumerGenerator.csexperiment/semantic-platform/Qyl.Consumer.OTel/Polyfills.csexperiment/semantic-platform/Qyl.Consumer.OTel/Qyl.Consumer.OTel.csprojexperiment/semantic-platform/Qyl.Platform.Fixture/Domain.csexperiment/semantic-platform/Qyl.Platform.Fixture/Program.csexperiment/semantic-platform/Qyl.Platform.Fixture/Qyl.Platform.Fixture.csprojexperiment/semantic-platform/Qyl.Semantic.Producer/Polyfills.csexperiment/semantic-platform/Qyl.Semantic.Producer/Qyl.Semantic.Producer.csprojexperiment/semantic-platform/Qyl.Semantic.Producer/SemanticContractProducer.csexperiment/semantic-platform/nuget.confignuget.configspike/Directory.Build.propsspike/Directory.Packages.propsspike/Qyl.Spike.Consumer/Program.csspike/Qyl.Spike.Consumer/Qyl.Spike.Consumer.csprojspike/Qyl.Spike.Consumer/spike.contract.txtspike/Qyl.Spike.Generator/PreCompilationSpikeGenerator.csspike/Qyl.Spike.Generator/Qyl.Spike.Generator.csprojspike/Spike.slnxspike/nuget.configsrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/InstrumentationContract.cssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.csprojsrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylAutoInstrumentationGenerator.cssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticContractProducer.cssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticTelemetryGenerator.cssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/TelemetryCapabilityGraphGenerator.cssrc/Qyl.OpenTelemetry.AutoInstrumentation/PublicAPI.Unshipped.txtsrc/Qyl.OpenTelemetry.AutoInstrumentation/QylTelemetryCapabilityGraph.cstests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/Fixture/OrderRequest.cstests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/Fixture/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots.Fixture.csprojtests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/QylSemanticBindingAttribute.g.verified.cstests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/QylSemanticTelemetry.g.verified.cstests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/Qyl_Snapshot_Domain_OrderRequest.SemanticContract.g.verified.cstools/verify-contract-invariants.pytools/verify-generator-snapshots.pytools/verify-precompilation-experiment.py
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: verify (qyl-linux)
⚠️ CI failures not shown inline (4)
GitHub Actions: qyl-smoketest / smoke (qyl-linux): feat(tcg): Telemetry Capability Graph — First-Light steps 1–2 (+ precompilation experiment lane)
Conclusion: failure
##[group]Run bash tools/smoketest.sh
�[36;1mbash tools/smoketest.sh�[0m
shell: /usr/bin/bash -e {0}
env:
DOTNET_ROOT: /home/ancplua/.dotnet
##[endgroup]
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:18.03
CSC : warning CS9057: Analyzer assembly '/tmp/qyl-smoke/packages/pkg/qyl.opentelemetry.autoinstrumentation/3.0.2/analyzers/dotnet/cs/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.dll' cannot be used because it references version '5.9.0.0' of the compiler, which is newer than the currently running version '5.6.0.0'. [/tmp/qyl-smoke/pkg-consumer/Consumer.csproj]
Build succeeded.
CSC : warning CS9057: Analyzer assembly '/tmp/qyl-smoke/packages/pkg/qyl.opentelemetry.autoinstrumentation/3.0.2/analyzers/dotnet/cs/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.dll' cannot be used because it references version '5.9.0.0' of the compiler, which is newer than the currently running version '5.6.0.0'. [/tmp/qyl-smoke/pkg-consumer/Consumer.csproj]
1 Warning(s)
expected one generated interceptor source in /tmp/qyl-smoke/pkg-consumer, found 0
0 Error(s)
/tmp/qyl-smoke/pkg-consumer/Generated/Microsoft.AspNetCore.App.SourceGenerators/Microsoft.AspNetCore.SourceGenerators.PublicProgramSourceGenerator/PublicTopLevelProgram.Generated.g.cs
Time Elapsed 00:00:02.66
##[error]Process completed with exit code 4.
GitHub Actions: qyl-smoketest / smoke (qyl-macos): feat(tcg): Telemetry Capability Graph — First-Light steps 1–2 (+ precompilation experiment lane)
Conclusion: failure
##[group]Run bash tools/smoketest.sh
�[36;1mbash tools/smoketest.sh�[0m
shell: /bin/bash -e {0}
env:
DOTNET_ROOT: /Users/ancplua/.dotnet
##[endgroup]
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:01.53
CSC : warning CS9057: Analyzer assembly '/var/folders/33/h4mz_z3x7ys2phgr3zm2wnq40000gn/T/qyl-smoke/packages/pkg/qyl.opentelemetry.autoinstrumentation/3.0.2/analyzers/dotnet/cs/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.dll' cannot be used because it references version '5.9.0.0' of the compiler, which is newer than the currently running version '5.6.0.0'. [/var/folders/33/h4mz_z3x7ys2phgr3zm2wnq40000gn/T/qyl-smoke/pkg-consumer/Consumer.csproj]
Build succeeded.
CSC : warning CS9057: Analyzer assembly '/var/folders/33/h4mz_z3x7ys2phgr3zm2wnq40000gn/T/qyl-smoke/packages/pkg/qyl.opentelemetry.autoinstrumentation/3.0.2/analyzers/dotnet/cs/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.dll' cannot be used because it references version '5.9.0.0' of the compiler, which is newer than the currently running version '5.6.0.0'. [/var/folders/33/h4mz_z3x7ys2phgr3zm2wnq40000gn/T/qyl-smoke/pkg-consumer/Consumer.csproj]
1 Warning(s)
0 Error(s)
Time Elapsed 00:00:02.11
expected one generated interceptor source in /var/folders/33/h4mz_z3x7ys2phgr3zm2wnq40000gn/T//qyl-smoke/pkg-consumer, found 0
/var/folders/33/h4mz_z3x7ys2phgr3zm2wnq40000gn/T//qyl-smoke/pkg-consumer/Generated/Microsoft.AspNetCore.App.SourceGenerators/Microsoft.AspNetCore.SourceGenerators.PublicProgramSourceGenerator/PublicTopLevelProgram.Generated.g.cs
##[error]Process completed with exit code 4.
GitHub Actions: qyl-smoketest / 0_smoke (qyl-macos).txt: feat(tcg): Telemetry Capability Graph — First-Light steps 1–2 (+ precompilation experiment lane)
Conclusion: failure
##[group]Run bash tools/smoketest.sh
�[36;1mbash tools/smoketest.sh�[0m
shell: /bin/bash -e {0}
env:
DOTNET_ROOT: /Users/ancplua/.dotnet
##[endgroup]
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:01.53
CSC : warning CS9057: Analyzer assembly '/var/folders/33/h4mz_z3x7ys2phgr3zm2wnq40000gn/T/qyl-smoke/packages/pkg/qyl.opentelemetry.autoinstrumentation/3.0.2/analyzers/dotnet/cs/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.dll' cannot be used because it references version '5.9.0.0' of the compiler, which is newer than the currently running version '5.6.0.0'. [/var/folders/33/h4mz_z3x7ys2phgr3zm2wnq40000gn/T/qyl-smoke/pkg-consumer/Consumer.csproj]
Build succeeded.
CSC : warning CS9057: Analyzer assembly '/var/folders/33/h4mz_z3x7ys2phgr3zm2wnq40000gn/T/qyl-smoke/packages/pkg/qyl.opentelemetry.autoinstrumentation/3.0.2/analyzers/dotnet/cs/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.dll' cannot be used because it references version '5.9.0.0' of the compiler, which is newer than the currently running version '5.6.0.0'. [/var/folders/33/h4mz_z3x7ys2phgr3zm2wnq40000gn/T/qyl-smoke/pkg-consumer/Consumer.csproj]
1 Warning(s)
0 Error(s)
Time Elapsed 00:00:02.11
expected one generated interceptor source in /var/folders/33/h4mz_z3x7ys2phgr3zm2wnq40000gn/T//qyl-smoke/pkg-consumer, found 0
/var/folders/33/h4mz_z3x7ys2phgr3zm2wnq40000gn/T//qyl-smoke/pkg-consumer/Generated/Microsoft.AspNetCore.App.SourceGenerators/Microsoft.AspNetCore.SourceGenerators.PublicProgramSourceGenerator/PublicTopLevelProgram.Generated.g.cs
##[error]Process completed with exit code 4.
GitHub Actions: qyl-smoketest / 1_smoke (qyl-linux).txt: feat(tcg): Telemetry Capability Graph — First-Light steps 1–2 (+ precompilation experiment lane)
Conclusion: failure
##[group]Run bash tools/smoketest.sh
�[36;1mbash tools/smoketest.sh�[0m
shell: /usr/bin/bash -e {0}
env:
DOTNET_ROOT: /home/ancplua/.dotnet
##[endgroup]
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:18.03
CSC : warning CS9057: Analyzer assembly '/tmp/qyl-smoke/packages/pkg/qyl.opentelemetry.autoinstrumentation/3.0.2/analyzers/dotnet/cs/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.dll' cannot be used because it references version '5.9.0.0' of the compiler, which is newer than the currently running version '5.6.0.0'. [/tmp/qyl-smoke/pkg-consumer/Consumer.csproj]
Build succeeded.
CSC : warning CS9057: Analyzer assembly '/tmp/qyl-smoke/packages/pkg/qyl.opentelemetry.autoinstrumentation/3.0.2/analyzers/dotnet/cs/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.dll' cannot be used because it references version '5.9.0.0' of the compiler, which is newer than the currently running version '5.6.0.0'. [/tmp/qyl-smoke/pkg-consumer/Consumer.csproj]
1 Warning(s)
expected one generated interceptor source in /tmp/qyl-smoke/pkg-consumer, found 0
0 Error(s)
/tmp/qyl-smoke/pkg-consumer/Generated/Microsoft.AspNetCore.App.SourceGenerators/Microsoft.AspNetCore.SourceGenerators.PublicProgramSourceGenerator/PublicTopLevelProgram.Generated.g.cs
Time Elapsed 00:00:02.66
##[error]Process completed with exit code 4.
🧰 Additional context used
📓 Path-based instructions (14)
experiment/**
📄 CodeRabbit inference engine (AGENTS.md)
Keep experimental compile-time tracing work out of the production build graph.
Files:
experiment/semantic-platform/Qyl.Consumer.Logging/Polyfills.csexperiment/semantic-platform/Qyl.Platform.Fixture/Qyl.Platform.Fixture.csprojexperiment/semantic-platform/Qyl.Platform.Fixture/Domain.csexperiment/contract-precompilation/Qyl.Contract.Generator/Polyfills.csexperiment/semantic-platform/Platform.slnxexperiment/semantic-platform/Directory.Packages.propsexperiment/semantic-platform/Qyl.Consumer.OTel/Polyfills.csexperiment/semantic-platform/Qyl.Semantic.Producer/Qyl.Semantic.Producer.csprojexperiment/contract-precompilation/Experiment.slnxexperiment/semantic-platform/Qyl.Semantic.Producer/Polyfills.csexperiment/semantic-platform/nuget.configexperiment/contract-precompilation/Directory.Build.propsexperiment/contract-precompilation/Qyl.Contract.Consumer/Dtos.csexperiment/contract-precompilation/nuget.configexperiment/semantic-platform/Qyl.Platform.Fixture/Program.csexperiment/contract-precompilation/Directory.Packages.propsexperiment/contract-precompilation/Qyl.Contract.Consumer/Qyl.Contract.Consumer.csprojexperiment/semantic-platform/Qyl.Consumer.OTel/Qyl.Consumer.OTel.csprojexperiment/semantic-platform/Qyl.Consumer.Logging/Qyl.Consumer.Logging.csprojexperiment/contract-precompilation/Qyl.Contract.Generator/Qyl.Contract.Generator.csprojexperiment/semantic-platform/Directory.Build.propsexperiment/contract-precompilation/Qyl.Contract.Consumer/Program.csexperiment/semantic-platform/Qyl.Consumer.Logging/LoggingConsumerGenerator.csexperiment/semantic-platform/Qyl.Consumer.OTel/OTelConsumerGenerator.csexperiment/semantic-platform/Qyl.Semantic.Producer/SemanticContractProducer.csexperiment/contract-precompilation/Qyl.Contract.Generator/ContractPreCompilationGenerator.cs
**
⚙️ CodeRabbit configuration file
AGENTS.md
**: # Qyl.OpenTelemetry.AutoInstrumentation agent rulesMission
This repository is the runtime AOT auto-instrumentation lane for qyl. Keep it separate from:
- semantic-convention package generation,
- the old CLR-profiler/OpenTelemetry auto-instrumentation substrate,
- unrelated compile-time tracing experiments.
The product goal is .NET 10 NativeAOT-compatible zero-code instrumentation through managed
build assets, source generation, DiagnosticListener consumption, and module-initializer boot.Clean slate before work
Before implementation work, confirm:
git worktree list git branch --show-current git diff --cached --name-only git stash list git status --shortWork from
mainunless the task explicitly asks for a topic branch, and hand the tree back as
clean as you found it — no stale local branches, stashes, staged files, or unrelated untracked
files left behind.Build and test reality
- SDK is pinned by
global.json(10.0.300,rollForward: latestFeature).- Build everything:
dotnet build Qyl.OpenTelemetry.AutoInstrumentation.slnx.TreatWarningsAsErrorsis on repo-wide with a heavy analyzer stack (trim/AOT/single-file
analyzers, ErrorProne.NET, Roslynator, PublicApiAnalyzers on packaged projects). A clean
build is the validation floor; analyzer regressions fail the build by design.- There are no
dotnet testprojects. Behavior is proven by the Python verifiers intools/
and the snapshot fixture undertests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots
(compare againstverified/). Route changes through the validation table below.- Public API changes require updating the
PublicAPI.Shipped.txt/PublicAPI.Unshipped.txt
baselines next to each packaged project (python3 tools/verify-public-api-baseline.py).- CI runs
tools/smoketest.shon pull requests and pushes tomain, plus the OTLP collector
fixture and WebAPI AOT demo workflows under.github/workflows/.- CI runs o...
Files:
experiment/semantic-platform/Qyl.Consumer.Logging/Polyfills.csspike/nuget.configexperiment/semantic-platform/Qyl.Platform.Fixture/Qyl.Platform.Fixture.csprojtests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/QylSemanticTelemetry.g.verified.csspike/Qyl.Spike.Consumer/spike.contract.txtsrc/Qyl.OpenTelemetry.AutoInstrumentation/QylTelemetryCapabilityGraph.csexperiment/semantic-platform/Qyl.Platform.Fixture/Domain.csexperiment/contract-precompilation/Qyl.Contract.Generator/Polyfills.csexperiment/semantic-platform/Platform.slnxexperiment/semantic-platform/Directory.Packages.propsexperiment/semantic-platform/Qyl.Consumer.OTel/Polyfills.csexperiment/semantic-platform/Qyl.Semantic.Producer/Qyl.Semantic.Producer.csprojexperiment/contract-precompilation/Experiment.slnxexperiment/semantic-platform/Qyl.Semantic.Producer/Polyfills.csexperiment/semantic-platform/nuget.configspike/Qyl.Spike.Generator/Qyl.Spike.Generator.csprojtests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/Fixture/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots.Fixture.csprojexperiment/contract-precompilation/Directory.Build.propssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.csprojsrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticContractProducer.csexperiment/contract-precompilation/Qyl.Contract.Consumer/Dtos.csspike/Spike.slnxspike/Directory.Packages.propsexperiment/contract-precompilation/nuget.configsrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticTelemetryGenerator.csexperiment/semantic-platform/Qyl.Platform.Fixture/Program.csexperiment/contract-precompilation/Directory.Packages.propstools/verify-generator-snapshots.pytests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/Fixture/OrderRequest.csexperiment/contract-precompilation/Qyl.Contract.Consumer/Qyl.Contract.Consumer.csprojspike/Qyl.Spike.Consumer/Program.csexperiment/semantic-platform/Qyl.Consumer.OTel/Qyl.Consumer.OTel.csprojdocs/schema/telemetry-capability-graph.schema.jsontests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/Qyl_Snapshot_Domain_OrderRequest.SemanticContract.g.verified.csexperiment/semantic-platform/Qyl.Consumer.Logging/Qyl.Consumer.Logging.csprojtests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/QylSemanticBindingAttribute.g.verified.csDirectory.Build.propsexperiment/contract-precompilation/Qyl.Contract.Generator/Qyl.Contract.Generator.csprojspike/Qyl.Spike.Consumer/Qyl.Spike.Consumer.csprojexperiment/semantic-platform/Directory.Build.propsnuget.configsrc/Qyl.OpenTelemetry.AutoInstrumentation/PublicAPI.Unshipped.txtDirectory.Packages.propstools/verify-precompilation-experiment.pyexperiment/contract-precompilation/Qyl.Contract.Consumer/Program.csspike/Directory.Build.propsexperiment/semantic-platform/Qyl.Consumer.Logging/LoggingConsumerGenerator.csexperiment/semantic-platform/Qyl.Consumer.OTel/OTelConsumerGenerator.csexperiment/semantic-platform/Qyl.Semantic.Producer/SemanticContractProducer.csspike/Qyl.Spike.Generator/PreCompilationSpikeGenerator.cstools/verify-contract-invariants.pysrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylAutoInstrumentationGenerator.csdocs/experiments/precompilation-verdict.mdsrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/TelemetryCapabilityGraphGenerator.cssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/InstrumentationContract.csdocs/TELEMETRY_CAPABILITY_GRAPH.mdAGENTS.mdexperiment/contract-precompilation/Qyl.Contract.Generator/ContractPreCompilationGenerator.cs
⚙️ 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:
experiment/semantic-platform/Qyl.Consumer.Logging/Polyfills.csspike/nuget.configexperiment/semantic-platform/Qyl.Platform.Fixture/Qyl.Platform.Fixture.csprojtests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/QylSemanticTelemetry.g.verified.csspike/Qyl.Spike.Consumer/spike.contract.txtsrc/Qyl.OpenTelemetry.AutoInstrumentation/QylTelemetryCapabilityGraph.csexperiment/semantic-platform/Qyl.Platform.Fixture/Domain.csexperiment/contract-precompilation/Qyl.Contract.Generator/Polyfills.csexperiment/semantic-platform/Platform.slnxexperiment/semantic-platform/Directory.Packages.propsexperiment/semantic-platform/Qyl.Consumer.OTel/Polyfills.csexperiment/semantic-platform/Qyl.Semantic.Producer/Qyl.Semantic.Producer.csprojexperiment/contract-precompilation/Experiment.slnxexperiment/semantic-platform/Qyl.Semantic.Producer/Polyfills.csexperiment/semantic-platform/nuget.configspike/Qyl.Spike.Generator/Qyl.Spike.Generator.csprojtests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/Fixture/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots.Fixture.csprojexperiment/contract-precompilation/Directory.Build.propssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.csprojsrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticContractProducer.csexperiment/contract-precompilation/Qyl.Contract.Consumer/Dtos.csspike/Spike.slnxspike/Directory.Packages.propsexperiment/contract-precompilation/nuget.configsrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticTelemetryGenerator.csexperiment/semantic-platform/Qyl.Platform.Fixture/Program.csexperiment/contract-precompilation/Directory.Packages.propstools/verify-generator-snapshots.pytests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/Fixture/OrderRequest.csexperiment/contract-precompilation/Qyl.Contract.Consumer/Qyl.Contract.Consumer.csprojspike/Qyl.Spike.Consumer/Program.csexperiment/semantic-platform/Qyl.Consumer.OTel/Qyl.Consumer.OTel.csprojdocs/schema/telemetry-capability-graph.schema.jsontests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/Qyl_Snapshot_Domain_OrderRequest.SemanticContract.g.verified.csexperiment/semantic-platform/Qyl.Consumer.Logging/Qyl.Consumer.Logging.csprojtests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/QylSemanticBindingAttribute.g.verified.csDirectory.Build.propsexperiment/contract-precompilation/Qyl.Contract.Generator/Qyl.Contract.Generator.csprojspike/Qyl.Spike.Consumer/Qyl.Spike.Consumer.csprojexperiment/semantic-platform/Directory.Build.propsnuget.configsrc/Qyl.OpenTelemetry.AutoInstrumentation/PublicAPI.Unshipped.txtDirectory.Packages.propstools/verify-precompilation-experiment.pyexperiment/contract-precompilation/Qyl.Contract.Consumer/Program.csspike/Directory.Build.propsexperiment/semantic-platform/Qyl.Consumer.Logging/LoggingConsumerGenerator.csexperiment/semantic-platform/Qyl.Consumer.OTel/OTelConsumerGenerator.csexperiment/semantic-platform/Qyl.Semantic.Producer/SemanticContractProducer.csspike/Qyl.Spike.Generator/PreCompilationSpikeGenerator.cstools/verify-contract-invariants.pysrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylAutoInstrumentationGenerator.csdocs/experiments/precompilation-verdict.mdsrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/TelemetryCapabilityGraphGenerator.cssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/InstrumentationContract.csdocs/TELEMETRY_CAPABILITY_GRAPH.mdAGENTS.mdexperiment/contract-precompilation/Qyl.Contract.Generator/ContractPreCompilationGenerator.cs
spike/**
📄 CodeRabbit inference engine (AGENTS.md)
Keep experimental compile-time tracing work out of the production build graph.
Files:
spike/nuget.configspike/Qyl.Spike.Consumer/spike.contract.txtspike/Qyl.Spike.Generator/Qyl.Spike.Generator.csprojspike/Spike.slnxspike/Directory.Packages.propsspike/Qyl.Spike.Consumer/Program.csspike/Qyl.Spike.Consumer/Qyl.Spike.Consumer.csprojspike/Directory.Build.propsspike/Qyl.Spike.Generator/PreCompilationSpikeGenerator.cs
**/*.csproj
📄 CodeRabbit inference engine (AGENTS.md)
Build everything under the pinned SDK, and keep repo-wide warnings-as-errors/analyzer expectations compatible with clean builds.
Files:
experiment/semantic-platform/Qyl.Platform.Fixture/Qyl.Platform.Fixture.csprojexperiment/semantic-platform/Qyl.Semantic.Producer/Qyl.Semantic.Producer.csprojspike/Qyl.Spike.Generator/Qyl.Spike.Generator.csprojtests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/Fixture/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots.Fixture.csprojsrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.csprojexperiment/contract-precompilation/Qyl.Contract.Consumer/Qyl.Contract.Consumer.csprojexperiment/semantic-platform/Qyl.Consumer.OTel/Qyl.Consumer.OTel.csprojexperiment/semantic-platform/Qyl.Consumer.Logging/Qyl.Consumer.Logging.csprojexperiment/contract-precompilation/Qyl.Contract.Generator/Qyl.Contract.Generator.csprojspike/Qyl.Spike.Consumer/Qyl.Spike.Consumer.csproj
tests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/**/verified/**
📄 CodeRabbit inference engine (AGENTS.md)
Update verified source-generator snapshots only by regenerating them from the corresponding generator inputs.
Files:
tests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/QylSemanticTelemetry.g.verified.cstests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/Qyl_Snapshot_Domain_OrderRequest.SemanticContract.g.verified.cstests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/QylSemanticBindingAttribute.g.verified.cs
tests/**
⚙️ CodeRabbit configuration file
tests/**: Deterministic only: no Task.Delay/sleep-based synchronization, no wall-clock
assertions, no external services. A test asserts observable telemetry output
(exported activities/metrics), not implementation internals. COVERAGE_LEDGER.md
must move with coverage-relevant changes.
Files:
tests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/QylSemanticTelemetry.g.verified.cstests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/Fixture/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots.Fixture.csprojtests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/Fixture/OrderRequest.cstests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/Qyl_Snapshot_Domain_OrderRequest.SemanticContract.g.verified.cstests/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.Snapshots/verified/QylSemanticBindingAttribute.g.verified.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/QylTelemetryCapabilityGraph.cssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticContractProducer.cssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticTelemetryGenerator.cssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylAutoInstrumentationGenerator.cssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/TelemetryCapabilityGraphGenerator.cssrc/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/InstrumentationContract.cs
**/*.slnx
📄 CodeRabbit inference engine (AGENTS.md)
The repository’s build graph must include the production solution, and experiments must stay out of it.
Files:
experiment/semantic-platform/Platform.slnxexperiment/contract-precompilation/Experiment.slnxspike/Spike.slnx
docs/schema/telemetry-capability-graph.schema.json
📄 CodeRabbit inference engine (AGENTS.md)
Keep the vendor-neutral Telemetry Capability Graph exchange schema current with the declared contract.
Files:
docs/schema/telemetry-capability-graph.schema.json
**/PublicAPI.Unshipped.txt
📄 CodeRabbit inference engine (AGENTS.md)
Update PublicAPI.Unshipped.txt when a packaged project’s public surface changes.
Files:
src/Qyl.OpenTelemetry.AutoInstrumentation/PublicAPI.Unshipped.txt
docs/experiments/**
📄 CodeRabbit inference engine (AGENTS.md)
Keep experimental compile-time tracing work under the docs/experiments tree and out of the main build graph.
Files:
docs/experiments/precompilation-verdict.md
src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/InstrumentationContract.cs
📄 CodeRabbit inference engine (COVERAGE_LEDGER.md)
Keep
InstrumentationContract.csaligned with the contract source of truth and the generated contract outputs.
Files:
src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/InstrumentationContract.cs
docs/TELEMETRY_CAPABILITY_GRAPH.md
📄 CodeRabbit inference engine (AGENTS.md)
Document the Telemetry Capability Graph contract and current shipped-versus-next status accurately.
Files:
docs/TELEMETRY_CAPABILITY_GRAPH.md
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 usageEdit AGENTS.md as the authoritative repository guidance file.
Files:
AGENTS.md
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-28T16:52:12.377Z
Learning: Keep this repository separate from semantic-convention package generation, the old CLR-profiler/OpenTelemetry auto-instrumentation substrate, and unrelated compile-time tracing experiments.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-28T16:52:12.377Z
Learning: Treat the Telemetry Capability Graph as a compile-time-derived, provenance-tagged contract and do not overstate future capabilities as already shipped.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-28T16:52:12.377Z
Learning: When changing the runtime state, first verify the working tree/branches/stashes and return the tree clean after the work is done.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-28T16:52:12.377Z
Learning: Keep EFCore-specific code in the EFCore package, SqlClient-specific code in the SqlClient package, hosting/bootstrap code in the Hosting package, and shared runtime helpers in the core package.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-28T16:52:12.377Z
Learning: Use only the approved instrumentation mechanisms: ordinary compiled C#, source-generated interceptors, build-transitive assets, module initializers, BCL telemetry primitives, and public diagnostic payloads; do not reintroduce profiler attach, startup hooks, runtime IL rewriting, ReJIT, plugin loading, install-style deployment, attach flows, or reflection-based dispatch.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-28T16:52:12.377Z
Learning: Missing values must stay missing; do not synthesize runtime telemetry values.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-28T16:52:12.377Z
Learning: Use the narrowest verifier that matches the changed surface, and run the whole-repo handoff gate for release or handoff work.
Learnt from: CR
Repo: ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation
Timestamp: 2026-06-28T16:52:12.377Z
Learning: Do not add a NuGet API key; publishing must stay OIDC-based and keyless.
🪛 ast-grep (0.44.0)
tools/verify-precompilation-experiment.py
[error] 39-39: Command coming from incoming request
Context: subprocess.run(args, cwd=CONSUMER, capture_output=True, text=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(subprocess-from-request)
[error] 39-39: Use of unsanitized data to create processes
Context: subprocess.run(args, cwd=CONSUMER, capture_output=True, text=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(os-system-unsanitized-data)
[warning] 64-64: Regex pattern passed to re is built from a non-literal (variable, call, concatenation, or f-string) value. If that value is attacker-controlled it can introduce a malicious pattern with catastrophic backtracking (ReDoS). Use a hardcoded literal pattern, or validate/escape untrusted input with re.escape() and bound the regex complexity before compiling.
Context: re.search(pattern, out)
Note: [CWE-1333] Inefficient Regular Expression Complexity.
(redos-non-literal-regex-python)
🪛 markdownlint-cli2 (0.22.1)
docs/experiments/precompilation-verdict.md
[warning] 17-17: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 29-29: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 41-41: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 52-52: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 52-52: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 124-124: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 134-134: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 151-151: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 199-199: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 206-206: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 206-206: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 210-210: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 213-213: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 220-220: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 229-229: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 230-230: Tables should be surrounded by blank lines
(MD058, blanks-around-tables)
[warning] 236-236: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
🔇 Additional comments (9)
nuget.config (1)
15-23: 🔒 Security & PrivacyThe wildcard does not defeat the Roslyn mapping. NuGet prefers the exact
roslyn-nightlypackage IDs overnuget.org’s*, so those packages still resolve from the nightly feed.> Likely an incorrect or invalid review comment.experiment/semantic-platform/Qyl.Consumer.Logging/Qyl.Consumer.Logging.csproj (1)
1-16: LGTM!experiment/semantic-platform/Qyl.Platform.Fixture/Domain.cs (1)
1-11: LGTM!experiment/semantic-platform/Qyl.Platform.Fixture/Program.cs (1)
1-36: LGTM!experiment/semantic-platform/Qyl.Platform.Fixture/Qyl.Platform.Fixture.csproj (1)
1-24: LGTM!experiment/semantic-platform/Platform.slnx (1)
1-10: LGTM!experiment/semantic-platform/Directory.Build.props (1)
1-5: LGTM!experiment/semantic-platform/Directory.Packages.props (1)
1-5: LGTM!experiment/semantic-platform/nuget.config (1)
1-8: LGTM!
| "signal": { | ||
| "type": "string", | ||
| "description": "OpenTelemetry signal this capability contributes to.", | ||
| "enum": ["traces", "metrics", "logs", "none"] | ||
| }, | ||
| "lane": { | ||
| "type": "string", | ||
| "description": "The qyl mechanism lane that owns this capability.", | ||
| "enum": [ | ||
| "SourceInterceptor", | ||
| "RuntimePublicTelemetry", | ||
| "FrameworkInitialization", | ||
| "OfficialLibraryHook", | ||
| "EnvironmentControl", | ||
| "InstrumentationOption", | ||
| "UnsupportedNativeAot" | ||
| ] | ||
| }, | ||
| "status": { | ||
| "type": "string", | ||
| "description": "Implementation status of the capability in the current build.", | ||
| "enum": ["Implemented", "ControlBound", "OptionBound", "ResearchRequired", "UnsupportedNativeAot"] | ||
| }, | ||
| "payloadAccess": { | ||
| "type": "string", | ||
| "description": "How the lane accesses the underlying payload: typed-public (AOT-safe), reflection-required (not AOT-safe), or not-applicable (compile-time only).", | ||
| "enum": ["TypedPublic", "ReflectionRequired", "NotApplicable"] | ||
| }, | ||
| "provenance": { | ||
| "type": "string", | ||
| "description": "The load-bearing distinction: whether the capability's attribute keys are owned at compile time, carried as runtime payload values, are a control surface (env/option), or unsupported on the AOT substrate. Consumers MUST map unknown members to 'unknown'.", | ||
| "enum": ["compile-time", "runtime", "control", "unsupported", "unknown"] |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
The schema closes enums that the contract says must stay open.
Line 62, Line 67, Line 80, Line 85, and Line 90 hard-code signal, lane, status, payloadAccess, and provenance as closed enums. That directly contradicts Line 5 and the spec’s same-major compatibility rule: the first additive member will make an otherwise compatible 0.1.x manifest fail schema validation.
Proposed fix
"signal": {
"type": "string",
- "description": "OpenTelemetry signal this capability contributes to.",
- "enum": ["traces", "metrics", "logs", "none"]
+ "description": "OpenTelemetry signal this capability contributes to. Known values today: traces, metrics, logs, none. Consumers MUST tolerate unknown members."
},
"lane": {
"type": "string",
- "description": "The qyl mechanism lane that owns this capability.",
- "enum": [
- "SourceInterceptor",
- "RuntimePublicTelemetry",
- "FrameworkInitialization",
- "OfficialLibraryHook",
- "EnvironmentControl",
- "InstrumentationOption",
- "UnsupportedNativeAot"
- ]
+ "description": "The qyl mechanism lane that owns this capability. Consumers MUST tolerate unknown members."
},
"status": {
"type": "string",
- "description": "Implementation status of the capability in the current build.",
- "enum": ["Implemented", "ControlBound", "OptionBound", "ResearchRequired", "UnsupportedNativeAot"]
+ "description": "Implementation status of the capability in the current build. Consumers MUST tolerate unknown members."
},
"payloadAccess": {
"type": "string",
- "description": "How the lane accesses the underlying payload: typed-public (AOT-safe), reflection-required (not AOT-safe), or not-applicable (compile-time only).",
- "enum": ["TypedPublic", "ReflectionRequired", "NotApplicable"]
+ "description": "How the lane accesses the underlying payload. Known values today: TypedPublic, ReflectionRequired, NotApplicable. Consumers MUST tolerate unknown members."
},
"provenance": {
"type": "string",
- "description": "The load-bearing distinction: whether the capability's attribute keys are owned at compile time, carried as runtime payload values, are a control surface (env/option), or unsupported on the AOT substrate. Consumers MUST map unknown members to 'unknown'.",
- "enum": ["compile-time", "runtime", "control", "unsupported", "unknown"]
+ "description": "The load-bearing distinction: whether the capability's attribute keys are owned at compile time, carried as runtime payload values, are a control surface (env/option), or unsupported on the AOT substrate. Consumers MUST map unknown members to 'unknown'. Known values today: compile-time, runtime, control, unsupported, unknown."
},As per coding guidelines, docs/schema/telemetry-capability-graph.schema.json: Keep the vendor-neutral Telemetry Capability Graph exchange schema current with the declared contract.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "signal": { | |
| "type": "string", | |
| "description": "OpenTelemetry signal this capability contributes to.", | |
| "enum": ["traces", "metrics", "logs", "none"] | |
| }, | |
| "lane": { | |
| "type": "string", | |
| "description": "The qyl mechanism lane that owns this capability.", | |
| "enum": [ | |
| "SourceInterceptor", | |
| "RuntimePublicTelemetry", | |
| "FrameworkInitialization", | |
| "OfficialLibraryHook", | |
| "EnvironmentControl", | |
| "InstrumentationOption", | |
| "UnsupportedNativeAot" | |
| ] | |
| }, | |
| "status": { | |
| "type": "string", | |
| "description": "Implementation status of the capability in the current build.", | |
| "enum": ["Implemented", "ControlBound", "OptionBound", "ResearchRequired", "UnsupportedNativeAot"] | |
| }, | |
| "payloadAccess": { | |
| "type": "string", | |
| "description": "How the lane accesses the underlying payload: typed-public (AOT-safe), reflection-required (not AOT-safe), or not-applicable (compile-time only).", | |
| "enum": ["TypedPublic", "ReflectionRequired", "NotApplicable"] | |
| }, | |
| "provenance": { | |
| "type": "string", | |
| "description": "The load-bearing distinction: whether the capability's attribute keys are owned at compile time, carried as runtime payload values, are a control surface (env/option), or unsupported on the AOT substrate. Consumers MUST map unknown members to 'unknown'.", | |
| "enum": ["compile-time", "runtime", "control", "unsupported", "unknown"] | |
| "signal": { | |
| "type": "string", | |
| "description": "OpenTelemetry signal this capability contributes to. Known values today: traces, metrics, logs, none. Consumers MUST tolerate unknown members." | |
| }, | |
| "lane": { | |
| "type": "string", | |
| "description": "The qyl mechanism lane that owns this capability. Consumers MUST tolerate unknown members." | |
| }, | |
| "status": { | |
| "type": "string", | |
| "description": "Implementation status of the capability in the current build. Consumers MUST tolerate unknown members." | |
| }, | |
| "payloadAccess": { | |
| "type": "string", | |
| "description": "How the lane accesses the underlying payload. Known values today: TypedPublic, ReflectionRequired, NotApplicable. Consumers MUST tolerate unknown members." | |
| }, | |
| "provenance": { | |
| "type": "string", | |
| "description": "The load-bearing distinction: whether the capability's attribute keys are owned at compile time, carried as runtime payload values, are a control surface (env/option), or unsupported on the AOT substrate. Consumers MUST map unknown members to 'unknown'. Known values today: compile-time, runtime, control, unsupported, unknown." | |
| }, |
🤖 Prompt for 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.
In `@docs/schema/telemetry-capability-graph.schema.json` around lines 59 - 90, The
schema is incorrectly using closed enums for the Telemetry Capability Graph
fields, which breaks the open-ended contract and same-major compatibility.
Update the `signal`, `lane`, `status`, `payloadAccess`, and `provenance`
properties in `telemetry-capability-graph.schema.json` to allow additional
future values instead of hard-coding fixed `enum` members, while preserving the
current documented defaults and the “unknown” mapping behavior for `provenance`.
Keep the property definitions aligned with the contract so new manifest values
validate without needing schema changes.
Source: Coding guidelines
| // Touch the DTOs so they are emitted into the compilation the standard phase inspects. | ||
| _ = new Qyl.Contract.Consumer.Contracts.OrderRequest("c", "t", "o", 0m); | ||
| _ = new Qyl.Contract.Consumer.Contracts.ShipmentEvent("o", "x", "dhl"); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Remove the DTO instantiations; they do not participate in standard-phase inference.
InferBindings/EnumerateSourceTypes in experiment/contract-precompilation/Qyl.Contract.Generator/ContractPreCompilationGenerator.cs:193-209 already walk every source type in the compilation, so Lines 22-24 do not make these DTOs visible to the generator. They only couple this harness to constructor signatures and runtime behavior that the experiment is not verifying.
Proposed fix
-// Touch the DTOs so they are emitted into the compilation the standard phase inspects.
-_ = new Qyl.Contract.Consumer.Contracts.OrderRequest("c", "t", "o", 0m);
-_ = new Qyl.Contract.Consumer.Contracts.ShipmentEvent("o", "x", "dhl");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Touch the DTOs so they are emitted into the compilation the standard phase inspects. | |
| _ = new Qyl.Contract.Consumer.Contracts.OrderRequest("c", "t", "o", 0m); | |
| _ = new Qyl.Contract.Consumer.Contracts.ShipmentEvent("o", "x", "dhl"); |
🤖 Prompt for 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.
In `@experiment/contract-precompilation/Qyl.Contract.Consumer/Program.cs` around
lines 22 - 24, Remove the DTO instantiations from Program.Main since they do not
affect standard-phase discovery; the generator already sees all source types
through InferBindings and EnumerateSourceTypes in
ContractPreCompilationGenerator. Keep the harness focused on the precompilation
experiment by avoiding constructor-coupled runtime touches of OrderRequest and
ShipmentEvent, and leave the source types present only through their
declarations.
| var line = raw.TrimEnd('\r'); | ||
| if (line.Length == 0 || line[0] == '#') continue; | ||
| var c = line.Split('\t'); | ||
| if (c.Length < 8) continue; |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Stop silently dropping malformed TSV rows.
Line 95 and Line 112 continue on short rows. A truncated qyl-contract.tsv or semantic-seeds.tsv line then becomes a smaller ContractRegistry.CapabilityCount or a missing inferred binding instead of a generator failure. Report a diagnostic with the bad line number and abort generation for malformed input.
Also applies to: 112-112
🤖 Prompt for 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.
In
`@experiment/contract-precompilation/Qyl.Contract.Generator/ContractPreCompilationGenerator.cs`
at line 95, The short-row guards in ContractPreCompilationGenerator are silently
skipping malformed TSV input, which can hide corruption and produce incomplete
output. In the parsing logic around the row-length checks in the generator,
replace the bare continue behavior with diagnostic reporting that includes the
offending line number and then abort generation on malformed qyl-contract.tsv or
semantic-seeds.tsv input. Use the existing parsing flow in
ContractPreCompilationGenerator to surface a hard failure instead of letting
ContractRegistry.CapabilityCount or inferred bindings be generated from partial
data.
| foreach (var a in type.GetAttributes()) | ||
| { | ||
| if (SymbolEqualityComparer.Default.Equals(a.AttributeClass, marker) && | ||
| a.ConstructorArguments.Length == 2 && | ||
| a.ConstructorArguments[0].Value is string prop && | ||
| a.ConstructorArguments[1].Value is string attr) | ||
| { | ||
| bindings.Add((prop, attr)); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Validate bound properties before generating log scope accessors.
Collect accepts any Property string and later emits value.{prop}. One bad contract row turns into a generated compile error instead of a rejected binding. Resolve the symbol on type first and keep only readable instance properties.
Patch
- if (SymbolEqualityComparer.Default.Equals(a.AttributeClass, marker) &&
- a.ConstructorArguments.Length == 2 &&
- a.ConstructorArguments[0].Value is string prop &&
- a.ConstructorArguments[1].Value is string attr)
+ if (SymbolEqualityComparer.Default.Equals(a.AttributeClass, marker) &&
+ a.ConstructorArguments.Length == 2 &&
+ a.ConstructorArguments[0].Value is string prop &&
+ a.ConstructorArguments[1].Value is string attr &&
+ type.GetMembers(prop).OfType<IPropertySymbol>().Any(static p => !p.IsStatic && p.GetMethod is not null))
{
bindings.Add((prop, attr));
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| foreach (var a in type.GetAttributes()) | |
| { | |
| if (SymbolEqualityComparer.Default.Equals(a.AttributeClass, marker) && | |
| a.ConstructorArguments.Length == 2 && | |
| a.ConstructorArguments[0].Value is string prop && | |
| a.ConstructorArguments[1].Value is string attr) | |
| { | |
| bindings.Add((prop, attr)); | |
| foreach (var a in type.GetAttributes()) | |
| { | |
| if (SymbolEqualityComparer.Default.Equals(a.AttributeClass, marker) && | |
| a.ConstructorArguments.Length == 2 && | |
| a.ConstructorArguments[0].Value is string prop && | |
| a.ConstructorArguments[1].Value is string attr && | |
| type.GetMembers(prop).OfType<IPropertySymbol>().Any(static p => !p.IsStatic && p.GetMethod is not null)) | |
| { | |
| bindings.Add((prop, attr)); |
🤖 Prompt for 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.
In
`@experiment/semantic-platform/Qyl.Consumer.Logging/LoggingConsumerGenerator.cs`
around lines 57 - 64, The Collect logic in LoggingConsumerGenerator is accepting
arbitrary Property strings and later generating value.{prop}, which can turn
invalid contract rows into compile errors. Update the binding discovery in
Collect to resolve each prop against the current type symbol first, and only add
entries for readable instance properties on type. Keep the attribute parsing and
bindings.Add flow, but filter out unresolved or non-readable properties before
generating the log scope accessors.
| var simple = t.TypeFqn.Substring(t.TypeFqn.LastIndexOf('.') + 1); | ||
| b.AppendLine($"/// <summary>Records OTel semantic-convention tags for <see cref=\"global::{t.TypeFqn}\"/>. Pure SetTag; no reflection.</summary>"); | ||
| b.AppendLine($"public static class {simple}Telemetry"); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Helper names collide across namespaces.
Every helper lands in Qyl.Generated.OTel, but the class name keeps only the last type segment. Foo.OrderRequest and Bar.OrderRequest both emit OrderRequestTelemetry, so the generator produces duplicate types and the build fails. Derive the helper name from the full metadata name or partition the generated namespace.
🤖 Prompt for 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.
In `@experiment/semantic-platform/Qyl.Consumer.OTel/OTelConsumerGenerator.cs`
around lines 39 - 41, The helper class name in OTelConsumerGenerator currently
uses only the last segment of t.TypeFqn, so different types with the same leaf
name generate duplicate {simple}Telemetry classes in Qyl.Generated.OTel. Update
the naming logic in the generator to derive a unique helper name from the full
metadata name (or otherwise partition the generated namespace) before emitting
the public static class declaration, so Foo.OrderRequest and Bar.OrderRequest no
longer collide.
| var contract = context.AdditionalTextsProvider | ||
| .Where(static text => text.Path.Replace('\\', '/').EndsWithIgnoreCase(ContractFileSuffix)) | ||
| .Select(static (text, cancellationToken) => text.GetText(cancellationToken)?.ToString() ?? string.Empty) | ||
| .Collect(); | ||
|
|
||
| context.RegisterPreCompilationSourceOutput(contract, static (precompilation, texts) => | ||
| { | ||
| var rows = ParseContract(string.Concat(texts)); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Preserve TSV file boundaries when combining contracts.
Line 40 uses string.Concat(texts). If one *.qyl-semantic-contract.tsv file does not end with \n, its last row is merged with the first row of the next file and the contract is parsed incorrectly. Join with an explicit line separator before calling ParseContract.
Proposed fix
- var rows = ParseContract(string.Concat(texts));
+ var rows = ParseContract(string.Join("\n", texts));📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| var contract = context.AdditionalTextsProvider | |
| .Where(static text => text.Path.Replace('\\', '/').EndsWithIgnoreCase(ContractFileSuffix)) | |
| .Select(static (text, cancellationToken) => text.GetText(cancellationToken)?.ToString() ?? string.Empty) | |
| .Collect(); | |
| context.RegisterPreCompilationSourceOutput(contract, static (precompilation, texts) => | |
| { | |
| var rows = ParseContract(string.Concat(texts)); | |
| var contract = context.AdditionalTextsProvider | |
| .Where(static text => text.Path.Replace('\\', '/').EndsWithIgnoreCase(ContractFileSuffix)) | |
| .Select(static (text, cancellationToken) => text.GetText(cancellationToken)?.ToString() ?? string.Empty) | |
| .Collect(); | |
| context.RegisterPreCompilationSourceOutput(contract, static (precompilation, texts) => | |
| { | |
| var rows = ParseContract(string.Join("\n", texts)); |
🤖 Prompt for 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.
In
`@src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticContractProducer.cs`
around lines 33 - 40, The contract aggregation in QylSemanticContractProducer
currently concatenates all TSV texts with string.Concat(texts), which can merge
the last row of one *.qyl-semantic-contract.tsv file into the first row of the
next when a file lacks a trailing newline. Update the PreCompilationSourceOutput
callback in QylSemanticContractProducer to join the collected texts with an
explicit line separator before passing the combined content to ParseContract,
preserving file boundaries and row integrity.
| private static List<BoundType> CollectBoundTypes(Compilation compilation, INamedTypeSymbol marker) | ||
| { | ||
| var result = new List<BoundType>(); | ||
| foreach (var type in EnumerateSourceTypes(compilation.GlobalNamespace)) | ||
| { | ||
| var bindings = new List<(string Property, string Attribute)>(); | ||
| foreach (var attribute in type.GetAttributes()) | ||
| { | ||
| if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, marker) && | ||
| attribute.GetConstructorArgument<string>(0) is { } property && | ||
| attribute.GetConstructorArgument<string>(1) is { } semanticAttribute) | ||
| { | ||
| bindings.Add((property, semanticAttribute)); | ||
| } | ||
| } | ||
|
|
||
| if (bindings.Count > 0) | ||
| { | ||
| result.Add(new BoundType( | ||
| type.ToDisplayString(), | ||
| type.Name, | ||
| bindings.OrderBy(static binding => binding.Property, StringComparer.Ordinal).ToList())); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Validate each bound property against the target type before emission.
The strings captured on Lines 49-50 are emitted verbatim as value.{property} on Line 99. A typo in app.qyl-semantic-contract.tsv or a consumer property rename produces uncompilable generated code instead of a targeted diagnostic. Resolve the property symbol in CollectBoundTypes and reject/report rows that do not map to a readable instance property.
🤖 Prompt for 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.
In
`@src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticTelemetryGenerator.cs`
around lines 40 - 61, CollectBoundTypes currently stores raw property names from
attributes and later emits them as value.{property}, so invalid or renamed
properties become broken generated code. In QylSemanticTelemetryGenerator,
resolve each captured property name against the target type symbol while
building BoundType, verify it maps to a readable instance property, and
reject/report any binding that does not resolve instead of carrying the raw
string through to emission.
| foreach (var bound in boundTypes) | ||
| { | ||
| builder.AppendLine($"/// <summary>Records OpenTelemetry semantic-convention tags for <see cref=\"global::{bound.TypeFqn}\"/>. Pure SetTag; no reflection.</summary>"); | ||
| builder.AppendLine($"internal static class {bound.SimpleName}Telemetry"); | ||
| builder.AppendLine("{"); | ||
| builder.AppendLine($" public static void Record(global::System.Diagnostics.Activity? activity, global::{bound.TypeFqn} value)"); | ||
| builder.AppendLine(" {"); | ||
| builder.AppendLine(" if (activity is null) return;"); | ||
| foreach (var (property, attribute) in bound.Bindings) | ||
| builder.AppendLine($" activity.SetTag(\"{Escape(attribute)}\", value.{property});"); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Make generated recorder type names globally unique.
Line 93 uses bound.SimpleName inside the fixed Qyl.OpenTelemetry.AutoInstrumentation.Generated namespace. Two bound types such as Foo.OrderRequest and Bar.OrderRequest will both emit OrderRequestTelemetry, causing a duplicate-type compile failure. Derive the helper name from the fully qualified type name instead of the simple name.
🤖 Prompt for 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.
In
`@src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylSemanticTelemetryGenerator.cs`
around lines 90 - 99, The generated helper type name in
QylSemanticTelemetryGenerator is not globally unique because it uses
bound.SimpleName inside the fixed Generated namespace, which can produce
duplicate telemetry classes for different bound types with the same simple name.
Update the name generation logic in QylSemanticTelemetryGenerator so the emitted
class name is derived from the fully qualified type name in bound.TypeFqn (using
a sanitized/encoded form) instead of bound.SimpleName, while keeping the Record
method and tag emission behavior unchanged.
| tail = "\n".join(build.stdout.splitlines()[-15:]) | ||
| if re.search(r"NU1\d{3}|unable to load the service index|Unable to find package", build.stdout): | ||
| print("precompilation-experiment-skip: roslyn nightly feed unreachable") | ||
| return 0 | ||
| print("precompilation-experiment-FAIL: build error\n" + tail, file=sys.stderr) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Don't mask restore/config regressions as a skip.
Line 51 matches every NU1xx and Unable to find package, so a broken version pin or bad source config exits 0 as “nightly feed unreachable”. The check also ignores build.stderr, where restore errors can land. Classify against combined stdout/stderr and only skip the actual feed-unreachable case.
🤖 Prompt for 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.
In `@tools/verify-precompilation-experiment.py` around lines 50 - 54, The skip
logic in verify-precompilation-experiment.py is too broad and can hide
restore/config regressions; update the failure classification in the build
result handling to inspect both build.stdout and build.stderr, and only return
the roslyn nightly feed unreachable skip for the actual feed-unreachable case.
Tighten the regex/condition around the existing re.search check so NU1xx and
Unable to find package messages that come from version pin or source
configuration failures still fall through to the failure path, while keeping the
precompilation-experiment-skip path for genuine feed outages.
…c TCG accessor Reverts the production precompilation-in-place rewrite that made the package unconsumable on released SDKs (CS9057: the analyzer referenced nightly Roslyn 5.9 vs the in-box SDK compiler 5.6, so the analyzer refused to load -> zero interceptors). Per docs/experiments/precompilation-verdict.md (verdict: DREAMING), the experimental RegisterPreCompilationSourceOutput stays in the isolated experiment/ + spike/ trees only. - Restore Directory.Build.props/Packages.props/nuget.config and the production generators (QylAutoInstrumentationGenerator, InstrumentationContract) to stable Roslyn 5.3.0; delete the in-production QylSemanticContractProducer / QylSemanticTelemetryGenerator and their snapshot fixtures. - Make the TCG public accessor robust: QylTelemetryCapabilityGraph is now a hand-written public partial type whose manifest body the generator fills via a 'partial' (elided if the generator has not run), matching the SemConvRegistry pattern. Fixes the cross-build-context fragility (CS0234 / RS0017) the smoketest caught. Verified: smoketest-ok (pkg + projref, managed + NativeAOT); full solution build 0/0; public-api-baseline-ok; generator-snapshots-ok; real 60-capability manifest bakes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Ferry triage of CodeRabbit's review (15 comments, reviewed against the pre-fix commit Squash-merging on a fully green CI run of the current tip
1 survivor worth a fast-follow — |
…rsion-matched validation) (#13) The schema's top-level description promised consumers tolerate unknown enum members, but the signal/lane/status/payloadAccess/provenance enums are closed — strict validation would reject a future document carrying a new enum value, contradicting the promise (CodeRabbit, #12). Reword to the model the spec (docs/TELEMETRY_CAPABILITY_GRAPH.md 'Versioning & compatibility') already documents: the enums are intentionally closed and a document is validated strictly against the schema matching its own schemaVersion; forward compatibility comes from version-matched validation plus tolerant consumer code (map unknown enum members to the catch-all, ignore unknown properties). Description text only — no structural change, so the emitted TCG validates identically. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Two verified threads landing together (the TCG docs reference the experiment lane, so they ship as one).
Shippable — Telemetry Capability Graph (TCG): First-Light steps 1–2
A qyl binary now declares its complete possible OpenTelemetry surface as a generated, provenance-tagged manifest — not discovered by sampling (North Star pillar 2).
TelemetryCapabilityGraphGeneratorbakes a 60-capability manifest into the core assembly (generatedInternal.QylTelemetryCapabilityGraphData, gated to core likeSemConvRegistryGenerator). Each capability tagged provenance = compile-time / runtime / control / unsupported — the distinction a sampling consumer can't recover (split 25 / 8 / 23 / 4).QylTelemetryCapabilityGraph.Json/.SchemaVersion/.CapabilityCount— the queryable surface, AOT-clean, no OTel SDK dependency, emits no new runtime telemetry (no OTLP-fixture risk).docs/schema/telemetry-capability-graph.schema.json(JSON Schema 2020-12) + specdocs/TELEMETRY_CAPABILITY_GRAPH.md— validated against the emitted artifact.AGENTS.mdreframed to the self-describing-observability North Star; all operational invariants preserved.Experiment lane (evidence, isolated OUT of the prod
.slnx)The precompilation experiments behind the decision, with their verdict — under
experiment/+spike/with their own isolated.slnx, never in the production build graph:RegisterPreCompilationSourceOutputproven callable end-to-end (nightly Roslyn).Verification (complete-and-verified)
dotnet build Qyl.OpenTelemetry.AutoInstrumentation.slnx→ 0 warnings / 0 errorsverify-public-api-baseline.py→public-api-baseline-okverify-generator-snapshots.py→generator-snapshots-ok🤖 Generated with Claude Code