@stigmer/server 3.24.0 → 3.26.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/dist/authorization/authorizer.d.ts +10 -4
- package/dist/authorization/authorizer.d.ts.map +1 -1
- package/dist/authorization/authorizer.js +11 -4
- package/dist/authorization/authorizer.js.map +1 -1
- package/dist/authorization/model/index.d.ts +4 -4
- package/dist/authorization/model/index.d.ts.map +1 -1
- package/dist/authorization/model/index.js +2 -0
- package/dist/authorization/model/index.js.map +1 -1
- package/dist/authorization/model/oauth_app.d.ts.map +1 -1
- package/dist/authorization/model/oauth_app.js +3 -2
- package/dist/authorization/model/oauth_app.js.map +1 -1
- package/dist/authorization/model/platform_client.d.ts +2 -0
- package/dist/authorization/model/platform_client.d.ts.map +1 -0
- package/dist/authorization/model/platform_client.js +31 -0
- package/dist/authorization/model/platform_client.js.map +1 -0
- package/dist/boot/compose.d.ts.map +1 -1
- package/dist/boot/compose.js +99 -13
- package/dist/boot/compose.js.map +1 -1
- package/dist/boot/list-indexes.d.ts +3 -0
- package/dist/boot/list-indexes.d.ts.map +1 -0
- package/dist/boot/list-indexes.js +24 -0
- package/dist/boot/list-indexes.js.map +1 -0
- package/dist/boot/route-shadowing.d.ts +25 -0
- package/dist/boot/route-shadowing.d.ts.map +1 -0
- package/dist/boot/route-shadowing.js +17 -0
- package/dist/boot/route-shadowing.js.map +1 -0
- package/dist/domain/agentexecution/controller.d.ts.map +1 -1
- package/dist/domain/agentexecution/controller.js +6 -8
- package/dist/domain/agentexecution/controller.js.map +1 -1
- package/dist/domain/agentexecution/list-index.d.ts +2 -0
- package/dist/domain/agentexecution/list-index.d.ts.map +1 -0
- package/dist/domain/agentexecution/list-index.js +23 -0
- package/dist/domain/agentexecution/list-index.js.map +1 -0
- package/dist/domain/agentexecution/steps.d.ts +17 -33
- package/dist/domain/agentexecution/steps.d.ts.map +1 -1
- package/dist/domain/agentexecution/steps.js +94 -95
- package/dist/domain/agentexecution/steps.js.map +1 -1
- package/dist/domain/agentexecution/usage.d.ts.map +1 -1
- package/dist/domain/agentexecution/usage.js +37 -14
- package/dist/domain/agentexecution/usage.js.map +1 -1
- package/dist/domain/artifact/controller.d.ts.map +1 -1
- package/dist/domain/artifact/controller.js +27 -15
- package/dist/domain/artifact/controller.js.map +1 -1
- package/dist/domain/artifact/list-index.d.ts +2 -0
- package/dist/domain/artifact/list-index.d.ts.map +1 -0
- package/dist/domain/artifact/list-index.js +21 -0
- package/dist/domain/artifact/list-index.js.map +1 -0
- package/dist/domain/iampolicy/membership.d.ts +6 -1
- package/dist/domain/iampolicy/membership.d.ts.map +1 -1
- package/dist/domain/iampolicy/membership.js +8 -2
- package/dist/domain/iampolicy/membership.js.map +1 -1
- package/dist/domain/identityaccount/constants.d.ts +13 -0
- package/dist/domain/identityaccount/constants.d.ts.map +1 -1
- package/dist/domain/identityaccount/constants.js +17 -0
- package/dist/domain/identityaccount/constants.js.map +1 -1
- package/dist/domain/identityaccount/controller.d.ts +3 -1
- package/dist/domain/identityaccount/controller.d.ts.map +1 -1
- package/dist/domain/identityaccount/controller.js +15 -6
- package/dist/domain/identityaccount/controller.js.map +1 -1
- package/dist/domain/identityaccount/operator.d.ts.map +1 -1
- package/dist/domain/identityaccount/operator.js +1 -0
- package/dist/domain/identityaccount/operator.js.map +1 -1
- package/dist/domain/identityaccount/provisioning.d.ts +18 -0
- package/dist/domain/identityaccount/provisioning.d.ts.map +1 -1
- package/dist/domain/identityaccount/provisioning.js +1 -0
- package/dist/domain/identityaccount/provisioning.js.map +1 -1
- package/dist/domain/identityaccount/resource-store.js +9 -5
- package/dist/domain/identityaccount/resource-store.js.map +1 -1
- package/dist/domain/identityaccount/steps.d.ts +11 -2
- package/dist/domain/identityaccount/steps.d.ts.map +1 -1
- package/dist/domain/identityaccount/steps.js +42 -4
- package/dist/domain/identityaccount/steps.js.map +1 -1
- package/dist/domain/identityaccount/store-contract.d.ts.map +1 -1
- package/dist/domain/identityaccount/store-contract.js +33 -0
- package/dist/domain/identityaccount/store-contract.js.map +1 -1
- package/dist/domain/identityaccount/store.d.ts +7 -5
- package/dist/domain/identityaccount/store.d.ts.map +1 -1
- package/dist/domain/identityaccount/store.js.map +1 -1
- package/dist/domain/platform/controller.d.ts +10 -0
- package/dist/domain/platform/controller.d.ts.map +1 -1
- package/dist/domain/platform/controller.js +2 -1
- package/dist/domain/platform/controller.js.map +1 -1
- package/dist/domain/platformclient/constants.d.ts +60 -0
- package/dist/domain/platformclient/constants.d.ts.map +1 -0
- package/dist/domain/platformclient/constants.js +78 -0
- package/dist/domain/platformclient/constants.js.map +1 -0
- package/dist/domain/platformclient/controller.d.ts +59 -0
- package/dist/domain/platformclient/controller.d.ts.map +1 -0
- package/dist/domain/platformclient/controller.js +191 -0
- package/dist/domain/platformclient/controller.js.map +1 -0
- package/dist/domain/platformclient/credentials.d.ts +13 -0
- package/dist/domain/platformclient/credentials.d.ts.map +1 -0
- package/dist/domain/platformclient/credentials.js +56 -0
- package/dist/domain/platformclient/credentials.js.map +1 -0
- package/dist/domain/platformclient/mint.d.ts +23 -0
- package/dist/domain/platformclient/mint.d.ts.map +1 -0
- package/dist/domain/platformclient/mint.js +254 -0
- package/dist/domain/platformclient/mint.js.map +1 -0
- package/dist/domain/platformclient/origin-guard.d.ts +9 -0
- package/dist/domain/platformclient/origin-guard.d.ts.map +1 -0
- package/dist/domain/platformclient/origin-guard.js +81 -0
- package/dist/domain/platformclient/origin-guard.js.map +1 -0
- package/dist/domain/platformclient/resource-store.d.ts +4 -0
- package/dist/domain/platformclient/resource-store.d.ts.map +1 -0
- package/dist/domain/platformclient/resource-store.js +117 -0
- package/dist/domain/platformclient/resource-store.js.map +1 -0
- package/dist/domain/platformclient/steps.d.ts +51 -0
- package/dist/domain/platformclient/steps.d.ts.map +1 -0
- package/dist/domain/platformclient/steps.js +339 -0
- package/dist/domain/platformclient/steps.js.map +1 -0
- package/dist/domain/platformclient/store-contract.d.ts +8 -0
- package/dist/domain/platformclient/store-contract.d.ts.map +1 -0
- package/dist/domain/platformclient/store-contract.js +208 -0
- package/dist/domain/platformclient/store-contract.js.map +1 -0
- package/dist/domain/platformclient/store.d.ts +58 -0
- package/dist/domain/platformclient/store.d.ts.map +1 -0
- package/dist/domain/platformclient/store.js +13 -0
- package/dist/domain/platformclient/store.js.map +1 -0
- package/dist/domain/platformclient/system-managed.d.ts +18 -0
- package/dist/domain/platformclient/system-managed.d.ts.map +1 -0
- package/dist/domain/platformclient/system-managed.js +80 -0
- package/dist/domain/platformclient/system-managed.js.map +1 -0
- package/dist/domain/platformclient/token-controller.d.ts +11 -0
- package/dist/domain/platformclient/token-controller.d.ts.map +1 -0
- package/dist/domain/platformclient/token-controller.js +32 -0
- package/dist/domain/platformclient/token-controller.js.map +1 -0
- package/dist/domain/platformclient/verifier.d.ts +10 -0
- package/dist/domain/platformclient/verifier.d.ts.map +1 -0
- package/dist/domain/platformclient/verifier.js +76 -0
- package/dist/domain/platformclient/verifier.js.map +1 -0
- package/dist/domain/session/list-index.d.ts +4 -0
- package/dist/domain/session/list-index.d.ts.map +1 -0
- package/dist/domain/session/list-index.js +26 -0
- package/dist/domain/session/list-index.js.map +1 -0
- package/dist/domain/session/steps.d.ts +7 -8
- package/dist/domain/session/steps.d.ts.map +1 -1
- package/dist/domain/session/steps.js +76 -78
- package/dist/domain/session/steps.js.map +1 -1
- package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
- package/dist/domain/workflowexecution/controller.js +53 -55
- package/dist/domain/workflowexecution/controller.js.map +1 -1
- package/dist/domain/workflowexecution/execution-filter.d.ts +4 -0
- package/dist/domain/workflowexecution/execution-filter.d.ts.map +1 -1
- package/dist/domain/workflowexecution/execution-filter.js +11 -5
- package/dist/domain/workflowexecution/execution-filter.js.map +1 -1
- package/dist/domain/workflowexecution/get-execution-summary.d.ts.map +1 -1
- package/dist/domain/workflowexecution/get-execution-summary.js +23 -17
- package/dist/domain/workflowexecution/get-execution-summary.js.map +1 -1
- package/dist/domain/workflowexecution/list-index.d.ts +2 -0
- package/dist/domain/workflowexecution/list-index.d.ts.map +1 -0
- package/dist/domain/workflowexecution/list-index.js +21 -0
- package/dist/domain/workflowexecution/list-index.js.map +1 -0
- package/dist/domain/workflowexecution/list-pending-approvals.d.ts.map +1 -1
- package/dist/domain/workflowexecution/list-pending-approvals.js +69 -32
- package/dist/domain/workflowexecution/list-pending-approvals.js.map +1 -1
- package/dist/domain/workflowexecution/queries.d.ts +30 -4
- package/dist/domain/workflowexecution/queries.d.ts.map +1 -1
- package/dist/domain/workflowexecution/queries.js +76 -22
- package/dist/domain/workflowexecution/queries.js.map +1 -1
- package/dist/encryption/key-manager.d.ts +20 -3
- package/dist/encryption/key-manager.d.ts.map +1 -1
- package/dist/encryption/key-manager.js +64 -42
- package/dist/encryption/key-manager.js.map +1 -1
- package/dist/extensions/caller-guards.d.ts +8 -3
- package/dist/extensions/caller-guards.d.ts.map +1 -1
- package/dist/extensions/drivers.d.ts +37 -0
- package/dist/extensions/drivers.d.ts.map +1 -1
- package/dist/extensions/guest-token-minting.d.ts +26 -0
- package/dist/extensions/guest-token-minting.d.ts.map +1 -0
- package/dist/extensions/guest-token-minting.js +2 -0
- package/dist/extensions/guest-token-minting.js.map +1 -0
- package/dist/extensions/identity.d.ts +6 -4
- package/dist/extensions/identity.d.ts.map +1 -1
- package/dist/extensions/identity.js.map +1 -1
- package/dist/extensions/list-read-scope.d.ts +9 -12
- package/dist/extensions/list-read-scope.d.ts.map +1 -1
- package/dist/extensions/list-read-scope.js.map +1 -1
- package/dist/extensions/registry.d.ts +30 -1
- package/dist/extensions/registry.d.ts.map +1 -1
- package/dist/extensions/registry.js +34 -1
- package/dist/extensions/registry.js.map +1 -1
- package/dist/index.d.ts +15 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/pipeline/interceptors/auth.d.ts +14 -0
- package/dist/pipeline/interceptors/auth.d.ts.map +1 -1
- package/dist/pipeline/interceptors/auth.js +24 -0
- package/dist/pipeline/interceptors/auth.js.map +1 -1
- package/dist/pipeline/steps/build-update-state.d.ts +11 -1
- package/dist/pipeline/steps/build-update-state.d.ts.map +1 -1
- package/dist/pipeline/steps/build-update-state.js +5 -2
- package/dist/pipeline/steps/build-update-state.js.map +1 -1
- package/dist/pipeline/steps/list-page.d.ts +63 -0
- package/dist/pipeline/steps/list-page.d.ts.map +1 -0
- package/dist/pipeline/steps/list-page.js +187 -0
- package/dist/pipeline/steps/list-page.js.map +1 -0
- package/dist/platformtoken/envelope.d.ts +100 -0
- package/dist/platformtoken/envelope.d.ts.map +1 -0
- package/dist/platformtoken/envelope.js +184 -0
- package/dist/platformtoken/envelope.js.map +1 -0
- package/dist/platformtoken/key-ring.d.ts +85 -0
- package/dist/platformtoken/key-ring.d.ts.map +1 -0
- package/dist/platformtoken/key-ring.js +164 -0
- package/dist/platformtoken/key-ring.js.map +1 -0
- package/dist/query/activity/handler.d.ts +6 -7
- package/dist/query/activity/handler.d.ts.map +1 -1
- package/dist/query/activity/handler.js +42 -59
- package/dist/query/activity/handler.js.map +1 -1
- package/dist/store/interface.d.ts +29 -0
- package/dist/store/interface.d.ts.map +1 -1
- package/dist/store/interface.js.map +1 -1
- package/dist/store/list-index.d.ts +123 -0
- package/dist/store/list-index.d.ts.map +1 -0
- package/dist/store/list-index.js +277 -0
- package/dist/store/list-index.js.map +1 -0
- package/dist/store/logger.d.ts +3 -0
- package/dist/store/logger.d.ts.map +1 -1
- package/dist/store/logger.js +5 -1
- package/dist/store/logger.js.map +1 -1
- package/dist/store/postgres/migrations.d.ts +10 -6
- package/dist/store/postgres/migrations.d.ts.map +1 -1
- package/dist/store/postgres/migrations.js +64 -6
- package/dist/store/postgres/migrations.js.map +1 -1
- package/dist/store/postgres/store.d.ts +26 -5
- package/dist/store/postgres/store.d.ts.map +1 -1
- package/dist/store/postgres/store.js +377 -22
- package/dist/store/postgres/store.js.map +1 -1
- package/dist/store/sqlite/migrations.d.ts +11 -5
- package/dist/store/sqlite/migrations.d.ts.map +1 -1
- package/dist/store/sqlite/migrations.js +50 -4
- package/dist/store/sqlite/migrations.js.map +1 -1
- package/dist/store/sqlite/store.d.ts +18 -3
- package/dist/store/sqlite/store.d.ts.map +1 -1
- package/dist/store/sqlite/store.js +321 -15
- package/dist/store/sqlite/store.js.map +1 -1
- package/package.json +6 -6
- package/src/authorization/README.md +1 -1
- package/src/authorization/__tests__/authorizer.test.ts +6 -2
- package/src/authorization/__tests__/drivers.ts +6 -1
- package/src/authorization/__tests__/wire-permissions.test.ts +1 -0
- package/src/authorization/authorizer.ts +11 -4
- package/src/authorization/model/__tests__/registry.test.ts +8 -1
- package/src/authorization/model/index.ts +6 -4
- package/src/authorization/model/oauth_app.ts +3 -2
- package/src/authorization/model/platform_client.ts +43 -0
- package/src/boot/__tests__/auth-enabled-composition.test.ts +2 -1
- package/src/boot/__tests__/list-indexes.test.ts +65 -0
- package/src/boot/__tests__/route-shadowing.test.ts +67 -0
- package/src/boot/compose.ts +113 -18
- package/src/boot/list-indexes.ts +25 -0
- package/src/boot/route-shadowing.ts +47 -0
- package/src/domain/agentexecution/__tests__/agentexecution.test.ts +85 -3
- package/src/domain/agentexecution/controller.ts +8 -10
- package/src/domain/agentexecution/list-index.ts +24 -0
- package/src/domain/agentexecution/steps.ts +118 -115
- package/src/domain/agentexecution/usage.ts +38 -17
- package/src/domain/artifact/controller.ts +28 -18
- package/src/domain/artifact/list-index.ts +22 -0
- package/src/domain/iampolicy/__tests__/membership.test.ts +7 -0
- package/src/domain/iampolicy/membership.ts +8 -2
- package/src/domain/identityaccount/__tests__/platform-client-accounts.test.ts +124 -0
- package/src/domain/identityaccount/__tests__/resource-store.test.ts +1 -0
- package/src/domain/identityaccount/constants.ts +20 -0
- package/src/domain/identityaccount/controller.ts +16 -4
- package/src/domain/identityaccount/operator.ts +1 -0
- package/src/domain/identityaccount/provisioning.ts +17 -0
- package/src/domain/identityaccount/resource-store.ts +9 -5
- package/src/domain/identityaccount/steps.ts +58 -3
- package/src/domain/identityaccount/store-contract.ts +51 -0
- package/src/domain/identityaccount/store.ts +7 -5
- package/src/domain/platform/__tests__/platform.test.ts +7 -1
- package/src/domain/platform/controller.ts +12 -1
- package/src/domain/platformclient/__tests__/controller.test.ts +397 -0
- package/src/domain/platformclient/__tests__/credentials.test.ts +46 -0
- package/src/domain/platformclient/__tests__/mint.test.ts +415 -0
- package/src/domain/platformclient/__tests__/resource-store.test.ts +140 -0
- package/src/domain/platformclient/__tests__/system-managed.test.ts +101 -0
- package/src/domain/platformclient/__tests__/verifier-and-guard.test.ts +207 -0
- package/src/domain/platformclient/constants.ts +120 -0
- package/src/domain/platformclient/controller.ts +449 -0
- package/src/domain/platformclient/credentials.ts +68 -0
- package/src/domain/platformclient/mint.ts +412 -0
- package/src/domain/platformclient/origin-guard.ts +117 -0
- package/src/domain/platformclient/resource-store.ts +150 -0
- package/src/domain/platformclient/steps.ts +472 -0
- package/src/domain/platformclient/store-contract.ts +318 -0
- package/src/domain/platformclient/store.ts +63 -0
- package/src/domain/platformclient/system-managed.ts +115 -0
- package/src/domain/platformclient/token-controller.ts +49 -0
- package/src/domain/platformclient/verifier.ts +106 -0
- package/src/domain/session/list-index.ts +28 -0
- package/src/domain/session/steps.ts +108 -123
- package/src/domain/workflowexecution/__tests__/list-read-scope-summaries.test.ts +155 -99
- package/src/domain/workflowexecution/__tests__/workflowexecution.test.ts +193 -31
- package/src/domain/workflowexecution/controller.ts +54 -82
- package/src/domain/workflowexecution/execution-filter.ts +20 -7
- package/src/domain/workflowexecution/get-execution-summary.ts +31 -24
- package/src/domain/workflowexecution/list-index.ts +22 -0
- package/src/domain/workflowexecution/list-pending-approvals.ts +82 -25
- package/src/domain/workflowexecution/queries.ts +134 -23
- package/src/encryption/key-manager.ts +87 -44
- package/src/extensions/__tests__/extension-composition.test.ts +3 -2
- package/src/extensions/__tests__/platform-client-composed.test.ts +288 -0
- package/src/extensions/__tests__/registry.test.ts +4 -1
- package/src/extensions/__tests__/tier-truthfulness.test.ts +8 -0
- package/src/extensions/caller-guards.ts +8 -3
- package/src/extensions/drivers.ts +37 -0
- package/src/extensions/guest-token-minting.ts +32 -0
- package/src/extensions/identity.ts +6 -4
- package/src/extensions/list-read-scope.ts +9 -12
- package/src/extensions/registry.ts +77 -3
- package/src/index.ts +65 -1
- package/src/pipeline/interceptors/auth.ts +27 -0
- package/src/pipeline/steps/__tests__/list-page.test.ts +186 -0
- package/src/pipeline/steps/__tests__/references.test.ts +2 -0
- package/src/pipeline/steps/build-update-state.ts +5 -2
- package/src/pipeline/steps/list-page.ts +284 -0
- package/src/platformtoken/__tests__/envelope.test.ts +277 -0
- package/src/platformtoken/__tests__/key-ring.test.ts +205 -0
- package/src/platformtoken/envelope.ts +276 -0
- package/src/platformtoken/key-ring.ts +266 -0
- package/src/query/activity/handler.ts +57 -78
- package/src/runnerauth/__tests__/runner-subject-composed.test.ts +9 -3
- package/src/store/README.md +51 -32
- package/src/store/__tests__/list-index.measure.test.ts +293 -0
- package/src/store/__tests__/list-index.test.ts +328 -0
- package/src/store/__tests__/store-contract.ts +346 -3
- package/src/store/interface.ts +39 -0
- package/src/store/list-index.ts +465 -0
- package/src/store/logger.ts +8 -1
- package/src/store/postgres/__tests__/list-index-repair.test.ts +133 -0
- package/src/store/postgres/__tests__/migrations.test.ts +27 -19
- package/src/store/postgres/__tests__/store-contract.test.ts +50 -3
- package/src/store/postgres/migrations.ts +69 -7
- package/src/store/postgres/store.ts +485 -29
- package/src/store/sqlite/__tests__/migrations.test.ts +51 -7
- package/src/store/sqlite/__tests__/store-contract.test.ts +70 -16
- package/src/store/sqlite/__tests__/support.ts +12 -3
- package/src/store/sqlite/migrations.ts +57 -6
- package/src/store/sqlite/store.ts +462 -21
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pins the
|
|
3
|
-
*
|
|
4
|
-
* by 20260830.01.sp.list-read-scoping):
|
|
2
|
+
* Pins the read of BOTH getExecutionSummary handlers through the list
|
|
3
|
+
* index and the ListReadScope's restrict verb:
|
|
5
4
|
*
|
|
6
|
-
* -
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
13
|
-
*
|
|
14
|
-
* the
|
|
5
|
+
* - the rows are the requested org's, within the time window, read
|
|
6
|
+
* through the index in every posture (a row with no creation stamp is
|
|
7
|
+
* kept, as the aggregation loop keeps it);
|
|
8
|
+
* - a composed scope is offered exactly those rows and never asked to
|
|
9
|
+
* enumerate (its enumeration verb throws here); the aggregation runs
|
|
10
|
+
* over the rows it keeps;
|
|
11
|
+
* - when it keeps NONE the answer is the proto DEFAULT INSTANCE — the
|
|
12
|
+
* conformance-pinned multi-tenant zero shape (workflow: success_rate 0
|
|
13
|
+
* and NO cost summary, the opposite of the OSS -1 sentinel and
|
|
14
|
+
* always-present zero cost);
|
|
15
|
+
* - NO scope composed = every row of the org and window, and the OSS
|
|
16
|
+
* zero pins hold.
|
|
15
17
|
*/
|
|
16
|
-
import { create
|
|
17
|
-
import { describe, expect, it } from "vitest";
|
|
18
|
+
import { create } from "@bufbuild/protobuf";
|
|
19
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
18
20
|
|
|
19
21
|
import { AgentExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
20
22
|
import { ExecutionPhase as AgentExecutionPhase } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
21
23
|
import { GetAgentExecutionSummaryRequestSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/io_pb";
|
|
22
24
|
import { WorkflowExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/api_pb";
|
|
23
25
|
import { ExecutionPhase } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/enum_pb";
|
|
24
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
GetExecutionSummaryRequestSchema,
|
|
28
|
+
SummaryTimeWindow,
|
|
29
|
+
} from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/io_pb";
|
|
25
30
|
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
26
31
|
|
|
27
32
|
import { createLogger } from "../../../boot/logger.js";
|
|
@@ -29,6 +34,8 @@ import type { ListReadScope } from "../../../extensions/list-read-scope.js";
|
|
|
29
34
|
import { testCallerIdentity } from "../../../pipeline/__tests__/support.js";
|
|
30
35
|
import { newPermissiveSingleTeamAuthorizer } from "../../../pipeline/steps/authorize.js";
|
|
31
36
|
import type { Store } from "../../../store/interface.js";
|
|
37
|
+
import { tempStore } from "../../../store/sqlite/__tests__/support.js";
|
|
38
|
+
import type { TempStore } from "../../../store/sqlite/__tests__/support.js";
|
|
32
39
|
|
|
33
40
|
import { getExecutionSummary as getAgentSummary } from "../../agentexecution/usage.js";
|
|
34
41
|
import { getExecutionSummary as getWorkflowSummary } from "../get-execution-summary.js";
|
|
@@ -40,73 +47,135 @@ const silentLogger = createLogger({
|
|
|
40
47
|
});
|
|
41
48
|
|
|
42
49
|
const caller = testCallerIdentity();
|
|
50
|
+
const NOW_SECONDS = BigInt(Math.floor(Date.now() / 1000));
|
|
51
|
+
const DAY = 24n * 60n * 60n;
|
|
43
52
|
|
|
44
|
-
|
|
53
|
+
interface RecordingScope extends ListReadScope {
|
|
54
|
+
readonly offered: Array<{ kind: ApiResourceKind; ids: string[] }>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** A scope that keeps `allowed`, records what it was offered, and refuses to enumerate. */
|
|
58
|
+
function restrictingScope(allowed: ReadonlyArray<string>): RecordingScope {
|
|
59
|
+
const offered: Array<{ kind: ApiResourceKind; ids: string[] }> = [];
|
|
45
60
|
return {
|
|
46
|
-
|
|
47
|
-
|
|
61
|
+
offered,
|
|
62
|
+
authorizedResourceIds: () =>
|
|
63
|
+
Promise.reject(new Error("the summaries never enumerate")),
|
|
64
|
+
restrictListEntries: (_caller, kind, entries) => {
|
|
65
|
+
offered.push({ kind, ids: entries.map((e) => e.id).sort() });
|
|
66
|
+
return Promise.resolve(
|
|
67
|
+
new Set(entries.map((e) => e.id).filter((id) => allowed.includes(id))),
|
|
68
|
+
);
|
|
69
|
+
},
|
|
48
70
|
};
|
|
49
71
|
}
|
|
50
72
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
73
|
+
let temp: TempStore | undefined;
|
|
74
|
+
afterEach(async () => {
|
|
75
|
+
await temp?.cleanup();
|
|
76
|
+
temp = undefined;
|
|
77
|
+
});
|
|
55
78
|
|
|
56
|
-
function
|
|
57
|
-
return
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
79
|
+
function audit(createdDaysAgo: bigint | undefined) {
|
|
80
|
+
return createdDaysAgo === undefined
|
|
81
|
+
? {}
|
|
82
|
+
: {
|
|
83
|
+
audit: {
|
|
84
|
+
specAudit: {
|
|
85
|
+
createdAt: {
|
|
86
|
+
seconds: NOW_SECONDS - createdDaysAgo * DAY,
|
|
87
|
+
nanos: 0,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
};
|
|
64
92
|
}
|
|
65
93
|
|
|
66
|
-
function
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
94
|
+
async function workflowStore(): Promise<Store> {
|
|
95
|
+
temp = tempStore();
|
|
96
|
+
const rows: Array<[string, string, ExecutionPhase, bigint | undefined]> = [
|
|
97
|
+
["wfe_mine_done", "acme", ExecutionPhase.EXECUTION_COMPLETED, 1n],
|
|
98
|
+
["wfe_mine_run", "acme", ExecutionPhase.EXECUTION_IN_PROGRESS, undefined],
|
|
99
|
+
["wfe_not_mine", "acme", ExecutionPhase.EXECUTION_FAILED, 1n],
|
|
100
|
+
["wfe_stale", "acme", ExecutionPhase.EXECUTION_FAILED, 30n],
|
|
101
|
+
["wfe_other_org", "rival", ExecutionPhase.EXECUTION_FAILED, 1n],
|
|
102
|
+
];
|
|
103
|
+
for (const [id, org, phase, days] of rows) {
|
|
104
|
+
await temp.store.saveResource(
|
|
105
|
+
ApiResourceKind.workflow_execution,
|
|
106
|
+
id,
|
|
107
|
+
WorkflowExecutionSchema,
|
|
108
|
+
create(WorkflowExecutionSchema, {
|
|
109
|
+
metadata: { id, name: id, slug: id, org },
|
|
110
|
+
status: { phase, ...audit(days) },
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
return temp.store;
|
|
74
115
|
}
|
|
75
116
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
// In the org but NOT authorized — the id set must drop it.
|
|
83
|
-
workflowExecRow("wfe_not_mine", "acme", ExecutionPhase.EXECUTION_FAILED),
|
|
117
|
+
async function agentStore(): Promise<Store> {
|
|
118
|
+
temp = tempStore();
|
|
119
|
+
const rows: Array<[string, string]> = [
|
|
120
|
+
["aexec_mine", "acme"],
|
|
121
|
+
["aexec_not_mine", "acme"],
|
|
122
|
+
["aexec_other_org", "rival"],
|
|
84
123
|
];
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
124
|
+
for (const [id, org] of rows) {
|
|
125
|
+
await temp.store.saveResource(
|
|
126
|
+
ApiResourceKind.agent_execution,
|
|
127
|
+
id,
|
|
128
|
+
AgentExecutionSchema,
|
|
129
|
+
create(AgentExecutionSchema, {
|
|
130
|
+
metadata: { id, name: id, org },
|
|
131
|
+
status: {
|
|
132
|
+
phase: AgentExecutionPhase.EXECUTION_IN_PROGRESS,
|
|
133
|
+
...audit(1n),
|
|
134
|
+
},
|
|
135
|
+
}),
|
|
136
|
+
);
|
|
92
137
|
}
|
|
138
|
+
return temp.store;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const LAST_7D = { org: "acme", timeWindow: SummaryTimeWindow.LAST_7D };
|
|
93
142
|
|
|
94
|
-
|
|
143
|
+
describe("workflow getExecutionSummary read", () => {
|
|
144
|
+
it("offers the scope the org's rows within the window, and aggregates the ones it keeps", async () => {
|
|
145
|
+
const scope = restrictingScope([
|
|
146
|
+
"wfe_mine_done",
|
|
147
|
+
"wfe_mine_run",
|
|
148
|
+
"wfe_other_org",
|
|
149
|
+
]);
|
|
95
150
|
const summary = await getWorkflowSummary(
|
|
96
|
-
|
|
97
|
-
|
|
151
|
+
{
|
|
152
|
+
store: await workflowStore(),
|
|
153
|
+
logger: silentLogger,
|
|
154
|
+
listReadScope: scope,
|
|
155
|
+
},
|
|
156
|
+
create(GetExecutionSummaryRequestSchema, LAST_7D),
|
|
98
157
|
caller,
|
|
99
158
|
);
|
|
159
|
+
expect(scope.offered).toEqual([
|
|
160
|
+
{
|
|
161
|
+
kind: ApiResourceKind.workflow_execution,
|
|
162
|
+
ids: ["wfe_mine_done", "wfe_mine_run", "wfe_not_mine"],
|
|
163
|
+
},
|
|
164
|
+
]);
|
|
100
165
|
expect(summary.totalCount).toBe(2);
|
|
101
166
|
expect(summary.activeCount).toBe(1);
|
|
102
167
|
// One terminal (completed) — a real 100%, not the -1 sentinel.
|
|
103
168
|
expect(summary.successRate).toBe(1);
|
|
104
169
|
});
|
|
105
170
|
|
|
106
|
-
it("
|
|
171
|
+
it("answers the default instance when the scope keeps none — the multi-tenant zero shape", async () => {
|
|
107
172
|
const summary = await getWorkflowSummary(
|
|
108
|
-
|
|
109
|
-
|
|
173
|
+
{
|
|
174
|
+
store: await workflowStore(),
|
|
175
|
+
logger: silentLogger,
|
|
176
|
+
listReadScope: restrictingScope([]),
|
|
177
|
+
},
|
|
178
|
+
create(GetExecutionSummaryRequestSchema, LAST_7D),
|
|
110
179
|
caller,
|
|
111
180
|
);
|
|
112
181
|
expect(summary.successRate).toBe(0);
|
|
@@ -115,48 +184,52 @@ describe("workflow getExecutionSummary read scope", () => {
|
|
|
115
184
|
expect(summary.avgDuration).toBeUndefined();
|
|
116
185
|
});
|
|
117
186
|
|
|
118
|
-
it("no scope composed
|
|
187
|
+
it("with no scope composed counts every row of the org and window, and keeps the OSS zero pins", async () => {
|
|
119
188
|
const summary = await getWorkflowSummary(
|
|
120
|
-
|
|
121
|
-
|
|
189
|
+
{
|
|
190
|
+
store: await workflowStore(),
|
|
191
|
+
logger: silentLogger,
|
|
192
|
+
listReadScope: undefined,
|
|
193
|
+
},
|
|
194
|
+
create(GetExecutionSummaryRequestSchema, LAST_7D),
|
|
122
195
|
caller,
|
|
123
196
|
);
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
expect(summary.totalCount).toBe(4);
|
|
197
|
+
// The org's three rows in the window, the unstamped one included; the
|
|
198
|
+
// stale row and the rival org's row are not read.
|
|
199
|
+
expect(summary.totalCount).toBe(3);
|
|
128
200
|
expect(summary.totalCost).toBeDefined();
|
|
129
201
|
});
|
|
130
202
|
});
|
|
131
203
|
|
|
132
|
-
describe("agent getExecutionSummary read
|
|
133
|
-
|
|
134
|
-
agentExecRow("aexec_mine", "acme", AgentExecutionPhase.EXECUTION_IN_PROGRESS),
|
|
135
|
-
agentExecRow("aexec_other_org", "rival", AgentExecutionPhase.EXECUTION_IN_PROGRESS),
|
|
136
|
-
agentExecRow("aexec_not_mine", "acme", AgentExecutionPhase.EXECUTION_IN_PROGRESS),
|
|
137
|
-
];
|
|
138
|
-
|
|
139
|
-
function deps(scope: ListReadScope | undefined) {
|
|
204
|
+
describe("agent getExecutionSummary read", () => {
|
|
205
|
+
function deps(store: Store, scope: ListReadScope | undefined) {
|
|
140
206
|
return {
|
|
141
|
-
store
|
|
207
|
+
store,
|
|
142
208
|
logger: silentLogger,
|
|
143
209
|
authorizer: newPermissiveSingleTeamAuthorizer(),
|
|
144
210
|
listReadScope: scope,
|
|
145
211
|
};
|
|
146
212
|
}
|
|
147
213
|
|
|
148
|
-
it("
|
|
214
|
+
it("offers the scope the org's rows as agent executions, and aggregates the ones it keeps", async () => {
|
|
215
|
+
const scope = restrictingScope(["aexec_mine", "aexec_other_org"]);
|
|
149
216
|
const summary = await getAgentSummary(
|
|
150
|
-
deps(
|
|
217
|
+
deps(await agentStore(), scope),
|
|
151
218
|
create(GetAgentExecutionSummaryRequestSchema, { org: "acme" }),
|
|
152
219
|
caller,
|
|
153
220
|
);
|
|
221
|
+
expect(scope.offered).toEqual([
|
|
222
|
+
{
|
|
223
|
+
kind: ApiResourceKind.agent_execution,
|
|
224
|
+
ids: ["aexec_mine", "aexec_not_mine"],
|
|
225
|
+
},
|
|
226
|
+
]);
|
|
154
227
|
expect(summary.activeCount).toBe(1);
|
|
155
228
|
});
|
|
156
229
|
|
|
157
|
-
it("
|
|
230
|
+
it("answers the default instance when the scope keeps none", async () => {
|
|
158
231
|
const summary = await getAgentSummary(
|
|
159
|
-
deps(
|
|
232
|
+
deps(await agentStore(), restrictingScope([])),
|
|
160
233
|
create(GetAgentExecutionSummaryRequestSchema, { org: "acme" }),
|
|
161
234
|
caller,
|
|
162
235
|
);
|
|
@@ -165,29 +238,12 @@ describe("agent getExecutionSummary read scope", () => {
|
|
|
165
238
|
expect(summary.avgDuration).toBeUndefined();
|
|
166
239
|
});
|
|
167
240
|
|
|
168
|
-
it("no scope composed
|
|
241
|
+
it("with no scope composed counts every row of the org", async () => {
|
|
169
242
|
const summary = await getAgentSummary(
|
|
170
|
-
deps(undefined),
|
|
171
|
-
create(GetAgentExecutionSummaryRequestSchema, { org: "acme" }),
|
|
172
|
-
caller,
|
|
173
|
-
);
|
|
174
|
-
expect(summary.activeCount).toBe(3);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it("the scope receives the kind it is scoping (agent_execution here)", async () => {
|
|
178
|
-
const kinds: ApiResourceKind[] = [];
|
|
179
|
-
const recordingScope: ListReadScope = {
|
|
180
|
-
authorizedResourceIds: (_caller, kind) => {
|
|
181
|
-
kinds.push(kind);
|
|
182
|
-
return Promise.resolve(new Set<string>());
|
|
183
|
-
},
|
|
184
|
-
restrictListEntries: () => Promise.resolve(new Set<string>()),
|
|
185
|
-
};
|
|
186
|
-
await getAgentSummary(
|
|
187
|
-
deps(recordingScope),
|
|
243
|
+
deps(await agentStore(), undefined),
|
|
188
244
|
create(GetAgentExecutionSummaryRequestSchema, { org: "acme" }),
|
|
189
245
|
caller,
|
|
190
246
|
);
|
|
191
|
-
expect(
|
|
247
|
+
expect(summary.activeCount).toBe(2);
|
|
192
248
|
});
|
|
193
249
|
});
|
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Load-bearing pins the zero-record conformance arm cannot cover:
|
|
11
11
|
* - list's legacy-phase fallback vs filter.phases precedence, the T13
|
|
12
|
-
* structured filter over seeded rows, the
|
|
13
|
-
*
|
|
12
|
+
* structured filter over seeded rows, the newest-created default
|
|
13
|
+
* order and its cursor pages (a token refused on another request),
|
|
14
|
+
* and a non-default sort answering its first page with no token;
|
|
14
15
|
* - listByWorkflow matching EITHER spec.workflow_id or
|
|
15
|
-
* spec.workflow_instance_id;
|
|
16
|
+
* spec.workflow_instance_id, and paging the workflow's runs;
|
|
16
17
|
* - getEventLog cursor pagination over REAL persisted events: has_more
|
|
17
18
|
* from the +1 fetch, latest_sequence, the 500 cap, the multi-type
|
|
18
19
|
* in-memory filter, and the malformed-record skip;
|
|
@@ -20,7 +21,8 @@
|
|
|
20
21
|
* avg duration, failure ranks, cost breakdown, workflow scoping,
|
|
21
22
|
* time-window cutoff);
|
|
22
23
|
* - listPendingApprovals projection (task_name not task_id; requester
|
|
23
|
-
* from spec audit)
|
|
24
|
+
* from spec audit), its pre-truncation total_count, and its cursor
|
|
25
|
+
* splitting one execution's waiting tasks across pages;
|
|
24
26
|
* - update's status-clearing standard build and delete's audit-trail
|
|
25
27
|
* return, over the wire.
|
|
26
28
|
*/
|
|
@@ -246,7 +248,10 @@ function eventRecord(
|
|
|
246
248
|
|
|
247
249
|
describe("get / list / listByWorkflow over the wire", () => {
|
|
248
250
|
it("get answers NotFound for an unknown id", async () => {
|
|
249
|
-
await expectCode(
|
|
251
|
+
await expectCode(
|
|
252
|
+
() => query.get({ value: "wfexec_missing" }),
|
|
253
|
+
Code.NotFound,
|
|
254
|
+
);
|
|
250
255
|
});
|
|
251
256
|
|
|
252
257
|
it("get round-trips a seeded execution", async () => {
|
|
@@ -269,9 +274,7 @@ describe("get / list / listByWorkflow over the wire", () => {
|
|
|
269
274
|
(entry) => entry.status?.phase === ExecutionPhase.EXECUTION_FAILED,
|
|
270
275
|
),
|
|
271
276
|
).toBe(true);
|
|
272
|
-
expect(legacy.entries.map((entry) => entry.metadata?.id)).toContain(
|
|
273
|
-
failed,
|
|
274
|
-
);
|
|
277
|
+
expect(legacy.entries.map((entry) => entry.metadata?.id)).toContain(failed);
|
|
275
278
|
expect(legacy.totalPages).toBe(1);
|
|
276
279
|
|
|
277
280
|
// filter.phases supersedes the legacy field: a COMPLETED filter with a
|
|
@@ -288,17 +291,115 @@ describe("get / list / listByWorkflow over the wire", () => {
|
|
|
288
291
|
).toBe(true);
|
|
289
292
|
});
|
|
290
293
|
|
|
291
|
-
it("list defaults to
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
+
it("list defaults to newest created first, so a queued run leads", async () => {
|
|
295
|
+
const org = "order-org";
|
|
296
|
+
const started = await seed(
|
|
297
|
+
seedInput({
|
|
298
|
+
org,
|
|
299
|
+
startedAt: "2026-05-23T14:00:00Z",
|
|
300
|
+
createdAtMs: Date.parse("2026-05-23T09:00:00Z"),
|
|
301
|
+
}),
|
|
302
|
+
);
|
|
303
|
+
const queued = await seed(
|
|
304
|
+
seedInput({
|
|
305
|
+
org,
|
|
306
|
+
phase: ExecutionPhase.EXECUTION_PENDING,
|
|
307
|
+
createdAtMs: Date.parse("2026-05-23T10:00:00Z"),
|
|
308
|
+
}),
|
|
294
309
|
);
|
|
295
|
-
const late = await seed(seedInput({ startedAt: "2026-05-23T14:00:00Z" }));
|
|
296
310
|
|
|
297
|
-
const result = await query.list({});
|
|
298
|
-
|
|
299
|
-
|
|
311
|
+
const result = await query.list({ org });
|
|
312
|
+
expect(result.entries.map((entry) => entry.metadata?.id)).toEqual([
|
|
313
|
+
queued,
|
|
314
|
+
started,
|
|
315
|
+
]);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it("list pages newest created first with no gap or duplicate, and refuses a token on another request", async () => {
|
|
319
|
+
const org = "paging-org";
|
|
320
|
+
const base = Date.parse("2026-09-01T00:00:00Z");
|
|
321
|
+
const newestFirst: string[] = [];
|
|
322
|
+
for (let i = 0; i < 5; i++) {
|
|
323
|
+
newestFirst.unshift(
|
|
324
|
+
await seed(seedInput({ org, createdAtMs: base + i * 1000 })),
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
await seed(seedInput({ org: "other-org", createdAtMs: base + 10_000 }));
|
|
328
|
+
|
|
329
|
+
const walked: string[] = [];
|
|
330
|
+
let pageToken = "";
|
|
331
|
+
let firstToken = "";
|
|
332
|
+
do {
|
|
333
|
+
const page = await query.list({ org, pageSize: 2, pageToken });
|
|
334
|
+
expect(page.entries.length).toBeLessThanOrEqual(2);
|
|
335
|
+
expect(page.totalPages).toBe(page.nextPageToken === "" ? 1 : 0);
|
|
336
|
+
walked.push(...page.entries.map((entry) => entry.metadata!.id));
|
|
337
|
+
firstToken = firstToken === "" ? page.nextPageToken : firstToken;
|
|
338
|
+
pageToken = page.nextPageToken;
|
|
339
|
+
} while (pageToken !== "");
|
|
340
|
+
expect(walked).toEqual(newestFirst);
|
|
341
|
+
|
|
342
|
+
const replayed = await expectCode(
|
|
343
|
+
() =>
|
|
344
|
+
query.list({ org: "other-org", pageSize: 2, pageToken: firstToken }),
|
|
345
|
+
Code.InvalidArgument,
|
|
346
|
+
);
|
|
347
|
+
expect(replayed.rawMessage).toBe(
|
|
348
|
+
"page_token was issued for a different request",
|
|
300
349
|
);
|
|
301
|
-
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it("a sort other than creation sorts the whole set and returns its first page with no token", async () => {
|
|
353
|
+
const org = "sorted-org";
|
|
354
|
+
const hours = ["10", "12", "14"];
|
|
355
|
+
for (const hour of hours) {
|
|
356
|
+
await seed(
|
|
357
|
+
seedInput({
|
|
358
|
+
org,
|
|
359
|
+
startedAt: `2026-05-23T${hour}:00:00Z`,
|
|
360
|
+
createdAtMs: Date.parse(`2026-05-20T${hour}:00:00Z`),
|
|
361
|
+
}),
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const page = await query.list({
|
|
366
|
+
org,
|
|
367
|
+
pageSize: 2,
|
|
368
|
+
sortField: ExecutionSortField.STARTED_AT,
|
|
369
|
+
sortAscending: true,
|
|
370
|
+
});
|
|
371
|
+
expect(page.entries.map((entry) => entry.status?.startedAt)).toEqual([
|
|
372
|
+
"2026-05-23T10:00:00Z",
|
|
373
|
+
"2026-05-23T12:00:00Z",
|
|
374
|
+
]);
|
|
375
|
+
expect(page.nextPageToken).toBe("");
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("listByWorkflow pages the workflow's runs", async () => {
|
|
379
|
+
const base = Date.parse("2026-09-03T00:00:00Z");
|
|
380
|
+
const newestFirst: string[] = [];
|
|
381
|
+
for (let i = 0; i < 3; i++) {
|
|
382
|
+
newestFirst.unshift(
|
|
383
|
+
await seed(
|
|
384
|
+
seedInput({ workflowId: "wf_paged", createdAtMs: base + i * 1000 }),
|
|
385
|
+
),
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const first = await query.listByWorkflow({
|
|
390
|
+
workflowId: "wf_paged",
|
|
391
|
+
pageSize: 2,
|
|
392
|
+
});
|
|
393
|
+
expect(first.nextPageToken).not.toBe("");
|
|
394
|
+
const second = await query.listByWorkflow({
|
|
395
|
+
workflowId: "wf_paged",
|
|
396
|
+
pageSize: 2,
|
|
397
|
+
pageToken: first.nextPageToken,
|
|
398
|
+
});
|
|
399
|
+
expect(second.nextPageToken).toBe("");
|
|
400
|
+
expect(
|
|
401
|
+
[...first.entries, ...second.entries].map((entry) => entry.metadata?.id),
|
|
402
|
+
).toEqual(newestFirst);
|
|
302
403
|
});
|
|
303
404
|
|
|
304
405
|
it("listByWorkflow requires workflow_id and matches either spec reference", async () => {
|
|
@@ -343,12 +444,17 @@ describe("getEventLog over the wire (CW-7 pagination contract)", () => {
|
|
|
343
444
|
const records: WorkflowExecutionEventRecord[] = [];
|
|
344
445
|
for (let sequence = 1; sequence <= 5; sequence++) {
|
|
345
446
|
records.push(
|
|
346
|
-
eventRecord(
|
|
447
|
+
eventRecord(
|
|
448
|
+
id,
|
|
449
|
+
sequence,
|
|
450
|
+
WorkflowEventType.task_started,
|
|
451
|
+
`t${sequence}`,
|
|
452
|
+
),
|
|
347
453
|
);
|
|
348
454
|
}
|
|
349
|
-
expect(
|
|
350
|
-
|
|
351
|
-
)
|
|
455
|
+
expect(await server.store.appendWorkflowExecutionEvents(id, records)).toBe(
|
|
456
|
+
5,
|
|
457
|
+
);
|
|
352
458
|
|
|
353
459
|
const page1 = await query.getEventLog({ executionId: id, pageSize: 2 });
|
|
354
460
|
expect(page1.events).toHaveLength(2);
|
|
@@ -360,10 +466,7 @@ describe("getEventLog over the wire (CW-7 pagination contract)", () => {
|
|
|
360
466
|
pageSize: 2,
|
|
361
467
|
afterSequence: page1.latestSequence,
|
|
362
468
|
});
|
|
363
|
-
expect(page2.events.map((event) => event.sequenceNumber)).toEqual([
|
|
364
|
-
3n,
|
|
365
|
-
4n,
|
|
366
|
-
]);
|
|
469
|
+
expect(page2.events.map((event) => event.sequenceNumber)).toEqual([3n, 4n]);
|
|
367
470
|
expect(page2.hasMore).toBe(true);
|
|
368
471
|
|
|
369
472
|
const page3 = await query.getEventLog({
|
|
@@ -444,7 +547,10 @@ describe("getEventLog over the wire (CW-7 pagination contract)", () => {
|
|
|
444
547
|
]);
|
|
445
548
|
const tailPage = await query.getEventLog({ executionId: tail });
|
|
446
549
|
expect(tailPage.events.map((event) => event.sequenceNumber)).toEqual([1n]);
|
|
447
|
-
expect(
|
|
550
|
+
expect(
|
|
551
|
+
tailPage.latestSequence,
|
|
552
|
+
"malformed rows never advance the cursor",
|
|
553
|
+
).toBe(1n);
|
|
448
554
|
});
|
|
449
555
|
|
|
450
556
|
it("caps page_size at 500 and defaults to 100", async () => {
|
|
@@ -548,7 +654,10 @@ describe("getExecutionSummary over the wire", () => {
|
|
|
548
654
|
});
|
|
549
655
|
expect(windowed.totalCount).toBe(0);
|
|
550
656
|
expect(windowed.successRate).toBe(-1);
|
|
551
|
-
expect(
|
|
657
|
+
expect(
|
|
658
|
+
windowed.totalCost,
|
|
659
|
+
"zero cost summary is ALWAYS present",
|
|
660
|
+
).toBeDefined();
|
|
552
661
|
expect(windowed.avgDuration, "no completed runs → absent").toBeUndefined();
|
|
553
662
|
|
|
554
663
|
const allTime = await query.getExecutionSummary({
|
|
@@ -603,9 +712,9 @@ describe("listPendingApprovals over the wire", () => {
|
|
|
603
712
|
expect(entry?.workflowName).toBe("Approval Flow");
|
|
604
713
|
expect(entry?.requester).toBe("usr_seeder");
|
|
605
714
|
expect(entry?.uiHint).toBe("approval-form");
|
|
606
|
-
expect(
|
|
607
|
-
|
|
608
|
-
)
|
|
715
|
+
expect(result.entries.some((item) => item.taskName === "paused-gate")).toBe(
|
|
716
|
+
false,
|
|
717
|
+
);
|
|
609
718
|
});
|
|
610
719
|
|
|
611
720
|
it("total_count is the pre-truncation total", async () => {
|
|
@@ -621,6 +730,54 @@ describe("listPendingApprovals over the wire", () => {
|
|
|
621
730
|
expect(page.entries).toHaveLength(1);
|
|
622
731
|
expect(page.totalCount).toBeGreaterThanOrEqual(3);
|
|
623
732
|
});
|
|
733
|
+
|
|
734
|
+
it("pages newest execution first, then each execution's waiting tasks in order, across page boundaries", async () => {
|
|
735
|
+
const org = "approvals-paging-org";
|
|
736
|
+
const waiting = (taskName: string) => ({
|
|
737
|
+
taskName,
|
|
738
|
+
status: WorkflowTaskStatus.WORKFLOW_TASK_WAITING_APPROVAL,
|
|
739
|
+
});
|
|
740
|
+
const older = await seed(
|
|
741
|
+
seedInput({
|
|
742
|
+
org,
|
|
743
|
+
phase: ExecutionPhase.EXECUTION_IN_PROGRESS,
|
|
744
|
+
createdAtMs: Date.parse("2026-09-04T00:00:00Z"),
|
|
745
|
+
tasks: [waiting("older-gate")],
|
|
746
|
+
}),
|
|
747
|
+
);
|
|
748
|
+
const newer = await seed(
|
|
749
|
+
seedInput({
|
|
750
|
+
org,
|
|
751
|
+
phase: ExecutionPhase.EXECUTION_IN_PROGRESS,
|
|
752
|
+
createdAtMs: Date.parse("2026-09-04T00:00:01Z"),
|
|
753
|
+
tasks: [waiting("first-gate"), waiting("second-gate")],
|
|
754
|
+
}),
|
|
755
|
+
);
|
|
756
|
+
|
|
757
|
+
const walked: Array<[string, string]> = [];
|
|
758
|
+
let pageToken = "";
|
|
759
|
+
do {
|
|
760
|
+
const page = await query.listPendingApprovals({
|
|
761
|
+
org,
|
|
762
|
+
pageSize: 1,
|
|
763
|
+
pageToken,
|
|
764
|
+
});
|
|
765
|
+
expect(page.totalCount).toBe(3);
|
|
766
|
+
walked.push(
|
|
767
|
+
...page.entries.map((entry): [string, string] => [
|
|
768
|
+
entry.executionId,
|
|
769
|
+
entry.taskName,
|
|
770
|
+
]),
|
|
771
|
+
);
|
|
772
|
+
pageToken = page.nextPageToken;
|
|
773
|
+
} while (pageToken !== "");
|
|
774
|
+
|
|
775
|
+
expect(walked).toEqual([
|
|
776
|
+
[newer, "first-gate"],
|
|
777
|
+
[newer, "second-gate"],
|
|
778
|
+
[older, "older-gate"],
|
|
779
|
+
]);
|
|
780
|
+
});
|
|
624
781
|
});
|
|
625
782
|
|
|
626
783
|
describe("updateStatus over the wire", () => {
|
|
@@ -717,7 +874,9 @@ describe("subscribe over the wire (streaming smoke through the real transport)",
|
|
|
717
874
|
}
|
|
718
875
|
}, Code.InvalidArgument);
|
|
719
876
|
await expectCode(async () => {
|
|
720
|
-
for await (const _ of query.subscribe({
|
|
877
|
+
for await (const _ of query.subscribe({
|
|
878
|
+
executionId: "wfexec_missing",
|
|
879
|
+
})) {
|
|
721
880
|
break;
|
|
722
881
|
}
|
|
723
882
|
}, Code.NotFound);
|
|
@@ -1256,7 +1415,10 @@ describe("submitFileDecision over the wire (propagation through the REAL in-proc
|
|
|
1256
1415
|
const changeSet = child.status?.fileChangeSets.find(
|
|
1257
1416
|
(cs) => cs.id === changeSetId,
|
|
1258
1417
|
);
|
|
1259
|
-
expect(
|
|
1418
|
+
expect(
|
|
1419
|
+
changeSet?.decisions,
|
|
1420
|
+
"the child recorded the decision",
|
|
1421
|
+
).toHaveLength(1);
|
|
1260
1422
|
});
|
|
1261
1423
|
|
|
1262
1424
|
it("the child's actionable rejection PROPAGATES unchanged (the file-decision asymmetry)", async () => {
|