Skip to content

feat(nuke): IDomainConventionsApi build + AGENTS.md#18

Merged
Alexander Nachtmann (ANcpLua) merged 5 commits into
mainfrom
feat/nuke-domain-conventions
May 12, 2026
Merged

feat(nuke): IDomainConventionsApi build + AGENTS.md#18
Alexander Nachtmann (ANcpLua) merged 5 commits into
mainfrom
feat/nuke-domain-conventions

Conversation

@ANcpLua
Copy link
Copy Markdown
Member

@ANcpLua Alexander Nachtmann (ANcpLua) commented May 12, 2026

Summary

Wires this repo into the producer/consumer split: a Nuke 10 build host implementing IDomainConventionsApi from the freshly-published Nuke.OpenTelemetry.Conventions@0.1.0 shared component, plus an AGENTS.md and the matching CI workflow.

What's in this PR

Nuke build host (build/)

  • build/_build.csproj — net10.0, references Nuke.Common 10.1.0 + Nuke.OpenTelemetry.Conventions 0.1.0 (resolved from the org GitHub Packages NuGet feed)
  • build/Build.cs — overrides every target on IDomainConventionsApi via explicit-interface implementation; adds a top-level Check aggregate (RestoreTypeSpecDeps → VerifyKeysLockstep → CompileDomainSpec → VerifyNoManualEditsToGenerated → EmitAll → VerifyEmitDeterministic → PackApiPackage)
  • build/NuGet.config — points at https://nuget.pkg.github.com/O-ANcppLua/index.json as the primary source, with the local sibling checkout path kept as offline-dev fallback
  • build.sh / build.cmd / .nuke/ — standard Nuke bootstrap

CI

  • .github/workflows/nuke.yml — runs ./build.sh Check on PR/push to main. Grants packages: read, passes GITHUB_ACTOR + GITHUB_TOKEN so the GitHub Packages NuGet feed credentials resolve.

Docs

  • AGENTS.md — documents tarball boundary (main.tsp vs index.tsp), lint:public regression gate, generated/ read-only policy, exports-map rules, peer-dep policy, publishing flow, planned IDomainConventionsApi wiring, and "what not to do" list.

Notable design choices

Decision Why
EmitOutputDir defaults to Artifacts/emit/, not ./emitters The repo's emitters/ directory holds emitter source code — using it as the output dir would shadow source. The interface default (./emitters) is overridden via doc-commented <inheritdoc>.
LintConventions runs npm run lint, not tsp compile --emit ... @ancplua/typespec-otelconventions-lint is a TypeSpec library (decorators + diagnostics), not an emitter — it has no $onEmit, so the interface's literal command errors with invalid-emitter. npm run lint (full-surface compile with --warn-as-error) is what actually exercises the linter.
lint excluded from VerifyEmitDeterministic byte-diff Same reason — it produces no files to compare.
nuke.yml is independent of publish.yml publish.yml stays small + npm-direct so trusted-publishing OIDC keeps working unchanged. nuke.yml is the local-build verification gate.

Verification

All five gates pass locally on feat/nuke-domain-conventions:

  1. dotnet restore build/_build.csproj
  2. dotnet build build/_build.csproj -c Release ✅ (0 errors, 0 warnings)
  3. ./build.sh --help lists all 13 targets ✅
  4. ./build.sh Check runs end-to-end ✅. VerifyKeysLockstep correctly skips with a warning (lockstep flip pending). VerifyEmitDeterministic confirms byte-identical output across two emit runs. VerifyNoManualEditsToGenerated, CompileDomainSpec, EmitAll, PackApiPackage all green.
  5. git status clean.

Test plan

  • Nuke build verification workflow goes green on this PR
  • CodeRabbit review surfaces no blocker on the Nuke wiring
  • Publish to GitHub Packages workflow remains green (unchanged by this PR)

Related

🤖 Generated with Claude Code


View in Codesmith
Need help on this PR? Tag @codesmith with what you need.

  • Let Codesmith autofix CI failures and bot reviews

Scaffold a Nuke 10 build host under build/ that overrides every target on
IDomainConventionsApi from the locally-built Nuke.OpenTelemetry.Conventions
0.1.0 package. Each target maps to either an existing npm script
(lint:public, lint, npm ci, npm pack) or the lockstep / determinism /
no-manual-edits policy this repo owns.

- VerifyKeysLockstep parses package-lock.json for the upstream keys
  package, asserts an exact pin against OtelKeysVersion, and byte-diffs
  generated/otel-keys.gen.tsp against the installed lib/otel-keys.gen.tsp.
  Skips with a warning when the package isn't installed yet (lockstep
  flip pending), per the contribution plan.
