Skip to content

feat(OMN-13847): per-hook wall-clock latency instrumentation (emit side) - #1834

Merged
jonahgabriel merged 2 commits into
devfrom
jonah/omn-13847-hook-latency-instrumentation
Jul 2, 2026
Merged

jonahgabriel merged 2 commits into
devfrom
jonah/omn-13847-hook-latency-instrumentation

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Jul 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes OMN-13847.

The OMN-13244 measurement baseline had no way to measure per-hook wall-clock latency (gap identified in the hook-usefulness analysis). This PR lands the foundational emit-side piece: a reusable monotonic-timer instrumentation primitive that wraps a hook body and emits a structured hook.executed telemetry event so hook usefulness becomes data-driven (p50/p95 latency per hook) instead of guessed.

What changed

  • plugins/onex/hooks/lib/hook_latency_instrumentation.py (new)
    • instrument_hook(hook_name, event, ...) context manager — time.monotonic() start/stop timer; emits on exit (from a finally block, so duration is recorded even when the hook raises or sys.exit()s). The yielded handle lets the hook body flag blocked = True.
    • instrumented_hook(...) decorator form for a hook entrypoint callable.
    • build_hook_execution_payload(...) / emit_hook_execution(...) — payload carries hook_name, event (PreToolUse/PostToolUse/…), duration_ms, blocked, correlation_id, and session_id (injected by emit_event from CLAUDE_CODE_SESSION_ID when not supplied).
    • Emission flows through the existing emit-daemon socket path (emit_client_wrapper.emit_event) — canonical event bus only, no bespoke REST/HTTP. Fire-and-forget: never raises, never blocks the hook.
  • tests/unit/hooks/lib/test_hook_latency_instrumentation.py (new) — 14 unit tests asserting duration_ms is emitted, blocked propagates, timing is recorded even when the body raises, the emitter is fail-open (never raises), and the decorator preserves metadata.

Design constraints honored

  • Inert when hooks are disabled. Nothing runs at import; no timer is scheduled. Duration is measured only while a hook body runs inside the context manager/decorator. With the current empty-hooks baseline (OMN-13846) this emits nothing — it only measures hooks that actually run and does not re-enable any hook.
  • Canonical event bus only. Same fire-and-forget contract as skill.started / hook.health.error.

Fast-follow (tracked on OMN-13847)

The daemon-side routing + projection is deliberately deferred because it is a coordinated cross-repo change (the event_registry_drift gate requires the omniclaude EVENT_REGISTRY/TopicBase surfaces and the omnimarket daemon topic registry to move together, so registering hook.executed in only one repo would red-gate the other):

  1. Register hook.executed in omnimarket/node_emit_daemon/registries/topics.yaml + the mirrored omniclaude SUPPORTED_EVENT_TYPES / EVENT_REGISTRY / TopicBase in one coordinated PR.
  2. Land the hook_executions time-series projection (migration + consumer, mirroring skill_executions) keyed for p50/p95 latency per hook.
  3. Wire the /api/hook-health/summary endpoint the hook_health_alert skill already expects.

Until (1) lands, emit_event treats hook.executed as an unregistered type and drops it client-side (graceful no-op), so this emit-side primitive is safe to ship ahead of the projection.

dod_evidence

  • Ticket: OMN-13847
  • Branch: jonah/omn-13847-hook-latency-instrumentation (based on origin/dev)
  • New tests: tests/unit/hooks/lib/test_hook_latency_instrumentation.py — 14 passed.
  • Local gate (all green):
    • uv run ruff format — 2 files left unchanged
    • uv run ruff check <both files> — All checks passed
    • uv run mypy plugins/onex/hooks/lib/hook_latency_instrumentation.py — Success: no issues found
    • uv run pytest tests/unit/hooks/lib/test_hook_latency_instrumentation.py — 14 passed
    • Coupled registry/wiring/governance/golden suites (test_emit_client_wrapper, test_event_registry, test_topic_registry, test_emission_wiring_presence, test_topic_governance, test_golden_event_validation) — 267 passed, 1 skipped
    • Repo-wide pytest --collect-only — 10,846 tests collected, no import/syntax errors introduced
    • pre-commit (pre-commit + pre-push stages) — passing on the changed files under the canonical 3.13 interpreter (CLAUDE.md rule Add Claude Code GitHub Workflow #11)

Evidence-Source: OCC#3487
Evidence-Ticket: OMN-13847

…t side)

The OMN-13244 measurement baseline had no way to measure per-hook wall-clock
latency. Add a reusable emit-side timing primitive that wraps a hook body with a
monotonic start/stop timer and emits a structured hook.executed event
(hook_name, event, duration_ms, blocked, correlation_id, session_id) via the
existing emit-daemon socket path (emit_client_wrapper.emit_event) -- canonical
event bus only, no bespoke REST.

Inert when hooks are disabled: nothing runs at import, timing only happens while
a hook body actually runs; does not re-enable any hook.

Fast-follow (OMN-13847): register hook.executed in the daemon topic registry
(omnimarket) + mirrored omniclaude EVENT_REGISTRY/TopicBase as one coordinated
cross-repo change (event_registry_drift gate), then land the hook_executions
projection (migration+consumer, mirroring skill_executions) and the
/api/hook-health/summary endpoint hook_health_alert expects.
@coderabbitai

coderabbitai Bot commented Jul 2, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 35 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

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.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: faed4324-e461-4435-a253-e24914c2058c

📥 Commits

Reviewing files that changed from the base of the PR and between 501f405 and dc06182.

📒 Files selected for processing (3)
  • .onex_state/evidence/OMN-13847/dod_report.json
  • plugins/onex/hooks/lib/hook_latency_instrumentation.py
  • tests/unit/hooks/lib/test_hook_latency_instrumentation.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jonah/omn-13847-hook-latency-instrumentation

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

@github-actions
github-actions Bot enabled auto-merge July 2, 2026 17:45
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

⚠️ Hostile Reviewer — DEGRADED (informational)

Blocking findings (critical/error): 0
Total findings: 0
Models succeeded: none

Note: All reviewer models failed or were unavailable. Degraded results are informational during the pilot phase (OMN-8524) and do not block merge. Error: cli_review exited non-zero (all models failed or binary error)


Gate semantics (pilot phase)

Verdict Meaning Blocks merge?
passed No critical/error findings No
blocked CRITICAL or ERROR findings found Yes
degraded All models unavailable (infra) No (pilot)

Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8524)

Comment thread tests/unit/hooks/lib/test_hook_latency_instrumentation.py
@github-actions
github-actions Bot added this pull request to the merge queue Jul 2, 2026
@jonahgabriel
jonahgabriel removed this pull request from the merge queue due to a manual request Jul 2, 2026
@github-actions
github-actions Bot enabled auto-merge July 2, 2026 18:41
@github-actions
github-actions Bot added this pull request to the merge queue Jul 2, 2026
@jonahgabriel
jonahgabriel removed this pull request from the merge queue due to a manual request Jul 2, 2026
@jonahgabriel
jonahgabriel added this pull request to the merge queue Jul 2, 2026
@jonahgabriel
jonahgabriel removed this pull request from the merge queue due to a manual request Jul 2, 2026
@jonahgabriel
jonahgabriel added this pull request to the merge queue Jul 2, 2026
Merged via the queue into dev with commit 8c92227 Jul 2, 2026
103 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-13847-hook-latency-instrumentation branch July 2, 2026 19:27
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