Skip to content

fix(llm): rate governance votes on what they execute - #444

Merged
spalen0 merged 3 commits into
mainfrom
fix/llm-vote-risk
Oct 23, 2026
Merged

spalen0 merged 3 commits into
mainfrom
fix/llm-vote-risk

Conversation

@spalen0

@spalen0 spalen0 commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Strategist Multisig nonce 3376 (gist) only calls Voter.vote_yea for proposals 2–5 on Voting 0x543e8871562a8C53E8B6a26835aeEcB3a5A13070. It was still tagged MEDIUM. The model's own analysis found no transfers, approvals or upgrades. It raised the tag only because "proposal contents and effective voting weight are unverified".

Per the verified Voter.vy / Voting.vy, vote_yea only records vote weight, plus YBC/delegated-staking tallies when the voter is a YBC member. A passed proposal still needs its own Voting.execute(uint256,bytes) call, which our monitor judges on its actions when it is queued.

Changes

System prompt (utils/llm/ai_explainer.py), two general rules:

  • Rate what executes. The risk tag is based on what the transaction executes. Missing context about effects it doesn't execute (proposal contents, how a recipient later uses funds) goes under Not verified and doesn't raise the tag. The rules for unverified targets and undecoded payloads still apply, since those do execute.
  • Votes are LOW, in any implementation. A call that only records a governance vote is LOW even when the proposal contents are unknown. Exceptions:
    • the vote itself executes the proposal (an Aragon-style _executesIfDecided flag set to true, or auto-execution on quorum). The model judges what executes.
    • delegating voting power, which is not a vote.

An earlier revision of this PR added per-signature vote anchors to utils/risk_anchors.py. They were dropped in favour of this single rule, which also covers voting contracts we haven't listed.

Testing

  • tests/ai_explainer/test_prompt.py: the system prompt carries the vote rule and its exceptions.
  • Full suite: 1999 passed, 4 skipped. ruff clean.
  • Not re-run against the live tx (no API keys in this environment).

🤖 Generated with Claude Code

spalen0 and others added 3 commits October 23, 2026 12:10
Strategist Multisig nonce 3376 only called Voter.vote_yea for proposals 2-5,
moving no funds and enacting nothing (execution is a separate
Voting.execute), yet was tagged MEDIUM because the proposal contents were
unverified.

- risk anchors: vote_yea/vote_nay (Yearn Voter) and Governor
  castVote/castVoteWithReason anchor at LOW
- system prompt: missing context about effects the transaction does not
  execute goes under "Not verified" and does not raise the tag; unverified
  targets and undecoded payloads still do

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Generalize the vote anchors beyond Yearn's Voter: OpenZeppelin Governor /
Compound Bravo castVote* (incl. BySig), GovernorAlpha castVote(uint256,bool),
Aave v2 submitVote and Curve-style vote_for_gauge_weights all anchor LOW.

Aragon-style vote(uint256,bool,bool) / votePct(...,bool) run the vote's
script in the same tx when `_executesIfDecided` is set and the vote decides
it, so they are LOW only with the flag off and MEDIUM ("judge that script")
with it on. delegate(address) stays unanchored: it hands voting power to
someone else.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hors

Per-signature vote anchors only cover the implementations we list. Drop them
and state the rule once in the system prompt: a call that only records a
governance vote, in any implementation, is LOW. Exceptions are a vote that
itself executes the proposal (Aragon-style `_executesIfDecided`, auto-execution
on quorum) and delegation, which is not a vote.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@spalen0
spalen0 marked this pull request as ready for review October 23, 2026 12:26
@spalen0
spalen0 merged commit fd810cd into main Oct 23, 2026
3 checks passed
@spalen0
spalen0 deleted the fix/llm-vote-risk branch October 23, 2026 12:27
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.

1 participant