Skip to content

feat(grafana-alertcheck): rename outcomes and print plain-worded tables - #2850

Merged
Tofel merged 1 commit into
alertgate/fail-fastfrom
alertgate/readable-output
Sep 29, 2026
Merged

Tofel merged 1 commit into
alertgate/fail-fastfrom
alertgate/readable-output

Conversation

@Tofel

@Tofel Tofel commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

check's output now speaks plain words, in both the JSON vocabulary and the
human tables:

  • outcomes: clean -> healthy, newly_bad -> new_failure, persistently_bad -> still_failing, flapping -> unstable, skipped -> paused, unobservable -> not_verified, and terminated_early.kind follows the same rename.
  • RESULTS and VIOLATIONS columns are spelled out (ALERT, VERDICT, BROKEN FOR, CHECKED EVERY, WINDOW COVERED, DETAILS; GRAFANA STATE, GRAFANA HEALTH, INSTANCES). INSTANCES is one word: the old "INSTANCE COUNT" header read as two columns, one of them empty under the count.
  • THRESHOLDS became LIMITS USED, with each limit named in plain wordsand explained by a legend under the table. The footer spells out the extra observation time, the evaluation wait and the clock difference from Grafana.

The rename reaches the JSON output, so consumers of violations[].outcome, outcomes and terminated_early must move to the new vocabulary.


Stack created with GitHub Stacks CLI • Give Feedback 💬

@Tofel
Tofel added this pull request to stack #2845 September 29, 2026 07:01
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

📊 API Diff Results

No changes detected for module github.com/smartcontractkit/chainlink-testing-framework/grafana-alertcheck

View full report

@Tofel
Tofel force-pushed the alertgate/readable-output branch from 2183f39 to fe1e962 Compare September 29, 2026 08:18
@Tofel
Tofel requested a balanced review from Copilot September 29, 2026 08:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The new table labels misreport coverage and polling for fail-fast and paused rules.

Review effort: Balanced
Findings: 1 Medium severity · 1 Low severity

Open (2)
What changed in this PR

Renames alert-check outcomes and makes terminal tables more operator-friendly.

Changes:

  • Replaces legacy outcome vocabulary across classification, fail-fast, and JSON output.
  • Introduces not_counted for unattributed observation shortfalls.
  • Rewords table headers, limits, documentation, and tests.
File Description
internal/​gate/​terminal.go Renames fail-fast outcomes.
internal/​gate/​terminal_test.go Updates termination tests.
internal/​gate/​coverage_test.go Updates coverage expectations.
internal/​gate/​classify.go Defines and applies new outcomes.
internal/​gate/​classify_test.go Updates classification tests.
internal/​gate/​check.go Renames drain-timeout outcomes.
internal/​gate/​check_test.go Updates end-to-end expectations.
docs/​reference/​log-format.md Updates log terminology.
docs/​reference/​cli.md Documents output vocabulary and tables.
docs/​how-alerts-are-evaluated.md Updates outcome semantics.
docs/​architecture.md Updates architectural terminology.
cmd/​table.go Adds plain-worded tables and footer.
cmd/​table_test.go Updates table-rendering tests.
.changeset/​v0.1.3.md Records the breaking output changes.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread grafana-alertcheck/internal/gate/classify.go
Comment thread grafana-alertcheck/docs/how-alerts-are-evaluated.md Outdated
@Tofel
Tofel force-pushed the alertgate/readable-output branch from fe1e962 to 1740506 Compare September 29, 2026 08:27
check's output now speaks plain words, in both the JSON vocabulary and the
human tables:

  - outcomes: clean -> healthy, newly_bad -> new_failure,
    persistently_bad -> still_failing, flapping -> unstable,
    skipped -> paused, unobservable -> not_verified, and
    terminated_early.kind follows the same rename. A --min-observed deficit
    that no resolved rule explains is now not_counted instead of being
    blamed on a paused rule.
  - RESULTS and VIOLATIONS columns are spelled out (ALERT, VERDICT,
    BROKEN FOR, CHECKED EVERY, WINDOW COVERED, DETAILS; GRAFANA STATE,
    GRAFANA HEALTH, INSTANCES). INSTANCES is one word: the old
    "INSTANCE COUNT" header read as two columns, one of them empty
    under the count.
  - THRESHOLDS became LIMITS USED, with each limit named in plain words
    and explained by a legend under the table. The footer spells out the
    extra observation time, the evaluation wait and the clock difference
    from Grafana.

