Plan reference: plan/glamsterdam-2026-09-05/issues/08-phase-8-network-soak-and-observability.md · Issue 8.1
Description
Expose the resolved current fork and the next activation epoch as metrics, and log one boundary event per fork change, so a pre-fork activation is never unmonitored (P2-1).
Implementation Notes
- Add
ForkSchedule::next_activation(&self, epoch) -> Option<(ForkName, Epoch)> beside entries() (crates/eth-types/src/fork.rs:67); it returns None for a far-future sentinel entry.
- Declare in
crates/rvc/src/metrics.rs (ARCH-6h owner, not metrics/src/definitions.rs): rvc_fork_current_id (IntGauge, ForkName::id()) and rvc_fork_next_activation_epoch (IntGaugeVec, label fork); force both in metrics::init(). Declare through metrics::define_int_gauge / define_int_gauge_vec (crates/metrics/src/lib.rs:149,156) — both are in NAME_CTORS (metric_name_stability.rs:28-29); any other constructor is invisible to metric_name_set_is_unchanged's source scan and the name ships unpinned while CI stays green.
- Update per slot in
DutyOrchestrator::run (crates/rvc/src/orchestrator/coordinator/mod.rs:393) at :411, where current_epoch is already computed and self.config.fork_schedule is in scope — not in AttestationService::process_slot (crates/rvc/src/orchestrator/attestation.rs:123), which returns NoDutiesForSlot early at :163.
- Sentinel: omit the series (never create the child;
remove_label_values when it becomes sentinel) — u64::MAX does not fit i64 and a fabricated number would alert wrongly.
- Log at
info only when the resolved fork changes; use crates/observability/src/pubkey.rs helpers if any key appears, so no_crypto_logging_paths.rs stays green.
Acceptance Criteria
Testing Notes
unit tests in #[cfg(test)] at each file's bottom; existing create_test_fork_schedule helpers supply schedules; tracing-test captures the log assertion.
Points: 3 · Type: feature · Priority: P0 · Scope: 1.5 days · Blocked by: P2 (ForkName::Gloas), P7 · Blocks: #333, #337
Plan reference:
plan/glamsterdam-2026-09-05/issues/08-phase-8-network-soak-and-observability.md· Issue 8.1Description
Expose the resolved current fork and the next activation epoch as metrics, and log one boundary event per fork change, so a pre-fork activation is never unmonitored (P2-1).
Implementation Notes
ForkSchedule::next_activation(&self, epoch) -> Option<(ForkName, Epoch)>besideentries()(crates/eth-types/src/fork.rs:67); it returnsNonefor a far-future sentinel entry.crates/rvc/src/metrics.rs(ARCH-6h owner, notmetrics/src/definitions.rs):rvc_fork_current_id(IntGauge,ForkName::id()) andrvc_fork_next_activation_epoch(IntGaugeVec, labelfork); force both inmetrics::init(). Declare throughmetrics::define_int_gauge/define_int_gauge_vec(crates/metrics/src/lib.rs:149,156) — both are inNAME_CTORS(metric_name_stability.rs:28-29); any other constructor is invisible tometric_name_set_is_unchanged's source scan and the name ships unpinned while CI stays green.DutyOrchestrator::run(crates/rvc/src/orchestrator/coordinator/mod.rs:393) at:411, wherecurrent_epochis already computed andself.config.fork_scheduleis in scope — not inAttestationService::process_slot(crates/rvc/src/orchestrator/attestation.rs:123), which returnsNoDutiesForSlotearly at:163.remove_label_valueswhen it becomes sentinel) —u64::MAXdoes not fiti64and a fabricated number would alert wrongly.infoonly when the resolved fork changes; usecrates/observability/src/pubkey.rshelpers if any key appears, sono_crypto_logging_paths.rsstays green.Acceptance Criteria
test_next_activation_skips_far_future_sentinel— a schedule withgloas_fork_epoch = u64::MAXreturnsNone.test_next_activation_epoch_series_absent_at_sentinel— registry gather contains norvc_fork_next_activation_epochsample.test_fork_current_id_tracks_resolved_fork— gauge equalsForkName::from_epoch(...).id()across an activation epoch.test_fork_boundary_logged_once_per_change— N slots inside one fork emit one boundary line.EXPECTED_METRIC_NAMESgains both names (sorted) and the pinned count assertion (crates/metrics/tests/metric_name_stability.rs:186-188) moves by exactly+2from whatever it reads at branch time, with an operator-facing note. No absolute target (D4).Testing Notes
unit tests in
#[cfg(test)]at each file's bottom; existingcreate_test_fork_schedulehelpers supply schedules;tracing-testcaptures the log assertion.Points: 3 · Type: feature · Priority: P0 · Scope: 1.5 days · Blocked by: P2 (
ForkName::Gloas), P7 · Blocks: #333, #337