Skip to content

feat: use cases#4100

Closed
NathanFlurry wants to merge 1 commit into01-28-feat_dashboard_traces_timeline_uifrom
02-03-feat_use_cases
Closed

feat: use cases#4100
NathanFlurry wants to merge 1 commit into01-28-feat_dashboard_traces_timeline_uifrom
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
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4100 February 3, 2026 19:42 Destroyed
@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

PR Review: feat: use cases

Summary

This PR adds several new example applications showcasing different Rivet Actor use cases:

  • AI Agent: Queue-driven actor-based AI agents with streaming responses
  • Collaborative Document: Real-time collaborative editing using Yjs and Rivet Actors
  • Geo-Distributed Database: Region-aware session management
  • Multiplayer Game: Matchmaking and game room coordination with collision detection

The PR includes both local and Vercel variants of each example, removes the deprecated multi-region example, and removes test coverage from the ai-agent example.

Changed files: 100 files (11,500 additions, 1,632 deletions)

Code Quality & Best Practices

✅ Strengths

  1. Clean actor patterns: All examples demonstrate proper actor design with clear separation of concerns (coordinator actors vs data actors).

  2. Consistent structure: Examples follow a consistent pattern across all implementations with src/actors.ts, src/server.ts, and frontend components.

  3. Good type safety: TypeScript types are well-defined for all state, events, and messages.

  4. Proper state management: Examples correctly use state for persistent data and connState for connection-specific data.

⚠️ Issues & Concerns

1. Test Coverage Removal (Critical)

The ai-agent example had comprehensive tests (tests/ai-agent.test.ts - 117 lines) that were completely removed:

// Removed tests included:
- Basic action handling
- Message persistence
- Tool calling verification
- Error handling scenarios

Recommendation: Tests should not be removed without replacement. Either:

  • Restore the tests and adapt them to the new implementation
  • Add equivalent test coverage for the new queue-based pattern
  • Document why test removal is acceptable in this specific case

2. Input Validation Gaps

ai-agent/src/actors.ts:61-64

const body = queued.body as AgentQueueMessage;
if (\!body?.text || typeof body.text \!== "string") {
    continue;
}
  • Missing validation for sender field type
  • No maximum length validation for text (could cause memory issues with large inputs)
  • Silent continue on invalid messages (should log for debugging)

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

