Skip to content

fix(v2): derive the log and run status enums from the persisted status list - #6612

Merged
waleedlatif1 merged 4 commits into
stagingfrom
fix/b1-v2-log-status-paused
Aug 12, 2026
Merged

fix(v2): derive the log and run status enums from the persisted status list#6612
waleedlatif1 merged 4 commits into
stagingfrom
fix/b1-v2-log-status-paused

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • workflow_execution_logs.status can hold paused, but the v2 log presenters parsed it against an enum that omitted the value, so one such row 500s the response.
  • The trigger is not an ordinary human-in-the-loop pause — that persists pending. paused is written only by PauseResumeManager.markResumeAttemptFailed, when a resume attempt does not run to completion (failed admission on billing/usage limits, an archived or undeployed workflow, a lost claim race; also an unavailable run buffer, a resume job that could not be enqueued, or a cancelled attempt). All routine business paths, not outages.
  • The failure is durable, not transient. The bad value is persisted, and the v2 list presenter parses inside items.map, so a single row turns the whole page into a 500 for that workspace every time it is fetched — until the row ages out.
  • Root cause is a vacuous compile-time guard. V2_LOG_STATUSES was declared as const satisfies readonly PersistedWorkflowExecutionStatus[] with an AssertNever exhaustiveness gate, but PersistedWorkflowExecutionStatus itself omitted paused — and satisfies checks membership, not completeness. The guard could never have caught this.
  • The fix is a derivation, not a seventh string. lib/logs/types.ts now exports PERSISTED_WORKFLOW_EXECUTION_STATUSES as the single runtime source of truth, with PersistedWorkflowExecutionStatus derived from it; both v2 enums derive from that const, and the duplicate paused append in contracts/v2/workflows.ts is deleted. Adding a string to one list and forgetting the other is no longer expressible.
  • Scope: /api/v2 sits behind the off-by-default v2-api feature flag, so no default configuration reaches this code. This is a v2-GA blocker, not a release blocker.

Verification

  • Reverting the three source files makes 7 tests fail across the 4 suites, including "serves a run whose persisted status is paused" on both v2 log endpoints.
  • Guard experiment: adding a hypothetical eighth status to the persisted const propagates automatically into both v2 enums (7 -> 8 options on the log/list enums, 8 -> 9 on the single-run enum), and trips three tripwires — two contract-test failures pinning the published wire enum, and bun run check:openapi failing as stale.
  • apps/docs/openapi-v2-logs.json and openapi-v2-workflows.json were regenerated with bun run generate:openapi, not hand-edited; bun run check:openapi passes (7 specs, 128 operations, 130 contracts cross-checked).
  • bun run type-check clean, biome clean.

Type of Change

  • Bug fix

Testing

14 tests across 4 suites: lib/api/contracts/v2/log-status.test.ts, lib/api/contracts/v2/workflow-run-status.test.ts, app/api/v2/logs/route.test.ts, app/api/v2/logs/[runId]/route.test.ts.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…s list

`GET /api/v2/logs` and `GET /api/v2/logs/{runId}` parse the raw
`workflow_execution_logs.status` column against a six-value enum that omits
`paused`, so a run holding that value returns 500. The list response is
validated whole-page, so one such row 500s every page it lands on, and the
row is durable until the run is resumed, cancelled, or failed.

`paused` is not written by an ordinary human-in-the-loop pause — that path
persists `pending` (logging-session.ts:1180). It is written by
`PauseResumeManager.markResumeAttemptFailed`, which fires on any
`ResumeAdmissionError`: a workspace over its usage limit, an archived or
undeployed workflow, or a concurrent resume losing the claim race. That is a
routine business path.

The enum was supposed to be protected by an `AssertNever` exhaustiveness gate,
but the gate was vacuous: it compared against `PersistedWorkflowExecutionStatus`,
a hand-written union that was itself missing `paused`, because the write goes
through a raw `sql` CASE fragment Drizzle cannot type-check. Adding `paused` to
both lists would leave the same vacuous gate in place for the next status.

