Skip to content

feat(example-apps): add dashrate#98

Open
thephez wants to merge 24 commits into
dashpay:mainfrom
thephez:rate-example
Open

feat(example-apps): add dashrate#98
thephez wants to merge 24 commits into
dashpay:mainfrom
thephez:rate-example

Conversation

@thephez

@thephez thephez commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds DashRate, a React + TypeScript + Vite example app for rating Dash Platform tutorial resources on testnet. It's the showcase for Platform 4.0's relational document queries — provable count, grouped count (GROUP BY) for the per-star distribution, range counts, and where filtering — and joins the existing example apps (dashnote, dashmint-lab, dashproof-lab).

A review is one mutable review document per identity per resource: a required 1–5 rating, an optional reviewText, and a resourceId pointing at a catalog entry. The unique $ownerId + resourceId index means saving again edits the existing document rather than duplicating it, and the contract keeps history so prior revisions are viewable. Read-only browsing works without signing in; writing a review requires a mnemonic in Settings.

What's included

  • The app — a four-view shell (resources / my-reviews / settings / how): a sidebar resource list plus a detail panel with the aggregate rating, a per-star distribution histogram (click a bar to filter), a review composer, recent reviews, and per-review revision history. App.tsx orchestrates; SDK concerns live one-per-file under src/dash/, data fetching in src/hooks/, presentational components in src/components/, pure utilities in src/lib/.
  • Relational query patterns — total count over a countable resourceId index; grouped count over [resourceId, rating] (rangeCountable) for the distribution, with the average derived in JS from the per-star counts (no sum/average query); rating == N where filtering covered by the same index.
  • Tests — Vitest unit tests over src/dash/ and src/lib/; component tests (@testing-library/react + jsdom) and hook tests (renderHook, including the request-id stale-response guards); and a read-only Playwright e2e smoke suite (smoke, settings). 152 tests; ~82% statement coverage.
  • Toolingeslint.config.js, tsconfig project refs, vite.config.ts, and CI (dashrate-ci.yml runs test + build); listed in the example-apps README.

Notes

  • DEFAULT_CONTRACT_ID ships a working testnet review contract; Settings can register a fresh one and switch to it.

Summary by CodeRabbit

  • New Features

    • Added the DashRate example app with a complete review and rating interface, including resource browsing, personal reviews, settings, review history, and rating summaries.
    • Added support for signing in, saving reviews, viewing past edits, and browsing without signing in.
  • Documentation

    • Added README and guidance docs for the new example app.
  • Chores

    • Added CI, linting, formatting, and test configuration for the DashRate app, plus updated ignore rules for generated artifacts.

thephez and others added 24 commits June 23, 2026 16:35
DashRate is a React + TypeScript + Vite app demonstrating Platform v4 document aggregation features (count, sum, average) and document history for rating tutorial resources on testnet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restructure the resource rating summary into a single flowing block (stars + average out of 5, then review count and total points as muted detail), reorder recent-review cards to lead with the platform identity and drop the redundant resource title, clarify sidebar review counts with a pluralized noun, and soften the review form copy and textarea height.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Point DEFAULT_CONTRACT_ID at a published testnet DashRate contract so fresh installs read aggregates and reviews immediately instead of an empty state, and update the README to document the default and the localStorage override.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace whole-star rounding with a StarMeter component that clips the gold fill to the exact average, so aggregate ratings render partial stars in the sidebar and detail header.

Group the rating, review form, and recent reviews as divider-separated sections of one resource instead of bordered boxes, and render reviews and history as continuous divided lists rather than stacked cards.

Move the aggregate rating under the title, put Open on the title row (opening in a new tab), and place the refreshing indicator on the eyebrow line with a reserved height so toggling it no longer shifts the layout. Restyle the signed-out prompt as a sign-in CTA that links to Settings, and soften the resource card hover so it no longer floods the card.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a per-star distribution histogram beside the aggregate rating and a server-side rating filter on the reviews list, showcasing Platform 4.0 grouped and range counts.

The distribution comes from one grouped count (`count` GROUP BY `rating` over a `[resourceId, rating]` countable + rangeCountable index); the average is derived in JS from the per-star counts, so no sum/average query is needed. The reviews filter adds a `rating == N` clause served by the same index, with its `orderBy` aligned to the index's trailing property. A plain `count` over `[resourceId]` supplies the total.

