@elevasis/sdk 1.27.0 → 1.28.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/sdk",
3
- "version": "1.27.0",
3
+ "version": "1.28.0",
4
4
  "description": "SDK for building Elevasis organization resources",
5
5
  "type": "module",
6
6
  "bin": {
@@ -58,9 +58,9 @@
58
58
  "tsup": "^8.0.0",
59
59
  "typescript": "5.9.2",
60
60
  "zod": "^4.1.0",
61
- "@repo/core": "0.34.2",
62
- "@repo/eslint-config": "0.0.0",
63
- "@repo/typescript-config": "0.0.0"
61
+ "@repo/core": "0.35.0",
62
+ "@repo/typescript-config": "0.0.0",
63
+ "@repo/eslint-config": "0.0.0"
64
64
  },
65
65
  "scripts": {
66
66
  "lint": "eslint src --max-warnings 0",
@@ -0,0 +1,43 @@
1
+ # System Interface readiness, scoped topology grants, and org ID brands
2
+
3
+ ## Why this note exists
4
+
5
+ The Organization Model API boundary now uses `system.apiInterface` plus derived readiness instead of authored `System.contracts` or top-level `bridgeContracts`. API-backed Systems are ready when their scoped Resources, ontology bindings, catalog contents, and scoped topology grants satisfy the published readiness profile.
6
+
7
+ This removes the old declaration-triggered contract layer before it became a tenant authoring requirement, and it gives API and UI consumers structured readiness diagnostics instead of incidental runtime failures.
8
+
9
+ The same release train also publishes branded WorkOS organization IDs and Supabase organization UUIDs through the shared core/UI package surface. The brands are a compile-time guard against mixing auth identity (`org_...`) with database identity (UUID) in package consumers.
10
+
11
+ ## Applies to
12
+
13
+ Template-derived projects that opt into API-backed Systems such as lead-gen or CRM after updating to the released package baselines that include `system.apiInterface` support.
14
+
15
+ The bare `_template` remains API-interface-light by default. Disabled sales, lead-gen, and CRM shell Systems should not declare API interfaces until a compatible recipe pack or tenant-owned model intentionally opts in.
16
+
17
+ Projects that consume the updated `@elevasis/core` or `@elevasis/ui` types may see stricter TypeScript checks around organization IDs. This is expected: WorkOS org IDs and Supabase org UUIDs are intentionally no longer interchangeable at typed chokepoints.
18
+
19
+ ## Required actions
20
+
21
+ 1. Pull the new package baselines after the release train publishes:
22
+ - `@elevasis/core`
23
+ - `@elevasis/ui`
24
+ - `@elevasis/sdk`
25
+ 2. Do not author `contracts`, `bridgeContracts`, versioned `*@v1` contract IDs, or a keyed `interfaces` map in tenant Organization Models.
26
+ 3. For an API-backed System, author the flat `system.apiInterface` marker only after the System's scoped Resources and ontology bindings are ready.
27
+ 4. Model cross-System API behavior with scoped topology grants rather than broad sibling-System references.
28
+ 5. Keep disabled optional-pack shells contract/interface-free until the project deliberately installs an API-ready pack.
29
+ 6. When TypeScript reports a branded org-ID mismatch, fix the source value rather than casting through `string`; use package-provided brand helpers only at trusted source boundaries.
30
+
31
+ ## Verification
32
+
33
+ - `pnpm -C core test -- organization-model`
34
+ - `pnpm -C operations check`
35
+ - Verify API-backed routes return structured readiness errors when a required System Interface is absent or not ready.
36
+ - Verify API-backed UI actions are disabled until the relevant System Interface readiness passes.
37
+ - Verify org-scoped query keys and Supabase `organization_id` filters receive the intended org-ID flavor after package baselines update.
38
+
39
+ ## Not handled by /git-sync
40
+
41
+ `/git-sync` can propagate template guidance, package baselines, and this note, but it does not decide when a tenant's business model is ready to declare `system.apiInterface`. Tenant-specific System Interface markers, scoped Resource bindings, and topology grants remain project-owned authoring decisions.
42
+
43
+ `/git-sync` also does not repair tenant-specific organization identity plumbing. If a project has local hooks or direct Supabase calls outside the template baseline, audit those call sites manually when adopting the branded org-ID package surface.
@@ -93,7 +93,7 @@ type MyInput = z.infer<typeof myInput>;
93
93
 
94
94
  Each execution creates an ephemeral worker thread from your deployed bundle. The platform validates input against your Zod schema, runs your handler, and returns the result. Workers are terminated immediately after completion -- there is no persistent server.
95
95
 
96
- Key implications: files written to disk disappear after execution, logs appear only after the execution completes (no streaming), and each execution is fully isolated with no shared state between runs. Outbound network access is unrestricted. Memory is capped at 256MB per worker; execution timeout is 300s for workflows and 600s for agents.
96
+ Key implications: files written to disk disappear after execution, logs appear only after the execution completes (no streaming), and each execution is fully isolated with no shared state between runs. Outbound network access is unrestricted. Memory is capped at 256MB per worker; the platform applies a default execution ceiling of 2 hours to all resource types (agents can override via `constraints.timeout`).
97
97
 
98
98
  For the complete execution lifecycle, concurrency model, observability, and resource limits, see [Runtime](runtime.mdx).
99
99
 
@@ -130,7 +130,7 @@ const sendEmailStep: WorkflowStep = {
130
130
 
131
131
  **Key points:**
132
132
 
133
- - `platform.call()` is async and times out after 60 seconds
133
+ - `platform.call()` is async and times out after 30 minutes (a worker-side safety net; real enforcement is server-side)
134
134
  - `credential` is the name of a platform environment variable set via `elevasis-sdk env set` when the tool needs one
135
135
  - On failure, `platform.call()` throws `PlatformToolError` (not `ToolingError`)
136
136
  - Always log success so executions are easy to debug in the dashboard
@@ -30,13 +30,13 @@ Workers are ephemeral -- each execution creates a new worker thread. There is no
30
30
 
31
31
  Timeouts are enforced by the platform. You do not handle them explicitly in your code:
32
32
 
33
- - **Default timeout:** A platform default applies to all resource types unless overridden.
33
+ - **Default timeout:** A platform default of 2 hours applies to all resource types unless overridden. This is a safety-net ceiling for runaway executions, not a target -- run long work with `--async` and observe via SSE/polling rather than holding a synchronous call open.
34
34
  - **Per-resource override:** Agents can configure `constraints.timeout` in the agent definition. Workflows use the platform default.
35
35
  - **Enforcement:** When a timeout fires, the worker is terminated immediately -- even if it is stuck in a synchronous loop. No special handler signature is required on your part.
36
36
 
37
37
  ### Cancellation
38
38
 
39
- Cancellation is initiated by the platform and requires no special code in your handler. The worker is terminated immediately and the execution is recorded as cancelled.
39
+ Cancellation is initiated by the platform and requires no special code in your handler. The worker is terminated immediately and the execution is recorded as `failed` with a cancellation reason (there is no separate `cancelled` status).
40
40
 
41
41
  **What triggers cancellation:**
42
42
 
@@ -61,7 +61,7 @@ Errors are displayed depending on the surface you use to inspect them:
61
61
  - **Unhandled exception in your handler:** The worker reports `status: 'failed'` with the error message.
62
62
  - **Memory limit exceeded (256MB):** The worker crashes with an out-of-memory error. The platform catches this; other tenants are unaffected.
63
63
  - **Timeout exceeded:** The platform terminates the worker and marks the execution failed with a timeout reason.
64
- - **Cancellation:** Execution is marked cancelled.
64
+ - **Cancellation:** The worker is terminated and the execution is marked `failed` with a cancellation reason.
65
65
 
66
66
  ---
67
67
 
@@ -133,12 +133,11 @@ Limits enforced per worker thread at runtime:
133
133
 
134
134
  Hard limits to prevent abuse and ensure platform stability:
135
135
 
136
- | Limit | Value |
137
- | ---------------------------------- | ------------- |
138
- | Max execution duration (workflows) | 300s (5 min) |
139
- | Max execution duration (agents) | 600s (10 min) |
140
- | Max log volume | 100MB/day |
141
- | Max deploy frequency | 60/day |
136
+ | Limit | Value |
137
+ | ---------------------- | -------------------------------------------------------------------------------------------- |
138
+ | Max execution duration | 2 hours (platform default for all resource types; agents override via `constraints.timeout`) |
139
+ | Max log volume | 100MB/day |
140
+ | Max deploy frequency | 60/day |
142
141
 
143
142
  - **Execution duration:** Executions exceeding the timeout are terminated by the platform. The execution is marked failed with a timeout reason.
144
143
  - **Log volume:** Total log output across all executions is capped at 100MB per day. Logs beyond this threshold may be truncated.
@@ -10,7 +10,7 @@ description: Add, hide, or replace CRM deal action buttons in a template-derived
10
10
 
11
11
  CRM deal pages derive their action buttons from an `ActionDef[]` array. The shared UI reads that array from the provider, filters it with `deriveActions(deal, actions)`, and renders one-click buttons for actions without a `payloadSchema`.
12
12
 
13
- For the broader CRM extension map -- pages, sidebars, hooks, workflow adapters, contracts, and org-model boundaries -- start with [Build and Extend CRM](extend-crm.md). This recipe is only the deal-action path.
13
+ For the broader CRM extension map -- pages, sidebars, hooks, workflow adapters, System Interfaces, and org-model boundaries -- start with [Build and Extend CRM](extend-crm.md). This recipe is only the deal-action path.
14
14
 
15
15
  **Shape reference:** The `ActionDef` flat shape and the consolidation that replaced the old `handler`/`kind` union are documented in `apps/docs/content/docs/in-progress/active-development/sdk-changes/crm/crm-current-state-assessment.mdx`.
16
16
 
@@ -31,6 +31,8 @@ Every action in the CRM action catalog maps to a deployed workflow via its `work
31
31
  4. Returns the refetched deal.
32
32
 
33
33
  External projects override an action's behavior by deploying a workflow with the same `workflowId` as the action entry. The resource registry picks the project-owned workflow over the platform default. The `isAvailableFor` predicate comes from the caller-supplied action catalog; override what the action does and keep button availability aligned with the server-side gate.
34
+
35
+ CRM action dispatch is an API-backed surface. The tenant Organization Model must expose an active and ready `sales.crm.apiInterface` marker before shared CRM action buttons are considered ready. If a lead-gen workflow hands off into CRM, model that crossing through lead-gen resources that bind the CRM pipeline plus a scoped topology grant to `sales.crm.apiInterface` instead of making base lead-gen readiness depend on CRM catalogs.
34
36
 
35
37
  ## ActionDef Shape
36
38
 
@@ -346,7 +348,9 @@ export function SendQuoteButton({ dealId }: { dealId: string }) {
346
348
  }
347
349
  ```
348
350
 
349
- Use this button through a custom deal route or a `renderActions` slot where available.
351
+ Use this button through a custom deal route or a `renderActions` slot where available.
352
+
353
+ Keep the same interface boundary for direct workflow buttons: custom UI may render read-only deal context without API readiness, but buttons that call `/execute`, `/execute-async`, or CRM action routes should be hidden or disabled until the relevant System Interface and any scoped topology grant are ready.
350
354
 
351
355
  ## 3. Build a Fully Custom Deal Page
352
356
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  ---
5
5
  title: Build and Extend CRM
6
- description: Map the CRM platform primitives available to SDK projects: shared UI pages, sidebar composition, data hooks, action definitions, workflow adapters, contracts, and org-model extension boundaries.
6
+ description: Map the CRM platform primitives available to SDK projects: shared UI pages, sidebar composition, data hooks, action definitions, workflow adapters, System Interfaces, and org-model extension boundaries.
7
7
  ---
8
8
 
9
9
  # Build and Extend CRM
@@ -25,13 +25,13 @@ CRM is a layered platform surface, not one component:
25
25
  - **Headless hooks:** deal, company, contact, note, task, list, transition, and action hooks live under `@elevasis/ui/hooks`.
26
26
  - **Action system:** `ActionDef`, `deriveActions`, and the caller-supplied provider-level `crmActions` catalog configure deal actions. The published `@elevasis/sdk` surface ships no default Elevasis action catalog -- projects supply their own `ActionDef[]`.
27
27
  - **Workflow adapters:** `crm` and `acqDb` from `@elevasis/sdk/worker` let workflows read and mutate CRM/acquisition data through platform tools.
28
- - **Contracts:** generated contract docs expose the current CRM shapes in `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md`.
28
+ - **System API Interface:** `sales.crm` uses the flat `system.apiInterface` marker for its API-backed CRM boundary. Readiness is derived from scoped resources, ontology bindings, required catalogs, and scoped topology grants. Cross-system lead-gen handoff belongs in scoped topology, not a top-level Bridge Contract or a hand-authored handoff interface field. Generated contract docs expose the current CRM shapes in `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md`.
29
29
 
30
30
  ## Decision Table
31
31
 
32
32
  | User wants | Start here | Notes |
33
33
  | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
34
- | Change CRM System availability, labels, pipeline stages, or resource descriptors | `core/config/organization-model.ts` | Treat this as Organization OS work. Use the project's configure ceremony if available. |
34
+ | Change CRM System availability, labels, pipeline stages, resource descriptors, or API readiness | `core/config/organization-model.ts` | Treat this as Organization OS work. Mark `sales.crm.apiInterface` active only when scoped CRM resources and ontology are ready for API-backed actions. |
35
35
  | Add CRM sidebar nav or a CRM route | `@elevasis/ui/features/crm` and `node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md` | Prefer manifest/sidebar composition. Do not fork shared source first. |
36
36
  | Wrap a shared CRM page with project chrome | `DealsListPage`, `DealDetailPage`, `CrmOverview` from `@elevasis/ui/features/crm` | Keep route files thin and put project-specific logic in local feature modules. |
37
37
  | Build a custom deal page | `useDealDetail`, `useDealNotes`, `useDealTasks`, `useExecuteAction` from `@elevasis/ui/hooks` | Use hooks for platform data and compose your own UI. |
@@ -237,6 +237,8 @@ Keep these boundaries straight:
237
237
  - `DealStage` and platform action defaults describe the current shared platform deal state vocabulary.
238
238
  - UI wrappers can relabel and route around shared surfaces, but changing persisted platform stages requires coordinated core/API/UI updates.
239
239
  - Do not add `sales.actions` to the org model in v1. Deal action customization is covered by [customize-crm-actions.md](customize-crm-actions.md).
240
+ - Mark `sales.crm.apiInterface` active only after CRM object, pipeline, action, and resource refs are ready.
241
+ - Model behavior that intentionally crosses from lead-gen into CRM through lead-gen resources that bind the CRM pipeline plus a scoped topology grant to `sales.crm.apiInterface`.
240
242
 
241
243
  ## Verify
242
244
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  ---
5
5
  title: Build and Extend Lead Gen
6
- description: Map the lead-gen platform primitives available to SDK projects: shared UI pages, provider-injected Organization Model config, data hooks, list/member state, artifacts, workflow adapters, contracts, and tenant-owned extension boundaries.
6
+ description: Map the lead-gen platform primitives available to SDK projects: shared UI pages, provider-injected Organization Model config, data hooks, list/member state, artifacts, workflow adapters, System Interfaces, and tenant-owned extension boundaries.
7
7
  ---
8
8
 
9
9
  # Build and Extend Lead Gen
@@ -27,13 +27,13 @@ Lead gen is a layered platform surface, not one component. Shared packages own s
27
27
  - **Acquisition substrate:** `acq_lists`, `acq_companies`, `acq_contacts`, `acq_artifacts`, list members, list companies, telemetry, and stateful transition shapes are exposed through generated contracts.
28
28
  - **Core readers:** `getLeadGenStageCatalog`, `getAllBuildTemplates`, `getProspectingBuildTemplateOptions`, and `createBuildPlanSnapshotFromTemplateId` from `@elevasis/core` read caller-supplied Organization Model/template values. They do not ship tenant catalogs or default templates.
29
29
  - **Workflow adapters:** `acqDb`, `list`, and `listBuilderWorkflow` from `@elevasis/sdk/worker` let workflows read and mutate lead-gen data through platform tools.
30
- - **Contracts:** generated contract docs expose the current lead-gen shapes in `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md`.
30
+ - **System API Interface:** `sales.lead-gen` uses the flat `system.apiInterface` marker for its API-backed lead-gen boundary. Readiness is derived from scoped resources, ontology bindings, required catalogs, and scoped topology grants. Lead-gen-to-CRM handoff uses scoped topology, not a top-level Bridge Contract or a hand-authored handoff interface field. Generated contract docs expose the current lead-gen shapes in `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md`.
31
31
 
32
32
  ## Decision Table
33
33
 
34
- | User wants | Start here | Notes |
35
- | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
36
- | Change lead-gen System availability, labels, quick access, stage catalogs, build templates, workflow actions, resources, or topology | `core/config/organization-model.ts` | Treat this as Organization OS work. Tenant projects own these values. Use the project's configure ceremony if available. |
34
+ | User wants | Start here | Notes |
35
+ | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
36
+ | Change lead-gen System availability, labels, quick access, stage catalogs, build templates, workflow actions, resources, topology, or API readiness | `core/config/organization-model.ts` | Treat this as Organization OS work. Tenant projects own these values. Mark `sales.lead-gen.apiInterface` active only when scoped resources and ontology are ready for API-backed lead-gen actions. |
37
37
  | Add lead-gen sidebar nav or a lead-gen route | `@elevasis/ui/features/lead-gen` and `node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md` | Prefer manifest/sidebar composition. Do not fork shared source first. |
38
38
  | Wrap a shared lead-gen page with project chrome | `LeadGenOverviewPage`, `LeadGenListsPage`, `LeadGenListDetailPage`, `ListBuilderPage`, `LeadGenCompaniesPage`, `LeadGenContactsPage` | Keep route files thin and put project-specific behavior in local feature modules. |
39
39
  | Build a custom campaign/list workspace | `ListBuilderPage`, `useLists`, `useList`, `useListProgress`, `useListExecutions`, `useWorkflowExecution`, `useExecutionSSE` from `@elevasis/ui` | Use the shared builder when possible; otherwise compose hooks for platform data and workflow execution. |
@@ -167,8 +167,9 @@ The shared pages call `useLeadGenConfig()` internally. That hook reads the provi
167
167
  - `buildTemplates` and `defaultBuildSteps` from `getAllBuildTemplates(organizationModel)`
168
168
  - `defaultBuildTemplateId` from the `sales.lead-gen` system config or first available template
169
169
  - `exportWorkflowId` from the lead-gen workflow resource whose action matches export semantics
170
+ - `canUseLeadGenApiActions` from derived `sales.lead-gen.apiInterface` readiness
170
171
 
171
- If the provider has no Organization Model, shared UI renders with empty config instead of falling back to Elevasis-owned defaults. A tenant that wants list creation and the build runner to be useful must provide lead-gen catalogs/templates/actions/resources/topology in `core/config/organization-model.ts`.
172
+ If the provider has no Organization Model, shared UI renders with empty config instead of falling back to Elevasis-owned defaults. Read-only shells can render without API readiness, but shared API-backed actions such as list creation, list deletion, data-mode updates, build runs, exports, and member transitions stay disabled until `sales.lead-gen.apiInterface` is active and ready. A tenant that wants list creation and the build runner to be useful must provide lead-gen catalogs/templates/actions/resources/topology in `core/config/organization-model.ts`; readiness is derived from those facts rather than a hand-authored requirements list.
172
173
 
173
174
  In external projects, pass the local list-action registry through the app factory and the tenant Organization Model through the authenticated shell:
174
175
 
@@ -425,6 +426,8 @@ Tenant-owned list-builder values belong in the main Organization Model:
425
426
  - action ids in the tenant action layer
426
427
  - workflow resources in the tenant resources map with ontology bindings and `primaryAction`
427
428
  - topology relationships in the tenant topology map
429
+ - `sales.lead-gen.apiInterface` with `lifecycle: 'active'`, `readinessProfile: 'sales.lead-gen.api'`, and the scoped API resource ids when API-backed lead-gen actions are ready
430
+ - lead-gen workflow resources that bind the CRM pipeline only when they intentionally hand off to CRM, plus a scoped topology grant from those lead-gen resources to `sales.crm.apiInterface`
428
431
 
429
432
  Use `core/config/extensions/*` for entity schema variants, not for list-builder stage catalogs or workflow bindings.
430
433
 
@@ -306,6 +306,36 @@ export type OrganizationModelSystemKind = z.infer<typeof SystemKindSchema>
306
306
  export type OrganizationModelSystemLifecycle = z.infer<typeof SystemLifecycleSchema>
307
307
  ```
308
308
 
309
+ ### `OrganizationModelSystemInterfaceKey`
310
+
311
+ ```typescript
312
+ export type OrganizationModelSystemInterfaceKey = z.infer<typeof SystemInterfaceKeySchema>
313
+ ```
314
+
315
+ ### `OrganizationModelSystemInterfaceLifecycle`
316
+
317
+ ```typescript
318
+ export type OrganizationModelSystemInterfaceLifecycle = z.infer<typeof SystemInterfaceLifecycleSchema>
319
+ ```
320
+
321
+ ### `OrganizationModelSystemInterfaceReadinessProfile`
322
+
323
+ ```typescript
324
+ export type OrganizationModelSystemInterfaceReadinessProfile = z.infer<typeof SystemInterfaceReadinessProfileSchema>
325
+ ```
326
+
327
+ ### `OrganizationModelSystemApiInterface`
328
+
329
+ ```typescript
330
+ export type OrganizationModelSystemApiInterface = z.infer<typeof SystemApiInterfaceSchema>
331
+ ```
332
+
333
+ ### `OrganizationModelSystemInterfaceRef`
334
+
335
+ ```typescript
336
+ export type OrganizationModelSystemInterfaceRef = z.infer<typeof SystemInterfaceRefSchema>
337
+ ```
338
+
309
339
  ### `OrganizationModelSystemStatus`
310
340
 
311
341
  ```typescript
@@ -469,6 +499,20 @@ export type OrganizationModelTopologyRelationship = z.infer<typeof OmTopologyRel
469
499
  export type OrganizationModelTopologyMetadata = z.infer<typeof OmTopologyMetadataSchema>
470
500
  ```
471
501
 
502
+ ### `OrganizationModelTopologySystemInterfaceGrant`
503
+
504
+ ```typescript
505
+ export type OrganizationModelTopologySystemInterfaceGrant = z.infer<typeof OmTopologySystemInterfaceGrantSchema>
506
+ ```
507
+
508
+ ### `OrganizationModelTopologySystemInterfaceGrantMetadata`
509
+
510
+ ```typescript
511
+ export type OrganizationModelTopologySystemInterfaceGrantMetadata = z.infer<
512
+ typeof OmTopologySystemInterfaceGrantMetadataSchema
513
+ >
514
+ ```
515
+
472
516
  ### `OrganizationModelActions`
473
517
 
474
518
  ```typescript
@@ -152,7 +152,7 @@ This is the static SDK-level error catalog. Check `.claude/memory/errors/` first
152
152
 
153
153
  ### PlatformToolError: timeout_error
154
154
 
155
- **Cause:** The platform tool call took longer than 60 seconds.
155
+ **Cause:** The platform tool call took longer than 30 minutes (the `platform.call()` safety-net timeout; real per-tool enforcement is server-side).
156
156
 
157
157
  **Fix:**
158
158
 
@@ -173,9 +173,9 @@ This is the static SDK-level error catalog. Check `.claude/memory/errors/` first
173
173
 
174
174
  ## Runtime Errors
175
175
 
176
- ### Execution timeout (300s)
176
+ ### Execution timeout
177
177
 
178
- **Cause:** The entire workflow execution exceeded the 300-second limit.
178
+ **Cause:** The entire execution exceeded the platform ceiling (2 hours by default; agents can override via `constraints.timeout`).
179
179
 
180
180
  **Fix:**
181
181