feat(daemon): the readiness probe behind §5's seam, proven against live services
Dimension 7.3. §5 shipped `Dependencies` as a trait and stopped there on
purpose — routing and the response shape are afd_api's, what it MEANS to reach
Postgres and Redis belongs to whoever owns the connections. `LiveDependencies`
is that half.
Both probes run concurrently. Sequentially, a Postgres that is timing out would
delay the Redis answer by the whole database budget, so `/readyz` would take
longer to say "not ready" the worse things got — the moment an orchestrator
most needs a fast one. Each carries its own deadline at the call site
(Invariant 4), because a probe that hangs reads to an orchestrator as a hung
PROCESS: it restarts the instance over someone else's outage. The bound is the
difference between reporting a dependency outage and becoming one.
Acquiring a connection is the database probe rather than a `SELECT 1`, because
acquiring is what every handler does — an exhausted pool, a closed pool and a
datastore that stopped answering all fail the same way a request would.
**"Stopped Postgres", without stopping Postgres.** The test cannot kill the
compose container — the rest of the lane is using it — so the pool is CLOSED
after it has answered once. That is faithful rather than convenient: from this
instance's view, "Postgres stopped" IS "the pool will not hand me a
connection", and it is deterministic where killing a container and waiting for
sqlx to notice is a race. What it does not cover is the transition, the seconds
where sqlx still holds sockets to a dead server — that needs §2's fault proxy
and stays `test_pool_error_classes` there rather than becoming a second copy.
Redis is asserted UNCHANGED across the same probe, because the two fields stay
separate all the way to the wire: a red database and a red queue are different
incidents, and collapsing them means reading logs to learn which.
make test-integration-rustd → 45 tests against live services (was 43)
test_readyz_dependency_probe ... ok
test_readyz_answers_within_its_deadline ... ok
**Coverage, and which number is the honest one.** `make test-coverage-rustd`
measured 587 tests across both tiers. Read from `rustd/lcov.info` — the
artefact the lane writes and codecov consumes — the workspace has **zero DA
entries with zero hits**, raw, not merely under a union:
afd_api 555 · afd_auth 510 · afd_core 209 · afd_crypto 374 · afd_db 836
afd_identity 524 · afd_observability 39 · afd_redis 715 · afd_state 121
afd_wire 45 · agentsfleetd 299 → 4227 / 4227 lines, 100.00%
That closes the §Coverage decision's open residue rather than moving its bar,
`entropy.rs:47` included. Two honest qualifications:
- This is LINE coverage, which is what `codecov.yml`'s 100% project target
grades. Region coverage is not 100% and cannot be: `entropy.rs:47` runs, but
the `map_err` closure inside it needs the kernel's entropy pool to fail.
- `cargo llvm-cov report` disagrees, reporting 99.12% and naming six files —
every one of them covered only by the integration lane. That is the stale-
profraw merge the M176 handoff warns about, confirmed here rather than
assumed: `lcov.info` is timestamped by the both-tiers run and has no
zero-hit line in it at all.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> K
Kishore Kumar committed
00d33a7721533a6317d887241445065003567d11
Parent: fc8093b