# v3.6 to 3.7

## Breaking Changes

<!-- Any breaking behavior change:
Any removal or change of default behavior that requires user action -->

### `HEAD` no longer resolves to a branch named `HEAD`

If a repository has a branch literally named `HEAD` (`refs/heads/HEAD`), a `targetRevision` of `HEAD`
(or an empty `targetRevision`) previously resolved to that branch. It now follows the repository's
symbolic `HEAD` to the tip of the default branch, as Git does.

**Impact:**

- Applications and ApplicationSets tracking `HEAD` in such a repository will switch from the
  `refs/heads/HEAD` branch to the default branch, and may sync different manifests.
- To keep tracking the branch, set `targetRevision: refs/heads/HEAD`. Otherwise, consider deleting the
  branch with `git push origin --delete refs/heads/HEAD`.

See [Branches named `HEAD`](../../user-guide/tracking_strategies.md#branches-named-head).

## Behavioral Improvements / Fixes

### Metrics can be pushed via OTLP

The API server, application controller and repo server can now push the metrics served at
`/metrics` to an OpenTelemetry collector, controlled by `otlp.metrics.enabled` and
`otlp.metrics.interval` in `argocd-cmd-params-cm`. It is off by default; see
[Pushing metrics via OTLP](../observability.md#pushing-metrics-via-otlp).

Two changes apply to deployments that already set `--otlp-address` for tracing:

- Spans now carry a `service.instance.id` resource attribute set to the pod hostname, in
  addition to `service.name`. Collector pipelines that derive metrics from spans (for example the
  `spanmetrics` connector with its default resource keys) will see series split per pod. Drop the
  attribute in the collector, or configure the connector's resource key attributes, if that is
  unwanted.
- On shutdown the tracer now drains its span queue with a 10s timeout instead of aborting on the
  cancelled process context, so the last batch of spans is exported rather than dropped.

### ApplicationSet webhook responses now match the API server webhook

The ApplicationSet controller's webhook endpoint now handles requests the same way as the API
server's `/api/webhook` endpoint:

- Payloads larger than the `webhook.maxPayloadSizeMB` value in the `argocd-cm` ConfigMap (default
  50MB) are rejected with `400 Bad Request`. Previously, the ApplicationSet webhook had no payload
  size limit.
- A GHCR event that fails signature verification is rejected with `401 Unauthorized` instead of
  `400 Bad Request`.
- When a payload cannot be parsed, the response body is a generic `Webhook processing failed`
  message. The parser error is logged by the ApplicationSet controller instead of being returned to
  the caller.

If you monitor the ApplicationSet webhook's response codes or bodies, update any checks that relied
on the previous behavior.

### Custom Healthchecks Added

- A bundled health check for Vault Secrets Operator's `secrets.hashicorp.com/VaultStaticSecret`
  resource. It reports `Healthy` when the `Healthy` condition is `True` and `Degraded` with the
  sync error when it is `False`, and stays `Progressing` until the operator has reconciled the
  current generation. With operator versions before 1.0.0, which set no conditions, it reports
  `Healthy` once `status.lastGeneration` matches the resource's generation.

## Other Changes

### Revoked token resync interval

`argocd-server` now reloads revoked tokens from Redis every 5 minutes instead of every 15 seconds. The interval is configurable with `ARGOCD_SESSION_REVOKED_TOKEN_RESYNC_DURATION`. See [Revoked token resync](../user-management/index.md#revoked-token-resync).

### `--http-retry-max` now applies to TLS (and `--grpc-web`) connections

Prior to v3.7, the CLI's global `--http-retry-max` flag had no effect on TLS
connections (the default) — the retryable HTTP transport was silently discarded
during TLS setup, so retries only ever applied to `--plaintext` connections.
This is now fixed, so `--http-retry-max` retries transient failures (connection
errors, HTTP `429`, and `5xx` except `501`) for HTTP requests over plaintext or TLS,
including `--grpc-web`. (Native gRPC connections use a separate, built-in retry
interceptor that this flag does not configure.)

The flag still defaults to `0` (no retries), so behavior is unchanged unless you
have opted in. If you do set `--http-retry-max`, be aware:

> [!WARNING]
> - Retries apply to **all** gRPC-web requests, including non-idempotent ones.
>   gRPC-web tunnels every RPC as an HTTP `POST`, so the retry layer cannot
>   distinguish reads from writes. A transient `5xx` returned *after* the server
>   has already processed a mutating request (e.g. `argocd account generate-token`,
>   `argocd app actions run`) will cause the request to be re-sent. Prefer enabling
>   the flag for idempotent/declarative operations (e.g. `app set`/`app sync`), and
>   consider this before enabling it globally for mutating commands.
> - Retries add latency ahead of any command-level timeout. Backoff is capped at
>   10s per attempt, but `--http-retry-max` attempts still accumulate; size it with
>   your `--timeout` values (e.g. `app sync`/`app wait`) in mind.
