Skip to content

feat: analysis page#500

Merged
antoncoding merged 10 commits intomasterfrom
feat/analysis
Apr 20, 2026
Merged

feat: analysis page#500
antoncoding merged 10 commits intomasterfrom
feat/analysis

Conversation

@antoncoding
Copy link
Copy Markdown
Owner

@antoncoding antoncoding commented Apr 20, 2026

Summary by CodeRabbit

  • New Features

    • Added Analysis page featuring comprehensive market risk breakdown with three tabbed views: oracle vendor exposure tracking, peg assumption monitoring, and asset dominance reporting.
    • Integrated interactive charts and detailed market tables for deeper risk insights.
    • Added Analysis menu item to navigation for easy access.
    • Enhanced data fetching with configurable refresh intervals for better performance control.
  • Improvements

    • Extended design system with compact button group variant for space-constrained layouts.

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
monarch Ready Ready Preview, Comment Apr 20, 2026 5:15pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

PR introduces 17 new agent skills for design tasks (adapt, animate, audit, bolder, clarify, colorize, critique, delight, distill, impeccable, layout, optimize, overdrive, polish, quieter, shape, typeset), adds supporting reference documentation and cleanup tooling, and launches a new /analysis dashboard page for risk visualization. Also extends navigation and query hooks to support the analysis feature.

Changes

