feat: Weaver-based generator + IUpstreamConventions Nuke wiring#1
Conversation
…eng/semconv
Drop the previous 228-file hand-curated TypeSpec library that this repo
shipped and replace it with the single-file Weaver-based generator extracted
from qyl/eng/semconv. The new pipeline emits exactly one artifact
(lib/otel-keys.gen.tsp) and produces output that is byte-identical to the
ANcpLua.OtelConventions.Api repo's checked-in generated/otel-keys.gen.tsp,
making this repo the canonical upstream producer for that file.
What was lifted from qyl/eng/semconv (sources kept registry-agnostic):
- templates/registry/typespec/{weaver.yaml,otel-keys.gen.tsp.j2}, rebranded
to root_namespace ANcpLua.OtelConventions.OTel.Keys and ANcpLua header text
- scripts/bootstrap-weaver.{sh,ps1}, paths rebased to the new repo layout
- scripts/run-weaver.sh as the upstream-to-typespec single-pass subset of
qyl's three-pass orchestrator (qyl + csharp_* passes intentionally dropped)
- test/staging-dir-guard.test.sh — regression test for the SEMCONV_STAGING_DIR
safety guard that rejects empty/root/non-absolute staging directories
Pipeline pins:
- semconv v1.41.0 (commit e018fe6f via .tools/semconv-upstream submodule)
- Weaver v0.23.0 (asserted by both bash and PowerShell bootstrap scripts)
Package shape:
- name @ancplua/typespec-otel-semconv, version 1.41.0-1 (semconv-N suffix)
- type module, publishConfig points at GitHub Packages, public access,
provenance attestations enabled
- exports the single ./lib/otel-keys.gen.tsp file
- peerDependency on @typespec/compiler ^1.11.0 || >=1.12.0-dev.0
Testing:
- test/regen.test.ts: vitest double-regen byte-identity + git-clean check
(also asserts no untracked output, closing the PR #4362 codex bug where
verify-clean missed brand-new files)
- test/smoke.tsp: tsp compile --warn-as-error --no-emit gate
- staging-dir-guard.test.sh: rejects empty / "/" / relative staging dirs
- npm run check chains verify-clean + lint:smoke + vitest
CI:
- .github/workflows/ci.yml runs the full check on PR and main
- .github/workflows/publish.yml mirrors the hardened workflow from
ANcpLua.OtelConventions.Api: dist-tag validation, scope auth, provenance
…ions Add a thin Nuke build (build/_build.csproj + build/Build.cs) that implements the IUpstreamConventions component interface declared in Nuke.OpenTelemetry.Conventions 0.1.0. Each target shells out to the existing scripts/*.sh entry points so the Nuke pipeline is one-to-one reproducible from the command line; Build.cs stays a thin orchestrator. Targets implemented (declaration-only stubs on the interface, concrete bodies here): - RestoreWeaver -> bash scripts/bootstrap-weaver.sh - FetchSemconvModel -> git submodule update --init .tools/semconv-upstream - GenerateOtelKeys -> bash scripts/run-weaver.sh - VerifyOtelKeysReproducible -> generate twice, diff bytewise (default target) - VerifyOtelKeysScriptParity -> run bash + pwsh bootstrap if pwsh available - VerifyOtelKeysCompile -> npm run lint:smoke - RunSmokeTests -> npm run test - VerifyClean -> npm run verify-clean - PackTypeSpecLibrary -> npm pack (with full check chain as dependencies) - PublishTypeSpecLibrary -> npm publish --provenance --access public The Nuke.OpenTelemetry.Conventions package is referenced as a local NuGet source pointed at the sibling repo's bin/Release output via build/NuGet.config with package-source mapping so only that one package resolves locally — the rest come from nuget.org. Once the package publishes to a real feed the local source row can be removed in a single line edit. Override notes: - OtelKeysOutput defaults to lib/otel-keys.gen.tsp (matches scripts/run-weaver.sh and the downstream API repo's expected name; the interface default lib/otel-keys.tsp would not match the script output) - WeaverVersion pinned to v0.23.0 to match the bootstrap scripts - TypeSpecCompilerRange aligned with package.json's peerDependency range Bootstrap scripts (build.sh / build.cmd) are the standard Nuke wrappers, and .nuke/parameters.json marks the Nuke root.
- build/NuGet.config: replace the uncommitted local-path source (NU1301 on a fresh runner) with the O-ANcppLua GitHub Packages NuGet feed. Credentials read from %GITHUB_ACTOR%/%GITHUB_PACKAGES_TOKEN%; package source mapping pins Nuke.OpenTelemetry.Conventions to the github feed and falls back to nuget.org for everything else. - .github/workflows/ci.yml: grant packages:read, pass GITHUB_ACTOR + GITHUB_TOKEN to the job env so the NuGet credentials resolve. - .github/workflows/publish.yml: drop the `npm install` fallback after npm ci (matches the hardening already on the API repo); drop the `always-auth: true` setup-node@v6 input that was emitting a deprecation warning (v6 auths automatically when registry-url is set).
Summary by CodeRabbitChores
WalkthroughZwei neue GitHub Actions Workflows wurden hinzugefügt: Der ChangesCI-Validierungs-Workflow
Paket-Publishing-Workflow
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Suggested labels
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error)
✅ Passed checks (7 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 @.github/workflows/ci.yml:
- Around line 19-24: The job currently exposes GITHUB_PACKAGES_TOKEN at job
level (env: GITHUB_PACKAGES_TOKEN) making it available during npm ci and tests;
remove GITHUB_PACKAGES_TOKEN from the top-level env and instead inject it only
into the specific .NET/Nuke steps that need the NuGet feed by adding env:
GITHUB_PACKAGES_TOKEN: ${{ secrets.GITHUB_TOKEN }} to those steps (the steps
that run NuGet restore, dotnet restore, or Nuke tasks), ensuring npm ci/test
steps do not have access to that env var.
In @.github/workflows/publish.yml:
- Around line 6-12: Add a hard ref-guard that aborts manual publishes if the
workflow was triggered from a non-tag ref: check the event context
(workflow_dispatch) and verify GITHUB_REF or github.ref_name matches refs/tags/*
before performing any tag resolution or defaulting the tag input; if the ref
does not match refs/tags/*, exit early with a clear failure message to prevent
unintended "latest" publishes when the tag input is empty. Ensure this guard
runs prior to any logic that inspects or defaults the workflow_dispatch input
named "tag" and is applied consistently for the other publish sections
referenced (lines around the publish job logic).
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: c7f3f7d4-d0fc-4669-90c5-1c93a9e8f58e
⛔ Files ignored due to path filters (280)
.gitignoreis excluded by none and included by none.gitmodulesis excluded by none and included by none.nuke/parameters.jsonis excluded by none and included by none.tools/semconv-upstreamis excluded by none and included by none.tools/semconv-upstreamis excluded by none and included by noneAGENTS.mdis excluded by none and included by noneREADME.mdis excluded by none and included by nonebuild.cmdis excluded by none and included by nonebuild.shis excluded by none and included by nonebuild/Build.csis excluded by none and included by nonebuild/NuGet.configis excluded by none and included by nonebuild/_build.csprojis excluded by none and included by noneglobal.jsonis excluded by none and included by nonelib/_decorators.tspis excluded by none and included by nonelib/_schema.tspis excluded by none and included by nonelib/android.entities.tspis excluded by none and included by nonelib/android.enums.tspis excluded by none and included by nonelib/android.tspis excluded by none and included by nonelib/anthropic.spans.tspis excluded by none and included by nonelib/app.entities.tspis excluded by none and included by nonelib/app.events.tspis excluded by none and included by nonelib/app.tspis excluded by none and included by nonelib/artifact.tspis excluded by none and included by nonelib/aspnetcore.enums.tspis excluded by none and included by nonelib/aspnetcore.metrics.tspis excluded by none and included by nonelib/aspnetcore.tspis excluded by none and included by nonelib/aws.entities.tspis excluded by none and included by nonelib/aws.enums.tspis excluded by none and included by nonelib/aws.spans.tspis excluded by none and included by nonelib/aws.tspis excluded by none and included by nonelib/az.events.tspis excluded by none and included by nonelib/az.tspis excluded by none and included by nonelib/azure.enums.tspis excluded by none and included by nonelib/azure.events.tspis excluded by none and included by nonelib/azure.metrics.tspis excluded by none and included by nonelib/azure.spans.tspis excluded by none and included by nonelib/azure.tspis excluded by none and included by nonelib/browser.entities.tspis excluded by none and included by nonelib/browser.events.tspis excluded by none and included by nonelib/browser.tspis excluded by none and included by nonelib/cassandra.enums.tspis excluded by none and included by nonelib/cassandra.tspis excluded by none and included by nonelib/cicd.entities.tspis excluded by none and included by nonelib/cicd.enums.tspis excluded by none and included by nonelib/cicd.metrics.tspis excluded by none and included by nonelib/cicd.spans.tspis excluded by none and included by nonelib/cicd.tspis excluded by none and included by nonelib/cli.spans.tspis excluded by none and included by nonelib/client.tspis excluded by none and included by nonelib/cloud.entities.tspis excluded by none and included by nonelib/cloud.enums.tspis excluded by none and included by nonelib/cloud.tspis excluded by none and included by nonelib/cloudevents.tspis excluded by none and included by nonelib/cloudfoundry.entities.tspis excluded by none and included by nonelib/cloudfoundry.tspis excluded by none and included by nonelib/code.tspis excluded by none and included by nonelib/container.entities.tspis excluded by none and included by nonelib/container.enums.tspis excluded by none and included by nonelib/container.metrics.tspis excluded by none and included by nonelib/container.tspis excluded by none and included by nonelib/cpu.enums.tspis excluded by none and included by nonelib/cpu.metrics.tspis excluded by none and included by nonelib/cpu.tspis excluded by none and included by nonelib/cpython.enums.tspis excluded by none and included by nonelib/cpython.metrics.tspis excluded by none and included by nonelib/cpython.tspis excluded by none and included by nonelib/db.enums.tspis excluded by none and included by nonelib/db.events.tspis excluded by none and included by nonelib/db.metrics.tspis excluded by none and included by nonelib/db.spans.tspis excluded by none and included by nonelib/db.tspis excluded by none and included by nonelib/deployment.entities.tspis excluded by none and included by nonelib/deployment.enums.tspis excluded by none and included by nonelib/deployment.tspis excluded by none and included by nonelib/destination.tspis excluded by none and included by nonelib/device.entities.tspis excluded by none and included by nonelib/device.events.tspis excluded by none and included by nonelib/device.tspis excluded by none and included by nonelib/disk.enums.tspis excluded by none and included by nonelib/disk.tspis excluded by none and included by nonelib/dns.metrics.tspis excluded by none and included by nonelib/dns.tspis excluded by none and included by nonelib/dotnet.enums.tspis excluded by none and included by nonelib/dotnet.metrics.tspis excluded by none and included by nonelib/dotnet.spans.tspis excluded by none and included by nonelib/dotnet.tspis excluded by none and included by nonelib/dynamodb.spans.tspis excluded by none and included by nonelib/elasticsearch.tspis excluded by none and included by nonelib/enduser.tspis excluded by none and included by nonelib/error.enums.tspis excluded by none and included by nonelib/error.tspis excluded by none and included by nonelib/event.tspis excluded by none and included by nonelib/exception.events.tspis excluded by none and included by nonelib/exception.tspis excluded by none and included by nonelib/faas.entities.tspis excluded by none and included by nonelib/faas.enums.tspis excluded by none and included by nonelib/faas.events.tspis excluded by none and included by nonelib/faas.metrics.tspis excluded by none and included by nonelib/faas.spans.tspis excluded by none and included by nonelib/faas.tspis excluded by none and included by nonelib/feature_flag.enums.tspis excluded by none and included by nonelib/feature_flag.events.tspis excluded by none and included by nonelib/feature_flag.tspis excluded by none and included by nonelib/file.tspis excluded by none and included by nonelib/gcp.entities.tspis excluded by none and included by nonelib/gcp.enums.tspis excluded by none and included by nonelib/gcp.tspis excluded by none and included by nonelib/gen_ai.enums.tspis excluded by none and included by nonelib/gen_ai.events.tspis excluded by none and included by nonelib/gen_ai.metrics.tspis excluded by none and included by nonelib/gen_ai.spans.tspis excluded by none and included by nonelib/gen_ai.tspis excluded by none and included by nonelib/geo.enums.tspis excluded by none and included by nonelib/geo.tspis excluded by none and included by nonelib/go.enums.tspis excluded by none and included by nonelib/go.metrics.tspis excluded by none and included by nonelib/go.tspis excluded by none and included by nonelib/graphql.enums.tspis excluded by none and included by nonelib/graphql.spans.tspis excluded by none and included by nonelib/graphql.tspis excluded by none and included by nonelib/heroku.entities.tspis excluded by none and included by nonelib/heroku.tspis excluded by none and included by nonelib/host.entities.tspis excluded by none and included by nonelib/host.enums.tspis excluded by none and included by nonelib/host.tspis excluded by none and included by nonelib/http.enums.tspis excluded by none and included by nonelib/http.events.tspis excluded by none and included by nonelib/http.metrics.tspis excluded by none and included by nonelib/http.spans.tspis excluded by none and included by nonelib/http.tspis excluded by none and included by nonelib/hw.enums.tspis excluded by none and included by nonelib/hw.metrics.tspis excluded by none and included by nonelib/hw.tspis excluded by none and included by nonelib/ios.enums.tspis excluded by none and included by nonelib/ios.tspis excluded by none and included by nonelib/jsonrpc.tspis excluded by none and included by nonelib/jvm.enums.tspis excluded by none and included by nonelib/jvm.metrics.tspis excluded by none and included by nonelib/jvm.tspis excluded by none and included by nonelib/k8s.entities.tspis excluded by none and included by nonelib/k8s.enums.tspis excluded by none and included by nonelib/k8s.metrics.tspis excluded by none and included by nonelib/k8s.tspis excluded by none and included by nonelib/kestrel.metrics.tspis excluded by none and included by nonelib/linux.enums.tspis excluded by none and included by nonelib/linux.tspis excluded by none and included by nonelib/log.enums.tspis excluded by none and included by nonelib/log.tspis excluded by none and included by nonelib/main.tspis excluded by none and included by nonelib/mainframe.tspis excluded by none and included by nonelib/mcp.enums.tspis excluded by none and included by nonelib/mcp.metrics.tspis excluded by none and included by nonelib/mcp.spans.tspis excluded by none and included by nonelib/mcp.tspis excluded by none and included by nonelib/message.enums.tspis excluded by none and included by nonelib/message.tspis excluded by none and included by nonelib/messaging.enums.tspis excluded by none and included by nonelib/messaging.events.tspis excluded by none and included by nonelib/messaging.metrics.tspis excluded by none and included by nonelib/messaging.tspis excluded by none and included by nonelib/net.enums.tspis excluded by none and included by nonelib/net.tspis excluded by none and included by nonelib/network.enums.tspis excluded by none and included by nonelib/network.tspis excluded by none and included by nonelib/nfs.metrics.tspis excluded by none and included by nonelib/nfs.tspis excluded by none and included by nonelib/nodejs.enums.tspis excluded by none and included by nonelib/nodejs.metrics.tspis excluded by none and included by nonelib/nodejs.tspis excluded by none and included by nonelib/oci.tspis excluded by none and included by nonelib/onc_rpc.tspis excluded by none and included by nonelib/openai.enums.tspis excluded by none and included by nonelib/openai.spans.tspis excluded by none and included by nonelib/openai.tspis excluded by none and included by nonelib/openshift.entities.tspis excluded by none and included by nonelib/openshift.metrics.tspis excluded by none and included by nonelib/openshift.tspis excluded by none and included by nonelib/opentracing.enums.tspis excluded by none and included by nonelib/opentracing.tspis excluded by none and included by nonelib/oracle.tspis excluded by none and included by nonelib/oracle_cloud.tspis excluded by none and included by nonelib/os.entities.tspis excluded by none and included by nonelib/os.enums.tspis excluded by none and included by nonelib/os.tspis excluded by none and included by nonelib/otel-keys.gen.tspis excluded by none and included by nonelib/otel.entities.tspis excluded by none and included by nonelib/otel.enums.tspis excluded by none and included by nonelib/otel.metrics.tspis excluded by none and included by nonelib/otel.tspis excluded by none and included by nonelib/peer.tspis excluded by none and included by nonelib/pool.tspis excluded by none and included by nonelib/pprof.tspis excluded by none and included by nonelib/process.entities.tspis excluded by none and included by nonelib/process.enums.tspis excluded by none and included by nonelib/process.metrics.tspis excluded by none and included by nonelib/process.tspis excluded by none and included by nonelib/profile.enums.tspis excluded by none and included by nonelib/profile.tspis excluded by none and included by nonelib/rpc.enums.tspis excluded by none and included by nonelib/rpc.events.tspis excluded by none and included by nonelib/rpc.metrics.tspis excluded by none and included by nonelib/rpc.spans.tspis excluded by none and included by nonelib/rpc.tspis excluded by none and included by nonelib/security_rule.tspis excluded by none and included by nonelib/server.tspis excluded by none and included by nonelib/service.entities.tspis excluded by none and included by nonelib/service.enums.tspis excluded by none and included by nonelib/service.tspis excluded by none and included by nonelib/session.events.tspis excluded by none and included by nonelib/session.tspis excluded by none and included by nonelib/signalr.enums.tspis excluded by none and included by nonelib/signalr.metrics.tspis excluded by none and included by nonelib/signalr.tspis excluded by none and included by nonelib/source.tspis excluded by none and included by nonelib/state.enums.tspis excluded by none and included by nonelib/state.tspis excluded by none and included by nonelib/system.enums.tspis excluded by none and included by nonelib/system.metrics.tspis excluded by none and included by nonelib/system.tspis excluded by none and included by nonelib/telemetry.entities.tspis excluded by none and included by nonelib/telemetry.enums.tspis excluded by none and included by nonelib/telemetry.tspis excluded by none and included by nonelib/test.enums.tspis excluded by none and included by nonelib/test.tspis excluded by none and included by nonelib/thread.tspis excluded by none and included by nonelib/tls.enums.tspis excluded by none and included by nonelib/tls.tspis excluded by none and included by nonelib/url.tspis excluded by none and included by nonelib/user.tspis excluded by none and included by nonelib/user_agent.enums.tspis excluded by none and included by nonelib/user_agent.tspis excluded by none and included by nonelib/v8js.enums.tspis excluded by none and included by nonelib/v8js.metrics.tspis excluded by none and included by nonelib/v8js.tspis excluded by none and included by nonelib/vcs.entities.tspis excluded by none and included by nonelib/vcs.enums.tspis excluded by none and included by nonelib/vcs.metrics.tspis excluded by none and included by nonelib/vcs.tspis excluded by none and included by nonelib/webengine.entities.tspis excluded by none and included by nonelib/webengine.tspis excluded by none and included by nonelib/zos.entities.tspis excluded by none and included by nonelib/zos.tspis excluded by none and included by nonepackage-lock.jsonis excluded by!**/package-lock.json,!**/package-lock.jsonand included by nonepackage.jsonis excluded by none and included by nonescripts/bootstrap-weaver.ps1is excluded by none and included by nonescripts/bootstrap-weaver.shis excluded by none and included by nonescripts/generate.mjsis excluded by none and included by nonescripts/run-weaver.shis excluded by none and included by nonesrc/generated/deprecated-keys.tsis excluded by!**/generated/**and included bysrc/**src/generated/entity-identifying.tsis excluded by!**/generated/**and included bysrc/**src/generated/enum-keyed-attrs.tsis excluded by!**/generated/**and included bysrc/**src/generated/known-domains.tsis excluded by!**/generated/**and included bysrc/**src/generated/metric-triplets.tsis excluded by!**/generated/**and included bysrc/**templates/registry/typespec/otel-keys.gen.tsp.j2is excluded by none and included by nonetemplates/registry/typespec/weaver.yamlis excluded by none and included by nonetest/__snapshots__/library-structure.jsonis excluded by none and included by nonetest/__snapshots__/openapi3-smoke.yamlis excluded by none and included by nonetest/deprecation.tspis excluded by none and included by nonetest/global-setup.tsis excluded by none and included by nonetest/lint.bad.tspis excluded by none and included by nonetest/lint.deprecated.tspis excluded by none and included by nonetest/lint.enum.tspis excluded by none and included by nonetest/lint.metric.tspis excluded by none and included by nonetest/lint.test.tsis excluded by none and included by nonetest/openapi3.tspis excluded by none and included by nonetest/regen.test.tsis excluded by none and included by nonetest/rules/no-deprecated-otel-key.rule.test.tsis excluded by none and included by nonetest/rules/prefer-otel-key.rule.test.tsis excluded by none and included by nonetest/setup.tsis excluded by none and included by nonetest/smoke.tspis excluded by none and included by nonetest/snapshot.test.tsis excluded by none and included by nonetest/staging-dir-guard.test.shis excluded by none and included by nonetest/tester.tsis excluded by none and included by nonetest/validate.entity.tspis excluded by none and included by nonetest/validate.entity.valid.tspis excluded by none and included by nonetest/validate.schema-url.tspis excluded by none and included by nonetest/validate.schema-url.valid.tspis excluded by none and included by nonetsconfig.jsonis excluded by none and included by nonetspconfig.yamlis excluded by none and included by nonevitest.config.tsis excluded by none and included by none
📒 Files selected for processing (11)
.github/workflows/ci.yml.github/workflows/publish.ymlsrc/decorators.tssrc/index.tssrc/lib.tssrc/rules/_shared.tssrc/rules/enum-typed-value.rule.tssrc/rules/metric-triplet-bound.rule.tssrc/rules/no-deprecated-otel-key.rule.tssrc/rules/prefer-otel-key.rule.tssrc/validate.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
.github/**
⚙️ CodeRabbit configuration file
GitHub Actions workflows. Review for: action version pinning (use SHA not tags for third-party actions), proper secret handling (no secrets in logs, use GITHUB_TOKEN where possible), unnecessary workflow triggers, and job dependency correctness. Flag missing concurrency groups on push-triggered workflows. Ensure matrix strategies cover the supported .NET TFMs.
Files:
.github/workflows/publish.yml.github/workflows/ci.yml
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: ANcpLua/typespec-otel-semconv
Timestamp: 2026-05-12T13:53:05.946Z
Learning: Pin upstream semantic conventions version (`v1.41.0`), Weaver version (`v0.23.0`), and submodule commit (`e018fe6f`) together in `package.json#metadata`, `templates/registry/typespec/weaver.yaml`, and `bootstrap-weaver.{sh,ps1}`. All four must move together when bumping the upstream pin.
Learnt from: CR
Repo: ANcpLua/typespec-otel-semconv
Timestamp: 2026-05-12T13:53:05.946Z
Learning: This repo emits only `lib/otel-keys.gen.tsp` as its single artifact. All code must serve byte-reproducibility of this one file. The 228-file shape from the old pure-JS implementation is removed deliberately.
Learnt from: CR
Repo: ANcpLua/typespec-otel-semconv
Timestamp: 2026-05-12T13:53:05.946Z
Learning: Use Bash and PowerShell scripts (`scripts/*.sh`) as the canonical pipeline. Shell scripts are the authoritative source for runtime behavior, including Weaver version, platform mapping, staging directory configuration, and install permissions.
Learnt from: CR
Repo: ANcpLua/typespec-otel-semconv
Timestamp: 2026-05-12T13:53:05.946Z
Learning: Template files (`templates/registry/typespec/`) are authoritative for the TypeSpec output shape, namespace, include set, and identifier rules. The Jinja template (`otel-keys.gen.tsp.j2`) and Weaver configuration (`weaver.yaml`) define the projection schema.
Learnt from: CR
Repo: ANcpLua/typespec-otel-semconv
Timestamp: 2026-05-12T13:53:05.946Z
Learning: Upstream YAML files at `.tools/semconv-upstream/model/**/*.{yaml,yml}` are authoritative for attribute names, briefs, stability status, and deprecation information. Do not override or redefine these in generated code.
Learnt from: CR
Repo: ANcpLua/typespec-otel-semconv
Timestamp: 2026-05-12T13:53:05.946Z
Learning: Ensure `npm run verify-clean` and the regen vitest pass on every commit. If a template or script change produces a different byte sequence, bump `package.json#version` as `{semconv}-{n+1}` and commit the updated `lib/otel-keys.gen.tsp`.
Learnt from: CR
Repo: ANcpLua/typespec-otel-semconv
Timestamp: 2026-05-12T13:53:05.946Z
Learning: Do not add qyl-specific code, models, C# SDK constants, Markdown documentation, or SQL column templates to this repo. Only registry-agnostic templates and generation logic belong here.
| env: | ||
| # build/NuGet.config has the org GitHub Packages NuGet feed as a packageSource | ||
| # and reads these env vars in its <packageSourceCredentials> section. | ||
| GITHUB_ACTOR: ${{ github.actor }} | ||
| GITHUB_PACKAGES_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| steps: |
There was a problem hiding this comment.
Secrets auf Step-Ebene begrenzen, nicht jobweit setzen.
GITHUB_PACKAGES_TOKEN ist aktuell auch während npm ci und Tests verfügbar; bitte nur in den .NET/Nuke-Schritten injizieren, die den NuGet-Feed wirklich benötigen.
Vorschlag (Least-Privilege)
check:
runs-on: ubuntu-latest
- env:
- # build/NuGet.config has the org GitHub Packages NuGet feed as a packageSource
- # and reads these env vars in its <packageSourceCredentials> section.
- GITHUB_ACTOR: ${{ github.actor }}
- GITHUB_PACKAGES_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
@@
- name: Nuke build (compile)
run: dotnet build build/_build.csproj -c Release
+ env:
+ GITHUB_ACTOR: ${{ github.actor }}
+ GITHUB_PACKAGES_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@
- name: Nuke VerifyOtelKeysReproducible
run: ./build.sh VerifyOtelKeysReproducible
+ env:
+ GITHUB_ACTOR: ${{ github.actor }}
+ GITHUB_PACKAGES_TOKEN: ${{ secrets.GITHUB_TOKEN }}🤖 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 @.github/workflows/ci.yml around lines 19 - 24, The job currently exposes
GITHUB_PACKAGES_TOKEN at job level (env: GITHUB_PACKAGES_TOKEN) making it
available during npm ci and tests; remove GITHUB_PACKAGES_TOKEN from the
top-level env and instead inject it only into the specific .NET/Nuke steps that
need the NuGet feed by adding env: GITHUB_PACKAGES_TOKEN: ${{
secrets.GITHUB_TOKEN }} to those steps (the steps that run NuGet restore, dotnet
restore, or Nuke tasks), ensuring npm ci/test steps do not have access to that
env var.
| workflow_dispatch: | ||
| inputs: | ||
| tag: | ||
| description: 'npm dist-tag (alphanumerics, dot, underscore, hyphen). Leave blank to auto-pick (latest for stable releases, next for prereleases).' | ||
| required: false | ||
| default: '' | ||
|
|
There was a problem hiding this comment.
Manueller Publish braucht einen Ref-Guard auf Git-Tags.
workflow_dispatch kann aktuell von Branches laufen; in Kombination mit leerem Input endet das schnell in einem unbeabsichtigten latest-Publish. Bitte vor dem Tag-Resolve auf refs/tags/* hart abbrechen.
Vorschlag (fail-fast bei nicht-Tag-Refs)
- name: Resolve npm dist-tag
shell: bash
env:
DISPATCH_TAG: ${{ inputs.tag }}
IS_PRERELEASE: ${{ github.event.release.prerelease }}
EVENT_NAME: ${{ github.event_name }}
run: |
set -euo pipefail
+ if [ "$EVENT_NAME" = "workflow_dispatch" ] && [[ "${GITHUB_REF:-}" != refs/tags/* ]]; then
+ echo "::error::workflow_dispatch publish is only allowed from tag refs (refs/tags/*)."
+ exit 1
+ fi
if [ "$EVENT_NAME" = "workflow_dispatch" ] && [ -n "$DISPATCH_TAG" ]; then
dist_tag="$DISPATCH_TAG"
elif [ "$IS_PRERELEASE" = "true" ]; then
dist_tag="next"
else
dist_tag="latest"
fiAlso applies to: 66-87
🤖 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 @.github/workflows/publish.yml around lines 6 - 12, Add a hard ref-guard that
aborts manual publishes if the workflow was triggered from a non-tag ref: check
the event context (workflow_dispatch) and verify GITHUB_REF or github.ref_name
matches refs/tags/* before performing any tag resolution or defaulting the tag
input; if the ref does not match refs/tags/*, exit early with a clear failure
message to prevent unintended "latest" publishes when the tag input is empty.
Ensure this guard runs prior to any logic that inspects or defaults the
workflow_dispatch input named "tag" and is applied consistently for the other
publish sections referenced (lines around the publish job logic).
Summary
Replaces the pure-JS Node generator with a Weaver-based pipeline lifted from
qyl/eng/semconv, and bolts a Nuke build host implementingIUpstreamConventionsfromNuke.OpenTelemetry.Conventions@0.1.0.Why
The previous
scripts/generate.mjsproduced a 228-file shape that didn't match what the downstream consumer (@o-ancpplua/otel-conventions-api) actually needs (singleotel-keys.gen.tsp). The Weaver pipeline atqyl/eng/semconvalready produced the correct shape — this PR lifts it out so the producer/consumer contract is decoupled from qyl's release cadence.What's in this PR
Generator (
templates/,scripts/,lib/,test/)templates/registry/typespec/{weaver.yaml,otel-keys.gen.tsp.j2}— lifted from qyl, rebrandedroot_namespacetoANcpLua.OtelConventions.OTel.Keys, added trailing newlinescripts/{bootstrap-weaver.sh,bootstrap-weaver.ps1,run-weaver.sh}— Bash↔PowerShell parity preserved,REPO_ROOTrebased, qyl-specific csharp_*/qyl passes dropped (only the upstream→typespec path remains)test/staging-dir-guard.test.sh— safety guard regression test for therm -rfpathlib/otel-keys.gen.tsp— generator output, checked in forverify-cleandiffpackage.jsonflipped to public, version1.41.0-1, noprivate: true, scripts:generate,verify-clean,lint:smoke,test,checkNuke build host (
build/)build/_build.csproj— net10.0,Nuke.Common 10.1.0+Nuke.OpenTelemetry.Conventions 0.1.0build/Build.cs— implementsIUpstreamConventionsvia explicit-interface; each target shells out to the matchingscripts/*.sh; pinsWeaverVersionto v0.23.0build/NuGet.config— points athttps://nuget.pkg.github.com/O-ANcppLua/index.jsonfor the shared Nuke component; nuget.org for everything elsebuild.sh/build.cmd/.nuke//global.json— standard Nuke bootstrapCI / publish
.github/workflows/ci.yml— runs Weaver bootstrap → generate →verify-clean→lint:smoke→ vitest → staging-guard regression → Nukedotnet build+VerifyOtelKeysReproducible. Grantspackages: read, passesGITHUB_ACTOR+GITHUB_TOKENfor the NuGet feed..github/workflows/publish.yml— release-triggered npm publish to GitHub Packages with provenance; same hardening as the API repo (validatedinputs.tag, prerelease →nextauto-routing, noalways-auth/nonpm installfallback)Byte-identity proof
The generated
lib/otel-keys.gen.tspis byte-identical to the consumer repo's current hand-copied artifact:This is the lockstep signal: once
@ancplua/typespec-otel-semconv@1.41.0-1publishes, the consumer can drop its hand-copied artifact and consume this package as a real npm dep.Verification (all 9 gates green locally)
bash scripts/bootstrap-weaver.sh— Weaver v0.23.0 binary installedbash scripts/run-weaver.sh— 1,648 lines / 707 consts emittednpm run lint:smoke✅ (tsp 1.12.0-dev.12)npm run verify-clean✅ (zero drift, zero untracked)npm run test✅ (vitest 4.1.6, 2/2: byte-identity + git-clean)dotnet build build/_build.csproj -c Release✅ (0 warn / 0 err)./build.sh GenerateOtelKeys✅./build.sh(defaultVerifyOtelKeysReproducible) +bash test/staging-dir-guard.test.sh✅ (3/3 guard tests PASS)Test plan
v1.41.0-1after merge to publish@ancplua/typespec-otel-semconv@1.41.0-1to GitHub PackagesANcpLua.OtelConventions.Api) then adds the npm dep and drops its hand-copiedgenerated/otel-keys.gen.tsp(separate PR)Versioning
{semconv-version}-{n}per the architecture sketch: this is1.41.0-1(semconv v1.41.0, first generator revision). Bumping semconv pin = bump1.41.0→1.42.0, resetnto 1. Bumping generator code without semconv changes = incrementn.🤖 Generated with Claude Code