feat(run-ops): webapp routes — friendlyId reads, cross-seam token resolution, co-location writes#4123
feat(run-ops): webapp routes — friendlyId reads, cross-seam token resolution, co-location writes#4123d-cs wants to merge 10 commits into
Conversation
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ 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 |
9b6eee8 to
94eaef6
Compare
@trigger.dev/build
trigger.dev
@trigger.dev/core
@trigger.dev/python
@trigger.dev/react-hooks
@trigger.dev/redis-worker
@trigger.dev/rsc
@trigger.dev/schema-to-json
@trigger.dev/sdk
commit: |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens/route.tsx (1)
97-101: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThe
as unknown as PrismaClientOrTransactiondouble casts bypass structural type checking on the injected clients. If the runOps replica client shapes ever diverge fromPrismaClientOrTransaction, this would silently compile. Consider aligning the presenter's parameter types (or the exported client types) so a single, checked cast — or no cast — suffices.apps/webapp/app/routes/api.v1.waitpoints.tokens.ts (1)
12-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueType-erasing double-cast (
as unknown as PrismaClientOrTransaction) repeated across presenters.Same
runOpsNewReplicaClient as unknown as PrismaClientOrTransaction/runOpsLegacyReplica as unknown as PrismaClientOrTransactionpattern appears here and inresources...waitpoints.tags.ts. Casting throughunknownbypasses structural type-checking for the replica client wiring; ifPrismaClientOrTransactionand the actualdb.serverclient types diverge, this masks it at compile time. Consider aligning the exported client types withPrismaClientOrTransaction(or defining a narrower shared type) so the cast can be dropped.Also applies to: 36-40
apps/webapp/test/api.v1.waitpoints.tokens.test.ts (1)
134-200: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTag-write test doesn't exercise the real
createWaitpointTagproduction path.The assertion that "the tag landed on the control-plane client" is performed by writing directly via
prisma.waitpointTag.upsertrather than callingcreateWaitpointTagfrom~/models/waitpointTag.server(the function the actualapi.v1.waitpoints.tokens.tsaction uses). This makes the control-plane assertion trivially true by construction and wouldn't catch a regression if the production tag-write path were changed to route through the run-ops store. Consider invoking the real model function instead, if feasible without pulling in unrelated route dependencies.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 1b3db469-9a23-444a-b2fc-0576d2b798e7
📒 Files selected for processing (39)
apps/webapp/app/components/admin/debugRun.tsxapps/webapp/app/routes/@.runs.$runParam.tsapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.batches/route.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens.$waitpointParam/route.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens/route.tsxapps/webapp/app/routes/api.v1.batches.$batchId.tsapps/webapp/app/routes/api.v1.runs.$runFriendlyId.input-streams.wait.tsapps/webapp/app/routes/api.v1.runs.$runFriendlyId.session-streams.wait.tsapps/webapp/app/routes/api.v1.waitpoints.tokens.$waitpointFriendlyId.callback.$hash.tsapps/webapp/app/routes/api.v1.waitpoints.tokens.$waitpointFriendlyId.complete.tsapps/webapp/app/routes/api.v1.waitpoints.tokens.$waitpointFriendlyId.tsapps/webapp/app/routes/api.v1.waitpoints.tokens.tsapps/webapp/app/routes/api.v2.batches.$batchId.tsapps/webapp/app/routes/api.v2.tasks.batch.tsapps/webapp/app/routes/api.v3.batches.tsapps/webapp/app/routes/engine.v1.runs.$runFriendlyId.wait.duration.tsapps/webapp/app/routes/engine.v1.runs.$runFriendlyId.waitpoints.tokens.$waitpointFriendlyId.wait.tsapps/webapp/app/routes/orgs.$organizationSlug.projects.$projectParam.runs.$runParam.tsapps/webapp/app/routes/projects.v3.$projectRef.runs.$runParam.tsapps/webapp/app/routes/realtime.v1.batches.$batchId.tsapps/webapp/app/routes/realtime.v1.runs.$runId.tsapps/webapp/app/routes/realtime.v1.runs.tsapps/webapp/app/routes/realtime.v1.streams.$runId.$streamId.tsapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.idempotencyKey.reset.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.streams.$streamKey/route.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.$waitpointFriendlyId.complete/route.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tags.tsapps/webapp/app/routes/resources.runs.$runParam.logs.download.tsapps/webapp/app/routes/resources.runs.$runParam.tsapps/webapp/app/routes/resources.taskruns.$runParam.cancel.tsapps/webapp/app/routes/resources.taskruns.$runParam.debug.tsapps/webapp/app/routes/resources.taskruns.$runParam.replay.tsapps/webapp/app/routes/runs.$runParam.tsapps/webapp/app/routes/sync.traces.runs.$traceId.tsapps/webapp/app/v3/runOpsMigration/waitpointTokenResolve.server.test.tsapps/webapp/test/api.v1.waitpoints.tokens.complete.crossSeamGuard.test.tsapps/webapp/test/api.v1.waitpoints.tokens.test.tsapps/webapp/test/crossSeamGuard.proof.test.tsapps/webapp/test/waitpointCallback.controlPlane.test.ts
|
On the three maintainability nitpicks in the review summary:
No code changes for these; the security/correctness comments have been addressed in the latest commit. |
6e4c0de to
48c395b
Compare
f8b64bd to
e145839
Compare
e145839 to
6cd0085
Compare
6cd0085 to
5ccf63f
Compare
5ccf63f to
105ba1c
Compare
e7056ff to
fa76c1b
Compare
f7cf260 to
d31f2e9
Compare
d31f2e9 to
4bfd808
Compare
4bfd808 to
9197016
Compare
9197016 to
fa0d473
Compare
…ck, co-location writes Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… contract Waitpoint ids are always cuid; residency is decided by co-location routing, not id-shape. Remove the removed setKsuidMintEnabled global and flip the standalone-token assertions to cuid/LEGACY. Drive the NEW/cross-seam side from a ksuid run co-locating its (cuid) token on #new instead of a ksuid token, and keep the cross-seam guard consulted unconditionally on a plain cuid token. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The public wait-token routes (complete, HTTP callback, retrieve) resolved the waitpoint with a bare read-through that defaulted its new-side client to the dedicated run-ops replica and gated on the async mint flag. A standalone wait token has a cuid id and, having no owning run, is written to the control-plane store, so under the split topology the run-ops replica does not hold it and the routes returned 404 "Waitpoint not found". Resolve these routes the same way the working waiter route does: fan out through the run-ops replica first, then the control-plane replica, so both a co-located (run-owned) waitpoint and a standalone control-plane token are found. Gate the fan-out on the URL-presence read gate rather than the mint flag, so read visibility spans both DBs whenever both are configured — including the window where both database URLs are set but the mint flag is off. The retrieve route hands the same fan-out clients and gate to ApiWaitpointPresenter. Adds a two-database testcontainer regression proving a control-plane-resident standalone token resolves via the legacy fallback under the read gate, and that the passthrough branch (gate off) misses it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment/label/title cleanup only — no product logic or test behavior changed. Removes leftover enumeration scaffolding across the PR10 files: Test A-D and Leg 1-4 case markers, (A)/(B)/(D) parenthesized markers, Step 1-3 prefixes, and --- comment framing, while preserving the behavioral prose and the describe/it titles. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lit deps for waitpoint detail Route the org-membership authorization gate through the primary client on the debug, run-inspector, and idempotency-key-reset routes so it matches the cancel and replay paths and never authorizes against lagging replica state. Restore the primary-DB org fallback in the replay action's RBAC scope resolver so the scope is never resolved without an org during replica lag. Pass the full split-read deps to WaitpointPresenter on the detail route so a waitpoint resident on the new run-ops DB resolves the same way it does on the list route. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… test's db.server mock The callback route now resolves the waitpoint via resolveWaitpointThroughReadThrough, whose module reads runOpsSplitReadEnabled off ~/db.server at import. The test's vi.mock omitted that export, so the mocked module threw at import and the whole suite failed to collect. Provide it (split-on) to match the read path the route exercises; ksuid (NEW) waitpoint ids route to the runOpsNewReplica proxy pointing at the seeded container. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-token test The "control-plane-resident standalone token is found when the run-ops replica does not hold it" case relied on the ambient RUN_OPS_SPLIT_ENABLED env being on. Locally .env sets it (plus distinct TASK_RUN_* URLs) so the resolver fans out new->legacy and finds the cuid-shaped token. In CI those vars are unset, so resolveWaitpointThroughReadThrough falls back to isSplitEnabled() -> false -> single-DB passthrough, which reads only the run-ops replica (prisma17), never the control-plane legacy replica (prisma14) that holds the token. The read returned null and the assertion "expected null not to be null" failed on CI shard 3. Inject deps.splitEnabled: true (mirroring the sibling read-gate test) so the fan-out is exercised deterministically regardless of ambient env. Test-only; preserves exactly what the case verifies (legacy fallback finds a control-plane token the new replica lacks). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fa0d473 to
50463ce
Compare
What
Wires the run-ops split into the webapp routes so requests are routed correctly across the store boundary. Builds on the presenter rework from the previous PR; this layer is the route/loader/action glue that calls those presenters and the run store.
friendlyIdthrough the run store, so a run is found regardless of which store holds it. This spans the dashboard run routes, the resource routes (resources.runs.*,resources.taskruns.*cancel/debug/replay, logs download), the API batch/run routes (api.v1/api.v2/api.v3), realtime routes, sync-traces, and the admindebugRunhelper.New tests cover token resolution across the seam (
waitpointTokenResolve), the cross-seam guard on the complete route, the control-plane callback path, and theapi.v1.waitpoints.tokenssurface.Why
Part of the run-ops database split. This is PR9 of the series (PR8/9/10): it connects the split-aware read presenters (PR8) to the actual HTTP/loader surface so reads and token resolution route correctly, without yet enabling the split. The behaviour-changing activation stays isolated in PR10 on top of this.
Tests
pnpm run test --filter webappfor the affected route/resolver suites, including the new cross-seam-guard and waitpoint-token suites.Notes
Draft, stacked on #4122 (
runops/pr08-presenters). Review that first; this diff is against it.Server-change / changeset note to be added at stack-assembly time.
🤖 Generated with Claude Code