Render usage-gate skip rows as first-class timeline events on the metrics page - #154
Conversation
The producer now emits a row with skipped/skipReason for ticks its usage gate paused, so the metrics chart no longer shows those pauses as unexplained dead stretches. A skip draws as a thin muted baseline tick — a shape no run mark uses, so it cannot read as a completed run — with the gate's PAUSE line verbatim in its tooltip, a legend entry, and a caption sentence, in both unit modes and both themes. A skip is an event, never a run: isSkip is the page's one discriminant and pmPartition splits records once, so tiles, controls and every chart aggregate see real runs only — no renderer re-tests skip-ness. Unknown skipped values still render as a generic skip (fail-open on display) and still never count as runs. Files with zero skip rows render exactly as before; all-skip files chart the pause on its own. Closes #152 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
issue-pr-cron#160's actual row is a stage:"final" record with zeroed run fields (startupPct 0.0, durationMs 0, outcome "skipped") plus the skip pair. Read as a run it drags the median, dives the total line and paints an errored run; the partition defuses all three, and this pins it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 23 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
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. Comment |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
issue-pr-cron#163's final row shape carries outcome:"skipped" as the typed discriminant beside skipped/skipReason, and ordinary rows omit both skip fields entirely. isSkip now reads outcome === "skipped" first with the gate-field presence arm kept for rows lacking the typed outcome; run outcomes (ok/error/session-limit) and absent fields never match. Classification is by type, not by string-matching a reason. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Reviewed acecb01: ready — skip rows as baseline ticks with verbatim reasons via text nodes, one typed isSkip predicate partitioning once so every aggregate sees runs only, phantom-zero-run hazard defused with the producer's real row shape pinned by test, zero-skip page pixel-identical, 187/187 with four mutants killed from committed baselines, screenshots verified. |
Closes #152
The metrics page draws its timeline from issue-pr-cron's
metrics/runs.jsonl. The producer now emits a row for each tick its usage gate paused (rainlanguage/issue-pr-cron#163):"outcome":"skipped"(the typed discriminant) alongside"skipped":"usage-gate"and"skipReason":"<the gate's PAUSE line verbatim>", with time carried byrunIdas on every row. This PR renders those rows as first-class, visually distinct events instead of the dead stretches — or, with the row's zeroed run fields, phantom zero-work "runs" — they would otherwise produce.What changed (
site/metrics.html)runId). The cue is shape (runs are dots on lines; a skip is a tick), not colour alone, and holds in light and dark. Never a bar or point that could read as a completed run with zero work.skipReason(the gate's PAUSE line), built as text nodes per the page's no-markup-sink rule. The legend names the mark ("skipped tick") whenever skips are on the plot — including proportion mode, which gains a legend only then. A caption sentence appears only when skips exist.isSkip:outcome === "skipped"primary,skippedpresence as the fallback arm; both fields are absent, not null, on ordinary rows) and one partition (pmPartition) split records before any renderer runs. Tiles, controls, y-scale and every series receive real runs only; no chart re-tests skip-ness. This matters concretely for the real row shape —stage:"final"withstartupPct: 0.0,durationMs: 0,outcome:"skipped"— which read as a run would drag the median, dive the total line to the baseline, and paint an errored run.skippedvalue still renders as a generic skip (marker + tooltip naming the kind it declares) rather than being dropped — and by the partition it is still never counted as a run. Same for a row carrying only the typed outcome.Hand-rolled vanilla JS matching the page's existing idioms (the framework question is #150 and out of scope here).
Screenshots
Same fixture both sides: the live
runs.jsonlplus three real-shape usage-gate skip rows after the last producer run. On master the skip rows inflate "runs recorded" to 82, put a red "outcome skipped" in the caption as if the latest run degraded, and leave stray zero-duration marks; on the branch they are muted baseline ticks with a legend entry and the caption sentence, excluded from every stat (79 runs recorded).QA
test/dashboard.test.js— predicate contract (typed outcome primary, gate-field fallback, run outcomes and absent fields never match); typed-outcome-only row routes to skips and renders generically; pmRecords admits a gate-fields-only row (nostartupPct/bootMs) and keeps vetter skips out; partition split; tiles unmoved by a skip (median and run-count pinned); the emitter's REAL row (zeroed run fields,outcome:"skipped") partitions as an event, moves no tile, draws no dot; marker is alineat its own timestamp, vertical and short, never a circle; draws in pct mode; unknownskippedrenders generically, never dropped, never a run; all-skips file still charts and dates the axis; a skip's stray numbers never reach the y-scale; zero-skip regression pin (no marker, no legend entry, same dots/lines/labels in both modes); legend naming in both modes; verbatim-reason tooltip unit + hover integration; caption on/off; hostile-input tests forskipReason/skipped/runId(unit + hover, markup-node sweep).isSkip→return false(drop the predicate): 7 tests failed; (2)pmPartitionruns side → unfilteredrecs(count skips into aggregates): 4 tests failed, including the tiles-aggregate and y-scale tests. From committed baseline acecb01 — (3) drop the typed-outcome arm: 2 tests failed; (4) drop the gate-field fallback arm: 7 tests failed. Each restore verified withgit statusclean and the full suite back green before the next mutant; head suite is 187/187.outcome:"skipped"+skipped/skipReasonverbatim; time viarunId; both skip fields absent on ordinary rows; no back-fill), plus the page's own rules — CLAUDE.md "Rendering untrusted data" (DOM nodes only) and the chart's "hue means error-ness" convention (skips are muted and shape-cued, no new hue).skipped:"usage-gate"— covered by the two-arm predicate (typed outcome alone, gate fields alone, unknown kinds) and the stray-numbers test (a skip row carrying run-shaped fields still moves no aggregate); both unit modes, both themes (skip styles use vars defined in all three theme blocks), zero/some/all skip-row files, single-event and unparseable-id x-scale fallbacks all exercised.🤖 Generated with Claude Code