Ctrl K
ComunidadGuías…

docs/adr/0092-community-first-run-resolver-latency.md

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# ADR-0092: The community first run does not wait for a resolver that is not there

## Metadata

| Field          | Value                                                     |
| -------------- | --------------------------------------------------------- |
| **Status**     | Accepted                                                  |
| **Date**       | 2026-10-20                                                |
| **Authors**    | Alessio Brillo                                            |
| **Deciders**   | Alessio Brillo                                            |
| **Supersedes** | —                                                         |
| **Relates to** | ADR-0002, ADR-0072, ADR-0075, ADR-0076, ADR-0091         |
| **Project**    | DOMINUS                                                   |

## Context

Unbound is the single source of truth for DNS (ADR-0072, ADR-0075). The
application waits for the resolver to become healthy and to prove DNSSEC
validation before it accepts traffic, and in cloud mode (`DNS_UNBOUND_STRICT`
on) it refuses to start without it.

The wait was configured with a single default: 30 seconds, in every
deployment mode. In the community edition that default is paid on every
command, by every user, for a resolver that in most community installations
is not there at all: the self-hosted "Personal" profile in the README is the
CLI alone, with no Unbound sidecar.

The measured cost, from the first run of the published artifact
(`scripts/verify-release.mjs`, ADR-0091): the CLI spent ~30 seconds in
"Unbound readiness check failed — retrying" before falling back to the Node
resolver. The command that the README's Quick Start advertises —
`npx dominus-oss@latest score vintagecoffee.com` — took half a minute
before it printed anything. The fallback was correct; the latency was not.

The fallback is already the accepted community posture (ADR-0076): it is
explicitly non-strict, it never produces an `Available` verdict that the
DNSSEC-validating resolver did not produce, and the strictness of the
production path is unaffected. The wait changes nothing about the outcome in
the community edition; it only changes how long the user waits to reach the
same outcome.

## Decision Drivers

1. **The first run is the product's first impression.** The public release
   makes `npx dominus-oss` a one-command experience. A half-minute of
   silence before the first output reads as a hang, and users who read it
   that way do not run the command again.
2. **The wait must not weaken the guarantee.** DNSSEC validation must stay
   mandatory for anything the product calls `Available`. Nothing here may
   change what a verdict means.
3. **The two modes want opposite defaults.** Cloud needs the long wait (the
   resolver must be there, and a sidecar that is still booting deserves the
   time). The community edition does not (the resolver is optional there).
4. **The change must be visible in the configuration.** A hidden latency
   change is a surprise; a documented default that differs per mode is a
   fact.

## Considered Options

### Option A: One default for both modes (status quo)

**Advantages:** simple.

**Disadvantages:** the community edition pays 30 seconds for a resolver that
is usually absent, on every command.

### Option B: Skip the readiness wait entirely in the community edition

**Advantages:** the fastest possible first run.

**Disadvantages:** it also skips the Unbound configuration validation
(`validator` module, `val-permissive-mode: no`), which is a diagnostic a
self-hoster with a broken `unbound.conf` would want. A misconfigured
resolver in a Docker deployment would degrade more quietly.

### Option C: A mode-dependent default for the readiness timeout

**Advantages:** the readiness path stays intact — the health check, the
DNSSEC proof, the configuration validation — and only its budget changes.
A resolver that is starting up still gets its chance; a machine with no
resolver stops waiting after five seconds instead of thirty.

**Disadvantages:** two defaults to remember, and the community figure is
still a wait.

## Decision

**Option C.**

- `DNS_UNBOUND_READINESS_TIMEOUT_MS` defaults to **30 000 ms in cloud mode**
  and **5 000 ms in the community edition**. The deployment mode is the one
  the configuration already computes (`detectCloudMode`: a `DATABASE_URL`
  or an `AUTH_PROVIDER` other than `env`).
- The mode detection is the same one that drives `DNS_UNBOUND_STRICT`, so
  the two defaults cannot disagree: the mode that is strict about the
  resolver is the mode that waits longest for it.
- An explicit value always wins. The variable stays overridable, and the
  `.env.example` entry documents both figures.
- Nothing else changes: the readiness path, the health check, the DNSSEC
  proof, the configuration validation and the strict-mode refusal all
  behave exactly as before.

## Consequences

### Positive

- The community first run reports in seconds instead of half a minute, with
  the same verdict and the same guarantees.
- The cloud path is untouched: a resolver that is still booting still gets
  the thirty seconds it needs, and a missing resolver still fails the boot.
- The fallback still never produces an `Available` verdict that the
  DNSSEC-validating resolver did not produce (ADR-0002, ADR-0076).

### Negative

- A resolver that becomes available between the fifth and the thirtieth
  second is no longer waited for in the community edition. The
  `FallbackResolver` re-evaluates the primary on every call, so the
  resolver is picked up as soon as it is healthy; the window is a slower
  first lookup, never a wrong verdict.
- Two defaults exist. The test
  (`src/__tests__/config-readiness-timeout.test.ts`) pins both, so they
  cannot drift.

## Links

- `src/config.ts` — the mode-dependent default.
- `src/__tests__/config-readiness-timeout.test.ts` — the pinned defaults.
- `src/app/provider-factory.ts` — the readiness wait and the fallback.
- `scripts/verify-release.mjs` — the verification that measured the latency.