feat(budget): Worker runtime budgets — CPU measurement, deploy gate, and fleet analytics #402

Merged
gmackie merged 31 commits from feat/worker-runtime-budgets into main 2026-08-23 21:34:04 +00:00
Owner

What

Worker runtime budgets: measure and enforce CPU time for Cloudflare Workers, and report compliance across the fleet.

  • @forgegraph/worker-budget — wraps a Worker's entrypoint (including an OpenNext adapter) to measure CPU time per request, clamp declared cpu_ms, and emit violations as structured telemetry. Cron and marker support included.
  • Deploy gate — a Worker declaring a limit above its plan, or an agent without the budget capability, is refused before upload instead of failing at the edge. Enforcement runs against a pinned, verified worker artifact with a bounded dependency closure.
  • Fleet analytics — /runtime-budgets dashboard plus forge budget workers cpu, forge budget violations tail, and forge budget summary.
  • Honest coverage — CPU and violation telemetry are tracked separately; coverage reads "Complete" only when both streams are complete and lossless with no dropped events, and otherwise names which stream is incomplete and how many events were lost.

Verification

  • go build ./... and go test ./... in agent/ — green.
  • tsc --noEmit for apps/web — clean.
  • vitest run in apps/web — 169 files, 1033 passed, 40 skipped.

Rebased onto main at 18b3f957 with no conflicts.

Note for review

TestImmutableWorkerArtifactRunsInstalledWranglerDryRunWithWritableScratch looked for wrangler and zod under apps/web/node_modules, but pnpm keeps workspace dependencies at the workspace root — so it hard-failed in every environment including CI and never actually exercised Wrangler. It now resolves them by walking up from the app directory the way node resolution does, and skips rather than fails a Go-only checkout. The test now genuinely runs the dry-run (~4s).

🤖 Generated with Claude Code

## What Worker runtime budgets: measure and enforce CPU time for Cloudflare Workers, and report compliance across the fleet. - **`@forgegraph/worker-budget`** — wraps a Worker's entrypoint (including an OpenNext adapter) to measure CPU time per request, clamp declared `cpu_ms`, and emit violations as structured telemetry. Cron and marker support included. - **Deploy gate** — a Worker declaring a limit above its plan, or an agent without the budget capability, is refused before upload instead of failing at the edge. Enforcement runs against a pinned, verified worker artifact with a bounded dependency closure. - **Fleet analytics** — `/runtime-budgets` dashboard plus `forge budget workers cpu`, `forge budget violations tail`, and `forge budget summary`. - **Honest coverage** — CPU and violation telemetry are tracked separately; coverage reads "Complete" only when both streams are complete and lossless with no dropped events, and otherwise names which stream is incomplete and how many events were lost. ## Verification - `go build ./...` and `go test ./...` in `agent/` — green. - `tsc --noEmit` for `apps/web` — clean. - `vitest run` in `apps/web` — 169 files, 1033 passed, 40 skipped. Rebased onto `main` at `18b3f957` with no conflicts. ## Note for review `TestImmutableWorkerArtifactRunsInstalledWranglerDryRunWithWritableScratch` looked for wrangler and zod under `apps/web/node_modules`, but pnpm keeps workspace dependencies at the workspace root — so it hard-failed in every environment including CI and never actually exercised Wrangler. It now resolves them by walking up from the app directory the way node resolution does, and skips rather than fails a Go-only checkout. The test now genuinely runs the dry-run (~4s). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
- apps/web/worker.mjs wraps the OTel-patched OpenNext output with
  withOpenNextBudget (1s default budget; /api/auth/* + SSE exempt by config)
- envConfig resolves FG_BUDGET_MODE / FG_LANE / FG_DEPLOYMENT_ID per request
- main flipped to worker.mjs in prod + staging wrangler configs
- verified: opennext build, wrangler dry-run bundle, __FG_BUDGET__ marker
  present in final minified output
Workspace opt-in (workspaces.requireWorkerBudget, migration 0090) makes
worker runtime budgets mandatory for Cloudflare Workers deploys:

- deploy preflight gains runtimeBudgetPolicy / workerRuntimeEvidence /
  isCloudflareWorkerApp inputs; when opted in, deploys missing evidence
  are rejected with distinct actionable errors (upgrade forge CLI when no
  evidence at all; add [forge.budget]; import @forgegraph/worker-budget
  for the __FG_BUDGET__ marker; set [observability] enabled = true).
- POST /api/fg/deploy accepts optional workerRuntimeBudget evidence in
  its body schema and feeds workspace policy + evidence into preflight.
- GET /api/agent/bindings emits limits.cpuMs (apps.cpuMsOverride ??
  1000, migration 0091 adds the override + reason columns) when the
  workspace enforces budgets; absent otherwise.
- packages/api/vitest.unit.config.ts: globalSetup-free config so pure
  unit tests run where the emulate-based setup can't.
The worker row reported "Complete" whenever CPU telemetry was complete, so a
snapshot with lossy or dropped violation events still read as full coverage.
Coverage now requires both streams complete and lossless with no dropped
events, and the partial case names which stream is incomplete and how many
events were lost.
The dry-run integration test looked for both under apps/web/node_modules, but
pnpm keeps workspace dependencies in the workspace root, so the test hard-failed
everywhere including CI and never exercised a real Wrangler. It now walks up
from the app directory the way node resolution does, and skips — rather than
fails — a Go-only checkout with no JS install.
docs(changelog): record worker runtime budgets
All checks were successful
CI / gitleaks (pull_request) Successful in 6s
forgegraph/ci CI passed
CI / ci (pull_request) Successful in 9m12s
e2906d856a
gmackie force-pushed feat/worker-runtime-budgets from e2906d856a
All checks were successful
CI / gitleaks (pull_request) Successful in 6s
forgegraph/ci CI passed
CI / ci (pull_request) Successful in 9m12s
to 1663361330
All checks were successful
CI / gitleaks (pull_request) Successful in 6s
forgegraph/ci CI passed
CI / ci (pull_request) Successful in 9m12s
2026-08-23 20:42:17 +00:00
Compare
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
gmackie/ForgeGraph!402
No description provided.