dashboard: quick-follow ratio instead of gap p10; transparent base so empty cells stay empty

For a Poisson block process the 10th-percentile gap of an honest author is
about one second by construction, so a fixed threshold flagged everyone.
quick-follow x is the share of an author's blocks arriving within 1 s of
the previous block divided by the network's share: 1 is normal, 2 or more
is withheld-block behaviour; needs 10 samples. Bucket boundaries are
selected as le="1.0" (Prometheus 3 normalises them to float strings).
Threshold bases are transparent so authors without samples show blank
cells, not red or blue.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CBgs2nSi4H2mdh8kD8vMX5
This commit is contained in:
Rob Thijssen
2026-09-04 09:04:27 +03:00
co-authored by Claude Fable 5.1
parent b17dfaeba1
commit 1d1b8d19de
+39 -27
View File
@@ -9,7 +9,7 @@
],
"timezone": "browser",
"schemaVersion": 39,
"version": 16,
"version": 17,
"refresh": "30s",
"time": {
"from": "now-6h",
@@ -1716,7 +1716,7 @@
"x": 0,
"y": 62
},
"description": "Blocks observed authored within the selected time range, by reward preimage (cumulative counter, exists from the exporter's restart onward). est. MH/s is the author's share of blocks times the network hashrate estimate over the range: a statistical figure, \u00b110% or so at a few hundred blocks. gap p10: the 10th percentile of seconds between the author's block and the previous one; near zero means blocks released right after others' (withheld). drift median: the author's block timestamp minus when we first saw it; a few seconds negative is normal, positive is future-dated. consecutive: blocks authored directly after the author's own previous block. Timing columns fill in from when the exporter started recording them. burst \u00d7: consecutive self-blocks divided by the count expected from the author's share (blocks \u00d7 share); about 1 is normal, sustained values above 2 mean blocks held and released together. Shown only where the expected count exceeds one. Cell colours: gap p10 red under 1 s and amber under 3 s; drift green in the normal negative band, amber once future-dated, red past 5 s, blue when more than 20 s in the past; burst amber above 2, red above 4.",
"description": "Blocks observed authored within the selected time range, by reward preimage (cumulative counter, exists from the exporter's restart onward). est. MH/s is the author's share of blocks times the network hashrate estimate over the range: a statistical figure, \u00b110% or so at a few hundred blocks. quick-follow \u00d7: the share of the author's blocks that arrived within 1 s of the previous block, divided by the network's share; about 1 is normal, 2 or more means blocks released right after others' (withheld). Needs 10 samples. drift median: the author's block timestamp minus when we first saw it; a few seconds negative is normal, positive is future-dated. consecutive: blocks authored directly after the author's own previous block. Timing columns fill in from when the exporter started recording them. burst \u00d7: consecutive self-blocks divided by the count expected from the author's share (blocks \u00d7 share); about 1 is normal, sustained values above 2 mean blocks held and released together. Shown only where the expected count exceeds one. Cell colours: quick-follow amber above 2 and red above 3; drift green in the normal negative band, amber once future-dated, red past 5 s, blue when more than 20 s in the past; burst amber above 2, red above 4.",
"targets": [
{
"datasource": {
@@ -1749,7 +1749,7 @@
},
"editorMode": "code",
"refId": "C",
"expr": "(histogram_quantile(0.1, sum by (preimage, le) (increase(quantus_block_gap_seconds_bucket{preimage!~\"all|other\"}[$__range])))) == (histogram_quantile(0.1, sum by (preimage, le) (increase(quantus_block_gap_seconds_bucket{preimage!~\"all|other\"}[$__range]))))",
"expr": "((sum by (preimage) (increase(quantus_block_gap_seconds_bucket{le=\"1.0\",preimage!~\"all|other\"}[$__range])) / sum by (preimage) (increase(quantus_block_gap_seconds_count{preimage!~\"all|other\"}[$__range]))) / scalar(sum(increase(quantus_block_gap_seconds_bucket{le=\"1.0\",preimage=\"all\"}[$__range])) / sum(increase(quantus_block_gap_seconds_count{preimage=\"all\"}[$__range])))) and on(preimage) (sum by (preimage) (increase(quantus_block_gap_seconds_count{preimage!~\"all|other\"}[$__range])) >= 10)",
"instant": true,
"range": false,
"format": "table"
@@ -1845,7 +1845,7 @@
"self 1": "ours",
"Value #A": "blocks",
"Value #B": "est. MH/s",
"Value #C": "gap p10 (s)",
"Value #C": "quick-follow \u00d7",
"Value #D": "drift median (s)",
"Value #E": "consecutive",
"Value #F": "burst \u00d7"
@@ -2012,7 +2012,23 @@
{
"matcher": {
"id": "byName",
"options": "gap p10 (s)"
"options": "consecutive"
},
"properties": [
{
"id": "decimals",
"value": 0
},
{
"id": "unit",
"value": "none"
}
]
},
{
"matcher": {
"id": "byName",
"options": "quick-follow \u00d7"
},
"properties": [
{
@@ -2042,15 +2058,19 @@
"mode": "absolute",
"steps": [
{
"color": "red",
"color": "transparent",
"value": null
},
{
"color": "orange",
"value": 1
"color": "green",
"value": 0
},
{
"color": "green",
"color": "orange",
"value": 2
},
{
"color": "red",
"value": 3
}
]
@@ -2091,9 +2111,13 @@
"mode": "absolute",
"steps": [
{
"color": "blue",
"color": "transparent",
"value": null
},
{
"color": "blue",
"value": -1000000
},
{
"color": "green",
"value": -20
@@ -2111,22 +2135,6 @@
}
]
},
{
"matcher": {
"id": "byName",
"options": "consecutive"
},
"properties": [
{
"id": "decimals",
"value": 0
},
{
"id": "unit",
"value": "none"
}
]
},
{
"matcher": {
"id": "byName",
@@ -2160,9 +2168,13 @@
"mode": "absolute",
"steps": [
{
"color": "green",
"color": "transparent",
"value": null
},
{
"color": "green",
"value": 0
},
{
"color": "orange",
"value": 2