Add cold-catchup carveout to check-12b post-restart absolute fire - #3931
Add cold-catchup carveout to check-12b post-restart absolute fire#3931tomerweller wants to merge 3 commits into
Conversation
Add cold-catchup carveout tests for check-12b's post-restart absolute fire: suppressed on bucket-apply (cold catchup) and on FRESH_START, exemption line renders, and warm restart still fires. Fail on main: eval_counter_streak has no fresh_start kwarg and no cold-catchup gate; renderer has no exemption form. Refs #3816 Co-authored-by: Claude Code <claude-code@anthropic.com>
The post-restart absolute fire (#3198) exists to catch a warm restart whose startup stall burst straddles the baseline-reset tick. A cold catchup after a state wipe legitimately accrues >= post_restart_absolute_threshold escalation ticks (forcing_catchup_behind) — being behind for minutes across ~10^5 ledgers is the point, not a stall — so the fire is a false positive on a healthy post-wipe recovery (#3816). Suppress the one-shot fire when this incarnation demonstrably did a from-scratch HAS-restore catchup, signalled by stellar_history_bucket_apply_success_total > 0 (per-incarnation, only emitted on the bucket-apply path, 0/absent on a warm near-tip restart), OR by FRESH_START=yes as a belt-and-suspenders arm. Keying on bucket-apply (not crash recovery) keeps #3197's blind spot closed: #3197 was a warm restart that did no bucket apply, so the fire still triggers there. A stuck cold catchup is still caught — only the one-shot fire is exempted; the same-PID delta/streak/burst path fires on later ticks if the counter keeps climbing. The exemption is surfaced so the tick shows "collecting baseline (cold-catchup exemption)". No threshold/toml change. Refs #3816 Co-authored-by: Claude Code <claude-code@anthropic.com>
🔍 Reviewer: CorrectnessVerdict: APPROVE Summary: Focused, well-tested cold-catchup carveout in Full reviewCycle 1 — complete class-labeled assessment (no prior Correctness comment on this PR).
No blocking concerns. |
🔍 Reviewer: RiskVerdict: APPROVE Summary: Monitoring-tooling-only change (no Full reviewCycle 1 — complete class-labeled assessment (no prior Risk comment on this PR).
No blocking concerns. |
Do: Re-triggered CI (Mode B — CI-failure bounce)Both reviewer lenses APPROVE and no inline changes were requested, so no code change was warranted. The bounce reason was a flaky testnet-infra cancellation of the Quickstart run, not a diff-attributable failure.
Ready for re-review once CI settles. |
Do: Re-triggered CI (Mode B — CI-failure bounce, 2nd occurrence)Both reviewer lenses (Correctness, Risk) APPROVE and there are no inline comments, so no code change is warranted. The bounce reason is again an environmental testnet-shard failure, not a diff-attributable one.
Ready for re-review once CI settles. If the testnet shard times out again environmentally, this is a candidate for /review-pr force-converge given both lenses approve and the failure is off-diff. |
Review: Bounce-Back Cycle 3Reason: CI failed (unrelated, will rebase) Reviewer A: APPROVE — cold-catchup carveout is correct and well-scoped; bug-fix regression test provably fails on origin/main. Unchanged since Cycle 1 (same head Both reviewer lenses APPROVE. Every code/build/test/lint check is green. The one red signal is a single Quickstart job — This is unrelated to the diff: this PR changes only Critical — head has NOT advanced. The head commit is still Last bounce before the head-scoped cap. This is bounce 3 on the current code state. If the head is still not advanced on the next Routing back to |
Both reviewer lenses (Correctness, Risk) APPROVE and there are no inline comments, so no code change is warranted. The prior bounces were caused by an environmental testnet-shard timeout in the Quickstart run, not by this diff (monitoring tooling only: scripts/lib/eval-alarms.py, its test, and .claude/skills/monitor-tick/SKILL.md). origin/main has not advanced past 9f534c2, so a rebase is a no-op. This empty commit advances the head SHA — as /review-pr Cycle 3 required — so CI re-runs against current testnet state and the head-scoped bounce counter resets. Refs #3816 Co-authored-by: Claude Code <claude-code@anthropic.com>
tomerweller
left a comment
There was a problem hiding this comment.
Do: Re-triggered CI on a fresh head SHA (Mode B — CI-failure bounce, cycle 4)
Both reviewer lenses (Correctness, Risk) APPROVE and there are no inline comments, so no code change is warranted. The bounce reason is again the environmental testnet-shard timeout in the Quickstart run (test (testnet, core,horizon, ...)), not diff-attributable — this PR touches only scripts/lib/eval-alarms.py, its test, and .claude/skills/monitor-tick/SKILL.md.
Per the Cycle 3 requirement to advance the head SHA (a bare CI re-trigger on the same tree does not reset the head-scoped bounce counter):
- Head advanced
c7a50e08→222b9cb.origin/mainhas not moved past9f534c2, so a rebase is a genuine no-op; the head is advanced via an empty commit that re-runs CI against current testnet state. - Local re-verification on the new head:
py_compile scripts/lib/eval-alarms.pyclean;test_eval_alarms_counter_reset.py— 32 passed, 0 failed.
Ready for re-review. The head-scoped bounce counter is now reset to the new SHA.
🔍 Reviewer: CorrectnessVerdict: APPROVE Summary: Cold-catchup carveout is correct, well-scoped, and covered by a bug-fix regression test that provably fails at the pre-fix commit and passes after the fix. Full reviewReviewed the PR head (222b9cb) merged with current
No blocking concerns. |
🔍 Reviewer: RiskVerdict: APPROVE Summary: Monitoring-tooling-only change (Python + skill doc); no observable/interop-parity surface, no regression/security/perf/operational risk. Warm-restart stall detection is preserved and guard-tested. Full reviewChanged files:
No blocking concerns. |
Review: Blocked — Unrelated CI Red Persists After Head AdvanceStatus: blocked Pattern: For three cycles now the only red signal has been a single Quickstart job — This is environmental testnet-infra flakiness, not diff-attributable: the PR changes only Per the Cycle 2 escalation plan ("if the testnet job fails again after a genuine rebase / head-SHA advance and remains red, the next Both agent reviewer lenses APPROVE — the code is correct and well-scoped; the block is purely the persistent, unrelated testnet-shard cancellation. Operator options:
To retry via the pipeline after the cause clears, post |
Closes #3816
Summary
check-12b's post-restart absolute fire (#3198) WARNs on a baseline-reset tick whenever the discarded
forcing_catchup_behindcounter is ≥ 50, to catch a warm restart whose startup stall burst straddles the reset tick. A cold catchup after a state wipe legitimately accrues ≥ 50 escalation ticks (63 across ~137k ledgers in the reported case) — being behind for minutes is the whole point of a from-scratch catchup, not a stall — so the fire is a false positive on a healthy post-wipe recovery.This adds a cold-catchup carveout in
eval_counter_streak: the one-shot post-restart fire is suppressed when this incarnation demonstrably did a from-scratch HAS-restore catchup, signalled bystellar_history_bucket_apply_success_total > 0(a per-incarnation counter, only emitted on the bucket-apply path, 0/absent on a warm near-tip restart), OR byFRESH_START=yesas a belt-and-suspenders arm. Keying on bucket-apply — not crash recovery — keeps the #3197/#3198 blind spot closed: #3197 was a warm restart that did no bucket apply, so the fire still triggers there. A genuinely stuck cold catchup is still caught, since only the one-shot fire is exempted and the same-PID delta/streak/burst path fires on later ticks if the counter keeps climbing. The exemption is surfaced so the tick rendersrecovery_stalled: collecting baseline (cold-catchup exemption). No threshold or toml change.Plan reference
Converged Plan comment
Test plan
python3 scripts/lib/test_eval_alarms_counter_reset.py— 32 passedscripts/lib/test_eval_alarms_*.pysuite — all greenpython3 -m py_compile scripts/lib/eval-alarms.pyRegression test (kind: bug-fix)
scripts/lib/test_eval_alarms_counter_reset.py::test_post_restart_fire_suppressed_on_cold_catchup(+test_render_cold_catchup_exemption_line,test_post_restart_fire_suppressed_on_fresh_start,test_post_restart_fire_still_fires_warm_restart)04afcba— verified FAILED with:eval_counter_streak() got an unexpected keyword argument 'fresh_start'and renderer emitting the plaincollecting baselinelinec7a50e0Deviations from plan
.claude/skills/monitor-tick/SKILL.md. There is also a.agents/skills/monitor-tick/SKILL.mdmirror, but the two already diverge at HEAD (not kept byte-identical), so I updated only the.claudecopy per plan scope rather than reconciling a stale mirror.🤖 Generated with Claude Code