Cohort / File(s) Summary
Agent Skills Core
.agents/skills/{adapt,animate,audit,bolder,clarify,colorize,critique,delight,distill,layout,optimize,overdrive,polish,quieter,shape,typeset}/SKILL.md
Added 17 user-invocable skill definitions (v2.1.1) defining structured workflows for design tasks: responsive adaptation, animations, auditing, visual boldness/quietness, copy clarity, color strategy, critiques, delightful UX, simplification, layout, performance, advanced effects, polishing, planning, and typography. Each follows a common pattern: run /impeccable for context, assess current state, plan approach, implement, and verify.
Agent References
.agents/skills/impeccable/reference/*, .agents/skills/critique/reference/*
Added 10 reference documents covering typography, color/contrast, spatial design, interaction design, motion design, responsive design, UX writing, craft/extract workflows, cognitive load, personas, and Nielsen heuristics scoring. Serve as guidance material for skills.
Agent Infrastructure
.agents/skills/impeccable/scripts/cleanup-deprecated.mjs, skills-lock.json
Added cleanup script with helper exports for removing deprecated skill artifacts and symlinks, plus initial skills-lock.json recording skill provenance and hashes.
Analysis Dashboard
app/analysis/page.tsx, src/features/analysis/analysis-view.tsx, src/features/analysis/utils/oracle-risk-analysis.ts
Added /analysis page with tabbed dashboard: Oracles (vendor exposure chart + detail panel), Pegs (peg assumption toggles), and Assets (dominance summaries). Includes risk analysis utility computing per-market exposure, oracle vendor aggregation, peg/vault assumption tracking, and asset bucketing.
Navigation Updates
src/components/layout/header/Navbar.tsx, src/components/layout/header/NavbarMobile.tsx
Added "Analysis" menu item with pie-chart icon to both desktop and mobile navigation dropdowns, navigating to /analysis.
Hook & Utility Refactors
src/hooks/queries/useMarketsQuery.ts, src/hooks/useProcessedMarkets.ts, src/components/DataPrefetcher.tsx, src/utils/oracle.ts, src/components/ui/button-group.tsx
Updated useMarketsQuery and useProcessedMarkets to accept optional refetch configuration, extended DataPrefetcher to skip prefetching on /analysis, added pyth vendor recognition to mapProviderToVendor, and added 'compact' variant to button-group styling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Possibly related PRs

Suggested labels

feature request, ui

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: analysis page' directly matches the main changeset, which adds a new analysis page with dashboard components and supporting infrastructure.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/analysis

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added feature request Specific feature ready to be implemented ui User interface labels Apr 20, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 13

🧹 Nitpick comments (3)
.agents/skills/critique/reference/personas.md (1)

168-176: Add language specifier to fenced code block.

The template code block should have a language identifier for proper syntax highlighting and rendering.

📝 Proposed fix
-```
+```markdown
 ### [Role] — "[Name]"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/critique/reference/personas.md around lines 168 - 176, The
fenced code block example for the persona template lacks a language specifier;
update the opening fence from ``` to include a markdown language tag (i.e.,
change the triple-backtick block that wraps the "### [Role] — \"[Name]\""
template to use ```markdown) so the template renders with proper syntax
highlighting and tooling support.
.agents/skills/impeccable/scripts/cleanup-deprecated.mjs (1)

44-60: findProjectRoot hardcodes POSIX root.

{ root: '/' } means on Windows the dir !== root guard never fires; the walk only terminates via the parent === dir fallback. Works, but why not use path.parse(dir).root?

Proposed fix
-export function findProjectRoot(startDir = process.cwd()) {
-  let dir = resolve(startDir);
-  const { root } = { root: '/' };
-  while (dir !== root) {
+import { parse } from 'node:path';
+// ...
+export function findProjectRoot(startDir = process.cwd()) {
+  let dir = resolve(startDir);
+  const { root } = parse(dir);
+  while (dir !== root) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/impeccable/scripts/cleanup-deprecated.mjs around lines 44 -
60, The function findProjectRoot currently hardcodes POSIX root via "{ root: '/'
}", which breaks the dir !== root guard on Windows; change it to derive the
filesystem root using path.parse(resolve(startDir)).root (or import parse from
'path' and use parse(dir).root) so the loop correctly detects platform-specific
roots; update the top-of-file imports to include parse (or use path.parse) and
replace the literal root with the parsed root before the while loop, leaving the
existing existsSync/join checks and parent fallback intact.
src/components/layout/header/Navbar.tsx (1)

170-174: Use client navigation for the internal Analysis route.

window.location.href does a full page reload. Use useRouter().push('/analysis') so this matches the mobile path and preserves app state.

♻️ Proposed fix
-import { usePathname } from 'next/navigation';
+import { usePathname, useRouter } from 'next/navigation';
@@
 export function Navbar() {
   const { theme, setTheme } = useTheme();
   const { address } = useConnection();
   const { open: openModal } = useModal();
+  const router = useRouter();
@@
               <DropdownMenuItem
                 endContent={<RiPieChart2Line className="h-4 w-4" />}
                 onClick={() => {
-                  window.location.href = '/analysis';
+                  router.push('/analysis');
                 }}
               >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/layout/header/Navbar.tsx` around lines 170 - 174, The
DropdownMenuItem's onClick currently uses window.location.href which triggers a
full reload; change it to use the Next router push for client navigation: import
and call useRouter (from next/navigation or next/router depending on your app)
inside the Navbar component, get router (e.g., const router = useRouter()) and
replace the onClick handler on the DropdownMenuItem to call
router.push('/analysis'); ensure Navbar is a client component ("use client") if
it isn’t already so useRouter can be used.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.agents/skills/animate/SKILL.md:
- Around line 123-128: Replace the invalid bullet-list inside the css fence in
SKILL.md with valid CSS rules or convert the block to a non-code markdown list;
specifically either change the fenced block to plain markdown text listing the
tips, or replace the css block with real CSS such as a class rule like
.interactive { transition: ... } and a named keyframes rule (e.g., `@keyframes`
fadeInUp { ... }) so the example is copy-pastable and syntactically correct;
update the fence language if you switch to plain text.

In @.agents/skills/audit/SKILL.md:
- Line 112: Remove the non-existent /harden command from the suggested-command
whitelist in the SKILL.md document: find the "**Suggested command**" list entry
that currently includes "/harden" (the bullet shown in the diff) and delete
"/harden" there, and also remove the second occurrence of "/harden" later in the
same document (the other suggested-command list around the referenced area).
Ensure the remaining suggested commands and punctuation remain unchanged.

In @.agents/skills/impeccable/reference/extract.md:
- Line 9: The sentence "If no design system exists, ask the user directly to
clarify what you cannot infer. before creating one. Understand the preferred
location and structure first." contains an extra period before "before"; edit
that sentence so it reads "ask the user directly to clarify what you cannot
infer before creating one." and keep the rest unchanged to preserve the
following sentence "Understand the preferred location and structure first."

In @.agents/skills/impeccable/scripts/cleanup-deprecated.mjs:
- Around line 128-138: The code currently unlinks a dangling symlink purely
based on DEPRECATED_NAMES without the same content check used for live targets;
update the symlink-removal branch inside the stat.isSymbolicLink() handling so
that when existsSync(skillPath) is false and you decide to unlinkSync(skillPath)
you also emit a clear log entry (including skillPath and the fact the symlink
target was missing) before pushing to deleted; keep the
isImpeccableSkill(skillPath) check for live targets unchanged and use the same
logger used elsewhere in this module so users can see what dangling symlinks
were auto-removed.
- Line 200: The CLI entry check fails on Windows because new
URL(import.meta.url).pathname yields a prefixed path (e.g., /C:/...) that
doesn't equal resolve(process.argv[1]); replace that comparison to use a proper
file-path conversion: import and use fileURLToPath(import.meta.url) (from the
'url' module) and compare resolve(process.argv[1]) ===
resolve(fileURLToPath(import.meta.url)) so the if block reliably detects direct
invocation across platforms; update the condition that references
process.argv[1], resolve(...), and new URL(import.meta.url).pathname
accordingly.

In @.agents/skills/layout/SKILL.md:
- Line 50: The link text "spatial design reference" in layout/SKILL.md points to
a broken relative path (reference/spatial-design.md); locate the actual
spatial-design.md under the impeccable skill (e.g., in that skill's reference
folder) and update the markdown link to the correct relative or absolute repo
path so it resolves from layout/SKILL.md (reference the file name
spatial-design.md and the link text "spatial design reference" when fixing).
Ensure the updated link uses the correct relative traversal (../.../) or an
absolute path from the repo root so the reference loads correctly.

In @.agents/skills/typeset/SKILL.md:
- Line 50: The markdown link labeled "[typography reference]" currently points
to a non-existent local path "reference/typography.md"; update that target to
the impeccable reference path by replacing the href "reference/typography.md"
with the correct impeccable path (e.g., "impeccable/reference/typography.md" or
the appropriate relative path to the impeccable docs) so the link resolves
correctly from .agents/skills/typeset/SKILL.md.

In `@src/features/analysis/analysis-view.tsx`:
- Around line 299-304: The legend currently only selects providers via the pie
slice onClick handler (using visibleData, OTHER_BUCKET_KEY, and onSelect); add a
keyboard-accessible selection path by handling Enter/Space on the legend button
elements (the same places as the onClick handlers referenced around the
visibleData usage and the second block at 334-342) so keyboard users can call
onSelect(key) when key exists and is not OTHER_BUCKET_KEY; ensure the existing
hide/toggle behavior is preserved (e.g., keep toggle on click/space if intended)
and prevent selection for OTHER_BUCKET_KEY just as the mouse path does.
- Around line 76-80: formatAssumptionLabel currently title-cases the entire
label which corrupts token symbols (e.g. sUSDe → SUSDe); modify
formatAssumptionLabel to only strip the suffixes (use the existing
.replace(/\s+peg$/i, '') and .replace(/\s+vault conversion$/i, '')) and remove
the final title-case pass (the .replace(/\b\w/g, ...) call) so the remaining
token text keeps its original casing; ensure you still trim any extra whitespace
and return the cleaned label from the function.
- Around line 489-496: The provider card, oracle table and peg bars currently
always show "Supply" and "% of total supply" and use bucket.valueUsd/totalUsd
even when exposureMetric === "borrow"; update the rendering logic (in the
component handling the provider card / oracle table and peg bar code paths that
reference bucket.valueUsd, formatUsdValue, formatPercent and the label strings)
to branch on exposureMetric: show "Borrow" and "% of total borrowed" and compute
percentages against the borrow total when exposureMetric === "borrow", otherwise
keep "Supply" and use the supply total; ensure the displayed numeric value comes
from the correct bucket field (borrow amount) or convert the value accordingly
and update the label strings to reflect "Borrow" vs "Supply".
- Around line 1017-1052: The table rows are rendering the full market USD
(row.supplyUsd / row.exposureUsd) instead of the bucket-specific amount carried
on each entry as row.attributedUsd; update the mapping in the entries slice
where TableRow is rendered so the UsdWithPercent valueUsd prop uses
row.attributedUsd (or the appropriate attributed bucket field) rather than
row.supplyUsd/row.exposureUsd, and ensure totalUsd passed to UsdWithPercent is
the matching bucket total (replace with the bucket-specific total variable if
one exists) so amounts and percentages reflect the selected bucket.

In `@src/features/analysis/utils/oracle-risk-analysis.ts`:
- Around line 330-335: The code buckets rows with empty pegAssumptions into
noPegAssumptionBucket even when the path is actually invalid; update the
hasUnknownPegRoute logic (currently defined using hasUnknownPegRoute,
row.oracleType, row.unknownLegCount, row.actualPath, and EMPTY_PATH) to also
detect invalid paths (e.g. row.oracleType === 'invalid' or row.actualPath ===
INVALID_PATH or a row.pathIsValid === false flag used in your model) and include
that in the hasUnknownPegRoute condition, and ensure the subsequent if/else uses
that updated hasUnknownPegRoute so rows with invalid paths are routed into
unknownPegRouteBucket via addToBucket(unknownPegRouteBucket, ...) rather than
falling through to addToBucket(noPegAssumptionBucket, ...).
- Around line 348-360: The special-case buckets noPegAssumptionBucket and
unknownPegRouteBucket are always returned as objects because finalizeBuckets(new
Map([[...]]))[0] produces a bucket even when it's empty; change the logic to
call finalizeBuckets for each Map into a variable, then check that the resulting
bucket exists and is non-empty (e.g., has count/size/total > 0 or the array
length > 0) and only return the bucket object when it contains data—otherwise
return null; reference finalizeBuckets, noPegAssumptionBucket.key, and
unknownPegRouteBucket.key to locate and update the return expressions.

---

Nitpick comments:
In @.agents/skills/critique/reference/personas.md:
- Around line 168-176: The fenced code block example for the persona template
lacks a language specifier; update the opening fence from ``` to include a
markdown language tag (i.e., change the triple-backtick block that wraps the
"### [Role] — \"[Name]\"" template to use ```markdown) so the template renders
with proper syntax highlighting and tooling support.

In @.agents/skills/impeccable/scripts/cleanup-deprecated.mjs:
- Around line 44-60: The function findProjectRoot currently hardcodes POSIX root
via "{ root: '/' }", which breaks the dir !== root guard on Windows; change it
to derive the filesystem root using path.parse(resolve(startDir)).root (or
import parse from 'path' and use parse(dir).root) so the loop correctly detects
platform-specific roots; update the top-of-file imports to include parse (or use
path.parse) and replace the literal root with the parsed root before the while
loop, leaving the existing existsSync/join checks and parent fallback intact.

In `@src/components/layout/header/Navbar.tsx`:
- Around line 170-174: The DropdownMenuItem's onClick currently uses
window.location.href which triggers a full reload; change it to use the Next
router push for client navigation: import and call useRouter (from
next/navigation or next/router depending on your app) inside the Navbar
component, get router (e.g., const router = useRouter()) and replace the onClick
handler on the DropdownMenuItem to call router.push('/analysis'); ensure Navbar
is a client component ("use client") if it isn’t already so useRouter can be
used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ab8fec46-1dec-4eb0-81a8-1ad715f7ce1b

📥 Commits

Reviewing files that changed from the base of the PR and between ecba111 and 5d52356.

📒 Files selected for processing (41)
  • .agents/skills/adapt/SKILL.md
  • .agents/skills/animate/SKILL.md
  • .agents/skills/audit/SKILL.md
  • .agents/skills/bolder/SKILL.md
  • .agents/skills/clarify/SKILL.md
  • .agents/skills/colorize/SKILL.md
  • .agents/skills/critique/SKILL.md
  • .agents/skills/critique/reference/cognitive-load.md
  • .agents/skills/critique/reference/heuristics-scoring.md
  • .agents/skills/critique/reference/personas.md
  • .agents/skills/delight/SKILL.md
  • .agents/skills/distill/SKILL.md
  • .agents/skills/impeccable/SKILL.md
  • .agents/skills/impeccable/reference/color-and-contrast.md
  • .agents/skills/impeccable/reference/craft.md
  • .agents/skills/impeccable/reference/extract.md
  • .agents/skills/impeccable/reference/interaction-design.md
  • .agents/skills/impeccable/reference/motion-design.md
  • .agents/skills/impeccable/reference/responsive-design.md
  • .agents/skills/impeccable/reference/spatial-design.md
  • .agents/skills/impeccable/reference/typography.md
  • .agents/skills/impeccable/reference/ux-writing.md
  • .agents/skills/impeccable/scripts/cleanup-deprecated.mjs
  • .agents/skills/layout/SKILL.md
  • .agents/skills/optimize/SKILL.md
  • .agents/skills/overdrive/SKILL.md
  • .agents/skills/polish/SKILL.md
  • .agents/skills/quieter/SKILL.md
  • .agents/skills/shape/SKILL.md
  • .agents/skills/typeset/SKILL.md
  • app/analysis/page.tsx
  • skills-lock.json
  • src/components/DataPrefetcher.tsx
  • src/components/layout/header/Navbar.tsx
  • src/components/layout/header/NavbarMobile.tsx
  • src/components/ui/button-group.tsx
  • src/features/analysis/analysis-view.tsx
  • src/features/analysis/utils/oracle-risk-analysis.ts
  • src/hooks/queries/useMarketsQuery.ts
  • src/hooks/useProcessedMarkets.ts
  • src/utils/oracle.ts

Comment thread .agents/skills/animate/SKILL.md Outdated
Comment on lines +123 to +128
```css
/* Prefer for simple, declarative animations */
- transitions for state changes
- @keyframes for complex sequences
- transform + opacity only (GPU-accelerated)
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Make the CSS example valid CSS (or switch to markdown text).

