Skip to content

feat: add DashProof Lab example app with Pages deploy#70

Merged
thephez merged 29 commits intomainfrom
feat/example-app-dashproof
Apr 29, 2026
Merged

feat: add DashProof Lab example app with Pages deploy#70
thephez merged 29 commits intomainfrom
feat/example-app-dashproof

Conversation

@thephez
Copy link
Copy Markdown
Collaborator

@thephez thephez commented Apr 29, 2026

Summary

  • Add DashProof Lab (example-apps/dashproof-lab/) — a React + TypeScript + Vite example app that hashes files in the browser and anchors the SHA-256 digest on Dash Platform testnet. Includes Create / Verify / History / How-it-works flows, a bundled default contract ID for read-only access, light/dark theme toggle honoring prefers-color-scheme, in-app Settings to register or paste a contract, copy-to-clipboard affordances, and a "Starter files" panel with three bundled fixtures.
  • Add unit/component coverage with Vitest + Testing Library and an end-to-end Playwright suite in e2e/ covering anchor / verify / history / copy / theme flows. Anchor-write specs run serially; read-only specs run in parallel; auth-gated specs self-skip when PLATFORM_MNEMONIC is unset.
  • Add a multi-app GitHub Pages deploy workflow (deploy-example-apps.yml) that auto-discovers any example-apps/* with a build script, runs its tests + build per matrix slot, and deploys passing apps to <owner>.github.io/<repo>/<app>/. A failing app is skipped from deploy without blocking the others. Includes a generated landing page (build-landing-page.mjs) listing only successfully deployed apps.
image

Summary by CodeRabbit

  • New Features

    • Added DashProof Lab app: create/verify anchors, local SHA‑256 hashing, copy-to-clipboard, history, theme toggle, and starter files.
    • Added automated build & GitHub Pages deployment producing a combined example-apps landing page.
  • Documentation

    • Added in-app “How it works”, READMEs, and a developer-facing guidance document for DashProof Lab.
  • Tests

    • Added extensive unit, integration, and E2E test coverage for the new app.

thephez and others added 26 commits April 29, 2026 12:40
Introduce a new Dash Platform proof-of-existence tutorial app built with React, TypeScript, and Vite. The app hashes files locally in the browser, anchors SHA-256 proofs on Dash Platform, verifies files by hash, and
supports history views by owner and chain ID.

This initial version includes the proof contract schema, contract registration flow, read-only verification and history access, starter fixture files, and component and utility tests for the main user flows.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rtions

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Auto-discovers any example-apps/<name>/ with a build script and deploys
each under /<repo>/<name>/ in a single combined site, with a generated
index page. Adding a new app needs no workflow edits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ships a deployed testnet contract ID so read-only verify and history
flows work on a fresh install without manual Settings configuration.
Removes the contract-required notices that are no longer reachable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
In-app developer guide that explains the proof model, maps each app
action to its src/dash/ file and SDK method, and gives a recommended
reading order. Renames the Anchor/Verify tabs to "Create proof" /
"Verify proof", auto-closes the login modal on success, and lists the
new app in example-apps/README.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the plain index.html the GitHub Pages workflow emitted with a themed app chooser generated by .github/scripts/build-landing-page.mjs:
dark Dash-blue palette, Inter, card grid sourced from each app's package.json displayName/description. Discover job now publishes per-app metadata; deploy job calls the new Node script. Both example apps gain a centered "View on GitHub" footer link pointing at the canonical dashpay/platform-tutorials repo.

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

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

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

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

Add Vitest tests for lib/* utilities, dash/queries read helpers, and the
CopyButton, Tabs, HowItWorks, IdentityCard, ExampleFilesPanel, and
LoginModal components. Wire a test:coverage script using @vitest/coverage-v8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add test/contract.test.ts for refreshContractCache, registerContract, and
ensureContract. Add test/logger.test.ts for errorMessage. Backfill
createAnchor entryHash/previousId validation and a toTimestamp edge case.
Lifts src/dash coverage from 86% to 99%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Covers verify, history (chain lookup), theme toggle, copy button, and
auth-gated anchor submit against live testnet. Includes shared fixtures,
tsconfig wiring, ESLint Node-globals override, and gitignore for
playwright-report/test-results.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds chain-empty notice, timeline ordering, chain-header copy/toast,
Verify→History deep link, and authed My-anchors paths (tab state,
summary stats, explorer link, tab switching). Introduces shared
loginViaModal and clickNav helpers in fixtures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Enables fullyParallel and Playwright's default worker count globally.
Marks the anchor describe as serial since concurrent writes against a
shared testnet identity would race the nonce.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- copy.spec: recompute SHA-256 from the random buffer in Node and
  compare exactly to the clipboard, instead of just shape-matching
  64 hex chars.
- verify.spec: read the rendered hash container and assert it equals
  the known fixture digest, not just that the Copy hash button enables.
- history.spec: scope the chain-header copy button to its containing
  section so the locator can't drift onto an unrelated copy control.
- history.spec: remove the timeline-ordering test; it was vacuously
  green against single-anchor fixture chains.

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

coderabbitai Bot commented Apr 29, 2026

Warning

Rate limit exceeded

@thephez has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 52 minutes and 1 second before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d0d9e5ac-7a31-4094-b233-cf24553a55a9

📥 Commits

Reviewing files that changed from the base of the PR and between 2dbf9c5 and ae75d1d.

📒 Files selected for processing (3)
  • example-apps/dashproof-lab/CLAUDE.md
  • example-apps/dashproof-lab/src/dash/contract.ts
  • example-apps/dashproof-lab/test/contract.test.ts
📝 Walkthrough

Walkthrough

Adds a GitHub Pages landing-page generator and deployment workflow; introduces a new DashProof Lab example app with React/Vite UI, Dash SDK integration (contract, anchor creation, queries, key management), session state, utilities, E2E and unit tests, TypeScript configs, and supporting assets.

Changes

Cohort / File(s) Summary
GitHub Pages infra
\.github/scripts/build-landing-page.mjs, \.github/workflows/deploy-example-apps.yml
New landing-page generator script and a manual GitHub Actions workflow that discovers example apps, builds/tests them, uploads per-app artifacts, assembles a combined _site, generates index.html from app metadata, and deploys to GitHub Pages.
Example app metadata & docs
example-apps/README.md, example-apps/dashmint-lab/package.json, example-apps/dashmint-lab/src/components/AppShell.tsx
Adds DashProof entry and package metadata; AppShell footer link updated in dashmint-lab.
Project configs & tooling
example-apps/dashproof-lab/{package.json,index.html,vite.config.ts,tsconfig*.json,playwright.config.ts,eslint.config.js,.gitignore,.prettierignore,.prettierrc.json}
New project manifests, Vite, TypeScript project refs, Playwright/E2E config, ESLint, Prettier and ignore/config files for dashproof-lab.
App entry, styles & public assets
example-apps/dashproof-lab/src/main.tsx, example-apps/dashproof-lab/src/styles/globals.css, example-apps/dashproof-lab/public/example-files/*
App bootstrap applying initial theme, global CSS with theme variables and UI styles, and public fixtures (proof fixture, release-bundle JSON).
UI components & primitives
example-apps/dashproof-lab/src/components/...
New UI: App, AppShell, Tabs, AnchorForm, VerifyPanel, HistoryPanel, LoginModal, IdentityCard, Modal, CopyButton, ExampleFilesPanel/Modal, OperationResultNotice, NavButton, ThemeToggle, and related helpers.
Session & React integration
example-apps/dashproof-lab/src/session/{SessionContext.tsx,useSession.ts}
Session provider and hook managing connectivity, authentication, mnemonic login, read-only mode, contract id persistence, and session actions.
Dash SDK adapters & contract logic
example-apps/dashproof-lab/src/dash/{types,client,keyManager,contract,createAnchor,queries,logger}.ts
Typed SDK abstractions, key manager re-export, contract schema/registration/refresh helpers, anchor creation with validation, query helpers (find/list anchors), and logging/error utilities.
Libraries & utilities
example-apps/dashproof-lab/src/lib/{hash,chainId,format}.ts, example-apps/dashproof-lab/src/hooks/useTheme.ts, example-apps/dashproof-lab/src/data/exampleFiles.ts
Hashing and byte utilities, chain-id suggestion, formatting helpers, theme store/hook with persistence/sync, and example fixture metadata.
E2E tests & fixtures
example-apps/dashproof-lab/e2e/{fixtures.ts,*.spec.ts}
Playwright fixtures and suites for hashing, copy, anchor creation, verify, history, and theme behaviors (mnemonic-driven login conditional).
Unit / integration tests
example-apps/dashproof-lab/test/**/*.{test.ts,tsx}
Comprehensive Vitest/JSDOM and Node tests covering components, hooks, dash helpers, contract logic, hashing, formatting, and regressions.
Large feature components
example-apps/dashproof-lab/src/components/{HistoryPanel.tsx,VerifyPanel.tsx,AnchorForm.tsx,LoginModal.tsx}
Significant new components with complex logic (async queries, cancellation guards, request-token patterns, session gating, file hashing, clipboard behavior, and contract interactions) — review attention advised.
Contract/query heavy logic
example-apps/dashproof-lab/src/dash/{contract.ts,queries.ts}
New contract registration/refresh and query normalization logic with base64/byte coercion and timestamp coercion — careful review recommended.
Tests exercising integration surfaces
example-apps/dashproof-lab/test/{contract.test.ts,dash.test.ts,queries.test.ts}
Extensive tests mocking SDK behaviors and validating contract lifecycle, anchor creation validations, query parameter shapes, and normalization edge cases.