The rename reaches the JSON output, so consumers of violations[].outcome,
outcomes and terminated_early must move to the new vocabulary.
@Tofel
Tofel force-pushed the alertgate/readable-output branch from 1740506 to c2c5809 Compare September 29, 2026 08:29
@Tofel
Tofel marked this pull request as ready for review September 29, 2026 09:08
@Tofel
Tofel requested a review from a team as a code owner September 29, 2026 09:08
@Tofel
Tofel removed this pull request from stack #2845 September 29, 2026 09:17
@Tofel
Tofel merged commit d923bbf into alertgate/fail-fast Sep 29, 2026
62 checks passed
@Tofel
Tofel deleted the alertgate/readable-output branch September 29, 2026 09:18
Tofel added a commit that referenced this pull request Sep 29, 2026
* feat(grafana-alertcheck): fail fast on a condition that cannot become a pass

check now stops collecting as soon as it observes a monotone terminal
verdict instead of always holding the runner to
to + transitionGrace + drainTimeout:

  - a post-from bad onset, which the full classifier calls newly_bad or
    flapping and fails whether or not it later clears; or
  - an inability that has already happened: a heartbeat gap, a sustained
    health=error run, a stale evaluation, an in-window pause, an absent
    rule.

terminalVerdict is pure and reuses proveCoverage and classifyRule over
the observed sub-window with a synthetic sentinel. A preexisting bad
instance is deliberately not terminal: it can still become recovered,
which passes. unobservable still beats violation (H6).

In recorder mode the evidence lives in another process, so check tails
the recorder's log while it waits, consuming complete newline-terminated
records only. That reading is used only for the guard; the strict
whole-file ReadLog still runs after the writer exits and is the only
evidence classified. On a terminal verdict the run is classified over
[from, At] by the same decide, with the policy window clamped and the
grace zeroed; the requested window and real thresholds are restored and
the Result carries TerminatedEarly. An early exit can never be 0.

--no-fail-fast leaves the guard unset and reproduces the previous
full-window behavior exactly.

