feat(morpho-v2): one grouped governance alert per vault - #330
Merged
Conversation
Governance diffs fired one Telegram message per category, so a vault with new pending configs plus an owner change plus an adapter swap produced five separate messages. Every category now buffers into a per-vault _VaultDiff that is flushed as a single message with one header and the highest severity of the group. Pending submits keep their existing collapsing of a shared validAt/txHash, so a batched multicall stays one section. Two properties the buffer makes possible: * Groups longer than Telegram's 4096-char cap split into "(i/N)" parts instead of being truncated — utils.telegram truncates and drops Markdown, which would silently lose the tail of exactly the large batches worth alerting on. * Cache cursors are committed only after the send succeeds. Writing them during the diff pass marked a change as alerted even when Telegram failed, and main() reports the failure without ever re-sending it. A partial send now repeats the whole group next run; duplicates beat a governance change nobody ever sees. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
spalen0
force-pushed
the
feat/morpho-v2-grouped-alerts
branch
from
July 31, 2026 14:58
364efbb to
3fb2601
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Supersedes #328, which was based on
feat/peg-monitoring-l3-eventsand predates the pending-alert grouping already onmain(8e09155) and the KATANA V2 vaults already inconfig.py. This branch is cut frommainand keeps both.1. One grouped alert per vault
Governance diffs fired one Telegram message per category, so a vault with new pending configs + a role change + an adapter swap produced several messages. Every category now buffers into a per-vault
_VaultDiff, flushed as a single message with one header (V2 [name](url) on chain), one severity (highest of the group), and sections separated by---.main's collapsing of a sharedvalidAt/txHashacross a batched multicall is preserved — that batch stays one section rather than N.Before (three messages, two vaults):
After (two messages — grouping is per vault, so the two Steakhouse resolutions merge):
The larger win is several categories landing on one vault in the same run — 4 messages become 1, at the highest severity of the group:
2. Oversized groups split instead of truncating
utils.telegramtruncates pastMAX_MESSAGE_LENGTHand drops Markdown with it, so concatenating naively would lose the tail of exactly the large batches worth alerting on._send_vault_alertspacks sections into as many(i/N)parts as needed, each under budget, with the header repeated. The budget derives fromMAX_MESSAGE_LENGTHrather than a hardcoded number.3. Cache cursors commit after the send
Previously the diff pass wrote cursors and then sent. If Telegram failed, the change was already marked as alerted and
main()reported the failure without ever re-sending it — the alert was lost. Writes are now buffered in_VaultDiffand committed only once the send returns. A partial send (part 1 lands, part 2 fails) repeats the whole group next run; duplicates beat a governance change nobody ever sees.Verification
Dry run against live data (
LOG_LEVEL=DEBUG, isolatedCACHE_DIR):Sentora RLUSD Main— 4 pending cap increases in one message.Gauntlet USDTon Katana — theincreaseTimelock(setSendAssetsGate → 604800s)alert.Tests
701 passed,ruff checkandruff formatclean. New coverage:send_alertleaves the cache untouched; a working one commits the cursors🤖 Generated with Claude Code