GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix(v2): derive the log and run status enums from the persisted statu… · simstudioai/sim@6931ea6

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • apps
    • docs
      • openapi-v2-logs.json
      • openapi-v2-workflows.json
    • sim
      • app/api/v2/logs
        • [runId]
          • route.test.ts
        • route.test.ts
      • lib
        • api/contracts/v2
          • log-status.test.ts
          • logs.ts
          • workflow-run-status.test.ts
          • workflows.ts
        • logs
          • types.ts
  • packages/db
    • schema.ts
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎apps/docs/openapi-v2-logs.json‎

Copy file name to clipboardExpand all lines: apps/docs/openapi-v2-logs.json
+20-4Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -640,8 +640,16 @@
640640
},
641641
"status": {
642642
"type": "string",
643-
"enum": ["pending", "running", "redacting", "completed", "failed", "cancelled"],
644-
"description": "Current execution status. `redacting` is transient while run output is scrubbed."
643+
"enum": [
644+
"pending",
645+
"running",
646+
"paused",
647+
"redacting",
648+
"completed",
649+
"failed",
650+
"cancelled"
651+
],
652+
"description": "Current execution status. `redacting` is transient while run output is scrubbed. `paused` is reported when a resume attempt did not run to completion and the run is waiting to be resumed again."
645653
},
646654
"level": {
647655
"type": "string",
@@ -1028,8 +1036,16 @@
10281036
},
10291037
"status": {
10301038
"type": "string",
1031-
"enum": ["pending", "running", "redacting", "completed", "failed", "cancelled"],
1032-
"description": "Current execution status. `redacting` is transient while run output is scrubbed."
1039+
"enum": [
1040+
"pending",
1041+
"running",
1042+
"paused",
1043+
"redacting",
1044+
"completed",
1045+
"failed",
1046+
"cancelled"
1047+
],
1048+
"description": "Current execution status. `redacting` is transient while run output is scrubbed. `paused` is reported when a resume attempt did not run to completion and the run is waiting to be resumed again."
10331049
},
10341050
"level": {
10351051
"type": "string",
Collapse file

‎apps/docs/openapi-v2-workflows.json‎

Copy file name to clipboardExpand all lines: apps/docs/openapi-v2-workflows.json
+5-5Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3923,13 +3923,13 @@
39233923
"enum": [
39243924
"pending",
39253925
"running",
3926+
"paused",
39263927
"redacting",
39273928
"completed",
39283929
"failed",
3929-
"cancelled",
3930-
"paused"
3930+
"cancelled"
39313931
],
3932-
"description": "Current or terminal run status. `redacting` is transient, reported while the output of a finished run is being scrubbed."
3932+
"description": "Current or terminal run status. `redacting` is transient, reported while the output of a finished run is being scrubbed. `paused` is reported while the run is waiting at a human-in-the-loop pause point."
39333933
},
39343934
"trigger": {
39353935
"type": "string",
@@ -4063,14 +4063,14 @@
40634063
"enum": [
40644064
"pending",
40654065
"running",
4066+
"paused",
40664067
"redacting",
40674068
"completed",
40684069
"failed",
40694070
"cancelled",
4070-
"paused",
40714071
"queued"
40724072
],
4073-
"description": "Current or terminal run status. `redacting` is transient, reported while the output of a finished run is being scrubbed."
4073+
"description": "Current or terminal run status. `redacting` is transient, reported while the output of a finished run is being scrubbed. `paused` is reported while the run is waiting at a human-in-the-loop pause point."
40744074
},
40754075
"trigger": {
40764076
"anyOf": [
Collapse file

‎apps/sim/app/api/v2/logs/[runId]/route.test.ts‎

Copy file name to clipboardExpand all lines: apps/sim/app/api/v2/logs/[runId]/route.test.ts
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,21 @@ describe('GET /api/v2/logs/[runId]', () => {
9494
})
9595
})
9696