- VerifyEmitDeterministic runs every emitter twice into
  Artifacts/emit-{a,b} and byte-compares. `lint` is excluded because
  it's a TypeSpec library (no $onEmit), not an emitter.
- VerifyNoManualEditsToGenerated runs `git diff --exit-code generated/`
  *and* `git status --porcelain generated/`, closing the Codex
  untracked-file gap.
- PublishApiPackage mirrors publish.yml's dist-tag resolution
  (NPM_DIST_TAG validated against ^[A-Za-z0-9._-]+$, default `latest`).
- Top-level `Check` target chains restore -> lockstep -> compile ->
  no-manual-edits -> emit-all -> determinism -> pack.

Build host targets net10.0, references Nuke.Common 10.1.0 plus the
local Nuke.OpenTelemetry.Conventions 0.1.0 .nupkg via build/NuGet.config.
Adds the same NuGet.Packaging + System.Security.Cryptography.Xml
security overrides as the component package so NuGetAudit stays silent.
Pins the .NET SDK to 10.0.203 via build/global.json and nuke.global.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a GitHub Actions workflow that runs the end-to-end IDomainConventionsApi
gate (`./build.sh Check`) on every PR and push to main. The workflow
complements (does not replace) publish.yml:

- publish.yml stays npm-direct so the trusted-publishing OIDC flow keeps
  working unchanged.
- nuke.yml provides the local-build verification gate: restore ->
  lockstep -> compile -> no-manual-edits -> emit-all -> determinism ->
  pack, exercising the Nuke build host on a clean checkout.

Uses actions/checkout@v6, actions/setup-node@v6 (Node 22), and
actions/setup-dotnet@v4 (10.0.x), matching the toolchain pinned in
build/global.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- AGENTS.md documents agent conventions for the repo: tarball boundary,
  lint:public regression gate, generated/ read-only, peer-dep policy,
  publishing flow, and the planned IDomainConventionsApi wiring.
- build/NuGet.config: add the O-ANcppLua GitHub Packages NuGet feed
  (https://nuget.pkg.github.com/O-ANcppLua/index.json) as the primary
  source for Nuke.OpenTelemetry.Conventions, with the local sibling
  checkout path kept as offline-dev fallback. Credentials read from
  %GITHUB_ACTOR% + %GITHUB_PACKAGES_TOKEN%.
- nuke.yml: grant packages:read, pass GITHUB_ACTOR + GITHUB_TOKEN to
  the job env so the NuGet.config credential section resolves on CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 13:46
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

Review Change Stack

Warning

Rate limit exceeded

@ANcpLua has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 56 minutes and 12 seconds before requesting another review.

To continue reviewing without waiting, purchase usage credits in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: aedd86f3-97a0-4574-ba37-fcfe6f373cd0

📥 Commits

Reviewing files that changed from the base of the PR and between 35a50ea and a60a72a.

📒 Files selected for processing (12)
  • .github/workflows/nuke.yml
  • .gitignore
  • .nuke/build.schema.json
  • .nuke/parameters.json
  • AGENTS.md
  • build.cmd
  • build.sh
  • build/Build.cs
  • build/NuGet.config
  • build/_build.csproj
  • build/global.json
  • nuke.global.json
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/nuke-domain-conventions
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/nuke-domain-conventions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

NU1301 fires when a configured packageSource path doesn't exist, even
if other sources resolve the package fine. The local fallback only
made sense for offline dev next to an uncommitted Nuke.OpenTelemetry
.Conventions checkout; CI runners never had that path, so it broke
restore.

Local dev now opts in explicitly via
  dotnet nuget add source ../Nuke.OpenTelemetry.Conventions/src/.../bin/Release \
    --name local-nuke-otel-conventions --configfile build/NuGet.config
(documented in the file's comment header). The org GitHub Packages
feed remains the only committed source for the shared Nuke component.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
XML comments cannot contain double-hyphens. The embedded `dotnet nuget
add source` example included `--name`/`--configfile` flags inside the
comment, which made the file invalid XML and broke restore with
"NuGet.Config is not valid XML." Rewrote the comment to describe the
opt-in path in prose instead of pasting the literal command.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Risk summary: Medium — new build/CI wiring is substantial and includes at least one likely cross-platform build-break in the git pathspec usage.

This PR wires the repo into the new producer/consumer split by adding a Nuke 10 build host implementing IDomainConventionsApi, plus a CI workflow and agent-facing documentation.

Changes:

  • Add a Nuke build host (build/_build.csproj, build/Build.cs) implementing IDomainConventionsApi targets and a Check aggregate.
  • Add CI workflow to run ./build.sh Check and add Nuke bootstrap/config files (build.sh, build.cmd, .nuke/*, build/NuGet.config).
  • Add AGENTS.md guidance and update .gitignore for Nuke/Artifacts outputs.

Blockers

  • VerifyNoManualEditsToGenerated passes an absolute path to git diff/git status, which commonly fails because git pathspecs are repo-relative (likely to break the Check gate on clean environments).

Important issues

  • SDK pinning is currently inconsistent/ineffective for local runs: build.sh runs from repo root, so build/global.json won’t be applied, and nuke.global.json is not used by dotnet.
  • AGENTS.md still describes Nuke/IDomainConventionsApi as “planned” even though this PR lands it, which will mislead agents.

Minor / optional

  • None noted.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
nuke.global.json Attempts to pin .NET SDK for Nuke, but currently not applied by dotnet.
build/NuGet.config Adds GitHub Packages NuGet source + local fallback for restoring Nuke shared component.
build/global.json Pins .NET SDK under build/, but won’t affect build.sh as written.
build/Build.cs Implements IDomainConventionsApi targets (restore/compile/emit/determinism/pack/publish) and adds Check.
build/_build.csproj Adds net10.0 Nuke build host referencing Nuke.OpenTelemetry.Conventions.
build.sh Bash bootstrap to run the build host.
build.cmd Windows bootstrap to run the build host.
AGENTS.md Adds agent guidance on surfaces, lint gates, tarball boundary, publishing, and Nuke usage.
.nuke/parameters.json Default Nuke parameters for emitters/lockstep behavior.
.nuke/build.schema.json Generated schema for Nuke parameters/targets.
.gitignore Ignores Nuke build outputs, Artifacts emit output, and npm pack tarballs.
.github/workflows/nuke.yml Adds CI job to run ./build.sh Check on PR/push.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread build/Build.cs
Comment on lines +337 to +342

// Tracked-diff guard: any modified tracked file under generated/.
Git($"diff --exit-code -- \"{generated}\"", workingDirectory: self.DomainSpecRoot);

// Untracked-file guard: porcelain output for generated/ must be empty.
var porcelain = Git($"status --porcelain -- \"{generated}\"", workingDirectory: self.DomainSpecRoot, logOutput: false);
Comment thread build.sh
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"

dotnet run --project ./build/_build.csproj -- "$@"
Comment thread nuke.global.json
Comment on lines +1 to +6
{
"sdk": {
"version": "10.0.203",
"rollForward": "latestFeature"
}
}
Comment thread AGENTS.md
Comment on lines +65 to +67
## Nuke (planned)

The `Nuke.OpenTelemetry.Conventions` shared package will land an `IDomainConventionsApi` component that this repo's `Build.cs` will implement. Targets: `RestoreTypeSpecDeps`, `VerifyKeysLockstep` (assert `generated/otel-keys.gen.tsp` matches the locked `@ancplua/typespec-otel-semconv` version), `CompileDomainSpec`, `EmitAll`, `VerifyEmitDeterministic`, `BuildCSharpEmit`, `VerifyNoManualEditsToGenerated`, `PackApiPackage`, `PublishApiPackage`. Until that lands, the npm scripts above are the source of truth.
@ANcpLua Alexander Nachtmann (ANcpLua) merged commit 6158eda into main May 12, 2026
2 checks passed
@ANcpLua Alexander Nachtmann (ANcpLua) deleted the feat/nuke-domain-conventions branch May 12, 2026 13:54
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ebfb19037c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".

Comment thread build/Build.cs
Comment on lines +151 to +154
Target IDomainConventionsApi.EmitCSharp => _ => _
.Description("Run the C# TypeSpec emitter into Artifacts/emit/csharp.")
.DependsOn(((IDomainConventionsApi)this).CompileDomainSpec)
.Executes(() => RunTypeSpecEmitter("@ancplua/typespec-emit-csharp", "csharp"));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Build emitter binaries before running emitter targets

EmitCSharp (and the sibling emitter targets) only depend on CompileDomainSpec, which runs lint:public and does not compile local emitters. On a clean checkout, those packages resolve to file: links and their lib/main.tsp files import ../dist/index.js, so running EmitCSharp/EmitDuckDb/EmitTsTypes before npm run build:emitters fails. This also makes EmitAll fragile because LintConventions (the only target that runs npm run lint, which builds emitters) is a sibling dependency and not an ordering dependency.

Useful? React with 👍 / 👎.

Comment thread build/Build.cs
Comment on lines +151 to +154
Target IDomainConventionsApi.EmitCSharp => _ => _
.Description("Run the C# TypeSpec emitter into Artifacts/emit/csharp.")
.DependsOn(((IDomainConventionsApi)this).CompileDomainSpec)
.Executes(() => RunTypeSpecEmitter("@ancplua/typespec-emit-csharp", "csharp"));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add emitter-build prerequisite before Emit targets*

EmitCSharp/EmitDuckDb/EmitTsTypes depend only on CompileDomainSpec, which runs lint:public and does not compile local emitter JS. These emitters are file: packages whose lib/main.tsp imports ../dist/index.js, so invoking any Emit* target on a clean checkout can fail before artifacts are generated. This breaks common workflows such as running ./build.sh EmitCSharp directly and makes the target graph fragile.

Useful? React with 👍 / 👎.

Comment thread build/Build.cs
Comment on lines +412 to +419
.DependsOn(
((IDomainConventionsApi)this).RestoreTypeSpecDeps,
((IDomainConventionsApi)this).VerifyKeysLockstep,
((IDomainConventionsApi)this).CompileDomainSpec,
((IDomainConventionsApi)this).VerifyNoManualEditsToGenerated,
((IDomainConventionsApi)this).EmitAll,
((IDomainConventionsApi)this).VerifyEmitDeterministic,
((IDomainConventionsApi)this).PackApiPackage);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Enforce ordering in Check pipeline

Check describes a linear gate (emit-all -> determinism -> pack) but wires all targets as sibling dependencies. In NUKE, DependsOn does not impose list order and execution between siblings is nondeterministic/parallel, so VerifyEmitDeterministic can run before EmitAll has completed its lint/build side effects, causing flaky failures on clean environments. Add explicit ordering edges (Before/After) or explicit prerequisites so the declared pipeline order is guaranteed.

Useful? React with 👍 / 👎.

Comment thread build/Build.cs
Comment on lines +151 to +154
Target IDomainConventionsApi.EmitCSharp => _ => _
.Description("Run the C# TypeSpec emitter into Artifacts/emit/csharp.")
.DependsOn(((IDomainConventionsApi)this).CompileDomainSpec)
.Executes(() => RunTypeSpecEmitter("@ancplua/typespec-emit-csharp", "csharp"));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Build emitter binaries before running emitter targets

EmitCSharp/EmitDuckDb/EmitTsTypes depend only on CompileDomainSpec, which runs lint:public and does not compile local emitter JS. These emitters are file: packages whose lib/main.tsp imports ../dist/index.js, so invoking any Emit* target on a clean checkout can fail before artifacts are generated. This breaks direct target runs like ./build.sh EmitCSharp and makes emitter execution fragile.

Useful? React with 👍 / 👎.

Comment thread build/Build.cs
Comment on lines +412 to +419
.DependsOn(
((IDomainConventionsApi)this).RestoreTypeSpecDeps,
((IDomainConventionsApi)this).VerifyKeysLockstep,
((IDomainConventionsApi)this).CompileDomainSpec,
((IDomainConventionsApi)this).VerifyNoManualEditsToGenerated,
((IDomainConventionsApi)this).EmitAll,
((IDomainConventionsApi)this).VerifyEmitDeterministic,
((IDomainConventionsApi)this).PackApiPackage);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Enforce target ordering in Check pipeline

Check is described as a linear gate (... -> emit-all -> determinism -> pack) but wires these as sibling DependsOn edges. In NUKE, dependency list position does not define execution order, so sibling targets can run in nondeterministic order/parallel. That allows VerifyEmitDeterministic to run before EmitAll completes its prerequisite side effects on clean environments, creating flaky or misleading failures.

Useful? React with 👍 / 👎.

Comment thread build/Build.cs
Comment on lines +106 to +112
if (!File.Exists(installed))
{
Log.Warning(
"VerifyKeysLockstep: '{Installed}' not found — skipping byte diff with '{Committed}'. " +
"Once the upstream package is installed this comparison will be enforced.",
installed, committed);
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail lockstep when upstream keys file is missing

When the upstream package is present in package-lock.json but node_modules/{pkg}/lib/otel-keys.gen.tsp is missing, VerifyKeysLockstep only logs a warning and returns success. In that scenario, the lockstep check is silently bypassed even though the package layout is invalid for this repo’s contract, so CI can pass without actually verifying generated keys consistency.

Useful? React with 👍 / 👎.

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.

2 participants