Contents

Performance diagnostics

Open Diagnostics → Performance. Yoke Events uses the workbench's selected universe and its existing All/multiple-project selection. It never combines universes. Changing scope cancels previous reads and closes inspection.

The default window is the last 24 hours, ending now. Choose a preset, select Custom to focus the date fields, or edit From/To in local time; custom ranges use timezone-qualified UTC timestamps on the wire. Refresh advances preset windows. Invalid or reversed dates name the correction before querying. Hover a bucket for values, sample counts, and resolution; click it or use arrow keys and Enter to inspect contributing calls. Inspection ranks every matching observation by raw duration, with paginated results and filters for functions, tools, hooks, relay waits, and watchers.

Ordinary function/tool latency and hook evaluator time use the left axis. The left axis uses a compressed scale: linear near zero and logarithmic above 100ms, so spikes remain visible without burying the target. Axis descriptions are horizontal below the chart, away from tick labels. Relay long-poll and watcher wall time use the right axis and start hidden; toggle them to compare. The dashed 2-second diagnostic target applies only to ordinary latency. Each series can be toggled independently. The display requests about one bucket per seven pixels (20–160 buckets) to keep real 24-hour data readable. Isolated observations remain points; gaps stay gaps. Client hook wall time contains evaluator time: inspection shows both and the measured remainder, without adding overlapping durations.

Measurement and unknowns

Buckets use individual observations, sum/count means and the existing linear interpolation percentile implementation. A bucket p95 is never an average of p95s or a relabeled maximum. Source observations are event-resolution; buckets are at least a minute and sized to the requested chart budget (20–800 points). There is no invented finer-resolution data or interpolation across gaps.

YokeFunctionCalled.duration_ms measures the handler, not end-to-end request wall time. HarnessToolCallCompleted, failed/structured/interrupted completion variants prefer vendor-native durations (context.detail.timing_status is native_duration). Codex reads the matching CommandExecution item from a bounded local rollout tail before relaying its existing duration_ms field; model turns between background-command check-backs are excluded. If that native record is absent, incomplete or unreadable, repaired session_tool_calls endpoints remain the fallback. Inspection labels the two as native_duration_ms and hook_elapsed_ms; the latter includes the interval between hooks and can include model wait. Both preserve timed, pending, unsupported and unknown distinctions across supported harnesses. Duplicate tool completion events share one (session_id, tool_use_id) count. HookDispatchTelemetry.duration_ms measures the evaluator; client_wall_ms and, on a relayed hook, the server's server_wall_ms are separately inspected. The semantic operation session_control.relay.claim identifies a relay long-poll. A stored command summary naming a registered yoke watch invocation identifies watcher wall time. A slow bare shell is still ordinary tool timing; duration alone never classifies a wait.

Inspection exposes existing owner/event measurements, permitted command summaries, harness/surface/machine, outcome, correlation identities and delivery lag when both completion and observation timestamps exist. Request queue/auth, DB and external dependency spans exported through OpenTelemetry are not stored in this ledger and cannot be fabricated here. They are explicitly unknown. No new collector, storage pipeline or private infrastructure access is required.

Counts cover delivered, retained observations, not events that never arrived. Older history outside retention and unsupported/missing timings stay unknown. The last observation timestamp is not a collector-health guarantee; query time is labeled separately. Empty windows do not assert health or zero latency.

Registered queries and bounds

To inspect Shipping's authorized overview through the same registered read:

yoke deployment-runs list --relevance overview

This includes current member QA and delivery facts, with a bounded live/recent run window per project. The overview includes pinned source identities without copying the driver's frozen preparation receipt into every card. Read that full receipt with yoke deployment-runs get RUN-ID bound_sources when diagnosing release preparation or recovery. Read its handler timing separately from browser HTTP and selection-to-card timings; SQL call counts alone do not prove latency.

An explicit Shipping entry starts its one authorized overview while project and saved-selection reads settle. The first render still applies the saved filter; navigation or unmount discards the early read, and later visits and actions read current facts. This overlaps startup work without caching across requests or changing the production timing requirement.

For a slow statement, use db.read.run with its actual parameters:

