Follow-ups from bot review feedback on #216 (the epic-branch → main merge PR). These were verified as valid against the current code; consolidating them here rather than patching the merge PR.
1. types/suite_test.go — nil panic in shared assertion helper
RunValidateBasicTable calls assert.Error(t, err, ...) and then unconditionally dereferences err.Error(). Unlike require, assert does not halt the test, so a nil error panics and masks the real assertion failure.
Fix: guard the Contains behind the assert.Error result:
if tc.expectedErr != "" {
if assert.Error(t, err, "expected error for case %q", tc.name) {
assert.Contains(t, err.Error(), tc.expectedErr, "error should contain expected substring for case %q", tc.name)
}
}
2. keeper/vault_test.go — rollback test never reaches NAV seeding
TestCreateVault_InitialPaymentNAVRolledBackOnFailure pre-creates the share marker, so CreateVault fails in createVaultMarker before seedInitialPaymentNAV runs. The NAV is never written, so asserting its absence proves nothing about rollback.
Note: seedInitialPaymentNAV is currently the last step before write(), so no downstream failure can occur after seeding without a test hook. The pragmatic fix is to force a failure inside the seed step (e.g. price denom == payment denom) and assert that the previously created vault account/marker are rolled back — and rename/redocument the test to describe what it actually covers.
3. keeper/nav.go — validateVaultNAVFields permits NAV entries for the underlying asset denom
The guard rejects nav.Denom == vault.TotalShares.Denom but not nav.Denom == vault.UnderlyingAsset. UnitPriceFraction short-circuits to (1,1) for the underlying asset before any NAV lookup, so such an entry can be stored but is never read — dead state that could confuse operators inspecting the NAV table.
Fix: add an explicit rejection for nav.Denom == vault.UnderlyingAsset (plus a test case), and update the SetVaultNAV godoc.
4. keeper/migrations.go — migrations iterate all auth accounts instead of the Vaults collection
Both MigrateVaultAccountPaymentDenomDefaults and migrateInternalNAVSeedFromMarker use k.AuthKeeper.GetAllAccounts(ctx), which is O(total_accounts) in time and memory. The keeper already has a Vaults collection with an O(vault_count) iteration path (GetVaults / Vaults.Walk in keeper/state.go).
Fix: iterate k.GetVaults(ctx) and load each vault via k.GetVault(ctx, addr). One-time migrations, so low urgency — but cheap to fix and more consistent with the rest of the keeper.
Origin: CodeRabbit and Greptile review threads on #216. Items 5–7 from that review were declined (table-driven refactor preferences; one finding factually incorrect about cache-context event propagation).
Follow-ups from bot review feedback on #216 (the epic-branch → main merge PR). These were verified as valid against the current code; consolidating them here rather than patching the merge PR.
1.
types/suite_test.go— nil panic in shared assertion helperRunValidateBasicTablecallsassert.Error(t, err, ...)and then unconditionally dereferenceserr.Error(). Unlikerequire,assertdoes not halt the test, so a nil error panics and masks the real assertion failure.Fix: guard the
Containsbehind theassert.Errorresult:2.
keeper/vault_test.go— rollback test never reaches NAV seedingTestCreateVault_InitialPaymentNAVRolledBackOnFailurepre-creates the share marker, soCreateVaultfails increateVaultMarkerbeforeseedInitialPaymentNAVruns. The NAV is never written, so asserting its absence proves nothing about rollback.Note:
seedInitialPaymentNAVis currently the last step beforewrite(), so no downstream failure can occur after seeding without a test hook. The pragmatic fix is to force a failure inside the seed step (e.g. price denom == payment denom) and assert that the previously created vault account/marker are rolled back — and rename/redocument the test to describe what it actually covers.3.
keeper/nav.go—validateVaultNAVFieldspermits NAV entries for the underlying asset denomThe guard rejects
nav.Denom == vault.TotalShares.Denombut notnav.Denom == vault.UnderlyingAsset.UnitPriceFractionshort-circuits to (1,1) for the underlying asset before any NAV lookup, so such an entry can be stored but is never read — dead state that could confuse operators inspecting the NAV table.Fix: add an explicit rejection for
nav.Denom == vault.UnderlyingAsset(plus a test case), and update theSetVaultNAVgodoc.4.
keeper/migrations.go— migrations iterate all auth accounts instead of the Vaults collectionBoth
MigrateVaultAccountPaymentDenomDefaultsandmigrateInternalNAVSeedFromMarkerusek.AuthKeeper.GetAllAccounts(ctx), which is O(total_accounts) in time and memory. The keeper already has aVaultscollection with an O(vault_count) iteration path (GetVaults/Vaults.Walkinkeeper/state.go).Fix: iterate
k.GetVaults(ctx)and load each vault viak.GetVault(ctx, addr). One-time migrations, so low urgency — but cheap to fix and more consistent with the rest of the keeper.Origin: CodeRabbit and Greptile review threads on #216. Items 5–7 from that review were declined (table-driven refactor preferences; one finding factually incorrect about cache-context event propagation).