Reading Keeper Logs: Why Strategy Allocations Change (And Why They Don't)
Every rebalance has a reasonCode and a gate log. Here's how to read them — and why 'skip' is the right answer more often than 'move'.
When your Apyee vault rebalances, the activity feed shows you the what: which strategy lost allocation, which gained it, what APY each was at. What the on-chain record also has — and what most depositors never look at — is the why. That field is called reasonCode, and it determines whether a move surfaces as a "yield" rebalance versus internal housekeeping.
There are exactly four reasonCodes. Knowing the difference is the difference between thinking "why does my allocation keep moving?" and reading the same data as "okay, the Keeper did its job".
The four reasonCodes
| reasonCode | Trigger | Frequency |
|---|---|---|
yield | APY spread between strategies clears all four gates | Most common |
alloc | Idle USDC needs to be redeployed (after emergency exit) | Rare |
hardcap | One strategy somehow exceeds its 40% cap | Very rare |
emergency | Composite risk signal triggered an emergencyWithdraw | Hopefully never |
In the activity feed, every rebalance shows a chip with the reason:
yield ↑— green chip, the spike-catching caserealloc— blue chip, re-fanning out reclaimed idle (almost always benign)cap limit— yellow chip, forced rebalance because of over-allocationemergency— red chip, the protocol got pulled out of something
Most users will only ever see yield and realloc chips. The other two are designed to fire rarely, by construction.
The four gates a yield rebalance must clear
A yield rebalance only fires if all of these pass:
- APY spread ≥ 10 bps. Smaller gaps aren't worth the gas.
- Gas ROI ≥ 3×. Expected captured yield must pay for the gas at least three times over within a reasonable holding window.
- Minimum move ≥ $500. Moving $20 between strategies is a rounding error after gas.
- Cooldown ≥ 6 hours. Prevents whipsaw on short-lived rate noise.
If any gate fails, the cycle logs the reason and waits 5 minutes for the next tick. A representative log line, from a real cycle on Ethereum:
[rebalance ETH] ideal=Aave 36% / Morpho 30% / Fluid 27% / idle 10%
current=Aave 32% / Morpho 28% / Fluid 30% / idle 10%
proposed=Fluid → Aave (4%)
gate=APY ✓ (200bps) / gasROI ✓ ($120 vs $40) / minAmount ✓ / cooldown ✗ (4h left)
action=skip (cooldown)
Read it left to right: the Keeper computed an ideal allocation, saw the current allocation was 4 percentage points off in the Fluid → Aave direction, the spread (200 bps) cleared the threshold, the gas math worked, the dollar amount was big enough — but cooldown said "you already moved in the last 6 hours". So: skip.
The next cycle reconsiders. If the spread is still there 4 hours later, the rebalance fires then. If it's not, the cycle skips again with a different reason. Either way, the log explains itself.
Why direction lock exists
A subtle but important gate that doesn't appear in the four above: direction lock. The Keeper refuses to move out of a higher-APY strategy into a lower-APY strategy, even if doing so would reduce deviation from the ideal allocation.
v1 of the Keeper (pre-2026-05-13) didn't have this lock. It would occasionally propose moves like "Aave 8% → Morpho 5% to fix a 4 pp deviation", which is technically a deviation reduction but obviously decreases yield. v2 added a direction check at the proposal stage: from.apy < to.apy must hold, or the proposal is rejected before gate evaluation even starts.
You won't see direction-rejected proposals in the activity feed — they don't become a transaction. They do show up in the Keeper's internal logs as skip (direction). If you're auditing operator behavior, that's where to look.
What this transparency costs
Every reasonCode, every gate result, every apyFromAt/apyToAt pair, every estimatedGainBps is written to the on-chain event. Storage costs gas. We pay it anyway, because:
- It's the only honest way to measure whether the Keeper is doing its job.
- It's the only way for you to audit a fee-charging service.
- It makes "capture" claims falsifiable. If we say "we caught a 209 bps uplift on Base", you can pull the event, read the fields, and check the math.
The alternative — a black-box rebalancer with a press release — would be cheaper to operate and easier to market. It would also be indistinguishable from a service that doesn't actually do what it claims.
What this means for you
Three practical things to take from this:
When you see a realloc chip, don't worry. It's the Keeper redeploying idle that briefly accumulated. Not a sign of anything bad.
When you see an emergency chip, do look closer. That's the one reasonCode that says "we pulled out of something because a risk signal fired". The detail tooltip will tell you which strategy and why.
When you see no rebalance for a while, that's also fine. Many cycles end in skip. The most common skip reasons are "APY spread too small" (markets stable) or "cooldown" (we already moved recently). The Keeper's job isn't to look busy. It's to act when acting beats not acting.
The takeaway
A rebalance log isn't a sign of activity. It's a sign of decided activity — and the same log shows you exactly why decisions went the other way when they did. Read the reasonCode chip first, the gate line second, the APY numbers third. In that order, the picture becomes legible.

