Conversation
…, informational on next)
…ags, WithOTelConfig presence)
…cord Phase 1 review follow-ups
BREAKING CHANGE: module path is now github.com/jasoet/pkg/v3; consumers must update imports.
BREAKING CHANGE: the logging package is removed. Migrate: logging.Initialize -> otel.Initialize, logging.InitializeWithFile -> otel.InitializeWithFile, logging.ContextLogger -> otel.ContextLogger, logging.LogLevel -> otel.LogLevel (identical signatures).
BREAKING CHANGE: NewConfig now takes variadic Option; With*/Disable* methods on *Config removed (use package-level options); DisableTracing/DisableMetrics renamed WithoutTracing/WithoutMetrics.
BREAKING CHANGE: LoadStringWithConfig and NestedEnvVars removed; use LoadStringWithOptions with WithEnvPrefix/WithDefaults/WithNestedEnvVars.
BREAKING CHANGE: Config builder methods removed (use retry.New with options); WithOTel renamed WithOTelConfig; Config.OperationName renamed Config.Name; invalid configs now error at Do time instead of panicking in setters.
… add keyDepth migration note
… API BREAKING CHANGE: MakeRequest/MakeRequestWithTrace return *rest.Response; Is* package funcs replaced by Response methods; IsUnauthorized renamed IsAuthError; RequestInfo.TraceInfo is now rest.TraceInfo.
…ty retry hook BREAKING CHANGE: NewUnauthorizedError/NewExecutionError/NewServerError/NewResponseError/NewResourceNotFoundError and RecordRetry are no longer exported (error types remain exported for type switches).
…e-checked examples
…n tracing BREAKING CHANGE: (*ConnectionConfig).Pool() removed; use db.NewPool(db.WithConnectionConfig(cfg)).
BREAKING CHANGE: ExecuteConcurrentlyTyped type parameters are now [R, T] (result first).
…en tests; correct doc values
…APIs - README/INSTRUCTION/AI_PATTERN/PROJECT_TEMPLATE now describe the v3 module (14 packages; logging merged into otel) instead of the frozen v2 world - replace removed db APIs (ConnectionConfig.Pool, RunPostgresMigrationsWithGorm) with db.NewPool(WithConnectionConfig, WithOTelConfig) + RunPostgresMigrations - fix stale /v2 import paths and coverage claims in fullstack-otel example and release guide
- proxy warmup targeted /v2 (silently no-op on every v3 tag) -> /v3 in both Taskfile and release workflow - drop invalid -tags=!examples from test steps (negation is not valid tag syntax) - add a go vet pass over example/integration/argo-tagged code so tagged-only regressions can no longer slip past CI
…events
- route URL-shaped OTLP endpoints through WithEndpointURL (bare host:port keeps
WithEndpoint); a scheme-prefixed endpoint previously mangled the export URL and
silently dropped all logs
- LayerContext.Error now records on the span exactly once (was emitting two
exception events and inflating error counts)
- InitializeWithFile returns a genuinely nil io.Closer for console-only output
- apply options before building the default LoggerProvider; validate before any
global-state mutation; add trace-correlation + severity-mapping tests
BREAKING CHANGE: WithOTLPEndpoint("") now errors instead of silently disabling
OTLP export; the nil-config zerolog fallback defaults to Info and labels the
emitter as 'scope' rather than 'service'.
…-After - normalize request headers into a private copy before the middleware chain, fixing a nil-map panic (hit by the documented OTel example) and a data race that mutated the caller's map - retry only idempotent methods by default (opt in with WithRetryNonIdempotent); stop retrying permanent errors (url/x509/context); retry 429 and honor Retry-After - store OTel config on the client and merge after all options so option order no longer disables telemetry - redact userinfo/secrets from url.full, carry true response size, fractional-ms durations; real in-memory exporters in OTel tests BREAKING CHANGE: POST/PATCH are no longer retried by default; ExecutionError and UnauthorizedError messages now include the cause/response body.
- derive the real status from the handler error after next() so errors and 404s are no longer recorded as 200, and set span status Error for 5xx - fractional-millisecond request duration; install Recover() and order OTel middleware outermost so rejects are observed - add WithBindAddress, tag func-typed config fields, redact sensitive query params, document built-in limits/timeouts
- rewrite the Struct Tags section: mapstructure (or dual) tags are required for keys that differ from the lowercased field name (plain yaml tags silently drop) - anchor env-prefix matching on a trailing underscore and reject empty prefixes so foreign vars (APPLE_*) no longer pollute config - use InConfig so nested env vars beat defaults; document the AutomaticEnv limitation
- ExecuteConcurrentlyTyped rejects a nil resultBuilder before execution instead of panicking after all work completes - include the goroutine stack trace in recovered-panic errors - correct three misleading claims in the example README (error timing, the item-dropping concurrency snippet, partial-results)
- return an error for a nil operation instead of panicking (matches the docs) - wrap both ctx.Err() and the last operation error on cancellation so errors.Is finds the real failure - do not run the operation when the context is already cancelled; add WithUnlimitedRetries; cover the OTel path with an in-memory exporter
- back off / exit the accept loop on persistent errors instead of spinning at 100% CPU on a non-shutdown listener error - reserve a starting sentinel so concurrent Start calls cannot both proceed - dial via net.Dialer.DialContext + ssh.NewClientConn so ctx aborts the connect
- refuse a pre-existing leaf symlink at the target (Lstat + O_NOFOLLOW), closing an arbitrary-file-overwrite-outside-destination hole - open with O_TRUNC so a shorter file fully replaces a longer one - enforce WithMaxArchiveSize mid-file (LimitReader) instead of after the write, and remove partial output on size/IO error; accept a relative '.' destination
…rors - normalize in StripChecksum/ExtractChecksum and strip separators in DecodeBase32 so a string ValidateChecksum accepts round-trips correctly instead of silently yielding a wrong payload - add errors.Is-matchable sentinels (ErrEmptyInput, ErrInvalidCharacter, ErrOverflow, ErrValueTooLarge); correct the generator-polynomial doc; document the leading-zero CRC blind spot; add fuzz tests
- build the H2C http.Server with ReadTimeout/WriteTimeout=0 (keeping ReadHeaderTimeout/IdleTimeout) so long-running and streaming RPCs are no longer killed by the default 5s/10s HTTP timeouts - extract trace context with an explicit TraceContext+Baggage propagator instead of the never-set global; add a stream tracing interceptor and forward traceparent through the gateway annotator - order tracing before logging so access logs carry trace_id/span_id; surface an error when GracefulStop times out; register uptime metrics once across restarts - per-check health timeouts, signal.Stop cleanup, rate-limit validation, and port-polling (not sleep) in tests
- snapshot the client and container id under RLock in every client-using method and return an error when closed, fixing a data race and nil panic after Close() - remove the created container and clear state when ContainerStart fails; run wait and start cleanup on context.WithoutCancel so a canceled caller ctx cannot leak a running container - surface in-stream image-pull errors; use WaitConditionRemoved with AutoRemove; derive the host from DaemonHost() so remote Docker/Podman daemons work - tag daemon-dependent tests with //go:build integration and replace hardcoded ports/names and sleeps with :0 mapping, unique names, and Wait
…onns - map the default SSLMode 'require' to a valid go-mssqldb encrypt value and validate MSSQL SSLMode, so an MSSQL pool connects out of the box - quote/escape Postgres DSN values and build the MSSQL DSN via net/url, closing a DSN parameter-injection / TLS-downgrade hole for special-character credentials - run migrations on a dedicated checked-out connection (postgres.WithConnection) so m.Close() no longer closes the caller's pool or pins a connection for process life - default zero pool sizes, close the pool on failed NewPool, avoid duplicate metrics on the global provider, and round sub-second timeouts up
- pass user commands as shell fragments in MapReduce/ParallelDataProcessing/ ParallelTestSuite (quoting only data args) so generated workflows no longer try to exec a program literally named e.g. 'wc -w' and fail at runtime - apply the default retry strategy to leaf templates only (not the entrypoint or exit-handler steps templates, which would re-run succeeded steps) - deep-copy builder-owned maps/slices/templates in Build so a built workflow cannot mutate the builder or other results - join all builder errors and add sentinel errors (ErrWorkflowFailed, ErrWaitTimeout, ErrTemplateConflict, ErrNilConfig); SubmitAndWait wraps context errors and aborts on permanent poll failures; wire real ContinueOn/status gating into ConditionalDeploy; sort ParallelTestSuite output; validate nil config and empty inputs
- WorkflowManager list/count/history use the high-level client APIs so every method targets the client's configured namespace instead of a hardcoded 'default', and raw-gRPC calls no longer bypass the tracing interceptor - job.History keys in-flight activities by scheduled-event id so concurrent activities are attributed to the correct step - StartAll stops already-started workers on failure; Close is idempotent; per-worker registrars replace the never-evicted global dedup maps - add WithTLS/WithCredentials/WithClientOptions (Temporal Cloud), wire schedule CatchupWindow and Args, honor StatsOpts.TodayOnly and HistoryOpts.MaxEvents, make DeleteSchedules converge, fix the logger caller skip, and replace can't-fail integration guards with require; fix the string(int) bug in the timer example
…pass - add db.WithOTelConfig to the options contract registry (it was missing though the function exists) and assert the expected compliant-package set so a dropped registry entry fails instead of passing vacuously - document grpc's sanctioned unexported-config exemption and refresh the stale rest ClientOption note
- fix misspellings (canceled/canceling/dialing) flagged by misspell - drop redundant trailing newlines from fmt.Println in examples (go vet) - wrap an over-long error string (lll); extract shouldRetryRequest from NewClient to bring cyclomatic complexity back under threshold - tag docker/testutil_test.go integration so its daemon-only helpers are not reported unused in the default build
grpc TestServerStopDuringStartNoZombie: freePort reserves an ephemeral port then releases it before the server binds, so under load Start can lose the race with 'address already in use'. That is infrastructure noise orthogonal to the zombie behavior under test, so retry the iteration with fresh ports instead of failing. temporal ExecuteSimpleWorkflow: Temporal workflow functions take workflow.Context, not context.Context; the integration test used the latter, so the SDK miscounted the arguments and ExecuteWorkflow failed with 'expected 2 args ... but found 1'. The bug was previously masked by a log-and-return guard now replaced with require.NoError.
TestStopGracefulTimeoutReturnsError's health handler blocked on <-release and ignored its context, so the forced Stop that follows a graceful-timeout could not cancel it: grpcServer.Stop() waited on the stuck handler and the test deadlocked (a 10m timeout under the runner's -race timing, though it passed locally). Select on ctx.Done() as well so the handler returns when the forced Stop cancels the RPC, while still blocking through the graceful window so the timeout path is exercised.
#59) ## Problem The blocking `API compatibility check` step was guarded by: ```yaml if: github.ref_name != 'next' && github.base_ref != 'next' ``` On the eventual `next` → `main` v3 pull request, `base_ref` is `main` and `ref_name` is the merge ref — neither equals `next`, so the **blocking** gate fires and reports the whole intended v3 break set. The release PR would have been unmergeable. Verified locally against a clean tree at this commit: ``` # summary Inferred base version: none Suggested version: v3.0.0 ``` Also, a gate that can block a merge was floating on `gorelease@latest` — not reproducible. ## Change - Add `github.head_ref != 'next'` to the blocking condition and `|| github.head_ref == 'next'` to the informational one, so anything involving `next` reports without gating. - Pin gorelease to `v0.0.0-20251113190631-e25ba8c21ef6`, the `golang.org/x/exp` pseudo-version already in `go.mod`. Exposed as a workflow-level `env` var so both steps stay in lockstep. - Document the "no baseline until the first non-prerelease /v3 tag" behaviour in a comment, since that is expected output for the release PR. - Fix the stale `/v2` module path in the `.golangci.yml` header comment. Closes the first two "Open Process Items" in `docs/plans/2026-07-22-v3-audit-backlog.md`.
## Problem Both HTTP tracing middlewares started their server span from the raw request context: ```go ctx, span := tracer.Start(req.Context(), ...) // server/otel_middleware.go ctx, span := tracer.Start(ctx, ...) // grpc gateway ``` No `Extract`, so an inbound `traceparent` header was discarded and **every server span became a new root**. This is inconsistent within the library itself: | path | behaviour | |---|---| | `rest` client outbound | injects `traceparent` ✅ | | `grpc` unary/stream interceptors | extracts ✅ | | `server` HTTP middleware | **dropped** ❌ | | `grpc` gateway HTTP middleware | **dropped** ❌ | So a `rest` → `server` call made with this library on both ends rendered as two disconnected traces. ## Change Extract W3C trace context + baggage from request headers before starting the span, reusing the composite propagator the gRPC interceptors already use. With no inbound headers this is a no-op and the span is still a root. ## Tests (written first, observed failing) New tests assert the span joins the caller's trace. Before the fix: ``` expected: "4bf92f3577b34da6a3ce929d0e0e4736" actual : "a1be0badcd4d1db205624bba8acf1c48" <- fresh root expected: "00f067aa0ba902b7" actual : "0000000000000000" <- no parent ``` Added for both packages, plus a companion test pinning the no-header case to a root span so the fix can't regress into always-remote-parent. ## Verification `task ci:check` — all packages pass, golangci-lint 0 issues. `go vet -tags='example integration argo' ./...` clean. ## Note for the migration guide Existing users gain correctly-parented server spans. Traces that previously appeared as separate roots will now join their caller — a visible change in any tracing backend, in the correct direction. Closes the "Shared gap (server + grpc)" item in `docs/plans/2026-07-22-v3-audit-backlog.md`.
## Problem `container.InspectResponse.NetworkSettings` is a **pointer**, and the daemon leaves it `nil` for containers without networking (`--network=none`, and some podman responses). Four exported `Executor` methods dereferenced it unconditionally and panicked: | method | line | |---|---| | `MappedPort` | `network.go:86` | | `GetAllPorts` | `network.go:147` | | `GetNetworks` | `network.go:175` | | `GetIPAddress` | `network.go:205,212` | `ContainerTarget.State` (`target.go:87`) already guards this exact field — these four were the gap. Recorded as "docker NetworkSettings parity" in `docs/plans/2026-07-22-v3-audit-backlog.md`. ## Change The projection logic was entangled with the client call, which is why the nil case had never been tested — it needs a live daemon to reach. Extracted four pure functions of an inspect response (`portBinding`, `allPortBindings`, `networkNames`, `networkIPAddress`) and guarded there, so the nil path is unit-testable without Docker. Behaviour: - `GetAllPorts` / `GetNetworks` return an empty map/slice instead of panicking — callers range over the result, so nil would be a second footgun. - `MappedPort` / `GetIPAddress` return their existing not-found errors unchanged. - Also stopped dereferencing `nil` `EndpointSettings` values inside the `Networks` map, which was a second latent panic. No public signature changes. ## Tests (written first, observed failing) New `docker/network_test.go` — the first run failed to compile (`undefined: portBinding`, …), driving the extraction. 17 cases covering bound/unbound/missing ports, named vs first-available network lookup, nil `NetworkSettings`, and nil `EndpointSettings`. These raise docker's unit coverage without needing a daemon, which matters since the package sat at 41% precisely because most paths require one. ## Verification `go test ./docker/` passes; `golangci-lint run ./docker/...` 0 issues. Full `task ci:check` green on this change.
## Why v3 carries **22 commits with `BREAKING CHANGE` footers** and had no consumer-facing migration document — the single largest gap blocking the v3.0.0 release. Worse, several breaks shipped in `fix:`-typed commits **without** footers, so semantic-release will never surface them: - `temporal.WorkflowManager.Close` removed entirely (commit `cadc208`'s footer omits it) - `rest.Client.HandleResponse` unexported (`6cc5af1`) - `grpc.MountGatewayOnEcho` now strips the base path; `Start*` return `nil` instead of `http.ErrServerClosed`; `GetGRPCServer()` returns nil after `Stop` - `server` **signal handling removed** — consumers silently lose graceful termination, and nothing fails to compile to tell them `MIGRATION.md` states each of these explicitly. ## Accuracy Every signature in the guide was verified against the code, not against the audit backlog's notes. That caught two places where the backlog described a *planned* API that did not ship: | backlog said | actually shipped | |---|---| | `temporal.NewClient` accepts/returns a ctx | `NewClient(opts ...Option) (client.Client, error)` | | `argo` operations keep a `namespace` param | `SubmitWorkflow(ctx, client, wf)` — no namespace | Both are documented as built. All 14 packages covered, plus a closing section on telemetry changes that need no code edit but will move dashboards. ## ADRs Five decisions a future reader would otherwise have to reverse-engineer: | ADR | Decision | |---|---| | 0001 | Freeze v2, ship v3 as one big bang (module-path versioning is what makes it cheap) | | 0002 | OTel config is injected, never serialized — a half-deserialized provider set is worse than none | | 0003 | Constructor naming: `New` for the primary type, `New<Thing>` when there are several | | 0004 | Selective de-leak — utility packages hide their dependency, SDK-integration packages don't | | 0005 | `grpc` restarts, `server` doesn't; and the `http.server.*` attribute-set divergence | ADR 0003 resolves the "constructor naming split" backlog item as **not a defect** — `retry.New` returns a `Config` because a `Config` *is* retry's primary artifact. The rule already holds; renaming would have added breaks that make call sites worse. `CONTEXT.md` pins the vocabulary those depend on (utility vs SDK-integration package, selective de-leak, escape hatch, convention contract, docs-of-record). ## Also - `README.md` claimed v2/v3 arrive "with minimal API changes". Corrected. - `INSTRUCTION.md` gains `MIGRATION.md`, `CONTEXT.md` and `docs/adr/` in Key Paths, plus a note to update the guide **as breaks land** rather than at release time. All relative links in the new docs verified to resolve.
## Coverage figures
Stale in **both** directions, and three packages had none. Regenerated
from a real unit+integration run (`-tags=integration`, Docker-backed
testcontainers):
| package | README said | actual |
|---|---|---|
| server | 77.1% | **97.0%** |
| grpc | 71.2% | **82.0%** |
| ssh | 78.2% | **85.6%** |
| db | 76.7% | **83.5%** |
| concurrent | 95.1% | **100.0%** |
| otel | 84.8% | 89.5% |
| compress | 82.4% | 85.3% |
| temporal | 81.2% | 84.5% |
| docker | 83.1% | 84.1% |
| config | 97.6% | 96.4% |
| rest | 92.9% | 93.0% |
| **argo** | *missing* | **94.8%** |
| **retry** | *missing* | **100.0%** |
| **base32** | *missing* | **100.0%** |
The README also told readers to open `output/coverage-all.html` — no
task produces that file — and described a methodology that did not match
the task it named. Now: figures come from `task test:integration` →
`output/coverage-integration.html`; `task test:complete` additionally
runs argo (needs k8s) → `output/coverage-complete.html`.
## examples/otel was entirely pre-v3
`/v2` import path, struct-literal configs throughout, and a link to
`otel/examples/example.go` — a directory that does not exist.
The **example program itself** used `&otel.Config{...}`. That still
compiles, but `loggerProviderSet` is unexported, so a struct literal
silently skips the default zerolog logger provider that `NewConfig`
installs. The example was teaching a pattern that quietly loses logging.
Converted to functional options; verified the program still prints its
documented output (the no-op example needed an explicit
`WithoutLogging()` to stay all-false, which is exactly the trap worth
showing).
## Broken links and unrunnable instructions
- `docker/README.md` linked the deleted `logging` package and said
"OpenTelemetry v2".
- Three READMEs linked a `CONTRIBUTING.md` that was never written.
Rather than delete the promise, wrote the file — the workflow it
describes already existed, scattered across README and INSTRUCTION.
- `examples/grpc/README.md` linked `../README.md` (nonexistent
`examples/README.md`).
- `examples/compress` and `examples/ssh` gave run instructions from
`<pkg>/examples/` directories that do not exist, and omitted the
`example` build tag — so they could not have worked. Both verified with
`go build -tags=example`.
Full markdown link scan now clean except two links inside historical
`docs/plans/` records, deliberately left as point-in-time documents.
## Backlog hygiene
Split resolved from open, each with a pointer to where the fix landed.
Notably, two entries were **verified still present rather than assumed
fixed**: `ssh`'s accept-loop reads `t.stopCh` unlocked at three points
while `Start` reassigns it under `t.mu`, and `t.wg.Add` after `Accept`
still races `Close`'s `wg.Wait`. Only the busy-spin half of that item
was ever fixed. Recorded with line numbers; left open deliberately as a
v3.x item.
Two backlog items are now closed as **decisions rather than defects** —
docker's `Inspect`/`GetStats` escape hatches (ADR 0004) and the
server/grpc lifecycle divergence (ADR 0005).
## Verification
`task ci:check` green (0 lint issues), `go vet -tags='example
integration argo' ./...` clean, `CLAUDE.md` == `AGENTS.md` parity
confirmed.
…64) ## Symptom The Release pipeline failed twice in a row on the db integration suite — **a different test each time**, same signature: ``` --- FAIL: TestOTelCallbacksTableAndRowsAffected (10.77s) # run 1 --- FAIL: TestPostgresMigrationsInvalidPath (10.52s) # run 2 (re-run) failed to ping database at localhost:33451/testdb: [::1]:33451 failed to receive message: unexpected EOF 127.0.0.1:33451 read: connection reset by peer ``` Both ~10s in — **well inside the 60s deadline**, so not a timeout. Both pass locally. The triggering commit was docs-only. ## Root cause The wait strategy, not the tests. The postgres image runs `initdb` against a **temporary** server, stops it, then starts the real one. All eight Postgres containers in this package waited only on the mapped port: ```go wait.ForListeningPort("5432/tcp").WithStartupTimeout(60*time.Second) ``` So the container could be declared ready while the server was on its way down, and the connection that followed got reset. This is documented in testcontainers-go itself — `postgres.BasicWaitStrategies()`: > First, we wait for the container to log readiness **twice**. This is because it **will restart itself after the first startup**. > […] For non-linux OSes like **Mac** […] Docker will have to start a separate proxy. **Without this, the tests will be flaky on those OSes!** The db tests used only the *second half* of that pair. The runner is a Mac. That also explains the intermittency and why a docs commit "caused" it: the window is invisible on an idle machine and opens under CI load. MySQL and MSSQL in the same file were never affected — they already wait on a real query via `wait.ForSQL`, with a comment saying so. ## Fix Add the occurrence-2 log check alongside the port check, behind one shared helper (`postgresReady()`) so the strategy can't drift back one call site at a time, with a deadline sized for a loaded runner. 8 call sites across 3 files now share it. Confirmed no other package is affected: every `postgres.Run` in the repo is in `db/`, and the remaining `ForListeningPort` uses (Temporal, sshd) are services that don't restart themselves during init. ## Verification | condition | result | |---|---| | db integration, idle | ok — 80.3s | | db integration, **10-way CPU contention** | ok — 102.7s | | `task ci:check` | pass, 0 lint issues | | `go vet -tags='example integration argo' ./...` | clean | | `golangci-lint --build-tags=integration ./db/...` | 0 issues | The loaded run is the condition CI was failing under.
) ## Why now This file is a hazard for the pending v3 promotion. It predated the v3 rework and contradicted itself — module path given as `/v3`, but `main`'s purpose described as *"active development for **v2.x** releases"*. It never mentioned the `next` branch or `release/v2`, and described `ci.yml` as PR-only when it also runs on push and tags. The consequential part: it told authors their PR description becomes release notes **"when squash-merged"**, unqualified. That is correct for merges into `next`. It is wrong for promoting a line into `main`: ```bash gh pr merge <N> --squash # collapses 102 commits into 1 # destroys all 22 BREAKING CHANGE footers ``` semantic-release would then analyse a single commit against `main`'s last tag (`v2.13.1`) and compute **`v2.14.0`** instead of `v3.0.0` — an invalid tag for a module whose path is `/v3`, and only visible once published. ## Change - Branch table: `main` / `next` / `release/v2` / `release/v1` with their module paths, status and release patterns. - The merge-commit rule for line promotion, with the reasoning above stated at the point of decision so it can't be "simplified" away. - A pre-promotion checklist, including that gorelease reporting `Inferred base version: none` is the **expected** result on the release PR, not a failure. - Accurate workflow triggers, the gorelease pinning note, and why the tagged `go vet` step exists separately from `task check`. - Points at `CONTRIBUTING.md` for contributor-facing process rather than duplicating it. All relative links verified to resolve.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promotes the v3 line to
main, publishing v3.0.0.Measured, by simulating both locally and running
semantic-release --dry-run:BREAKING CHANGEfooters--merge--squashA
v2.14.0tag on a module whose path is/v3is not installable, and it's only visible once published. This is documented in MAINTAINING.md with the recipe to re-check.Expected CI result
The API compatibility check reports informationally, not blocking —
ci.ymlkeys that offhead_ref == 'next'. gorelease reportingInferred base version: none / Suggested version: v3.0.0is the expected output: there is no prior non-prerelease/v3baseline.What's in it
102 commits, 22 with
BREAKING CHANGEfooters, across all 14 packages.github.com/jasoet/pkg/v3loggingabsorbed intootelWithOTelConfiginjection point everywhere, enforced byinternal/archtestMIGRATION.md is the consumer-facing record, and it covers breaks that shipped without footers and therefore never reached the generated notes — notably
server's removal of signal handling,temporal.WorkflowManager.Close, and grpc's gateway base-path stripping.Verification on
next@d802f3atask ci:check(unit + lint)go vet -tags='example integration argo' ./...3.0.0After merging
Confirm the published tag is
v3.0.0and that the Go proxy warmup step succeeded. Because this promotes a prerelease line, semantic-release moves the existingv3.0.0-next.*notes onto the release channel rather than regenerating a changelog body; the release description is worth enriching with a pointer toMIGRATION.md.