Skip to content

feat: use cases#4100

Open
NathanFlurry wants to merge 5 commits intographite-base/4100from
02-03-feat_use_cases
Open

feat: use cases#4100
NathanFlurry wants to merge 5 commits intographite-base/4100from
02-03-feat_use_cases

Conversation

@NathanFlurry
Copy link
Member

Description

Please include a summary of the changes and the related issue. Please also include relevant motivation and context.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Copy link
Member Author

NathanFlurry commented Feb 3, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more


How to use the Graphite Merge Queue

Add the label merge-queue to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@NathanFlurry NathanFlurry changed the base branch from actor-messages to graphite-base/4100 February 3, 2026 19:40
@NathanFlurry NathanFlurry changed the base branch from graphite-base/4100 to 01-02-feat_rivetkit_workflows February 3, 2026 19:40
@claude
Copy link

claude bot commented Feb 3, 2026

PR Review: Use Cases Examples

Overview

This PR reorganizes the examples directory by removing ai-agent and multi-region examples (with tests) and adding four new use-case examples with both local and Vercel versions.

Total changes: 124 files (+9168/-1283)

Code Quality & Best Practices

Strengths

  1. Consistent architecture - all examples follow the actor pattern correctly
  2. Good documentation with clear READMEs and code comments
  3. Proper Vercel parity with appropriate adapters

Critical Issues

1. Missing Tests

The PR removes tests from ai-agent and multi-region but adds no tests for the new examples. This is inconsistent with other examples in the repo which have comprehensive test coverage.

Recommendation: Add test files for each example covering actor creation, action invocations, queue processing, collision detection, and Yjs document sync.

2. Type Safety Issues

  • multiplayer-game-vercel/src/actors.ts:237 uses any for the client type
  • agent-orchestration/src/actors.ts:64 uses unsafe type assertion

3. Security Concerns

  • No length validation on titles, names, or sender fields (DoS risk)
  • No sanitization of user inputs
  • Recommendations:
    • title.trim().slice(0, 100) || "Untitled document"
    • name.trim().slice(0, 20) || "Player"

4. Error Handling

  • agent-orchestration doesn't log errors properly
  • multiplayer-game has no validation for invalid inputs (negative dx/dy, NaN)
  • No bounds validation on player count before join

5. Performance Issues

  • multiplayer-game broadcasts full game state on every move (inefficient)
  • collaborative-document writes to KV on every update without debouncing

6. Missing Error Cases

  • deleteDocument doesn't actually destroy actors (resource leak)
  • join returns null without error message when room is full

7. Code Style

Multiple files have incomplete comment sentences, violating CLAUDE.md guidelines.

Recommendations

Must Fix (Blocking)

  1. Add comprehensive test coverage for all new examples
  2. Fix type safety issues (remove any types)
  3. Add input validation for security (length limits, sanitization)
  4. Fix deleteDocument to actually destroy actors

Should Fix

  1. Improve error handling and logging
  2. Add missing error cases and proper error responses
  3. Fix performance issues (broadcast throttling, KV write debouncing)
  4. Follow CLAUDE.md comment style guidelines

Nice to Have

  1. Add configuration for timeouts and limits
  2. Add architecture documentation
  3. Consider extracting common utilities

Conclusion

The examples demonstrate good use of Rivet Actors patterns and provide valuable real-world use cases. However, the lack of tests is a critical gap that should be addressed before merging.

Recommendation: Request changes to add tests and fix critical issues before merging.

@claude
Copy link

claude bot commented Feb 3, 2026

Pull Request Review

This PR introduces new use-case focused examples by reorganizing and renaming existing examples. The changes are mostly well-structured, but there are several areas that need attention before merging.


🔴 Critical Issues

1. Missing Test Coverage for New Examples

Most of the new examples lack test files:

  • agent-orchestration - no tests
  • collaborative-document - no tests
  • geo-distributed-database - no tests
  • multiplayer-game - no tests
  • per-tenant-database - has tests

Recommendation: According to the codebase testing practices, each example should have basic test coverage. At minimum, add integration tests similar to per-tenant-database/tests/per-tenant-database.test.ts for the other examples.

2. Timestamp Naming Convention Violation

In examples/per-tenant-database/src/actors.ts, timestamps don't follow the required naming convention from CLAUDE.md:

// Lines 8, 22-23, 30-32
created_at: number;  // ✅ Correct
updated_at: number;  // ✅ Correct

But in geo-distributed-database/src/actors.ts:

// Lines 8, 10
lastLoginAt: number;  // ❌ Should be last_login_at

Action Required: Rename lastLoginAt to last_login_at throughout geo-distributed-database/src/actors.ts (lines 8, 10, 35, 68).


⚠️ Code Quality & Best Practices

3. Error Handling in Agent Orchestration

In agent-orchestration/src/actors.ts:135-159, the error handling catches and broadcasts errors but doesn't use proper logging:

} catch (error) {
    const errorMessage = error instanceof Error ? error.message : "Unknown error";
    // No tracing/logging here

Recommendation: Add structured logging using tracing as mentioned in CLAUDE.md:

} catch (error) {
    tracing::error!(?error, "failed to stream AI response");
    const errorMessage = error instanceof Error ? error.message : "Unknown error";

4. Queue Timeout Inconsistency

In agent-orchestration/src/actors.ts:59:

const queued = await c.queue.next("message", { timeout: 30000 });

The 30-second timeout is hardcoded without explanation. Consider:

  • Adding a constant: const QUEUE_TIMEOUT_MS = 30000;
  • Documenting why 30 seconds was chosen
  • Making it configurable if appropriate

5. Missing Input Validation

Multiple actors accept user input without proper validation:

multiplayer-game/src/actors.ts:122-143:

join: async (c, name: string): Promise<JoinResult | null> => {
    // No validation that 'name' is a reasonable length or contains safe characters
    const player = createPlayer(playerId, name);

Recommendation: Add input validation:

join: async (c, name: string): Promise<JoinResult | null> => {
    const sanitizedName = name.trim().slice(0, 50); // Limit length
    if (!sanitizedName) {
        return null; // Reject empty names
    }
    const player = createPlayer(playerId, sanitizedName);

🟡 Performance Considerations

6. Inefficient Collision Detection

In multiplayer-game/src/actors.ts:190-235, the collision detection uses nested loops with O(n²) complexity:

for (let i = 0; i < ordered.length; i++) {
    for (let j = ordered.length - 1; j > i; j--) {
        const distance = Math.hypot(eater.x - target.x, eater.y - target.y);

For 10 players (MAX_PLAYERS), this is fine, but the algorithm doesn't scale. Consider:

  • Adding a comment explaining the O(n²) complexity is acceptable for small player counts
  • Documenting the MAX_PLAYERS constraint more clearly
  • If MAX_PLAYERS increases, consider spatial partitioning (quadtree)

7. Missing Cleanup in Collaborative Document

In collaborative-document/src/actors.ts:36-45, the Yjs document and awareness are created but never explicitly cleaned up:

createVars: async (c) => {
    const doc = new Y.Doc();
    const stored = await c.kv.get("yjs:doc", { type: "binary" });
    if (stored) {
        Y.applyUpdate(doc, stored);
    }
    const awareness = new Awareness(doc);
    return { doc, awareness };
},

Recommendation: Add cleanup to prevent memory leaks if actors are destroyed. Consider adding an onDestroy hook if available in RivetKit.


🔵 Documentation & Style

8. README Link Inconsistencies

The README files use relative GitHub links, but some point to /tree/main/ which may not exist if viewing from a branch:

[src/actors.ts](https://github.com/rivet-dev/rivet/tree/main/examples/agent-orchestration/src/actors.ts)

This is actually correct per CLAUDE.md's EXAMPLE_TEMPLATE.md, so no change needed. ✅

9. Comment Quality Issues

Several comments violate the CLAUDE.md comment guidelines:

agent-orchestration/src/actors.ts:46:

// Persistent state that survives restarts: https://rivet.dev/docs/actors/state

This is fine, but some other comments could be improved:

multiplayer-game/src/actors.ts:47:

// Coordinator actor that tracks active game rooms. https://rivet.dev/docs/actors/design-patterns

Good! These follow the guideline to write complete sentences.


🟢 Positive Aspects

  1. Good actor patterns: The coordinator/worker pattern (e.g., agentManager + agent, matchmaker + gameRoom) demonstrates solid distributed systems design
  2. Proper state management: All actors correctly use state for persistent data and connState for connection-specific data
  3. Broadcasting events: Good use of c.broadcast() for real-time updates
  4. Type safety: Comprehensive TypeScript types throughout
  5. Example parity: Both local and Vercel versions exist for deployability

📋 Summary Checklist

Before merging:

  • Add test coverage for agent-orchestration, collaborative-document, geo-distributed-database, and multiplayer-game
  • Fix timestamp naming: lastLoginAtlast_login_at in geo-distributed-database
  • Add structured logging to error handlers
  • Add input validation for user-provided strings (names, titles)
  • Document queue timeout constant
  • Consider adding cleanup for Yjs documents
  • Add performance constraint comments for collision detection

Verdict

The code quality is generally good with solid architectural patterns, but the lack of test coverage and naming convention violations are blockers. Please address the critical issues before merging.

Estimated effort: ~2-4 hours to add tests and fix naming conventions.

@claude
Copy link

claude bot commented Feb 3, 2026

Pull Request Review: feat: use cases

Overview

This PR introduces several new example use cases and refactors existing examples to better showcase RivetKit capabilities. The changes add ~13K lines and remove ~1.8K lines, primarily focused on examples showcasing real-world patterns.

Summary of Changes

New Examples Added

  1. Collaborative Document - CRDT-based collaborative editing with Yjs
  2. Multiplayer Game - Agar.io-style game with matchmaker pattern
  3. Geo-Distributed Database - User session management with regional data locality

Refactored Examples

  1. AI Agent - Simplified to use queue-driven pattern with streaming responses
  2. Multi-Region - Removed (likely merged into geo-distributed-database)

Code Quality & Best Practices

✅ Strengths

  1. Clean Actor Patterns: All examples follow good RivetKit actor design patterns:

    • Coordinator pattern (matchmaker, agentManager, documentList)
    • Data actors (gameRoom, document, userSession, agent)
    • Proper state management with persistent storage
  2. Type Safety: Strong TypeScript usage throughout with proper type exports and interfaces

  3. Good Documentation: Each example has clear README with features, implementation details, and resource links

  4. Consistent Structure: All examples follow the same project structure making them easy to understand

⚠️ Areas for Improvement

1. Test Coverage Concerns

Issue: Tests were removed from several examples without replacement:

  • examples/ai-agent/tests/ai-agent.test.ts (117 lines deleted)
  • examples/ai-agent-vercel/tests/ai-agent.test.ts (117 lines deleted)
  • examples/multi-region/tests/regions.test.ts (181 lines deleted)
  • vitest.config.ts files removed

Recommendation: While examples may not need comprehensive test suites, consider:

  • Adding at least basic smoke tests to ensure actors start correctly
  • Testing critical paths like message queueing in AI agent
  • Documenting testing strategy in CLAUDE.md if tests are intentionally omitted from examples

Priority: Medium - Examples should demonstrate best practices including testing

2. Error Handling Patterns

AI Agent (examples/ai-agent/src/actors.ts:132-154):

} catch (error) {
    const errorMessage =
        error instanceof Error ? error.message : "Unknown error";

    assistantMessage.content =
        assistantMessage.content ||
        "I hit a snag while responding. Please try again.";

Issues:

  • Silent error handling in production could hide issues
  • No structured logging for debugging
  • Error state stored but not clear if it persists across restarts

Recommendations:

  • Add structured logging: console.error('AI stream failed:', error) or similar
  • Consider exponential backoff for transient failures
  • Document error recovery behavior

Priority: Medium

3. Potential Race Condition in Game Room

File: examples/multiplayer-game/src/actors.ts:108-120

onDisconnect: (c, conn) => {
    const playerId = conn.state.playerId;
    if (!playerId) return;

    if (c.state.players[playerId]) {
        delete c.state.players[playerId];
        c.broadcast("playerLeft", { playerId });
        c.broadcast("gameState", buildGameState(...));
        void reportRoomCount(c);  // <-- Fire-and-forget
    }

Issue: void reportRoomCount(c) is fire-and-forget. If it fails, the matchmaker's room count will be stale.

Recommendations:

  • Consider: await reportRoomCount(c) to ensure consistency
  • Or: Add error handling with retry logic
  • Or: Document that eventual consistency is acceptable here

Priority: Low-Medium (depends on how critical count accuracy is)

4. Missing Input Validation

Collaborative Document (examples/collaborative-document/src/actors.ts:104-124):

createDocument: async (c, title: string) => {
    const documentId = randomUUID();
    const createdAt = Date.now();
    const workspaceId = c.key[0] ?? "default";
    const safeTitle = title.trim() || "Untitled document";

Issues:

  • No max length check on title
  • No sanitization for potential XSS in title
  • c.key[0] ?? "default" might hide bugs if key structure is wrong

Recommendations:

  • Add max length validation (e.g., 200 chars)
  • Consider title sanitization for display
  • Add runtime assertion that c.key[0] exists

Priority: Medium (security + data integrity)

5. Type Safety in Queue Messages

AI Agent (examples/ai-agent/src/actors.ts:59-64):

const queued = await c.queue.next("message");

const body = queued.body as AgentQueueMessage;
if (!body?.text || typeof body.text !== "string") {
    continue;
}

Issues:

  • Runtime type checking after cast defeats TypeScript safety
  • No validation of sender field

Recommendations:

  • Consider using Zod/Valibot for runtime validation
  • Or: Define a type guard function
function isAgentQueueMessage(body: unknown): body is AgentQueueMessage {
    return typeof body === 'object' && body !== null &&
           'text' in body && typeof body.text === 'string';
}

Priority: Low-Medium (code quality)

Performance Considerations

✅ Good Practices

  1. Efficient State Updates: Examples use proper batching (e.g., gameState broadcasts after batch operations)
  2. Reasonable Limits: MAX_PLAYERS, MAX_ACTIVITY prevent unbounded growth
  3. Stream Processing: AI agent properly streams responses instead of buffering

⚠️ Potential Issues

  1. Collaborative Document KV Writes (examples/collaborative-document/src/actors.ts:71-73):

Issue: Every update writes full snapshot to KV. For active documents, this could be expensive.

Recommendations:

  • Consider debouncing KV writes (e.g., max 1 write/second)
  • Or: Use incremental updates if RivetKit supports it
  • Document the write frequency tradeoff

Priority: Medium (cost optimization)

  1. Game State Broadcasts (examples/multiplayer-game/src/actors.ts:180):

Issue: Full game state broadcast on every move could be bandwidth-heavy with many players.

Current Mitigation: Already sending specific playerMoved events, so full gameState broadcast might be redundant.

Recommendation: Consider removing the full gameState broadcast if playerMoved is sufficient.

Priority: Low (optimization opportunity)

Security Concerns

⚠️ Moderate Issues

  1. No Rate Limiting: Queue-based AI agent has no rate limiting on message submission

    • Risk: Could drain OpenAI credits rapidly
    • Recommendation: Add queue depth limits or rate limiting
  2. Input Sanitization: Document titles, player names not sanitized

    • Risk: XSS if rendered as HTML
    • Recommendation: Sanitize in frontend or document that examples assume trusted input

Priority: Medium (examples should demonstrate secure patterns)

Architecture & Design

✅ Excellent Patterns

  1. Coordinator Pattern: Consistent use across examples (matchmaker, documentList, agentManager)
  2. State Separation: Clear separation between ephemeral (connState) and persistent (state)
  3. Event-Driven: Proper use of broadcasts for real-time updates

💡 Suggestions

  1. Resource Cleanup: Consider documenting actor lifecycle and when to clean up idle actors
  2. Backpressure: Document queue behavior when consumers are slow (AI agent)
  3. Consistency Models: Document eventual consistency tradeoffs (e.g., matchmaker room counts)

Documentation Quality

✅ Strengths

  • Clear README for each example
  • Good inline comments explaining patterns
  • Links to relevant documentation

⚠️ Gaps

  1. Prerequisites: AI agent mentions OPENAI_API_KEY but other examples don't document env vars
  2. Testing Strategy: No mention of why tests were removed
  3. Production Readiness: Should clarify these are examples, not production-ready code

Recommendations Summary

Must Fix (High Priority)

None - code is functional

Should Fix (Medium Priority)

  1. Add basic test coverage or document testing philosophy
  2. Improve error handling in AI agent with structured logging
  3. Add input validation (max lengths, sanitization)
  4. Consider making reportRoomCount await or document eventual consistency

Nice to Have (Low Priority)

  1. Add type guards instead of runtime type checks
  2. Optimize KV writes in collaborative document
  3. Extract complex type annotations
  4. Add rate limiting examples

Conclusion

This is a strong PR that adds valuable examples demonstrating RivetKit patterns. The code is well-structured, follows consistent patterns, and provides good documentation.

Recommendation: ✅ Approve with minor suggestions

The examples are production-quality demonstrations of RivetKit capabilities. The concerns raised are primarily about demonstrating best practices (testing, error handling, input validation) rather than functionality issues.

The removal of tests is the most significant concern - consider at least documenting the testing philosophy for examples in CLAUDE.md.


Great work on these use cases! They provide clear, practical demonstrations of different RivetKit patterns that will help users understand the framework.

@NathanFlurry NathanFlurry changed the base branch from 01-02-feat_rivetkit_workflows to graphite-base/4100 February 3, 2026 20:02
@NathanFlurry NathanFlurry changed the base branch from graphite-base/4100 to feat_workflow_add_workflow_history_inspector_integration February 4, 2026 19:05
@railway-app
Copy link

railway-app bot commented Feb 4, 2026

🚅 Deployed to the rivet-pr-4100 environment in rivet-frontend

Service Status Web Updated (UTC)
website ❌ Build Failed (View Logs) Web Feb 5, 2026 at 8:15 am
frontend-inspector ❌ Build Failed (View Logs) Web Feb 5, 2026 at 8:14 am
frontend-cloud ❌ Build Failed (View Logs) Web Feb 5, 2026 at 8:14 am
mcp-hub ✅ Success (View Logs) Web Feb 5, 2026 at 8:13 am

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 4, 2026

More templates

@rivetkit/virtual-websocket

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/virtual-websocket@4100

@rivetkit/cloudflare-workers

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/cloudflare-workers@4100

@rivetkit/db

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/db@4100

@rivetkit/framework-base

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/framework-base@4100

@rivetkit/next-js

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/next-js@4100

@rivetkit/react

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/react@4100

rivetkit

pnpm add https://pkg.pr.new/rivet-dev/rivet/rivetkit@4100

@rivetkit/sql-loader

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/sql-loader@4100

@rivetkit/traces

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/traces@4100

@rivetkit/workflow-engine

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/workflow-engine@4100

@rivetkit/engine-runner

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner@4100

@rivetkit/engine-runner-protocol

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner-protocol@4100

commit: 9067558

@graphite-app graphite-app bot changed the base branch from feat_workflow_add_workflow_history_inspector_integration to graphite-base/4100 February 4, 2026 20:38
@graphite-app graphite-app bot force-pushed the 02-03-feat_use_cases branch from 4791c3b to b644aff Compare February 4, 2026 20:39
@graphite-app graphite-app bot force-pushed the graphite-base/4100 branch from 7d741be to 9c7edc9 Compare February 4, 2026 20:39
@graphite-app graphite-app bot changed the base branch from graphite-base/4100 to main February 4, 2026 20:40
@graphite-app graphite-app bot force-pushed the 02-03-feat_use_cases branch from b644aff to 4202678 Compare February 4, 2026 20:40
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4100 February 4, 2026 20:40 Destroyed
@NathanFlurry NathanFlurry changed the base branch from main to graphite-base/4100 February 5, 2026 08:35
@NathanFlurry NathanFlurry changed the base branch from graphite-base/4100 to 02-05-refactor_rivetkit_migrate_granularly_to_zod_v4 February 5, 2026 08:35
@NathanFlurry NathanFlurry marked this pull request as ready for review February 5, 2026 08:35
@jog1t jog1t force-pushed the 02-05-refactor_rivetkit_migrate_granularly_to_zod_v4 branch from 440850e to 96a52dc Compare February 5, 2026 20:34
@graphite-app graphite-app bot changed the base branch from 02-05-refactor_rivetkit_migrate_granularly_to_zod_v4 to graphite-base/4100 February 5, 2026 22:07
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.

2 participants