Skip to content

M7-25 Grafana panel plugin "Bothy Live"

No Date Ruling Reason
D-M7-25-0 2026-10-18 Base int/m1-wave42 at c5a86a6, branch feat/M7-25-grafana-plugin in its own worktree; not merged locally and not pushed, the PR lane ports it. The brief relies on no core rule and no D-W ruling that the base lacks in a way the code depends on (D-W-125 and rulings T7, T8, T11 only forbid cost, signing and publishing, which this ticket does not do), so nothing is ported first. The base has no section 10 in this file, so the rows stand in a section per ticket. Names that differ from the brief (D-W-100): the spec chapter is 25-visualisierung.md on the base (25-visualization.md on main, D-M7-25-8); the generator is scripts/gen-queries.mts (Node runs it with type stripping); the plugin Makefile adds check (all component targets but build) next to test, lint, typecheck and generate-check; the display name in Grafana's panel picker is "Live views", because 02 section 6 lists only folder, release component, plugin ID and dashboard as places of the working name for the plugin and test_product_name_places.py holds that list; the TypeScript identifiers use Live instead of the working name for the same reason. Instructions of the launcher; merged layout wins over the brief (D-W-100); ADR 0044.
D-M7-25-1 2026-10-18 Scaffold and versions: npx @grafana/create-plugin@7.13.0 once (panel, org bothy, name live, ID bothy-live-panel), recorded in .config/.cprc.json; Grafana 13.2.3 as BOTHY_GRAFANA_VERSION of the Compose stack, grafanaDependency >=13.2.3, @grafana/data and @grafana/ui 13.2.3; a unit test holds the three equal. .config/ stays as generated (its files are exempt from the SPDX header check and its JSONC tsconfig.json from check-json); the root files extend it as .config/README.md describes. Every dependency is pinned exactly and locked; TypeScript is 5.9.3, the version of sdk/typescript. Removed from the scaffold: the agent instruction files, the GitHub workflows inside the plugin (they never run there), the Docker development environment and its provisioning (provisioning is M7-26), the Playwright end-to-end test with @grafana/plugin-e2e and @playwright/test (VZ-T13 belongs to M7-26), @grafana/sign-plugin and the sign script (unsigned until V1, ruling T11), and the unused @grafana/runtime, @grafana/i18n and @grafana/schema. Component version 0.0.0 like the other components before their first release. Brief, design note 1 and requirements 9, 11 and 12.
D-M7-25-2 2026-10-18 Views: one panel shows one view, chosen by the option view; each view reads only the refIds of its queries.yaml entry. Executive page: the option warnBudgetRatio (default 0.25, the default of stats.slo_warn_budget_ratio) separates "on target" and "budget tight"; gray "not enough data" when a recording rule has no value for the SLO, because Prometheus has no event count per SLO that would match stats.slo_min_events. Option showCosts (default on) for topology and backend view. Timeline: playback in ticks of 250 ms with the speeds of viz.timeline_speeds; a refresh of a relative period keeps the playhead inside the period instead of resetting it. Styles are inline styles from the token theme, so tests can read the colours. Brief, design note 2; spec 25 sections 6.4, 6.5 and 15.
D-M7-25-3 2026-10-18 Colour lint rule: the local ESLint rule bothy/no-color-literal (eslint-rules/no-color-literal.cjs) on src/**/*.{ts,tsx} reports a string or template literal with a hex colour, a CSS colour function (rgb, rgba, hsl, hsla, hwb, lab, lch, oklab, oklch, color), a named CSS colour or transparent as the whole value, or a named colour after a colour property in CSS text or among the words of the value of a style key such as border or boxShadow (1px solid red). Prose that only contains a colour word passes. The logo src/img/logo.svg is an image, not code; a unit test holds its colours to token values. Brief, requirement 14.
D-M7-25-4 2026-10-18 Kiosk form: TV mode is Grafana's kiosk mode, opened with /d/bothy-live?kiosk (also kiosk=1 or kiosk=true), the user menu item "Enable kiosk mode" or d k, left with Esc. The documentation of Grafana 13.2 confirms the menu item, the shortcut, Esc and the kiosk view modes of playlists but names no URL form; the URL parameter is confirmed from the source of v13.2.3 (AppChromeService.setKioskModeFromUrl), where kiosk=tv no longer exists. Spec 25 section 8.2 records the sources. Brief, requirement 16; spec 25 section 8.2 marked the URL form as assumed.
D-M7-25-5 2026-10-18 License gate for npm: the plugin bundles only its own code (React, Emotion and @grafana/* are webpack externals that Grafana provides at runtime; everything else is a build or test tool). plugins/grafana-bothy-live/osv-scanner.toml names each package version whose license is unknown to deps.dev or not on quality/licenses/allowed.txt: four MIT packages with license.override after reading their LICENCE, the others with license.ignore and the reason that they are dev tools or reached only through the externals; three advisories (react-router via @grafana/ui, sprintf-js via jest) are ignored until 2026-11-18 with their reason. A unit test fails when a production dependency that is not an external enters the dependency graph, or when an entry has no reason. quality/licenses/allowed.txt is unchanged. Brief, requirement 9 and acceptance "license gate for npm green"; docs/quality/licenses.md exempts what is not shipped.
D-M7-25-6 2026-10-18 The name test of 17 section 10 item 4 for queries.yaml runs in make signal-check (tools/signalcheck/signalcheck.py, M1-68): every expr of the file passes rules 2 to 4 and the promtool syntax check of rule 6 like a dashboard query; a missing file contributes nothing. One gate for every file that queries metrics; make ops-check holds no PromQL name check.
D-M7-25-7 2026-10-18 Wiring: make bootstrap-ci runs npm ci in the plugin; tools/ci/components.py selects the gate component plugins for a change of design/build/ts/, of bothy-live.json and of the Grafana pin files; Sonar reads the plugin's lcov report, treats *.test.tsx as tests, excludes .config/ and src/queries.gen.ts, and leaves the plugin's configuration files, its lint rule and its generator out of coverage, because tests run them as tools (ESLint, a child process). jest-setup.js replaces the scaffold's MessageChannel of worker_threads by a timer-based one: its port kept Node's event loop alive, so a single test file never exited. The root gates run the plugin like sdk/typescript; without these the plugin's tests would not run on a token or dashboard change and Sonar would count tool files as uncovered code.
D-M7-25-8 2026-10-21 Port to main: the ticket's own four commits onto main after M1-71, without the integration rulings of its base wave. The spec chapter, the dashboards page, the license page and plugins/README.md take the ticket's additions in the English documents of main; the component map names 09-agents.md, 05-actions.md and 07-permissions.md. Two cases of main's component tests that held infra/compose/compose.yaml as an input of no component now expect the component plugins and the job test-sdk-plugins, because the Grafana pin there is an input of the plugin's tests (D-M7-25-7); the push plan test likewise. The three coverage packing steps of ci.yml also pack plugins/*/coverage/lcov.info, the plugin's report that sonar-project.properties names. Only the ticket's own change lands; English documents on main win.