Skip to content

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

Merged
Tofel merged 2 commits into
mainfrom
alertgate/stop
Sep 29, 2026
Merged

Tofel merged 2 commits into
mainfrom
alertgate/stop

Conversation

@Tofel

@Tofel Tofel commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

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.


Stack created with GitHub Stacks CLI • Give Feedback 💬

@Tofel
Tofel added this pull request to stack #2845 September 28, 2026 10:11
@Tofel
Tofel requested a lite review from Copilot September 28, 2026 10:11
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

📊 API Diff Results

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

View full report

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

Unresolved recorder identity and cleanup error-handling issues can cause unsafe termination or incomplete cleanup.

Review effort: Lite
Findings: 1 High severity · 1 Medium severity

Open (2)
What changed in this PR

Adds a stop subcommand and shared recorder-stop protocol for safely reaping detached Grafana recorders.

Changes:

  • Adds SIGKILL fallback and pidfile cleanup.
  • Exposes gate.StopRecorder and registers the CLI command.
  • Adds tests and updates documentation while preserving check semantics.
File Summary
grafana-alertcheck/​README.md Updates workflow documentation.
grafana-alertcheck/​internal/​gate/​stop.go Implements recorder stopping and cleanup.
grafana-alertcheck/​internal/​gate/​stop_test.go Tests stop behavior.
grafana-alertcheck/​internal/​gate/​check.go Reuses the shared stop protocol.
grafana-alertcheck/​internal/​gate/​check_process.go Adds SIGKILL support.
grafana-alertcheck/​docs/​reference/​cli.md Documents stop usage and semantics.
grafana-alertcheck/​docs/​index.md Adds cleanup guidance.
grafana-alertcheck/​docs/​architecture.md Documents stop and check semantics.
grafana-alertcheck/​cmd/​stop.go Implements the stop command.
grafana-alertcheck/​cmd/​stop_test.go Tests CLI behavior.
grafana-alertcheck/​cmd/​main.go Registers the stop subcommand.

💡 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/stop.go Outdated
Comment thread grafana-alertcheck/internal/gate/stop.go Outdated

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

Unresolved stop-protocol cleanup issues affect idempotence and can remove a newer pidfile; the unrelated 1 artifact should also be removed.

Review effort: Lite
Findings: 1 High severity · 1 Medium severity · 1 Low severity

Open (3)
Resolved since last review (2)

Comment thread grafana-alertcheck/internal/gate/stop.go Outdated
Comment thread grafana-alertcheck/internal/gate/stop.go Outdated
Comment thread 1 Outdated
@Tofel
Tofel force-pushed the alertgate/stop branch 2 times, most recently from 775b869 to 9bbfec2 Compare September 28, 2026 18:09
@Tofel
Tofel requested a lite review from Copilot September 28, 2026 18:09

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

Unresolved stop-protocol authority and process-cleanup safety issues must be addressed.

Review effort: Lite
Findings: 1 High severity

Open (1)
Resolved since last review (3)

Comment thread grafana-alertcheck/internal/gate/stop.go Outdated

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

🔵 Needs a closer look

Two moderate unresolved findings require pidfile cleanup and stronger idempotence coverage.

Review effort: Lite
Findings: None

Resolved since last review (1)

@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 enabled auto-merge (squash) September 29, 2026 09:20
Tofel and others added 2 commits September 29, 2026 11:26
…rder

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.
* 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
Tofel merged commit 85f64ec into main Sep 29, 2026
62 checks passed
@Tofel
Tofel deleted the alertgate/stop branch September 29, 2026 09:33
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.

3 participants