Skip to content

refactor(generator): drop dead InterceptorTarget mirrors, un-shadow factory helpers - #15

Merged
ANcpLua merged 2 commits into
mainfrom
simplify/interceptor-generator-cleanup
Jun 29, 2026
Merged

refactor(generator): drop dead InterceptorTarget mirrors, un-shadow factory helpers#15
ANcpLua merged 2 commits into
mainfrom
simplify/interceptor-generator-cleanup

Conversation

@ANcpLua

@ANcpLua ANcpLua commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Summary — complete and verified

Code-quality cleanup of the auto-instrumentation source generator (invoked via /simplify). The generator's output is byte-identical — every change is internal to the generator, so the emitted interceptors are unchanged.

What changed

  • Removed two dead InterceptorTarget fieldsMatcherReceiverTypePattern and MatcherContractKeys were mirrored from the matcher descriptor in TryGetInvocation but never read anywhere (the ReSharper "positional property is never accessed" smell). Drops two fields of per-call-site state.
  • Un-shadowed the factory helpers — renamed the outer-class Parameters()BuildParameters() and ContractKeys()BuildContractKeys() so they no longer collide with the same-named data properties InterceptorTarget.Parameters / InterceptorMatcherDescriptor.ContractKeys ("member hides method from outer class"). Factory verbs now read as factories; the data properties keep their canonical names.
  • Unified one inconsistent call formEmitDirectLoggerInterceptor now uses the location.GetInterceptsLocationAttributeSyntax() extension form already used by EmitAttributeAndSignature (identical output).
  • Carries a whitespace / in-modifier / switch-expression normalization pass over the same files.

Investigated and deliberately NOT changed

The prompt asked whether EmitInterceptsLocationAttribute (the file sealed class InterceptsLocationAttribute polyfill) is redundant given GetInterceptsLocationAttributeSyntax. It is not — proven empirically:

// net10.0 probe — bare reference to the type:
var t = typeof(System.Runtime.CompilerServices.InterceptsLocationAttribute);
// → error CS0234: 'InterceptsLocationAttribute' does not exist in 'System.Runtime.CompilerServices'

InterceptsLocationAttribute is not in the .NET 10 BCL, so the generated interceptors still need the type declared in the consumer. GetInterceptsLocationAttributeSyntax() emits only the attribute usage ([InterceptsLocationAttribute(1, "data")]), not its declaration. The two are complementary; the polyfill stays.

Verification

  • dotnet build Qyl.OpenTelemetry.AutoInstrumentation.slnx0 warnings, 0 errors (TreatWarningsAsErrors + full analyzer stack; full consumer compile against the generated interceptors confirms the polyfill is correctly retained).
  • python3 tools/verify-generator-snapshots.pygenerator-snapshots-ok
  • python3 tools/verify-source-interceptor-consumer.pysource-interceptor-consumer-ok

No public API surface changed (all touched members are private/internal).

🤖 Generated with Claude Code

…actory helpers

Targeted simplifications to the auto-instrumentation source generator. Generated
output is byte-identical (generator-snapshots-ok, source-interceptor-consumer-ok;
full slnx build green at 0 warnings).

- Remove InterceptorTarget.MatcherReceiverTypePattern and MatcherContractKeys:
  both were mirrored from the matcher descriptor in TryGetInvocation but never
  read anywhere (ReSharper "positional property is never accessed"). Drops two
  fields of per-call-site state.
- Rename the outer-class factory helpers Parameters() -> BuildParameters() and
  ContractKeys() -> BuildContractKeys() so they no longer shadow the same-named
  InterceptorTarget.Parameters / InterceptorMatcherDescriptor.ContractKeys data
  properties ("member hides method from outer class").
- Unify EmitDirectLoggerInterceptor onto the
  location.GetInterceptsLocationAttributeSyntax() extension form already used by
  EmitAttributeAndSignature.

EmitInterceptsLocationAttribute (the `file sealed class InterceptsLocationAttribute`
polyfill) is intentionally KEPT, not deleted: System.Runtime.CompilerServices.
InterceptsLocationAttribute is NOT in the .NET 10 BCL (a bare reference fails
CS0234), so the generated interceptors still need the type declared in the
consumer. It is distinct from GetInterceptsLocationAttributeSyntax(), which emits
only the attribute *usage*, not its declaration.

Also carries a whitespace / `in`-modifier / switch-expression normalization pass
over the same files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e91c9eed-a2ba-4617-87e2-5ef6f3ee1065

📥 Commits

Reviewing files that changed from the base of the PR and between 81331cf and 82c40bc.

📒 Files selected for processing (1)
  • tools/verify-contract-invariants.py
📜 Recent review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: smoke (qyl-linux)
  • GitHub Check: smoke (qyl-macos)
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

AGENTS.md

**: # Qyl.OpenTelemetry.AutoInstrumentation agent rules

Mission

This repository is the runtime AOT auto-instrumentation lane for qyl, evolving into a
self-describing observability substrate. The foundation is unchanged: .NET 10
NativeAOT-compatible zero-code instrumentation through managed build assets, source generation,
DiagnosticListener consumption, and module-initializer boot. The direction is the North Star
below.

Keep this repository separate from:

  • semantic-convention package generation (Qyl.OpenTelemetry.SemanticConventions is a referenced
    vocabulary package, not generated here),
  • the old CLR-profiler/OpenTelemetry auto-instrumentation substrate.

