Skip to content

feat(vault): god-mode improvement for the v3 Loans and Activity#2128

Open
jeremy-babylonlabs wants to merge 2 commits into
mainfrom
fix/god-mode-support-v3
Open

feat(vault): god-mode improvement for the v3 Loans and Activity#2128
jeremy-babylonlabs wants to merge 2 commits into
mainfrom
fix/god-mode-support-v3

Conversation

@jeremy-babylonlabs

Copy link
Copy Markdown
Contributor

Add loan and activity mock types so the panel drives the two v3 pages that had no injectable state. Loan mocks render as Active Loans rows (four scenarios: borrowable, repay-only, missing liquidity read, pending APR) with the summary totalling the rendered rows; activity mocks render in the feed (nine scenarios covering both flat log rows and the expandable liquidation group card), dated relative to now so the Today / Yesterday group headers apply.

Add Loans summary overrides for the states a real position cannot be talked into on demand: a health factor per production band, and the borrow-capacity cards in their loading and error states. The forced health-factor status is derived with the real banding function so it cannot drift from production.

Mount the panel once per route subtree (dev/GodModeMount) rather than a copy per page. Overview, Vaults, Loans and Activity now all get the debug sections as well, and the panel keeps its open/dragged position across navigation within a subtree. This replaces the per-page mounts added in #2124.

Restyle the liquidation-analysis and position-notification debug sections to the panel's zinc chrome; they were light-theme purple cards sitting inside a fixed dark box.

Mock rows are display-only: their ids and symbols resolve to no real reserve or event, both row actions stay disabled, nothing is polled or persisted, and the whole of src/dev is dropped from production builds.

…y pages

Add `loan` and `activity` mock types so the panel drives the two v3 pages that
had no injectable state. Loan mocks render as Active Loans rows (four
scenarios: borrowable, repay-only, missing liquidity read, pending APR) with
the summary totalling the rendered rows; activity mocks render in the feed
(nine scenarios covering both flat log rows and the expandable liquidation
group card), dated relative to now so the Today / Yesterday group headers
apply.

Add Loans summary overrides for the states a real position cannot be talked
into on demand: a health factor per production band, and the borrow-capacity
cards in their loading and error states. The forced health-factor status is
derived with the real banding function so it cannot drift from production.

Mount the panel once per route subtree (dev/GodModeMount) rather than a copy
per page. Overview, Vaults, Loans and Activity now all get the debug sections
as well, and the panel keeps its open/dragged position across navigation
within a subtree. This replaces the per-page mounts added in #2124.

Restyle the liquidation-analysis and position-notification debug sections to
the panel's zinc chrome; they were light-theme purple cards sitting inside a
fixed dark box.

Mock rows are display-only: their ids and symbols resolve to no real reserve
or event, both row actions stay disabled, nothing is polled or persisted, and
the whole of src/dev is dropped from production builds.
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

🔐 Commit Signature Verification

All 2 commit(s) passed verification

Commit Author Signature Key Type Key Check
ac31992b7971 jeremy-babylonlabs sk-ssh-ed25519
6c0d00146345 jeremy-babylonlabs sk-ssh-ed25519

Summary

  • Commits verified: 2
  • Signature check: ✅ All passed
  • Key type enforcement: ✅ All sk-ssh-ed25519

Required key type: sk-ssh-ed25519 (FIDO2 hardware key)

Last verified: 2026-07-23 14:40 UTC

@greptile-apps

greptile-apps Bot commented Jul 23, 2026

Copy link
Copy Markdown

Greptile Summary

This PR expands god mode across the v3 Loans and Activity pages. The main changes are:

  • Adds display-only loan and activity mock scenarios.
  • Adds Loans health-factor and borrow-capacity overrides.
  • Moves the debug panel from individual pages to route-level mounts.
  • Applies shared zinc styling to the debug sections.

Confidence Score: 4/5

The Activity provider boundary and Loans override composition need fixes before merging.

  • The Activity debug mount can access pending-vault state without its provider.
  • Forced borrow-capacity states can be overridden by live loading or error values.
  • An empty hidden-real Activity demo can remain on the loading spinner.

services/vault/src/router.tsx, services/vault/src/components/pages/Loans.tsx, services/vault/src/hooks/useActivitiesWithPending.ts

Important Files Changed

Filename Overview
services/vault/src/router.tsx Moves the panel to route-level mounts, but the Activity subtree omits a provider required by a mounted debug section.
services/vault/src/components/pages/Loans.tsx Adds mock loan rows and summary overrides, but forced capacity states remain mixed with live loading and error state.
services/vault/src/dev/demoDeposit.ts Adds display-only loan rows and relative-date activity scenarios with isolated mock identifiers.
services/vault/src/hooks/useActivitiesWithPending.ts Merges mock activity rows without persistence, but an empty hide-real feed can retain the live loading state.
services/vault/src/components/simple/ActiveLoansList.tsx Disables both loan actions for display-only rows.
services/vault/src/dev/debugPositionStore.ts Adds stable external-store snapshots for Loans summary overrides.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  R[Router] --> A[Aave route subtree]
  R --> T[Activity subtree]
  A --> AC[AaveConfigProvider]
  AC --> PV[PendingVaultsProvider]
  PV --> RO[ReorderOverrideProvider]
  RO --> GM1[GodModeMount]
  T --> AC2[AaveConfigProvider]
  AC2 --> RO2[ReorderOverrideProvider]
  RO2 --> GM2[GodModeMount]
  GM2 -. missing pending-vault context .-> PV
