Plan reference: plan/glamsterdam-2026-09-05/issues/08-phase-8-network-soak-and-observability.md · Issue 8.4
Description
Count fail-closed signer rejections with a bounded sign_type / version label pair, so a signer that lags the Gloas types is visible on day one instead of as missing duties.
Implementation Notes
- Declare
rvc_signer_rejections_total (IntCounterVec, labels reason, sign_type, version) in crates/signer/src/metrics.rs (already an ARCH-6h owner with a metrics dependency — no new workspace edge, no layer_edges.rs change).
- Increment where
SigningError is classified: From<SigningError> for SignerError at crates/signer/src/lib.rs:148-165. SigningError::UnsupportedSigningType (arm at :161) maps to reason="unsupported_type"; the unknown-version reject added by 4.9 maps to reason="unsupported_version". A From impl is a pure conversion — if incrementing there double-counts or fires under #[cfg(test)] conversions, move the increment to the call sites that classify the error and say so in the PR.
- Labels are code-derived constants in a
pub mod rejection_reason; version is the fork name from ForkName::as_ref() or "unknown" — never the raw request string (cardinality).
- A transient HTTP 400 must not land here as
unsupported_type (it would make a serialization bug look like a permanent capability gap); classify it under the transient path 4.10 establishes. At HEAD a 400 arrives as SigningError::RemoteSignerError, not UnsupportedSigningType.
Acceptance Criteria
Testing Notes
existing FailingRemoteSigner / SigningError fixtures in crates/signer/src/lib.rs tests cover every arm; no signer process needed.
Points: 2 · Type: feature · Priority: P0 · Scope: 1 day · Blocked by: #334, P4 (#254 type/version fail-closed, #255 400-stays-transient) · Blocks: #337
Plan reference:
plan/glamsterdam-2026-09-05/issues/08-phase-8-network-soak-and-observability.md· Issue 8.4Description
Count fail-closed signer rejections with a bounded
sign_type/versionlabel pair, so a signer that lags the Gloas types is visible on day one instead of as missing duties.Implementation Notes
rvc_signer_rejections_total(IntCounterVec, labelsreason,sign_type,version) incrates/signer/src/metrics.rs(already an ARCH-6h owner with ametricsdependency — no new workspace edge, nolayer_edges.rschange).SigningErroris classified:From<SigningError> for SignerErroratcrates/signer/src/lib.rs:148-165.SigningError::UnsupportedSigningType(arm at:161) maps toreason="unsupported_type"; the unknown-version reject added by 4.9 maps toreason="unsupported_version". AFromimpl is a pure conversion — if incrementing there double-counts or fires under#[cfg(test)]conversions, move the increment to the call sites that classify the error and say so in the PR.pub mod rejection_reason;versionis the fork name fromForkName::as_ref()or"unknown"— never the raw request string (cardinality).unsupported_type(it would make a serialization bug look like a permanent capability gap); classify it under the transient path 4.10 establishes. At HEAD a 400 arrives asSigningError::RemoteSignerError, notUnsupportedSigningType.Acceptance Criteria
test_unsupported_signing_type_increments_with_bounded_labels.test_unknown_version_increments_unsupported_version_reason.test_http_400_does_not_increment_unsupported_type.test_rejection_labels_come_from_rejection_reason_module.EXPECTED_METRIC_NAMESgainsrvc_signer_rejections_total; the pinned count assertion moves by exactly+1from its value at branch time — no absolute target (D4).Testing Notes
existing
FailingRemoteSigner/SigningErrorfixtures incrates/signer/src/lib.rstests cover every arm; no signer process needed.Points: 2 · Type: feature · Priority: P0 · Scope: 1 day · Blocked by: #334, P4 (#254 type/version fail-closed, #255 400-stays-transient) · Blocks: #337