Sequence Diagram(s)

sequenceDiagram
  participant User as Browser User
  participant UI as DashProof UI
  participant Session as SessionProvider
  participant KM as IdentityKeyManager
  participant SDK as Dash SDK
  participant Network as Dash Testnet

  rect rgba(200,230,255,0.5)
  User->>UI: select file & submit anchor
  UI->>UI: compute SHA‑256 (hashFile)
  UI->>Session: request createAnchor(entryHash, chainId, meta)
  Session->>KM: getAuth() → identityKey & signer
  Session->>SDK: ensure connected / createClient
  Session->>SDK: documents.create({ document, identityKey, signer })
  SDK->>Network: submit document
  Network-->>SDK: confirmation / document id
  SDK-->>Session: success
  Session-->>UI: anchored confirmation
  UI-->>User: show success notice
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 I nibble bytes and spin a thread,
New lab and pages hop ahead,
Hashes hum and contracts sing,
Tests and builds prepare to spring—
A carrot-flavored deploy delight,
Examples land and take their flight! 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.48% 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 PR title "feat: add DashProof Lab example app with Pages deploy" directly and clearly describes the main changes in the changeset, which introduces a new example app (DashProof Lab) and adds GitHub Pages deployment infrastructure.
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
  • Commit unit tests in branch feat/example-app-dashproof

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
Review rate limit: 0/1 reviews remaining, refill in 52 minutes and 1 second.

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 18

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
example-apps/dashproof-lab/test/HowItWorks.test.tsx (1)

1-94: ⚠️ Potential issue | 🟠 Major

Move this test to be co-located with HowItWorks.tsx.

This test currently lives in example-apps/dashproof-lab/test/, but the repo rule requires unit tests to sit next to their subject file.

As per coding guidelines: "example-apps/dashproof-lab/**/*.test.{ts,tsx}: Co-locate unit tests with their subject files (e.g. AnchorForm.test.tsx next to AnchorForm.tsx, SessionContext.test.tsx next to SessionContext.tsx)"

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

In `@example-apps/dashproof-lab/test/HowItWorks.test.tsx` around lines 1 - 94,
This test file for the HowItWorks component must be moved to the same directory
as HowItWorks.tsx; relocate the test file next to the HowItWorks component,
update its import so it imports HowItWorks via a relative path from the same
directory (e.g., import HowItWorks from "./HowItWorks" or equivalent), remove
the old test copy, and ensure the test runner's file-globting still picks up the
new co-located test (no other test changes needed).
example-apps/dashproof-lab/test/logger.test.ts (1)

1-47: 🛠️ Refactor suggestion | 🟠 Major

Move this test to be co-located with src/dash/logger.ts.

This suite is currently in test/ but the repo rule requires unit tests to live next to their subject file.

As per coding guidelines, "example-apps/dashproof-lab/**/*.test.{ts,tsx}: Co-locate unit tests with their subject files (e.g. AnchorForm.test.tsx next to AnchorForm.tsx, SessionContext.test.tsx next to SessionContext.tsx)".

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

In `@example-apps/dashproof-lab/test/logger.test.ts` around lines 1 - 47, The test
suite for errorMessage should be moved from the test/ directory to live next to
its implementation in the same folder as src/dash/logger.ts; relocate the file
so it imports errorMessage from "./logger" (or relative path matching logger.ts)
and keep the describe/it blocks unchanged, ensuring the test filename follows
the convention logger.test.ts and any import paths updated accordingly.
example-apps/dashproof-lab/test/Tabs.test.tsx (1)

1-59: ⚠️ Potential issue | 🟠 Major

Move this test next to Tabs.tsx to satisfy the test co-location rule.

This suite should be colocated with its subject (for example: src/components/Tabs.test.tsx) instead of the top-level test/ directory.

As per coding guidelines: example-apps/dashproof-lab/**/*.test.{ts,tsx}: Co-locate unit tests with their subject files.

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

In `@example-apps/dashproof-lab/test/Tabs.test.tsx` around lines 1 - 59, The Tabs
test file should be moved from test/Tabs.test.tsx into the same directory as the
component (e.g. next to src/components/Tabs.tsx as src/components/Tabs.test.tsx)
to satisfy the co-location rule; after moving, update any relative imports if
required (the test imports Tabs from "../src/components/Tabs" — change that to a
local import like "./Tabs" or the correct relative path) and ensure the vitest
environment directive and test imports remain correct so the suite continues to
run.
🟡 Minor comments (7)
example-apps/dashproof-lab/src/components/Modal.tsx-49-53 (1)

49-53: ⚠️ Potential issue | 🟡 Minor

Set explicit button type on modal close control.

On Line 49, missing type="button" can trigger accidental form submits in embedded contexts.

Proposed fix
           <button
+            type="button"
             onClick={onClose}
             className="text-ink-4 transition hover:text-ink"
             aria-label="Close"
           >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@example-apps/dashproof-lab/src/components/Modal.tsx` around lines 49 - 53,
The modal's close control button in Modal.tsx lacks an explicit type which can
cause accidental form submissions; update the button element that calls onClose
(the close control in the Modal component) to include type="button" so it does
not act as a submit button in embedded forms, ensuring the onClose handler
remains unchanged.
example-apps/dashproof-lab/tsconfig.json-1-8 (1)

1-8: ⚠️ Potential issue | 🟡 Minor

Add strict: true and use Node16 module target in referenced TypeScript configs.

The root config references are correct, but the referenced TypeScript configurations need updates:

  • All three configs (tsconfig.app.json, tsconfig.node.json, tsconfig.e2e.json) currently use "module": "esnext" instead of Node16 module targeting
  • None have "strict": true enabled (only individual strict rules like noUnusedLocals: true)
  • These should be updated to match TypeScript best practices for strict type-checking
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@example-apps/dashproof-lab/tsconfig.json` around lines 1 - 8, Update the
three referenced TypeScript configs (tsconfig.app.json, tsconfig.node.json,
tsconfig.e2e.json) to enable full strict checking and use Node16 module
resolution: set "strict": true in each config and change "module" from "esnext"
to "Node16" (or "node16" casing used in your project) so they target Node16
module semantics; preserve or remove individual strict-related flags (like
noUnusedLocals) as desired since "strict": true enables the full strict set.
example-apps/dashproof-lab/src/main.tsx-3-8 (1)

3-8: ⚠️ Potential issue | 🟡 Minor

Prevent first-paint theme flash for light mode users.

Line 3 loads theme-dependent CSS before Line 8 sets data-theme, so users can briefly see dark defaults before light theme is applied. Move initial theme assignment to an inline script in index.html head (before CSS) to avoid flicker.

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

In `@example-apps/dashproof-lab/src/main.tsx` around lines 3 - 8, The initial
theme is being applied too late (applyTheme(getInitialTheme()) in main.tsx),
causing a flash; remove that runtime call and instead add an inline script in
index.html head (before any CSS link) that runs the same logic as
getInitialTheme and sets document.documentElement.dataset.theme (or equivalent
DOM attribute used by applyTheme) so the correct data-theme is present before
CSS loads; keep the getInitialTheme/applyTheme implementations for client code
but delete the early call in main.tsx and ensure the inline script mirrors
getInitialTheme behavior and sets the same attribute name used by applyTheme.
example-apps/dashproof-lab/src/components/AppShell.tsx-149-154 (1)

149-154: ⚠️ Potential issue | 🟡 Minor

Make the menu button label reflect open/closed state.

At Line 152, aria-label is always “Open menu”, even when the drawer is open. This gives incorrect SR feedback.

Suggested patch
-            aria-label="Open menu"
+            aria-label={drawerOpen ? 'Close menu' : 'Open menu'}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@example-apps/dashproof-lab/src/components/AppShell.tsx` around lines 149 -
154, The menu button currently always uses aria-label="Open menu" which
misreports state; update the button in AppShell (the element using onClick={()
=> setDrawerOpen(!drawerOpen)} and aria-expanded={drawerOpen}) to compute the
label from drawerOpen (e.g., "Open menu" when false, "Close menu" when true) so
screen readers receive correct feedback and the label changes in sync with
setDrawerOpen/drawerOpen.
example-apps/dashproof-lab/src/components/HistoryPanel.tsx-165-178 (1)

165-178: ⚠️ Potential issue | 🟡 Minor

Grouping assumes consecutive chainIds, but anchors are sorted by createdAt.

The groupedAnchors reducer groups consecutive anchors with the same chainId. However, listAnchorsByOwner returns results sorted by createdAt descending (per context snippet 2), so anchors from the same chain may not be consecutive if interleaved with other chains. This could result in the same chain appearing in multiple groups.

Consider pre-sorting by chainId before grouping, or using a Map-based grouping approach.

🔧 Proposed fix using Map-based grouping
   const groupedAnchors = useMemo(() => {
-    return anchors.reduce<Array<{ chainId: string; items: AnchorRecord[] }>>(
-      (groups, anchor) => {
-        const existing = groups.at(-1);
-        if (existing?.chainId === anchor.chainId) {
-          existing.items.push(anchor);
-          return groups;
-        }
-        groups.push({ chainId: anchor.chainId, items: [anchor] });
-        return groups;
-      },
-      [],
-    );
+    const map = new Map<string, AnchorRecord[]>();
+    for (const anchor of anchors) {
+      const existing = map.get(anchor.chainId);
+      if (existing) {
+        existing.push(anchor);
+      } else {
+        map.set(anchor.chainId, [anchor]);
+      }
+    }
+    return Array.from(map, ([chainId, items]) => ({ chainId, items }));
   }, [anchors]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@example-apps/dashproof-lab/src/components/HistoryPanel.tsx` around lines 165
