Skip to content

Comments

[Graphite MQ] Draft PR GROUP:spec_cc4b61 (PRs 4237, 4239)#4240

Closed
graphite-app[bot] wants to merge 2 commits intomainfrom
gtmq_spec_cc4b61_1771541374554-5303771c-a6b3-405b-b9e6-171f2215d310
Closed

[Graphite MQ] Draft PR GROUP:spec_cc4b61 (PRs 4237, 4239)#4240
graphite-app[bot] wants to merge 2 commits intomainfrom
gtmq_spec_cc4b61_1771541374554-5303771c-a6b3-405b-b9e6-171f2215d310

Conversation

@graphite-app
Copy link
Contributor

@graphite-app graphite-app bot commented Feb 19, 2026

This draft PR was created by the Graphite merge queue.
Trunk will be fast forwarded to the HEAD of this PR when CI passes, and the original PRs will be closed.

The following PRs are included in this draft PR:

# 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
# 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
@railway-app
Copy link

railway-app bot commented Feb 19, 2026

This PR was not deployed automatically as @graphite-app[bot] does not have access to the Railway project.

In order to get automatic PR deploys, please add @graphite-app[bot] to your workspace on Railway.

@graphite-app graphite-app bot closed this Feb 19, 2026
@railway-app railway-app bot temporarily deployed to rivet-frontend / production February 19, 2026 22:50 Inactive
@graphite-app graphite-app bot deleted the gtmq_spec_cc4b61_1771541374554-5303771c-a6b3-405b-b9e6-171f2215d310 branch February 19, 2026 22:50
@claude
Copy link

claude bot commented Feb 19, 2026

PR Review

This draft PR combines two changes: feat(rivetkit): canInvoke (#4237) and fix(rivetkit): fix run workflow teardown (#4239).


#4237canInvoke Access Control Hook

Overall: Clean, well-structured feature. Type safety is solid and test coverage is comprehensive.

Issues

1. assertCanInvokeWebSocket creates an ActionContext for a WebSocket check

ActionContext satisfies ConnContext so this works, but it is semantically odd. WebSocketContext is already imported in the same file but unused here. Consider using new WebSocketContext(this, conn) so the context type matches the invocation kind.

2. Queue access check assumes conn is always a real client connection

// router-endpoints.ts
const ctx = new ActionContext(actor, conn);
await actor.assertCanInvoke(ctx, { kind: "queue", name });

If conn is ever undefined or nullable in a server-side enqueue path (enqueueing from within the actor rather than from a client), this could throw unexpectedly. Worth confirming conn is always a real connection object on this code path, or adding a guard that skips the check for non-client-sourced enqueues.

3. State mutation side effect inside canInvoke is not mentioned in docs

The fixture's canInvoke writes to state on every call. This is intentional for the test, but users may not realize writes inside canInvoke trigger a state save on every invocation. Consider adding a note in the docs that canInvoke can read and write actor state, but writes have the usual persistence cost.

4. Queue named never in the workflow fixture

queues: {
    never: queue<unknown>(),
},

never shadows the TypeScript built-in type name. Not a compile error here, but unnecessarily confusing. Consider renaming to neverQueue or waitForever.

Minor Observations

  • The invalidCanInvokeReturn branch uses return undefined as never to bypass TypeScript — this correctly tests runtime enforcement of the boolean contract.
  • canInvoke is correctly not checked on unsubscribe.
  • The check is correctly applied to raw WebSocket routes only (not the standard PATH_CONNECT protocol WebSocket), which is the right separation between canInvoke and onBeforeConnect.

#4239 — Fix Workflow Run Teardown

Overall: The refactor is sound, but there is one behavioral change worth flagging.

Issues

1. Workflow errors now propagate and may crash the actor

Old behavior swallowed the error after logging. New behavior rethrows it:

} catch (error) {
    runCtx.log.error({ ... });
    throw error;  // propagates to run handler -> crashes actor
}

This is a behavioral change. If this is intentional (fail-fast is usually correct), it should be explicitly noted in the PR description and ideally tested. If actors were relying on silent recovery, this is a breaking change.

2. Timing-sensitive test

const firstSleepDelayMs = timeline.sleepAts[0] - timeline.wakeAts[0];
expect(firstSleepDelayMs).toBeLessThan(1_000);

With sleepTimeout: 75 there is ~13x headroom, which is reasonable, but timing tests can still flake on heavily loaded CI runners. If this starts flaking, consider driving the assertion from a multiple of the configured timeout rather than an absolute 1_000ms.

Positive Changes

  • The abort-before-listen guard (if (runCtx.abortSignal.aborted) { onAbort(); }) is a correct defensive pattern that avoids a race window.
  • Removing the Promise<never> pattern in favor of await handle.result is the right design — it makes the workflow function composable and allows proper finally cleanup.
  • The #stopCalled guards added in instance/mod.ts correctly distinguish clean stop from unexpected exit, preventing false crash reporting.

Summary

Area Finding Severity
Workflow error rethrowing Behavioral change — now crashes actor on workflow error Medium
assertCanInvokeWebSocket context type ActionContext used instead of WebSocketContext Low
Queue conn guard Possible NPE if conn is server-side Low
Fixture queue named never Shadows TypeScript built-in Low
Timing test Could flake on slow CI Low

The canInvoke feature is well-designed and the workflow teardown fix addresses a real problem. The main item to confirm before merging is whether the workflow error-rethrow behavior is intentional and whether any existing consumers depended on the silent-recovery behavior.

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