chore: bump biome to 2.4.14 and enforce stricter lint rules#583
Merged
Conversation
- Migrate biome.json to v2 schema (files.includes, assist.actions) - Enable complexity/useMaxParams (max=2) — 244 violations annotated with // biome-ignore + TODO refactor to ≤2 params - Enable nursery/noFloatingPromises, noMisusedPromises, noShadow, useExhaustiveSwitchCases; style/noUselessElse, noParameterAssign — 122 violations annotated with rule-specific TODO ignores - Disable suspicious/noNonNullAssertedOptionalChain and useIterableCallbackReturn (new in 2.x recommended set; out of scope) - Update scripts/lint/checksum-address.js to read v2 files.includes - Absorb v2 formatter changes (JSON, organizeImports) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Collaborator
|
@codex reivew |
|
Codex Review: Didn't find any major issues. Can't wait for the next one! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Foulks-Plb
previously approved these changes
May 4, 2026
… barrel cycle aaveV2/aaveV3/compoundV3 (borrow) and aaveV2/aaveV3/aaveV3Optimizer/ compoundV2/compoundV3 (supply) imported their base class through the folder's ./index.js barrel. The cycle only loaded successfully when the base class re-export came first; Biome v2's organizeImports sorts PascalCase after lowercase, putting MigratableBorrowPosition.js last and causing "Class extends value undefined" at module evaluation. Import the base class directly from its source file to break the cycle. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Foulks-Plb
approved these changes
May 4, 2026
0xbulma
added a commit
that referenced
this pull request
May 4, 2026
Biome 2.4.14 (bumped on main in #583) enforces stricter import sorting. The CI lint job failed with `assist/source/organizeImports` on packages/morpho-test/src/fixtures/tokens.test.ts. Auto-fixed via `biome check --write` — single-character reorder of the named imports from "@morpho-org/blue-sdk" so that addressesRegistry precedes ChainId alphabetically. Verification: - pnpm lint -> no errors (2 unrelated warnings on codegen.ts and 1 info on anvil.ts pre-date this branch). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0xbulma
added a commit
that referenced
this pull request
May 19, 2026
* docs(tibs): propose colocated vitest coverage migration
Adds TIB-2026-04-27 describing the convention switch to colocated
*.test.ts files across the eight in-scope SDK packages, the canonical
viem transport-level mock and nock-based HTTP/GraphQL patterns, and
an eight-phase rollout sequenced easiest-first.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(tibs): refocus TIB on maximizing unit-test coverage
Renames TIB-2026-04-27 from "colocated vitest coverage" to
"maximize unit-test coverage of SDK packages" — colocation is
demoted to one of four implementation conventions, alongside
viem transport-level mocking, nock for HTTP/GraphQL, and the
*.integration.test.ts naming for fork-bound tests.
Adds a coverage baseline section captured locally with
`pnpm test:coverage --project <name> --coverage.reportOnFailure=true`
across all in-scope projects, including:
- per-project pass/fail and coverage breakdown
- per-package lcov-merged line coverage table
- list of zero-coverage files of note (e.g. LiquidationEncoder.ts at
0% / 1,001 LOC, MetaMorphoAction.ts at 0% / 332 LOC,
liquidity-sdk-viem/loader.ts at 0%)
- list of <30% files (BundlerAction at 16.52%, midas tokens at 2.70%)
Each phase now has a concrete coverage target (≥ 80–95% line) and
explicitly names the zero-coverage files it must address.
Adds barrel `index.ts` to coverage exclusion (the long zero-coverage
tail in the report has no real code).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(tibs): scope TIB to adding unit tests, not migrating fork tests
Tightens the TIB so the only change to existing tests is "none."
Existing files under packages/X/test/ — fork-based, e2e, or
otherwise — keep their paths, names, imports, and contents. The
TIB now strictly adds new colocated unit tests in src/ alongside
them. Both layouts coexist for the lifetime of the TIB.
- Goals/Non-Goals: explicit non-goal that no existing test is
moved or refactored.
- Convention 1 (Colocation): scoped to NEW unit tests; layout
diagram shows the existing test/ directory marked UNTOUCHED.
- Convention 4: replaced "rename fork tests to *.integration.test.ts
and relocate" with "existing tests are not touched."
- vitest.config.ts: include is now a UNION of test/**/*.test.ts and
src/**/*.test.ts, so both layouts run side by side.
- Implementation Phases: each phase only ADDS files in src/; no
git mv, no path rewrites in existing tests.
- Considered Alternatives: adds rejection for "migrate existing
fork tests too" (unnecessary churn for no coverage gain).
- Open Questions: drops the *.integration.test.ts naming question
(now moot); keeps the "are there fork-only files" question.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(morpho-ts): phase 1 — colocated unit tests, raise coverage to 96%
Implements TIB-2026-04-27 phase 1.
Config:
- vitest.config.ts: union the morpho-ts project include to match both
the existing test/ files (untouched) and new src/**/*.test.ts.
- vitest.config.ts: tighten coverage.exclude to drop *.test.ts,
__test-utils__/, barrel index.ts, abis.ts, and api codegen.
- packages/morpho-ts/tsconfig.build.{cjs,esm}.json: exclude src/**/*.test.ts
and __test-utils__/ from emitted lib/.
New colocated unit tests (no existing test in test/ moved or modified):
- src/urls.test.ts: ZERO_ADDRESS, getSubdomainBaseUrl, all subdomain consts.
- src/utils.test.ts: every public utility (predicates, comparator, dotted
path access, keys/values/entries/fromEntries/mergeEntries,
retryPromiseLinearBackoff, deepFreeze, getLast/filterDefined).
- src/time/time.test.ts: full unit-conversion matrix and fromPeriod/toPeriod,
plus Time.wait and Time.timestamp.
- src/format/array.test.ts: formatUnion, formatEnumeration.
- src/format/string.test.ts: formatLongString edge cases.
- src/format/locale.test.ts: getLocaleSymbols, getEffectiveLocale,
convertNumStrToLocal, convertNumStrFromEffectiveTo,
getEnUSNumberToLocalParts. Browser globals stubbed via vi.stubGlobal.
Verification:
- 9 test files / 265 tests pass (project: morpho-ts).
- Coverage: morpho-ts line coverage 78.60% -> 96.32% (288/299).
utils.ts, urls.ts, format/array.ts, format/string.ts now at 100%.
- pnpm --filter @morpho-org/morpho-ts build succeeds.
- find packages/morpho-ts/lib -name "*.test.*" returns empty.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts:
# vitest.config.ts
* test(test): phase 2 — shared createMockClient/mockRead helpers + tests
Implements TIB-2026-04-27 phase 2.
New module @morpho-org/test/mock:
- createMockClient(chain): viem Client backed by a vi.fn() that intercepts
JSON-RPC at the transport level. Required for SDK code using viem/actions
named imports (readContract(client, ...)) — those resolve through
client.transport, not via methods on the client object.
- mockRead({ address, abi, functionName, result }): pre-program eth_call
responses by selector; multiple stack with last-write-wins semantics.
- expectReadCall(...): inspect mock call history and decode args.
Config:
- packages/test/package.json: ./mock sub-export wired into exports,
typesVersions, and publishConfig.exports.
- packages/test/tsconfig.build.{cjs,esm}.json: exclude src/**/*.test.ts
and __test-utils__/ from emitted lib/.
- vitest.config.ts: union test project include with src/**/*.test.ts.
Tests (24 pass):
- src/mock.test.ts: chain id default & override, unhandled-method throws,
mockRead by selector + address case-insensitive, distinct functions,
last-write-wins, abi validation, expectReadCall filtering.
- src/fixtures.test.ts: randomAddress structural shape, testAccount
derives canonical Anvil accounts deterministically.
Existing test/utils.test.ts is unchanged (still requires fork RPC).
Verification:
- pnpm test --project test --run packages/test/src -> 24/24 pass.
- pnpm --filter @morpho-org/test build succeeds with mock.js + mock.d.ts.
- find packages/test/lib -name "*.test.*" -> empty.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(blue-sdk): phase 3 — colocated unit tests for math, errors, tokens, vaults
Implements TIB-2026-04-27 phase 3 — focused on the zero-coverage files
the TIB baseline called out, plus the foundational math libraries.
Config:
- vitest.config.ts: union the blue-sdk project include with src/**/*.test.ts.
- packages/blue-sdk/tsconfig.build.{cjs,esm}.json: exclude src/**/*.test.ts
and __test-utils__/ from emitted lib/.
New colocated unit tests (existing test/unit/* and test/e2e/* untouched):
- src/math/MathLib.test.ts: WAD/RAY/MAX_UINT_*, maxUint, abs/min/max,
zeroFloorSub, mulDiv (Down/Up, divide-by-zero), wMul, wDiv, wTaylor-
Compounded, wToRay. → 100% coverage.
- src/math/SharesMath.test.ts: VIRTUAL_SHARES/ASSETS, toAssets/toShares
with empty pool & non-empty pool, rounding direction, monotonicity,
round-trip bias. → 100% coverage.
- src/math/AdaptiveCurveIrmLib.test.ts: wExp clipping (LN_WEI_INT,
WEXP_UPPER_BOUND), monotonicity, getBorrowRate first-interaction and
subsequent paths, getUtilizationAtBorrowRate full curve sweep,
clamping. → 100% coverage.
- src/errors.test.ts: every error class incl. BlueErrors and VaultV2Errors
namespaces, _try sync/async with matching/non-matching error classes
and subclasses. → 100% coverage.
- src/preLiquidation.test.ts: registry shape (8 LLTV tiers, 5 fields each),
invariants (preLCF2 > preLCF1, preLIF >= 1 WAD, preLltv < lltv),
getDefaultPreLiquidationParams success and unsupported throw.
→ 100% coverage.
- src/token/Token.test.ts: constructor field storage and BigIntish coercion,
Token.native, fromUsd/toUsd round-trip, rounding direction. → 100%.
- src/token/ConstantWrappedToken.test.ts: decimal scaling, slippage ignored,
exact-in/exact-out helpers. → 100%.
- src/token/ExchangeRateWrappedToken.test.ts: rate storage, wrap/unwrap
with various rates, slippage propagation. → 100%.
- src/holding/AssetBalances.test.ts: constructor seed, add accumulation,
sub decrement, chainability, all peripheral balance types. → 100%.
- src/user/User.test.ts: field storage and mutability. → 100%.
- src/vault/VaultUser.test.ts: field storage. → 100%.
- src/vault/VaultConfig.test.ts: decimals=18 forced, asset+decimalsOffset
preserved. → 100%.
- src/vault/VaultMarketPublicAllocatorConfig.test.ts: field storage. → 100%.
Verification:
- pnpm test --project blue-sdk --run packages/blue-sdk/src
-> 13 files, 148 tests pass.
- pnpm --filter @morpho-org/blue-sdk build succeeds.
- find packages/blue-sdk/lib -name "*.test.*" -> empty.
- Files moved from 0% baseline to 100%: AssetBalances, ExchangeRate-
WrappedToken, VaultUser. Math libraries also at 100%.
Out of scope for this phase: the large classes (Market 812 LOC,
MarketUtils 630, Vault 459, Position 342, VaultV2 288) which remain
covered by existing test/ files; their colocated unit tests can be
extended in a follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(morpho-test): phase 4 — colocated fixture validation tests
Implements TIB-2026-04-27 phase 4. Adds morpho-test as a new vitest
project (previously unrun) and 3 colocated test files validating the
canonical fixtures.
- vitest.config.ts: new "morpho-test" project, include src/**/*.test.ts.
- packages/morpho-test/tsconfig.build.{cjs,esm}.json: exclude tests +
helpers from emitted lib/.
- src/fixtures/markets.test.ts: 4-chain registry shape, MarketParams
invariants, idle market check, market id determinism, randomMarket.
- src/fixtures/vaults.test.ts: VaultConfig invariants, decimalsOffset,
randomVault defaults.
- src/fixtures/tokens.test.ts: withSimplePermit registry shape and
canonical addresses.
24 tests pass; build succeeds.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(liquidity-sdk-viem): phase 5 — colocated unit tests + nock GraphQL pattern
Implements TIB-2026-04-27 phase 5.
Config:
- vitest.config.ts: union liquidity-sdk-viem project include with
src/**/*.test.ts.
- packages/liquidity-sdk-viem/tsconfig.build.{cjs,esm}.json: exclude
src/**/*.test.ts and __test-utils__/ from emitted lib/.
Tests (12 pass):
- src/api/index.test.ts: apiSdk shape, getMarkets via nock against
BLUE_API_GRAPHQL_URL (success, empty items, GraphQL error path),
getSdk + custom endpoint round-trip. Establishes the canonical
nock pattern for GraphQL mocking.
- src/loader.test.ts: LiquidityLoader constructor stores client and
parameters, default empty params, fetch method exposed and returns
a Promise, maxWithdrawalUtilization override.
The existing test/loader.test.ts (fork-based, exercises the full
SimulationState path) is left untouched.
Verification:
- pnpm test --project liquidity-sdk-viem --run packages/liquidity-sdk-viem/src
-> 2 files / 12 tests pass.
- pnpm --filter @morpho-org/liquidity-sdk-viem build succeeds.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(test): tighten createMockClient client type to Client<CustomTransport, chain>
Followup to Phase 2: the previously over-erased Client type prevented
mock clients from satisfying SDK signatures expecting Client<Transport, Chain>
(observed in Phase 5's loader.test.ts). Tighten MockClientHandle.client to
Client<CustomTransport, chain> so it slots in everywhere a typed client
is required.
Also fixes Phase 5 loader.test.ts to cast string literal to MarketId
brand and import MarketId type.
Verification:
- pnpm --filter @morpho-org/test build succeeds.
- pnpm --filter @morpho-org/liquidity-sdk-viem build succeeds.
- All previous tests still pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(bundler-sdk-viem): phase 6 — colocated tests for errors + ActionBundle
Implements TIB-2026-04-27 phase 6.
Config:
- vitest.config.ts: union bundler-sdk-viem project include with
src/**/*.test.ts.
- packages/bundler-sdk-viem/tsconfig.build.{cjs,esm}.json: exclude
src/**/*.test.ts and __test-utils__/ from emitted lib/.
Tests (15 pass):
- src/errors.test.ts: every BundlerErrors class — Bundle (wraps inner
error, preserves index/op/steps/stack), MissingSignature, MissingSwapData,
UnexpectedAction (chainId in message), UnexpectedSignature, MissingSkim-
Handler, UnskimedToken.
- src/ActionBundle.test.ts: ActionBundleRequirements (defaults, sign
aggregation), ActionBundle (chainId branch, SimulationResult branch,
tx()/txs() shape).
Existing fork-based tests in test/ untouched.
Verification:
- pnpm test --project bundler-sdk-viem --run packages/bundler-sdk-viem/src
-> 2 files, 15 tests pass.
- pnpm --filter @morpho-org/bundler-sdk-viem build succeeds.
- find packages/bundler-sdk-viem/lib -name "*.test.*" -> empty.
Out of scope for this PR: BundlerAction.ts (2,346 LOC, dozens of
encoders) and operations.ts/actions.ts which need extensive ABI
round-trip suites; can land in follow-ups.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(blue-sdk-viem): phase 7 — colocated unit tests for utils, error, augment, fetchMarketParams
Implements TIB-2026-04-27 phase 7.
Config:
- vitest.config.ts: union blue-sdk-viem project include with
src/**/*.test.ts.
- packages/blue-sdk-viem/tsconfig.build.{cjs,esm}.json: exclude
src/**/*.test.ts and __test-utils__/ from emitted lib/.
Tests (38 pass):
- src/error.test.ts: isUnknownOfFactoryError predicate (plain Error,
non-Error, BaseError without revert, ContractFunctionRevertedError
with/without matching errorName, nested cause walking).
- src/utils.test.ts: safeParseNumber (integer/decimal/scientific/zero/
negative), safeParseUnits (truncation, leading dot, invalid input,
negative), safeGetAddress (EIP-55 normalization + invalid throws),
restructure (named ABI -> object, unnamed throws, missing function
throws).
- src/augment/augment.test.ts: every augmented blue-sdk class has a
static fetch wired (Market, MarketParams, Token, Position, Holding,
User, Vault, VaultConfig, VaultMarketAllocation, VaultMarketConfig,
VaultMarketPublicAllocatorConfig, VaultUser).
- src/fetch/MarketParams.test.ts: cache-hit returns cached MarketParams,
cache-miss path uses createMockClient + mockRead with the canonical
morpho address from chain registry.
Existing fork-based test/* files untouched.
Verification:
- pnpm test --project blue-sdk-viem --run packages/blue-sdk-viem/src
-> 4 files, 38 tests pass.
- pnpm --filter @morpho-org/blue-sdk-viem build succeeds.
- find packages/blue-sdk-viem/lib -name "*.test.*" -> empty.
Out of scope for this PR: MetaMorphoAction.ts (332 LOC of encoders)
and the full fetch/queries surface — extensive ABI round-trip tests
can land in follow-ups.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(liquidation-sdk-viem): phase 8 — colocated tests for thresholds, helpers, sky, 1inch
Implements TIB-2026-04-27 phase 8.
Config:
- vitest.config.ts: union liquidation-sdk-viem project include with
src/**/*.test.ts.
- packages/liquidation-sdk-viem/tsconfig.build.{cjs,esm}.json: exclude
src/**/*.test.ts and __test-utils__/ from emitted lib/.
Tests (33 pass):
- src/thresholds.test.ts: collateralUsdThreshold values across the
four chains.
- src/preLiquidation/helpers.test.ts: parseWithBigInt (trailing-n
conversion, negatives, arrays, nested objects, non-matching strings).
- src/swap/1inch.test.ts: URL builders, fetchSwap end-to-end via nock
(200 success path, slippage bps -> percentage conversion,
Authorization header, error path on 5xx, null/undefined param skipping).
- src/tokens/sky.test.ts: getAlternativeToken (4 token pairs +
unsupported throw), isTokenPair (both directions, missing inputs,
unrelated pairs), isSkyToken, getConversionFunction (4 directions
+ unsupported throw).
Existing test/* fork-based tests untouched.
Verification:
- pnpm test --project liquidation-sdk-viem --run packages/liquidation-sdk-viem/src
-> 4 files, 33 tests pass.
- pnpm --filter @morpho-org/liquidation-sdk-viem build succeeds.
- find packages/liquidation-sdk-viem/lib -name "*.test.*" -> empty.
Out of scope for this PR: LiquidationEncoder.ts (1,001 LOC), the
swap/paraswap.ts and flashbots.ts paths, and the full token-specific
encoders (midas, pendle, spectra). These can land in follow-ups now
that the canonical nock pattern is established.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(morpho-test): sort imports in tokens.test.ts to satisfy biome 2.4.14
Biome 2.4.14 (bumped on main in #583) enforces stricter import sorting.
The CI lint job failed with `assist/source/organizeImports` on
packages/morpho-test/src/fixtures/tokens.test.ts.
Auto-fixed via `biome check --write` — single-character reorder of
the named imports from "@morpho-org/blue-sdk" so that addressesRegistry
precedes ChainId alphabetically.
Verification:
- pnpm lint -> no errors (2 unrelated warnings on codegen.ts and
1 info on anvil.ts pre-date this branch).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(morpho-sdk): phase 9 — extend TIB scope to morpho-sdk + evm-simulation
Two packages added on main after the TIB was authored: morpho-sdk
(1.1.0, the new flagship transaction-builder package featured in
README via #581) and evm-simulation (1.0.0). Neither was in the
original in-scope list because neither existed yet.
Audit results:
- evm-simulation: already at 94.77% line coverage with 18 colocated
.spec.ts files; tsconfig.build.{cjs,esm}.json already excludes
*.spec.ts/*.test.ts/test-helpers/. No test work needed.
- morpho-sdk: already practices colocation (24 src + 24 test/) with
tsconfig.build.{cjs,esm}.json excluding *.test.ts. Most colocated
tests are fork-bound (import test/setup.ts which validates
MAINNET_RPC_URL). Three pure-helper files lacked tests entirely.
New tests in morpho-sdk (18 pass, no fork required):
- src/helpers/constant.test.ts: MAX_SLIPPAGE_TOLERANCE,
DEFAULT_LLTV_BUFFER, MAX_ABSOLUTE_SHARE_PRICE invariants.
- src/helpers/encodeDeallocation.test.ts: encodeForceDeallocateCall
round-trip via decodeFunctionData/decodeAbiParameters for both
adapter shapes (with/without marketParams); error path on
non-positive amounts.
- src/helpers/metadata.test.ts: addTransactionMetadata empty-data
short-circuit, timestamp append, raw-hex origin append, 0x-prefixed
origin rejection (current implementation behavior),
warn-on-invalid-origin, to/value preservation, combined
timestamp + origin layout.
TIB updates:
- Scope row extended to include morpho-sdk and evm-simulation.
- New "Addenda" section dated 2026-05-04 documenting the audit,
the decision to extend scope, and the new tests under this PR.
Also updates fixtures.test.ts (Phase 2) to compare account.address
directly against EIP-55 checksums after the lint:address script
rewrote string literals to checksum form.
Verification:
- pnpm test --project morpho-sdk --run packages/morpho-sdk/src/helpers
-> 18 tests pass.
- pnpm --filter @morpho-org/morpho-sdk build succeeds.
- find packages/morpho-sdk/lib -name "*.test.*" -> empty.
- pnpm lint -> no errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(tibs): add post-implementation coverage report addendum
Runs pnpm test:coverage across all 10 in-scope projects (with
--coverage.reportOnFailure so fork tests that fail locally on
rate-limited RPC still contribute), merges lcov, and records the
per-package numbers as a second 2026-05-04 addendum to TIB-2026-04-27.
Highlights:
- Combined: 914 tests pass, 43.76% statements / 36.39% branches /
47.43% functions / 44.07% lines (repo-wide denominator).
- morpho-ts 96.32% (+17.72 pp), blue-sdk 80.76% (+11.86 pp),
blue-sdk-viem 61.77% (+5.01 pp), bundler-sdk-viem 35.89% (+0.62 pp),
evm-simulation 94.77% (already on target).
- Notes the apparent regression in liquidity-sdk-viem and
liquidation-sdk-viem: their denominators shrank because the new
coverage excludes (index.ts barrels, abis.ts, api/{sdk,types}.ts)
removed generated/re-export code from the report — exactly what
the TIB's "exclude generated files" recommendation called for.
- Lists the files that moved from 0% in the baseline to >=90% after
Phases 1-9 (utils, urls, format/array, format/string, AssetBalances,
ExchangeRateWrappedToken, VaultUser, MathLib, SharesMath,
AdaptiveCurveIrmLib, errors, preLiquidation).
- Acknowledges files still at 0% locally (LiquidationEncoder,
MetaMorphoAction, morpho-sdk actions/entities) which CI fork tests
are expected to cover.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test: phase 10 — MetaMorphoAction encoders, MarketUtils gaps, flashbots
Implements Phase 10 of TIB-2026-04-27. Targets the most tractable
remaining surface from each phase's "Out of scope" list — pure
encoders and pure-math helpers — without trying to reach the very
largest deferred files (LiquidationEncoder 1,001 LOC, BundlerAction
2,346 LOC, marketV1 1,071 LOC), which warrant their own TIB.
New tests (52 pass):
- packages/blue-sdk-viem/src/MetaMorphoAction.test.ts (27 tests):
every public encoder round-tripped via decodeFunctionData -
configuration (curator, allocator, fee recipient, skim recipient,
fee), timelock (submit/accept/revoke), supply cap, forced market
removal, guardian, management (skim, supply queue, withdraw queue,
reallocate), ERC4626 (mint, deposit, withdraw, redeem). Plus
selector-uniqueness and shape invariants.
- packages/blue-sdk/src/market/MarketUtils.test.ts (22 tests):
getUtilization (every branch), getCollateralPower, getCollateral-
Value (incl. missing-price), getMaxBorrowAssets, toSupplyAssets/
toSupplyShares rounding, getAccruedInterest (zero-elapsed,
zero-fee, realistic-rate non-zero), rateToApy.
- packages/liquidation-sdk-viem/src/flashbots.test.ts (3 tests):
sendRawBundle posts eth_sendBundle JSON-RPC body to the relay
with target block hex-encoded and X-Flashbots-Signature header
set. signBundle is intentionally not unit-tested - documented
inline why (viem/actions ESM spy limitation).
Coverage delta (per-package line):
- blue-sdk-viem: 61.77% -> 67.85% (+6.08 pp from MetaMorphoAction)
- blue-sdk: 80.76% -> 80.98% (+0.22 pp)
- liquidation-sdk-viem: 18.86% -> 19.71% (+0.85 pp)
- Combined: 44.07% -> 44.56% lines, +52 tests (914 -> 966)
MetaMorphoAction.ts notable: 332 LOC at 0% in the original TIB
baseline, now effectively fully covered on the encoder surface.
TIB updated with a Phase 10 addendum dated 2026-05-04 documenting
the coverage delta and out-of-scope follow-ups.
Verification:
- All 52 new tests pass.
- pnpm --filter @morpho-org/blue-sdk-viem
--filter @morpho-org/blue-sdk
--filter @morpho-org/liquidation-sdk-viem build succeeds.
- find lib -name "*.test.*" -> empty in all three packages.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address PR review findings
Applied fixes for 4 unresolved review threads on #596:
1. mock.ts: disambiguate overloaded ABI functions in mockRead (Codex P2).
Build the set of selectors for every same-named view/pure ABI entry
instead of selecting only the first match by name. Read interception
now compares the call's 4-byte selector against the full set, so reads
against contracts with overloaded view methods no longer silently miss.
Adds a colocated test for the overload case.
2. AGENTS.md: carve out transport-level mocks for unit tests (Devin).
The original §2.6 / §5 ban on "mocked viem clients on RPC paths" was
intended to forbid integration tests that fake contract behaviour.
Per TIB-2026-04-27 (this PR), unit tests for non-fork-bound logic may
inject createMockClient from @morpho-org/test/mock — it installs a
vi.fn-backed custom() transport, the same surface viem/actions reads
from, so the mock is behaviour-faithful. Anvil forks remain mandatory
for end-to-end contract verification. AGENTS.md now reflects this.
3. .changeset/test-mock-subexport.md: minor bump for @morpho-org/test
(Devin). Adding ./mock sub-export is additive surface; documented per
AGENTS.md §2.10.
4. mock.ts: add @param/@returns/@throws JSDoc tags to createMockClient,
mockRead, expectReadCall (Devin). Aligns with AGENTS.md §6 required-
tags rule.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: remove changeset for ./mock sub-export
The new @morpho-org/test/mock sub-export is consumed only by internal
test code in this monorepo (not by external published consumers), and
the publish flow gates on changesets separately at release time. The
changeset added in 47f2e26 was unnecessary noise.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address local review findings (round 2)
Applied fixes for the local-review findings on top of the previous
round of PR-review fixes:
mock.ts public surface:
- Drop the `as unknown as chain` default; require an explicit chain
arg so chainId-validation tests can never drift.
- Replace `as Parameters<typeof encodeFunctionResult>[0]` with viem's
EncodeFunctionResultParameters generic.
- Rewrite the dispatch as a flat Map<address|selector, encoded result>
on the handle (no more unbounded closure chain).
- Move eth_call dispatch into createMockClient itself; mockRead now
just registers entries in the shared map.
- Let decodeFunctionData errors bubble in expectReadCall (single-pass
flatMap, no swallowed exceptions).
- Add @example blocks on createMockClient, mockRead, expectReadCall
(per AGENTS.md §6).
- Document the eth_call-only scope and the "missing other RPC methods
fall through to default handler" behaviour.
Test files using createMockClient:
- packages/test/src/mock.test.ts: pass mainnet explicitly; add a
mixed-mutability overload test pinning the runtime filter behaviour;
fix stale "safeTransferFrom" comment.
- packages/blue-sdk-viem/src/fetch/MarketParams.test.ts: drop dead
mockRead at arbitrary address; pass mainnet; tighten test name.
- packages/liquidity-sdk-viem/src/loader.test.ts: pass mainnet;
replace silent-rejection swallow with `.rejects.toThrow()`.
- packages/bundler-sdk-viem/src/ActionBundle.test.ts: drop `null!`
placeholders + `as never` client; use a typed nativeTransfer action
and a real createMockClient handle.
Source bug fix:
- packages/morpho-sdk/src/helpers/metadata.ts: the regex
`/^(?!0x)/` was a no-op (zero-width negative-lookahead replaced an
empty match with empty). Fix to `/^0x/` so a `0x`-prefixed origin
is normalized correctly. Update colocated test to match: 0xcafe
now appends 'cafe' to the calldata; new tests cover
timestamp = false explicit, raw-hex length-check (separate from
isHex), and 0x-prefixed length-check.
Other test improvements:
- preLiquidation.test.ts: add expect.fail() guard so the bare try/
catch can no longer silently green if getDefaultPreLiquidationParams
stops throwing.
- bundler-sdk-viem/errors.test.ts: assert by class identity, not
message string (per AGENTS.md §5).
- blue-sdk-viem/augment/augment.test.ts: replace `typeof X.fetch ===
"function"` with `expect(X.fetch).toBe(fetchX)` identity assertions
for all 12 augmented classes — catches regressions that wire fetch
to the wrong function.
- liquidation-sdk-viem/flashbots.test.ts: switch to testAccount() per
packages/test/CLAUDE.md; recover the signature header to verify
it's a real signMessage of the body keccak; pin blockNumber as a
hex literal; assert nock.isDone().
- liquidation-sdk-viem/swap/1inch.test.ts: pin error class on 5xx;
add coverage for non-numeric slippage (NaN encoding) and missing
API key ('Bearer undefined' header) — both pin current behaviour.
- blue-sdk/math/MathLib.test.ts: add maxUint(0) boundary and
zeroFloorSub with negative y.
- morpho-ts/utils.test.ts: bigIntComparator now covers null/null,
undefined/undefined, and mixed nullish.
- Drop mutability-only tests from User.test.ts, VaultUser.test.ts,
VaultMarketPublicAllocatorConfig.test.ts (they only verified the
TypeScript type is mutable, not behaviour).
TIB and AGENTS.md:
- TIB Status: Proposed -> Accepted.
- TIB References: drop "(to be migrated)" parenthetical that
contradicted Convention 4.
- TIB addendum heading: "Coverage after implementation" -> "Coverage
after Phases 1-9" (Phase 10 has its own addendum).
- TIB addendum: drop stale colocated-test-count (changes per phase).
Verification:
- 548 colocated tests pass across 42 files.
- pnpm lint passes (no errors; pre-existing warnings on codegen.ts /
anvil.ts from biome 2.4.14 are unchanged).
- pnpm --filter <every touched package> build succeeds.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address local review findings (round 3)
- Restore changeset for the @morpho-org/test ./mock sub-export
- Add changeset for addTransactionMetadata 0x-prefix-origin behavioural change
- mock.ts: tighten JSDoc on dispatch key format and mockRead checksum
semantics; pre-filter expectReadCall by selector set so unrelated calls
to the same address don't abort decode iteration
- mock.test.ts: strengthen "non-view/pure overload" test to actually assert
the permissive runtime registers nonpayable selectors too
- MetaMorphoAction.test.ts: add inline-snapshot pinning for security-critical
setters (setCurator/setFee/setFeeRecipient/setIsAllocator/submitGuardian/
acceptGuardian/submitCap/acceptCap/submitMarketRemoval); use vitest 4
test-context expect to avoid shadowing
- augment.test.ts: split single 12-expect block into test.each with one row
per wiring; cover AccrualPosition.fetch, fetchPreLiquidation, AccrualVault.fetch
- ActionBundle.test.ts: hoist dynamic imports of @morpho-org/test/mock and
viem/chains to top of file
- 1inch.test.ts: replace process.env mutation with vi.stubEnv +
vi.unstubAllEnvs in afterEach (concurrent-safe)
- flashbots.test.ts: add explicit length check on split(":") before destructure
- Pin error classes across .toThrow() sites (InvalidAddressError, ClientError,
SyntaxError, TypeError) instead of bare .toThrow()
- loader.test.ts: tighten reject message regex
- metadata.ts: extend JSDoc with 0x-prefix normalization rules
- AGENTS.md §2.6: broaden mock-allowed scope wording with explicit list of
fork-only paths (oracles, accruals, deployless, contract-revert)
- TIB §Convention 2: replace stale pre-shipped API code block
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address local review (round 4) — concurrent-test safety + JSDoc
HIGH — concurrent-mode races on process-global state:
- flashbots.test.ts, 1inch.test.ts, liquidity-sdk-viem/api/index.test.ts:
convert nock-using describes to `describe.sequential`. Under the repo
default `sequence: { concurrent: true }`, `afterEach(nock.cleanAll)`
would wipe other in-flight tests' interceptors. 1inch.test.ts also
had `vi.stubEnv` / `vi.unstubAllEnvs` racing on process.env.
MEDIUM — same class of race on other globals:
- metadata.test.ts: `vi.spyOn(console, "warn")` across 3 tests — last
spy wins, restoreAllMocks revokes mid-flight. Sequentialize.
- locale.test.ts: `vi.stubGlobal("window"|"navigator"|"document")`
across 4 tests — same hazard. Sequentialize.
LOW — JSDoc clarity in `@morpho-org/test/mock`:
- mock.ts: tighten `MockClientHandle.dispatch` concurrency note to
describe the actual race (`(addr, selector)` overwrite, mid-flight
`dispatch.clear`) instead of a non-existent "different key format".
- mock.ts: move `createMockClient`'s @throws into @remarks — the
factory itself never throws; the throw happens at later transport
call time, which @throws conventionally doesn't document on factories.
- mock.test.ts: convert tautological "round-trip" test to actually
decode the returned ABI-encoded result via `decodeFunctionResult`
and assert the registered value (42n) comes back. Previous version
decoded a separately re-encoded call and asserted `result.startsWith("0x")`,
which would pass on any hex string.
Verified: all touched tests still pass under `CI=true pnpm vitest run`.
Pre-existing fork-test failures (MAINNET_RPC_URL required) are unrelated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: drop ambiguous test count from locale.test.ts comment
The describe.sequential comment said "the four tests below call
vi.stubGlobal" but the describe contains 5 tests. Only 4 actually
call stubGlobal; the first test asserts on the un-stubbed window
global and also benefits from sequencing. Drop the count to avoid
the off-by-one and clarify both reasons for serializing the describe.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address Codex P2 review on @morpho-org/test/mock
Two Codex P2 findings on PR #596:
1. mockRead encodes per-overload (was: once, then reused for every
overload selector). For ABIs whose same-named overloads have
different return types, the previous behaviour stored bytes
encoded against the wrong output ABI under the other selectors,
producing wrong values at decode time. Now: try-encode each
overload's single-item ABI; register only selectors where
encoding succeeds. Throw if the supplied result matches no
overload's return shape (clear signal for the caller). Behaviour
is unchanged when overloads share a return type. Added test
coverage for the different-return-type case.
2. Drop the CJS `require` condition for ./mock from
publishConfig.exports + exclude mock.ts from the CJS build.
mock.ts imports vitest at the top level and vitest rejects
require() ("Vitest cannot be imported in a CommonJS module
using require()"). The ESM entry is the only legitimate
consumer surface for this subpath (vitest is ESM-only).
Changeset documents both as a patch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(changeset): reframe ./mock changeset around mockRead behaviour change
The changeset existed because of two changes shipped in b0d12e1:
1. mockRead now encodes per-overload (behavioural change to a public
exported function — does warrant a patch changeset).
2. ./mock CJS condition removed from publishConfig.exports — packaging
metadata catching up to reality (the entry was crash-on-load via
vitest's require() rejection; no working consumer is affected).
Per AGENTS.md §7 the packaging cleanup alone wouldn't merit a
changeset. Rewrite to lead with the mockRead behaviour change and
relegate the CJS removal to a drive-by note.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address Rubilmax PR review (round 5)
10 unresolved threads from human review:
Source changes:
- metadata.ts: strip leading 0x/0X case-insensitively (was: lowercase only,
silently dropped "0Xcafe"). Add even-length guard on the raw fragment —
odd-nibble origin would otherwise pad at concatHex broadcast time and
corrupt the trailing analytics byte. Both regressions widened by the
round-2 0x-strip fix.
- mock.ts JSDoc: align @throws to canonical {ErrorClass} syntax per
docs/jsdoc-style.md §5. Rewrite expectReadCall's @example as a
self-contained runnable snippet with real fixture addresses (USDC +
dead-address) instead of "0x..." placeholders. Add a return-type note
documenting that decoded args are a union over the whole abi rather
than narrowed to functionName. Update the stale "decode errors bubble"
paragraph — the round-3 selector pre-filter makes mismatched-ABI calls
return [] instead of throwing.
Test additions:
- error.test.ts: cover getUnsupportedVaultV2Adapter (5 cases incl. nested
cause walk + missing args) and the 3 untested permit-domain error
classes (field preservation + message format + edge cases).
- metadata.test.ts: 0X-prefix accepted; odd-length raw + 0x-prefixed
fragments rejected with warn.
- encodeDeallocation.test.ts: actually assert the error message contains
the adapter address (test title previously misleading).
- mock.test.ts: malformed eth_call (missing to/data) falls through to
unhandled-RPC; unrelated-call filtering pinned; wrong-arity ABI now
returns [] (no decode-throw) as documented above.
- flashbots.test.ts: cover the !response.ok 5xx branch using explicit
application/json content-type (Rubilmax's suggested approach).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
@biomejs/biome1.9.4 → 2.4.14, migratebiome.jsonto v2 schema (files.includes,assist.actions).complexity/useMaxParams(max=2),style/noParameterAssign,style/noUselessElse, and nursery rulesnoFloatingPromises,noMisusedPromises,noShadow,useExhaustiveSwitchCases. All 366 existing violations are suppressed with rule-specific// biome-ignore … TODO …comments so the lint pass stays green while leaving a clean refactor backlog.suspicious/noNonNullAssertedOptionalChainandsuspicious/useIterableCallbackReturn(newly recommended in 2.x; out of scope for this change).scripts/lint/checksum-address.jsto read the newfiles.includesshape and absorb v2's JSON formatter / organizeImports output across the monorepo.Test plan
pnpm installsucceeds;pnpm biome --versionreports 2.4.14pnpm lintexits 0pnpm testformorpho-tsandsimulation-sdk(non-RPC) passes locally🤖 Generated with Claude Code