- 178, The reducer in HistoryPanel that computes groupedAnchors assumes anchors
with the same chainId are consecutive (it checks existing = groups.at(-1)), but
anchors are sorted by createdAt so same chainIds can be split across groups; fix
by replacing the sequential grouping with a Map-based grouping keyed by
anchor.chainId (or pre-sort anchors by chainId) so each chainId maps to a single
group, then convert that Map to the desired Array<{ chainId: string; items:
AnchorRecord[] }>; update references to groupedAnchors accordingly.
example-apps/dashproof-lab/src/session/SessionContext.tsx-88-112 (1)

88-112: ⚠️ Potential issue | 🟡 Minor

Align SDK type annotations with external SDK types instead of using as never cast.

The cast sdk: connected as never on line 91 masks a type annotation mismatch. The local DashSdk interface differs from ConnectedDashClientLike (which IdentityKeyManager.create() actually expects and createClient() returns). Replace the local DashSdk type on line 47 with ConnectedDashClientLike from setupDashClient-core, or ensure the local interface matches the external type definition. This removes the need for the cast and improves type safety.

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

In `@example-apps/dashproof-lab/src/session/SessionContext.tsx` around lines 88 -
112, The code is using a unsafe cast `sdk: connected as never` when calling
IdentityKeyManager.create; replace the local DashSdk type with the correct
external type (ConnectedDashClientLike from setupDashClient-core) or update the
local DashSdk interface to exactly match ConnectedDashClientLike, then import
ConnectedDashClientLike and change the parameter/variable types (e.g., the `sdk`
state/prop and the `connect()` return) so you can pass `connected` directly into
IdentityKeyManager.create without the `as never` cast; remove the cast and
ensure IdentityKeyManager.create, connect, and any createClient usage all use
the same ConnectedDashClientLike type.
example-apps/dashproof-lab/e2e/fixtures.ts-98-112 (1)

98-112: ⚠️ Potential issue | 🟡 Minor

Trim the mnemonic before proceeding.

HAS_MNEMONIC treats whitespace-only env values as missing, but this helper does not. A value like ' ' gets filled into the form, leaves submit disabled, and then times out on the authenticated assertion.

💡 Suggested fix
 export async function loginViaModal(page: Page) {
-  const mnemonic = process.env.PLATFORM_MNEMONIC;
+  const mnemonic = process.env.PLATFORM_MNEMONIC?.trim();
   if (!mnemonic)
     throw new Error("PLATFORM_MNEMONIC is required for loginViaModal");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@example-apps/dashproof-lab/e2e/fixtures.ts` around lines 98 - 112, In
loginViaModal ensure the mnemonic read from process.env.PLATFORM_MNEMONIC is
trimmed and validated before use: replace the raw mnemonic use in the function
with a trimmed version (e.g., const trimmed = mnemonic.trim()), throw the
existing error if trimmed is empty (treat whitespace-only as missing), and use
the trimmed value when filling the mnemonic input and any other checks in
waitForBrowsingReady/navLink/login flow (references: loginViaModal,
PLATFORM_MNEMONIC, mnemonicInput).
🧹 Nitpick comments (9)
example-apps/dashproof-lab/src/components/NavButton.tsx (1)

10-30: Improve nav accessibility semantics (aria-current + decorative glyph hiding).

glyph is decorative and should be hidden from assistive tech; also expose active page state on the button.

Proposed refactor
     <button
       type="button"
       onClick={onClick}
+      aria-current={active ? 'page' : undefined}
       className={`relative flex w-full items-center gap-2 rounded-lg px-2.5 py-2 text-[13px] font-medium transition-[background,color] duration-[120ms] ${
         active
           ? "bg-surface-2 text-ink"
           : "bg-transparent text-ink-3 hover:text-ink-2"
       }`}
     >
@@
-      <span
+      <span
+        aria-hidden="true"
         className={`w-3.5 text-center text-sm ${
           active ? "text-accent" : "text-ink-4"
         }`}
       >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@example-apps/dashproof-lab/src/components/NavButton.tsx` around lines 10 -
30, NavButton should expose active state and hide the decorative glyph: when
rendering the <button> (component NavButton) add aria-current="page" only when
active (otherwise omit the attribute) to expose the active page to assistive
tech, and mark the glyph span (the element rendering the glyph prop) as purely
decorative by adding aria-hidden="true" (and tabIndex={-1} if the glyph can be
focusable) so screen readers ignore it; keep the existing label visible to AT.
Use the existing props/variables active, glyph, label, and onClick to locate the
changes.
example-apps/dashproof-lab/src/components/CopyButton.tsx (1)

33-41: Avoid stale timers by clearing prior timeout before starting a new one.

Rapid clicks create overlapping timeouts, which can flip done back to false earlier than intended and can fire after unmount. Use a ref + cleanup for the timer.

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

In `@example-apps/dashproof-lab/src/components/CopyButton.tsx` around lines 33 -
41, handleClick currently sets a timeout without clearing prior timers, causing
overlapping timers and possible updates after unmount; change the component to
store the timer id in a ref (e.g., timeoutRef), clear any existing
timeoutRef.current before calling window.setTimeout, assign the returned id to
timeoutRef.current, and add a useEffect cleanup that clears timeoutRef.current
on unmount; update references to setDone and onCopied inside handleClick as-is
so the visible behavior remains the same.
example-apps/dashproof-lab/src/components/OperationResultNotice.tsx (1)

1-17: Run Prettier on the new dashproof-lab TS/TSX files.

This file is still using double quotes, so it doesn’t match the repo’s single-quote formatting rule.

As per coding guidelines, "**/*.{js,mjs,ts,tsx,json,md}: Code must be formatted with Prettier using single quotes, 2-space tabs, and trailing commas`."

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

In `@example-apps/dashproof-lab/src/components/OperationResultNotice.tsx` around
lines 1 - 17, The file uses double quotes instead of the repo's Prettier
single-quote style; run Prettier or update string/JSX quoting to single quotes
across this file (e.g., change occurrences in OperationResultNoticeProps, the
tone literal types, and the toneClass object) so all import/type strings and
class strings use single quotes and adhere to the project's formatting rules
(single quotes, 2-space indentation, trailing commas) before committing.
example-apps/dashproof-lab/test/App.test.tsx (1)

1-12: Move this suite next to src/App.tsx.

The new example-apps/dashproof-lab/test/ layout is drifting from the repo’s test-colocation rule, which will get harder to navigate as more component tests land.

As per coding guidelines, "example-apps/dashproof-lab/**/*.test.{ts,tsx}: Co-locate unit tests with their subject files (e.g. AnchorForm.test.tsx next to AnchorForm.tsx, SessionContext.test.tsx next to SessionContext.tsx)`."

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

In `@example-apps/dashproof-lab/test/App.test.tsx` around lines 1 - 12, Move the
test suite file (App.test.tsx) to be colocated with its subject component
(App.tsx): relocate the test from the separate test/ folder into the same
directory as App.tsx, update the import of App in the test to the correct
relative path (e.g., import App from "./App"), and ensure any module-relative
assets or mocks referenced by the test are adjusted to their new relative paths
so the tests run unchanged.
example-apps/dashproof-lab/test/contract.test.ts (1)

1-315: Move this suite next to src/dash/contract.ts to match test co-location rules.

This file is currently centralized under test/, but project rules require colocating *.test.ts/tsx with the subject module (for this one, near src/dash/contract.ts).

As per coding guidelines example-apps/dashproof-lab/**/*.test.{ts,tsx}: “Co-locate unit tests with their subject files (e.g. AnchorForm.test.tsx next to AnchorForm.tsx, SessionContext.test.tsx next to SessionContext.tsx)”.

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

In `@example-apps/dashproof-lab/test/contract.test.ts` around lines 1 - 315, Move
this test suite to be co-located with the module that exports ensureContract,
registerContract, and refreshContractCache (i.e., place the test next to the
contract module), update the import that currently reads "../src/dash/contract"
to a local import (e.g. "./contract") so the tests import the module relatively,
keep the top-of-file Vitest environment pragma, and run a quick test to confirm
mocks for MockIdentifier, mockDataContractConstructor and identifierFreeMock
still work after relocation.
example-apps/dashproof-lab/src/components/AnchorForm.tsx (1)

137-141: Clipboard write errors are silently swallowed.

If navigator.clipboard.writeText rejects (e.g., due to permissions or secure context issues), the promise rejection is unhandled. Consider adding error handling or at minimum avoiding the "Copied" state on failure.

🔧 Proposed fix
   async function handleCopyHash() {
     if (!hashHex || !navigator.clipboard?.writeText) return;
-    await navigator.clipboard.writeText(hashHex);
-    setHashCopied(true);
+    try {
+      await navigator.clipboard.writeText(hashHex);
+      setHashCopied(true);
+    } catch {
+      // Clipboard access denied or unavailable
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@example-apps/dashproof-lab/src/components/AnchorForm.tsx` around lines 137 -
141, handleCopyHash currently assumes navigator.clipboard.writeText always
succeeds and sets setHashCopied(true) even on rejection; wrap the await
navigator.clipboard.writeText(hashHex) in try/catch, only call
setHashCopied(true) on success, and handle failures by logging or showing an
error (e.g., via console.error or a UI error setter) so rejections from
navigator.clipboard.writeText and missing permissions are not swallowed;
reference handleCopyHash, hashHex, setHashCopied, and
navigator.clipboard.writeText when applying the change.
example-apps/dashproof-lab/src/lib/format.ts (1)

51-66: Minor: Intl.RelativeTimeFormat instantiated inside the loop.

A new formatter is created on each iteration. For a utility that may be called frequently, consider hoisting the formatter or caching it. However, this is a minor optimization and the current implementation is correct.

♻️ Optional optimization
+const rtf = new Intl.RelativeTimeFormat(undefined, { numeric: "auto" });
+
 export function formatRelativeTime(
   timestamp: number | null | undefined,
   fromNow: number = Date.now(),
 ): string {
   if (!timestamp) return "Pending";
   const diffSec = (timestamp - fromNow) / 1000;
   let value = diffSec;
   for (const div of RELATIVE_DIVISIONS) {
     if (Math.abs(value) < div.amount) {
-      const rtf = new Intl.RelativeTimeFormat(undefined, { numeric: "auto" });
       return rtf.format(Math.round(value), div.name);
     }
     value /= div.amount;
   }
   return "";
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@example-apps/dashproof-lab/src/lib/format.ts` around lines 51 - 66, The
function formatRelativeTime creates a new Intl.RelativeTimeFormat on every loop
iteration; hoist or cache the formatter to avoid repeated allocations by
creating a single RelativeTimeFormat instance once (e.g., outside the for-loop
or as a module-level constant) and reuse it when formatting values, keeping the
same options and still using RELATIVE_DIVISIONS and Math.round(value) as before.
example-apps/dashproof-lab/src/dash/contract.ts (1)

155-171: Move ensureContract out of src/dash/.

This function mixes localStorage fallback policy with SDK orchestration, so it is no longer a single SDK operation wrapper. Keeping that logic in the Dash helper layer makes this directory harder to reason about and breaks the repo boundary for src/dash/.

As per coding guidelines, "Create one file per Platform SDK operation in src/dash/, each exporting an async function with a leading JSDoc block naming the SDK method it wraps. No hooks, no wrappers — the SDK call is the function."

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

In `@example-apps/dashproof-lab/src/dash/contract.ts` around lines 155 - 171, The
ensureContract function mixes localStorage fallback with SDK orchestration and
should be moved out of the src/dash/ SDK directory: remove ensureContract from
this SDK layer and create it in the application/helper layer where higher-level
orchestration belongs; keep the SDK-only files in src/dash/ to each export a
single async wrapper (e.g., registerContract) with a leading JSDoc. Update
callers to import the new ensureContract from the application/helper module, and
keep registerContract and loadStoredContractId as separate functions
(registerContract remains in the SDK wrapper file, loadStoredContractId stays
with app-level storage utilities).
example-apps/dashproof-lab/src/dash/queries.ts (1)

92-163: Split these query helpers into one file per SDK operation.

findAnchorByHash, listAnchorsByOwner, and listAnchorsByChain are three separate sdk.documents.query(...) operations in one src/dash/ module. Decomposing them now will keep the Dash layer aligned with the repo contract and easier to extend.

As per coding guidelines, "Create one file per Platform SDK operation in src/dash/, each exporting an async function with a leading JSDoc block naming the SDK method it wraps. No hooks, no wrappers — the SDK call is the function."

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

In `@example-apps/dashproof-lab/src/dash/queries.ts` around lines 92 - 163, The
three SDK query helpers (findAnchorByHash, listAnchorsByOwner,
listAnchorsByChain) are combined in one module but per guidelines must be one
file per SDK operation; split each into its own module exporting a single async
function that directly wraps sdk.documents.query, add a leading JSDoc that names
the SDK method (e.g., "sdk.documents.query"), keep the existing logic
(refreshContractCache, query construction, normalizeAnchors) inside each
function, remove any hooks/wrappers, and update imports/exports where they are
used so callers import the new single-function modules by the original function
names.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@example-apps/dashproof-lab/.prettierrc.json`:
- Line 1: Replace the empty Prettier config with explicit rules: update the
.prettierrc.json to pin singleQuote: true, tabWidth: 2, trailingComma: "all"
(and optionally printWidth and useTabs as false) so the repo enforces the
required formatting profile; ensure the config object contains these keys and
values so files matching the repo pattern (/** /*.{js,mjs,ts,tsx,json,md}) are
formatted with single quotes, 2-space indentation, and trailing commas.

In `@example-apps/dashproof-lab/CLAUDE.md`:
- Line 27: The README references outdated Session API names (browseOnly /
browsing) that no longer match the implementation (enterReadOnly / readonly);
update the docs in CLAUDE.md to use the current symbols (enterReadOnly and
readonly) everywhere (including the occurrences around lines referenced and the
mentions at 66-67) or alternatively add small alias functions in
SessionContext.tsx (e.g., export a browseOnly wrapper that calls enterReadOnly
and map browsing to readonly) so the documentation and code stay in sync; ensure
you reference SessionContext.tsx, useSession.ts, and App.tsx when making the
change so wording and any auto-call in App.tsx reflect the real API.

In `@example-apps/dashproof-lab/e2e/history.spec.ts`:
- Around line 1-4: This suite is order-dependent because it assumes an existing
anchor created by anchor.spec.ts; make the tests self-contained by seeding the
required anchor(s) in this file (use a beforeAll or the top-level describe block
for the "Authed History" tests) instead of relying on external specs, e.g., call
the same anchor-creation logic used in anchor.spec.ts (or a shared helper) to
create at least one on-chain anchor before the "My anchors" tests run and tear
down or isolate the created data so the tests at lines ~108-152 and the "My
anchors" tests no longer depend on external ordering.

In `@example-apps/dashproof-lab/e2e/verify.spec.ts`:
- Around line 30-35: The two network-backed Playwright assertions using await
expect(page.getByText("Proof found")).toBeVisible() and await
expect(page.getByText("Matching proof", { exact: true })).toBeVisible() should
include explicit timeouts to avoid CI flakes; update both calls to pass a
timeout option (e.g., .toBeVisible({ timeout: 30000 })) or use a shared constant
like NETWORK_TIMEOUT and apply .toBeVisible({ timeout: NETWORK_TIMEOUT }) so the
checks wait longer for testnet round-trips.

In `@example-apps/dashproof-lab/eslint.config.js`:
- Around line 12-17: The extends array in eslint.config.js is missing the
required Airbnb base profile; update the flat config to include airbnb-base by
either wrapping the classic config with FlatCompat from `@eslint/eslintrc` (import
FlatCompat and add the result of compat.extendConfig('airbnb-base') into the
current extends array alongside js.configs.recommended,
tseslint.configs.recommended, reactHooks.configs.flat.recommended,
reactRefresh.configs.vite) or install a native flat-compatible package (e.g.,
eslint-config-airbnb-base-x or eslint-config-airbnb-extended) and add that
package’s config name to the extends array so the project’s ESLint uses the
Airbnb base rules per the coding guidelines.

In `@example-apps/dashproof-lab/src/components/CopyButton.tsx`:
- Around line 9-41: The copy behavior reports success blindly; make copyText an
async function that returns a boolean indicating success by awaiting
navigator.clipboard.writeText(text) (catch and return false on error) and only
using the textarea fallback if the clipboard promise rejects or is unavailable
(return true on successful execCommand copy, false otherwise); then update
handleClick in the CopyButton component to await copyText(value) and only call
setDone(true) and onCopied(label) when the returned boolean is true (keep the
timeout to reset state on success); also normalize string literals to single
quotes to satisfy Prettier.

In `@example-apps/dashproof-lab/src/components/ExampleFilesPanel.tsx`:
- Around line 27-28: The href currently uses fixture.publicPath directly (e.g.,
in ExampleFilesPanel.tsx where href={fixture.publicPath}
download={fixture.filename}), which breaks when the app is served from a
sub-path; change it to resolve the fixture URL against the app base path (use
your app's base URL value such as process.env.PUBLIC_URL or
import.meta.env.BASE_URL) by constructing the absolute URL (e.g., new
URL(fixture.publicPath, baseUrl).toString()) before assigning it to href so
downloads work regardless of the deployment sub-path.

In `@example-apps/dashproof-lab/src/components/Modal.tsx`:
- Around line 37-60: The modal lacks accessible dialog semantics; add
role="dialog" and aria-modal="true" to the panel container and link the heading
as the dialog label by giving the h2 a stable id and setting aria-labelledby on
the same panel div; generate the id using React's useId() (or accept an id prop)
to avoid collisions, assign that id to the h2 (instead of relying on title
text), and set aria-labelledby="{thatId}" on the div that currently renders the
panel (the element using panelClassName), keeping the backdrop onClick and the
close button as-is.

In `@example-apps/dashproof-lab/src/components/OperationResultNotice.tsx`:
- Around line 24-29: The root container in OperationResultNotice is a plain div
so screen readers won't announce async status changes; update the outer div (the
one using className={`rounded-lg border px-4 py-3 ${toneClass[tone]}`}) to be a
live region by adding appropriate ARIA attributes — e.g. set aria-live to
"assertive" for error-like tones and "polite" for non-error tones, include
role="status" (or role="alert" for assertive if you prefer) and
aria-atomic="true" so title/children changes are announced; implement the
conditional aria-live logic based on the tone prop (used with toneClass[tone])
and keep the rest of the layout (title, children) unchanged.

In `@example-apps/dashproof-lab/src/components/VerifyPanel.tsx`:
- Around line 140-143: The guard in handleDragLeave currently casts
event.relatedTarget to Node and passes it to contains(), which is unsafe; update
handleDragLeave to first check if event.relatedTarget is non-null and
event.relatedTarget instanceof Node before calling
event.currentTarget.contains(event.relatedTarget), and apply the same fix in
AnchorForm's corresponding handler (the function at or around the symbol used on
line ~122) so that contains() only receives a Node and no unsafe cast is used.

In `@example-apps/dashproof-lab/src/dash/contract.ts`:
- Around line 147-151: The code builds contractId from published but falls back
to the sentinel "unknown" and persists it; instead, detect a missing/invalid ID
(from published.id or published.toJSON()?.id) and fail fast—do not call
saveContractId or log success when the ID is missing. Update the logic around
contractId (the published variable, contractId constant, and saveContractId
call) to validate the extracted ID and throw or return an error (or call an
error logger) if no real ID is present so a placeholder is never written to
storage.

In `@example-apps/dashproof-lab/src/dash/types.ts`:
- Around line 18-58: The DashSdk documents.query signature diverges from the
shared core ConnectedDashClientLike (in setupDashClient-core.d.mts) by adding
orderBy/startAfter and returning DashAnchorQueryResults, causing runtime
mismatch where src/dash/queries.ts relies on those extras; fix by aligning the
type to the core: either import and use ConnectedDashClientLike (or its document
query type) for DashSdk.documents.query, or remove orderBy/startAfter and change
the return type to the core's document array shape so the method signatures
match the actual SDK; ensure references to documents.query in your query helpers
are updated to the corrected parameter/return types.

In `@example-apps/dashproof-lab/src/lib/hash.ts`:
- Around line 39-41: The ArrayBuffer.isView(value) branch currently copies the
entire backing buffer and ignores subview boundaries; replace that logic to
construct a Uint8Array using the view's byteOffset and byteLength (e.g., new
Uint8Array(value.buffer, value.byteOffset, value.byteLength)) and then copy that
slice if a detached copy is required so subviews are honored; update the branch
handling in hash.ts where ArrayBuffer.isView(value) is checked to use the view's
byteOffset/byteLength when producing the Uint8Array.
- Around line 3-7: Remove the unsafe UTF-8 decoding fallback that calls
file.text() when computing file bytes: replace the ternary that currently
chooses file.arrayBuffer() ? file.arrayBuffer() : file.text() ? file.text() :
new Response(file).arrayBuffer() so that it never uses file.text(); instead
prefer file.arrayBuffer() when available and otherwise use new
Response(file).arrayBuffer() to obtain a binary-safe ArrayBuffer/Uint8Array for
SHA-256 hashing (update the expression that constructs the Uint8Array from file
to only branch between file.arrayBuffer() and new Response(file).arrayBuffer()).

In `@example-apps/dashproof-lab/src/styles/globals.css`:
- Line 1: Replace the lint-breaking `@import` and unquoted font name: change the
top line to use the string form `@import`
"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap";
and ensure the Roboto token in the font-family declaration (the font-family
property that includes Inter/JetBrains/Roboto) is quoted as "Roboto" so all font
names are valid CSS identifiers for stylelint.
- Line 4: Update the stylelint config to allow Tailwind v4 at-rules by adding an
ignore list to the at-rule-no-unknown rule: modify the configuration that
currently extends stylelint-config-standard-scss and add "at-rule-no-unknown"
with an ignoreAtRules array including "theme", "utility", "source", and
"tailwind" so the `@theme` (and other Tailwind) at-rules in globals.css won't be
flagged; ensure the rule key name and the ignoreAtRules entry are added to the
existing rules block in the config.

In `@example-apps/dashproof-lab/test/App.test.tsx`:
- Around line 102-110: The test helper makeSession is mocking enterReadOnly but
the app actually calls browseOnly on the SessionContext when status === "idle";
update makeSession to provide a browseOnly mock (e.g., browseOnly:
vi.fn().mockResolvedValue(undefined)) and remove or stop asserting on
enterReadOnly, then change any assertions in the tests (including the other
block around lines 123-131) to expect browseOnly to have been called by App.tsx;
reference the makeSession factory, browseOnly, enterReadOnly, and
App.tsx/SessionContext.tsx to locate and update the mocks and assertions.

In `@example-apps/dashproof-lab/test/LoginModal.test.tsx`:
- Around line 12-13: The test file LoginModal.test.tsx is placed under test/
instead of being co-located with its subject; move the file so it sits alongside
the component (next to src/components/LoginModal.tsx) and update any import
paths if necessary so the test imports { LoginModal } from "./LoginModal" (or
the correct relative path) to follow the repository’s co-location guideline for
example-apps/dashproof-lab/**/*.test.{ts,tsx}.

---

Outside diff comments:
In `@example-apps/dashproof-lab/test/HowItWorks.test.tsx`:
- Around line 1-94: This test file for the HowItWorks component must be moved to
the same directory as HowItWorks.tsx; relocate the test file next to the
HowItWorks component, update its import so it imports HowItWorks via a relative
path from the same directory (e.g., import HowItWorks from "./HowItWorks" or
equivalent), remove the old test copy, and ensure the test runner's
file-globting still picks up the new co-located test (no other test changes
needed).

In `@example-apps/dashproof-lab/test/logger.test.ts`:
- Around line 1-47: The test suite for errorMessage should be moved from the
test/ directory to live next to its implementation in the same folder as
src/dash/logger.ts; relocate the file so it imports errorMessage from "./logger"
(or relative path matching logger.ts) and keep the describe/it blocks unchanged,
ensuring the test filename follows the convention logger.test.ts and any import
paths updated accordingly.

In `@example-apps/dashproof-lab/test/Tabs.test.tsx`:
- Around line 1-59: The Tabs test file should be moved from test/Tabs.test.tsx
into the same directory as the component (e.g. next to src/components/Tabs.tsx
as src/components/Tabs.test.tsx) to satisfy the co-location rule; after moving,
update any relative imports if required (the test imports Tabs from
"../src/components/Tabs" — change that to a local import like "./Tabs" or the
correct relative path) and ensure the vitest environment directive and test
imports remain correct so the suite continues to run.

---

Minor comments:
In `@example-apps/dashproof-lab/e2e/fixtures.ts`:
- Around line 98-112: In loginViaModal ensure the mnemonic read from
process.env.PLATFORM_MNEMONIC is trimmed and validated before use: replace the
raw mnemonic use in the function with a trimmed version (e.g., const trimmed =
mnemonic.trim()), throw the existing error if trimmed is empty (treat
whitespace-only as missing), and use the trimmed value when filling the mnemonic
input and any other checks in waitForBrowsingReady/navLink/login flow
(references: loginViaModal, PLATFORM_MNEMONIC, mnemonicInput).

In `@example-apps/dashproof-lab/src/components/AppShell.tsx`:
- Around line 149-154: The menu button currently always uses aria-label="Open
menu" which misreports state; update the button in AppShell (the element using
onClick={() => setDrawerOpen(!drawerOpen)} and aria-expanded={drawerOpen}) to
compute the label from drawerOpen (e.g., "Open menu" when false, "Close menu"
when true) so screen readers receive correct feedback and the label changes in
sync with setDrawerOpen/drawerOpen.

In `@example-apps/dashproof-lab/src/components/HistoryPanel.tsx`:
- Around line 165-178: The reducer in HistoryPanel that computes groupedAnchors
assumes anchors with the same chainId are consecutive (it checks existing =
groups.at(-1)), but anchors are sorted by createdAt so same chainIds can be
split across groups; fix by replacing the sequential grouping with a Map-based
grouping keyed by anchor.chainId (or pre-sort anchors by chainId) so each
chainId maps to a single group, then convert that Map to the desired Array<{
chainId: string; items: AnchorRecord[] }>; update references to groupedAnchors
accordingly.

In `@example-apps/dashproof-lab/src/components/Modal.tsx`:
- Around line 49-53: The modal's close control button in Modal.tsx lacks an
explicit type which can cause accidental form submissions; update the button
element that calls onClose (the close control in the Modal component) to include
type="button" so it does not act as a submit button in embedded forms, ensuring
the onClose handler remains unchanged.

In `@example-apps/dashproof-lab/src/main.tsx`:
- Around line 3-8: The initial theme is being applied too late
(applyTheme(getInitialTheme()) in main.tsx), causing a flash; remove that
runtime call and instead add an inline script in index.html head (before any CSS
link) that runs the same logic as getInitialTheme and sets
document.documentElement.dataset.theme (or equivalent DOM attribute used by
applyTheme) so the correct data-theme is present before CSS loads; keep the
getInitialTheme/applyTheme implementations for client code but delete the early
call in main.tsx and ensure the inline script mirrors getInitialTheme behavior
and sets the same attribute name used by applyTheme.

In `@example-apps/dashproof-lab/src/session/SessionContext.tsx`:
- Around line 88-112: The code is using a unsafe cast `sdk: connected as never`
when calling IdentityKeyManager.create; replace the local DashSdk type with the
correct external type (ConnectedDashClientLike from setupDashClient-core) or
update the local DashSdk interface to exactly match ConnectedDashClientLike,
then import ConnectedDashClientLike and change the parameter/variable types
(e.g., the `sdk` state/prop and the `connect()` return) so you can pass
`connected` directly into IdentityKeyManager.create without the `as never` cast;
remove the cast and ensure IdentityKeyManager.create, connect, and any
createClient usage all use the same ConnectedDashClientLike type.

In `@example-apps/dashproof-lab/tsconfig.json`:
- Around line 1-8: Update the three referenced TypeScript configs
(tsconfig.app.json, tsconfig.node.json, tsconfig.e2e.json) to enable full strict
checking and use Node16 module resolution: set "strict": true in each config and
change "module" from "esnext" to "Node16" (or "node16" casing used in your
project) so they target Node16 module semantics; preserve or remove individual
strict-related flags (like noUnusedLocals) as desired since "strict": true
enables the full strict set.

---

Nitpick comments:
In `@example-apps/dashproof-lab/src/components/AnchorForm.tsx`:
- Around line 137-141: handleCopyHash currently assumes
navigator.clipboard.writeText always succeeds and sets setHashCopied(true) even
on rejection; wrap the await navigator.clipboard.writeText(hashHex) in
try/catch, only call setHashCopied(true) on success, and handle failures by
logging or showing an error (e.g., via console.error or a UI error setter) so
rejections from navigator.clipboard.writeText and missing permissions are not
swallowed; reference handleCopyHash, hashHex, setHashCopied, and
navigator.clipboard.writeText when applying the change.

In `@example-apps/dashproof-lab/src/components/CopyButton.tsx`:
- Around line 33-41: handleClick currently sets a timeout without clearing prior
timers, causing overlapping timers and possible updates after unmount; change
the component to store the timer id in a ref (e.g., timeoutRef), clear any
existing timeoutRef.current before calling window.setTimeout, assign the
returned id to timeoutRef.current, and add a useEffect cleanup that clears
timeoutRef.current on unmount; update references to setDone and onCopied inside
handleClick as-is so the visible behavior remains the same.

In `@example-apps/dashproof-lab/src/components/NavButton.tsx`:
- Around line 10-30: NavButton should expose active state and hide the
decorative glyph: when rendering the <button> (component NavButton) add
aria-current="page" only when active (otherwise omit the attribute) to expose
the active page to assistive tech, and mark the glyph span (the element
rendering the glyph prop) as purely decorative by adding aria-hidden="true" (and
tabIndex={-1} if the glyph can be focusable) so screen readers ignore it; keep
the existing label visible to AT. Use the existing props/variables active,
glyph, label, and onClick to locate the changes.

In `@example-apps/dashproof-lab/src/components/OperationResultNotice.tsx`:
- Around line 1-17: The file uses double quotes instead of the repo's Prettier
single-quote style; run Prettier or update string/JSX quoting to single quotes
across this file (e.g., change occurrences in OperationResultNoticeProps, the
tone literal types, and the toneClass object) so all import/type strings and
class strings use single quotes and adhere to the project's formatting rules
(single quotes, 2-space indentation, trailing commas) before committing.

In `@example-apps/dashproof-lab/src/dash/contract.ts`:
- Around line 155-171: The ensureContract function mixes localStorage fallback
with SDK orchestration and should be moved out of the src/dash/ SDK directory:
remove ensureContract from this SDK layer and create it in the
application/helper layer where higher-level orchestration belongs; keep the
SDK-only files in src/dash/ to each export a single async wrapper (e.g.,
registerContract) with a leading JSDoc. Update callers to import the new
ensureContract from the application/helper module, and keep registerContract and
loadStoredContractId as separate functions (registerContract remains in the SDK
wrapper file, loadStoredContractId stays with app-level storage utilities).

In `@example-apps/dashproof-lab/src/dash/queries.ts`:
- Around line 92-163: The three SDK query helpers (findAnchorByHash,
listAnchorsByOwner, listAnchorsByChain) are combined in one module but per
guidelines must be one file per SDK operation; split each into its own module
exporting a single async function that directly wraps sdk.documents.query, add a
leading JSDoc that names the SDK method (e.g., "sdk.documents.query"), keep the
existing logic (refreshContractCache, query construction, normalizeAnchors)
inside each function, remove any hooks/wrappers, and update imports/exports
where they are used so callers import the new single-function modules by the
original function names.

In `@example-apps/dashproof-lab/src/lib/format.ts`:
- Around line 51-66: The function formatRelativeTime creates a new
Intl.RelativeTimeFormat on every loop iteration; hoist or cache the formatter to
avoid repeated allocations by creating a single RelativeTimeFormat instance once
(e.g., outside the for-loop or as a module-level constant) and reuse it when
formatting values, keeping the same options and still using RELATIVE_DIVISIONS
and Math.round(value) as before.

In `@example-apps/dashproof-lab/test/App.test.tsx`:
- Around line 1-12: Move the test suite file (App.test.tsx) to be colocated with
its subject component (App.tsx): relocate the test from the separate test/
folder into the same directory as App.tsx, update the import of App in the test
to the correct relative path (e.g., import App from "./App"), and ensure any
module-relative assets or mocks referenced by the test are adjusted to their new
relative paths so the tests run unchanged.

In `@example-apps/dashproof-lab/test/contract.test.ts`:
- Around line 1-315: Move this test suite to be co-located with the module that
exports ensureContract, registerContract, and refreshContractCache (i.e., place
the test next to the contract module), update the import that currently reads
"../src/dash/contract" to a local import (e.g. "./contract") so the tests import
the module relatively, keep the top-of-file Vitest environment pragma, and run a
quick test to confirm mocks for MockIdentifier, mockDataContractConstructor and
identifierFreeMock still work after relocation.
🪄 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: 8bdbf2f6-1566-45b0-bd18-de589ffe0ae3

📥 Commits

Reviewing files that changed from the base of the PR and between 4c302b8 and 6410793.

⛔ Files ignored due to path filters (3)
  • example-apps/dashproof-lab/package-lock.json is excluded by !**/package-lock.json
  • example-apps/dashproof-lab/public/example-files/invoice-batch-2026-04.csv is excluded by !**/*.csv
  • example-apps/dashproof-lab/public/favicon.svg is excluded by !**/*.svg
📒 Files selected for processing (75)
  • .github/scripts/build-landing-page.mjs
  • .github/workflows/deploy-example-apps.yml
  • example-apps/README.md
  • example-apps/dashmint-lab/package.json
  • example-apps/dashmint-lab/src/components/AppShell.tsx
  • example-apps/dashproof-lab/.gitignore
  • example-apps/dashproof-lab/.prettierignore
  • example-apps/dashproof-lab/.prettierrc.json
  • example-apps/dashproof-lab/CLAUDE.md
  • example-apps/dashproof-lab/README.md
  • example-apps/dashproof-lab/e2e/anchor.spec.ts
  • example-apps/dashproof-lab/e2e/copy.spec.ts
  • example-apps/dashproof-lab/e2e/fixtures.ts
  • example-apps/dashproof-lab/e2e/history.spec.ts
  • example-apps/dashproof-lab/e2e/theme.spec.ts
  • example-apps/dashproof-lab/e2e/verify.spec.ts
  • example-apps/dashproof-lab/eslint.config.js
  • example-apps/dashproof-lab/index.html
  • example-apps/dashproof-lab/package.json
  • example-apps/dashproof-lab/playwright.config.ts
  • example-apps/dashproof-lab/public/example-files/proof-fixture-01.txt
  • example-apps/dashproof-lab/public/example-files/release-bundle-2026-04-24.json
  • example-apps/dashproof-lab/src/App.tsx
  • example-apps/dashproof-lab/src/components/AnchorForm.tsx
  • example-apps/dashproof-lab/src/components/AppShell.tsx
  • example-apps/dashproof-lab/src/components/CopyButton.tsx
  • example-apps/dashproof-lab/src/components/ExampleFilesModal.tsx
  • example-apps/dashproof-lab/src/components/ExampleFilesPanel.tsx
  • example-apps/dashproof-lab/src/components/HistoryPanel.tsx
  • example-apps/dashproof-lab/src/components/HowItWorks.tsx
  • example-apps/dashproof-lab/src/components/IdentityCard.tsx
  • example-apps/dashproof-lab/src/components/LoginModal.tsx
  • example-apps/dashproof-lab/src/components/Modal.tsx
  • example-apps/dashproof-lab/src/components/NavButton.tsx
  • example-apps/dashproof-lab/src/components/OperationResultNotice.tsx
  • example-apps/dashproof-lab/src/components/Tabs.tsx
  • example-apps/dashproof-lab/src/components/VerifyPanel.tsx
  • example-apps/dashproof-lab/src/dash/client.ts
  • example-apps/dashproof-lab/src/dash/contract.ts
  • example-apps/dashproof-lab/src/dash/createAnchor.ts
  • example-apps/dashproof-lab/src/dash/keyManager.ts
  • example-apps/dashproof-lab/src/dash/logger.ts
  • example-apps/dashproof-lab/src/dash/queries.ts
  • example-apps/dashproof-lab/src/dash/types.ts
  • example-apps/dashproof-lab/src/data/exampleFiles.ts
  • example-apps/dashproof-lab/src/hooks/useTheme.ts
  • example-apps/dashproof-lab/src/lib/chainId.ts
  • example-apps/dashproof-lab/src/lib/format.ts
  • example-apps/dashproof-lab/src/lib/hash.ts
  • example-apps/dashproof-lab/src/main.tsx
  • example-apps/dashproof-lab/src/session/SessionContext.tsx
  • example-apps/dashproof-lab/src/session/useSession.ts
  • example-apps/dashproof-lab/src/styles/globals.css
  • example-apps/dashproof-lab/test/AnchorForm.test.tsx
  • example-apps/dashproof-lab/test/App.test.tsx
  • example-apps/dashproof-lab/test/CopyButton.test.tsx
  • example-apps/dashproof-lab/test/ExampleFilesPanel.test.tsx
  • example-apps/dashproof-lab/test/HistoryPanel.test.tsx
  • example-apps/dashproof-lab/test/HowItWorks.test.tsx
  • example-apps/dashproof-lab/test/IdentityCard.test.tsx
  • example-apps/dashproof-lab/test/LoginModal.test.tsx
  • example-apps/dashproof-lab/test/SessionContext.test.tsx
  • example-apps/dashproof-lab/test/Tabs.test.tsx
  • example-apps/dashproof-lab/test/VerifyPanel.test.tsx
  • example-apps/dashproof-lab/test/contract.test.ts
  • example-apps/dashproof-lab/test/dash.test.ts
  • example-apps/dashproof-lab/test/lib.test.ts
  • example-apps/dashproof-lab/test/logger.test.ts
  • example-apps/dashproof-lab/test/queries.test.ts
  • example-apps/dashproof-lab/test/useTheme.test.ts
  • example-apps/dashproof-lab/tsconfig.app.json
  • example-apps/dashproof-lab/tsconfig.e2e.json
  • example-apps/dashproof-lab/tsconfig.json
  • example-apps/dashproof-lab/tsconfig.node.json
  • example-apps/dashproof-lab/vite.config.ts

Comment thread example-apps/dashproof-lab/.prettierrc.json
Comment thread example-apps/dashproof-lab/CLAUDE.md Outdated
Comment thread example-apps/dashproof-lab/e2e/history.spec.ts
Comment thread example-apps/dashproof-lab/e2e/verify.spec.ts
Comment thread example-apps/dashproof-lab/eslint.config.js
Comment thread example-apps/dashproof-lab/src/lib/hash.ts
Comment thread example-apps/dashproof-lab/src/styles/globals.css
Comment thread example-apps/dashproof-lab/src/styles/globals.css
Comment thread example-apps/dashproof-lab/test/App.test.tsx
Comment thread example-apps/dashproof-lab/test/LoginModal.test.tsx
Verified each CodeRabbit suggestion against the code, mirroring dashmint-lab
patterns where applicable. Notable fixes: Modal a11y (role=dialog, aria-modal,
aria-labelledby), OperationResultNotice aria-live, HistoryPanel Map-based
grouping (sequential reduce split same-chain anchors in byOwner mode),
contract.ts throws on missing publish id instead of saving "unknown",
hash.ts honors byteOffset/byteLength for typed-array subviews and drops the
unsafe file.text() UTF-8 fallback, ExampleFilesPanel resolves downloads
through import.meta.env.BASE_URL for sub-path deploys, mnemonic trim in
e2e fixtures, formatRelativeTime hoists its formatter, and CLAUDE.md
session-status terminology now matches the code (enterReadOnly/readonly).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@thephez
Copy link
Copy Markdown
Collaborator Author

thephez commented Apr 29, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (4)
example-apps/dashproof-lab/test/Modal.test.tsx (1)

1-1: Mirror test path to source structure under test/

Please place this as test/components/Modal.test.tsx to match src/components/Modal.tsx and keep the subject-path convention consistent.

Suggested move
- example-apps/dashproof-lab/test/Modal.test.tsx
+ example-apps/dashproof-lab/test/components/Modal.test.tsx

As per coding guidelines, component/unit tests should be in test/ with the same relative path structure as their source.

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

In `@example-apps/dashproof-lab/test/Modal.test.tsx` at line 1, Test file
Modal.test.tsx currently lives at the repo root; move it so its relative
location mirrors the Modal component's source (i.e., place Modal.test.tsx under
the test/components directory alongside the component name Modal.tsx) to follow
the project convention; update any import paths inside the test to the new
relative location if necessary and ensure test runner config still picks up
tests under the test/ tree.
example-apps/dashproof-lab/test/hashFile.test.ts (1)

6-33: Use single quotes to match repository formatting rules.

This file currently uses double-quoted strings; project formatting guidance specifies single quotes.

As per coding guidelines, "**/*.{js,mjs,ts,tsx,json,md}: Code must be formatted with Prettier using single quotes, 2-space tabs, and trailing commas".

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

In `@example-apps/dashproof-lab/test/hashFile.test.ts` around lines 6 - 33, The
test file uses double-quoted strings; update all string literals and
import/export specifiers in this file (including the import line and all
"describe", "it", file names, MIME types, and expected hex strings used with
bytesToHex and hashFile) to use single quotes to match the repository Prettier
rules, then run the project's formatter or lint fix (Prettier/ESLint) to ensure
trailing commas and 2-space indentation are applied; verify tests still pass.
example-apps/dashproof-lab/test/HistoryPanel.test.tsx (2)

64-65: Assert query call arguments, not only invocation.

Line 64 currently allows false positives if the wrong owner/contract is passed. Tighten to objectContaining({ ownerId, contractId }) so this test catches wiring regressions.

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

In `@example-apps/dashproof-lab/test/HistoryPanel.test.tsx` around lines 64 - 65,
The test currently only asserts that mockListAnchorsByOwner was called; change
the assertion to verify the call arguments by using expect.objectContaining({
ownerId, contractId }) so the test fails if the wrong owner or contract is
passed — replace expect(mockListAnchorsByOwner).toHaveBeenCalled() with
expect(mockListAnchorsByOwner).toHaveBeenCalledWith(expect.objectContaining({
ownerId, contractId })) in HistoryPanel.test.tsx (targeting the
mockListAnchorsByOwner call).

117-120: Avoid styling-coupled selectors for grouping assertions.

Line 117 ties the test to Tailwind class names, which makes the behavior test brittle to visual refactors. Prefer a stable semantic hook (data-testid/role/label) for chain sections.

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

In `@example-apps/dashproof-lab/test/HistoryPanel.test.tsx` around lines 117 -
120, The test is brittle because it queries DOM by Tailwind classes
("section.overflow-hidden.rounded-xl") via the chainSections variable; instead
add a stable semantic hook to the component (e.g., add
data-testid="chain-section" or an accessible role/aria-label on the section
elements in the HistoryPanel/where chain sections are rendered) and update the
test to use the testing-library query (e.g., getAllByTestId('chain-section') or
getAllByRole/getByLabelText) rather than querySelectorAll; update the component
that renders the sections (HistoryPanel or the specific section-rendering
function) and replace the selector in HistoryPanel.test.tsx accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@example-apps/dashproof-lab/CLAUDE.md`:
- Around line 25-26: Update the description of src/dash/ to reflect current
module contents: state that each file primarily exports an async function
wrapping a Platform SDK operation (with a leading JSDoc naming the SDK method),
but explicitly allow that some modules (e.g., src/dash/contract.ts) also export
storage/cache helper utilities; keep the prohibition on React hooks or UI
wrappers. Mention the shared core re-exports (createClient, IdentityKeyManager)
remain unchanged so contributors understand the special-case helpers.

In `@example-apps/dashproof-lab/e2e/fixtures.ts`:
- Around line 109-110: The test uses a stale selector: change the locator for
mnemonic input in fixtures.ts (the const mnemonicInput and its usage in
loginViaModal) to match the current placeholder used by the LoginModal component
(update from "mnemonic phrase" to the actual placeholder like "invoice-2026-04"
or, better, switch to a more stable selector such as a data-testid or role);
update any assertions (e.g., await expect(mnemonicInput).toBeVisible()) to use
the new selector so loginViaModal works with the current LoginModal.tsx.

In `@example-apps/dashproof-lab/src/dash/contract.ts`:
- Around line 93-103: Guard all direct localStorage accesses in
loadStoredContractId, saveContractId, and clearStoredContractId by wrapping
calls to localStorage.getItem/setItem/removeItem in try/catch blocks; in
loadStoredContractId return DEFAULT_CONTRACT_ID or null when getItem throws or
returns undefined, and in saveContractId/clearStoredContractId silently no-op
(or log) on exceptions to avoid hard failures (use STORAGE_KEY and
DEFAULT_CONTRACT_ID identifiers to find the code).

In `@example-apps/dashproof-lab/src/lib/format.ts`:
- Around line 100-114: The function formatHashBlocks can enter infinite loops
when blockSize <= 0 or blocksPerLine <= 0; add a guard at the start of
formatHashBlocks to validate and normalize these parameters (e.g., if blockSize
<= 0 then set blockSize = 1 or throw a clear error, and similarly for
blocksPerLine) so the for loops that increment by blockSize and blocksPerLine
always make progress; reference the function name formatHashBlocks and the
parameters blockSize and blocksPerLine when making the change.
- Around line 1-4: The truncation threshold is wrong: truncateId currently
checks if id.length <= head * 2 but always preserves a fixed 8-character tail,
causing incorrect truncation when head ≠ 8; change the threshold to compare
against head + 8 (or introduce a tail parameter) so the short-circuit uses the
same tail size as the slice. Update the conditional in truncateId (and/or add an
optional tail parameter defaulting to 8) and use that tail value both in the
length check and in the id.slice(-tail) call so the head/tail logic is
consistent.

In `@example-apps/dashproof-lab/test/OperationResultNotice.test.tsx`:
- Line 6: The test is placed at the wrong location relative to the source: the
file imports the OperationResultNotice component but the test must mirror the
source-relative structure; move the test so it lives under the test directory
that mirrors the component hierarchy (i.e., alongside other component tests in a
components subfolder) and update any import paths if needed so
OperationResultNotice resolves correctly.

---

Nitpick comments:
In `@example-apps/dashproof-lab/test/hashFile.test.ts`:
- Around line 6-33: The test file uses double-quoted strings; update all string
literals and import/export specifiers in this file (including the import line
and all "describe", "it", file names, MIME types, and expected hex strings used
with bytesToHex and hashFile) to use single quotes to match the repository
Prettier rules, then run the project's formatter or lint fix (Prettier/ESLint)
to ensure trailing commas and 2-space indentation are applied; verify tests
still pass.

In `@example-apps/dashproof-lab/test/HistoryPanel.test.tsx`:
- Around line 64-65: The test currently only asserts that mockListAnchorsByOwner
was called; change the assertion to verify the call arguments by using
expect.objectContaining({ ownerId, contractId }) so the test fails if the wrong
owner or contract is passed — replace
expect(mockListAnchorsByOwner).toHaveBeenCalled() with
expect(mockListAnchorsByOwner).toHaveBeenCalledWith(expect.objectContaining({
ownerId, contractId })) in HistoryPanel.test.tsx (targeting the
mockListAnchorsByOwner call).
- Around line 117-120: The test is brittle because it queries DOM by Tailwind
classes ("section.overflow-hidden.rounded-xl") via the chainSections variable;
instead add a stable semantic hook to the component (e.g., add
data-testid="chain-section" or an accessible role/aria-label on the section
elements in the HistoryPanel/where chain sections are rendered) and update the
test to use the testing-library query (e.g., getAllByTestId('chain-section') or
getAllByRole/getByLabelText) rather than querySelectorAll; update the component
that renders the sections (HistoryPanel or the specific section-rendering
function) and replace the selector in HistoryPanel.test.tsx accordingly.

In `@example-apps/dashproof-lab/test/Modal.test.tsx`:
- Line 1: Test file Modal.test.tsx currently lives at the repo root; move it so
its relative location mirrors the Modal component's source (i.e., place
Modal.test.tsx under the test/components directory alongside the component name
Modal.tsx) to follow the project convention; update any import paths inside the
test to the new relative location if necessary and ensure test runner config
still picks up tests under the test/ tree.
🪄 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: 6124b82e-f57e-4e42-aa13-5516efc4937d

📥 Commits

Reviewing files that changed from the base of the PR and between 6410793 and 9677608.

📒 Files selected for processing (17)
  • example-apps/dashproof-lab/CLAUDE.md
  • example-apps/dashproof-lab/e2e/fixtures.ts
  • example-apps/dashproof-lab/src/components/ExampleFilesPanel.tsx
  • example-apps/dashproof-lab/src/components/HistoryPanel.tsx
  • example-apps/dashproof-lab/src/components/Modal.tsx
  • example-apps/dashproof-lab/src/components/OperationResultNotice.tsx
  • example-apps/dashproof-lab/src/dash/contract.ts
  • example-apps/dashproof-lab/src/hooks/useTheme.ts
  • example-apps/dashproof-lab/src/lib/format.ts
  • example-apps/dashproof-lab/src/lib/hash.ts
  • example-apps/dashproof-lab/test/ExampleFilesPanel.test.tsx
  • example-apps/dashproof-lab/test/HistoryPanel.test.tsx
  • example-apps/dashproof-lab/test/Modal.test.tsx
  • example-apps/dashproof-lab/test/OperationResultNotice.test.tsx
  • example-apps/dashproof-lab/test/contract.test.ts
  • example-apps/dashproof-lab/test/hashFile.test.ts
  • example-apps/dashproof-lab/test/lib.test.ts
✅ Files skipped from review due to trivial changes (1)
  • example-apps/dashproof-lab/src/lib/hash.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • example-apps/dashproof-lab/src/components/Modal.tsx
  • example-apps/dashproof-lab/src/components/OperationResultNotice.tsx
  • example-apps/dashproof-lab/test/contract.test.ts
  • example-apps/dashproof-lab/test/lib.test.ts
  • example-apps/dashproof-lab/src/components/HistoryPanel.tsx
  • example-apps/dashproof-lab/src/hooks/useTheme.ts

Comment thread example-apps/dashproof-lab/CLAUDE.md Outdated
Comment thread example-apps/dashproof-lab/e2e/fixtures.ts
Comment thread example-apps/dashproof-lab/src/dash/contract.ts
Comment thread example-apps/dashproof-lab/src/lib/format.ts Outdated
Comment thread example-apps/dashproof-lab/src/lib/format.ts
Comment thread example-apps/dashproof-lab/test/OperationResultNotice.test.tsx
truncateId used `head * 2` as the short-circuit threshold but always sliced
a fixed 8-char tail, so e.g. truncateId("ABCDEFGHI", 4) emitted a 13-char
string from a 9-char input. Add an explicit `tail` parameter that drives
both the threshold and the slice.

Also clarify CLAUDE.md: src/dash/ modules can export tightly-related helpers
alongside their SDK wrapper, and the test/ directory is intentionally flat
(not mirrored against src/) so future reviewers don't suggest colocation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@example-apps/dashproof-lab/CLAUDE.md`:
- Line 32: The document uses two spellings for the same term ("colocated" and
"co-located"); pick one spelling (e.g., "co-located") and update all occurrences
in CLAUDE.md to that spelling so terminology is consistent—search for the tokens
"colocated" and "co-located" and replace them uniformly (ensure phrases like
"not colocated next to source files" are updated to the chosen form).
🪄 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: 20936f6a-ea0c-47f4-8f91-865eef06fc69

📥 Commits

Reviewing files that changed from the base of the PR and between 9677608 and 2dbf9c5.

📒 Files selected for processing (4)
  • example-apps/dashproof-lab/CLAUDE.md
  • example-apps/dashproof-lab/src/lib/format.ts
  • example-apps/dashproof-lab/test/HistoryPanel.test.tsx
  • example-apps/dashproof-lab/test/lib.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • example-apps/dashproof-lab/test/HistoryPanel.test.tsx
  • example-apps/dashproof-lab/src/lib/format.ts
  • example-apps/dashproof-lab/test/lib.test.ts

Comment thread example-apps/dashproof-lab/CLAUDE.md Outdated
…ailures

Reading localStorage can throw SecurityError in sandboxed iframes or strict
cookie configurations. SessionProvider boots from loadStoredContractId, so
an uncaught throw would white-screen the app — fall back to
DEFAULT_CONTRACT_ID instead. Writes (save/clear) are intentionally left
unguarded so quota/permission failures still surface in the LoginModal
error UI rather than silently dropping a freshly-registered contract ID.

Also normalize "colocated" → "co-located" in CLAUDE.md for consistent
terminology.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@thephez thephez merged commit 7c981f3 into main Apr 29, 2026
3 checks passed
@thephez thephez deleted the feat/example-app-dashproof branch April 29, 2026 19:40
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