* feat(grafana-alertcheck): rename outcomes and print plain-worded tables (#2850)

check's output now speaks plain words, in both the JSON vocabulary and the
human tables:

  - outcomes: clean -> healthy, newly_bad -> new_failure,
    persistently_bad -> still_failing, flapping -> unstable,
    skipped -> paused, unobservable -> not_verified, and
    terminated_early.kind follows the same rename. A --min-observed deficit
    that no resolved rule explains is now not_counted instead of being
    blamed on a paused rule.
  - RESULTS and VIOLATIONS columns are spelled out (ALERT, VERDICT,
    BROKEN FOR, CHECKED EVERY, WINDOW COVERED, DETAILS; GRAFANA STATE,
    GRAFANA HEALTH, INSTANCES). INSTANCES is one word: the old
    "INSTANCE COUNT" header read as two columns, one of them empty
    under the count.
  - THRESHOLDS became LIMITS USED, with each limit named in plain words
    and explained by a legend under the table. The footer spells out the
    extra observation time, the evaluation wait and the clock difference
    from Grafana.

The rename reaches the JSON output, so consumers of violations[].outcome,
outcomes and terminated_early must move to the new vocabulary.
Tofel added a commit that referenced this pull request Sep 29, 2026
* feat(grafana-alertcheck): fail fast on a condition that cannot become a pass

check now stops collecting as soon as it observes a monotone terminal
verdict instead of always holding the runner to
to + transitionGrace + drainTimeout:

  - a post-from bad onset, which the full classifier calls newly_bad or
    flapping and fails whether or not it later clears; or
  - an inability that has already happened: a heartbeat gap, a sustained
    health=error run, a stale evaluation, an in-window pause, an absent
    rule.

terminalVerdict is pure and reuses proveCoverage and classifyRule over
the observed sub-window with a synthetic sentinel. A preexisting bad
instance is deliberately not terminal: it can still become recovered,
which passes. unobservable still beats violation (H6).

In recorder mode the evidence lives in another process, so check tails
the recorder's log while it waits, consuming complete newline-terminated
records only. That reading is used only for the guard; the strict
whole-file ReadLog still runs after the writer exits and is the only
evidence classified. On a terminal verdict the run is classified over
[from, At] by the same decide, with the policy window clamped and the
grace zeroed; the requested window and real thresholds are restored and
the Result carries TerminatedEarly. An early exit can never be 0.

--no-fail-fast leaves the guard unset and reproduces the previous
full-window behavior exactly.

* feat(grafana-alertcheck): rename outcomes and print plain-worded tables (#2850)

check's output now speaks plain words, in both the JSON vocabulary and the
human tables:

  - outcomes: clean -> healthy, newly_bad -> new_failure,
    persistently_bad -> still_failing, flapping -> unstable,
    skipped -> paused, unobservable -> not_verified, and
    terminated_early.kind follows the same rename. A --min-observed deficit
    that no resolved rule explains is now not_counted instead of being
    blamed on a paused rule.
  - RESULTS and VIOLATIONS columns are spelled out (ALERT, VERDICT,
    BROKEN FOR, CHECKED EVERY, WINDOW COVERED, DETAILS; GRAFANA STATE,
    GRAFANA HEALTH, INSTANCES). INSTANCES is one word: the old
    "INSTANCE COUNT" header read as two columns, one of them empty
    under the count.
  - THRESHOLDS became LIMITS USED, with each limit named in plain words
    and explained by a legend under the table. The footer spells out the
    extra observation time, the evaluation wait and the clock difference
    from Grafana.

The rename reaches the JSON output, so consumers of violations[].outcome,
outcomes and terminated_early must move to the new vocabulary.
Tofel added a commit that referenced this pull request Sep 29, 2026
…rder (#2843)

* feat(grafana-alertcheck): add stop subcommand to reap a detached recorder

Extract the recorder-stop protocol out of check into an exported
gate.StopRecorder, then expose it as `stop --out <file> [--pidfile F]`.

stop reuses check's pidfile-plus-flock authority: the flock proves a
writer exists right now, the pidfile names it. Unlike check it is a
cleanup operation, so it SIGKILLs a recorder that ignores SIGTERM,
removes the pidfile, and treats a missing pidfile as "nothing to stop".
That makes it idempotent and safe as an `if: always()` step after a
failed work step, where the recorder's Setsid session means neither
check nor the runner will otherwise reap it.

check keeps its semantics unchanged: a writer that will not exit is a
could-not-check, never a silent kill, and it never removes the pidfile.

* alertgate/fail fast (#2844)

* feat(grafana-alertcheck): fail fast on a condition that cannot become a pass

check now stops collecting as soon as it observes a monotone terminal
verdict instead of always holding the runner to
to + transitionGrace + drainTimeout:

  - a post-from bad onset, which the full classifier calls newly_bad or
    flapping and fails whether or not it later clears; or
  - an inability that has already happened: a heartbeat gap, a sustained
    health=error run, a stale evaluation, an in-window pause, an absent
    rule.

terminalVerdict is pure and reuses proveCoverage and classifyRule over
the observed sub-window with a synthetic sentinel. A preexisting bad
instance is deliberately not terminal: it can still become recovered,
which passes. unobservable still beats violation (H6).

In recorder mode the evidence lives in another process, so check tails
the recorder's log while it waits, consuming complete newline-terminated
records only. That reading is used only for the guard; the strict
whole-file ReadLog still runs after the writer exits and is the only
evidence classified. On a terminal verdict the run is classified over
[from, At] by the same decide, with the policy window clamped and the
grace zeroed; the requested window and real thresholds are restored and
the Result carries TerminatedEarly. An early exit can never be 0.

--no-fail-fast leaves the guard unset and reproduces the previous
full-window behavior exactly.

* feat(grafana-alertcheck): rename outcomes and print plain-worded tables (#2850)

check's output now speaks plain words, in both the JSON vocabulary and the
human tables:

  - outcomes: clean -> healthy, newly_bad -> new_failure,
    persistently_bad -> still_failing, flapping -> unstable,
    skipped -> paused, unobservable -> not_verified, and
    terminated_early.kind follows the same rename. A --min-observed deficit
    that no resolved rule explains is now not_counted instead of being
    blamed on a paused rule.
  - RESULTS and VIOLATIONS columns are spelled out (ALERT, VERDICT,
    BROKEN FOR, CHECKED EVERY, WINDOW COVERED, DETAILS; GRAFANA STATE,
    GRAFANA HEALTH, INSTANCES). INSTANCES is one word: the old
    "INSTANCE COUNT" header read as two columns, one of them empty
    under the count.
  - THRESHOLDS became LIMITS USED, with each limit named in plain words
    and explained by a legend under the table. The footer spells out the
    extra observation time, the evaluation wait and the clock difference
    from Grafana.

The rename reaches the JSON output, so consumers of violations[].outcome,
outcomes and terminated_early must move to the new vocabulary.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants