.NET packages generated by Weaver from one semantic-convention registry. The registry is the one artifact both halves of qyl share: what an application emits and what the collector recognises are generated from it, so qyl cannot emit an attribute name its own collector does not know.
qyl owns these .NET bindings and generates them directly from the language-independent
OpenTelemetry registries, together with qyl and library-native definitions.
registry/manifest.yaml pins core and GenAI coverage;
registry/vendor/ records the verified library versions and their native
telemetry. qyl can update and publish these bindings independently of upstream .NET SDK and
automatic-instrumentation releases.
| Package | Contents |
|---|---|
Qyl.Telemetry.SemanticConventions |
The stable tier: attribute-key constants, SchemaUrl, the qyl-owned telemetry names, typed Activity setter extensions with their value-set structs, and the metric, span, event and entity definitions — plus the definition types themselves (MetricDefinition<TInstrument>, SpanDefinition<TKind>, EventDefinition, EntityDefinition, and their Stability/Deprecation/RequirementLevel/AttributeRef/AttributePhase/EntityRef companions). The agent-first API in namespace Qyl: the span starters Spans (Source, Work, DbClient, RecordFailure) and SpanNames; and the trace contract SpanRecord, StoreIdentity, the Views over them and RegistryPolicy |
Qyl.Telemetry.SemanticConventions.Incubating |
Attribute-key constants at every stability tier, the rows the stable tier does not carry for the other five kinds and their value-set structs, the incubating starters Qyl.IncubatingSpans and their views, the qyl-owned instrument names, and Mapping.AttributeMapping — the collector's normalize table |
Qyl.Telemetry.SemanticConventions.Analyzers |
Roslyn diagnostics and code fixes for semantic-convention consumers, with a generated rule catalog, a migration catalog, and editorconfig severity profiles |
Three packages ship. Qyl.Telemetry.SemanticConventions.SourceGeneration is retired: its
last published version is 8.1.0, and no later release ships it.
All three are published on nuget.org;
VersionPrefix in Directory.Build.props names the current release
line. Incubating APIs track unstable upstream conventions and may change between minor
releases.
All three packages, at whatever line nuget.org holds today (pin --version when you need one):
dotnet add package Qyl.Telemetry.SemanticConventions
dotnet add package Qyl.Telemetry.SemanticConventions.Incubating
dotnet add package Qyl.Telemetry.SemanticConventions.AnalyzersThe Analyzers package is a development dependency, so the third command writes its
PrivateAssets="all" itself. This Program.cs then compiles unchanged on net10.0 and
touches each surface once:
using System.Diagnostics;
using Qyl.Telemetry.SemanticConventions;
using Qyl.Telemetry.SemanticConventions.Activities;
using Qyl.Telemetry.SemanticConventions.Attributes.Http;
using Qyl.Telemetry.SemanticConventions.Metrics;
using Qyl.Telemetry.SemanticConventions.Names;
using Qyl.Telemetry.SemanticConventions.Incubating.Activities;
using Qyl.Telemetry.SemanticConventions.Incubating.Mapping;
// Attribute keys, the pinned schema URL, and the qyl-owned names.
Console.WriteLine(HttpAttributes.RequestMethod); // http.request.method
Console.WriteLine(SchemaUrl.Current); // https://opentelemetry.io/schemas/1.44.0
Console.WriteLine(QylTelemetryNames.Scopes.QylCollector); // Qyl.Collector
// A metric is an object, not a name constant.
var duration = HttpMetricDefinitions.HttpClientRequestDuration;
Console.WriteLine($"{duration.Name} {duration.Instrument} {duration.Unit}");
// http.client.request.duration histogram s
// The stable setter extension and its incubating sibling, on one Activity. An enum attribute
// takes its value-set struct: a member, or Custom for a value the registry does not list.
using var activity = new Activity("GET").Start();
activity.SetHttpRequestMethod(HttpRequestMethod.Get);
activity.SetHttpRequestBodySize(1234);
// A span starter on the application scope AddQyl subscribes: required attributes positional,
// conditional ones without a default, the name from the registry's chain ("write orders").
using var span = Qyl.Spans.DbClient(DbSystemName.Postgresql, collectionName: "orders",
@namespace: "shop", operationName: "write", serverPort: null);
// The collector's normalize table.
Console.WriteLine(AttributeMapping.TryGetRename("http.method", out var live) ? live : "(none)");
Console.WriteLine(AttributeMapping.IsObsoleted("db.connection_string")); // True
Console.WriteLine(AttributeMapping.NamespaceOf("qyl.session.id")); // qylBoth namespaces are in scope at once and no call is ambiguous, because the two packages are
disjoint for every kind but attributes. The program also publishes NativeAOT clean —
dotnet publish -c Release -r <rid> -p:PublishAot=true emits no trim or AOT warning, because
nothing here reflects: the keys are const string, the definitions are constructed objects,
the starters are static methods with TagList creation tags, and AttributeMapping is switch
statements over string literals.
registry/manifest.yaml is the single source of truth for the
upstream pins. It names two dependencies:
- core —
open-telemetry/semantic-conventionsat the tag itsschema_urlcarries, materialised as a local filtered copy under.build/core-filtered/modelbyscripts/fetch-core.sh. The filter removesgen-ai/,mcp/,openai/and theregistry.aws.bedrockgroup, exactly the way upstreamsemantic-conventions-genaifilters core in its own Makefile: an unfiltered core dependency collides with the genai one ongen_ai.agent.description. - genai —
open-telemetry/semantic-conventions-genai, a git URL pinned to a commit.
qyl's own YAML sits next to them under registry/. registry/qyl
carries the 17 qyl.* attributes, the two qyl-owned instruments, the two qyl-owned event
names and the six scope names. registry/vendor carries one file per
pinned third-party library: the keys that library puts on its own ActivitySource or Meter
and that upstream semantic conventions do not define. Weaver resolves all three layers
itself; there is no merge step.
Vendor keys retain their native spelling. Registry membership is not an allowlist for application
attributes; persistence follows the generated policy's explicit exclusions and capture rules.
This registry carries telemetry vocabulary only; qyl's
client-visible product requests, responses, stream events and errors are owned by
qyl-api-schema.
The Anthropic coverage notes distinguish Claude Code, Cowork,
Desktop, the Claude API/SDK and Chrome instrumentation, including beta and dynamic paths.
The browser extension audit also covers ChatGPT
1.26.1005.11759, separating its inactive tracing hooks from its Statsig product analytics.
The OpenAI reference
covers the pinned Codex runtime, ChatGPT desktop, public cloud schemas and Chrome audit.
The complete registry reference includes qyl,
vendor and resolved upstream definitions at every stability. Both are rendered directly by
Weaver 0.28.0 from templates/registry/markdown/*.j2; run
mise exec -- scripts/generate-reference.sh to regenerate them. The qyl agent-observability
profile defines development adapter obligations; the catalog does not assert deployed ingestion.
Operation IDs belong on span/event attributes. The ordinary lifecycle signals do not associate
an operation entity with the OpenTelemetry resource: that would require a new resource identity
for each operation. The standalone entity vocabulary does not impose that resource layout.
Two Rego sets, because two registry shapes answer different questions.
registry/policies runs against the plain resolved shape, the only one
that keeps group annotations: every attribute qyl declares is in qyl.*, and every vendor
group has its metadata sibling naming the library, version, repository, ref, licence and
ActivitySources, with a file-and-line note on every attribute. Weaver loads it from the
registry directory itself. registry/policies-v2 is passed
explicitly and runs against the materialized v2 registry, the only shape that carries the
full dependency catalog: qyl.attribute.namespace enumerates every root namespace plus
other, there is at least one GenAI token histogram (unit {token}) for QYL0402 to name
and exactly one unconstrained execute_tool span, and every GenAI any attribute carries a
JSON Schema annotation.
registry/.weaver.toml and
registry/policies/live_check_advice are one
judgement in two halves, and both are needed to state it. --advice-policies replaces the
rego advisors only: Weaver's deprecated, stability, type and enum advisors are compiled
into the binary, always run, and emit at a level no policy can change. .weaver.toml drops
the three findings the qyl rules replace, by finding id and never by attribute name. Run
with --advice-policies alone and each of those findings is reported twice, once at
Weaver's level and once at qyl's, and --fail-on violation fails on telemetry qyl handles
correctly.
The judgement itself is decided from the registry entry alone — there is no attribute-key list anywhere in the set:
| finding | level | why |
|---|---|---|
open_enum_value |
information | The enum carries the member _OTHER, so it is open and a value outside the member list is what the specification prescribes. error.type is the case that matters: exception type names and status codes are all undocumented values of an open enum. |
undocumented_enum_value |
information | The same on a closed enum. Weaver's default level, kept. |
deprecated_renamed |
improvement | AttributeMapping.TryGetRename rewrites the key to its final live replacement. |
deprecated_obsoleted |
improvement | AttributeMapping.IsObsoleted tells the collector to drop the key and count the drop. |
deprecated_uncategorized |
violation | The registry names no replacement and the collector has no rule. Weaver's default level, kept. |
type_coercible |
improvement | The value parses as the declared type, so the collector coerces it. |
type_not_coercible |
violation | It does not. Weaver's default level, kept. |
enum_type_invalid |
violation | An enum sample that is neither string nor int. Weaver's default level, kept. |
Everything else is Weaver's, unchanged, including missing_attribute, not_stable, the
required/recommended/opt-in findings and the four name and namespace rules that
otel.rego — Weaver's own default policy,
copied verbatim into the set — carries.
The pins are exact by design: a moving input must not change generated constants without a
commit here. scripts/check-pin-freshness.py reports when
one falls behind upstream and does not decide whether to move it; run it by hand, and
weekly.yml reports it every Monday in its job summary. The
genai pin is a branch commit, and the manifest pins that repository's model/ sub-folder
only, so the check counts a commit against the pin only when it changes a file under
model/; a lock-file or tooling commit on main leaves the pin current and is reported as
distance without staleness.
uv run scripts/check-pin-freshness.py # 0 = every pin current, 10 = a pin is behind, 2 = unknownMoving a pin is a deliberate change: edit registry/manifest.yaml, re-run
scripts/generate.sh, review the regenerated surface, and record the delta in
CHANGELOG.md.
scripts/generate.sh checks the registry against both policy sets and
then runs the same weaver registry generate --v2 --include-unreferenced for each target under
templates/registry: snapshot, csharp and typescript. There is no
compile-time generator: the output is committed, the same shape as the check-generated target in
opentelemetry-weaver-examples/basic.
The snapshot target writes the resolved registry to .build/registry.json. Its SHA-256, without
the local paths of fetched dependencies, reaches both language targets as
registry_snapshot_sha256 (C# RegistrySnapshot.Sha256, TypeScript REGISTRY_SNAPSHOT_SHA256),
and the live-check matchers are generated from the file.
registry/ (manifest.yaml: core + genai dependencies; qyl/ and vendor/ next to them)
|
v
scripts/generate.sh -> weaver registry generate --v2 --include-unreferenced <target>
|
+-- snapshot ---> .build/registry.json (the fingerprint, the live-check matchers)
+-- csharp -----> src/Qyl.Telemetry.SemanticConventions/Generated/ (stable tier)
| src/Qyl.Telemetry.SemanticConventions.Incubating/Generated/ (the other tiers)
| src/…Analyzers/SemconvRegistryFacts.g.cs, SemconvDeprecations.g.cs, SemconvTypedSurface.g.cs
| generated/pins.props (the pins, for MSBuild)
+-- typescript -> typescript/src/, typescript/dist/, typescript/package.json
A target's weaver.yaml, such as
templates/registry/csharp/weaver.yaml, declares its
files: one JQ filter shaping the registry into a context, one .j2 template rendering it. No
template parameter has a default. The three schema URLs are registry facts the filters read off
the materialized registry itself; the Weaver version, the core tag, the
core commit and the genai commit reach the templates only from Version.props and
registry/manifest.yaml, through scripts/generate.sh. A bare weaver registry generate
therefore writes error: missing param <name> into the header instead of a stale pin.
Because the resolved v2 registry flattens registry.* groups into the catalog and drops
their group annotations, scripts/generate.sh reads the two lists that live only in
annotations — the scope names qyl constructs and the vendor ActivitySource names — out of
the same YAML and hands them to the templates as parameters. The same holds for qyl's policy
over the registry, registry/qyl/policy.yaml: which keys the
collector does not persist (qyl.persisted: false, the denied-key tokens, qyl.token_exempt),
and the finite captured HTTP-header / textual RPC-metadata field-name and credential rule,
which attributes are known only when an operation ends (qyl.phase: end), and the span-name
chains and starters keyed by span refinement id (qyl.span_name, starter, domain, fixed).
scripts/generate.sh reads it into one parameter file, --params .build/generate-params.json,
which the templates receive as params.policy. After the snapshot it adds every registry enum
attribute whose key contains a denied token to token_exempt: the tokens guard free text, and an
enum attribute such as cicd.pipeline.result carries one of its registry members. registry/
stays the only source. Weaver writes
files and never deletes one, so scripts/generate.sh clears both Generated/ trees and
typescript/src and typescript/dist first.
scripts/check-generated.sh is the gate: it regenerates
everything and fails on git diff HEAD. GeneratedSurfaceTests checks that both packages
provide the required signal families. Compilation and focused contract tests validate their
behavior without a second inventory of generated-file hashes.
weaver must be the version Version.props pins — scripts/generate.sh
refuses to run against any other. mise run check runs the whole sequence; commit and push
regenerated outputs first so its drift check compares the intended commit:
uv run --no-project --with pyyaml python3 -m unittest discover --start-directory tests/scripts --pattern 'test_*.py'
./scripts/check-generated.sh
npm test --prefix typescript
./scripts/check-live-check-policies.sh
dotnet restore Qyl.Telemetry.SemanticConventions.slnx
dotnet build Qyl.Telemetry.SemanticConventions.slnx --no-restore --configuration Release
dotnet run --project tests/Qyl.Telemetry.SemanticConventions.Pipeline.Tests/ --configuration Release --no-buildThe test project is a Microsoft.Testing.Platform project: mise run check runs it with
dotnet run --project, and global.json selects the native runner, so dotnet test drives it
too.
Each package's Generated/ directory holds one file per registry root for six kinds.
| Kind | Stable package | Incubating package |
|---|---|---|
| Attributes | Attributes.{Root}.{Root}Attributes |
Incubating.Attributes.{Root}.{Root}Attributes |
| Activities | Activities.{Root}ActivityExtensions and a value-set struct per enum attribute (Activities.DbSystemName) |
Incubating.Activities.{Root}IncubatingActivityExtensions and its structs (Incubating.Activities.MessagingSystem) |
| Metrics | Metrics.{Root}MetricDefinitions |
Incubating.Metrics.{Root}IncubatingMetricDefinitions |
| Spans | Spans.{Root}SpanDefinitions |
Incubating.Spans.{Root}IncubatingSpanDefinitions |
| Events | Events.{Root}EventDefinitions |
Incubating.Events.{Root}IncubatingEventDefinitions |
| Entities | Entities.{Root}EntityDefinitions |
Incubating.Entities.{Root}IncubatingEntityDefinitions |
| Starters | Qyl.Spans, Qyl.SpanNames |
Qyl.IncubatingSpans |
| Views | Views.SpanViews, Views.DbClientSpan |
Incubating.Views.IncubatingSpanViews and its view structs |
Attributes is the one kind both packages carry in full — the stable package the stable rows
plus the deprecated migration symbols, the incubating package every key, at the byte-identical
shape the collector reads by reflection. Every enum-value class carries AllValues and
Contains; those const string classes live under Attributes only, for switch and pattern
matching. Under Activities an enum attribute is an open value-set struct (DbSystemName): one
static member per registry value, Custom(...) for a value the registry does not list (QYL0121
reports one a member carries), Value, Key, value equality, and no conversion from string.
The typed setter of an enum attribute takes the struct. Resource-only attributes
(service.name, deployment.environment.name, host.*: referenced by entities and by no span,
event or metric) get no Activity setter.
One shared Weaver JQ symbol map distinguishes wire keys before filtering by stability or
generating constants, setters and value sets. For example, error.type uses SetErrorType,
while native error_type uses SetErrorTypeNative. A collision with the Native suffix gets
a deterministic code-point suffix. The emitted wire names remain unchanged. Analyzer lookup
uses the declaring type and complete parameter signature. TypeScript enum constants use the
same collision-aware attribute naming as their attribute constants.
Span rows are keyed by the registry's span refinement id and grouped by type, so a
specialization (db.postgresql.client, the gen_ai skill spans) is a row of its own with
Type naming its base; each row carries its SpanName chain, and each AttributeRef its
condition text, Phase, SamplingRelevant and IsPersisted. A reference's qyl.phase overrides
the global phase policy for metadata, starter parameters and analyzer parameter maps.
Sampling relevance is independent of that availability decision.
Metric, span, event and entity definitions expose a separate SignalRequirementLevel:
Recommended by default, or OptIn. This describes collection of the signal, independently
of whether an attribute is required on it. Metrics, spans and events carry EntityAssociations:
an outer implicit one-of list of EntityRef, EntityAssociation.OneOf and
EntityAssociation.AllOf expressions. Every reference includes its defining registry's
schema URL and any source path provided by Weaver; nested alternatives are not flattened.
Typed views validate required values as well as span kind and fixed discriminators.
TryCreate returns false with a null view for an unsuccessful projection; direct construction
rejects a nonmatching record. Required getters never substitute an empty string or zero for
malformed telemetry. Optional getters return null when a value cannot be projected.
The starters (ADR D2) exist for the span groups no library qyl subscribes to already emits:
db.client on Qyl.Spans; messaging.process.consumer, gen_ai.invoke_agent.internal,
gen_ai.execute_tool.internal and its three skill specializations on Qyl.IncubatingSpans.
Required attributes are positional, conditionally required ones nullable with no default (an
omission is CS7036), recommended ones default to null; OptIn, end-phase and group-fixed
attributes take no parameter and go through the typed setters or RecordFailure. Each starter
stamps its qyl.instrumentation.domain, names the span through Qyl.SpanNames, puts every
supplied value into the creation tags and returns null when nothing listens. Spans.Work(name)
covers business work no group describes (domain app). Use native Activity.SetTag for
application attributes, preserving their names and types. RecordFailure sets status Error with a bounded description, error.type
and the exception event. Qyl.SpanNames carries every naming chain of the policy in the stable
package, so producers that may not read the incubating tier name their spans the same way.
For the other five the two packages are disjoint. The stable package carries the stable
and deprecated rows under {Root}{Kind}; the incubating package carries only the rows the
stable package does not, under {Root}Incubating{Kind}, so a consumer may using both
namespaces without an ambiguous-call error. A registry root with no non-stable rows gets no
incubating type at all. A definition generated in either package is an instance of the same
public type, so it can be handed between libraries and applications.
These singletons round the surface out.
SchemaUrl.Current— the pinned core schema URL, stable package only;SchemaUrl.QylandSchemaUrl.QylVersion— the qyl registry's own (https://qyl.at/schemas/<version>), which qyl's ActivitySources carry.RegistryPolicy— the collector's persistence rule as a table (NotPersistedKeys,NotPersistedPrefixes,DeniedKeyTokens,TokenExemptKeys,VendorKeys,IsPersisted); the views and the qyl collector's catalog read it.TokenExemptKeysincludes every registry enum attribute whose key contains a denied token.SpanRecord,SpanEventRecord,SpanLinkRecord,ResourceRecord,InstrumentationScopeRecord,ResourceEntityReferenceandStoreIdentity— the trace contract the generated views read andQyl.Telemetry.Testingbuilds on. Construct a span with its trace ID, span ID and name; initialize its remaining metadata by name. Resource and scope schema URLs are independent, and typed attributes and exact nanosecond times remain available alongside the .NET timestamp projections.Names.QylTelemetryNames— stable package only, because the producer packages build theirActivitySourceandMeterfrom it and may not read the incubating tier.Scopesis the seven scope names qyl constructs (the application scopeQyl.Telemetry.Applicationamong them);VendorActivitySourcesis the source names of the pinned third-party libraries, soAddSourceand a span processor's source match need no literal, and define the reserved names QYL0200 checks. Custom application and library names remain valid;Eventsis the one qyl-owned event name.Incubating.Attributes.{Root}.{Root}MetricAttributes— the qyl-owned instrument names and their units, for the roots that declare one.Incubating.Mapping.AttributeMapping— the collector's normalize table, four switch statements over string literals so it stays netstandard2.0-compatible and NativeAOT-clean.TryGetRenameresolves every renamed key transitively to its final live replacement;IsObsoletedis every key the registry deprecates without naming one, so the collector can drop it and count the drop;IsVendorPassThroughis every key that reached the registry throughregistry/vendor/;NamespaceOfclamps a key to the closed value set ofqyl.attribute.namespace, returningotherfor anything the registry does not know. The four pins ride along as constants.
RegistryCatalog.TryGetAttribute and TryGetMetric expose complete stable and incubating
facts without reflecting over constants: value kinds, template keys, metric instruments and
units, stability and structured deprecations. The analyzers embed the same generated catalog
privately, with no runtime dependency on the consumer library. TypeScript's separate
./catalog export provides findAttribute and findMetric from the same normalized facts.
An unknown custom name is not an OpenTelemetry error. Requirements belong to a selected
signal definition, and the catalog does not assign instruments to scopes.
weaver registry live-check compares emitted spans, metrics and logs against the registry
and reports a finding per attribute, judged by the two halves above.
registry/.weaver.toml is generated from the resolved span definitions and the naming contracts
in registry/qyl/policy.yaml. It selects Weaver v2 and routes spans by their wire name and kind,
so client/server spans sharing a name retain distinct requirements. The registry type is also
accepted as an explicit name. Free-form names without a recognizable literal or enum are not
guessed; they need an explicit type or a producer-specific discriminator before their required
fields can be checked. Unmatched telemetry still receives global attribute validation.
scripts/check-signal-validation.py proves that an ordinary operation passes, each required
field fails when removed, and a shared native name routes separately for client and server.
Generation also runs scripts/check-future.py. It rejects owned registry defects and unknown
dependency diagnostics, while reporting the pinned dependencies' known forward-compatibility
warnings separately in artifacts/logs/future.json. Weaver 0.28's definition/2 experimental
format notice is reported separately even for valid local files. This gate does not claim that
the raw weaver registry check --future command exits zero for those pinned upstream inputs.
All three of -r, --config and --advice-policies need a local path. Weaver's
<url>[sub-folder] archive syntax does not work for this registry: the core dependency is a
local filtered copy at .build/core-filtered/model that only scripts/fetch-core.sh
materialises, so pointing -r at …/archive/refs/tags/<tag>.zip[registry] fails with
IO error for operation on .build/core-filtered/model. --advice-policies and --config do
not accept a URL at all — and --advice-policies fails silently on a path it cannot read,
loading no policies and leaving only the built-in advisors, so a typo there looks like a
registry that suddenly disagrees with itself.
Fetch the tag and materialise the core copy once:
tag="$(git ls-remote --tags --refs --sort=-version:refname \
https://github.com/ANcpLua/Qyl.Telemetry.SemanticConventions 'v*' | head -n1 | cut -f2)"
tag="${tag#refs/tags/}" # the latest tag, v<x.y.z>
curl -sSLo semconv.zip \
"https://github.com/ANcpLua/Qyl.Telemetry.SemanticConventions/archive/refs/tags/${tag}.zip"
unzip -q semconv.zip # -> Qyl.Telemetry.SemanticConventions-<version>/
cd Qyl.Telemetry.SemanticConventions-"${tag#v}"
./scripts/fetch-core.sh # writes .build/core-filtered/model
weaver registry live-check \
-r registry --include-unreferenced \
--config registry/.weaver.toml \
--advice-policies registry/policies/live_check_advice \
--input-source ../spans.json --fail-on violationWeaver 0.28.0 answers that --include-unreferenced with ⚠ The flag include_unreferenced is deprecated. Please prefer manually adding the required imports; the warning is expected and the
flag stays, because a registry's imports block declares metrics, events and entities only and
this registry generates every attribute key its dependencies carry.
git clone --depth 1 --branch "${tag}" followed by ./scripts/fetch-core.sh is equivalent and
is what Qyl.Telemetry.AutoInstrumentation's live check (./eng/build.sh LiveCheck) needs in
.semconv.
scripts/check-live-check-policies.sh pins the exact
findings the set produces over
a sample covering every rule, and asserts that
dropping --config brings the built-in violations back.
Every change ends the same way: run ./scripts/generate.sh and commit the regenerated files
alongside the YAML, because scripts/check-generated.sh compares them against HEAD.
A term. A qyl-owned attribute goes in registry/qyl/attributes.yaml
and must be in the qyl.* namespace — qyl_namespace.rego refuses anything else in that
group. An instrument goes in metrics.yaml, an event name in
events.yaml, a scope name in the annotations of
names.yaml. A term that belongs to upstream is not added here at
all: it arrives by moving the core or genai pin.
A vendor model. One file per library under registry/vendor/, with two
groups. registry.vendor.<library> carries the attributes into the resolved catalog; every
attribute needs the file and line of the library release that declares and sets the key.
vendor.<library> carries the metadata annotation — library, exact pinned version,
repository, ref, licence, and the ActivitySource names it emits on, each with its own
file-and-line note. vendor_metadata.rego fails weaver registry check on a file that
cannot answer those questions. Vendor rows are development stability and are identified by
their registry provenance path, so no prefix allowlist exists anywhere. A vendor key whose
root namespace is new must also gain its member in qyl.attribute.namespace, or
policies-v2 fails and the dropped-attribute counter would bucket the whole namespace as
other.
A policy. A rule about qyl's own groups and their annotations goes in
registry/policies/ — Weaver loads that directory from the registry
itself. A rule that needs the resolved catalog of every dependency goes in
registry/policies-v2/, which scripts/generate.sh passes with -p
against --v2 --include-unreferenced. A rule about ingested telemetry rather than the
registry is not either of these: it is an advice policy under
registry/policies/live_check_advice/, it must decide
from the registry entry rather than from a key list, and its finding has to be added to the
sample and the expected table in scripts/check-live-check-policies.sh.
Bump VersionPrefix in Directory.Build.props, set the registry/manifest.yaml schema_url to https://qyl.at/schemas/<version>, add the CHANGELOG.md entry, run scripts/generate.sh (it writes the same version into typescript/package.json) and commit. Then run ./release.sh <version>: it packs the three NuGet packages and the npm tarball, publishes them with the keys registered in Vitals, tags v<version> and creates the GitHub release. --dry-run packs and runs npm's publish dry run only.
Apache-2.0
Weaver's typescript target (templates/registry/typescript) renders the typescript/ package's stable and incubating constants, its lookup catalog and its captured-field policy from the same resolved registry and parameters as the C# bindings. See the TypeScript package documentation. The package has no runtime dependencies. Run npm test --prefix typescript to verify the packed exports.