Both indices are count-only on purpose: pairing `summable` on the `[resourceId]` prefix with the count-only `[resourceId, rating]` continuation registers fine but breaks every document insert (dashpay/platform#3960), so the average moved off `summable` and onto the derived distribution.

Add a dashrate CLAUDE.md documenting the query patterns and the index gotchas (grouped-count key encoding, rangeCountable, the summable-prefix conflict, orderBy-vs-index).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve each on-screen identity's DPNS name and display it in place of the short identity ID — in the recent-reviews rows, the My reviews header, and the Settings identity line — falling back to the short ID when no name is registered.

Names resolve lazily after the lists render: only distinct, not-yet-cached owners are looked up, in parallel, and cached by identity across resource switches, so a feed of many rows by few reviewers costs one lookup per reviewer and revisiting a resource costs nothing.

Make the dedicated reviews effect the single owner of the recent-reviews list, keyed on resource and rating filter, so clearing the filter re-fetches the full list instead of leaving the filtered subset on screen.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Switching resources or rating filters left the previous selection's reviews on screen until the slower document query returned. Reset the review list during render when the (resource, filter) key changes, so the section goes empty immediately and repopulates when the fetch lands.

Replace the misleading "No reviews yet" shown during that gap with a "Loading reviews…" indicator (relocated from the header eyebrow row), so an in-flight load no longer reads as an empty resource.

Drop the default top margin on section headings so "Your review" and "Review history" align with "Recent reviews" instead of sitting lower.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add tests for the previously untested write path and pure helpers, and
fill the read-path gaps: review create/update branches and rating
validation, format helpers, DPNS name resolution, catalog integrity,
the remaining query helpers (getRatingCount, listMyReviews,
findMyReviewForResource), normalizeReviews shape tolerance, and the
review-history limit clamp.

Add a test:coverage script backed by @vitest/coverage-v8 and a coverage
block in the Vite config, matching the sibling apps. Ignore the
generated coverage/ output in the ESLint config.

Wire findResource into App.tsx in place of the two inline RESOURCES.find
lookups so the exported helper is real app behavior rather than dead code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a Dash bridge link so users without an identity have a path to create
one for testing.

Move the identity index and contract controls behind an Advanced settings
disclosure so the default sign-in view is just the mnemonic. Group them in
a single bordered panel, render the index as a compact numeric field with a
help note, and label the contract ID optional.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Re-fetch the current resource's review list after a successful save and
swap it in place, so an edited or new review appears under Recent reviews
without navigating away or refreshing. Swapping in place (no clear) keeps
the existing rows visible, avoiding a flash to the loading state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a workflow that runs the Vitest suite and build (tsc -b included) on push/PR touching example-apps/dashrate, matching how the other apps are gated. Also apply Prettier to the test files so they match the project style.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Break the monolithic App.tsx into focused view components, data hooks,
and shared session/ratings modules to reduce its size and improve
maintainability.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the resource summary directly under its title, drop the redundant rating prompt and "Comment" label in favor of an accessible placeholder plus a visually hidden label, and turn revision history into a "Show/Hide previous versions" toggle nested under the user's review instead of a peer section.

Add focus styling and a subtle background for form fields, tighten the spacing between the stars and the comment box, and remove the dead .section-head selector and an obsolete .settings-form comment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the redundant per-operation start/success logs from the read-side queries — the per-resource fan-out emitted ~28 console lines per Resources-view load. Keep the error logs, replace the per-resource success spam with one aggregate "Loaded ratings for N resources." line, and keep one summary line on the review-list and my-reviews loads.

Remove the now-unused log parameter from findMyReviewForResource (its result already flows into UI state) and the dead distributionLabel helper.

Add a 480px small-phone CSS tier with tighter spacing and a few row→column stacks below the existing 820px breakpoint.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The mnemonic input is a textarea, so Enter inserted a newline instead of submitting the login form. Submit on Enter (without Shift) when a mnemonic is present and the form isn't busy; Shift+Enter still adds a newline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…yout

Describe the current App-as-orchestrator structure with the components/, hooks/, session/, and expanded lib/ directories, and document the sdkCore.ts loader, the full test list, and the test:coverage script in both CLAUDE.md and the README.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On the stacked mobile layout the resource list sits above the detail panel, so tapping a resource left the rating and reviews off-screen. Selecting now scrolls the detail into view at the ≤820px breakpoint; the desktop two-column layout is untouched.

Pin the topbar (sticky, top: 0) on mobile so the nav tabs stay reachable after the jump, relax the shell's overflow to horizontal-only so sticky isn't trapped, and offset the detail's scroll-margin-top so the heading clears the pinned header.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reveal the histogram count on row hover/focus as an "N review(s)" label, and hide the gold bar entirely at zero votes instead of leaving a 2px sliver.

Flatten the unselected resource cards — transparent fill and border, no shadow, tighter list gap — so only the selected card carries the green tint and outline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…stogram

Measure the sticky topbar's real height when scrolling to the detail panel on mobile, instead of a hardcoded 120px offset that over- or undershoots once the header wraps to a taller stack.

Gate the histogram count's hover reveal behind a real hovering pointer so a tap or scroll over a row on touch devices no longer leaves the count stuck visible; touch keeps the active/focus reveals.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Matches the in-app GitHub link the sibling example apps already carry, so the deployed dashrate app links back to the canonical platform-tutorials repo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add Testing Library component/hook tests for the view shells, review pieces, and SDK-backed hooks, mocking the SDK loaders so the bundle never enters jsdom. Extend the Vitest include to `.tsx` and have tsconfig.app strict-typecheck the test files.

Add a Playwright e2e suite (smoke + settings) running desktop and mobile against real testnet, with playwright.config auto-booting Vite on :5182, plus the test:e2e scripts, dev deps, and lint/tsconfig excludes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add Vitest coverage for App.tsx orchestration handlers (save-review guards
and success refresh, register/clear/submit contract, sign-out, load history)
and for the SDK/WASM error shapes errorMessage extracts.

Also list dashrate in the example-apps README and ignore Playwright report
and test-results output.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds the DashRate example app, its Dash SDK data and mutation helpers, React hooks and views, app-level orchestration, CI/tooling configuration, and unit/e2e coverage.

Changes

DashRate app rollout

Layer / File(s) Summary
Workspace setup
.github/workflows/dashrate-ci.yml, .gitignore, example-apps/README.md, example-apps/dashrate/{README.md,CLAUDE.md,package.json,eslint.config.js,playwright.config.ts,tsconfig*.json,vite.config.ts,index.html,.prettierignore,.prettierrc.json,src/vite-env.d.ts}
Adds the DashRate workspace configuration, CI workflow, package metadata, and app documentation.
SDK foundation and contract helpers
example-apps/dashrate/src/{dash/{types.ts,client.ts,keyManager.ts,sdkCore.ts,sdkModule.ts,contract.ts,history.ts,review.ts,resolveDpnsName.ts},session/types.ts}, example-apps/dashrate/test/{contract.test.ts,history.test.ts,review.test.ts,resolveDpnsName.test.ts}
Defines Dash SDK types, loaders, contract registration, review persistence, history, and DPNS resolution.
Query and utility helpers
example-apps/dashrate/src/{dash/queries.ts,lib/{format.ts,logger.ts,ratings.ts}}, example-apps/dashrate/test/{format.test.ts,logger.test.ts,queries.test.ts}
Implements review query helpers and shared formatting, logging, and rating utilities.
Reactive data hooks
example-apps/dashrate/src/hooks/{useDpnsNames.ts,useMyReviews.ts,useResourceRatings.ts}, example-apps/dashrate/test/{useDpnsNames.test.tsx,useMyReviews.test.tsx,useResourceRatings.test.tsx}
Adds hooks for DPNS name lookup, my-review loading, and per-resource rating state.
Reusable UI components
example-apps/dashrate/src/{catalog/resources.ts,components/{AppNotices.tsx,HowItWorks.tsx,MyReviewCard.tsx,ReviewHistory.tsx,ReviewRow.tsx,StarMeter.tsx,TopNav.tsx}}, example-apps/dashrate/test/{AppNotices.test.tsx,MyReviewCard.test.tsx,ReviewHistory.test.tsx,ReviewRow.test.tsx,StarMeter.test.tsx,TopNav.test.tsx,resources.test.ts}
Adds shared catalog and display components for navigation, review summaries, history, stars, and help content.
Workspace views and styling
example-apps/dashrate/src/{components/{MyReviewsView.tsx,RecentReviews.tsx,ResourcesView.tsx,ReviewForm.tsx,SettingsView.tsx},main.tsx,styles.css}, example-apps/dashrate/test/{MyReviewsView.test.tsx,RecentReviews.test.tsx,ResourcesView.test.tsx,ReviewForm.test.tsx,SettingsView.test.tsx}
Adds the resource workspace, settings and review views, the React entrypoint, and app styling.
App orchestration and E2E
example-apps/dashrate/src/App.tsx, example-apps/dashrate/test/App.test.tsx, example-apps/dashrate/test/e2e/{fixtures.ts,settings.spec.ts,smoke.spec.ts}
Adds App state orchestration and app-level unit and end-to-end coverage.

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant saveReview
  participant findMyReviewForResource
  participant DashSdk
  App->>saveReview: session, contractId, resourceId, rating, reviewText
  saveReview->>findMyReviewForResource: ownerId + resourceId
  findMyReviewForResource->>DashSdk: sdk.documents.query(...)
  DashSdk-->>findMyReviewForResource: existing review or none
  saveReview->>DashSdk: sdk.documents.create / replace
  DashSdk-->>saveReview: review id
  saveReview-->>App: review id
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

A bunny hopped through DashRate’s glade,
Where stars and reviews happily played.
With clicks and tests in tidy rows,
My whiskers twitch at how it grows. 🐰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.46% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding the DashRate example app under example-apps.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

example-apps/dashrate/eslint.config.js

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

example-apps/dashrate/playwright.config.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

example-apps/dashrate/src/App.tsx

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

  • 60 others

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🧹 Nitpick comments (19)
example-apps/dashrate/src/hooks/useResourceRatings.ts (1)

138-160: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

loadResourceData re-fetches every resource's count/distribution on each resource selection.

selectedResourceId is in loadResourceData's dependency list (Line 157) only because of the per-resource findMyReviewForResource block (Lines 138-150). Since loadResourceData is a dependency of the effect at Lines 197-217, changing the selected resource recreates the callback and reruns the effect, re-issuing getRatingCount + getRatingDistribution for all RESOURCES even though those aggregates don't depend on the selection. Consider splitting the per-resource "my review" lookup into its own effect/callback keyed on selectedResourceId, leaving the all-resource aggregate load keyed on contractId/session. If the full reload is intentional for the demo, please disregard.

Also applies to: 197-217

🤖 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 `@example-apps/dashrate/src/hooks/useResourceRatings.ts` around lines 138 -
160, Move the selected-resource “my review” lookup out of loadResourceData so
changing selectedResourceId does not recreate that callback and rerun the
aggregate refresh effect; keep the RESOURCES count/distribution loading in
loadResourceData keyed only by contractId/session, and add a separate effect or
callback for findMyReviewForResource, setMySelectedReview, setRating,
setHoverRating, and setReviewText that depends on selectedResourceId and
session. Update the useEffect that currently depends on loadResourceData to
avoid re-fetching all resource aggregates when only the selection changes.
.github/workflows/dashrate-ci.yml (1)

32-32: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Consider hardening the checkout with persist-credentials: false.

zizmor flags credential persistence (artipacked). Risk here is low (contents: read, no pushes), but since no step needs the token, disabling persistence is a cheap hardening.

🔒 Proposed change
-      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+        with:
+          persist-credentials: false
🤖 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 @.github/workflows/dashrate-ci.yml at line 32, The checkout step in the
dashrate CI workflow is persisting Git credentials unnecessarily, so harden the
existing actions/checkout usage by disabling credential persistence. Update the
checkout configuration to set persist-credentials to false since no later step
needs the token, keeping the workflow behavior unchanged while reducing
exposure.

Source: Linters/SAST tools

example-apps/dashrate/src/dash/contract.ts (1)

84-90: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Guard localStorage writes like the read path.

loadStoredContractId already wraps getItem in try/catch, but saveContractId/clearStoredContractId call setItem/removeItem unguarded. These throw when storage is disabled or full (e.g. Safari private mode). Notably, saveContractId runs at Line 143 after sdk.contracts.publish succeeds, so a storage failure would surface as an error even though the contract was already published on-chain, losing the returned ID.

♻️ Proposed guard
 export function saveContractId(contractId: string): void {
-  localStorage.setItem(STORAGE_KEY, contractId);
+  try {
+    localStorage.setItem(STORAGE_KEY, contractId);
+  } catch {
+    // ignore storage failures (e.g. private mode / quota)
+  }
 }

 export function clearStoredContractId(): void {
-  localStorage.removeItem(STORAGE_KEY);
+  try {
+    localStorage.removeItem(STORAGE_KEY);
+  } catch {
+    // ignore storage failures
+  }
 }
🤖 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 `@example-apps/dashrate/src/dash/contract.ts` around lines 84 - 90, The
localStorage write path in saveContractId and clearStoredContractId is
unguarded, unlike loadStoredContractId, so wrap both setItem and removeItem in
the same try/catch style used by the read helper. Update the contract.ts storage
helpers to swallow or safely handle storage errors, and ensure the
saveContractId call site after sdk.contracts.publish does not turn a successful
publish into a failure because persistence to localStorage was unavailable.
example-apps/dashrate/test/ReviewRow.test.tsx (1)

1-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run this file through the app's Prettier config.

This test file uses double-quoted strings, so it won't match the repository formatting contract. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/test/ReviewRow.test.tsx` around lines 1 - 45, This test
file is not formatted according to the repository’s Prettier rules. Reformat the
ReviewRow test to match the app’s standard style in the same file, keeping the
existing assertions and structure intact while converting the current
double-quoted imports/strings and spacing to the project’s Prettier output for
this `ReviewRow` test.

Source: Coding guidelines

example-apps/dashrate/src/catalog/resources.ts (1)

1-64: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run this file through the app's Prettier config.

This file uses double-quoted strings throughout, so it won't match the repository formatting contract. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/src/catalog/resources.ts` around lines 1 - 64, The
RESOURCES module and findResource function need to be reformatted to match the
app’s Prettier contract. Update the RatedResource interface, RESOURCES array,
and findResource implementation in this file to use the repository’s standard
formatting (single quotes, 2-space indentation, and trailing commas where
applicable) so it is consistent with the rest of the codebase.

Source: Coding guidelines

example-apps/dashrate/test/MyReviewCard.test.tsx (1)

1-56: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run this file through the app's Prettier config.

This test file uses double-quoted strings, so it won't match the repository formatting contract. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/test/MyReviewCard.test.tsx` around lines 1 - 56, This
test file needs to be reformatted to match the repository Prettier contract.
Update the Jest/Vitest test in MyReviewCard.test.tsx so imports, strings, and
other formatting follow the app’s Prettier rules (single quotes, 2-space
indentation, trailing commas) while keeping the existing test logic and symbols
like makeReview, MyReviewCard, and vi.fn unchanged.

Source: Coding guidelines

example-apps/dashrate/test/MyReviewsView.test.tsx (1)

1-110: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run this file through the app's Prettier config.

This test file uses double-quoted strings, so it won't match the repository formatting contract. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/test/MyReviewsView.test.tsx` around lines 1 - 110, The
test file formatting does not match the repository’s Prettier contract, so
update the MyReviewsView test to follow the app’s configured style. Reformat the
existing imports, strings, indentation, and trailing commas in
MyReviewsView.test.tsx to match Prettier output, keeping the current test
behavior unchanged.

Source: Coding guidelines

example-apps/dashrate/src/components/HowItWorks.tsx (1)

1-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run this file through the app's Prettier config.

This file uses double-quoted strings, so it won't match the repository formatting contract. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/src/components/HowItWorks.tsx` around lines 1 - 39,
Format the HowItWorks component to match the repository’s Prettier contract:
update the JSX in HowItWorks so string literals and attributes follow the
project’s single-quote style, 2-space indentation, and trailing-comma rules.
Keep the component behavior unchanged and use the existing HowItWorks export as
the target for the formatting pass.

Source: Coding guidelines

example-apps/dashrate/src/components/AppNotices.tsx (1)

1-19: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run this file through the app's Prettier config.

This file uses double-quoted strings, so it won't match the repository formatting contract. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/src/components/AppNotices.tsx` around lines 1 - 19, Run
the AppNotices component through the project’s Prettier formatting so it matches
the repository contract; the current JSX in AppNotices uses double quotes and
should be reformatted to the standard single-quote, 2-space indentation, and
trailing-comma style. Keep the component behavior unchanged and use the existing
AppNotices export as the target for the formatting-only update.

Source: Coding guidelines

example-apps/dashrate/test/AppNotices.test.tsx (1)

1-41: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run this file through the app's Prettier config.

This test file uses double-quoted strings, so it won't match the repository formatting contract. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/test/AppNotices.test.tsx` around lines 1 - 41, Format
the AppNotices test file with the repository’s Prettier rules: convert the
existing double-quoted imports and test strings to single quotes, keep 2-space
indentation, and preserve/add trailing commas where Prettier would. Use the
AppNotices test cases and the afterEach/render/describe blocks as the targets
for the formatting pass.

Source: Coding guidelines

example-apps/dashrate/test/RecentReviews.test.tsx (1)

1-98: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run this file through the app's Prettier config.

This test file uses double-quoted strings, so it won't match the repository formatting contract. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/test/RecentReviews.test.tsx` around lines 1 - 98, The
RecentReviews test file is not matching the repository’s Prettier style, mainly
due to quote and formatting inconsistencies. Reformat the test to the app’s
standard Prettier output so imports, strings, and indentation are consistent
with the rest of the codebase. Keep the changes confined to the RecentReviews
test helpers and test cases, and preserve the existing behavior while
normalizing the formatting.

Source: Coding guidelines

example-apps/dashrate/test/TopNav.test.tsx (1)

1-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run the file through the app’s Prettier config.

This TSX test still uses double-quoted imports/strings instead of the required single-quote style. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/test/TopNav.test.tsx` around lines 1 - 54, This TopNav
test file is not matching the app’s Prettier style, so reformat the TSX in
TopNav.test.tsx using the project’s formatter. Update the imports, string
literals, and trailing commas to the single-quote Prettier conventions used
across the repo, while keeping the existing TopNav, NAV, and vi-based test logic
unchanged.

Source: Coding guidelines

example-apps/dashrate/src/components/RecentReviews.tsx (1)

1-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run the file through the app’s Prettier config.

This TSX file still uses double-quoted imports/strings instead of the required single-quote style. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/src/components/RecentReviews.tsx` around lines 1 - 60,
RecentReviews still isn’t formatted with the app’s Prettier rules, specifically
the import and string quoting style. Reformat the RecentReviews component in
example-apps/dashrate/src/components/RecentReviews.tsx using the project
Prettier config so the imports and all string literals follow single-quote
conventions, with the existing 2-space indentation and trailing commas
preserved.

Source: Coding guidelines

example-apps/dashrate/src/components/ResourcesView.tsx (1)

1-231: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run the file through the app’s Prettier config.

This TSX file still uses double-quoted imports/strings instead of the required single-quote style. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/src/components/ResourcesView.tsx` around lines 1 - 231,
The ResourcesView TSX file is not formatted according to the app’s Prettier
rules, so update it to match the configured style. Reformat the imports and
string literals in ResourcesView and its helper logic using the Prettier config
(single quotes, 2-space indentation, trailing commas) while preserving behavior
and keeping the existing symbols like ResourcesView and handleSelectResource
intact.

Source: Coding guidelines

example-apps/dashrate/src/components/ReviewForm.tsx (1)

1-117: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run the file through the app’s Prettier config.

This TSX file still uses double-quoted imports/strings instead of the required single-quote style. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/src/components/ReviewForm.tsx` around lines 1 - 117,
The ReviewForm TSX file is not aligned with the app’s Prettier formatting rules,
specifically the quote style and any related formatting conventions. Run
ReviewForm through the project’s Prettier config and ensure the exported
ReviewForm component, its import statements, and all JSX/string literals are
formatted consistently with single quotes, 2-space indentation, and trailing
commas where applicable.

Source: Coding guidelines

example-apps/dashrate/src/components/ReviewHistory.tsx (1)

1-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run the file through the app’s Prettier config.

This TSX file still uses double-quoted imports/strings instead of the required single-quote style. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/src/components/ReviewHistory.tsx` around lines 1 - 31,
The ReviewHistory component needs formatting to match the app’s Prettier rules,
since it still uses double quotes and may not fully conform to the required
style. Run the ReviewHistory TSX through the project’s Prettier config so the
imports, strings, indentation, and trailing commas are normalized consistently
with the existing formatting standards.

Source: Coding guidelines

example-apps/dashrate/src/components/StarMeter.tsx (1)

1-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run the file through the app’s Prettier config.

This TSX file still uses double-quoted imports/strings instead of the required single-quote style. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/src/components/StarMeter.tsx` around lines 1 - 31, The
StarMeter component in StarMeter.tsx is not formatted according to the app’s
Prettier rules, so update the file to match the existing formatting conventions
used in the codebase. Run it through the project’s Prettier config and ensure
the `StarMeter` import, string literals, indentation, and any trailing commas
follow the required single-quote, 2-space, trailing-comma style.

Source: Coding guidelines

example-apps/dashrate/test/ReviewHistory.test.tsx (1)

1-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run the file through the app’s Prettier config.

This TSX test still uses double-quoted imports/strings instead of the required single-quote style. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/test/ReviewHistory.test.tsx` around lines 1 - 38, The
ReviewHistory test file is not formatted according to the app’s Prettier rules,
specifically the imports and string literals still use double quotes. Reformat
the test to match the existing Prettier config and project style, keeping the
same behavior in ReviewHistory and the entries test data while ensuring
single-quote usage, 2-space indentation, and trailing commas where applicable.

Source: Coding guidelines

example-apps/dashrate/test/StarMeter.test.tsx (1)

1-55: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Run the file through the app’s Prettier config.

This TSX test still uses double-quoted imports/strings instead of the required single-quote style. As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

🤖 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 `@example-apps/dashrate/test/StarMeter.test.tsx` around lines 1 - 55, The
StarMeter test file needs to be formatted to match the app’s Prettier rules,
since it still uses double quotes instead of the required single-quote style.
Reformat the existing `StarMeter.test.tsx` content with Prettier so imports,
strings, indentation, and trailing commas conform to the project’s standard,
keeping the same test names and helpers such as `fill` and
`describe("StarMeter", ...)`.

Source: Coding guidelines

🤖 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 `@example-apps/dashrate/.prettierrc.json`:
- Around line 1-4: The app-local Prettier config is missing the single-quote
setting, so formatting in this workspace still emits double-quoted JS/TS output.
Update the Prettier configuration in the dashrate app’s .prettierrc.json to
enable single quotes alongside the existing printWidth and trailingComma
settings, so npm run format follows the repo’s formatting contract.

In `@example-apps/dashrate/eslint.config.js`:
- Around line 11-15: The flat ESLint config block for `files: ["**/*.{ts,tsx}"]`
is too broad and applies browser globals to `playwright.config.ts`, causing
Node-only references like `process.env.CI` to fail linting. Update the config in
`eslint.config.js` by either narrowing this browser-scoped block to only
app/test source files or adding a separate Node-scoped override for
`playwright.config.ts`, keeping the browser globals tied to the correct sources
and using the existing flat-config structure.

In `@example-apps/dashrate/README.md`:
- Around line 50-56: The README description of aggregate queries is inconsistent
about where the total review count comes from; update the wording in the
dashrate README to make the query plan consistent. Use the existing
aggregate/index terms already mentioned there (`resourceId`, `rating`,
`countable`, `rangeCountable`, `summable`) and clarify whether the standalone
count index is only for total counts or whether the grouped count query is the
single source for histogram, sum, and average so the reader sees one coherent
explanation.

In `@example-apps/dashrate/src/components/AppNotices.tsx`:
- Around line 12-15: Update the notice in AppNotices so it no longer says “No
default contract is bundled yet,” since DashRate now ships a default testnet
contract ID. Reword the message to describe a missing or cleared active contract
configuration instead, while keeping the guidance about signing in, registering
a contract, or pasting an existing contract ID in Settings. Use the notice
markup in AppNotices as the target for the text change.
- Line 10: The status message in AppNotices is rendered as a plain paragraph, so
assistive tech may not announce updates. Update the status rendering in
AppNotices to use an accessible live region, such as adding role="status" or an
aria-live attribute to the existing status element, so changes are announced
when status updates at runtime.

In `@example-apps/dashrate/src/components/ReviewForm.tsx`:
- Around line 36-37: The history toggle logic in ReviewForm is load-only right
now, but the UI label and state imply a real open/close interaction. Update the
ReviewForm prop contract and toggle handling so the control has an explicit
expanded/collapse state or clearly remains load-only, and make the button
behavior match the displayed label instead of always calling onLoadHistory. Use
the existing ReviewForm component and the historyOpen/displayRating logic as the
place to wire in the new state or callback.

In `@example-apps/dashrate/src/components/StarMeter.tsx`:
- Around line 10-12: The spoken label in StarMeter is using the raw rating
instead of the same clamped value used for fillPercent, so update the label
logic to reuse the bounded 0–5 value for both the visual meter and the
aria-label. Fix this in StarMeter by deriving a single clamped rating from value
and using it for both the percentage fill and the accessible text, while still
keeping the null case as the “No rating yet” label.

In `@example-apps/dashrate/src/dash/resolveDpnsName.ts`:
- Around line 16-21: The resolveDpnsName helper currently returns null for both
a real “no DPNS name” result and for SDK lookup failures, which causes
useDpnsNames to cache transient errors as permanent misses. Update
resolveDpnsName to distinguish a successful empty result from an exception
thrown by sdk.dpns.username, and return or surface failures in a separate way so
useDpnsNames can retry rather than caching null; keep the existing normalization
logic in resolveDpnsName for valid string results.

In `@example-apps/dashrate/src/styles.css`:
- Around line 263-266: The .sr-only accessibility helper still uses the
deprecated clip property, which Stylelint flags. Update the .sr-only rule in the
stylesheet to remove clip and keep the existing clip-path-based visually hidden
behavior, preserving the rest of the rules unchanged.

In `@example-apps/dashrate/test/SettingsView.test.tsx`:
- Around line 114-116: The test assertion around the rendered current value is
too generic and can break once the contract ID is displayed inside the same
paragraph. Update the expectation in SettingsView.test.tsx to target the full
rendered text for the “Current:” label together with the contract ID, using the
existing screen query near the clear-button interaction so the assertion matches
the actual SettingsView output.

---

Nitpick comments:
In @.github/workflows/dashrate-ci.yml:
- Line 32: The checkout step in the dashrate CI workflow is persisting Git
credentials unnecessarily, so harden the existing actions/checkout usage by
disabling credential persistence. Update the checkout configuration to set
persist-credentials to false since no later step needs the token, keeping the
workflow behavior unchanged while reducing exposure.

In `@example-apps/dashrate/src/catalog/resources.ts`:
- Around line 1-64: The RESOURCES module and findResource function need to be
reformatted to match the app’s Prettier contract. Update the RatedResource
interface, RESOURCES array, and findResource implementation in this file to use
the repository’s standard formatting (single quotes, 2-space indentation, and
trailing commas where applicable) so it is consistent with the rest of the
codebase.

In `@example-apps/dashrate/src/components/AppNotices.tsx`:
- Around line 1-19: Run the AppNotices component through the project’s Prettier
formatting so it matches the repository contract; the current JSX in AppNotices
uses double quotes and should be reformatted to the standard single-quote,
2-space indentation, and trailing-comma style. Keep the component behavior
unchanged and use the existing AppNotices export as the target for the
formatting-only update.

In `@example-apps/dashrate/src/components/HowItWorks.tsx`:
- Around line 1-39: Format the HowItWorks component to match the repository’s
Prettier contract: update the JSX in HowItWorks so string literals and
attributes follow the project’s single-quote style, 2-space indentation, and
trailing-comma rules. Keep the component behavior unchanged and use the existing
HowItWorks export as the target for the formatting pass.

In `@example-apps/dashrate/src/components/RecentReviews.tsx`:
- Around line 1-60: RecentReviews still isn’t formatted with the app’s Prettier
rules, specifically the import and string quoting style. Reformat the
RecentReviews component in
example-apps/dashrate/src/components/RecentReviews.tsx using the project
Prettier config so the imports and all string literals follow single-quote
conventions, with the existing 2-space indentation and trailing commas
preserved.

In `@example-apps/dashrate/src/components/ResourcesView.tsx`:
- Around line 1-231: The ResourcesView TSX file is not formatted according to
the app’s Prettier rules, so update it to match the configured style. Reformat
the imports and string literals in ResourcesView and its helper logic using the
Prettier config (single quotes, 2-space indentation, trailing commas) while
preserving behavior and keeping the existing symbols like ResourcesView and
handleSelectResource intact.

In `@example-apps/dashrate/src/components/ReviewForm.tsx`:
- Around line 1-117: The ReviewForm TSX file is not aligned with the app’s
Prettier formatting rules, specifically the quote style and any related
formatting conventions. Run ReviewForm through the project’s Prettier config and
ensure the exported ReviewForm component, its import statements, and all
JSX/string literals are formatted consistently with single quotes, 2-space
indentation, and trailing commas where applicable.

In `@example-apps/dashrate/src/components/ReviewHistory.tsx`:
- Around line 1-31: The ReviewHistory component needs formatting to match the
app’s Prettier rules, since it still uses double quotes and may not fully
conform to the required style. Run the ReviewHistory TSX through the project’s
Prettier config so the imports, strings, indentation, and trailing commas are
normalized consistently with the existing formatting standards.

In `@example-apps/dashrate/src/components/StarMeter.tsx`:
- Around line 1-31: The StarMeter component in StarMeter.tsx is not formatted
according to the app’s Prettier rules, so update the file to match the existing
formatting conventions used in the codebase. Run it through the project’s
Prettier config and ensure the `StarMeter` import, string literals, indentation,
and any trailing commas follow the required single-quote, 2-space,
trailing-comma style.

In `@example-apps/dashrate/src/dash/contract.ts`:
- Around line 84-90: The localStorage write path in saveContractId and
clearStoredContractId is unguarded, unlike loadStoredContractId, so wrap both
setItem and removeItem in the same try/catch style used by the read helper.
Update the contract.ts storage helpers to swallow or safely handle storage
errors, and ensure the saveContractId call site after sdk.contracts.publish does
not turn a successful publish into a failure because persistence to localStorage
was unavailable.

In `@example-apps/dashrate/src/hooks/useResourceRatings.ts`:
- Around line 138-160: Move the selected-resource “my review” lookup out of
loadResourceData so changing selectedResourceId does not recreate that callback
and rerun the aggregate refresh effect; keep the RESOURCES count/distribution
loading in loadResourceData keyed only by contractId/session, and add a separate
effect or callback for findMyReviewForResource, setMySelectedReview, setRating,
setHoverRating, and setReviewText that depends on selectedResourceId and
session. Update the useEffect that currently depends on loadResourceData to
avoid re-fetching all resource aggregates when only the selection changes.

In `@example-apps/dashrate/test/AppNotices.test.tsx`:
- Around line 1-41: Format the AppNotices test file with the repository’s
Prettier rules: convert the existing double-quoted imports and test strings to
single quotes, keep 2-space indentation, and preserve/add trailing commas where
Prettier would. Use the AppNotices test cases and the afterEach/render/describe
blocks as the targets for the formatting pass.

In `@example-apps/dashrate/test/MyReviewCard.test.tsx`:
- Around line 1-56: This test file needs to be reformatted to match the
repository Prettier contract. Update the Jest/Vitest test in
MyReviewCard.test.tsx so imports, strings, and other formatting follow the app’s
Prettier rules (single quotes, 2-space indentation, trailing commas) while
keeping the existing test logic and symbols like makeReview, MyReviewCard, and
vi.fn unchanged.

In `@example-apps/dashrate/test/MyReviewsView.test.tsx`:
- Around line 1-110: The test file formatting does not match the repository’s
Prettier contract, so update the MyReviewsView test to follow the app’s
configured style. Reformat the existing imports, strings, indentation, and
trailing commas in MyReviewsView.test.tsx to match Prettier output, keeping the
current test behavior unchanged.

In `@example-apps/dashrate/test/RecentReviews.test.tsx`:
- Around line 1-98: The RecentReviews test file is not matching the repository’s
Prettier style, mainly due to quote and formatting inconsistencies. Reformat the
test to the app’s standard Prettier output so imports, strings, and indentation
are consistent with the rest of the codebase. Keep the changes confined to the
RecentReviews test helpers and test cases, and preserve the existing behavior
while normalizing the formatting.

In `@example-apps/dashrate/test/ReviewHistory.test.tsx`:
- Around line 1-38: The ReviewHistory test file is not formatted according to
the app’s Prettier rules, specifically the imports and string literals still use
double quotes. Reformat the test to match the existing Prettier config and
project style, keeping the same behavior in ReviewHistory and the entries test
data while ensuring single-quote usage, 2-space indentation, and trailing commas
where applicable.

In `@example-apps/dashrate/test/ReviewRow.test.tsx`:
- Around line 1-45: This test file is not formatted according to the
repository’s Prettier rules. Reformat the ReviewRow test to match the app’s
standard style in the same file, keeping the existing assertions and structure
intact while converting the current double-quoted imports/strings and spacing to
the project’s Prettier output for this `ReviewRow` test.

In `@example-apps/dashrate/test/StarMeter.test.tsx`:
- Around line 1-55: The StarMeter test file needs to be formatted to match the
app’s Prettier rules, since it still uses double quotes instead of the required
single-quote style. Reformat the existing `StarMeter.test.tsx` content with
Prettier so imports, strings, indentation, and trailing commas conform to the
project’s standard, keeping the same test names and helpers such as `fill` and
`describe("StarMeter", ...)`.

In `@example-apps/dashrate/test/TopNav.test.tsx`:
- Around line 1-54: This TopNav test file is not matching the app’s Prettier
style, so reformat the TSX in TopNav.test.tsx using the project’s formatter.
Update the imports, string literals, and trailing commas to the single-quote
Prettier conventions used across the repo, while keeping the existing TopNav,
NAV, and vi-based test logic unchanged.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: a4cd5598-adca-46bf-b18b-bdd88558fede

📥 Commits

Reviewing files that changed from the base of the PR and between 56bc71e and f82021e.

⛔ Files ignored due to path filters (1)
  • example-apps/dashrate/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (75)
  • .github/workflows/dashrate-ci.yml
  • .gitignore
  • example-apps/README.md
  • example-apps/dashrate/.prettierignore
  • example-apps/dashrate/.prettierrc.json
  • example-apps/dashrate/CLAUDE.md
  • example-apps/dashrate/README.md
  • example-apps/dashrate/eslint.config.js
  • example-apps/dashrate/index.html
  • example-apps/dashrate/package.json
  • example-apps/dashrate/playwright.config.ts
  • example-apps/dashrate/src/App.tsx
  • example-apps/dashrate/src/catalog/resources.ts
  • example-apps/dashrate/src/components/AppNotices.tsx
  • example-apps/dashrate/src/components/HowItWorks.tsx
  • example-apps/dashrate/src/components/MyReviewCard.tsx
  • example-apps/dashrate/src/components/MyReviewsView.tsx
  • example-apps/dashrate/src/components/RecentReviews.tsx
  • example-apps/dashrate/src/components/ResourcesView.tsx
  • example-apps/dashrate/src/components/ReviewForm.tsx
  • example-apps/dashrate/src/components/ReviewHistory.tsx
  • example-apps/dashrate/src/components/ReviewRow.tsx
  • example-apps/dashrate/src/components/SettingsView.tsx
  • example-apps/dashrate/src/components/StarMeter.tsx
  • example-apps/dashrate/src/components/TopNav.tsx
  • example-apps/dashrate/src/dash/client.ts
  • example-apps/dashrate/src/dash/contract.ts
  • example-apps/dashrate/src/dash/history.ts
  • example-apps/dashrate/src/dash/keyManager.ts
  • example-apps/dashrate/src/dash/queries.ts
  • example-apps/dashrate/src/dash/resolveDpnsName.ts
  • example-apps/dashrate/src/dash/review.ts
  • example-apps/dashrate/src/dash/sdkCore.ts
  • example-apps/dashrate/src/dash/sdkModule.ts
  • example-apps/dashrate/src/dash/types.ts
  • example-apps/dashrate/src/hooks/useDpnsNames.ts
  • example-apps/dashrate/src/hooks/useMyReviews.ts
  • example-apps/dashrate/src/hooks/useResourceRatings.ts
  • example-apps/dashrate/src/lib/format.ts
  • example-apps/dashrate/src/lib/logger.ts
  • example-apps/dashrate/src/lib/ratings.ts
  • example-apps/dashrate/src/main.tsx
  • example-apps/dashrate/src/session/types.ts
  • example-apps/dashrate/src/styles.css
  • example-apps/dashrate/src/vite-env.d.ts
  • example-apps/dashrate/test/App.test.tsx
  • example-apps/dashrate/test/AppNotices.test.tsx
  • example-apps/dashrate/test/MyReviewCard.test.tsx
  • example-apps/dashrate/test/MyReviewsView.test.tsx
  • example-apps/dashrate/test/RecentReviews.test.tsx
  • example-apps/dashrate/test/ResourcesView.test.tsx
  • example-apps/dashrate/test/ReviewForm.test.tsx
  • example-apps/dashrate/test/ReviewHistory.test.tsx
  • example-apps/dashrate/test/ReviewRow.test.tsx
  • example-apps/dashrate/test/SettingsView.test.tsx
  • example-apps/dashrate/test/StarMeter.test.tsx
  • example-apps/dashrate/test/TopNav.test.tsx
  • example-apps/dashrate/test/contract.test.ts
  • example-apps/dashrate/test/e2e/fixtures.ts
  • example-apps/dashrate/test/e2e/settings.spec.ts
  • example-apps/dashrate/test/e2e/smoke.spec.ts
  • example-apps/dashrate/test/format.test.ts
  • example-apps/dashrate/test/history.test.ts
  • example-apps/dashrate/test/logger.test.ts
  • example-apps/dashrate/test/queries.test.ts
  • example-apps/dashrate/test/resolveDpnsName.test.ts
  • example-apps/dashrate/test/resources.test.ts
  • example-apps/dashrate/test/review.test.ts
  • example-apps/dashrate/test/useDpnsNames.test.tsx
  • example-apps/dashrate/test/useMyReviews.test.tsx
  • example-apps/dashrate/test/useResourceRatings.test.tsx
  • example-apps/dashrate/tsconfig.app.json
  • example-apps/dashrate/tsconfig.json
  • example-apps/dashrate/tsconfig.node.json
  • example-apps/dashrate/vite.config.ts

Comment on lines +1 to +4
{
"printWidth": 80,
"trailingComma": "all"
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Enable single quotes in the app-local Prettier config.

npm run format in this workspace will currently keep emitting double-quoted JS/TS output, which breaks the repo formatting contract for example-apps/dashrate.

♻️ Proposed fix
 {
   "printWidth": 80,
+  "singleQuote": true,
   "trailingComma": "all"
 }

As per coding guidelines, **/*.{js,mjs,ts,tsx,json}: Prettier formatting must use single quotes, 2-space indentation, and trailing commas.

📝 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
{
"printWidth": 80,
"trailingComma": "all"
}
{
"printWidth": 80,
"singleQuote": true,
"trailingComma": "all"
}
🤖 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 `@example-apps/dashrate/.prettierrc.json` around lines 1 - 4, The app-local
Prettier config is missing the single-quote setting, so formatting in this
workspace still emits double-quoted JS/TS output. Update the Prettier
configuration in the dashrate app’s .prettierrc.json to enable single quotes
alongside the existing printWidth and trailingComma settings, so npm run format
follows the repo’s formatting contract.

Source: Coding guidelines

Comment on lines +11 to +15
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2022,
globals: globals.browser,
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Split browser and Node globals in the flat config.

files: ['**/*.{ts,tsx}'] also matches playwright.config.ts, but this block only exposes browser globals. That makes process.env.CI in example-apps/dashrate/playwright.config.ts a lint error unless you add a Node-scoped override or narrow this browser block to app/test sources.

♻️ Proposed fix
 export default tseslint.config(
   { ignores: ['dist', 'coverage', 'playwright-report', 'test-results'] },
   {
     extends: [js.configs.recommended, ...tseslint.configs.recommended],
-    files: ['**/*.{ts,tsx}'],
+    files: ['src/**/*.{ts,tsx}', 'test/**/*.{ts,tsx}'],
     languageOptions: {
       ecmaVersion: 2022,
       globals: globals.browser,
     },
     plugins: {
       'react-hooks': reactHooks,
       'react-refresh': reactRefresh,
     },
     rules: {
       ...reactHooks.configs.recommended.rules,
       'react-refresh/only-export-components': [
         'warn',
         { allowConstantExport: true },
       ],
     },
   },
+  {
+    files: ['*.config.ts'],
+    languageOptions: {
+      ecmaVersion: 2022,
+      globals: globals.node,
+    },
+  },
 );
📝 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
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2022,
globals: globals.browser,
},
export default tseslint.config(
{ ignores: ['dist', 'coverage', 'playwright-report', 'test-results'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['src/**/*.{ts,tsx}', 'test/**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2022,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
{
files: ['*.config.ts'],
languageOptions: {
ecmaVersion: 2022,
globals: globals.node,
},
},
);
🤖 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 `@example-apps/dashrate/eslint.config.js` around lines 11 - 15, The flat ESLint
config block for `files: ["**/*.{ts,tsx}"]` is too broad and applies browser
globals to `playwright.config.ts`, causing Node-only references like
`process.env.CI` to fail linting. Update the config in `eslint.config.js` by
either narrowing this browser-scoped block to only app/test source files or
adding a separate Node-scoped override for `playwright.config.ts`, keeping the
browser globals tied to the correct sources and using the existing flat-config
structure.

Comment on lines +50 to +56
- the total review count uses the standalone `resourceId` index (`countable: "countable"`)
- the rating distribution and the `rating == N` filter use the compound `resourceId + rating` index
(`countable: "countable"` plus `rangeCountable: true`)

Neither aggregate index uses `summable`: the count/sum/average shown per resource is computed in JS
from the grouped distribution count, so a single grouped `count` query backs both the histogram and
the average.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Clarify which aggregate values come from the grouped count.

Lines 50-52 say the total review count uses the standalone resourceId count index, but Lines 54-56 then say the displayed count/sum/average all come from the grouped distribution query. Those two descriptions can't both be true, so the README is currently teaching the wrong query plan.

✏️ Suggested wording
-Neither aggregate index uses `summable`: the count/sum/average shown per resource is computed in JS
-from the grouped distribution count, so a single grouped `count` query backs both the histogram and
-the average.
+Neither aggregate index uses `summable`: the displayed average is computed in JS from the grouped
+distribution count, while the total review count comes from the standalone `resourceId` count
+index.
📝 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
- the total review count uses the standalone `resourceId` index (`countable: "countable"`)
- the rating distribution and the `rating == N` filter use the compound `resourceId + rating` index
(`countable: "countable"` plus `rangeCountable: true`)
Neither aggregate index uses `summable`: the count/sum/average shown per resource is computed in JS
from the grouped distribution count, so a single grouped `count` query backs both the histogram and
the average.
- the total review count uses the standalone `resourceId` index (`countable: "countable"`)
- the rating distribution and the `rating == N` filter use the compound `resourceId + rating` index
(`countable: "countable"` plus `rangeCountable: true`)
Neither aggregate index uses `summable`: the displayed average is computed in JS from the grouped
distribution count, while the total review count comes from the standalone `resourceId` count
index.
🤖 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 `@example-apps/dashrate/README.md` around lines 50 - 56, The README description
of aggregate queries is inconsistent about where the total review count comes
from; update the wording in the dashrate README to make the query plan
consistent. Use the existing aggregate/index terms already mentioned there
(`resourceId`, `rating`, `countable`, `rangeCountable`, `summable`) and clarify
whether the standalone count index is only for total counts or whether the
grouped count query is the single source for histogram, sum, and average so the
reader sees one coherent explanation.

}) {
return (
<>
{status && <p className="status">{status}</p>}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Announce status changes to assistive tech.

The status message is runtime feedback, but it's rendered as a plain <p>, so screen readers will usually miss updates. Add role="status" or an aria-live region 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 `@example-apps/dashrate/src/components/AppNotices.tsx` at line 10, The status
message in AppNotices is rendered as a plain paragraph, so assistive tech may
not announce updates. Update the status rendering in AppNotices to use an
accessible live region, such as adding role="status" or an aria-live attribute
to the existing status element, so changes are announced when status updates at
runtime.

Comment on lines +12 to +15
<p className="notice">
No default contract is bundled yet. Sign in and register a DashRate
contract, or paste an existing contract ID in Settings.
</p>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Update the no-contract notice to match the shipped default contract.

The PR objective says DashRate ships a default testnet contract ID, so this message is misleading whenever hasContract is false. Reword it to describe a missing or cleared active contract configuration instead of saying none is bundled.

🤖 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 `@example-apps/dashrate/src/components/AppNotices.tsx` around lines 12 - 15,
Update the notice in AppNotices so it no longer says “No default contract is
bundled yet,” since DashRate now ships a default testnet contract ID. Reword the
message to describe a missing or cleared active contract configuration instead,
while keeping the guidance about signing in, registering a contract, or pasting
an existing contract ID in Settings. Use the notice markup in AppNotices as the
target for the text change.

Comment on lines +36 to +37
const historyOpen = history.length > 0;
const displayRating = hoverRating ?? rating ?? 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

The history toggle never gets a real “close” path.

historyOpen is derived only from history.length, but the button always calls onLoadHistory. Once history is loaded, the label flips to “Hide previous versions” even though this component still invokes the load callback and has no explicit way to collapse the section. Add an explicit expanded state/callback, or make the prop contract unambiguously load-only.

Also applies to: 99-112

🤖 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 `@example-apps/dashrate/src/components/ReviewForm.tsx` around lines 36 - 37,
The history toggle logic in ReviewForm is load-only right now, but the UI label
and state imply a real open/close interaction. Update the ReviewForm prop
contract and toggle handling so the control has an explicit expanded/collapse
state or clearly remains load-only, and make the button behavior match the
displayed label instead of always calling onLoadHistory. Use the existing
ReviewForm component and the historyOpen/displayRating logic as the place to
wire in the new state or callback.

Comment on lines +10 to +12
const fillPercent = value === null ? 0 : Math.max(0, Math.min(5, value)) * 20;
const label =
value === null ? "No rating yet" : `${formatAverage(value)} out of 5`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clamp the spoken label to the same range as the fill.

fillPercent is bounded to 0–5, but aria-label still uses the raw value. For inputs like 7 or -2, the UI shows a clamped meter while assistive tech announces an impossible rating. Reuse the clamped value for both paths.

🤖 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 `@example-apps/dashrate/src/components/StarMeter.tsx` around lines 10 - 12, The
spoken label in StarMeter is using the raw rating instead of the same clamped
value used for fillPercent, so update the label logic to reuse the bounded 0–5
value for both the visual meter and the aria-label. Fix this in StarMeter by
deriving a single clamped rating from value and using it for both the percentage
fill and the accessible text, while still keeping the null case as the “No
rating yet” label.

Comment on lines +16 to +21
try {
const result = await sdk.dpns.username(identityId);
if (typeof result !== "string" || result.length === 0) return null;
return result.endsWith(".dash") ? result.slice(0, -5) : result;
} catch {
return null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Don’t collapse lookup failures into the same null used for “no DPNS name”.

Lines 16-21 make transient SDK failures indistinguishable from a confirmed miss. useDpnsNames then caches that null and stops retrying the same identity, so a temporary failure can permanently degrade display names until reload. Please keep null for true “no name” results and surface lookup failures separately so the hook can retry them.

🤖 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 `@example-apps/dashrate/src/dash/resolveDpnsName.ts` around lines 16 - 21, The
resolveDpnsName helper currently returns null for both a real “no DPNS name”
result and for SDK lookup failures, which causes useDpnsNames to cache transient
errors as permanent misses. Update resolveDpnsName to distinguish a successful
empty result from an exception thrown by sdk.dpns.username, and return or
surface failures in a separate way so useDpnsNames can retry rather than caching
null; keep the existing normalization logic in resolveDpnsName for valid string
results.

Comment on lines +263 to +266
.sr-only {
border: 0;
clip: rect(0 0 0 0);
clip-path: inset(50%);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Remove the deprecated clip property from .sr-only.

Stylelint is already flagging Line 265. Keeping clip here leaves the stylesheet red even though clip-path and the rest of the visually-hidden rules already cover the behavior.

Suggested fix
 .sr-only {
   border: 0;
-  clip: rect(0 0 0 0);
   clip-path: inset(50%);
   height: 1px;
   margin: -1px;
📝 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
.sr-only {
border: 0;
clip: rect(0 0 0 0);
clip-path: inset(50%);
.sr-only {
border: 0;
clip-path: inset(50%);
🧰 Tools
🪛 Stylelint (17.13.0)

[error] 265-265: Deprecated property "clip" (property-no-deprecated)

(property-no-deprecated)

🤖 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 `@example-apps/dashrate/src/styles.css` around lines 263 - 266, The .sr-only
accessibility helper still uses the deprecated clip property, which Stylelint
flags. Update the .sr-only rule in the stylesheet to remove clip and keep the
existing clip-path-based visually hidden behavior, preserving the rest of the
rules unchanged.

Source: Linters/SAST tools

Comment on lines +114 to +116
expect(screen.getByRole("spinbutton")).toBeTruthy(); // identity index input
expect(screen.getByText("Current:")).toBeTruthy();
fireEvent.click(screen.getByRole("button", { name: /^clear$/i }));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant test and component with line numbers
git ls-files example-apps/dashrate/test/SettingsView.test.tsx example-apps/dashrate/src/components/SettingsView.tsx
printf '\n--- TEST ---\n'
cat -n example-apps/dashrate/test/SettingsView.test.tsx | sed -n '1,220p'
printf '\n--- COMPONENT ---\n'
cat -n example-apps/dashrate/src/components/SettingsView.tsx | sed -n '1,260p'

Repository: dashpay/platform-tutorials

Length of output: 11966


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for the exact text query and related assertions in tests
rg -n 'getByText\("Current:"|Current:|spinbutton|clear' example-apps/dashrate/test/SettingsView.test.tsx example-apps/dashrate/src/components/SettingsView.tsx

Repository: dashpay/platform-tutorials

Length of output: 757


Use a matcher that includes the rendered contract ID. getByText("Current:") won’t match the <p> once the <code> value is rendered, so this assertion can fail even when the UI is correct.

Suggested fix
-    expect(screen.getByText("Current:")).toBeTruthy();
+    expect(screen.getByText(/Current:\s*c1/i)).toBeTruthy();
📝 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
expect(screen.getByRole("spinbutton")).toBeTruthy(); // identity index input
expect(screen.getByText("Current:")).toBeTruthy();
fireEvent.click(screen.getByRole("button", { name: /^clear$/i }));
expect(screen.getByRole("spinbutton")).toBeTruthy(); // identity index input
expect(screen.getByText(/Current:\s*c1/i)).toBeTruthy();
fireEvent.click(screen.getByRole("button", { name: /^clear$/i }));
🤖 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 `@example-apps/dashrate/test/SettingsView.test.tsx` around lines 114 - 116, The
test assertion around the rendered current value is too generic and can break
once the contract ID is displayed inside the same paragraph. Update the
expectation in SettingsView.test.tsx to target the full rendered text for the
“Current:” label together with the contract ID, using the existing screen query
near the clear-button interaction so the assertion matches the actual
SettingsView output.

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.

1 participant