Inside a css fence, the bullet lines are not valid CSS and can mislead readers who copy it.

Suggested fix
 ```css
-/* Prefer for simple, declarative animations */
-- transitions for state changes
-- `@keyframes` for complex sequences
-- transform + opacity only (GPU-accelerated)
+/* Prefer for simple, declarative animations */
+.interactive {
+  transition: transform 200ms var(--ease-out-quart), opacity 200ms var(--ease-out-quart);
+}
+
+@keyframes fadeInUp {
+  from { opacity: 0; transform: translateY(8px); }
+  to { opacity: 1; transform: translateY(0); }
+}
</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/animate/SKILL.md around lines 123 - 128, Replace the invalid
bullet-list inside the css fence in SKILL.md with valid CSS rules or convert the
block to a non-code markdown list; specifically either change the fenced block
to plain markdown text listing the tips, or replace the css block with real CSS
such as a class rule like .interactive { transition: ... } and a named keyframes
rule (e.g., `@keyframes` fadeInUp { ... }) so the example is copy-pastable and
syntactically correct; update the fence language if you switch to plain text.

Comment thread .agents/skills/audit/SKILL.md Outdated
- **Impact**: How it affects users
- **WCAG/Standard**: Which standard it violates (if applicable)
- **Recommendation**: How to fix it
- **Suggested command**: Which command to use (prefer: /animate, /quieter, /shape, /optimize, /adapt, /clarify, /layout, /distill, /delight, /audit, /harden, /polish, /bolder, /typeset, /critique, /colorize, /overdrive)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether a harden skill exists and is user-invocable.
fd -i '^SKILL\.md$' .agents/skills --exec sh -c '
  for f in "$@"; do
    if grep -qi "^name:\s*harden$" "$f"; then
      echo "FOUND: $f"
      sed -n "1,20p" "$f"
    fi
  done
' sh {}

Repository: antoncoding/monarch

Length of output: 45


Remove /harden from the command whitelist.

The /harden skill doesn't exist in the repository, so recommending it will break the workflow for users. Remove it from lines 112 and 131.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/audit/SKILL.md at line 112, Remove the non-existent /harden
command from the suggested-command whitelist in the SKILL.md document: find the
"**Suggested command**" list entry that currently includes "/harden" (the bullet
shown in the diff) and delete "/harden" there, and also remove the second
occurrence of "/harden" later in the same document (the other suggested-command
list around the referenced area). Ensure the remaining suggested commands and
punctuation remain unchanged.


Find the design system, component library, or shared UI directory. Understand its structure: component organization, naming conventions, design token structure, import/export conventions.

**CRITICAL**: If no design system exists, ask the user directly to clarify what you cannot infer. before creating one. Understand the preferred location and structure first.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix grammar: remove extra period.

Line 9 has an extra period before "before". Should read: "ask the user directly to clarify what you cannot infer before creating one."

📝 Proposed fix
-**CRITICAL**: If no design system exists, ask the user directly to clarify what you cannot infer. before creating one. Understand the preferred location and structure first.
+**CRITICAL**: If no design system exists, ask the user directly to clarify what you cannot infer before creating one. Understand the preferred location and structure first.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
**CRITICAL**: If no design system exists, ask the user directly to clarify what you cannot infer. before creating one. Understand the preferred location and structure first.
**CRITICAL**: If no design system exists, ask the user directly to clarify what you cannot infer before creating one. Understand the preferred location and structure first.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/impeccable/reference/extract.md at line 9, The sentence "If
no design system exists, ask the user directly to clarify what you cannot infer.
before creating one. Understand the preferred location and structure first."
contains an extra period before "before"; edit that sentence so it reads "ask
the user directly to clarify what you cannot infer before creating one." and
keep the rest unchanged to preserve the following sentence "Understand the
preferred location and structure first."

Comment on lines +128 to +138
if (stat.isSymbolicLink()) {
// Symlink: check the target if it's alive, otherwise treat
// dangling symlinks to deprecated names as safe to remove.
const targetAlive = existsSync(skillPath);
const isMatch = targetAlive ? isImpeccableSkill(skillPath) : true;
if (isMatch) {
unlinkSync(skillPath);
deleted.push(skillPath);
}
continue;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Dangling symlink is auto-deleted based on name alone.

For a symlink whose target is gone, the code removes it purely because its name is in DEPRECATED_NAMES. If a user happens to have an unrelated dangling symlink sharing one of these common names (e.g. extract, normalize), it'll be nuked without the impeccable-content check that protects real dirs. Worth at least a log line so the user sees what vanished.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/impeccable/scripts/cleanup-deprecated.mjs around lines 128 -
138, The code currently unlinks a dangling symlink purely based on
DEPRECATED_NAMES without the same content check used for live targets; update
the symlink-removal branch inside the stat.isSymbolicLink() handling so that
when existsSync(skillPath) is false and you decide to unlinkSync(skillPath) you
also emit a clear log entry (including skillPath and the fact the symlink target
was missing) before pushing to deleted; keep the isImpeccableSkill(skillPath)
check for live targets unchanged and use the same logger used elsewhere in this
module so users can see what dangling symlinks were auto-removed.

}

// CLI entry point
if (process.argv[1] && resolve(process.argv[1]) === resolve(new URL(import.meta.url).pathname)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

CLI entry check silently skips on Windows.

new URL(import.meta.url).pathname returns something like /C:/path/cleanup-deprecated.mjs on Windows, which won't match resolve(process.argv[1]). The CLI block then never runs, and node cleanup-deprecated.mjs exits quietly — exactly the "did it work?" confusion the post-update docs want to avoid.

Proposed fix
-import { join, resolve } from 'node:path';
+import { join, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
@@
-if (process.argv[1] && resolve(process.argv[1]) === resolve(new URL(import.meta.url).pathname)) {
+if (process.argv[1] && resolve(process.argv[1]) === resolve(fileURLToPath(import.meta.url))) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (process.argv[1] && resolve(process.argv[1]) === resolve(new URL(import.meta.url).pathname)) {
if (process.argv[1] && resolve(process.argv[1]) === resolve(fileURLToPath(import.meta.url))) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/impeccable/scripts/cleanup-deprecated.mjs at line 200, The
CLI entry check fails on Windows because new URL(import.meta.url).pathname
yields a prefixed path (e.g., /C:/...) that doesn't equal
resolve(process.argv[1]); replace that comparison to use a proper file-path
conversion: import and use fileURLToPath(import.meta.url) (from the 'url'
module) and compare resolve(process.argv[1]) ===
resolve(fileURLToPath(import.meta.url)) so the if block reliably detects direct
invocation across platforms; update the condition that references
process.argv[1], resolve(...), and new URL(import.meta.url).pathname
accordingly.

Comment on lines +299 to +304
onClick={(_, index) => {
const key = visibleData[index]?.key;
if (key && key !== OTHER_BUCKET_KEY) {
onSelect(key);
}
}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add a keyboard path for provider selection.

The only provider selection path is the pie slice click. Legend buttons are keyboard-focusable, but they only hide slices, so keyboard users cannot switch the provider detail/table.

Also applies to: 334-342

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/analysis/analysis-view.tsx` around lines 299 - 304, The legend
currently only selects providers via the pie slice onClick handler (using
visibleData, OTHER_BUCKET_KEY, and onSelect); add a keyboard-accessible
selection path by handling Enter/Space on the legend button elements (the same
places as the onClick handlers referenced around the visibleData usage and the
second block at 334-342) so keyboard users can call onSelect(key) when key
exists and is not OTHER_BUCKET_KEY; ensure the existing hide/toggle behavior is
preserved (e.g., keep toggle on click/space if intended) and prevent selection
for OTHER_BUCKET_KEY just as the mouse path does.