Instead, `PERSISTED_WORKFLOW_EXECUTION_STATUSES` becomes the single runtime
source of truth, `PersistedWorkflowExecutionStatus` is derived from it, and both
v2 contracts derive their enums from the const rather than re-declaring them.
Both surfaces pass the column through verbatim, so their reported set is the
persisted set by definition — there is no editorial choice for a gate to force,
only the question of whether a newly persisted status should be public, which
the option-list tests now pin. The `[...V2_PERSISTED_RUN_STATUSES, 'paused']`
append on the runs contract is deleted rather than adjusted; it would otherwise
be a duplicate.

Alternatives rejected:
- A `.catch()` or `safeParse` in the presenters is dead code:
  `v2-json-route.ts:271` re-parses the whole body with the same schema.
- Normalizing `markResumeAttemptFailed` to write `pending` would remove the
  distinction the resume claim query at human-in-the-loop-manager.ts:973 relies
  on, and leaves the contract wrong for any other future status.
- Typing the Drizzle column does not help: the offending write is a raw `sql`
  fragment, and `packages/db` cannot import the app's status list.

The v2 workflows spec changes are reordering and description only — the value
set there already contained `paused`. The v2 logs spec gains `paused`, which is
additive and safe while the whole `/api/v2` surface is behind the off-by-default
`v2-api` flag; it must land before v2 GA, after which it would be breaking.
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview Aug 12, 2026 8:56am

Request Review

@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches public v2 API response contracts and OpenAPI status enums, but is a scoped bugfix behind the off-by-default v2-api flag with no auth or data-write changes.

Overview
Fixes v2 log endpoints 500ing when a row has persisted status paused (written after a failed resume attempt), by aligning the public status enums with the real persisted set.

Introduces PERSISTED_WORKFLOW_EXECUTION_STATUSES as the single source of truth (including paused), derives both log and run response schemas from it, and regenerates the OpenAPI specs. Contract and route tests now pin that derivation so future status additions cannot silently diverge again.

Reviewed by Cursor Bugbot for commit f6e0952. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR establishes the persisted workflow-execution status tuple as the runtime source of truth for v2 log and run status schemas, allowing persisted paused rows to be presented without response-validation failures.

  • Derives TypeScript status types and v2 Zod enums from one persisted-status tuple.
  • Documents the ambiguous persisted paused semantics without promising an unavailable discriminator.
  • Regenerates the affected OpenAPI specifications and adds contract and route regression coverage.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
apps/sim/lib/logs/types.ts Introduces the canonical persisted-status tuple and derives the corresponding TypeScript union from it.
apps/sim/lib/api/contracts/v2/logs.ts Derives the v2 log status schema from the persisted tuple so paused rows validate successfully.
apps/sim/lib/api/contracts/v2/workflows.ts Derives run status schemas from the persisted tuple and accurately documents the limits of paused-state discrimination.
packages/db/schema.ts Replaces stale inline status guidance with compliant TSDoc pointing to the canonical runtime status list.
apps/sim/lib/api/contracts/v2/log-status.test.ts Pins the public log-status wire contract and verifies that it remains derived from the persisted tuple.
apps/sim/lib/api/contracts/v2/workflow-run-status.test.ts Verifies persisted-status derivation while preserving the detail-only queued overlay and narrower filter contract.
apps/docs/openapi-v2-logs.json Regenerates the log API specification to include and explain the persisted paused status.
apps/docs/openapi-v2-workflows.json Regenerates workflow run schemas with the derived status ordering and corrected paused-state semantics.

Reviews (3): Last reviewed commit: "fix(v2): stop promising a paused discrim..." | Re-trigger Greptile

Comment thread apps/sim/lib/api/contracts/v2/workflows.ts Outdated
Comment thread packages/db/schema.ts Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 6931ea6. Configure here.

Comment thread apps/sim/lib/api/contracts/v2/workflows.ts Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 16ba04d. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit f6e0952. Configure here.

@waleedlatif1
waleedlatif1 merged commit 366829b into staging Aug 12, 2026
21 of 22 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/b1-v2-log-status-paused branch August 12, 2026 08:51
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