Skip to content

feat(miner): expose the §6.8 OTel metric set (§3.1.2/RFC0001.8/H2.2) - #159

Closed
jensholdgaard wants to merge 2 commits into
mainfrom
miner-telemetry-rfc0001
Closed

feat(miner): expose the §6.8 OTel metric set (§3.1.2/RFC0001.8/H2.2)#159
jensholdgaard wants to merge 2 commits into
mainfrom
miner-telemetry-rfc0001

Conversation

@jensholdgaard

@jensholdgaard jensholdgaard commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Summary

Implements the RFC 0001 miner telemetry slice: exposes the mandatory §6.8 OpenTelemetry metric set and flips three red-gate stubs — §3.1.2 (mandatory metric set exposed), RFC0001.8 (confidence_p50/p01 gauges), H2.2 (per-service params-overflow-rate alert).

Instruments are registered on the process-global ourios.miner meter via the lightweight opentelemetry API crate only — the heavy SDK/OTLP exporter stays in ourios-telemetry per the §6.8 export-architecture split. No new crate (the ourios-telemetry commitment already exists).

§6.8 metrics now exposed

Flat, pre-redesign names + data-point attributes exactly as the §6.8 table pins (matching the existing alias_* precedent; the dotted-ourios.* semconv conversion is the deferred §6.8 redesign, not this slice):

Metric Kind Attributes
template_count observable gauge tenant_id
merges_total counter tenant_id, event_type
confidence histogram tenant_id, service
confidence_p50 / confidence_p01 observable gauge tenant_id, service
body_retention_ratio observable gauge tenant_id
parse_failures_total counter tenant_id, service
params_overflow_total counter tenant_id, service
params_overflow_ratio observable gauge tenant_id, service
template_version_changes_total counter tenant_id
miner_latency_seconds histogram tenant_id

(alias_assertions_total / alias_retractions_total are already implemented in ourios-core::alias.)