Loading

Reviews (1): Last reviewed commit: "feat(vault): god-mode mocks and controls..." | Re-trigger Greptile

render on this page. */}
<ReorderOverrideProvider>
<Activity />
<GodModePanelSlot />

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Activity Mount Misses Required Provider

When the position-notification debug flags are enabled on /activity, this mount renders PositionNotificationsDebugPanel outside the PendingVaultsProvider used by the main Aave subtree. Its pending or activating-vault context access can then throw instead of rendering the panel.

Comment on lines +83 to +86
const shownCapacityLoading =
borrowCapacityOverride?.loading || isBorrowCapacityLoading;
const shownCapacityError =
borrowCapacityOverride?.error ?? borrowCapacityError;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Forced State Retains Live Failure

The override fields are combined independently with live state. Selecting Error while the live request is loading keeps the loader active, while selecting Loading during a live error retains that error, so the panel does not show the forced state.

Suggested change
const shownCapacityLoading =
borrowCapacityOverride?.loading || isBorrowCapacityLoading;
const shownCapacityError =
borrowCapacityOverride?.error ?? borrowCapacityError;
const shownCapacityLoading = borrowCapacityOverride
? borrowCapacityOverride.loading
: isBorrowCapacityLoading;
const shownCapacityError = borrowCapacityOverride
? borrowCapacityOverride.error
: borrowCapacityError;

// With mocks injected there is something to render immediately, so the
// page must not sit on its spinner waiting for a query that, disconnected,
// will never resolve.
isLoading: demo && demo.rows.length > 0 ? false : isLoading,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Empty Mock Feed Stays Loading

When demo injection has hideReal enabled but contains no Activity mocks, the merged result is intentionally an empty demo-only feed. This condition still inherits the live query's loading state, so a disconnected Activity page can remain on its spinner instead of showing the empty feed.

Suggested change
isLoading: demo && demo.rows.length > 0 ? false : isLoading,
isLoading:
demo && (demo.hideReal || demo.rows.length > 0) ? false : isLoading,

… with it

A forced borrow-capacity state was combined with the live one field by field,
so selecting Error while the live read was loading kept the loader on screen
and selecting Loading during a live error kept the error — the forced state
never rendered. It now replaces the live pair wholesale.

Hide-real with zero activity mocks is a deliberate empty demo-only feed, but
it still inherited the live query's loading state, leaving a disconnected
Activity page on its spinner. The demo now short-circuits the loading state
whenever it governs the feed.

Also record, at the Activity mount, the panel's audited context dependency
set (AaveConfig, ReorderOverride, ActivatingVaults) and why PendingVaults is
deliberately not duplicated there.

@gbarkhatov gbarkhatov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. This is a well-structured, thoroughly tested extension of the dev-only god-mode tooling, and it stays clear of every critical value-movement path in CLAUDE.md. Nice touches: the health-factor status is re-derived with the real banding function (can't drift from prod), the borrow-capacity snapshots keep a stable identity for useSyncExternalStore, forced summary states replace the live state wholesale, and mock rows are provably action-inert with non-colliding ids.

Two inline notes below — one worth fixing (a stale comment), one optional dev-only nit.

Two non-blocking observations, no change required:

  1. PR-description precision. useActivitiesWithPending.ts and Loans.tsx statically import from dev/demoDeposit, so that module (and its LOAN_SCENARIOS / ACTIVITY_SCENARIOS data) sits in the production import graph and relies on Rollup DCE of the import.meta.env.DEV dead branches to be stripped. "The whole of src/dev is dropped from production builds" is strictly true only for the dynamically-imported GodModeMount; the statically-imported demo hooks are inert-but-present (same pre-existing pattern as useDemoLoan / useDemoCollateral). Functionally fine.

  2. useActivitiesWithPending isLoading flip (intended). When connected with the live query still loading and activity mocks injected, isLoading flips to false immediately, suppressing the real feed's spinner so real rows appear afterward. This is deliberate and already documented in the code comment — noting only for visibility.


The page reads the indexer's activity list directly and does not
consume the demo store, so the panel drives theme, the protocol-status
/ max-vaults overrides and the shared mock list here — no mock rows

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is now stale and contradicts the code. ActivityuseActivitiesWithPendinguseDemoActivity() merges demo rows into the returned feed, so mock activity rows do render on this page — including while disconnected. Activity.tsx's own comment says exactly that ("demo rows are merged in by this hook … so the feed can be exercised without a wallet"), and the PR description lists nine activity scenarios rendering here.

The rationale above about which providers are / aren't mounted is correct and worth keeping — please just fix this last sentence so it states that Activity renders mock rows via the demo store, rather than the opposite.

/** Unit a mock item's amount is denominated in: BTC everywhere except loans,
* whose amount is the borrowed stablecoin. */
function amountUnit(type: DemoType): string {
return type === "loan" ? "USDC" : "BTC";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dev-only nit: the amount field is labelled Amount (BTC) for activity mocks, but the Borrow and Repay activity scenarios ignore the amount arg and hard-code DEMO_ACTIVITY_DEBT_AMOUNT (USDC) — so for those two the control has no effect and the unit doesn't match the value the row shows. Deposit / withdraw / redeem / liquidation activity rows do use the amount as BTC, so the label is right for them. Low priority; if you want it tidy, derive the unit per activity scenario (and/or disable the field where it's inert). Not blocking.

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.

2 participants