join: async (c, name: string): Promise<JoinResult | null> => {
    // ...
    if (Object.keys(c.state.players).length >= c.state.maxPlayers) {
        return null;
    }
  • No validation on name parameter (empty strings, length limits, sanitization)
  • Could allow players to join with empty or malicious names

Recommendation: Add input validation:

// ai-agent example
const trimmedText = body.text.trim();
if (trimmedText.length === 0 || trimmedText.length > 10000) {
    console.warn("Invalid message length", trimmedText.length);
    continue;
}

// multiplayer-game example
const sanitizedName = name.trim();
if (sanitizedName.length === 0 || sanitizedName.length > 50) {
    return null;
}

3. Error Handling Issues

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.";

    c.state.status = {
        state: "error",
        updatedAt: Date.now(),
        error: errorMessage,
    };
  • Errors are caught but not logged (makes debugging difficult)
  • The error is broadcast to clients, potentially exposing sensitive information

Recommendation: Add logging and sanitize error messages:

} catch (error) {
    console.error("AI agent error:", error);
    const errorMessage = error instanceof Error ? error.message : "Unknown error";
    const userFacingError = "I hit a snag while responding. Please try again.";

    c.state.status = {
        state: "error",
        updatedAt: Date.now(),
        error: userFacingError, // Don't expose internal errors to clients
    };

4. Race Condition in Collision Detection

multiplayer-game/src/actors.ts:190-235

const resolveCollisions = (
    players: Record<string, Player>,
    connections: Map<string, { state: { playerId: string | null } }>,
) => {
    // ...
    for (const conn of connections.values()) {
        if (conn.state.playerId === targetId) {
            conn.state.playerId = null;
        }
    }
  • The function modifies connection state directly while iterating
  • If a player is eaten, their connection state is cleared, but there's no guarantee the client is notified before the next action

Recommendation: Consider adding a disconnect or notification before clearing state.

5. Magic Numbers & Configuration

Multiple examples have hardcoded constants that should be configurable:

ai-agent/src/actors.ts:30-31

const SYSTEM_PROMPT =
    "You are a focused AI assistant. Keep responses concise, actionable, and ready for handoff.";

multiplayer-game/src/actors.ts:4-7

const MAX_PLAYERS = 10;
const WORLD_SIZE = 1200;
const START_MASS = 20;
const SPEED_BASE = 7;

geo-distributed-database/src/actors.ts:24

const MAX_ACTIVITY = 6;

Recommendation: These are fine for examples, but consider documenting that production apps should make these configurable.

6. Inconsistent Error Returns

multiplayer-game/src/actors.ts:122

join: async (c, name: string): Promise<JoinResult | null> => {
    // Returns null on failure
}

vs.

multiplayer-game/src/actors.ts:144

move: async (c, dx: number, dy: number) => {
    // Returns null on failure
}
  • Actions return null on failure without explaining why
  • Clients can't distinguish between "room full" vs "player not found" vs other errors

Recommendation: Return error objects with reasons:

join: async (c, name: string): Promise<{ success: true; data: JoinResult } | { success: false; reason: string }>

Performance Considerations

⚠️ Potential Issues

  1. Unbounded Message History (ai-agent/src/actors.ts:75)

    c.state.messages.push(userMessage);
    • Messages accumulate indefinitely in state
    • Could cause memory issues for long-running agents
    • Recommendation: Implement message history limits or pagination
  2. Broadcast on Every Movement (multiplayer-game/src/actors.ts:167-180)

    c.broadcast("playerMoved", { ... });
    // ...
    c.broadcast("gameState", buildGameState(...));
    • Every player movement triggers two broadcasts (playerMoved + gameState)
    • gameState contains the entire player map
    • Recommendation: Consider throttling or only broadcasting deltas
  3. N² Collision Detection (multiplayer-game/src/actors.ts:201-221)

    • Nested loops check every player against every other player
    • Fine for 10 players, but doesn't scale
    • Recommendation: Document the scaling limitation or consider spatial partitioning for larger games
  4. Full Yjs Document State (collaborative-document/src/actors.ts:39-42)

    const stored = await c.kv.get("yjs:doc", { type: "binary" });
    if (stored) {
        Y.applyUpdate(doc, stored);
    }
    • Loads entire document state on actor creation
    • Recommendation: This is fine for examples, but production apps should consider document size limits

Security Concerns

⚠️ Moderate Risk

  1. No Rate Limiting

    • AI agent can process unlimited messages from the queue
    • Game actions (move, join) have no rate limits
    • Recommendation: Add rate limiting for production deployments
  2. Client-Controlled IDs (multiplayer-game/src/actors.ts:132)

    const playerId = c.conn.id;
    • Uses connection ID as player ID (this is fine, but worth noting)
  3. Potential XSS in User-Generated Content

    • Player names, agent messages, and document content are not sanitized
    • Frontend should handle escaping, but backend should validate
    • Recommendation: Add input sanitization or document that frontends must escape

✅ Good Security Practices

  1. Type checking on queue messages (ai-agent/src/actors.ts:62)
  2. Connection state isolation (collaborative-document/src/actors.ts:25-27)
  3. Proper disconnect cleanup (gameRoom.onDisconnect, document.onDisconnect)

Documentation & Developer Experience

✅ Strengths

  1. Good README structure: Each example has clear setup instructions
  2. Inline comments: Actor code includes helpful comments about patterns
  3. Type exports: All examples export their types for client usage

⚠️ Improvements Needed

  1. Missing prerequisites documentation

    • ai-agent README mentions OpenAI API key but not how to set it
    • No .env.example files
  2. No migration guide

    • Old ai-agent had different API (sendMessage action)
    • New version uses queue pattern
    • Users upgrading from old example will be confused
  3. Vercel-specific configuration not explained

    • Vercel examples have vercel.json but no explanation of differences from local version

Architecture & Design Patterns

✅ Excellent Patterns

  1. Coordinator Pattern: agentManager, matchmaker, documentList show proper multi-actor coordination
  2. Queue-Driven Processing: ai-agent's use of c.queue.next() in run loop is a great pattern
  3. Connection State Management: All examples properly separate connection state from persistent state

💡 Suggestions

  1. Consider adding error recovery examples

    • What happens if AI agent crashes mid-stream?
    • What if matchmaker actor restarts?
  2. Document state persistence behavior

    • Examples assume state survives restarts, but this isn't obvious to new users

Testing

❌ Critical Issue

  • 117 lines of tests removed with no replacement
  • Removed tests covered:
    • Mock AI SDK integration
    • Message handling
    • Tool calling
    • State persistence
    • Error scenarios

This is the most significant issue in the PR.

Recommendations

  1. Restore or replace test coverage for ai-agent example
  2. Add tests for new examples:
    • collaborative-document: Yjs integration, awareness updates
    • multiplayer-game: Collision detection, matchmaking
    • geo-distributed-database: Region-specific behavior

Summary & Recommendations

Must Fix Before Merge

  1. Restore test coverage for ai-agent or provide justification for removal
  2. Add input validation for user-provided strings (names, messages)
  3. Add error logging in catch blocks
  4. Document message history limits or implement cleanup

Should Fix

  1. Add .env.example files with required environment variables
  2. Add rate limiting examples or documentation
  3. Sanitize error messages before broadcasting to clients
  4. Add maximum length validation for text inputs

Nice to Have

  1. Migration guide for users upgrading from old examples
  2. Performance documentation (scaling limits, expected throughput)
  3. Test coverage for new examples
  4. Document differences between local and Vercel variants

Overall Assessment

Quality: Good architectural patterns and clean code structure, but test coverage removal is concerning.

Security: Moderate risk - needs input validation and rate limiting for production use.

Documentation: Good README structure, but missing some critical setup details.

Recommendation: Request changes - primarily for test coverage restoration and input validation improvements.


These examples will be very valuable for users learning Rivet Actors. The code quality is generally high, and the patterns demonstrated are excellent. Addressing the test coverage and input validation issues will make this PR production-ready.

@NathanFlurry NathanFlurry changed the base branch from 01-02-feat_rivetkit_workflows to graphite-base/4100 February 3, 2026 20:02
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4100 February 4, 2026 19:05 Destroyed
@NathanFlurry NathanFlurry changed the base branch from graphite-base/4100 to feat_workflow_add_workflow_history_inspector_integration February 4, 2026 19:05
@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
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4100 February 4, 2026 20:39 Destroyed
@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
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4100 February 5, 2026 08:12 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
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4100 February 6, 2026 07:58 Destroyed
@NathanFlurry NathanFlurry changed the base branch from graphite-base/4100 to 01-28-feat_dashboard_traces_timeline_ui February 6, 2026 07:58
@graphite-app
Copy link
Contributor

graphite-app bot commented Feb 6, 2026

Merge activity

  • Feb 6, 8:22 AM UTC: NathanFlurry added this pull request to the Graphite merge queue.
  • Feb 6, 8:23 AM UTC: CI is running for this pull request on a draft pull request (#4146) due to your merge queue CI optimization settings.
  • Feb 6, 8:24 AM UTC: Merged by the Graphite merge queue via draft PR: #4146.

graphite-app bot pushed a commit that referenced this pull request Feb 6, 2026
# 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
@graphite-app graphite-app bot closed this Feb 6, 2026
@graphite-app graphite-app bot deleted the 02-03-feat_use_cases branch February 6, 2026 08:24
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