Comment thread src/features/analysis/analysis-view.tsx
Comment on lines +1017 to +1052
{entries.slice(0, MAX_TABLE_ROWS).map(({ row }) => {
const assumptions =
assumptionMode === 'peg' ? row.pegAssumptions : assumptionMode === 'vault' ? row.vaultAssumptions : row.allAssumptions;

return (
<TableRow key={row.id}>
<TableCell className="px-3 py-3 text-center">
<Tooltip content={<span className="text-xs">{getNetworkName(row.chainId) ?? row.chainId}</span>}>
<span className="inline-flex items-center justify-center">
<NetworkIcon
networkId={row.chainId}
size={16}
/>
</span>
</Tooltip>
</TableCell>
<TableCell className="px-4 py-3">
<Link
href={getMarketHref(row)}
className="no-underline"
>
<MarketIdentity
market={row.market}
chainId={row.chainId}
mode={MarketIdentityMode.Focused}
focus={MarketIdentityFocus.Loan}
showOracle={false}
showId
iconSize={18}
/>
</Link>
</TableCell>
<TableCell className="px-4 py-3 text-right tabular-nums">
<UsdWithPercent
valueUsd={forceSupplyAmounts ? row.supplyUsd : row.exposureUsd}
totalUsd={totalUsd}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use the bucket amount in bucket tables.

entries carries attributedUsd, but the row renders full market USD. Provider/assumption tables can show amounts and percentages that do not match the selected bucket.

Suggested fix
-            {entries.slice(0, MAX_TABLE_ROWS).map(({ row }) => {
+            {entries.slice(0, MAX_TABLE_ROWS).map(({ row, attributedUsd }) => {
@@
-                      valueUsd={forceSupplyAmounts ? row.supplyUsd : row.exposureUsd}
+                      valueUsd={forceSupplyAmounts ? row.supplyUsd : attributedUsd}
                       totalUsd={totalUsd}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{entries.slice(0, MAX_TABLE_ROWS).map(({ row }) => {
const assumptions =
assumptionMode === 'peg' ? row.pegAssumptions : assumptionMode === 'vault' ? row.vaultAssumptions : row.allAssumptions;
return (
<TableRow key={row.id}>
<TableCell className="px-3 py-3 text-center">
<Tooltip content={<span className="text-xs">{getNetworkName(row.chainId) ?? row.chainId}</span>}>
<span className="inline-flex items-center justify-center">
<NetworkIcon
networkId={row.chainId}
size={16}
/>
</span>
</Tooltip>
</TableCell>
<TableCell className="px-4 py-3">
<Link
href={getMarketHref(row)}
className="no-underline"
>
<MarketIdentity
market={row.market}
chainId={row.chainId}
mode={MarketIdentityMode.Focused}
focus={MarketIdentityFocus.Loan}
showOracle={false}
showId
iconSize={18}
/>
</Link>
</TableCell>
<TableCell className="px-4 py-3 text-right tabular-nums">
<UsdWithPercent
valueUsd={forceSupplyAmounts ? row.supplyUsd : row.exposureUsd}
totalUsd={totalUsd}
{entries.slice(0, MAX_TABLE_ROWS).map(({ row, attributedUsd }) => {
const assumptions =
assumptionMode === 'peg' ? row.pegAssumptions : assumptionMode === 'vault' ? row.vaultAssumptions : row.allAssumptions;
return (
<TableRow key={row.id}>
<TableCell className="px-3 py-3 text-center">
<Tooltip content={<span className="text-xs">{getNetworkName(row.chainId) ?? row.chainId}</span>}>
<span className="inline-flex items-center justify-center">
<NetworkIcon
networkId={row.chainId}
size={16}
/>
</span>
</Tooltip>
</TableCell>
<TableCell className="px-4 py-3">
<Link
href={getMarketHref(row)}
className="no-underline"
>
<MarketIdentity
market={row.market}
chainId={row.chainId}
mode={MarketIdentityMode.Focused}
focus={MarketIdentityFocus.Loan}
showOracle={false}
showId
iconSize={18}
/>
</Link>
</TableCell>
<TableCell className="px-4 py-3 text-right tabular-nums">
<UsdWithPercent
valueUsd={forceSupplyAmounts ? row.supplyUsd : attributedUsd}
totalUsd={totalUsd}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/analysis/analysis-view.tsx` around lines 1017 - 1052, The table
rows are rendering the full market USD (row.supplyUsd / row.exposureUsd) instead
of the bucket-specific amount carried on each entry as row.attributedUsd; update
the mapping in the entries slice where TableRow is rendered so the
UsdWithPercent valueUsd prop uses row.attributedUsd (or the appropriate
attributed bucket field) rather than row.supplyUsd/row.exposureUsd, and ensure
totalUsd passed to UsdWithPercent is the matching bucket total (replace with the
bucket-specific total variable if one exists) so amounts and percentages reflect
the selected bucket.

Comment thread src/features/analysis/utils/oracle-risk-analysis.ts Outdated
Comment thread src/features/analysis/utils/oracle-risk-analysis.ts Outdated
@antoncoding antoncoding changed the title feat: simple analysis feat: analysis page Apr 20, 2026
@antoncoding antoncoding merged commit 8b9abe0 into master Apr 20, 2026
4 checks passed
@antoncoding antoncoding deleted the feat/analysis branch April 20, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request Specific feature ready to be implemented ui User interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant