@stigmer/sdk 3.12.4 → 3.12.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/__tests__/mcpserver-connect.test.d.ts +2 -0
  2. package/__tests__/mcpserver-connect.test.d.ts.map +1 -0
  3. package/__tests__/mcpserver-connect.test.js +146 -0
  4. package/__tests__/mcpserver-connect.test.js.map +1 -0
  5. package/__tests__/update-input-roundtrip.test.d.ts +2 -0
  6. package/__tests__/update-input-roundtrip.test.d.ts.map +1 -0
  7. package/__tests__/update-input-roundtrip.test.js +791 -0
  8. package/__tests__/update-input-roundtrip.test.js.map +1 -0
  9. package/__tests__/update-input.test.d.ts +2 -0
  10. package/__tests__/update-input.test.d.ts.map +1 -0
  11. package/__tests__/update-input.test.js +188 -0
  12. package/__tests__/update-input.test.js.map +1 -0
  13. package/gen/agent.d.ts +21 -0
  14. package/gen/agent.d.ts.map +1 -1
  15. package/gen/agent.js +73 -1
  16. package/gen/agent.js.map +1 -1
  17. package/gen/agentchannel.d.ts +23 -1
  18. package/gen/agentchannel.d.ts.map +1 -1
  19. package/gen/agentchannel.js +55 -1
  20. package/gen/agentchannel.js.map +1 -1
  21. package/gen/agentexecution.d.ts +29 -1
  22. package/gen/agentexecution.d.ts.map +1 -1
  23. package/gen/agentexecution.js +155 -2
  24. package/gen/agentexecution.js.map +1 -1
  25. package/gen/agentinstance.d.ts +21 -0
  26. package/gen/agentinstance.d.ts.map +1 -1
  27. package/gen/agentinstance.js +32 -1
  28. package/gen/agentinstance.js.map +1 -1
  29. package/gen/agentshare.d.ts +23 -1
  30. package/gen/agentshare.d.ts.map +1 -1
  31. package/gen/agentshare.js +53 -1
  32. package/gen/agentshare.js.map +1 -1
  33. package/gen/apikey.d.ts +21 -0
  34. package/gen/apikey.d.ts.map +1 -1
  35. package/gen/apikey.js +33 -1
  36. package/gen/apikey.js.map +1 -1
  37. package/gen/artifact.d.ts +8 -0
  38. package/gen/artifact.d.ts.map +1 -1
  39. package/gen/artifact.js +1 -0
  40. package/gen/artifact.js.map +1 -1
  41. package/gen/channelapp.d.ts +21 -0
  42. package/gen/channelapp.d.ts.map +1 -1
  43. package/gen/channelapp.js +45 -0
  44. package/gen/channelapp.js.map +1 -1
  45. package/gen/client.d.ts +3 -3
  46. package/gen/client.d.ts.map +1 -1
  47. package/gen/environment.d.ts +21 -0
  48. package/gen/environment.d.ts.map +1 -1
  49. package/gen/environment.js +31 -1
  50. package/gen/environment.js.map +1 -1
  51. package/gen/executioncontext.d.ts +8 -0
  52. package/gen/executioncontext.d.ts.map +1 -1
  53. package/gen/executioncontext.js +1 -0
  54. package/gen/executioncontext.js.map +1 -1
  55. package/gen/iampolicy.d.ts +8 -0
  56. package/gen/iampolicy.d.ts.map +1 -1
  57. package/gen/iampolicy.js +1 -0
  58. package/gen/iampolicy.js.map +1 -1
  59. package/gen/identityaccount.d.ts +29 -0
  60. package/gen/identityaccount.d.ts.map +1 -1
  61. package/gen/identityaccount.js +57 -2
  62. package/gen/identityaccount.js.map +1 -1
  63. package/gen/identityprovider.d.ts +21 -0
  64. package/gen/identityprovider.d.ts.map +1 -1
  65. package/gen/identityprovider.js +40 -0
  66. package/gen/identityprovider.js.map +1 -1
  67. package/gen/invitation.d.ts +8 -0
  68. package/gen/invitation.d.ts.map +1 -1
  69. package/gen/invitation.js +1 -0
  70. package/gen/invitation.js.map +1 -1
  71. package/gen/mcpserver.d.ts +22 -0
  72. package/gen/mcpserver.d.ts.map +1 -1
  73. package/gen/mcpserver.js +87 -1
  74. package/gen/mcpserver.js.map +1 -1
  75. package/gen/oauthapp.d.ts +23 -1
  76. package/gen/oauthapp.d.ts.map +1 -1
  77. package/gen/oauthapp.js +40 -0
  78. package/gen/oauthapp.js.map +1 -1
  79. package/gen/organization.d.ts +26 -0
  80. package/gen/organization.d.ts.map +1 -1
  81. package/gen/organization.js +49 -2
  82. package/gen/organization.js.map +1 -1
  83. package/gen/platformclient.d.ts +22 -0
  84. package/gen/platformclient.d.ts.map +1 -1
  85. package/gen/platformclient.js +42 -1
  86. package/gen/platformclient.js.map +1 -1
  87. package/gen/project.d.ts +21 -0
  88. package/gen/project.d.ts.map +1 -1
  89. package/gen/project.js +32 -1
  90. package/gen/project.js.map +1 -1
  91. package/gen/proto-utils.d.ts +36 -0
  92. package/gen/proto-utils.d.ts.map +1 -1
  93. package/gen/proto-utils.js +58 -0
  94. package/gen/proto-utils.js.map +1 -1
  95. package/gen/schedule.d.ts +23 -1
  96. package/gen/schedule.d.ts.map +1 -1
  97. package/gen/schedule.js +79 -1
  98. package/gen/schedule.js.map +1 -1
  99. package/gen/session.d.ts +21 -0
  100. package/gen/session.d.ts.map +1 -1
  101. package/gen/session.js +80 -1
  102. package/gen/session.js.map +1 -1
  103. package/gen/skill.d.ts +8 -0
  104. package/gen/skill.d.ts.map +1 -1
  105. package/gen/skill.js +1 -0
  106. package/gen/skill.js.map +1 -1
  107. package/gen/workflow.d.ts +21 -0
  108. package/gen/workflow.d.ts.map +1 -1
  109. package/gen/workflow.js +79 -0
  110. package/gen/workflow.js.map +1 -1
  111. package/gen/workflowexecution.d.ts +21 -0
  112. package/gen/workflowexecution.d.ts.map +1 -1
  113. package/gen/workflowexecution.js +36 -1
  114. package/gen/workflowexecution.js.map +1 -1
  115. package/gen/workflowinstance.d.ts +21 -0
  116. package/gen/workflowinstance.d.ts.map +1 -1
  117. package/gen/workflowinstance.js +33 -1
  118. package/gen/workflowinstance.js.map +1 -1
  119. package/index.d.ts +21 -20
  120. package/index.d.ts.map +1 -1
  121. package/index.js +25 -21
  122. package/index.js.map +1 -1
  123. package/mcpserver-connect.d.ts +79 -0
  124. package/mcpserver-connect.d.ts.map +1 -0
  125. package/mcpserver-connect.js +114 -0
  126. package/mcpserver-connect.js.map +1 -0
  127. package/package.json +2 -2
  128. package/src/__tests__/mcpserver-connect.test.ts +181 -0
  129. package/src/__tests__/update-input-roundtrip.test.ts +1031 -0
  130. package/src/__tests__/update-input.test.ts +250 -0
  131. package/src/gen/agent.ts +89 -3
  132. package/src/gen/agentchannel.ts +72 -4
  133. package/src/gen/agentexecution.ts +188 -6
  134. package/src/gen/agentinstance.ts +41 -1
  135. package/src/gen/agentshare.ts +68 -4
  136. package/src/gen/apikey.ts +42 -1
  137. package/src/gen/artifact.ts +9 -0
  138. package/src/gen/channelapp.ts +57 -1
  139. package/src/gen/client.ts +3 -3
  140. package/src/gen/environment.ts +40 -1
  141. package/src/gen/executioncontext.ts +9 -0
  142. package/src/gen/iampolicy.ts +9 -0
  143. package/src/gen/identityaccount.ts +77 -2
  144. package/src/gen/identityprovider.ts +49 -0
  145. package/src/gen/invitation.ts +9 -0
  146. package/src/gen/mcpserver.ts +101 -3
  147. package/src/gen/oauthapp.ts +51 -1
  148. package/src/gen/organization.ts +66 -2
  149. package/src/gen/platformclient.ts +52 -1
  150. package/src/gen/project.ts +41 -1
  151. package/src/gen/proto-utils.ts +64 -0
  152. package/src/gen/schedule.ts +98 -4
  153. package/src/gen/session.ts +97 -3
  154. package/src/gen/skill.ts +9 -0
  155. package/src/gen/workflow.ts +96 -2
  156. package/src/gen/workflowexecution.ts +45 -1
  157. package/src/gen/workflowinstance.ts +42 -1
  158. package/src/index.ts +32 -3
  159. package/src/mcpserver-connect.ts +159 -0
