feat(ui): add error boundaries and error utilities - #325
Conversation
- Add root error boundary (app/error.tsx) for global error handling - Add dashboard error boundary (app/dashboard/error.tsx) - Add errorUtils.ts with logError, logForDebugging, Result type - Provides consistent error handling patterns for the UI 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds two client-side React error UIs (dashboard-level and root-level) and a new error utilities module that provides logging helpers, a Result type with ok/err constructors, and a status-code-to-message helper. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| <html> | ||
| <body className="min-h-screen bg-void flex items-center justify-center p-6"> |
There was a problem hiding this comment.
Remove html/body wrapper in app error boundary
app/error.tsx wraps the error UI in <html><body> (lines 18-19), but App Router error.tsx components are rendered inside the nearest layout. Returning full document tags produces nested <html>/<body> when any runtime error occurs, leading to invalid markup and hydration failures instead of a reliable fallback screen. Use the segment layout (or move this markup to global-error.tsx) so the boundary can render correctly.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
pmoves/ui/app/error.tsx (1)
24-25: Consider usinggetErrorMessagefor user-friendly error display.Directly exposing
error.messagemay leak technical implementation details to users. Since this PR introducesgetErrorMessageinerrorUtils.tsfor user-friendly messages, consider using it when the error includes an HTTP status, or provide a more generic fallback.pmoves/ui/app/dashboard/error.tsx (1)
26-27: Consider generic fallback for error messages.Directly exposing
error.messagemay reveal technical details. Consider providing a more generic fallback message for production.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
pmoves/ui/app/dashboard/error.tsx(1 hunks)pmoves/ui/app/error.tsx(1 hunks)pmoves/ui/lib/errorUtils.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
pmoves/ui/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (pmoves/AGENTS.md)
UI updates: run
make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>"to lint the Next.js bundle and validate Supabase connectivity; referencepmoves/docs/UI_NOTEBOOK_WORKBENCH.md
Files:
pmoves/ui/app/error.tsxpmoves/ui/lib/errorUtils.tspmoves/ui/app/dashboard/error.tsx
🧠 Learnings (1)
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/ui/**/*.{js,jsx,ts,tsx} : UI updates: run `make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>"` to lint the Next.js bundle and validate Supabase connectivity; reference `pmoves/docs/UI_NOTEBOOK_WORKBENCH.md`
Applied to files:
pmoves/ui/app/error.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (python)
🔇 Additional comments (6)
pmoves/ui/app/dashboard/error.tsx (1)
36-41: LGTM: Good UX for dashboard recovery.The "Back to Dashboard" link provides a clear escape path if the reset fails, improving user experience.
pmoves/ui/lib/errorUtils.ts (4)
19-27: LGTM: Debug logging properly gated.The function correctly restricts debug logging to development or when explicitly enabled via flag.
33-52: LGTM: Production-ready error logging with Sentry preparation.The error normalization and TODO comment for Sentry integration are well-structured. The function provides a solid foundation for production error tracking.
58-74: LGTM: Clean Result type implementation.The Result type and constructor functions follow established patterns for functional error handling. This provides a good alternative to throwing exceptions for expected failures.
79-92: LGTM: Comprehensive HTTP status messages.The function covers common HTTP status codes with user-friendly messages and provides a sensible default fallback.
pmoves/ui/app/error.tsx (1)
1-37: Verify Next.js bundle and Supabase connectivity.As per coding guidelines for UI updates, please run the smoke test to validate the Next.js bundle and Supabase connectivity:
make -C pmoves notebook-workbench-smoke ARGS="--thread=$(uuidgen)"Reference:
pmoves/docs/UI_NOTEBOOK_WORKBENCH.md
| useEffect(() => { | ||
| // Log to error reporting service | ||
| console.error('[GlobalError]', error); | ||
| }, [error]); |
There was a problem hiding this comment.
Use the new error utilities and avoid logging sensitive data.
The comment indicates this should "Log to error reporting service," but it only uses console.error. Since this PR introduces errorUtils.ts with a production-ready logError function, import and use it here for consistency. Additionally, logging the entire error object could expose sensitive data like user identifiers or PII.
🔎 Apply this diff to use errorUtils and avoid PII exposure:
'use client';
import { useEffect } from 'react';
+import { logError } from '@/lib/errorUtils';
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
- // Log to error reporting service
- console.error('[GlobalError]', error);
+ // Log to error reporting service (sanitized)
+ logError('Global error boundary caught an error', error, 'critical', {
+ component: 'GlobalError',
+ digest: error.digest,
+ });
}, [error]);Based on coding guidelines: avoid logging sensitive data like user identifiers.
📝 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.
| useEffect(() => { | |
| // Log to error reporting service | |
| console.error('[GlobalError]', error); | |
| }, [error]); | |
| 'use client'; | |
| import { useEffect } from 'react'; | |
| import { logError } from '@/lib/errorUtils'; | |
| export default function GlobalError({ | |
| error, | |
| reset, | |
| }: { | |
| error: Error & { digest?: string }; | |
| reset: () => void; | |
| }) { | |
| useEffect(() => { | |
| // Log to error reporting service (sanitized) | |
| logError('Global error boundary caught an error', error, 'critical', { | |
| component: 'GlobalError', | |
| digest: error.digest, | |
| }); | |
| }, [error]); |
🤖 Prompt for AI Agents
In pmoves/ui/app/error.tsx around lines 12 to 15, replace the console.error call
with the project's errorUtils logError function and stop logging the full error
object to avoid PII exposure: import logError from the errorUtils module, call
logError with a sanitized payload (e.g., an object containing only non-sensitive
fields such as error.message, a truncated stack, and minimal context like
component name or action) and remove the direct console.error; ensure any user
identifiers or full error objects are omitted or redacted before passing to
logError.
| interface ErrorContext { | ||
| component?: string; | ||
| action?: string; | ||
| userId?: string; | ||
| [key: string]: unknown; | ||
| } |
There was a problem hiding this comment.
Remove userId from ErrorContext to prevent PII logging.
The userId field in ErrorContext could lead to logging user identifiers, which is flagged in the coding guidelines as a compliance/privacy risk. Even with the Sentry integration commented out, this field creates a path for PII to be logged. Consider removing it or renaming it to something more abstract like userSessionId (if the actual ID is anonymized).
🔎 Apply this diff to remove the userId field:
interface ErrorContext {
component?: string;
action?: string;
- userId?: string;
[key: string]: unknown;
}Based on coding guidelines: avoid logging sensitive data like user identifiers.
📝 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.
| interface ErrorContext { | |
| component?: string; | |
| action?: string; | |
| userId?: string; | |
| [key: string]: unknown; | |
| } | |
| interface ErrorContext { | |
| component?: string; | |
| action?: string; | |
| [key: string]: unknown; | |
| } |
🤖 Prompt for AI Agents
In pmoves/ui/lib/errorUtils.ts around lines 8 to 13, the ErrorContext interface
currently exposes a userId property which risks logging PII; remove the userId
field from the interface and, if you need to preserve an identifier, replace it
with a non-PII alternative like userSessionId (only after ensuring it is
anonymized), then update all usages: remove passing raw user IDs, update any
Sentry or logging calls to use the new anonymized key or omit it, and adjust
types/tests accordingly so no code still expects userId.
- Use logError() instead of console.error() for production visibility - Remove html/body tags from root error boundary (not global-error.tsx) - Add role="alert" and aria-live for accessibility - Add aria-hidden="true" to decorative icon - Add error context (component, digest) to log calls 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
pmoves/ui/app/error.tsx (2)
6-18: Error logging implementation looks good.The use of
logErrorwith 'critical' severity and contextual metadata (component name, digest) is appropriate for a root-level error boundary.💡 Optional: Consider aligning the context component name with the function name
Line 15 uses
'RootErrorBoundary'but the function is namedRootError. For consistency:- component: 'RootErrorBoundary', + component: 'RootError',
23-23: Consider whetheraria-live="assertive"is the right choice.
assertiveimmediately interrupts screen readers, which is appropriate for critical, time-sensitive alerts. For a root-level error boundary this may be justified, butaria-live="polite"would be less disruptive while still announcing the error.This is a UX/accessibility trade-off: use
"assertive"if you want to ensure users are immediately aware of the error, or"polite"for a less intrusive experience.pmoves/ui/app/dashboard/error.tsx (1)
7-19: Error logging implementation is correct.Using 'error' severity (rather than 'critical') is appropriate for a dashboard-level boundary. The past review feedback has been addressed.
💡 Optional: Consider aligning the context component name with the function name
Similar to the root error boundary, line 16 uses
'DashboardErrorBoundary'but the function is namedDashboardError:- component: 'DashboardErrorBoundary', + component: 'DashboardError',
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
pmoves/ui/app/dashboard/error.tsx(1 hunks)pmoves/ui/app/error.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
pmoves/ui/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (pmoves/AGENTS.md)
UI updates: run
make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>"to lint the Next.js bundle and validate Supabase connectivity; referencepmoves/docs/UI_NOTEBOOK_WORKBENCH.md
Files:
pmoves/ui/app/error.tsxpmoves/ui/app/dashboard/error.tsx
🧬 Code graph analysis (2)
pmoves/ui/app/error.tsx (1)
pmoves/ui/lib/errorUtils.ts (1)
logError(33-52)
pmoves/ui/app/dashboard/error.tsx (1)
pmoves/ui/lib/errorUtils.ts (1)
logError(33-52)
🔇 Additional comments (3)
pmoves/ui/app/error.tsx (1)
1-4: LGTM!The imports are correct, and the past review feedback about using
logErrorfrom errorUtils has been properly addressed.pmoves/ui/app/dashboard/error.tsx (2)
1-5: LGTM!The imports are correct. The past review feedback about using
logErrorhas been properly addressed.
40-53: LGTM!Providing both a retry action and a navigation option (Back to Dashboard) offers good user experience and appropriate escape routes for dashboard-level errors.
| <p className="text-ink-muted mb-6 text-sm"> | ||
| {error.message || 'Failed to load this section'} | ||
| </p> |
There was a problem hiding this comment.
Displaying raw error messages exposes sensitive information.
Line 38 renders error.message directly to users, which can expose database details, API errors, internal paths, or stack traces in production. This is the same security/UX concern as in the root error boundary.
🔎 Apply this diff to show a generic message and optionally include the digest:
- <p className="text-ink-muted mb-6 text-sm">
- {error.message || 'Failed to load this section'}
- </p>
+ <p className="text-ink-muted mb-6 text-sm">
+ Failed to load this section. Please try again or return to the dashboard.
+ </p>
+ {error.digest && (
+ <p className="text-xs text-ink-muted/70 mb-6 font-mono">
+ Error ID: {error.digest}
+ </p>
+ )}The full error details are logged via logError for debugging. Users should see a friendly message, and the digest can help support teams look up details in logs.
🤖 Prompt for AI Agents
In pmoves/ui/app/dashboard/error.tsx around lines 37 to 39, the code currently
renders error.message directly which can expose sensitive internal details;
replace that direct rendering with a generic user-facing message like "Something
went wrong loading this section." and optionally render a nondisclosing digest
or ticket id (e.g. error.digest) instead of the raw message; ensure any
displayed digest is precomputed/sanitized and do not render stack traces or raw
error fields, while keeping the full error logged via logError for debugging.
| <p className="text-ink-muted mb-6"> | ||
| {error.message || 'An unexpected error occurred'} | ||
| </p> |
There was a problem hiding this comment.
Displaying raw error messages exposes sensitive information.
Line 37 renders error.message directly to users. In production, error messages can contain database schema details, API endpoints, internal paths, or stack traces. This exposes implementation details and creates a poor user experience.
🔎 Apply this diff to show a generic message and optionally include the digest for support:
- <p className="text-ink-muted mb-6">
- {error.message || 'An unexpected error occurred'}
- </p>
+ <p className="text-ink-muted mb-6">
+ An unexpected error occurred. Please try again or contact support if the problem persists.
+ </p>
+ {error.digest && (
+ <p className="text-xs text-ink-muted/70 mb-6 font-mono">
+ Error ID: {error.digest}
+ </p>
+ )}The error details are already being logged via logError for debugging purposes. Users should see a friendly message while support teams can reference the digest to look up full details in logs.
📝 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.
| <p className="text-ink-muted mb-6"> | |
| {error.message || 'An unexpected error occurred'} | |
| </p> | |
| <p className="text-ink-muted mb-6"> | |
| An unexpected error occurred. Please try again or contact support if the problem persists. | |
| </p> | |
| {error.digest && ( | |
| <p className="text-xs text-ink-muted/70 mb-6 font-mono"> | |
| Error ID: {error.digest} | |
| </p> | |
| )} |
🤖 Prompt for AI Agents
In pmoves/ui/app/error.tsx around lines 36 to 38, do not render raw
error.message to users; replace the direct message with a generic, user-friendly
sentence (e.g., "Something went wrong. Please contact support.") and optionally
display a short error digest or ID (compute a stable hash or short fingerprint
of the error + timestamp/server-id) so support can correlate with logs; continue
logging full error details via existing logError, and ensure no internal details
or stack traces are exposed to the UI.
- Add UI Development Checklist section to CLAUDE.md with security, privacy, accessibility, and code quality guidelines - Create ui-patterns.md context doc with error handling, authentication, and accessibility patterns from PRs #325, #326, #327 - Document CodeRabbit review learnings for future reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update status date to 2025-12-18 - Add Prosodic TTS sidecar (PR #328): boundary-aware chunking, TTFS optimization - Add Pipecat multimodal layer Phase 1 (PR #332): STT/LLM/TTS processors - Add Flute Gateway Voice Agent Infrastructure section with API examples - Document UI security hardening (PRs #325-331) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(ui): add error boundaries and error utilities - Add root error boundary (app/error.tsx) for global error handling - Add dashboard error boundary (app/dashboard/error.tsx) - Add errorUtils.ts with logError, logForDebugging, Result type - Provides consistent error handling patterns for the UI 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address PR review feedback for error boundaries - Use logError() instead of console.error() for production visibility - Remove html/body tags from root error boundary (not global-error.tsx) - Add role="alert" and aria-live for accessibility - Add aria-hidden="true" to decorative icon - Add error context (component, digest) to log calls 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add UI Development Checklist section to CLAUDE.md with security, privacy, accessibility, and code quality guidelines - Create ui-patterns.md context doc with error handling, authentication, and accessibility patterns from PRs #325, #326, #327 - Document CodeRabbit review learnings for future reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(ui): implement cohesive design system for console (#324) * feat(ui): implement cohesive design system for console - Add card-brutal and card-glass component styles - Implement Cataclysm color palette (cyan, forest, ember, violet, gold) - Introduce DashboardShell layout component - Update login page with split branding layout - Modernize dashboard pages with consistent typography - Fix JSX conditional rendering in ingestion-queue - Add CSS variables and utility classes in globals.css - Extend Tailwind config with design tokens 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): add missing heading-serif class and improve focus accessibility - Add heading-serif CSS class used in login page - Add focus:ring-2 focus:ring-cata-cyan/30 to form inputs for WCAG 2.1 AA compliance - Add focus ring to OAuth provider buttons Addresses critical issues from PR #324 code review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * feat(ui): add error boundaries and error utilities (#325) * feat(ui): add error boundaries and error utilities - Add root error boundary (app/error.tsx) for global error handling - Add dashboard error boundary (app/dashboard/error.tsx) - Add errorUtils.ts with logError, logForDebugging, Result type - Provides consistent error handling patterns for the UI 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address PR review feedback for error boundaries - Use logError() instead of console.error() for production visibility - Remove html/body tags from root error boundary (not global-error.tsx) - Add role="alert" and aria-live for accessibility - Add aria-hidden="true" to decorative icon - Add error context (component, digest) to log calls 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): resolve ESLint set-state-in-effect error in chat page Move setStatus('connecting') inside async function to avoid calling setState synchronously in useEffect body. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test(ui): update tests for new design system - Add usePathname mock to services-pages Jest test - Use getAllByRole for multiple service links in Jest - Use .first() locator in Playwright E2E tests - Update ingest test to look for "ingest" instead of "ingestion dashboard" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): accessibility improvements and Tailwind JIT compliance (#327) * fix(ui): accessibility improvements and Tailwind JIT compliance - Add skip link for keyboard navigation (WCAG 2.1 AA) - Add id="main-content" to DashboardShell main element - Fix dynamic Tailwind class generation in services/page.tsx: - Replace `tag tag-${color}` with TAG_CLASSES lookup - Replace complex ternary bg class with ICON_BG_CLASSES lookup - Extract colorClasses to module-level BORDER_CLASSES constant - Fix misleading comment in globals.css (heading-serif uses sans-serif font) Fixes accessibility and design consistency issues from PR #324 review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: remove focus:outline-none for WCAG 2.4.7 compliance Skip link now has visible focus outline (focus:outline-2) instead of hiding it. The cyan background provides primary feedback, but the outline ensures compliance with WCAG 2.4.7 Focus Visible requirement. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(a11y): improve skip link accessibility compliance - Add focus:outline-void for visible outline against cyan background - Add tabIndex={-1} to main-content for proper skip link focus - Correct WCAG reference: SC 2.4.1 Bypass Blocks is Level A, not AA - Add cross-reference comment linking skip target to layout.tsx 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui/chat): eliminate silent failures and preserve input on error (#326) * fix(ui/chat): eliminate silent failures and preserve input on error - API routes: Return 401 with error message instead of empty array on auth failure - API routes: Add JWT parsing error logging for debugging - fetchMessages: Return {data, error} pattern instead of silent empty array - sendMessage: Check response status and return {ok, error} - handleSend: Only clear input after successful send (preserve on failure) - Add error banner UI to show API errors to users - Add sending state with disabled UI during request Fixes silent failure issues identified in PR #324 review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address PR review feedback for chat error handling - Use logError() instead of logForDebugging() in JWT catch blocks - Add explicit JSON parsing error handling with logging - Add database error logging with sanitized client messages - Fix field name mismatch: agent_id → agent 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): add defensive error handling to client-side chat code - Replace `.catch(() => ({}))` with explicit try-catch blocks in fetchMessages and sendMessage for proper error logging - Wrap realtime subscription callbacks (onInsert/onUpdate/onDelete) in try-catch to prevent silent failures - Replace console.error with logForDebugging for consistent logging - Add component and context metadata to all error logs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(api): use consistent 401 status for authentication failures Changed missing owner ID response from 400 to 401 in /api/chat/send to match /api/chat/messages behavior. Both endpoints now return 401 Unauthorized when authentication is required. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * refactor(ui): extract ownerFromJwt to shared lib/jwtUtils.ts (#330) DRY fix - extracts duplicate JWT parsing logic to shared utility: - Create lib/jwtUtils.ts with proper base64url decoding (RFC 4648) - Update chat/send/route.ts to use shared ownerFromJwt - Update chat/messages/route.ts to use shared ownerFromJwt - Add component parameter for contextual error logging The shared implementation fixes base64url encoding by replacing '-' with '+' and '_' with '/' before decoding, and handles padding correctly per RFC 4648. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * feat(ui): add structured JSON logging for Loki observability (#331) Wire logError() to emit structured JSON for Loki/Promtail ingestion: - Add StructuredLogEntry interface for consistent log format - Add emitStructuredLog() helper for env-aware output - Production: JSON to stdout (Promtail picks up via docker logs) - Development: Colorized console output for debugging - Remove Sentry TODO comment (using self-hosted Loki instead) Log format includes: timestamp, level, message, error details, component, action, and full context for searchability in Grafana. No new infrastructure needed - uses existing Loki/Promtail stack. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix(security): remove client-provided ownerId bypass in API routes (#329) * fix(security): remove client-provided ownerId bypass in API routes CRITICAL SECURITY FIX - Removes authentication bypass vulnerabilities: - uploads/presign: Remove body.ownerId fallback, require session auth - uploads/persist: Remove body.ownerId fallback, require session auth - chat/send: Remove body.ownerId fallback, use JWT only - chat/messages: Remove query param ownerId fallback, use JWT only User identity must now come exclusively from authenticated JWT tokens, preventing IDOR (Insecure Direct Object Reference) attacks where attackers could access or modify resources by supplying arbitrary owner IDs in request bodies or query parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: remove unused logForDebugging import 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * docs: add UI development checklist and patterns from CodeRabbit review - Add UI Development Checklist section to CLAUDE.md with security, privacy, accessibility, and code quality guidelines - Create ui-patterns.md context doc with error handling, authentication, and accessibility patterns from PRs #325, #326, #327 - Document CodeRabbit review learnings for future reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address CodeRabbit review nitpicks from PR #321 - deepresearch/worker.py: Use _env_bool helper for CGP_PUBLISH_ENABLED, move datetime import to module level - supaserch/app.py: Replace nested ternary with status_proj_map dict - publisher-discord/main.py: Add _safe_format_number helper for defensive numeric formatting in CHIT event handlers - geometry-nats-subjects.md: Add 'text' language identifier to code block 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat(ui): implement cohesive design system for console (#324) * feat(ui): implement cohesive design system for console - Add card-brutal and card-glass component styles - Implement Cataclysm color palette (cyan, forest, ember, violet, gold) - Introduce DashboardShell layout component - Update login page with split branding layout - Modernize dashboard pages with consistent typography - Fix JSX conditional rendering in ingestion-queue - Add CSS variables and utility classes in globals.css - Extend Tailwind config with design tokens 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): add missing heading-serif class and improve focus accessibility - Add heading-serif CSS class used in login page - Add focus:ring-2 focus:ring-cata-cyan/30 to form inputs for WCAG 2.1 AA compliance - Add focus ring to OAuth provider buttons Addresses critical issues from PR #324 code review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * feat(ui): add error boundaries and error utilities (#325) * feat(ui): add error boundaries and error utilities - Add root error boundary (app/error.tsx) for global error handling - Add dashboard error boundary (app/dashboard/error.tsx) - Add errorUtils.ts with logError, logForDebugging, Result type - Provides consistent error handling patterns for the UI 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address PR review feedback for error boundaries - Use logError() instead of console.error() for production visibility - Remove html/body tags from root error boundary (not global-error.tsx) - Add role="alert" and aria-live for accessibility - Add aria-hidden="true" to decorative icon - Add error context (component, digest) to log calls 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): resolve ESLint set-state-in-effect error in chat page Move setStatus('connecting') inside async function to avoid calling setState synchronously in useEffect body. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test(ui): update tests for new design system - Add usePathname mock to services-pages Jest test - Use getAllByRole for multiple service links in Jest - Use .first() locator in Playwright E2E tests - Update ingest test to look for "ingest" instead of "ingestion dashboard" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): accessibility improvements and Tailwind JIT compliance (#327) * fix(ui): accessibility improvements and Tailwind JIT compliance - Add skip link for keyboard navigation (WCAG 2.1 AA) - Add id="main-content" to DashboardShell main element - Fix dynamic Tailwind class generation in services/page.tsx: - Replace `tag tag-${color}` with TAG_CLASSES lookup - Replace complex ternary bg class with ICON_BG_CLASSES lookup - Extract colorClasses to module-level BORDER_CLASSES constant - Fix misleading comment in globals.css (heading-serif uses sans-serif font) Fixes accessibility and design consistency issues from PR #324 review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: remove focus:outline-none for WCAG 2.4.7 compliance Skip link now has visible focus outline (focus:outline-2) instead of hiding it. The cyan background provides primary feedback, but the outline ensures compliance with WCAG 2.4.7 Focus Visible requirement. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(a11y): improve skip link accessibility compliance - Add focus:outline-void for visible outline against cyan background - Add tabIndex={-1} to main-content for proper skip link focus - Correct WCAG reference: SC 2.4.1 Bypass Blocks is Level A, not AA - Add cross-reference comment linking skip target to layout.tsx 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui/chat): eliminate silent failures and preserve input on error (#326) * fix(ui/chat): eliminate silent failures and preserve input on error - API routes: Return 401 with error message instead of empty array on auth failure - API routes: Add JWT parsing error logging for debugging - fetchMessages: Return {data, error} pattern instead of silent empty array - sendMessage: Check response status and return {ok, error} - handleSend: Only clear input after successful send (preserve on failure) - Add error banner UI to show API errors to users - Add sending state with disabled UI during request Fixes silent failure issues identified in PR #324 review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address PR review feedback for chat error handling - Use logError() instead of logForDebugging() in JWT catch blocks - Add explicit JSON parsing error handling with logging - Add database error logging with sanitized client messages - Fix field name mismatch: agent_id → agent 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): add defensive error handling to client-side chat code - Replace `.catch(() => ({}))` with explicit try-catch blocks in fetchMessages and sendMessage for proper error logging - Wrap realtime subscription callbacks (onInsert/onUpdate/onDelete) in try-catch to prevent silent failures - Replace console.error with logForDebugging for consistent logging - Add component and context metadata to all error logs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(api): use consistent 401 status for authentication failures Changed missing owner ID response from 400 to 401 in /api/chat/send to match /api/chat/messages behavior. Both endpoints now return 401 Unauthorized when authentication is required. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * refactor(ui): extract ownerFromJwt to shared lib/jwtUtils.ts (#330) DRY fix - extracts duplicate JWT parsing logic to shared utility: - Create lib/jwtUtils.ts with proper base64url decoding (RFC 4648) - Update chat/send/route.ts to use shared ownerFromJwt - Update chat/messages/route.ts to use shared ownerFromJwt - Add component parameter for contextual error logging The shared implementation fixes base64url encoding by replacing '-' with '+' and '_' with '/' before decoding, and handles padding correctly per RFC 4648. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * feat(ui): add structured JSON logging for Loki observability (#331) Wire logError() to emit structured JSON for Loki/Promtail ingestion: - Add StructuredLogEntry interface for consistent log format - Add emitStructuredLog() helper for env-aware output - Production: JSON to stdout (Promtail picks up via docker logs) - Development: Colorized console output for debugging - Remove Sentry TODO comment (using self-hosted Loki instead) Log format includes: timestamp, level, message, error details, component, action, and full context for searchability in Grafana. No new infrastructure needed - uses existing Loki/Promtail stack. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix(security): remove client-provided ownerId bypass in API routes (#329) * fix(security): remove client-provided ownerId bypass in API routes CRITICAL SECURITY FIX - Removes authentication bypass vulnerabilities: - uploads/presign: Remove body.ownerId fallback, require session auth - uploads/persist: Remove body.ownerId fallback, require session auth - chat/send: Remove body.ownerId fallback, use JWT only - chat/messages: Remove query param ownerId fallback, use JWT only User identity must now come exclusively from authenticated JWT tokens, preventing IDOR (Insecure Direct Object Reference) attacks where attackers could access or modify resources by supplying arbitrary owner IDs in request bodies or query parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: remove unused logForDebugging import 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * docs: add UI development checklist and patterns from CodeRabbit review - Add UI Development Checklist section to CLAUDE.md with security, privacy, accessibility, and code quality guidelines - Create ui-patterns.md context doc with error handling, authentication, and accessibility patterns from PRs #325, #326, #327 - Document CodeRabbit review learnings for future reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address CodeRabbit review nitpicks from PR #321 - deepresearch/worker.py: Use _env_bool helper for CGP_PUBLISH_ENABLED, move datetime import to module level - supaserch/app.py: Replace nested ternary with status_proj_map dict - publisher-discord/main.py: Add _safe_format_number helper for defensive numeric formatting in CHIT event handlers - geometry-nats-subjects.md: Add 'text' language identifier to code block 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat(ui): add error boundaries and error utilities - Add root error boundary (app/error.tsx) for global error handling - Add dashboard error boundary (app/dashboard/error.tsx) - Add errorUtils.ts with logError, logForDebugging, Result type - Provides consistent error handling patterns for the UI 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address PR review feedback for error boundaries - Use logError() instead of console.error() for production visibility - Remove html/body tags from root error boundary (not global-error.tsx) - Add role="alert" and aria-live for accessibility - Add aria-hidden="true" to decorative icon - Add error context (component, digest) to log calls 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add UI Development Checklist section to CLAUDE.md with security, privacy, accessibility, and code quality guidelines - Create ui-patterns.md context doc with error handling, authentication, and accessibility patterns from PRs #325, #326, #327 - Document CodeRabbit review learnings for future reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update status date to 2025-12-18 - Add Prosodic TTS sidecar (PR #328): boundary-aware chunking, TTFS optimization - Add Pipecat multimodal layer Phase 1 (PR #332): STT/LLM/TTS processors - Add Flute Gateway Voice Agent Infrastructure section with API examples - Document UI security hardening (PRs #325-331) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add two-stage workflow for secure Claude reviews on forked PRs
Summary
app/error.tsx) for global error catchingapp/dashboard/error.tsx) for dashboard-specific errorserrorUtils.tswith:logError()- Production error logging (Sentry-ready)logForDebugging()- Development-only debug loggingResult<T, E>type for error handling without throwinggetErrorMessage()- User-friendly HTTP status messagesTest plan
Related
Part of PR review fixes (silent failure handling)
🤖 Generated with Claude Code
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.