dev/ds: live DS consolidation audit page (preview for design review)#2319
dev/ds: live DS consolidation audit page (preview for design review)#23190xkkonrad wants to merge 5 commits into
Conversation
Adds /dev/ds/audit — a filterable inventory of all 428 token/style/component/ pattern implementations with real grep usage counts and dead/never-used flags, plus the 104 proposed merge clusters. Data generated by the consolidation giga-sweep (report in mono inbox/ds-consolidation-audit). Wires an Audit card into the /dev/ds index and updates its stats to the audited numbers.
The (mobile-ui) auth guard redirected /dev/ds (and other DEV_ONLY_PUBLIC_ROUTES) to /setup on any production build, even though dev/layout.tsx documents that all /dev routes are meant to be accessible on localhost, staging, and Vercel previews. Gate the public exemption on !peanut.me instead of IS_DEV so the design-system showcase is viewable (no login) on preview deploys, while staying gated on peanut.me.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughAdds a new design-system audit experience with reusable audit UI, generated usage datasets, and page shells for audit views. It also updates design-system navigation, related catalog pages, and dev-route exposure, plus expands mobile-ui public-route gating for additional dev tooling paths. ChangesDesign System Audit and Navigation
Public Route Gating Update
Estimated code review effort: 4 (Complex) | ~45 minutes Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
⚔️ Resolve merge conflicts
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. Comment |
Code-analysis diffPainscore total: 5838.65 → 5062.69 (-775.96) 🆕 New findings (33)
…and 13 more. ✅ Resolved (13)
📈 Painscore deltas (top movers)
|
🧪 UI test report — ✅ all greenSuites
📊 Coverage (unit)
⏱ 10 slowest test cases
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
src/app/(mobile-ui)/dev/ds/audit/page.tsx (2)
7-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
STATUS_ORDERcan silently drift fromSTATUS_META/AuditStatus.
STATUS_METAis aRecord<AuditStatus, …>so the compiler forces every status to be present, butSTATUS_ORDERis a hand-written array with no such guarantee — ifAuditStatusgains a new member later,STATUS_METAwill fail to compile (good), butSTATUS_ORDERwill happily stay stale and the new status simply won't get a filter chip (Line 156).♻️ Derive order from the exhaustive map
-const STATUS_ORDER: AuditStatus[] = ['canonical', 'variant', 'duplicate', 'adhoc', 'dead'] +const STATUS_ORDER = Object.keys(STATUS_META) as AuditStatus[]🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/`(mobile-ui)/dev/ds/audit/page.tsx around lines 7 - 14, `STATUS_ORDER` is manually duplicated from `STATUS_META`/`AuditStatus` and can go stale when statuses change. Update the audit page’s ordering logic in `page.tsx` so the filter order is derived from the exhaustive `STATUS_META` map (or otherwise tied to `AuditStatus`) instead of maintaining a separate hard-coded array. Keep the existing `STATUS_META` keys as the single source of truth and use them where the chips are rendered.
15-15: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winKeep the layer filter in sync with the generated data
LAYERSis hardcoded whileaudit-data.tsstill typeslayerasstring, so a new layer value can disappear from the filter chips without any type signal. Export a sharedLayerunion there (or derive the list from the data) and reuse it here.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/`(mobile-ui)/dev/ds/audit/page.tsx at line 15, The layer filter in the audit page is hardcoded and can drift from the generated audit data, so update the shared layer source instead of keeping a local string list. Add or reuse a exported Layer union from audit-data.ts, make the data and filter chips use that type, and have the page’s LAYERS constant derive from the shared typed source or reuse it directly so new layers can’t be added without compiler coverage.src/app/(mobile-ui)/dev/ds/page.tsx (2)
54-54: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueHero subtitle omits the new Audit section.
The breadcrumb-style flow
Foundations → Primitives → Patterns → Playgroundwasn't updated to include the newly added "Audit" section.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/`(mobile-ui)/dev/ds/page.tsx at line 54, The hero subtitle breadcrumb in the dev DS page still uses Foundations → Primitives → Patterns → Playground and needs to include the new Audit section. Update the subtitle text in the page component that renders this breadcrumb so the flow reflects the added section, keeping the existing ordering consistent with the new navigation structure.
31-37: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winHardcoded audit stats can drift from the live totals.
These counts (428, 68, 104) are duplicated by hand here, while
/dev/ds/auditcomputes the same values dynamically:const totals = useMemo(() => {... return { items: AUDIT_ITEMS.length, dead, clusters: AUDIT_CLUSTERS.length } }, []). Since this PR's stated goal is a "live" inventory that stays in sync, hardcoding these numbers on the index page defeats that purpose — any future edit toAUDIT_ITEMS/AUDIT_CLUSTERSwill silently make this page's stats stale.Consider extracting
AUDIT_ITEMS/AUDIT_CLUSTERS(or the totals) to a shared module so both pages derive counts from the same source.Based on the provided context, the audit page computes totals as "export default function DesignSystemAuditPage() { const [tab, setTab] = useState<'inventory' | 'clusters'>('inventory')" with totals derived from
AUDIT_ITEMS.length,dead, andAUDIT_CLUSTERS.length, so keeping this index page's numbers in sync manually is fragile.Also applies to: 60-62
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/`(mobile-ui)/dev/ds/page.tsx around lines 31 - 37, The Audit card stats are hardcoded and can drift from the live data. Update the `Audit` entry in the DS index page to derive its count, dead count, and cluster count from the same source used by `DesignSystemAuditPage` (or a shared totals helper/module), instead of duplicating `428`, `68`, and `104` by hand. Use the existing `AUDIT_ITEMS` and `AUDIT_CLUSTERS` data flow or extract the `totals` calculation so both pages stay synchronized automatically.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app/`(mobile-ui)/dev/ds/audit/page.tsx:
- Around line 1-24: The Prettier check is failing for this component, so update
the formatting in the audit page module to match the repository style. Re-run
Prettier on the file containing STATUS_META, STATUS_ORDER, LAYERS, and
StatusChip, and make any whitespace, indentation, or wrapping changes needed so
pnpm prettier --check passes.
In `@src/app/`(mobile-ui)/layout.tsx:
- Around line 39-45: The dev-tooling public-path check in the mobile layout is
comparing the raw BASE_URL string, so a production URL variant like a trailing
slash can incorrectly make dev routes public. Update the devToolingPublic logic
in the layout component to use a normalized production-host check or existing
environment flag instead of direct string inequality, then pass that stable
boolean into isPublicRoute.
---
Nitpick comments:
In `@src/app/`(mobile-ui)/dev/ds/audit/page.tsx:
- Around line 7-14: `STATUS_ORDER` is manually duplicated from
`STATUS_META`/`AuditStatus` and can go stale when statuses change. Update the
audit page’s ordering logic in `page.tsx` so the filter order is derived from
the exhaustive `STATUS_META` map (or otherwise tied to `AuditStatus`) instead of
maintaining a separate hard-coded array. Keep the existing `STATUS_META` keys as
the single source of truth and use them where the chips are rendered.
- Line 15: The layer filter in the audit page is hardcoded and can drift from
the generated audit data, so update the shared layer source instead of keeping a
local string list. Add or reuse a exported Layer union from audit-data.ts, make
the data and filter chips use that type, and have the page’s LAYERS constant
derive from the shared typed source or reuse it directly so new layers can’t be
added without compiler coverage.
In `@src/app/`(mobile-ui)/dev/ds/page.tsx:
- Line 54: The hero subtitle breadcrumb in the dev DS page still uses
Foundations → Primitives → Patterns → Playground and needs to include the new
Audit section. Update the subtitle text in the page component that renders this
breadcrumb so the flow reflects the added section, keeping the existing ordering
consistent with the new navigation structure.
- Around line 31-37: The Audit card stats are hardcoded and can drift from the
live data. Update the `Audit` entry in the DS index page to derive its count,
dead count, and cluster count from the same source used by
`DesignSystemAuditPage` (or a shared totals helper/module), instead of
duplicating `428`, `68`, and `104` by hand. Use the existing `AUDIT_ITEMS` and
`AUDIT_CLUSTERS` data flow or extract the `totals` calculation so both pages
stay synchronized automatically.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6ecfb401-451e-412d-9ecc-fac4cdb95091
📒 Files selected for processing (4)
src/app/(mobile-ui)/dev/ds/audit/audit-data.tssrc/app/(mobile-ui)/dev/ds/audit/page.tsxsrc/app/(mobile-ui)/dev/ds/page.tsxsrc/app/(mobile-ui)/layout.tsx
| // Allow access to public paths without authentication. | ||
| // Dev tooling routes (/dev/ds, /dev/components, gift-test, shake-test, …) are public | ||
| // on any non-production deploy — localhost, staging, Vercel previews — matching the | ||
| // intent documented in dev/layout.tsx. On peanut.me they stay gated (dev/layout 404s | ||
| // them anyway), so this only opens them where they're meant to be viewable. | ||
| const devToolingPublic = IS_DEV || BASE_URL !== 'https://peanut.me' | ||
| const isPublicPath = isPublicRoute(pathName, devToolingPublic) |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Normalize the production host before making dev tooling public.
BASE_URL is env-driven, so a production value like https://peanut.me/ would make BASE_URL !== 'https://peanut.me' true and pass true into isPublicRoute, making dev-only routes public. Compare a parsed hostname or central production-environment flag instead of the raw full URL.
Suggested fix
- const devToolingPublic = IS_DEV || BASE_URL !== 'https://peanut.me'
+ const baseHostname = (() => {
+ try {
+ return new URL(BASE_URL).hostname
+ } catch {
+ return BASE_URL
+ }
+ })()
+ const devToolingPublic = IS_DEV || baseHostname !== 'peanut.me'📝 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.
| // Allow access to public paths without authentication. | |
| // Dev tooling routes (/dev/ds, /dev/components, gift-test, shake-test, …) are public | |
| // on any non-production deploy — localhost, staging, Vercel previews — matching the | |
| // intent documented in dev/layout.tsx. On peanut.me they stay gated (dev/layout 404s | |
| // them anyway), so this only opens them where they're meant to be viewable. | |
| const devToolingPublic = IS_DEV || BASE_URL !== 'https://peanut.me' | |
| const isPublicPath = isPublicRoute(pathName, devToolingPublic) | |
| // Allow access to public paths without authentication. | |
| // Dev tooling routes (/dev/ds, /dev/components, gift-test, shake-test, …) are public | |
| // on any non-production deploy — localhost, staging, Vercel previews — matching the | |
| // intent documented in dev/layout.tsx. On peanut.me they stay gated (dev/layout 404s | |
| // them anyway), so this only opens them where they’re meant to be viewable. | |
| const baseHostname = (() => { | |
| try { | |
| return new URL(BASE_URL).hostname | |
| } catch { | |
| return BASE_URL | |
| } | |
| })() | |
| const devToolingPublic = IS_DEV || baseHostname !== 'peanut.me' | |
| const isPublicPath = isPublicRoute(pathName, devToolingPublic) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/`(mobile-ui)/layout.tsx around lines 39 - 45, The dev-tooling
public-path check in the mobile layout is comparing the raw BASE_URL string, so
a production URL variant like a trailing slash can incorrectly make dev routes
public. Update the devToolingPublic logic in the layout component to use a
normalized production-host check or existing environment flag instead of direct
string inequality, then pass that stable boolean into isPublicRoute.
…usage relabels
Adds a second, real-usage-verified lens to the DS doc site so designers can see
what the live product actually renders vs. what only exists in code/showcase.
Nav
- Audit is now a top-level tier with a sub-nav: Code Audit / App Divergences /
Big Components (everything reachable from the navbar, incl. the audits).
Relabels (the old audit conflated code call-sites with app usage)
- /dev/ds/audit reframed as a CODE audit (DRY consolidation); adds a caveat that
its counts include /dev showcase + tests and cross-links to App Divergences.
- Title primitive marked unused ("dead in product" — MarketingHero is its only
real call-site) in the primitives index + detail page.
- bg-peanut-repeat-* flagged DEAD-IN-PRODUCT (0 real usages) in Foundations/Colors.
New pages (data grep-verified, dead claims adversarially re-verified)
- /dev/ds/audit/app — App Divergences: 65 items across primitives, buttons,
pills, tokens; real vs dev usage; 8 showcase-only, 13 dead.
- /dev/ds/audit/components — Big Components: 85 items across modals (36), drawers,
lists, composite cards; each with real usage + how it diverges from siblings.
- Shared UsageAudit explorer (live/showcase-only/dead legend, filters, counts).
…nesses The Playground nav pointed at /dev/ds/playground/* routes that never existed (the whole tier 404'd). Fix: - add /dev/ds/playground index page listing the real harnesses - repoint sub-nav to the standalone pages: /dev/shake-test, /dev/perk-success-test, /dev/share-builder - allow perk-success-test + share-builder in DEV_ONLY_PUBLIC_ROUTES_REGEX so they don't bounce to /setup on non-prod deploys - .gitignore: exempt the ds playground route from the broad 'playground/' ignore
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
src/app/(mobile-ui)/dev/ds/_components/UsageAudit.tsx (2)
160-185: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueFilter toggle buttons could expose selected state via
aria-pressed.Selection is currently conveyed only through color/border styling; adding
aria-pressed={cat === c}/aria-pressed={status === s}would help assistive tech users perceive the active filter.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/`(mobile-ui)/dev/ds/_components/UsageAudit.tsx around lines 160 - 185, The filter toggle buttons in UsageAudit currently indicate selection only through styling; update the category and status button groups so the buttons expose their active state with aria-pressed. Add aria-pressed based on cat === c and status === s in the mapped button elements, keeping the existing setCat and setStatus handlers unchanged.
154-159: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winSearch input lacks an accessible label.
Only a
placeholderis provided; screen-reader users have no accessible name for this control once text is entered (placeholders aren't a reliable substitute for labels).♿ Proposed fix
<input + aria-label="Search name / divergence / file" value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search name / divergence / file…" className="w-full rounded-sm border border-n-1 bg-white px-3 py-2 text-sm outline-none focus:border-primary-1" />🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/`(mobile-ui)/dev/ds/_components/UsageAudit.tsx around lines 154 - 159, The search field in UsageAudit’s input control is missing an accessible name because it only uses a placeholder. Update the input in UsageAudit to include a proper label association or an equivalent accessible name (for example via a visible label, aria-label, or aria-labelledby) while keeping the existing search behavior and styling intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app/`(mobile-ui)/dev/ds/audit/page.tsx:
- Around line 94-96: The internal navigation link in the audit page uses a plain
anchor tag, which triggers the Next.js no-html-link-for-pages rule. Update the
App Divergences link in page.tsx to use Next.js Link from next/link instead of
<a>, keeping the same href and styling so client-side routing is used. Locate
the change in the component rendering the App Divergences navigation.
In `@src/app/`(mobile-ui)/dev/ds/foundations/colors/page.tsx:
- Around line 112-121: Replace the raw internal anchor in the colors page with
Next.js navigation by using the existing link component import pattern in the
page component. Update the `DesignNote` content that links to
`/dev/ds/audit/app` so it uses `next/link` instead of `<a>`, keeping the same
text and underline styling while preserving internal routing behavior.
In `@src/constants/routes.ts`:
- Around line 111-115: The DEV_ONLY_PUBLIC_ROUTES_REGEX in routes constants is
too permissive for the dev/ds and dev/components branches and matches partial
segments like /dev/dsfoo. Tighten the regex in DEV_ONLY_PUBLIC_ROUTES_REGEX by
adding a path boundary/end anchor for those dev-only routes so only the exact
intended public paths match when devToolingPublic is enabled.
---
Nitpick comments:
In `@src/app/`(mobile-ui)/dev/ds/_components/UsageAudit.tsx:
- Around line 160-185: The filter toggle buttons in UsageAudit currently
indicate selection only through styling; update the category and status button
groups so the buttons expose their active state with aria-pressed. Add
aria-pressed based on cat === c and status === s in the mapped button elements,
keeping the existing setCat and setStatus handlers unchanged.
- Around line 154-159: The search field in UsageAudit’s input control is missing
an accessible name because it only uses a placeholder. Update the input in
UsageAudit to include a proper label association or an equivalent accessible
name (for example via a visible label, aria-label, or aria-labelledby) while
keeping the existing search behavior and styling intact.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 18f8454b-2e05-468e-950c-4be677894720
📒 Files selected for processing (16)
.gitignoresrc/app/(mobile-ui)/dev/ds/_components/DocSidebar.tsxsrc/app/(mobile-ui)/dev/ds/_components/UsageAudit.tsxsrc/app/(mobile-ui)/dev/ds/_components/nav-config.tssrc/app/(mobile-ui)/dev/ds/audit/app/audit-app-data.tssrc/app/(mobile-ui)/dev/ds/audit/app/page.tsxsrc/app/(mobile-ui)/dev/ds/audit/audit-data.tssrc/app/(mobile-ui)/dev/ds/audit/components/audit-components-data.tssrc/app/(mobile-ui)/dev/ds/audit/components/page.tsxsrc/app/(mobile-ui)/dev/ds/audit/page.tsxsrc/app/(mobile-ui)/dev/ds/foundations/colors/page.tsxsrc/app/(mobile-ui)/dev/ds/page.tsxsrc/app/(mobile-ui)/dev/ds/playground/page.tsxsrc/app/(mobile-ui)/dev/ds/primitives/page.tsxsrc/app/(mobile-ui)/dev/ds/primitives/title/page.tsxsrc/constants/routes.ts
✅ Files skipped from review due to trivial changes (2)
- src/app/(mobile-ui)/dev/ds/audit/components/audit-components-data.ts
- src/app/(mobile-ui)/dev/ds/audit/app/audit-app-data.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/app/(mobile-ui)/dev/ds/page.tsx
| <a href="/dev/ds/audit/app" className="font-bold underline"> | ||
| App Divergences → | ||
| </a> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use next/link instead of <a> for internal navigation.
Static analysis flags this as a Next.js no-html-link-for-pages violation for internal route /dev/ds/audit/app.
🔧 Proposed fix
+import Link from 'next/link'
...
- <a href="/dev/ds/audit/app" className="font-bold underline">
+ <Link href="/dev/ds/audit/app" className="font-bold underline">
App Divergences →
- </a>
+ </Link>📝 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.
| <a href="/dev/ds/audit/app" className="font-bold underline"> | |
| App Divergences → | |
| </a> | |
| <Link href="/dev/ds/audit/app" className="font-bold underline"> | |
| App Divergences → | |
| </Link> |
🧰 Tools
🪛 ESLint
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 94-94: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/`(mobile-ui)/dev/ds/audit/page.tsx around lines 94 - 96, The internal
navigation link in the audit page uses a plain anchor tag, which triggers the
Next.js no-html-link-for-pages rule. Update the App Divergences link in page.tsx
to use Next.js Link from next/link instead of <a>, keeping the same href and
styling so client-side routing is used. Locate the change in the component
rendering the App Divergences navigation.
Source: Linters/SAST tools
| <DesignNote type="warning"> | ||
| DEAD IN PRODUCT —{' '} | ||
| <code className="rounded bg-white px-1 font-mono text-[10px]">bg-peanut-repeat-*</code> (normal / | ||
| large / small) are defined in the Tailwind theme but rendered on{' '} | ||
| <span className="underline">zero</span> real app screens (0 non-dev, non-test call-sites). | ||
| Don’t treat these as design-system tokens — they’re delete-candidates. See{' '} | ||
| <a href="/dev/ds/audit/app" className="underline"> | ||
| App Divergences → | ||
| </a> | ||
| </DesignNote> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use next/link instead of raw <a> for internal navigation.
ESLint's @next/next/no-html-link-for-pages flags this anchor to /dev/ds/audit/app, an internal route.
🔧 Proposed fix
+import Link from 'next/link'
...
- <a href="/dev/ds/audit/app" className="underline">
+ <Link href="/dev/ds/audit/app" className="underline">
App Divergences →
- </a>
+ </Link>📝 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.
| <DesignNote type="warning"> | |
| DEAD IN PRODUCT —{' '} | |
| <code className="rounded bg-white px-1 font-mono text-[10px]">bg-peanut-repeat-*</code> (normal / | |
| large / small) are defined in the Tailwind theme but rendered on{' '} | |
| <span className="underline">zero</span> real app screens (0 non-dev, non-test call-sites). | |
| Don’t treat these as design-system tokens — they’re delete-candidates. See{' '} | |
| <a href="/dev/ds/audit/app" className="underline"> | |
| App Divergences → | |
| </a> | |
| </DesignNote> | |
| import Link from 'next/link' | |
| <DesignNote type="warning"> | |
| DEAD IN PRODUCT —{' '} | |
| <code className="rounded bg-white px-1 font-mono text-[10px]">bg-peanut-repeat-*</code> (normal / | |
| large / small) are defined in the Tailwind theme but rendered on{' '} | |
| <span className="underline">zero</span> real app screens (0 non-dev, non-test call-sites). | |
| Don’t treat these as design-system tokens — they’re delete-candidates. See{' '} | |
| <Link href="/dev/ds/audit/app" className="underline"> | |
| App Divergences → | |
| </Link> | |
| </DesignNote> |
🧰 Tools
🪛 ESLint
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
[error] 118-118: Do not use an <a> element to navigate to /dev/ds/audit/app/. Use <Link /> from next/link instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
(@next/next/no-html-link-for-pages)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/`(mobile-ui)/dev/ds/foundations/colors/page.tsx around lines 112 -
121, Replace the raw internal anchor in the colors page with Next.js navigation
by using the existing link component import pattern in the page component.
Update the `DesignNote` content that links to `/dev/ds/audit/app` so it uses
`next/link` instead of `<a>`, keeping the same text and underline styling while
preserving internal routing behavior.
Source: Linters/SAST tools
| * Regex for dev-only public routes (dev index, gift-test, shake-test, ds playground harnesses) | ||
| * Only matched when IS_DEV is true (or on non-production deploys) | ||
| */ | ||
| export const DEV_ONLY_PUBLIC_ROUTES_REGEX = /^\/(dev$|dev\/gift-test|dev\/shake-test|dev\/ds|dev\/components)/ | ||
| export const DEV_ONLY_PUBLIC_ROUTES_REGEX = | ||
| /^\/(dev$|dev\/gift-test|dev\/shake-test|dev\/perk-success-test|dev\/share-builder|dev\/ds|dev\/components)/ |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
Regex allows partial-segment matches for dev/ds and dev/components.
Without a trailing boundary, paths like /dev/dsfoo or /dev/componentsHidden would also match and become public whenever devToolingPublic is true. Low risk since this only applies on non-production deploys, but worth tightening.
🔒 Proposed fix
-export const DEV_ONLY_PUBLIC_ROUTES_REGEX =
- /^\/(dev$|dev\/gift-test|dev\/shake-test|dev\/perk-success-test|dev\/share-builder|dev\/ds|dev\/components)/
+export const DEV_ONLY_PUBLIC_ROUTES_REGEX =
+ /^\/(dev$|dev\/gift-test|dev\/shake-test|dev\/perk-success-test|dev\/share-builder|dev\/ds(\/|$)|dev\/components(\/|$))/📝 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.
| * Regex for dev-only public routes (dev index, gift-test, shake-test, ds playground harnesses) | |
| * Only matched when IS_DEV is true (or on non-production deploys) | |
| */ | |
| export const DEV_ONLY_PUBLIC_ROUTES_REGEX = /^\/(dev$|dev\/gift-test|dev\/shake-test|dev\/ds|dev\/components)/ | |
| export const DEV_ONLY_PUBLIC_ROUTES_REGEX = | |
| /^\/(dev$|dev\/gift-test|dev\/shake-test|dev\/perk-success-test|dev\/share-builder|dev\/ds|dev\/components)/ | |
| * Regex for dev-only public routes (dev index, gift-test, shake-test, ds playground harnesses) | |
| * Only matched when IS_DEV is true (or on non-production deploys) | |
| */ | |
| export const DEV_ONLY_PUBLIC_ROUTES_REGEX = | |
| /^\/(dev$|dev\/gift-test|dev\/shake-test|dev\/perk-success-test|dev\/share-builder|dev\/ds(\/|$)|dev\/components(\/|$))/ |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/constants/routes.ts` around lines 111 - 115, The
DEV_ONLY_PUBLIC_ROUTES_REGEX in routes constants is too permissive for the
dev/ds and dev/components branches and matches partial segments like /dev/dsfoo.
Tighten the regex in DEV_ONLY_PUBLIC_ROUTES_REGEX by adding a path boundary/end
anchor for those dev-only routes so only the exact intended public paths match
when devToolingPublic is enabled.
Adds
/dev/ds/audit— a live, filterable inventory of all 428 token/component/pattern implementations with real grep usage counts + dead-flags + 104 merge clusters, from the DS consolidation giga-sweep. Also makes/devtooling routes public on non-prod deploys so the showcase is viewable on the Vercel preview without login (matching dev/layout intent; peanut.me stays gated).Purpose: hand design (Vlad) a live URL to review the design-system consolidation. Not necessarily for merge — primarily for the preview deploy.
🤖 Generated with Claude Code