Commit a6535c2
Add mz-release-signoff agent skill (#38355)
### Motivation
Release verification is a weekly rotation across seven Grafana
dashboards, and almost all of its cost is rediscovery rather than
judgement. Each verifier works out again which environments run the
candidate, when each stack was upgraded, which panels matter, and which
apparent signals are artifacts of the upgrade itself. This records that
method once so a run starts from the measurement.
### Description
An area-agnostic spine plus one reference per dashboard.
The spine covers finding the candidate version and the upgrade
boundaries, selecting the environment set, choosing a window that
reaches the previous upgrade, batching many metrics into one range
query, and the rules for separating a regression from drift. Environment
selection differs by stack: production pins the canary environments by
name, because they share the released version with customer environments
for part of the week and a version filter loses them, while staging can
join on the release-candidate version.
The judgement rules are the part worth reviewing. Every upgrade restarts
the process, which resets memory downward and flatters the new version,
so levels have to be compared at equal age since restart. Zero-downtime
upgrades run two generations side by side, so every sum doubles for one
bucket and that bucket has to be excluded. Arrangement gauges are
bimodal and only their base level is comparable. Fleet CPU on staging
moved by a factor of two over three weeks, so a few percent across a
boundary carries no information on its own.
Each reference names the metrics with their types and labels, then gives
one `Hazards and invariants` section. Each entry there leads with the
property that holds at any fleet size and gives the measurement it came
from inline, because splitting the two produced near-verbatim
duplication in every reference.
### Guarding against metric drift
A reference that names a metric the product no longer exports is worse
than no reference, because the sweep reads the empty result as a healthy
zero. Two mechanisms cover that, split by when they run.
At run time, `scripts/catalog-diff.sh` reads `doc/user/data/metrics.yml`
at the release tags on either side of a sign-off boundary. The catalog
is checked in, so it is tagged with each release, and the working tree's
copy describes `main` rather than the build under test. Diffing the two
tags separates an empty panel that is a finding from a metric that
arrived or departed with the release.
At commit time, `ci/test/lint-skill-metrics.sh` resolves every `mz_*`
name in the skill against the catalog and fails on any that neither
resolves nor carries a documented exemption. A rename therefore breaks
in the commit that renames rather than during a sign-off weeks later.
Matching is not a string comparison: a `metric!` built with `format!` is
catalogued with its placeholders globbed, and histograms are catalogued
as their expanded families, so both forms have to be resolved through
patterns.
`scripts/` also holds the batched-query builder that step 5 needs and
the panel-query slicer that step 4 refers to.
### No recorded baselines
An earlier revision carried per-area baseline tables. They are gone,
because they duplicated work the method already does and would need
syncing with the product forever. The before-window of a run is derived
in the same query as the after-window, which makes it the only baseline
guaranteed to describe the same fleet, so a figure recorded months
earlier is redundant the day it is written. Absolute fleet sums also
move whenever an environment is created, deleted, or resized, and a
stale reference value is worse than none because it invites a comparison
the reader should not make.
What survives is the part that does not decay. Invariants such as a
healthy `mz_source_progress` series contributing exactly 1000 to its
rate, so the panel is a series count in disguise; `environmentd` never
swapping; upsert state being structurally absent from staging, so that
dashboard can only be verified from the production sandbox; rehydration
latency being a last-value staircase with one step per upgrade; and
`environmentd_needs_update` acting as the rollout clock. Alongside
those, a coarse dated order-of-magnitude block per area, kept only to
catch a mis-scoped selector such as a missing `container="clusterd"`,
and explicitly not for comparison.
### Verification
Documentation only. Every claim in the references was measured against
the live dashboards rather than estimated, and the skill was then run
end to end against the `v26.39.0-rc.3` boundary across production canary
and staging in us-east-1 and eu-west-1. That run is what surfaced the
persist recheck above and the two dashboard defects added to the list.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>1 parent cb4e73f commit a6535c2
15 files changed
Lines changed: 1353 additions & 0 deletions
File tree
- .agents/skills
- mz-release-signoff
- references
- scripts
- ci/test
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
23 | 24 | | |
24 | 25 | | |
25 | 26 | | |
| |||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
0 commit comments