North Star — declare and prove the whole stack

Every observability tool today is pull-by-observation: a backend learns what a service emits
by receiving samples over time, and never knows whether it has seen the whole surface. qyl has a
capability none of them have — because instrumentation is source-generated interceptors + a static
contract + a referenced semconv registry + (incrementally) DTO inference, the complete set of
telemetry a binary can ever produce is a compile-time-derivable fact, with provenance.

The substrate goal: every qyl binary ships a complete, machine-readable Telemetry Capability
Graph (TCG)
— the full possible OpenTelemetry surface for that exact binary, each capability
tagged compile-time-owned vs runtime-valued — and proves it by self-hosting (instrumenting its
own pipeline with its own mechanism, zero extra code). Any external entity consumes the TCG to know
the entire stack before a span is sampled. The contract becomes the shared semantic graph; an OTLP
backend is just one consumer.

Three pillars:

  1. Self-host (the proof). qyl instruments qyl with qyl — QylSelfTelemetry /
    SemConvConformanceProcessor are the seed; the binary observing itself is how "declared TCG ==
    runtime reality" is checked.
  2. **Compile-time-complete ...

Files:

  • tools/verify-contract-invariants.py

⚙️ CodeRabbit configuration file

**: Operating principles (solo-dev, agentic SDLC — reviews are advisory, agents act on them):

  1. 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.
  2. 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.)
  3. 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:

  • tools/verify-contract-invariants.py
🔇 Additional comments (1)
tools/verify-contract-invariants.py (1)

710-710: LGTM!

Also applies to: 1553-1560, 1713-1713, 1831-1833


📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Enhanced auto-generation of interception targets with more consistent use of optimized parameter and contract-key builders across integrations.
    • Improved generated behavior for tracing, including related enrichment and activity handling.
  • Bug Fixes

    • Corrected matcher/target contract-key generation consistency for several common instrumentations.
    • Improved generated source formatting, including more reliable string escaping and type-name normalization.
  • Refactor

    • Streamlined generator internals to pass data by reference where appropriate, keeping emitted output consistent.
  • Tests

    • Updated invariant verification to match the new generated method signatures.

Walkthrough

The generator now uses BuildParameters and BuildContractKeys throughout shape detection, descriptor construction, emission, and verification. InterceptorTarget drops matcher-specific fields, and multiple helper and emission signatures now pass targets and descriptors by in.

Changes

Readonly target passing and helper updates

Layer / File(s) Summary
Shape helpers and target contract changes
src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylAutoInstrumentationGenerator.Shapes.cs, src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylAutoInstrumentationGenerator.Descriptors.cs
Parameter and contract-key builders were renamed, shape detection call sites were updated, and InterceptorTarget lost matcher-specific fields while keeping matcher family and method shape.
Invocation detectors and matcher descriptors
src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylAutoInstrumentationGenerator.Detection.cs, src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylGeneratedSourceInterceptorCatalog.cs, src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylAutoInstrumentationGenerator.Descriptors.cs
Invocation detectors now build parameters and additional contract keys through the new helpers, and generated matcher descriptors use BuildContractKeys for the listed contracts.
Pipeline and validation passing
src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylAutoInstrumentationGenerator.cs
TryCreateInterceptedInvocation, matcher declaration checks, emission selection, and descriptor validation now use in parameters through the generator pipeline.
Trace and interceptor emission
src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylAutoInstrumentationGenerator.cs, src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/QylAutoInstrumentationGenerator.Descriptors.cs
Trace emission, HTTP web request, database, gRPC, stream-reader, GraphQL, and logger emission paths now pass in target or in descriptor into helper calls and generated output helpers.
Verifier token updates
tools/verify-contract-invariants.py
The contract invariant verifier expects the updated in-parameter call signatures for delegation, descriptor validation, target coverage, and generator API checks.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change set: internal generator refactoring to remove mirrored fields and rename helper methods.
Description check ✅ Passed The description is directly about the generator refactor and matches the implemented cleanup and verification steps.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch simplify/interceptor-generator-cleanup
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch simplify/interceptor-generator-cleanup

Comment @coderabbitai help to get the list of available commands.

…ariants guard

The carried whitespace/`in`-modifier pass changed the generator's descriptor
delegation calls to pass the readonly record structs by `in` (e.g.
`descriptor.DurationMetric.AppendRecordDurationStatement(builder, in target)`,
`EnsureTargetDeclaredByMatcher(descriptor, in target)`,
`ValidateMethodShape(in descriptor)`). verify-contract-invariants.py pins these
call sites as exact-string architecture anchors and stops at the first miss, so
the `verify` leg failed on both runners.

Updated the seven affected anchors to the `in` form. The guard's assertions —
that the generator delegates emission to descriptor methods and validates
matcher-declared kinds via EnsureTargetDeclaredByMatcher — are unchanged; only
the incidental argument-passing token is tracked. Generated output is identical
(generator-snapshots-ok), so no behavior changed.

Verified: python3 tools/verify-aot-autoinstrumentation-goal.py
--no-demos --skip "smoketest,webapi aot demo,otlp collector fixtures"
-> aot-autoinstrumentation-goal-partial-ok (contract invariants + all legs green).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ANcpLua
ANcpLua merged commit 8858081 into main Jun 29, 2026
9 checks passed
@ANcpLua
ANcpLua deleted the simplify/interceptor-generator-cleanup branch June 29, 2026 23:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant