Skip to content

feat(pivot): PR-I.1a — in-repo Go submodule scaffold at module/#214

Merged
trilamsr merged 4 commits into
mainfrom
pr-i-1a-module-scaffold
May 31, 2026
Merged

feat(pivot): PR-I.1a — in-repo Go submodule scaffold at module/#214
trilamsr merged 4 commits into
mainfrom
pr-i-1a-module-scaffold

Conversation

@trilamsr

@trilamsr trilamsr commented May 31, 2026

Copy link
Copy Markdown
Contributor

What this PR does

Scaffolds the in-repo Go submodule at module/ per RFC-0013 §migration PR-I.1a. Submodule carries module/go.mod declaring module github.com/tracecoreai/tracecore/module on go 1.26.3 and a single module/doc.go package-doc stub (no functional Go source yet — the stub exists so the Go module proxy can validate module/v0.0.1 at tag-cut; proxies typically require ≥1 .go file). Root go.work lists . and ./module so dev builds resolve both modules without publishing. No file movement, no behaviour change — the OCB binary at ./_build/tracecore and go build ./... / go vet ./... / go test ./... all stay green side-by-side with this scaffold.

The module/v0.0.1 genesis tag will be cut after merge to validate the publish path (Go module proxy can resolve the submodule via doc.go) before any real code moves in PR-I.1b.

Side-effects required to keep CI green

1. .gitignore un-ignores go.work

The workspace file is committed now; go.work.sum stays ignored as a per-environment cache (each module's own go.sum already pins direct + transitive deps).

2. Makefile build target sets GOWORK=off for the OCB invocation

OCB generates ./_build/{go.mod,main.go} and runs go build from inside ./_build/. With workspace mode active, that inner build tries to resolve ./_build as a package of the root module (since the workspace lists .) and fails with main module does not contain package github.com/tracecoreai/tracecore/_build. The generated module is intentionally non-workspace; isolate it.

3. go.work carries a replace for google.golang.org/genproto

Root cause (debugged in this PR, not papered over): google.golang.org/grpc@v1.81.1's status package imports google.golang.org/genproto/googleapis/rpc/status. That path lives in two modules in our build graph:

  • google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa (split-out submodule — what grpc-go actually pulls today)
  • google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd (last monolithic-genproto release before the split — pulled transitively by viper@v1.12.0)

Two modules provide the same import path. Result: ambiguous-import build error.

Why workspace mode trips on it but single-module mode doesn't: Go's module loader prunes transitive indirect deps under MVS in single-module mode (GOWORK=off), and the old monolithic genproto sits behind a viper transitive that no live import path touches — so it gets pruned. Workspace mode (Go 1.18+) loads the union of every member module's require lines without that pruning step, so the old monolithic genproto survives into the package-load phase and collides with the split-out submodule.

Why not "just bump viper": viper@v1.12.0 is the dep that pulls the old monolithic genproto. It's pinned by the golangci-lint v2 module. Verified 2026-05-31: even golangci-lint@v2.12.2 (latest at time of PR) still pins viper@v1.12.0 (and wrapcheck@v2.12.0 does too). We don't import viper directly; bumping it would require forking golangci-lint or waiting for upstream. The replace in go.work is the smallest in-tree fix that keeps workspace mode usable today.

The replace points the workspace at google.golang.org/genproto@v0.0.0-20240227224415-6ceb2ff114de, a post-split monolithic-genproto tag that no longer ships the conflicting path. GOWORK=off builds ignore the block entirely. The redirect can be removed once golangci-lint's viper pin moves past the pre-split genproto era (track upstream golangci-lint go.mod).

4. builder-config.yaml gains commented-out skeleton entries

Future receivers: / processors: / replaces: lines that PR-I.1b and PR-I.2 will uncomment — keeps those PRs mechanical (no indentation or module-path typo risk). The replaces: skeleton sits at root level (zero indent, sibling to dist: / receivers: / processors: / exporters: / extensions:), matching the OCB v0.110.0 schema (cmd/builder/internal/builder/config.go declares Config.Replaces []string mapstructure:"replaces") and the canonical upstream pattern in opentelemetry-collector-releases/distributions/otelcol-contrib/manifest.yaml(replaces: as the final root-level block after all component lists). The comment inbuilder-config.yaml` documents this placement decision explicitly so the PR-I.1b uncomment is byte-clean.

5. module/doc.go package-doc stub

module/v0.0.1 will be cut from an otherwise-empty submodule after PR-I.1a merges. The Go module proxy validates incoming modules by requiring at least one .go file at the module root — without doc.go, a GOPROXY=https://proxy.golang.org go list -m github.com/tracecoreai/tracecore/module@v0.0.1 may fail with no Go source files and break the PR-I.1b release-tag workflow. Single package-doc file, no functional code.

Verification (all green under workspace mode)

Gate Status
go build ./... clean
go vet ./... clean
go list ./module/... resolves to github.com/tracecoreai/tracecore/module
go vet ./module/... clean
go test -count=1 ./components/... ./internal/... ./pkg/... ./tools/... pass (all packages)
make check (fmt + tidy-check + lint + vet + mod-verify) clean
make verify (check + license + build-tags + doc-check + actionlint + zizmor + ...) clean
make build (OCB) produces ./_build/tracecore

Linked issue(s)

Refs RFC-0013 §migration PR-I.1a (line 247 of docs/rfcs/0013-distro-first-pivot.md).

Release notes

[CHANGE] Empty in-repo Go submodule scaffold landed at `module/` (path `github.com/tracecoreai/tracecore/module`) carrying `go.mod` plus a single `doc.go` package-doc stub (proxy-validation), alongside root `go.work` listing `.` and `./module`. Genesis tag `module/v0.0.1` will be cut after merge. No file movement or operator-visible behaviour change in this PR — receivers/processors arrive in PR-I.1b and PR-I.2.

Checklist

  • Tests added or updated — no new test surface; existing root tests stay green under workspace mode (go test ./components/... ./internal/... ./pkg/... ./tools/... pass).
  • make check runs green continuously while editing; make ci passes before pushing — make verify (superset of make check) clean.
  • Commits are signed off (git commit -s)
  • For new components, follows the layout required by STYLE.mdmodule/ carries go.mod + doc.go + README.md only; no functional Go source files in this PR (component layout enforced when PR-I.1b moves nccl_fr in).
  • PR title and Summary still reflect the current diff (re-check after pushing fixes)

Tri Lam added 4 commits May 31, 2026 01:55
Empty submodule (module/go.mod declaring module path on go 1.26.3 — no
source files yet) plus root go.work listing `.` and `./module` so dev
builds resolve both modules without publishing. Per RFC-0013 §migration
PR-I.1a: scaffolding only, no file movement.

The `module/v0.0.1` genesis tag will be cut after merge to validate the
publish path (Go module proxy can resolve the empty submodule) before
any real code moves in PR-I.1b.

Side-effects required to keep CI green side-by-side:

- .gitignore un-ignores go.work (the workspace file is committed now;
  go.work.sum stays ignored as a per-environment cache).

- Makefile `build` target sets GOWORK=off for the OCB invocation. OCB
  generates ./_build/{go.mod,main.go} and runs `go build` from inside
  ./_build/. With workspace mode active, that inner build tries to
  resolve ./_build as a package of the root module (since the workspace
  lists `.`) and fails with "main module does not contain package
  github.com/tracecoreai/tracecore/_build". The generated module is
  intentionally non-workspace; isolate it.

- go.work carries a replace directive for google.golang.org/genproto.
  viper@v1.12.0 (transitive dep of the golangci-lint tool chain) pulls
  the old monolithic google.golang.org/genproto which provides
  googleapis/rpc/status — a path now owned by the split-out
  google.golang.org/genproto/googleapis/rpc that grpc-go imports.
  Workspace mode unifies these two providers and surfaces an
  ambiguous-import build error that single-module mode (GOWORK=off)
  prunes away via MVS. The replace points the workspace at a recent
  monolithic-genproto tag that no longer ships the conflicting path.
  GOWORK=off builds ignore the block entirely.

- builder-config.yaml gains commented-out skeleton entries for the
  future receivers / processors / replaces lines that PR-I.1b and
  PR-I.2 will uncomment — keeps those PRs mechanical (no indentation
  or module-path typo risk).

Verification (all under workspace mode):
- `go build ./...` — clean
- `go vet ./...` — clean
- `go test ./components/... ./internal/... ./pkg/... ./tools/...` — pass
- `make check` (fmt + tidy-check + lint + vet + mod-verify) — clean
- `make verify` (check + license + build-tags + doc-check + zizmor + ...) — clean
- `make build` (OCB) — produces ./_build/tracecore

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Signed-off-by: Tri Lam <tri@maydow.com>
Pre-PR-open self-review surfaced that the prior comment named the symptom
("viper pulls old genproto") but not the deeper root cause. Replaces it
with:

- The grpc-go import path that triggers the collision, with both module
  versions that provide it.
- The Go-internal reason workspace mode shows the conflict and single-
  module mode hides it (MVS pruning gap).
- The "why not bump viper" cul-de-sac (golangci-lint v2.12.2, the latest
  at time of PR, still pins viper@v1.12.0 — verified by running
  `go get golangci-lint@v2.12.2 && go mod tidy && go vet ./...` in this
  worktree before reverting; the conflict re-surfaced).
- The cleanup trigger that retires the replace.

No code change. CI behaviour identical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Signed-off-by: Tri Lam <tri@maydow.com>
Two reviewer findings on PR #214:

1. builder-config.yaml: the commented `replaces:` skeleton was already at
   root-level indentation (zero indent, sibling to `dist:` / `receivers:` /
   `processors:` / `exporters:` / `extensions:`), which matches OCB v0.110.0
   schema (`cmd/builder/internal/builder/config.go` declares `Config.Replaces
   []string \`mapstructure:"replaces"\``) and the canonical upstream pattern
   in `opentelemetry-collector-releases/distributions/otelcol-contrib/
   manifest.yaml` (replaces: as the final root-level block after all
   component lists). Expand the comment to document this placement decision
   so PR-I.1b's uncomment is unambiguously byte-clean.

2. module/doc.go: add a doc.go stub so `module/v0.0.1` (genesis tag cut after
   PR-I.1a merges) resolves through the Go module proxy. Proxies typically
   require at least one .go file in the module root — without doc.go, a
   `go list -m github.com/tracecoreai/tracecore/module@v0.0.1` fetch through
   `proxy.golang.org` may fail and break the PR-I.1b release-tag workflow.

Verified: `go list ./module/...` → `github.com/tracecoreai/tracecore/module`,
`go vet ./module/...` clean, `make check` + `make build` + `go test ./...`
green. Per RFC-0013 design-review root-cause discipline: fix proxy + schema
documentation risks at scaffold time, not post-PR-I.1b failure.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Signed-off-by: Tri Lam <tri@maydow.com>
@trilamsr trilamsr enabled auto-merge (squash) May 31, 2026 09:12
@trilamsr trilamsr merged commit 1785bd6 into main May 31, 2026
13 of 15 checks passed
@trilamsr trilamsr deleted the pr-i-1a-module-scaffold branch May 31, 2026 09:16
trilamsr added a commit that referenced this pull request May 31, 2026
## Summary

RFC-0013 §migration PR-K.2: delete the four in-tree receivers
(`clockreceiver`, `kernelevents`, `k8sevents`, `containerstdout`)
plus the `xidgen` failure-injector (whose sole consumer was
`kernelevents`'s wire shape per RFC §migration L253). PR-K.1
(#211) just severed `internal/synthesis/patterns/` + `replay` from
`k8sevents`, unblocking the source-tree cut. PR-J (#195) shipped
the four upstream-OTel recipes that replace the in-tree receivers
in the bundled Helm-chart pipeline; this PR retires the
behind-the-curtain code.

Chart cleanup (values keys, DaemonSet template refs, `NOTES.txt`
deprecation warnings) intentionally stays in PR-K.3 so operators
get one minor of deprecation telemetry before the values shape
breaks.

> **Branch state note:** PR-F.2 (#215,
`internal/{componentstatus,pipeline,pipelinebuilder,config,consumer,fanout,runtime/lifecycle}`
deletion) and PR-I.1a (#214, `module/` Go submodule scaffold +
`go.work`) both landed on main mid-flight and have been merged into this
branch. The `_test.go` placeholder-name migration originally scoped here
(RFC §migration's "~86 fixture refs" line) is now moot — PR-F.2 deleted
every `internal/*` file that held those refs, so the migration target
evaporated. `make ci` + `make verify` + `make build` re-run green
against the merged tree.

```release-notes
[CHANGE] In-tree receivers clockreceiver/kernelevents/k8sevents/containerstdout deleted in favor of PR-J upstream-OTel recipes. xidgen failure-injector deleted alongside kernelevents (sole consumer).
```

## What lands

### Deletions — receivers (4)

| Path | Files | LOC | Replacement (PR-J recipe) |
|---|---|---|---|
| `components/receivers/clockreceiver/` | 10 | ~1.4k |
`hostmetricsreceiver` (loadscraper @ 1s) — PR-E landed in #180. RFC-0013
§migration originally named `telemetrygeneratorreceiver` but that
receiver does not exist in opentelemetry-collector-contrib (contrib
#41687 + #43657 both closed `not_planned`). |
| `components/receivers/kernelevents/` | 49 | ~13.2k |
[`journaldreceiver` + `filelogreceiver` (kmsg) + OTTL Xid
transform](../blob/main/docs/integrations/journald-kernel.md).
Customer-stable `kernelevents.xid` + `gpu.id` attributes preserved via
the OTTL transform per RFC-0013 §3. |
| `components/receivers/k8sevents/` | 37 | ~6.8k | [`k8sobjectsreceiver`
(watch mode on `events`) + OTTL `k8s.event.hint`
transform](../blob/main/docs/integrations/k8sobjects-events.md).
11-entry hint enum preserved via the OTTL transform per RFC-0013 §3. The
typed `internal/synthesis/patterns/Record` + `NodeRecord` (severed in
PR-K.1) keeps M19's pod-evicted detector pinned. |
| `components/receivers/containerstdout/` | 56 | ~6.4k |
[`filelogreceiver` + container stanza + `file_storage`
extension](../blob/main/docs/integrations/filelog-container.md).
Per-rank attribution + dataloader-timing extraction move to OTTL
transforms in the bundled recipe per RFC-0013 §3. |

### Deletions — supporting infra

| Path | Why |
|---|---|
| `tools/failure-inject/xidgen/` (2 files, 281 LOC) | Sole consumer was
the kernelevents wire shape per RFC-0013 §migration L253. Operators
inject NVRM Xid via real `/dev/kmsg` (`sudo tee`) or `systemd-cat`
against the journald recipe. |
| `install/kubernetes/tracecore/ci/containerstdout-on-values.yaml` (41
LOC) | Chart-render fixture for the deleted receiver. Remaining chart
fixtures (`all-receivers-off-values.yaml`,
`one-receiver-on-values.yaml`, `pyspy-on-values.yaml`) untouched; their
`clockreceiver: enabled: false` / `kernelevents: enabled: false` rows
survive to PR-K.3's chart cleanup. |
| `.github/ISSUE_TEMPLATE/component-bug-kernelevents.yml` |
Receiver-specific bug template; no surviving receiver. |

### failure-inject CLI surface

`failure-inject xid --code=N [--format=…] [--count=N]` removed.
`failure-inject {pod-evict,nccl-hang,cpu-steal}` unchanged.
`tools/failure-inject/testdata/golden.sha256` drops the two `xid`
golden rows. `.github/workflows/chaos.yml` drops the two
two-run-determinism steps that exercised the xid byte-determinism
contract; pod-evict's determinism + the golden-SHA replay loop
survive.

### Tooling shed

- `Makefile`: retire `test-extras-sustained` body (was kernelevents-
  only; now `@true` — target retained so downstream automation has
  a stable name; future sustained-load suites slot back in).
  Retire `test-extras-fuzz-kmsg` / `test-extras-fuzz-journald`;
  `test-extras-fuzz` loop drops to nccl-fr only. Drop the
  kernelevents row from `test-extras-race`. Empty the `bench-check`
  for-loop (k8sevents was the only baseline; PR-F.2 already
  rewrote the comment block to reflect this — the merge keeps
  both edits aligned).
- `go.mod`: sheds
`k8s.io/{api,apimachinery,client-go,klog/v2,kube-openapi,utils}`,
  `sigs.k8s.io/{json,randfill,structured-merge-diff/v6,yaml}`,
  `gopkg.in/{evanphx/json-patch.v4,inf.v0}` — the dep cluster
  k8sevents dragged in. `go.uber.org/goleak` also dropped post-
  merge (was held only by PR-F.2's-deleted
  `internal/pipeline/chaos_test.go`).

### Doc + comment sweep

Comment-only references to deleted receivers in
`components/exporters/{otlphttp,stdoutexporter}/`,
`components/receivers/{nccl_fr,pyspy}/`,
`internal/synthesis/patterns/{doc,model,verdict}.go` rewired to
surviving references (or to upstream recipe pointers).
`docs/README.md` per-component-docs table drops five dead links
(caught by `doc-check.sh`'s rotten-link gate — that is in fact
how I caught the last drift). `bench/install/README.md`
tick-alias note + schema-v2-rename note updated.
`tools/failure-inject/README.md` xid section removed; status
banner rewritten.

CHANGELOG (new PR-K.2 entry under Unreleased + wave-4 paragraph
re-balanced), MILESTONES (M1 + M9 + M10 + M15 status lines flipped
from "DELETED at v0.2.0" → "DELETED in PR-K.2" with file pointers
to the integration recipes), `docs/migration/v0.1-to-v0.2.md`
(PR-K.1 + PR-K.2 checkboxes flipped, PR-F.2 + PR-I.1a status
block updated post-merge), AGENTS.md (queued-for-deletion
paragraph updated to current reality) all swept.

### What evaporated mid-flight

Originally this PR was also going to migrate a handful of
`_test.go` files that held placeholder-name string references
to `clockreceiver` (in `internal/pipeline/saferun_test.go`,
`internal/config/fuzz_test.go`,
`internal/pipelinebuilder/fuzz_test.go`).
PR-F.2 (#215) deleted those files outright while this branch
was being drafted, so the migration target disappeared. No
follow-up needed.

## Net LOC delta

```
192 files changed, 120 insertions(+), 28,927 deletions(-)
```

## What is intentionally NOT in this PR

- **Helm-chart `receivers.clockreceiver` / `receivers.kernelevents`
  / `receivers.containerstdout` toggles + DaemonSet template refs
  + `containerstdout-rbac.yaml` template** — stays for PR-K.3 so
  operators see `NOTES.txt` deprecation warnings before the values
  shape breaks. The toggles are already inert post-PR-A2 (enabling
  any of them in `values.yaml` crashes the OCB binary at boot
  because the factories are not registered) — keeping them as
  no-ops for one minor preserves operator UX.
- **`internal/{componentstatus,pipeline,…}/` deletion** — already
  done in PR-F.2 (#215) before this branch landed; merged in.
- **Chart `values.yaml` `# clockreceiver — in-tree heartbeat
  retired by RFC-0013 PR-A2` style retire-banners** — stays for
  PR-K.3 alongside the actual values-keys cleanup.
- **`tools/failure-inject/ncclhang/`** — KEPT. Used by
  `pkg/nccl/fr_parser/synthesize_test.go` +
  `bench/overhead/nccl_fr_bench_test.go`; this is the canonical
  example of a failure-injector that survives the v0.2.0 cut.

## Root cause

The four receivers + xidgen survived only because PR-K.1's pattern-
library severance from `k8sevents` was still in flight. With #211
merged at the start of this session, the deletion is unblocked.
There is no workaround being applied here — this PR is the
root-cause deletion of the in-tree receivers themselves, which
RFC-0013 §migration set as the v0.2.0 deletion target.

## Test plan

- [x] `make ci` green post-merge (verify + license + nccl-fr-rce-gate +
      register-lint + actionlint + zizmor + coverage-check +
      ci-fuzz-nccl-fr + govulncheck + doc-check + no-autoupdate-check +
      build).
- [x] `make verify` green post-merge.
- [x] `make build` green post-merge (OCB compile against
      `builder-config.yaml` with `GOWORK=off` per the PR-I.1a
      isolation guard yields `./_build/tracecore`).
- [x] `go test ./...` green across the post-merge tree.
- [x] Hard pre-flight: zero external Go importers for any
      deletion target (`clockreceiver`, `kernelevents`, `k8sevents`,
      `containerstdout`, `xidgen`) — re-verified after the merge.
- [ ] CI: `chart-render` job validates the surviving chart fixtures
      (`all-receivers-off-values.yaml`, `one-receiver-on-values.yaml`,
`pyspy-on-values.yaml`); the deleted `containerstdout-on-values.yaml`
      drop-out should not regress conftest coverage of the
      containerstdout-allowlist / operational-invariant rules
      because the template guard still fires when
      `containerstdout.enabled=true` is set in any future values
      file. PR-K.3 will reassess once the chart-side keys go.
- [ ] CI: `install (kind)` job continues to render the bench
      tracecore-values.yaml against the OCB binary
      (hostmetricsreceiver heartbeat surface).
- [ ] CI: `harness-determinism (amd64/arm64)` job no longer runs
      the xid byte-determinism steps; pod-evict + golden-SHA loop
      survive. Expected: 2 fewer steps per matrix arm.

## Gates that should fail this PR if I missed something

- `doc-check`'s "dead markdown link" gate would catch any
  surviving link into the deleted dirs (caught the
  `docs/README.md` regressions on the first run; fixed and
  re-verified).
- `go vet ./...` would catch a stale import; ran clean.
- `golangci-lint run ./...` would catch unused imports or dead
  code introduced by the sweep; 0 issues reported.
- `go mod tidy -diff` would catch a missing dep prune; ran clean
  after the post-merge prune of `go.uber.org/goleak`.

Refs RFC-0013 §migration PR-K.2.

Signed-off-by: Tri Lam <tri@maydow.com>
Co-authored-by: Tri Lam <tri@maydow.com>
trilamsr added a commit that referenced this pull request May 31, 2026
## Summary

Two related fixes for `install-bench` CI which has been failing since
PR-I.1a (#214) introduced `go.work` workspace mode.

### Root cause

PR-I.1a (#214) added `module/go.mod` + root `go.work` listing `use ( .
./module )`. The Makefile's OCB invocation correctly sets `GOWORK=off`
to avoid workspace-mode collisions, but the
`install/kubernetes/tracecore/Dockerfile` inner re-link step (`cd _build
&& go build .`) did NOT propagate `GOWORK=off`. Workspace mode then
tries to resolve `_build/` as a workspace member, fails w/ `main module
does not contain package github.com/tracecoreai/tracecore/_build`.

Secondary issue: `Makefile fmt` + `license-check` targets walk the full
repo tree including `.claude/worktrees/agent-*/_build/` from concurrent
subagent worktrees, falsely flagging OCB-generated code as gofumpt-dirty
/ missing SPDX.

### Fixes

1. **`install/kubernetes/tracecore/Dockerfile:25`** — add `GOWORK=off`
to the inner `go build` so the distroless-friendly re-link works under
workspace mode.
2. **`Makefile fmt + license-check`** — extend the existing `_build/`
exclusion to also skip `.claude/worktrees/` so subagent worktrees don't
pollute pre-commit/pre-push gates.
3. **`.gitignore`** — formally ignore `.claude/worktrees/` (was missing;
matches existing pattern for `.claude/scheduled_tasks.lock` etc.).

## Test plan

- [x] `make fmt` clean
- [x] `make license-check` clean
- [x] `make check` clean
- [ ] CI `install-bench` passes on this branch (validates root cause)
- [ ] CI `install (kind)` passes on this branch

```release-notes
NONE
```

Signed-off-by: Tri Lam <tri@maydow.com>
Co-authored-by: Tri Lam <tri@maydow.com>
trilamsr added a commit that referenced this pull request May 31, 2026
#224)

## Summary

RFC-0013 §migration **PR-I.1b** — mechanical move of `nccl_fr` receiver
+ safe-pickle parser into the in-repo Go submodule scaffolded by #214.

- `git mv components/receivers/nccl_fr → module/receiver/ncclfrreceiver`
(Go package renamed `ncclfr → ncclfrreceiver` to match the OCB receiver
name; **OCB component type string `nccl_fr` unchanged** — operator
scrape names + dashboards do not regress, per PR-B1 metric-namespace
decision).
- `git mv pkg/nccl/fr_parser → module/pkg/nccl/fr_parser`.
- `builder-config.yaml` uncomments the PR-I.1a placeholder: adds `gomod:
github.com/tracecoreai/tracecore/module v0.1.0` + `import:
github.com/tracecoreai/tracecore/module/receiver/ncclfrreceiver` (split
because the single-`go.mod` submodule puts the receiver one path-segment
below the module root — a per-component `gomod:` would fail since
`module/receiver/ncclfrreceiver/` has no `go.mod` of its own).
- Root-level `replaces: github.com/tracecoreai/tracecore/module =>
../module` (`../module`, not `./module`, because OCB writes the replaces
verbatim into `./_build/go.mod`, one directory deeper than repo root).
- `module/go.mod` pins collector deps to **v0.110.0** + otel to
**v1.30.0** (the OCB-distribution baseline). MVS inside `_build/go.mod`
would otherwise pull forward to v1.59.0 — `scraperhelper` was split out
of `collector/receiver` between those two release lines, which would
break the `hostmetricsreceiver@v0.110.0` build added in PR-E.
- Root `go.mod` adds `replace github.com/tracecoreai/tracecore/module =>
./module` + matching `require` so `go mod tidy` (which ignores
`go.work`) resolves the submodule from the in-repo checkout rather than
the proxy. (Drops the first time a release builds against a published
`module/vX.Y.Z` tag.)
- Importers updated in root: `tools/genfixtures` (+ `-out` default),
`bench/overhead/nccl_fr_bench_test.go`, `scripts/nccl-fr-rce-gate.sh`
(runs `go list -deps` from inside `module/`), `Makefile`
(`generate-fixtures` / `test-extras-fuzz-nccl-fr` / `ci-fuzz-nccl-fr` /
`nccl-fr-rce-gate`), `.github/workflows/nccl-fr-fuzz-nightly.yml`, and
two doc-comment refs in
`components/exporters/stdoutexporter/selftel{,_test}.go`.
- OTel instrumentation scope on `selftel.go` moves to the new Go import
path
(`github.com/tracecoreai/tracecore/module/receiver/ncclfrreceiver`),
OTel convention: scope = Go import path.

**No operator-visible metric/log-data regression** — receiver type
string + metric instrument names unchanged across the OCB wire boundary.
The OTel instrumentation scope name does move (per OTel convention scope
= Go import path; matches bullet 7 + RFC-0013 §Migration + CHANGELOG),
but the scope is a logger/meter attribute, not part of metric instrument
names or the component-type-string operators configure against — so
dashboards and scrape jobs do not regress.

Post-merge: tag `module/v0.1.0 <merge-sha>` (the first version pinned in
`builder-config.yaml`).

## Test plan

Locally run + green on this branch (verified at commit `da44388`;
subsequent commits are an `origin/main` merge + a `doc-check.sh`
`scan_paths` fix-up that prunes three docs deleted by #215/#217 — no
source semantic change):

- [x] `make check` — fmt, golangci-lint, vet, mod-verify (0 issues).
- [x] `make verify` — license-check, generate-fixtures-check,
build-tags, **nccl-fr-rce-gate** (parser depends only on stdlib),
register-lint, actionlint, zizmor, doc-check, no-autoupdate-check.
- [x] `make build` — OCB v0.110.0 builds `./_build/tracecore` with the
submodule receiver wired in.
- [x] `./_build/tracecore components` — confirms `nccl_fr` receiver
registered (alongside hostmetrics, filelog, journald, k8sobjects, otlp,
prometheus).
- [x] `go test ./...` (root module).
- [x] `cd module && go test ./...` (submodule:
`module/pkg/nccl/fr_parser` + `module/receiver/ncclfrreceiver`).
- [x] `make ci-fuzz-nccl-fr` — 30s `FuzzParseFRPickle` on the moved
parser, no crashers.
- [x] `bash scripts/nccl-fr-rce-gate.sh` — parser deps clean (no
`os/exec`, `plugin`, `reflect.Call`, `reflect.MakeFunc`).

CI to confirm:

- [ ] All required checks green on this PR.
- [ ] `nccl-fr-fuzz-nightly` runs against the new path on next nightly
trigger.

Post-merge:

- [ ] Tag `module/v0.1.0 <merge-sha> && git push origin module/v0.1.0`.

## Why this is a root-cause fix, not a workaround

Two non-obvious decisions in this diff — both root-cause, not
workarounds:

1. **`replaces: ../module` (not `./module`) in builder-config.yaml.**
OCB writes the `replaces:` directive verbatim into `./_build/go.mod`.
Paths in `go.mod` resolve relative to that file's directory, which is
one level deeper than repo root. `./module` would fail to resolve;
`../module` resolves correctly to `<repo>/module/`.
2. **`module/go.mod` pins collector v0.110.0, not the root's v1.59.0.**
OCB's MVS reconciles `_build/go.mod`'s require graph against the
submodule's `go.mod`. If the submodule pinned the higher version, MVS
pulls forward inside `_build/go.mod` and `hostmetricsreceiver@v0.110.0`
(added in PR-E to replace `clockreceiver`) fails to build because
`scraperhelper` moved out of `go.opentelemetry.io/collector/receiver`
between v0.110.0 and v1.59.0. The root module independently uses v1.59.0
for its non-OCB code paths; MVS reconciles to the higher version where
root + submodule overlap, which is fine for root.

```release-notes
none
```

---------

Signed-off-by: Tri Lam <tri@maydow.com>
Co-authored-by: Tri Lam <tri@maydow.com>
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