yoke db read "EXPLAIN (ANALYZE, BUFFERS) SELECT id FROM deployment_runs ORDER BY created_at DESC LIMIT 20"

Keep the query read-only and scoped. Execution time excludes transport, row decoding, Python work and rendering; also count repeated executions. Shipping shares attachment environment/case reads and decoded copy/source identities only within one evaluation. The next request reads current QA and withdrawals again. Completed execution rows are read together for the displayed runs, then each selected execution uses the same roster and target validator as a detail read. Older unselected rows are not validated or allowed to change the current answer. Shared-copy ownership resolves each run/stage/member's selected group targets once per presentation, rather than once per matching copy. Later requests repeat canonical selection, including attachment withdrawals and source-currency checks. Verdict checks read attempt identity, start, completion and outcome fields without captured output bodies, using the same actual-attempt ordering and ambiguity checks. Full attempt detail remains available separately. Member obligations and acceptance share one set of frozen member snapshots within the overview evaluation. Sharing labels also reuse those snapshots and live attachments; copy matching reads only identity and executable-content fields. Full case and attempt detail reads remain unchanged.

events.performance.aggregate and events.performance.detail authorize every selected project with events.read before reading or serializing observations and summaries. All contains only accessible projects; universe-attributed rows require an actual universe-admin grant and never enter selected-project metrics. The serving connection owns universe identity; the payload accepts no universe, actor, org or arbitrary query fields. There is no shared aggregate cache.

yoke events performance aggregate --since 2026-10-08T00:00:00Z --until 2026-10-09T00:00:00Z --project-ids 1,2 --points 400
yoke events performance detail --since 2026-10-08T00:00:00Z --until 2026-10-08T00:05:00Z --family tool --limit 50

The range is half-open: From is included and To is excluded. Range inputs must be timezone-qualified RFC3339 instants; numeric epochs and calendar-only values refuse. Bucket endpoints, observation time and query time use fixed-six UTC RFC3339 strings. Inspection preserves the bucket's exact microseconds.

Read each command's --help for paging and bounds. Time, event-name and project predicates use existing indexed columns. The aggregate reads only timing/context keys and command summaries, never stored responses or ledger results. The range is capped at 250,000 observations; larger ranges refuse by name and teach a shorter range, rather than returning a silently sampled percentile. Detail returns at most 100 contributors per page and labels the total and pagination. Telemetry availability has no effect on operational correctness.

Packaged chart dependency

uPlot 1.6.32 is pinned in the UI npm manifest and lockfile. Its minified runtime, stylesheet and MIT license ship in the wheel's static assets; no runtime CDN is used. To regenerate them, run npm ci under the UI directory and then:

yoke dev run -- python3 -m yoke_core.ui.build_chart_dependency --target-root <checkout>

Use uPlot's API documentation and the pinned dependency's dist/uPlot.d.ts when changing chart interaction.

Read runs

yoke deployment-runs list --project PROJECT
yoke deployment-runs list --project PROJECT --cursor NEXT_CURSOR
yoke deployment-runs get RUN-ID status current_stage release_lineage

The CLI list returns up to 20 summary rows, bounded by encoded page bytes before transport. Keep the same project/status filters when passing next_cursor to --cursor; a null cursor means the page is complete. --limit N sets the row ceiling, and a byte bound may return fewer whole rows. Summary rows omit large carried-work, source receipts, member and QA records; the result names the detail recipe. get RUN-ID FIELD ... returns only the requested row fields in one read; a single field keeps its scalar answer. With no fields, get reads the full row. --include-member-closure explicitly adds settlement diagnostics to that full read. list --relevance overview requests Shipping's member QA and delivery facts.

Registered callers use deployment_runs.list with summary=true and optional cursor, or deployment_runs.get with a nonempty fields list. Do not combine fields with field or member closure. Older serving releases refuse the new CLI contract as deployment_run_read_projection_unavailable; ask the control-plane operator to install a release with field selection and summary pagination, and read individual fields meanwhile. An oversized summary row refuses with its run-specific detail recipe; no row is silently shortened.

Performance diagnostics · Yoke