97+
it('serves a run whose persisted status is paused', async () => {
98+
mocks.execute.mockResolvedValue({
99+
log: { ...log, status: 'paused' },
100+
workflowFolderPath: '/agents',
101+
executionData: { traceSpans: [], finalOutput: null },
102+
})
103+
104+
const response = await GET(new NextRequest('http://localhost:3000/api/v2/logs/run-1'), {
105+
params: Promise.resolve({ runId: 'run-1' }),
106+
})
107+
108+
expect(response.status).toBe(200)
109+
expect((await response.json()).data).toMatchObject({ runId: 'run-1', status: 'paused' })
110+
})
111+
97112
it('conceals canonical workspace authorization as log not-found', async () => {
98113
mocks.execute.mockRejectedValueOnce(new NoWorkspaceAccessError())
99114

Collapse file

‎apps/sim/app/api/v2/logs/route.test.ts‎

Copy file name to clipboardExpand all lines: apps/sim/app/api/v2/logs/route.test.ts
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,24 @@ describe('GET /api/v2/logs', () => {
9898
})
9999
})
100100

101+
it('serves a run whose persisted status is paused', async () => {
102+
mocks.execute.mockResolvedValue({
103+
items: [{ log: { ...log, status: 'paused' }, executionData: null }],
104+
nextCursor: null,
105+
includeFullDetails: false,
106+
includeFinalOutput: false,
107+
includeTraceSpans: false,
108+
})
109+
110+
const response = await GET(
111+
new NextRequest(`http://localhost:3000/api/v2/logs?workspaceId=${WORKSPACE_ID}`)
112+
)
113+
const body = await response.json()
114+
115+
expect(response.status).toBe(200)
116+
expect(body.data[0]).toMatchObject({ runId: 'run-1', status: 'paused' })
117+
})
118+
101119
it('rejects malformed cursors after admission and before protected reads', async () => {
102120
const response = await GET(
103121
new NextRequest(
Collapse file

‎apps/sim/lib/api/contracts/v2/log-status.test.ts‎

Copy file name to clipboard
+26Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { v2LogStatusSchema } from '@/lib/api/contracts/v2/logs'
3+
import { PERSISTED_WORKFLOW_EXECUTION_STATUSES } from '@/lib/logs/types'
4+
5+
/**
6+
* Both log endpoints pass `workflow_execution_logs.status` through verbatim — unlike the
7+
* run endpoints there is no `paused` overlay and no `queued` — so any drift between the
8+
* reported enum and the persisted list 500s a whole page of results.
9+
*/
10+
describe('v2 log status schema', () => {
11+
it('publishes exactly the persisted statuses', () => {
12+
expect(v2LogStatusSchema.options).toEqual([
13+
'pending',
14+
'running',
15+
'paused',
16+
'redacting',
17+
'completed',
18+
'failed',
19+
'cancelled',
20+
])
21+
})
22+
23+
it('stays derived from the persisted status list', () => {
24+
expect(v2LogStatusSchema.options).toEqual([...PERSISTED_WORKFLOW_EXECUTION_STATUSES])
25+
})
26+
})
Collapse file

‎apps/sim/lib/api/contracts/v2/logs.ts‎

Copy file name to clipboardExpand all lines: apps/sim/lib/api/contracts/v2/logs.ts
+9-22Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
v2FolderPathSchema,
1111
v2TimestampSchema,
1212
} from '@/lib/api/contracts/v2/shared'
13-
import type { PersistedWorkflowExecutionStatus } from '@/lib/logs/types'
13+
import { PERSISTED_WORKFLOW_EXECUTION_STATUSES } from '@/lib/logs/types'
1414

1515
/**
1616
* v2 logs contracts. The query schemas are reused verbatim from v1 (the request
@@ -23,29 +23,16 @@ const v2LogCostSchema = z
2323
.nullable()
2424
.describe('Cost charged for the run, or null when unavailable.')
2525
/**
26-
* Every status the execution logger can persist, including the transient
27-
* `redacting` state written while a finished run's output is scrubbed. The
28-
* column is free text, so a value missing here fails the response parse and
29-
* turns a single row into a 500 for the whole page. `_ExhaustiveLogStatus`
30-
* makes a future addition to the persisted union a compile error instead.
26+
* Both log endpoints pass `workflow_execution_logs.status` through verbatim, so the
27+
* reported set is exactly the persisted set — a value missing here fails the response
28+
* parse, and because list validation is whole-page one such row turns an entire page
29+
* into a 500.
3130
*/
32-
const V2_LOG_STATUSES = [
33-
'pending',
34-
'running',
35-
'redacting',
36-
'completed',
37-
'failed',
38-
'cancelled',
39-
] as const satisfies readonly PersistedWorkflowExecutionStatus[]
40-
41-
type AssertNever<T extends never> = T
42-
type _ExhaustiveLogStatus = AssertNever<
43-
Exclude<PersistedWorkflowExecutionStatus, (typeof V2_LOG_STATUSES)[number]>
44-
>
45-
4631
export const v2LogStatusSchema = z
47-
.enum(V2_LOG_STATUSES)
48-
.describe('Current execution status. `redacting` is transient while run output is scrubbed.')
32+
.enum(PERSISTED_WORKFLOW_EXECUTION_STATUSES)
33+
.describe(
34+
'Current execution status. `redacting` is transient while run output is scrubbed. `paused` is reported when a resume attempt did not run to completion and the run is waiting to be resumed again.'
35+
)
4936

5037
/** Execution `files` is a per-run jsonb array of attachment metadata. */
5138
const v2LogFilesSchema = z
Collapse file

‎apps/sim/lib/api/contracts/v2/workflow-run-status.test.ts‎

Copy file name to clipboardExpand all lines: apps/sim/lib/api/contracts/v2/workflow-run-status.test.ts
+34-21Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,49 @@ import {
44
v2WorkflowRunStatusFilterSchema,
55
v2WorkflowRunStatusValueSchema,
66
} from '@/lib/api/contracts/v2/workflows'
7-
import type { PersistedWorkflowExecutionStatus } from '@/lib/logs/types'
7+
import { PERSISTED_WORKFLOW_EXECUTION_STATUSES } from '@/lib/logs/types'
88

99
/**
10-
* The runtime mirror of the persisted union. `satisfies` keeps it honest against
11-
* `PersistedWorkflowExecutionStatus`, and the `AssertNever` gate in the contract keeps
12-
* that union honest against the reported enums, so a status added to the execution logger
13-
* fails compilation in both places before it can 500 a response parse.
10+
* Both run endpoints report `workflow_execution_logs.status`, overlaid with `paused` from
11+
* `paused_executions`, so every reported value lands in the persisted set. These tests
12+
* guard the two ways that can break: the derivation being replaced by a hand-maintained
13+
* list again, and a status being added to the persisted set without anyone confirming it
14+
* belongs on the public wire (and regenerating the OpenAPI specs).
1415
*/
15-
const PERSISTED_STATUSES = [
16-
'pending',
17-
'running',
18-
'redacting',
19-
'completed',
20-
'failed',
21-
'cancelled',
22-
] as const satisfies readonly PersistedWorkflowExecutionStatus[]
23-
2416
describe('v2 workflow run status schemas', () => {
25-
it.each(PERSISTED_STATUSES)('reports the persisted status %s on both run endpoints', (status) => {
26-
expect(v2WorkflowRunListStatusValueSchema.parse(status)).toBe(status)
27-
expect(v2WorkflowRunStatusValueSchema.parse(status)).toBe(status)
17+
it('publishes exactly the persisted statuses on the run list', () => {
18+
expect(v2WorkflowRunListStatusValueSchema.options).toEqual([
19+
'pending',
20+
'running',
21+
'paused',
22+
'redacting',
23+
'completed',
24+
'failed',
25+
'cancelled',
26+
])
2827
})
2928

30-
it('reports the paused overlay on both run endpoints', () => {
31-
expect(v2WorkflowRunListStatusValueSchema.parse('paused')).toBe('paused')
32-
expect(v2WorkflowRunStatusValueSchema.parse('paused')).toBe('paused')
29+
it('stays derived from the persisted status list', () => {
30+
expect(v2WorkflowRunListStatusValueSchema.options).toEqual([
31+
...PERSISTED_WORKFLOW_EXECUTION_STATUSES,
32+
])
33+
expect(v2WorkflowRunStatusValueSchema.options).toEqual([
34+
...PERSISTED_WORKFLOW_EXECUTION_STATUSES,
35+
'queued',
36+
])
3337
})
3438

3539
it('reports queued only where the job queue is consulted', () => {
36-
expect(v2WorkflowRunStatusValueSchema.parse('queued')).toBe('queued')
40+
expect(v2WorkflowRunStatusValueSchema.options).toEqual([
41+
'pending',
42+
'running',
43+
'paused',
44+
'redacting',
45+
'completed',
46+
'failed',
47+
'cancelled',
48+
'queued',
49+
])
3750
expect(v2WorkflowRunListStatusValueSchema.safeParse('queued').success).toBe(false)
3851
})
3952

Collapse file

‎apps/sim/lib/api/contracts/v2/workflows.ts‎

Copy file name to clipboardExpand all lines: apps/sim/lib/api/contracts/v2/workflows.ts
+11-32Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {
3636
workflowIdParamsSchema,
3737
} from '@/lib/api/contracts/workflows'
3838
import { MAX_WORKFLOW_EXECUTION_TIMEOUT_SECONDS } from '@/lib/billing/execution-timeout-defaults'
39-
import type { PersistedWorkflowExecutionStatus } from '@/lib/logs/types'
39+
import { PERSISTED_WORKFLOW_EXECUTION_STATUSES } from '@/lib/logs/types'
4040

4141
export const V2_WORKFLOW_RUN_ID_HEADER = 'X-Run-Id'
4242

@@ -982,48 +982,27 @@ export const v2ResumeWorkflowContract = defineRouteContract({
982982
},
983983
})
984984

985-
/**
986-
* Every status the execution logger can persist into `workflow_execution_logs.status`,
987-
* including the transient `redacting` state written while a finished run's output is
988-
* scrubbed. The column is free text and both run endpoints pass it straight through, so
989-
* a value missing here fails the response parse — and because list validation is
990-
* whole-page, one such row turns an entire page into a 500. `_ExhaustiveRunStatus` makes
991-
* a future addition to the persisted union a compile error instead.
992-
*/
993-
const V2_PERSISTED_RUN_STATUSES = [
994-
'pending',
995-
'running',
996-
'redacting',
997-
'completed',
998-
'failed',
999-
'cancelled',
1000-
] as const satisfies readonly PersistedWorkflowExecutionStatus[]
1001-
1002-
type AssertNever<T extends never> = T
1003-
type _ExhaustiveRunStatus = AssertNever<
1004-
Exclude<PersistedWorkflowExecutionStatus, (typeof V2_PERSISTED_RUN_STATUSES)[number]>
1005-
>
985+
const RUN_STATUS_DESCRIPTION =
986+
'Current or terminal run status. `redacting` is transient, reported while the output of a finished run is being scrubbed. `paused` is reported while the run is waiting at a human-in-the-loop pause point.'
1006987

1007988
/**
1008-
* The list projection overlays `paused` onto the persisted status whenever the run has a
1009-
* `paused` or `partially_resumed` row in `paused_executions`. It cannot report `queued`:
1010-
* a run that is still only in the job queue has no log row to list.
989+
* The list projection passes `workflow_execution_logs.status` through except where it
990+
* overlays `paused` for a run holding a `paused` or `partially_resumed` row in
991+
* `paused_executions`. Both branches land in the persisted set, so the reported enum is
992+
* derived from it — a value missing here fails the response parse, and because list
993+
* validation is whole-page one such row turns an entire page into a 500. `queued` is not
994+
* reportable: a run still only in the job queue has no log row to list.
1011995
*/
1012-
const V2_WORKFLOW_RUN_LIST_STATUSES = [...V2_PERSISTED_RUN_STATUSES, 'paused'] as const
1013-
1014-
const RUN_STATUS_DESCRIPTION =
1015-
'Current or terminal run status. `redacting` is transient, reported while the output of a finished run is being scrubbed.'
1016-
1017996
export const v2WorkflowRunListStatusValueSchema = z
1018-
.enum(V2_WORKFLOW_RUN_LIST_STATUSES)
997+
.enum(PERSISTED_WORKFLOW_EXECUTION_STATUSES)
1019998
.describe(RUN_STATUS_DESCRIPTION)
1020999

10211000
/**
10221001
* The single-run read additionally consults the async job queue by deterministic job id,
10231002
* so a run accepted but not yet started reports `queued` rather than 404.
10241003
*/
10251004
export const v2WorkflowRunStatusValueSchema = z
1026-
.enum([...V2_WORKFLOW_RUN_LIST_STATUSES, 'queued'])
1005+
.enum([...PERSISTED_WORKFLOW_EXECUTION_STATUSES, 'queued'])
10271006
.describe(RUN_STATUS_DESCRIPTION)
10281007

10291008
/**
Collapse file

‎apps/sim/lib/logs/types.ts‎

Copy file name to clipboardExpand all lines: apps/sim/lib/logs/types.ts
+24-6Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -204,13 +204,31 @@ export interface WorkflowExecutionLog {
204204
createdAt: string
205205
}
206206

207+
/**
208+
* Every value written into `workflow_execution_logs.status`. The column is free text and
209+
* one writer sets it through a raw `sql` CASE Drizzle cannot type-check, so this list —
210+
* not the column type — is the only source of truth. API contracts that pass the column
211+
* through derive their enums from it, so adding a status here widens the public wire; the
212+
* contract tests fail until that widening is reviewed and the OpenAPI specs regenerated.
213+
*
214+
* `redacting` is transient while a finished run's output is scrubbed. `paused` is written
215+
* only by `PauseResumeManager.markResumeAttemptFailed`, when a resume attempt does not run
216+
* to completion — it failed admission, the run buffer was unavailable, the resume job could
217+
* not be enqueued, or the attempt was cancelled. An ordinary human-in-the-loop pause
218+
* persists `pending`.
219+
*/
220+
export const PERSISTED_WORKFLOW_EXECUTION_STATUSES = [
221+
'pending',
222+
'running',
223+
'paused',
224+
'redacting',
225+
'completed',
226+
'failed',
227+
'cancelled',
228+
] as const
229+
207230
export type PersistedWorkflowExecutionStatus =
208-
| 'running'
209-
| 'pending'
210-
| 'completed'
211-
| 'failed'
212-
| 'cancelled'
213-
| 'redacting'
231+
(typeof PERSISTED_WORKFLOW_EXECUTION_STATUSES)[number]
214232

215233
export interface CompletedWorkflowExecutionLog extends WorkflowExecutionLog {
216234
persistedStatus: PersistedWorkflowExecutionStatus
Collapse file

‎packages/db/schema.ts‎

Copy file name to clipboardExpand all lines: packages/db/schema.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ export const workflowExecutionLogs = pgTable(
411411
),
412412

413413
level: text('level').notNull(), // 'info' | 'error'
414-
status: text('status').notNull().default('running'), // 'running' | 'pending' | 'completed' | 'failed' | 'cancelled'
414+
status: text('status').notNull().default('running'), // see PERSISTED_WORKFLOW_EXECUTION_STATUSES in apps/sim/lib/logs/types.ts
415415
trigger: text('trigger').notNull(), // 'api' | 'webhook' | 'schedule' | 'manual' | 'chat'
416416

417417
startedAt: timestamp('started_at').notNull(),

0 commit comments

Comments
0 (0)
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.