Skip to content

test(horismos,archon): config completeness + E2E SIGHUP regression; fix(archon,ergasia): reload deadlock + DHT isolation (#529 step 9)#589

Merged
forkwright merged 1 commit into
mainfrom
audit/529-step9
Jul 7, 2026
Merged

test(horismos,archon): config completeness + E2E SIGHUP regression; fix(archon,ergasia): reload deadlock + DHT isolation (#529 step 9)#589
forkwright merged 1 commit into
mainfrom
audit/529-step9

Conversation

@forkwright

Copy link
Copy Markdown
Owner

Step 9 — the final step of the #529 reactive-config migration. Makes the config classification self-enforcing, proves the whole SIGHUP path end-to-end, and documents it. Building the E2E test surfaced two real bugs (below), both fixed here.

Completeness classification test (crates/horismos/src/diff.rs): walks every serde-json leaf of a fully-populated exemplar Config (each Option<Struct> subsystem set to Some(..) so mixed subtrees expose per-field leaves; taxis.libraries.<id>.* canonicalized). Asserts every leaf is in exactly one of three lists — LIVE (66 leaves, the reactive contract wired by steps 2-8), RESTART_REQUIRED (10 leaves), or UNWIRED (31 dead-config leaves, each // #575-commented) — and that their union is exactly the full 107-leaf set (disjoint + exhaustive, no ghosts either direction). Adding a config field without classifying it now fails the build.

E2E SIGHUP regression (crates/archon/tests/config_reload_e2e.rs): spawns the real harmonia binary, parses the first-run admin password from stdout, logs in, rewrites the TOML (opds_page_size LIVE, jwt_secret rotation, db_path RESTART), sends SIGHUP, then bounded-polls (no fixed sleeps) to assert the page-size change is live, the pre-rotation bearer now 401s while a refresh recovers, and restart_pending contains database.db_path. The child is reaped in a Drop guard.

Two production bugs the E2E test caught and this PR fixes:

  1. SIGHUP deadlocked the whole server (archon/src/main.rs) — main held a StdoutLock guard across the entire run_serve lifetime (its future never migrates threads under tokio::main), so the first concurrent tracing:: call (the SIGHUP handler) blocked forever on the same lock. Fixed by passing an unlocked Stdout handle (locks per write, never across an await). Without this, every prior step's reload machinery would have hung on the first reload.
  2. DHT-init flake / shared-state hazard (crates/ergasia/src/session.rs) — librqbit's persistent DHT defaulted to the global ~/.cache/com.rqbit.dht/dht.json, so concurrent instances (and parallel test processes) raced/corrupted each other's DHT routing state. Now pinned to an instance-local path under session_state_path via PersistentDhtConfig.config_filename — isolating tests and preventing two harmonia instances on one box from clobbering each other's DHT state.

Docs: new docs/architecture/config-reload.md (mechanism + per-field live/restart table + JWT-rotation / dual-endpoint-drain / rebuild-reset semantics, grounded against shipped code); corrected two now-false claims in configuration.md. CHANGELOG is release-please-managed.

Gate: kanon gate --full green — fmt, check, clippy (-D warnings), nextest (full workspace), deny, kanon lint (0/0). Gate-Passed stamped.

Closes #529

…P reload regression + docs; fix(ergasia): instance-local DHT persistence (#529)

Gate-Passed: kanon 0.1.5 +stages:fmt,check,clippy,nextest,lint sha:c106f795d08319830730f9130a562cc6cdd86937
@forkwright forkwright merged commit 99e0ea1 into main Jul 7, 2026
12 checks passed
@forkwright forkwright deleted the audit/529-step9 branch July 7, 2026 05:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

config reload: SIGHUP reload is a silent no-op in archon serve

1 participant