Skip to content

Commit 8465ac5

Browse files
d-csclaude
andauthored
feat(run-ops): webapp db topology, flags, and split-mode resolver wiring (#4117)
## What Wires the run-ops split into the webapp: database topology, environment flags, split-mode gating, and the control-plane resolver/cache layer that the run-store and run-engine seams from the previous PR plug into. - **DB topology & env** (`apps/webapp/app/db.server.ts`, `env.server.ts`, `entry.server.tsx`): adds the run-ops database clients/topology and the environment variables that configure and gate the split. - **runOpsMigration module** (new `apps/webapp/app/v3/runOpsMigration/`): the webapp-side machinery — `splitMode.server.ts`, `controlPlaneResolver.server.ts` + `controlPlaneCache.server.ts`, `readThrough.server.ts`, `crossSeamGuard.server.ts`, `distinctDbSentinel.server.ts`, id-minting helpers (`mintBatchFriendlyId`, `runOpsMintKind`, `resolveInheritedMintKind`), `runOpsCascadeCleanup.server.ts`, the split read gate, and route/unblock catalogs. - **Store/engine wiring** (`app/v3/runStore.server.ts`, `runEngine.server.ts`, `runEngineHandlers.server.ts` + new `runEngineHandlersShared.server.ts`): points the webapp's store/engine construction at the resolver, and factors shared handler logic out so both seams use one path. - **Read-path touch-ups**: `runtimeEnvironment.server.ts`, `eventRepository/index.server.ts`, `taskRunHeartbeatFailed.server.ts`, `engineVersion.server.ts` route their run/environment lookups read-through the resolver. - `413a94511` — interlocks split mode against the native realtime backend so the two aren't enabled in an incompatible combination (see `.server-changes/run-ops-split-realtime-interlock.md`). - `dc74c57fd` — drops the earlier "known-migrated" read layer; residency is determined by id-shape only. ## Why PR5 of the run-ops split stack. This is the webapp foundation layer: it stands up the DB topology, flags, and resolver/cache the rest of the stack depends on, and repoints webapp read paths through the resolver. Additive when the split is not enabled (existing single-DB behavior preserved behind flags); behavior-changing on the read-through paths and the realtime interlock. ## Tests New vitest coverage across `apps/webapp/test/` and colocated `*.server.test.ts` files: db topology, split mode, split read gate, cross-seam guard, mint cutover / flip latency, control-plane cache, control-plane resolver, distinct-db sentinel, read-through loaders (route loaders, run-detail loaders, `findEnvironmentFromRun`), and the run-engine handlers. Testcontainers-backed; no mocks. `pnpm-lock.yaml` synced for the two new webapp deps. ## Notes Draft, **stacked on #4116** (`runops/pr04-store-engine`). Review that first; this diff is against it. Server-change / changeset note to be added at stack-assembly time. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent c266e96 commit 8465ac5

68 files changed

Lines changed: 6898 additions & 330 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
area: webapp
3+
type: feature
4+
---
5+
Add the run-ops database split webapp foundation — DB topology/flag wiring, split-mode gating, distinct-DB and native-realtime boot interlocks, and a cache-first control-plane resolver with cache invalidation on env/org writes — all inert until the split is enabled.

apps/webapp/CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ const signal = getRequestAbortSignal();
7575
Access via `env` export from `app/env.server.ts`. **Never use `process.env` directly.**
7676

7777
For testable code, **never import env.server.ts** in test files. Pass configuration as options instead:
78-
- `realtimeClient.server.ts` (testable service, takes config as constructor arg)
79-
- `realtimeClientGlobal.server.ts` (creates singleton with env config)
78+
- `realtime/nativeRealtimeClient.server.ts` (testable service, takes config as constructor arg)
79+
- `realtime/nativeRealtimeClientInstance.server.ts` (creates singleton with env config)
8080

8181
## Run Engine 2.0
8282

apps/webapp/app/components/admin/backOffice/ApiRateLimitSection.server.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { prisma } from "~/db.server";
22
import { env } from "~/env.server";
33
import { logger } from "~/services/logger.server";
44
import { type Duration } from "~/services/rateLimiter.server";
5+
import { controlPlaneResolver } from "~/v3/runOpsMigration/controlPlaneResolver.server";
56
import { API_RATE_LIMIT_INTENT } from "./ApiRateLimitSection";
67
import {
78
handleRateLimitAction,
@@ -31,6 +32,8 @@ export const apiRateLimitDomain: RateLimitDomain = {
3132
where: { id: orgId },
3233
data: { apiRateLimiterConfig: next as any },
3334
});
35+
// apiRateLimiterConfig is embedded in every env of the org; drop all its cached env rows.
36+
controlPlaneResolver.invalidateOrganization(orgId);
3437
logger.info("admin.backOffice.apiRateLimit", {
3538
adminUserId,
3639
orgId,

apps/webapp/app/components/admin/backOffice/BatchRateLimitSection.server.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { prisma } from "~/db.server";
22
import { env } from "~/env.server";
33
import { logger } from "~/services/logger.server";
44
import { type Duration } from "~/services/rateLimiter.server";
5+
import { controlPlaneResolver } from "~/v3/runOpsMigration/controlPlaneResolver.server";
56
import { BATCH_RATE_LIMIT_INTENT } from "./BatchRateLimitSection";
67
import {
78
handleRateLimitAction,
@@ -31,6 +32,8 @@ export const batchRateLimitDomain: RateLimitDomain = {
3132
where: { id: orgId },
3233
data: { batchRateLimitConfig: next as any },
3334
});
35+
// batchRateLimitConfig is embedded in every env of the org; drop all its cached env rows.
36+
controlPlaneResolver.invalidateOrganization(orgId);
3437
logger.info("admin.backOffice.batchRateLimit", {
3538
adminUserId,
3639
orgId,

0 commit comments

Comments
 (0)