← 1.0.0 scope SAPE-7

Config reload, led by the partial reload: loading some of it and reporting success is the bug

Status
To do
Component
server
Priority
Medium
Blocked by
Blocks
SAPE-12

Description

Give the daemon a reload that re-reads its configuration without a restart, in the nginx shape: validate the whole new configuration first, apply it only if all of it is valid, and keep the running configuration untouched otherwise. The work is led by the failure case, not the success case — the design starts from what happens when the third of five entries is bad.

Why now

The partial reload is the reason this is in 1.0.0 rather than after it. A reload that applies what it can and reports success leaves the server in a state that matches neither the old configuration nor the new one, and reports that state as correct. The operator then debugs against a file that is not what is running. Building the naive version first and hardening it later means shipping that mode, and it is the mode that produces wrong answers rather than errors.

Measured 2026-09-20. Greenfield: a case-insensitive search for reload across every non-test .go file under internal/ and cmd/ returns nothing. There is no reload to fix, which is why the order of construction is the decision this ticket is really making — the all-or-nothing rule has to be the first thing built, not a later correction.

pipelines/tasks/0071 measured the adjacent question — how an external operation runs — and confirms this ticket's own scope note: a declared operation already reloads without any of this mechanism, over frame 13 (internal/server/declare.go:67), operator-only, no restart and no SIGHUP. This ticket's reload is for the daemon's configuration file only; it does not need to, and must not, grow to cover operations or collections, which already have their own live path.

Acceptance criteria

  1. A reload with a valid configuration applies it, the server keeps serving, and open connections are not dropped — asserted by a connection held across the reload that is still usable after.
  2. A configuration whose third of five entries is invalid applies none of the five. After the failed reload, each of the other four is read back and matches the old value. This is the test the ticket exists for.
  3. The failed reload returns a non-zero exit status and names the entry that was rejected and why. Asserted on the message, so the diagnosis cannot decay to "reload failed".
  4. A reload that fails leaves a server that still answers. Asserted by invoking an operation successfully after the failure.
  5. Repeated reloads of the same valid configuration are stable: the tenth leaves the server in the state the first did, with no accumulation. Measured by comparing the readable configuration state, and by the connection count not drifting.

Out of scope