@@ -0,0 +1,791 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { create, toJson, isFieldSet, } from "@bufbuild/protobuf";
3
+ import { timestampFromDate } from "@bufbuild/protobuf/wkt";
4
+ import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
5
+ import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
6
+ import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
7
+ import { AgentSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
8
+ import { AgentChannelSchema } from "@stigmer/protos/ai/stigmer/agentic/agentchannel/v1/api_pb";
9
+ import { AgentChannelSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agentchannel/v1/spec_pb";
10
+ import { AgentExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
11
+ import { AgentExecutionSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/spec_pb";
12
+ import { InteractionMode, ApprovalMode, ServiceTier, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
13
+ import { AgentInstanceSchema } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/api_pb";
14
+ import { AgentInstanceSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/spec_pb";
15
+ import { AgentShareSchema } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/api_pb";
16
+ import { AgentShareSpecSchema, AgentShareAudience, } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/spec_pb";
17
+ import { ApiKeySchema } from "@stigmer/protos/ai/stigmer/iam/apikey/v1/api_pb";
18
+ import { ApiKeySpecSchema } from "@stigmer/protos/ai/stigmer/iam/apikey/v1/spec_pb";
19
+ import { ChannelAppSchema } from "@stigmer/protos/ai/stigmer/agentic/channelapp/v1/api_pb";
20
+ import { ChannelAppSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/channelapp/v1/spec_pb";
21
+ import { EnvironmentSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
22
+ import { EnvironmentSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/spec_pb";
23
+ import { IdentityAccountSchema } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/api_pb";
24
+ import { IdentityAccountSpecSchema } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/spec_pb";
25
+ import { IdentityAccountProvisioningMode } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/enum_pb";
26
+ import { IdentityProviderSchema } from "@stigmer/protos/ai/stigmer/iam/identityprovider/v1/api_pb";
27
+ import { IdentityProviderSpecSchema } from "@stigmer/protos/ai/stigmer/iam/identityprovider/v1/spec_pb";
28
+ import { IamRole } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
29
+ import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
30
+ import { McpServerSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/spec_pb";
31
+ import { OAuthAppSchema } from "@stigmer/protos/ai/stigmer/iam/oauthapp/v1/api_pb";
32
+ import { OAuthAppSpecSchema, VendorApprovalStatus, TokenEndpointAuthMethod, } from "@stigmer/protos/ai/stigmer/iam/oauthapp/v1/spec_pb";
33
+ import { OrganizationSchema } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/api_pb";
34
+ import { OrganizationSpecSchema } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/spec_pb";
35
+ import { ManagementMode } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/enum_pb";
36
+ import { PlatformClientSchema } from "@stigmer/protos/ai/stigmer/iam/platformclient/v1/api_pb";
37
+ import { PlatformClientSpecSchema } from "@stigmer/protos/ai/stigmer/iam/platformclient/v1/spec_pb";
38
+ import { ProjectSchema } from "@stigmer/protos/ai/stigmer/tenancy/project/v1/api_pb";
39
+ import { ProjectSpecSchema } from "@stigmer/protos/ai/stigmer/tenancy/project/v1/spec_pb";
40
+ import { ScheduleSchema } from "@stigmer/protos/ai/stigmer/agentic/schedule/v1/api_pb";
41
+ import { ScheduleSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/schedule/v1/spec_pb";
42
+ import { SessionSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
43
+ import { SessionSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/spec_pb";
44
+ import { Harness, CursorMode, ExecutionTarget, GitWriteBackMode, } from "@stigmer/protos/ai/stigmer/agentic/session/v1/enum_pb";
45
+ import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
46
+ import { WorkflowSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/spec_pb";
47
+ import { WorkflowTaskKind, BudgetExceededPolicy, } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/enum_pb";
48
+ import { WorkflowExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/api_pb";
49
+ import { WorkflowExecutionSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/spec_pb";
50
+ import { WorkflowInstanceSchema } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/api_pb";
51
+ import { WorkflowInstanceSpecSchema, WorkflowExecutionVisibility, } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/spec_pb";
52
+ import { buildAgentProto, toAgentUpdateInput } from "../gen/agent";
53
+ import { buildAgentChannelProto, toAgentChannelUpdateInput } from "../gen/agentchannel";
54
+ import { buildAgentExecutionProto, toAgentExecutionUpdateInput } from "../gen/agentexecution";
55
+ import { buildAgentInstanceProto, toAgentInstanceUpdateInput } from "../gen/agentinstance";
56
+ import { buildAgentShareProto, toAgentShareUpdateInput } from "../gen/agentshare";
57
+ import { buildApiKeyProto, toApiKeyUpdateInput } from "../gen/apikey";
58
+ import { buildChannelAppProto, toChannelAppUpdateInput } from "../gen/channelapp";
59
+ import { buildEnvironmentProto, toEnvironmentUpdateInput } from "../gen/environment";
60
+ import { buildIdentityAccountProto, toIdentityAccountUpdateInput } from "../gen/identityaccount";
61
+ import { buildIdentityProviderProto, toIdentityProviderUpdateInput } from "../gen/identityprovider";
62
+ import { buildMcpServerProto, toMcpServerUpdateInput } from "../gen/mcpserver";
63
+ import { buildOAuthAppProto, toOAuthAppUpdateInput } from "../gen/oauthapp";
64
+ import { buildOrganizationProto, toOrganizationUpdateInput } from "../gen/organization";
65
+ import { buildPlatformClientProto, toPlatformClientUpdateInput } from "../gen/platformclient";
66
+ import { buildProjectProto, toProjectUpdateInput } from "../gen/project";
67
+ import { buildScheduleProto, toScheduleUpdateInput } from "../gen/schedule";
68
+ import { buildSessionProto, toSessionUpdateInput } from "../gen/session";
69
+ import { buildWorkflowProto, toWorkflowUpdateInput } from "../gen/workflow";
70
+ import { buildWorkflowExecutionProto, toWorkflowExecutionUpdateInput } from "../gen/workflowexecution";
71
+ import { buildWorkflowInstanceProto, toWorkflowInstanceUpdateInput } from "../gen/workflowinstance";
72
+ /**
73
+ * Systematic wipe-bug guard for every generated toXxxUpdateInput mapper
74
+ * (update RPCs are full-spec replacements — see gen/proto-utils.ts and the
75
+ * mapper JSDoc). Three layers per resource, generalizing the pattern that
76
+ * caught oss#319:
77
+ *
78
+ * 1. SCHEMA TRIPWIRE — proto reflection asserts the fixture populates
79
+ * EVERY top-level spec field (one arm per oneof). When a proto gains a
80
+ * field, this fails first, forcing the fixture forward; the round-trip
81
+ * then proves the regenerated mapper carries it.
82
+ * 2. ROUND-TRIP — build(toUpdateInput(fixture)) must reproduce the spec
83
+ * exactly (compared as JSON, defaults omitted). Nested sub-fields are
84
+ * covered by population: every nested value in a fixture is
85
+ * non-default, so a dropped nested field breaks equality.
86
+ * 3. METADATA — name/slug/org/labels survive; visibility is carried
87
+ * (idempotent — the server preserves it regardless, oss#573).
88
+ */
89
+ const META = {
90
+ id: "res-123",
91
+ name: "Fixture Resource",
92
+ slug: "fixture-resource",
93
+ org: "acme",
94
+ labels: { team: "platform" },
95
+ visibility: ApiResourceVisibility.visibility_private,
96
+ };
97
+ function assertFixtureCoversSpec(schema, spec) {
98
+ for (const field of schema.fields) {
99
+ if (field.oneof)
100
+ continue; // oneofs are asserted as a group below
101
+ expect(isFieldSet(spec, field), `fixture must populate ${schema.typeName}.${field.name} — a new proto ` +
102
+ `field lands here first; add it to the fixture, then the round-trip ` +
103
+ `test proves the regenerated mapper carries it`).toBe(true);
104
+ }
105
+ for (const oneof of schema.oneofs) {
106
+ const value = spec[oneof.localName];
107
+ expect(value?.case, `fixture must set one arm of ${schema.typeName}.${oneof.name}`).toBeDefined();
108
+ }
109
+ }
110
+ function assertSpecRoundTrip(specSchema, original, rebuilt) {
111
+ expect(toJson(specSchema, rebuilt.spec)).toEqual(toJson(specSchema, original.spec));
112
+ expect(rebuilt.metadata?.name).toBe(META.name);
113
+ expect(rebuilt.metadata?.slug).toBe(META.slug);
114
+ expect(rebuilt.metadata?.org).toBe(META.org);
115
+ expect(rebuilt.metadata?.labels).toEqual(META.labels);
116
+ expect(rebuilt.metadata?.visibility).toBe(META.visibility);
117
+ }
118
+ // ---------------------------------------------------------------------------
119
+ // Shared nested fixtures
120
+ // ---------------------------------------------------------------------------
121
+ const MCP_USAGE = {
122
+ mcpServerRef: {
123
+ org: "acme",
124
+ slug: "github-mcp",
125
+ version: "v3",
126
+ kind: ApiResourceKind.mcp_server,
127
+ },
128
+ enabledTools: ["create_issue"],
129
+ toolApprovalOverrides: [
130
+ { toolName: "create_issue", requiresApproval: true, message: "Careful." },
131
+ ],
132
+ };
133
+ const WORKSPACE_ENTRIES = [
134
+ {
135
+ name: "repo",
136
+ source: {
137
+ source: {
138
+ case: "gitRepo",
139
+ value: {
140
+ url: "https://github.com/acme/app.git",
141
+ branch: "main",
142
+ commit: "abc123",
143
+ depth: 1,
144
+ writeBackMode: GitWriteBackMode.GIT_WRITE_BACK_BRANCH_AND_PR,
145
+ },
146
+ },
147
+ },
148
+ },
149
+ {
150
+ name: "scratch",
151
+ source: { source: { case: "localPath", value: { path: "/tmp/scratch" } } },
152
+ },
153
+ ];
154
+ const RUN_CONFIG = {
155
+ modelName: "claude-sonnet-4.6",
156
+ maxCostUsd: 4,
157
+ maxToolRounds: 30,
158
+ serviceTier: ServiceTier.FAST,
159
+ };
160
+ // ---------------------------------------------------------------------------
161
+ // Per-resource fixtures + suites
162
+ // ---------------------------------------------------------------------------
163
+ describe("toAgentUpdateInput", () => {
164
+ const fixture = () => create(AgentSchema, {
165
+ metadata: META,
166
+ spec: {
167
+ description: "Handles support tickets.",
168
+ iconUrl: "https://acme.example/agent.png",
169
+ instructions: "Be terse.",
170
+ mcpServerUsages: [MCP_USAGE],
171
+ skillRefs: [
172
+ { org: "acme", slug: "triage", version: "v2", kind: ApiResourceKind.skill },
173
+ ],
174
+ subAgents: [
175
+ {
176
+ name: "researcher",
177
+ description: "Digs into logs.",
178
+ instructions: "Cite sources.",
179
+ mcpAccess: [{ mcpServer: "github-mcp", enabledTools: ["search_code"] }],
180
+ skillRefs: [
181
+ { org: "acme", slug: "log-analysis", version: "v1", kind: ApiResourceKind.skill },
182
+ ],
183
+ modelOverride: "gpt-5.6-sol",
184
+ },
185
+ ],
186
+ env: { API_KEY: { isSecret: true, description: "Vendor key", optional: true } },
187
+ },
188
+ });
189
+ it("fixture covers every AgentSpec field (schema tripwire)", () => {
190
+ assertFixtureCoversSpec(AgentSpecSchema, fixture().spec);
191
+ });
192
+ it("round-trips the full spec and metadata through the builder", () => {
193
+ const original = fixture();
194
+ assertSpecRoundTrip(AgentSpecSchema, original, buildAgentProto(toAgentUpdateInput(original)));
195
+ });
196
+ });
197
+ describe("toAgentChannelUpdateInput", () => {
198
+ const fixture = () => create(AgentChannelSchema, {
199
+ metadata: META,
200
+ spec: {
201
+ agentRef: { org: "acme", slug: "support-bot", kind: ApiResourceKind.agent },
202
+ enabled: true,
203
+ providerConfig: { case: "slack", value: {} },
204
+ environmentRefs: [
205
+ { org: "acme", slug: "prod", kind: ApiResourceKind.environment },
206
+ ],
207
+ appRef: { org: "acme", slug: "acme-slack", kind: ApiResourceKind.channel_app },
208
+ proactiveMessagingEnabled: true,
209
+ runConfig: RUN_CONFIG,
210
+ },
211
+ });
212
+ it("fixture covers every AgentChannelSpec field (schema tripwire)", () => {
213
+ assertFixtureCoversSpec(AgentChannelSpecSchema, fixture().spec);
214
+ });
215
+ it("round-trips the full spec and metadata through the builder", () => {
216
+ const original = fixture();
217
+ assertSpecRoundTrip(AgentChannelSpecSchema, original, buildAgentChannelProto(toAgentChannelUpdateInput(original)));
218
+ });
219
+ });
220
+ describe("toAgentExecutionUpdateInput", () => {
221
+ const fixture = () => create(AgentExecutionSchema, {
222
+ metadata: META,
223
+ spec: {
224
+ sessionId: "sess-1",
225
+ agentId: "agent-1",
226
+ sessionSpec: {
227
+ agentInstanceId: "inst-1",
228
+ subject: "Fix the flaky test",
229
+ harnessStateId: "hs-1",
230
+ harnessStateIdHistory: ["hs-0"],
231
+ metadata: { "stigmer.ai/context": "embedded" },
232
+ workspaceEntries: WORKSPACE_ENTRIES,
233
+ mcpServerUsages: [MCP_USAGE],
234
+ skillRefs: [
235
+ { org: "acme", slug: "triage", version: "v2", kind: ApiResourceKind.skill },
236
+ ],
237
+ harness: Harness.CURSOR,
238
+ cursorMode: CursorMode.CLOUD,
239
+ executionTarget: ExecutionTarget.CLOUD,
240
+ },
241
+ message: "Please fix it.",
242
+ executionConfig: {
243
+ modelName: "claude-sonnet-4.6",
244
+ contextManagement: {
245
+ disableSummarization: true,
246
+ customTriggerThreshold: 90,
247
+ customTargetTokens: 50000,
248
+ },
249
+ maxToolRounds: 40,
250
+ maxToolResultChars: 20000,
251
+ maxCostUsd: 8,
252
+ interactionMode: InteractionMode.PLAN,
253
+ structuredOutputSchema: { type: "object" },
254
+ buildFromPlan: true,
255
+ approvalMode: ApprovalMode.UNATTENDED,
256
+ serviceTier: ServiceTier.FAST,
257
+ },
258
+ runtimeEnv: { TOKEN: { value: "shh", isSecret: true } },
259
+ callbackToken: new Uint8Array([1, 2, 3]),
260
+ autoApproveAll: true,
261
+ parentWorkflowId: "wf-1",
262
+ attachments: [
263
+ {
264
+ filename: "spec.pdf",
265
+ storageKey: "att/spec.pdf",
266
+ mountPath: "/work/spec.pdf",
267
+ contentType: "application/pdf",
268
+ extract: true,
269
+ localPath: "/tmp/spec.pdf",
270
+ },
271
+ ],
272
+ workspaceFileRefs: ["src/app.ts"],
273
+ activityTaskQueue: "runner-q",
274
+ supersedesExecutionId: "exec-0",
275
+ conversationCatchup: {
276
+ digest: "Prior turns summarized.",
277
+ windowEnd: timestampFromDate(new Date("2026-08-15T10:00:00Z")),
278
+ },
279
+ declaredPreferences: {
280
+ orgContext: "We deploy to us-east-1.",
281
+ userContext: "Keep answers terse.",
282
+ },
283
+ },
284
+ });
285
+ it("fixture covers every AgentExecutionSpec field (schema tripwire)", () => {
286
+ assertFixtureCoversSpec(AgentExecutionSpecSchema, fixture().spec);
287
+ });
288
+ it("round-trips the full spec and metadata through the builder", () => {
289
+ const original = fixture();
290
+ assertSpecRoundTrip(AgentExecutionSpecSchema, original, buildAgentExecutionProto(toAgentExecutionUpdateInput(original)));
291
+ });
292
+ });
293
+ describe("toAgentInstanceUpdateInput", () => {
294
+ const fixture = () => create(AgentInstanceSchema, {
295
+ metadata: META,
296
+ spec: {
297
+ agentId: "agent-1",
298
+ description: "Prod instance.",
299
+ environmentRefs: [
300
+ { org: "acme", slug: "prod", kind: ApiResourceKind.environment },
301
+ ],
302
+ },
303
+ });
304
+ it("fixture covers every AgentInstanceSpec field (schema tripwire)", () => {
305
+ assertFixtureCoversSpec(AgentInstanceSpecSchema, fixture().spec);
306
+ });
307
+ it("round-trips the full spec and metadata through the builder", () => {
308
+ const original = fixture();
309
+ assertSpecRoundTrip(AgentInstanceSpecSchema, original, buildAgentInstanceProto(toAgentInstanceUpdateInput(original)));
310
+ });
311
+ });
312
+ describe("toAgentShareUpdateInput", () => {
313
+ const fixture = () => create(AgentShareSchema, {
314
+ metadata: META,
315
+ spec: {
316
+ agentRef: { org: "acme", slug: "support-bot", kind: ApiResourceKind.agent },
317
+ enabled: true,
318
+ audience: AgentShareAudience.org,
319
+ allowedOrigins: ["https://acme.example"],
320
+ messages: {
321
+ rateLimited: "Slow down.",
322
+ unavailable: "Back soon.",
323
+ conversationEnded: "Bye.",
324
+ },
325
+ environmentRefs: [
326
+ { org: "acme", slug: "prod", kind: ApiResourceKind.environment },
327
+ ],
328
+ runConfig: RUN_CONFIG,
329
+ },
330
+ });
331
+ it("fixture covers every AgentShareSpec field (schema tripwire)", () => {
332
+ assertFixtureCoversSpec(AgentShareSpecSchema, fixture().spec);
333
+ });
334
+ it("round-trips the full spec and metadata through the builder", () => {
335
+ const original = fixture();
336
+ assertSpecRoundTrip(AgentShareSpecSchema, original, buildAgentShareProto(toAgentShareUpdateInput(original)));
337
+ });
338
+ });
339
+ describe("toApiKeyUpdateInput", () => {
340
+ const fixture = () => create(ApiKeySchema, {
341
+ metadata: META,
342
+ spec: {
343
+ keyHash: "sha256:abcd",
344
+ fingerprint: "fp-1234",
345
+ expiresAt: timestampFromDate(new Date("2027-01-01T00:00:00Z")),
346
+ neverExpires: true,
347
+ },
348
+ });
349
+ it("fixture covers every ApiKeySpec field (schema tripwire)", () => {
350
+ assertFixtureCoversSpec(ApiKeySpecSchema, fixture().spec);
351
+ });
352
+ it("round-trips the full spec and metadata through the builder", () => {
353
+ const original = fixture();
354
+ assertSpecRoundTrip(ApiKeySpecSchema, original, buildApiKeyProto(toApiKeyUpdateInput(original)));
355
+ });
356
+ });
357
+ describe("toChannelAppUpdateInput", () => {
358
+ const slackFixture = () => create(ChannelAppSchema, {
359
+ metadata: META,
360
+ spec: {
361
+ providerConfig: {
362
+ case: "slack",
363
+ value: { clientId: "1234.5678", clientSecret: "shh", signingSecret: "sign" },
364
+ },
365
+ },
366
+ });
367
+ const whatsappFixture = () => create(ChannelAppSchema, {
368
+ metadata: META,
369
+ spec: {
370
+ providerConfig: {
371
+ case: "whatsapp",
372
+ value: { appId: "wa-1", appSecret: "shh", accessToken: "tok", verifyToken: "vrfy" },
373
+ },
374
+ },
375
+ });
376
+ it("fixture covers every ChannelAppSpec field (schema tripwire)", () => {
377
+ assertFixtureCoversSpec(ChannelAppSpecSchema, slackFixture().spec);
378
+ });
379
+ it("round-trips the slack arm through the builder", () => {
380
+ const original = slackFixture();
381
+ assertSpecRoundTrip(ChannelAppSpecSchema, original, buildChannelAppProto(toChannelAppUpdateInput(original)));
382
+ });
383
+ it("round-trips the whatsapp arm through the builder", () => {
384
+ const original = whatsappFixture();
385
+ assertSpecRoundTrip(ChannelAppSpecSchema, original, buildChannelAppProto(toChannelAppUpdateInput(original)));
386
+ });
387
+ });
388
+ describe("toEnvironmentUpdateInput", () => {
389
+ const fixture = () => create(EnvironmentSchema, {
390
+ metadata: META,
391
+ spec: {
392
+ description: "Prod secrets.",
393
+ data: {
394
+ API_KEY: { value: "shh", isSecret: true, description: "Vendor key" },
395
+ },
396
+ },
397
+ });
398
+ it("fixture covers every EnvironmentSpec field (schema tripwire)", () => {
399
+ assertFixtureCoversSpec(EnvironmentSpecSchema, fixture().spec);
400
+ });
401
+ it("round-trips the full spec and metadata through the builder", () => {
402
+ const original = fixture();
403
+ assertSpecRoundTrip(EnvironmentSpecSchema, original, buildEnvironmentProto(toEnvironmentUpdateInput(original)));
404
+ });
405
+ });
406
+ describe("toIdentityAccountUpdateInput (tripwire)", () => {
407
+ const fixture = () => create(IdentityAccountSchema, {
408
+ metadata: META,
409
+ spec: {
410
+ idpId: "auth0|abc123",
411
+ email: "ada@acme.example",
412
+ firstName: "Ada",
413
+ lastName: "Lovelace",
414
+ pictureUrl: "https://acme.example/ada.png",
415
+ isMachineAccount: true,
416
+ provisioningMode: IdentityAccountProvisioningMode.federated,
417
+ identityProviderRef: {
418
+ org: "acme",
419
+ slug: "acme-okta",
420
+ kind: ApiResourceKind.identity_provider,
421
+ },
422
+ preferences: {
423
+ standingContext: "Keep answers terse.",
424
+ defaultHarness: "cursor",
425
+ defaultNativeModel: "claude-sonnet-4.6",
426
+ defaultCursorModel: "composer-2.5",
427
+ },
428
+ },
429
+ });
430
+ it("fixture covers every IdentityAccountSpec field (schema tripwire)", () => {
431
+ assertFixtureCoversSpec(IdentityAccountSpecSchema, fixture().spec);
432
+ });
433
+ it("round-trips the full spec and metadata through the builder", () => {
434
+ const original = fixture();
435
+ assertSpecRoundTrip(IdentityAccountSpecSchema, original, buildIdentityAccountProto(toIdentityAccountUpdateInput(original)));
436
+ });
437
+ });
438
+ describe("toIdentityProviderUpdateInput", () => {
439
+ const fixture = () => create(IdentityProviderSchema, {
440
+ metadata: META,
441
+ spec: {
442
+ displayName: "Acme Okta",
443
+ jwksUri: "https://acme.okta.example/jwks",
444
+ allowedIssuers: ["https://acme.okta.example"],
445
+ expectedAudience: "stigmer",
446
+ rateLimitBudget: 120,
447
+ userinfoEndpoint: "https://acme.okta.example/userinfo",
448
+ isSsoProvider: true,
449
+ oidcClientId: "oidc-123",
450
+ autoProvisionAccounts: true,
451
+ autoGrantOnOrg: true,
452
+ autoGrantRole: IamRole.admin,
453
+ tenantOrgClaim: "org_slug",
454
+ },
455
+ });
456
+ it("fixture covers every IdentityProviderSpec field (schema tripwire)", () => {
457
+ assertFixtureCoversSpec(IdentityProviderSpecSchema, fixture().spec);
458
+ });
459
+ it("round-trips the full spec and metadata through the builder", () => {
460
+ const original = fixture();
461
+ assertSpecRoundTrip(IdentityProviderSpecSchema, original, buildIdentityProviderProto(toIdentityProviderUpdateInput(original)));
462
+ });
463
+ it("preserves rate_limit_budget when only the display name changes (live wipe bug)", () => {
464
+ const original = fixture();
465
+ const rebuilt = buildIdentityProviderProto({
466
+ ...toIdentityProviderUpdateInput(original),
467
+ displayName: "Acme Okta (renamed)",
468
+ });
469
+ expect(rebuilt.spec?.rateLimitBudget).toBe(120);
470
+ expect(rebuilt.spec?.displayName).toBe("Acme Okta (renamed)");
471
+ });
472
+ });
473
+ describe("toMcpServerUpdateInput", () => {
474
+ const fixture = () => create(McpServerSchema, {
475
+ metadata: META,
476
+ spec: {
477
+ description: "GitHub tools.",
478
+ iconUrl: "https://acme.example/mcp.png",
479
+ tags: ["devtools"],
480
+ serverType: {
481
+ case: "stdio",
482
+ value: { command: "npx", args: ["-y", "github-mcp"], workingDir: "/srv" },
483
+ },
484
+ defaultEnabledTools: ["search_code"],
485
+ env: { GH_TOKEN: { isSecret: true, description: "PAT", optional: true } },
486
+ pinnedToolApprovals: [
487
+ { toolName: "create_issue", message: "Writes data.", fromDestructiveHint: true },
488
+ ],
489
+ repositoryUrl: "https://github.com/acme/github-mcp",
490
+ githubStars: 4200,
491
+ auth: {
492
+ oauthAppRef: { org: "acme", slug: "gh-oauth", kind: ApiResourceKind.oauth_app },
493
+ targetEnvVar: "GH_TOKEN",
494
+ tokenLifetimeHint: "8h",
495
+ scopeHints: ["repo"],
496
+ discoveryUrl: "https://github.com/.well-known/oauth",
497
+ oauthOnly: true,
498
+ },
499
+ },
500
+ });
501
+ it("fixture covers every McpServerSpec field (schema tripwire)", () => {
502
+ assertFixtureCoversSpec(McpServerSpecSchema, fixture().spec);
503
+ });
504
+ it("round-trips the stdio arm through the builder", () => {
505
+ const original = fixture();
506
+ assertSpecRoundTrip(McpServerSpecSchema, original, buildMcpServerProto(toMcpServerUpdateInput(original)));
507
+ });
508
+ it("round-trips the http arm through the builder", () => {
509
+ const original = create(McpServerSchema, {
510
+ metadata: META,
511
+ spec: {
512
+ serverType: {
513
+ case: "http",
514
+ value: {
515
+ url: "https://mcp.acme.example",
516
+ headers: { Authorization: "Bearer x" },
517
+ queryParams: { v: "1" },
518
+ timeoutSeconds: 30,
519
+ },
520
+ },
521
+ },
522
+ });
523
+ assertSpecRoundTrip(McpServerSpecSchema, original, buildMcpServerProto(toMcpServerUpdateInput(original)));
524
+ });
525
+ });
526
+ describe("toOAuthAppUpdateInput", () => {
527
+ const fixture = () => create(OAuthAppSchema, {
528
+ metadata: META,
529
+ spec: {
530
+ provider: "github",
531
+ clientId: "gh-client-1",
532
+ clientSecret: "***REDACTED***",
533
+ authorizationUrl: "https://github.com/login/oauth/authorize",
534
+ tokenUrl: "https://github.com/login/oauth/access_token",
535
+ scopes: ["repo", "read:user"],
536
+ userinfoUrl: "https://api.github.com/user",
537
+ scopeParameterName: "scope",
538
+ vendorApprovalStatus: VendorApprovalStatus.APPROVED,
539
+ vendorApprovalDocsUrl: "https://acme.example/vendor-docs",
540
+ tokenEndpointAuthMethod: TokenEndpointAuthMethod.CLIENT_SECRET_POST,
541
+ },
542
+ });
543
+ it("fixture covers every OAuthAppSpec field (schema tripwire)", () => {
544
+ assertFixtureCoversSpec(OAuthAppSpecSchema, fixture().spec);
545
+ });
546
+ it("round-trips the full spec (incl. the redaction marker) through the builder", () => {
547
+ // Sending the redaction marker back means "keep the stored secret" —
548
+ // the server's EncryptClientSecretForUpdateStep preserves on redacted.
549
+ const original = fixture();
550
+ assertSpecRoundTrip(OAuthAppSpecSchema, original, buildOAuthAppProto(toOAuthAppUpdateInput(original)));
551
+ });
552
+ });
553
+ describe("toOrganizationUpdateInput (tripwire)", () => {
554
+ const fixture = () => create(OrganizationSchema, {
555
+ metadata: META,
556
+ spec: {
557
+ description: "We make everything.",
558
+ logoUrl: "https://acme.example/logo.png",
559
+ managementMode: ManagementMode.self_managed,
560
+ identityProviderRef: {
561
+ org: "acme",
562
+ slug: "acme-okta",
563
+ kind: ApiResourceKind.identity_provider,
564
+ },
565
+ externalOrgId: "ext-org-1",
566
+ isPersonal: true,
567
+ preferences: { standingContext: "We deploy to us-east-1." },
568
+ },
569
+ });
570
+ it("fixture covers every OrganizationSpec field (schema tripwire)", () => {
571
+ assertFixtureCoversSpec(OrganizationSpecSchema, fixture().spec);
572
+ });
573
+ it("round-trips the full spec and metadata through the builder", () => {
574
+ const original = fixture();
575
+ assertSpecRoundTrip(OrganizationSpecSchema, original, buildOrganizationProto(toOrganizationUpdateInput(original)));
576
+ });
577
+ });
578
+ describe("toPlatformClientUpdateInput", () => {
579
+ const fixture = () => create(PlatformClientSchema, {
580
+ metadata: META,
581
+ spec: {
582
+ clientId: "pc-1",
583
+ clientSecretHash: "sha256:hash",
584
+ secretFingerprint: "fp-1",
585
+ expiresAt: timestampFromDate(new Date("2027-06-01T00:00:00Z")),
586
+ neverExpires: true,
587
+ autoProvisionAccounts: true,
588
+ autoGrantOnOrg: true,
589
+ autoGrantRole: IamRole.owner,
590
+ allowedOrigins: ["https://embed.acme.example"],
591
+ environmentRefs: [
592
+ { org: "acme", slug: "prod", kind: ApiResourceKind.environment },
593
+ ],
594
+ },
595
+ });
596
+ it("fixture covers every PlatformClientSpec field (schema tripwire)", () => {
597
+ assertFixtureCoversSpec(PlatformClientSpecSchema, fixture().spec);
598
+ });
599
+ it("round-trips the full spec and metadata through the builder", () => {
600
+ const original = fixture();
601
+ assertSpecRoundTrip(PlatformClientSpecSchema, original, buildPlatformClientProto(toPlatformClientUpdateInput(original)));
602
+ });
603
+ it("preserves environment_refs when only origins change (live wipe bug)", () => {
604
+ const original = fixture();
605
+ const rebuilt = buildPlatformClientProto({
606
+ ...toPlatformClientUpdateInput(original),
607
+ allowedOrigins: ["https://other.acme.example"],
608
+ });
609
+ expect(rebuilt.spec?.environmentRefs.map((r) => r.slug)).toEqual(["prod"]);
610
+ expect(rebuilt.spec?.allowedOrigins).toEqual(["https://other.acme.example"]);
611
+ });
612
+ });
613
+ describe("toProjectUpdateInput", () => {
614
+ const fixture = () => create(ProjectSchema, {
615
+ metadata: META,
616
+ spec: {
617
+ entryPoint: "apps/web",
618
+ description: "Customer portal.",
619
+ members: [{ org: "acme", slug: "ada" }],
620
+ },
621
+ });
622
+ it("fixture covers every ProjectSpec field (schema tripwire)", () => {
623
+ assertFixtureCoversSpec(ProjectSpecSchema, fixture().spec);
624
+ });
625
+ it("round-trips the full spec and metadata through the builder", () => {
626
+ const original = fixture();
627
+ assertSpecRoundTrip(ProjectSpecSchema, original, buildProjectProto(toProjectUpdateInput(original)));
628
+ });
629
+ });
630
+ describe("toScheduleUpdateInput", () => {
631
+ const fixture = () => create(ScheduleSchema, {
632
+ metadata: META,
633
+ spec: {
634
+ cron: "0 9 * * 1",
635
+ timeZone: "America/New_York",
636
+ enabled: true,
637
+ target: {
638
+ case: "agent",
639
+ value: {
640
+ agentRef: { org: "acme", slug: "support-bot", kind: ApiResourceKind.agent },
641
+ message: "Weekly triage.",
642
+ harness: Harness.NATIVE,
643
+ workspaceEntries: WORKSPACE_ENTRIES,
644
+ environmentRefs: [
645
+ { org: "acme", slug: "prod", kind: ApiResourceKind.environment },
646
+ ],
647
+ runConfig: RUN_CONFIG,
648
+ },
649
+ },
650
+ },
651
+ });
652
+ it("fixture covers every ScheduleSpec field (schema tripwire)", () => {
653
+ assertFixtureCoversSpec(ScheduleSpecSchema, fixture().spec);
654
+ });
655
+ it("round-trips the full spec and metadata through the builder", () => {
656
+ const original = fixture();
657
+ assertSpecRoundTrip(ScheduleSpecSchema, original, buildScheduleProto(toScheduleUpdateInput(original)));
658
+ });
659
+ });
660
+ describe("toSessionUpdateInput", () => {
661
+ const fixture = () => create(SessionSchema, {
662
+ metadata: META,
663
+ spec: {
664
+ agentInstanceId: "inst-1",
665
+ subject: "Fix the flaky test",
666
+ harnessStateId: "hs-1",
667
+ harnessStateIdHistory: ["hs-0"],
668
+ metadata: { "stigmer.ai/context": "embedded" },
669
+ workspaceEntries: WORKSPACE_ENTRIES,
670
+ mcpServerUsages: [MCP_USAGE],
671
+ skillRefs: [
672
+ { org: "acme", slug: "triage", version: "v2", kind: ApiResourceKind.skill },
673
+ ],
674
+ harness: Harness.CURSOR,
675
+ cursorMode: CursorMode.CLOUD,
676
+ executionTarget: ExecutionTarget.CLOUD,
677
+ },
678
+ });
679
+ it("fixture covers every SessionSpec field (schema tripwire)", () => {
680
+ assertFixtureCoversSpec(SessionSpecSchema, fixture().spec);
681
+ });
682
+ it("round-trips the full spec and metadata through the builder", () => {
683
+ const original = fixture();
684
+ assertSpecRoundTrip(SessionSpecSchema, original, buildSessionProto(toSessionUpdateInput(original)));
685
+ });
686
+ it("preserves harness state history when only the subject changes (hand-written mapper gap)", () => {
687
+ const original = fixture();
688
+ const rebuilt = buildSessionProto({
689
+ ...toSessionUpdateInput(original),
690
+ subject: "New subject",
691
+ });
692
+ expect(rebuilt.spec?.harnessStateIdHistory).toEqual(["hs-0"]);
693
+ expect(rebuilt.spec?.subject).toBe("New subject");
694
+ });
695
+ });
696
+ describe("toWorkflowUpdateInput", () => {
697
+ const fixture = () => create(WorkflowSchema, {
698
+ metadata: META,
699
+ spec: {
700
+ description: "Nightly triage.",
701
+ document: {
702
+ dsl: "1.0",
703
+ namespace: "acme",
704
+ name: "nightly-triage",
705
+ version: "0.2.0",
706
+ description: "Runs every night.",
707
+ },
708
+ tasks: [
709
+ {
710
+ name: "call-api",
711
+ kind: WorkflowTaskKind.http_call,
712
+ taskConfig: { url: "https://api.acme.example/tickets" },
713
+ export: { as: "tickets" },
714
+ flow: { then: "triage" },
715
+ compensate: [
716
+ {
717
+ name: "undo",
718
+ kind: WorkflowTaskKind.set_vars,
719
+ taskConfig: { variables: { rolledBack: true } },
720
+ },
721
+ ],
722
+ },
723
+ ],
724
+ env: { API_KEY: { isSecret: true, description: "Vendor key", optional: true } },
725
+ budget: {
726
+ maxCostMicros: 5000000n,
727
+ maxTotalTokens: 2000000n,
728
+ maxDurationSeconds: 1800,
729
+ onExceeded: BudgetExceededPolicy.budget_exceeded_human_review,
730
+ },
731
+ },
732
+ });
733
+ it("fixture covers every WorkflowSpec field (schema tripwire)", () => {
734
+ assertFixtureCoversSpec(WorkflowSpecSchema, fixture().spec);
735
+ });
736
+ it("round-trips the full spec (recursive tasks, bigint budget) through the builder", () => {
737
+ const original = fixture();
738
+ assertSpecRoundTrip(WorkflowSpecSchema, original, buildWorkflowProto(toWorkflowUpdateInput(original)));
739
+ });
740
+ });
741
+ describe("toWorkflowExecutionUpdateInput", () => {
742
+ const fixture = () => create(WorkflowExecutionSchema, {
743
+ metadata: META,
744
+ spec: {
745
+ workflowInstanceId: "wfi-1",
746
+ workflowId: "wf-1",
747
+ triggerMessage: "Manual run.",
748
+ triggerMetadata: { source: "console" },
749
+ runtimeEnv: { TOKEN: { value: "shh", isSecret: true } },
750
+ callbackToken: new Uint8Array([9, 8, 7]),
751
+ executionTarget: ExecutionTarget.CLOUD,
752
+ },
753
+ });
754
+ it("fixture covers every WorkflowExecutionSpec field (schema tripwire)", () => {
755
+ assertFixtureCoversSpec(WorkflowExecutionSpecSchema, fixture().spec);
756
+ });
757
+ it("round-trips the full spec and metadata through the builder", () => {
758
+ const original = fixture();
759
+ assertSpecRoundTrip(WorkflowExecutionSpecSchema, original, buildWorkflowExecutionProto(toWorkflowExecutionUpdateInput(original)));
760
+ });
761
+ });
762
+ describe("toWorkflowInstanceUpdateInput", () => {
763
+ const fixture = () => create(WorkflowInstanceSchema, {
764
+ metadata: META,
765
+ spec: {
766
+ workflowId: "wf-1",
767
+ description: "Prod instance.",
768
+ environmentRefs: [
769
+ { org: "acme", slug: "prod", kind: ApiResourceKind.environment },
770
+ ],
771
+ executionVisibility: WorkflowExecutionVisibility.organization,
772
+ },
773
+ });
774
+ it("fixture covers every WorkflowInstanceSpec field (schema tripwire)", () => {
775
+ assertFixtureCoversSpec(WorkflowInstanceSpecSchema, fixture().spec);
776
+ });
777
+ it("round-trips the full spec and metadata through the builder", () => {
778
+ const original = fixture();
779
+ assertSpecRoundTrip(WorkflowInstanceSpecSchema, original, buildWorkflowInstanceProto(toWorkflowInstanceUpdateInput(original)));
780
+ });
781
+ it("preserves execution_visibility when only environments change (live wipe bug)", () => {
782
+ const original = fixture();
783
+ const rebuilt = buildWorkflowInstanceProto({
784
+ ...toWorkflowInstanceUpdateInput(original),
785
+ environmentRefs: [{ org: "acme", slug: "staging", kind: ApiResourceKind.environment }],
786
+ });
787
+ expect(rebuilt.spec?.executionVisibility).toBe(WorkflowExecutionVisibility.organization);
788
+ expect(rebuilt.spec?.environmentRefs.map((r) => r.slug)).toEqual(["staging"]);
789
+ });
790
+ });
791
+ //# sourceMappingURL=update-input-roundtrip.test.js.map