Read-only ActivityPub → atproto bridge for the threadiverse using Coves lexicons

docs(deploy): correct a runbook that recommended the harmful kill switch (18b review) master

A fact-check of 18597cc against the code found the runbook telling an operator to reach for the wrong lever in an emergency, because the code told the runbook the wrong thing first. PARKING SPENDS THE RETRY BUDGET. `ClaimNext` increments `attempts` on every claim; `Release` — which `park` calls — never resets it; `parkDelay` is 5s and `DefaultMaxDeliveryAttempts` is 8. So with `OUTBOUND_DISABLED` engaged and workers running, each ordering key's head delivery is re-claimed and re-parked about twelve times a minute, and its budget is gone in roughly forty seconds. Nothing poisons WHILE parked, which is the half that reads true and is why this survived: `releaseOrPoison` poisons on the FIRST retryable failure after the switch clears. An hour-long kill switch therefore ends in a burst of poisoned deliveries with single-attempt failures. `worker.go` asserted in its own comment that park "does not advance the poison budget", and the runbook inherited that claim and went further, ranking `OUTBOUND_DISABLED` above `OUTBOUND_WORKERS=0` and telling the operator to prefer it. The ranking is now reversed, with the reason: at workers=0 no worker is constructed at all, so nothing claims and nothing is spent. The comments in `park` and `parkCausal` are corrected and say so explicitly, so the next reader does not re-trust the old text. `RedrivePoisoned` resets attempts to zero and is the remedy — previously documented nowhere. The behaviour itself is NOT fixed here. `Release` is one statement serving two callers that mean opposite things — "retryable failure, back off", where incrementing is correct, and "parked by a switch", where it is not — so the fix needs a design decision and a test, and a naive one must not disarm `parkCausal`, whose safety comes from a wall clock rather than a count. FOLLOWUPS carries it as a defect with the candidate directions and a proposed test shape. The KEK blast radius named two tables and there are three. `ap_actors.rsa_key_sealed` holds every NATIVE Coves user's AP signing key under the same key — the exact population v2 exists to serve, and the one a rotation plan written from the old text would have left unable to sign. Two further corrections found while fixing it: `service_keys.private_key_pem` has not existed since migration 013 renamed it to `key_material`, and only its plc-rotation row is sealed while the service-actor row is plaintext; and `bridged_actors.signing_key` is escrowed secp256k1 repo key material, not the per-actor RSA the document claimed. Also corrected: a "none of which exists" that does — `ap_actors.rsa_key_version` is present and unused as a selector, and a false not-implemented makes someone rebuild what is already there; `OUTBOUND_DRY_RUN` does not validate the translator, since translation happens at enqueue time and the worker POSTs the stored payload verbatim; the scoped switches are inert at workers=0 because the switch struct is only constructed in that branch; Caddy does not proxy coves.social entirely to the appview, so /.well-known/webfinger returns a static-file 404 today and that is the signature to diff against; and the "2-3h to poison" derivation is about 63 minutes, fixed in the runbook and in divergence.go where it originated. Added what an operator needs and did not have: the four tidepool_outbound_* counters, where `parked` is the only positive confirmation a switch engaged and `cancelled` rises on its own from the worker's consent check; the divergence gauges' pre-sweep -1; and the psql query for `last_error_class` and `response_excerpt`, which are on no admin route. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>