The existing atomic counters stay as the in-process read path (test accessors like merges_total()); the OTel instruments are driven in lockstep at the same centralized emission sites (apply_overflow_retention, record_parse_failure, record_tokenizer_failure, the merge site, emit_record, ingest). Synchronous instruments are init-seeded with a zero-add / sentinel record so the full mandatory set surfaces in the first collection cycle at zero traffic (§3.1.2's collect-on-read guarantee); observable gauges always emit at least one sentinel point.

Quantile approach (flagged OTel decision)

confidence_p50 / confidence_p01 are observable gauges over an exact nearest-rank quantile of a bounded 1024-sample per-(tenant, service) reservoir. The confidence histogram remains the §6.8 source of truth; the gauges are the named in-process views per RFC0001.8.

Open question for the maintainer's OpenTelemetry review: §6.8 does not pin the quantile mechanism (sketch vs. exact), the window size, or whether p50/p01 should stay in-process gauges vs. become collector-/backend-derived quantiles over the exported histogram (the OTLP-native idiom). The RFC itself flags this exact fork as a contract change deferred to the dotted-semconv redesign. I picked the simplest defensible option (exact-over-bounded-window) and isolated it in Reservoir so the redesign can swap it under its own review.

Overflow ratio / H2.2 alert

params_overflow_ratio = overflow_lines / lines per (tenant_id, service) (a line is counted once toward the numerator regardless of how many of its params overflowed; params_overflow_total still counts per-param). H2.2's "alert" is the gauge crossing the documented 0.01 threshold — Ourios ships the metric + the alert rule, not an alerting engine. The test drives a service to ~1.48% overflow and asserts the gauge exceeds 0.01 while a clean sibling service stays at 0.0 (per-service isolation).

Invariants / hazards touched

  • §3.1 (mandatory telemetry) — the full §6.8 set is now exposed and collectable.
  • §6.3 (observability of ourselves) — no "metrics later".
  • §3.2 / H2 — overflow ratio + per-service alert threshold.

No existing passing test was weakened. Added TemplateChange::event_type() (mirrors AuditPayload::event_type) for the merges_total event_type attribute.

semconv weaver

Unaffected. semconv/registry/ and the generated ourios-semconv crate are untouched; the miner's flat-named metrics were never in the weaver registry (same as alias_*). The dotted-semconv registry entries are the deferred §6.8 redesign. otel-weaver semantic-conventions integration tests remain a deferred follow-up, not added here.

Verification (local)

  • cargo test --all-features — all binaries pass, 0 failed, exit 0 (the three flipped stubs now green; lib unit tests include 5 new metrics.rs tests).
  • cargo fmt --all --check — clean.
  • cargo clippy --all-targets --all-features -- -D warnings — clean.
  • weaver is not installed locally; reasoned from the untouched registry + the CI job definition rather than running it.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Miner now exports comprehensive OpenTelemetry metrics instrumentation, including per-ingest latency, template counts, per-service confidence quantiles (p50, p01), and overflow/retention ratio tracking.
  • Tests

    • Implemented previously stubbed tests to validate mandatory metric set exposure and per-service overflow alerting thresholds.

Register the full RFC 0001 §6.8 mandatory metric set on the
process-global `ourios.miner` meter (API-only dep per the §6.8
export-architecture split; SDK/OTLP stay in ourios-telemetry) and
flip three red-gate stubs into real AAA tests.

Metrics now exposed (flat pre-redesign names per §6.8, matching the
existing alias_* precedent — the dotted-ourios.* semconv conversion
is the deferred §6.8 redesign, not this slice):

- counters: merges_total{tenant_id,event_type},
  parse_failures_total{tenant_id,service},
  params_overflow_total{tenant_id,service},
  template_version_changes_total{tenant_id}
- histograms: confidence{tenant_id,service},
  miner_latency_seconds{tenant_id}
- observable gauges: template_count{tenant_id},
  confidence_p50/_p01{tenant_id,service},
  body_retention_ratio{tenant_id},
  params_overflow_ratio{tenant_id,service}

The atomic counters stay as the in-process read path (test
accessors); the OTel instruments are driven in lockstep at the same
centralized emission sites. Init-seeded so the full set surfaces at
zero traffic (§3.1.2 collect-on-read guarantee).

confidence_p50/_p01 are observable gauges over an exact nearest-rank
quantile of a bounded (1024-sample) per-(tenant,service) reservoir;
the confidence histogram remains the §6.8 source of truth. §6.8 does
not pin the quantile mechanism/window — flagged for the maintainer's
OTel review (RFC already names the gauge-vs-backend-derived fork).

params_overflow_ratio = overflow_lines / lines per (tenant,service);
H2.2's "alert" is the gauge crossing the documented 0.01 threshold
(we ship the metric + rule, not an alerting engine).

semconv weaver job unaffected: semconv/registry/ and ourios-semconv
untouched; the miner's flat-named metrics were never in the registry.

Touches §3.1 (mandatory telemetry) / §6.3 (observability).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jensholdgaard, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 31 minutes and 47 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 624f2954-6904-4d5a-b772-deb56d4a350b

📥 Commits

Reviewing files that changed from the base of the PR and between ba6c98c and 89b1bca.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • crates/ourios-miner/Cargo.toml
  • crates/ourios-miner/src/metrics.rs
  • crates/ourios-miner/tests/hazards.rs
  • crates/ourios-miner/tests/invariants.rs
  • crates/ourios-miner/tests/rfc_internal.rs
  • crates/ourios-semconv/src/lib.rs
  • docs/rfcs/0001-template-miner.md
  • semconv/registry/attributes.yaml
  • semconv/registry/metrics.yaml
  • templates/registry/rust/lib.rs.j2
📝 Walkthrough

Walkthrough

This PR implements OpenTelemetry metrics instrumentation for the miner cluster per RFC 0001 §6.8, adding a canonical event-type mapping to TemplateChange, a comprehensive metrics module with OTel instruments and quantile reservoirs, and cluster-wide telemetry wiring across ingest, error, and emission paths. Three previously-ignored test suites are activated to validate metric exposure and per-service thresholds.

Changes

RFC 6.8 Telemetry Metrics

Layer / File(s) Summary
TemplateChange event type contract
crates/ourios-core/src/audit.rs
TemplateChange::event_type() exposes canonical stable event-type strings (Widened, TypeExpanded, RejectedDegenerate) to enable merge telemetry recording.
Metrics dependencies and module setup
crates/ourios-miner/Cargo.toml, crates/ourios-miner/src/lib.rs
Adds OpenTelemetry metrics API, testing utilities, and tokio runtime as dev-dependencies; declares the new internal metrics module.
Metrics module implementation
crates/ourios-miner/src/metrics.rs
MinerMetrics struct owns OTel instruments (counters, histograms) and shared state for observable gauges (template_count, confidence_p50/p01, body_retention_ratio, params_overflow_ratio). Bounded per-(tenant, service) Reservoir computes exact nearest-rank quantiles. Recording methods update telemetry and shared state. Seeding and sentinel emissions ensure metrics appear at zero traffic. Includes unit tests for quantiles, ratios, and service-name extraction.
Cluster telemetry wiring
crates/ourios-miner/src/cluster.rs
Initializes MinerMetrics on MinerCluster; refactors apply_overflow_retention, record_parse_failure, record_tokenizer_failure to accept OtlpLogRecord and emit telemetry. Captures ingest Instant and records latency/template_count after body dispatch. Updates emit_record to compute service and call record_line for per-line confidence. Routes all error paths (tokenizer, parse, overflow) through telemetry helpers. Replaces direct atomic merge increments with metrics.record_merge() using TemplateChange::event_type().
Test suite activation
crates/ourios-miner/tests/invariants.rs, crates/ourios-miner/tests/hazards.rs, crates/ourios-miner/tests/rfc_internal.rs
Activates three tests: invariant_3_1_2 verifies all mandatory metric names are exposed at zero traffic; H2.2 validates per-service overflow ratio exceeds 0.01 under oversized params; RFC 6.8 test confirms confidence_p50/p01 gauges match independently computed nearest-rank quantiles. All use in-memory telemetry exporters.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

The changes span multiple files with mixed density: the metrics module introduces substantial logic (instruments, reservoirs, quantile computation, shared state management), the cluster integration involves numerous call-site updates and refactoring of helpers throughout ingest/emit paths, and the test suite requires understanding of telemetry exporter/gauge/counter inspection patterns. The PR's cohesion—all changes work together to implement one RFC—partially offsets the breadth, but the variety of metrics types (counters, histograms, gauges, quantiles) and ingest-path complexity demand careful review.

Possibly related PRs

  • jensholdgaard/ourios#104: This PR introduces the crates/ourios-telemetry crate scaffolding that is now used as a dev-dependency for metrics testing infrastructure.

Poem

🐰 Metrics bloom where miner minds convene,
Quantiles dance in reservoirs of green,
Per-tenant tales in counters flow and gleam,
RFC 6.8 fulfills the telemetry dream! ✨📊

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically summarizes the main change: exposing the §6.8 OpenTelemetry metric set, with reference citations to the specific RFC sections and invariants being implemented.
Description check ✅ Passed The description is comprehensive and well-structured, covering all required sections (Summary, Related, and implicit Checklist items). It provides detailed context on the implementation, metric specifications, design decisions, and verification steps.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch miner-telemetry-rfc0001

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jensholdgaard
jensholdgaard requested a review from Copilot June 8, 2026 05:31
@jensholdgaard

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements the RFC 0001 miner telemetry slice by registering and driving the RFC §6.8 OpenTelemetry metric set from ourios-miner (API-only), and flips the red-gate test stubs for §3.1.2, RFC0001.8, and H2.2 to green.

Changes:

  • Add MinerMetrics with §6.8 counters/histograms plus observable gauges backed by in-process state (including a bounded confidence reservoir).
  • Wire telemetry emission into the miner hot paths (ingest, merge emission, parse/tokenizer failure paths, overflow retention, and record emission).
  • Add in-memory OTel SDK-based integration tests for mandatory metric exposure, confidence quantile gauges, and per-service overflow ratio threshold behavior.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
crates/ourios-miner/src/metrics.rs New miner metric instrument registration + callbacks + state/reservoir implementation.
crates/ourios-miner/src/cluster.rs Hooks metric recording into ingest/emission sites and merge events.
crates/ourios-miner/src/lib.rs Adds the internal metrics module.
crates/ourios-miner/Cargo.toml Adds OTel API dependency + dev deps for in-memory SDK testing.
crates/ourios-miner/tests/invariants.rs Implements §3.1.2 mandatory metric-set exposure test using in-memory exporter.
crates/ourios-miner/tests/rfc_internal.rs Implements RFC0001.8 p50/p01 gauge test with cross-check vs sink samples.
crates/ourios-miner/tests/hazards.rs Implements H2.2 per-service overflow ratio threshold test.
crates/ourios-core/src/audit.rs Adds TemplateChange::event_type() for merges_total event_type attribute.
Cargo.lock Records new (dev) dependencies used by miner tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/ourios-miner/src/metrics.rs Outdated
Comment thread crates/ourios-miner/src/metrics.rs Outdated
Comment thread crates/ourios-miner/src/metrics.rs Outdated
Comment thread crates/ourios-miner/src/metrics.rs Outdated
Comment thread crates/ourios-miner/src/metrics.rs Outdated
Comment thread crates/ourios-miner/src/metrics.rs Outdated
….* + fix observable handles

Migrates the RFC 0001 §6.8 miner metric set off flat names
(template_count, merges_total, …) onto the dotted-`ourios.miner.*`
weaver registry alongside the compaction set, regenerating
`ourios-semconv` and consuming the generated constants in
`crate::metrics`. Adds the `ourios.service` attribute and the
`ourios.miner.template_change` enum (widened / type_expanded) to the
registry; the merges change-kind moves from the flat `event_type`
attribute onto it. The §3.1.2 / RFC0001.8 / H2.2 tests assert the
dotted names via the generated constants.

Also folds the Copilot correctness fixes:
- retain the five observable-gauge handles in `MinerMetrics` so their
  collection callbacks stay registered (a dropped handle deregisters
  the callback, dropping the gauge from the exported stream);
- recover a poisoned lock in the four collection callbacks rather than
  panic (a metrics callback must never bring the process down);
- pre-allocate the confidence reservoir to RESERVOIR_CAP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 6 comments.

Comment on lines +291 to +294
let tenant_event = [
KeyValue::new(semconv::OURIOS_TENANT, INIT_SENTINEL),
KeyValue::new(semconv::OURIOS_MINER_TEMPLATE_CHANGE, INIT_SENTINEL),
];
Comment on lines +416 to +434
.with_callback(move |obs| {
let st = s.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
let mut emitted = false;
for ((tenant, service), tally) in &st.by_service {
if let Some(v) = tally.confidence.quantile(q) {
obs.observe(v, &service_attrs(tenant, service));
emitted = true;
}
}
if !emitted {
obs.observe(
0.0,
&[
KeyValue::new(semconv::OURIOS_TENANT, INIT_SENTINEL),
KeyValue::new(semconv::OURIOS_SERVICE, INIT_SENTINEL),
],
);
}
})
pub(crate) fn record_line(&self, tenant: &TenantId, service: &str, confidence: f64) {
self.confidence
.record(confidence, &service_attrs(tenant, service));
let mut st = self.state.lock().expect("metrics state mutex poisoned");
}
self.params_overflow_total
.add(count, &service_attrs(tenant, service));
let mut st = self.state.lock().expect("metrics state mutex poisoned");
/// Record one body-retention event for the
/// `body_retention_ratio` numerator (§6.3 retention paths).
pub(crate) fn record_body_retention(&self, tenant: &TenantId) {
let mut st = self.state.lock().expect("metrics state mutex poisoned");
/// Mirror a tenant's current template count into the state the
/// `template_count` observable gauge reads.
pub(crate) fn set_template_count(&self, tenant: &TenantId, count: u64) {
let mut st = self.state.lock().expect("metrics state mutex poisoned");
@jensholdgaard

Copy link
Copy Markdown
Owner Author

Closing to redo this spec-first. This slice was built code-first (the instrumentation with flat names, then the weaver registry retrofitted) — which inverts the standing process: new OTel metrics/attributes must be designed in the semconv/registry/ FIRST (per the OTel semantic-conventions formulation rules — https://github.com/open-telemetry/semantic-conventions, policies/*.rego + naming docs), regenerated into ourios-semconv, and only then implemented against the generated constants.

Reopening as a fresh PR whose main theme is the semconv/weaver registry design (so the review reads spec-first), with the §6.8 ourios.miner.* metrics audited against the OTel formulation rules, the 6 correctness fixes baked in from the start, and §3.1.2/RFC0001.8/H2.2 flipped on top.

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.

2 participants