@moltzap/protocol 2026.503.3 → 2026.504.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/brands.d.ts +11 -0
- package/dist/brands.d.ts.map +1 -0
- package/dist/brands.js +14 -0
- package/dist/brands.js.map +1 -0
- package/dist/helpers.d.ts +29 -26
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +34 -16
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/internal/ajv.d.ts +5 -0
- package/dist/internal/ajv.d.ts.map +1 -0
- package/dist/internal/ajv.js +22 -0
- package/dist/internal/ajv.js.map +1 -0
- package/dist/notification.d.ts +14 -0
- package/dist/notification.d.ts.map +1 -0
- package/dist/notification.js +11 -0
- package/dist/notification.js.map +1 -0
- package/dist/rpc-errors.d.ts +30 -0
- package/dist/rpc-errors.d.ts.map +1 -0
- package/dist/rpc-errors.js +23 -0
- package/dist/rpc-errors.js.map +1 -0
- package/dist/rpc-groups.d.ts +120 -0
- package/dist/rpc-groups.d.ts.map +1 -0
- package/dist/rpc-groups.js +131 -0
- package/dist/rpc-groups.js.map +1 -0
- package/dist/rpc-registry.d.ts +1238 -278
- package/dist/rpc-registry.d.ts.map +1 -1
- package/dist/rpc-registry.js +11 -22
- package/dist/rpc-registry.js.map +1 -1
- package/dist/rpc.d.ts +26 -5
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +21 -11
- package/dist/rpc.js.map +1 -1
- package/dist/schema/apps.d.ts +13 -23
- package/dist/schema/apps.d.ts.map +1 -1
- package/dist/schema/apps.js +2 -12
- package/dist/schema/apps.js.map +1 -1
- package/dist/schema/contacts.d.ts +6 -2
- package/dist/schema/contacts.d.ts.map +1 -1
- package/dist/schema/conversations.d.ts +15 -5
- package/dist/schema/conversations.d.ts.map +1 -1
- package/dist/schema/delivery.d.ts +9 -3
- package/dist/schema/delivery.d.ts.map +1 -1
- package/dist/schema/errors.d.ts +0 -4
- package/dist/schema/errors.d.ts.map +1 -1
- package/dist/schema/errors.js +0 -4
- package/dist/schema/errors.js.map +1 -1
- package/dist/schema/frames.d.ts +48 -51
- package/dist/schema/frames.d.ts.map +1 -1
- package/dist/schema/frames.js +28 -50
- package/dist/schema/frames.js.map +1 -1
- package/dist/schema/identity.d.ts +17 -9
- package/dist/schema/identity.d.ts.map +1 -1
- package/dist/schema/index.d.ts +3 -4
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +3 -4
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/internal-frames.d.ts +10 -0
- package/dist/schema/internal-frames.d.ts.map +1 -0
- package/dist/schema/internal-frames.js +5 -0
- package/dist/schema/internal-frames.js.map +1 -0
- package/dist/schema/invites.d.ts +6 -2
- package/dist/schema/invites.d.ts.map +1 -1
- package/dist/schema/json-rpc.d.ts +27 -0
- package/dist/schema/json-rpc.d.ts.map +1 -0
- package/dist/schema/json-rpc.js +32 -0
- package/dist/schema/json-rpc.js.map +1 -0
- package/dist/schema/messages.d.ts +15 -5
- package/dist/schema/messages.d.ts.map +1 -1
- package/dist/schema/methods/apps.d.ts +138 -85
- package/dist/schema/methods/apps.d.ts.map +1 -1
- package/dist/schema/methods/apps.js +4 -45
- package/dist/schema/methods/apps.js.map +1 -1
- package/dist/schema/methods/auth.d.ts +62 -34
- package/dist/schema/methods/auth.d.ts.map +1 -1
- package/dist/schema/methods/contacts.d.ts +27 -9
- package/dist/schema/methods/contacts.d.ts.map +1 -1
- package/dist/schema/methods/conversations.d.ts +91 -18
- package/dist/schema/methods/conversations.d.ts.map +1 -1
- package/dist/schema/methods/conversations.js +2 -2
- package/dist/schema/methods/conversations.js.map +1 -1
- package/dist/schema/methods/messages.d.ts +39 -13
- package/dist/schema/methods/messages.d.ts.map +1 -1
- package/dist/schema/methods/presence.d.ts +6 -2
- package/dist/schema/methods/presence.d.ts.map +1 -1
- package/dist/schema/notifications.d.ts +791 -0
- package/dist/schema/notifications.d.ts.map +1 -0
- package/dist/schema/notifications.js +173 -0
- package/dist/schema/notifications.js.map +1 -0
- package/dist/schema/presence.d.ts +3 -1
- package/dist/schema/presence.d.ts.map +1 -1
- package/dist/schema/primitives.d.ts +21 -5
- package/dist/schema/primitives.d.ts.map +1 -1
- package/dist/schema/primitives.js +6 -0
- package/dist/schema/primitives.js.map +1 -1
- package/dist/test-fixtures/seed-data.d.ts +0 -1388
- package/dist/test-fixtures/seed-data.d.ts.map +1 -1
- package/dist/test-fixtures/seed-data.js +34 -990
- package/dist/test-fixtures/seed-data.js.map +1 -1
- package/dist/testing/agent-registration.d.ts +3 -1
- package/dist/testing/agent-registration.d.ts.map +1 -1
- package/dist/testing/agent-registration.js +6 -15
- package/dist/testing/agent-registration.js.map +1 -1
- package/dist/testing/arbitraries/frames.d.ts +2 -2
- package/dist/testing/arbitraries/frames.d.ts.map +1 -1
- package/dist/testing/arbitraries/frames.js +9 -7
- package/dist/testing/arbitraries/frames.js.map +1 -1
- package/dist/testing/arbitraries/from-typebox.d.ts.map +1 -1
- package/dist/testing/arbitraries/from-typebox.js +19 -10
- package/dist/testing/arbitraries/from-typebox.js.map +1 -1
- package/dist/testing/arbitraries/index.d.ts +1 -1
- package/dist/testing/arbitraries/index.d.ts.map +1 -1
- package/dist/testing/arbitraries/index.js +1 -1
- package/dist/testing/arbitraries/index.js.map +1 -1
- package/dist/testing/arbitraries/rpc.d.ts +3 -2
- package/dist/testing/arbitraries/rpc.d.ts.map +1 -1
- package/dist/testing/arbitraries/rpc.js +13 -3
- package/dist/testing/arbitraries/rpc.js.map +1 -1
- package/dist/testing/captures.d.ts.map +1 -1
- package/dist/testing/captures.js +4 -3
- package/dist/testing/captures.js.map +1 -1
- package/dist/testing/codec.d.ts +13 -11
- package/dist/testing/codec.d.ts.map +1 -1
- package/dist/testing/codec.js +43 -50
- package/dist/testing/codec.js.map +1 -1
- package/dist/testing/conformance/__divergence_proofs__/executable-proof-helpers.d.ts.map +1 -1
- package/dist/testing/conformance/__divergence_proofs__/executable-proof-helpers.js +15 -5
- package/dist/testing/conformance/__divergence_proofs__/executable-proof-helpers.js.map +1 -1
- package/dist/testing/conformance/_helpers.d.ts +12 -7
- package/dist/testing/conformance/_helpers.d.ts.map +1 -1
- package/dist/testing/conformance/_helpers.js +30 -7
- package/dist/testing/conformance/_helpers.js.map +1 -1
- package/dist/testing/conformance/adversity.d.ts.map +1 -1
- package/dist/testing/conformance/adversity.js +83 -90
- package/dist/testing/conformance/adversity.js.map +1 -1
- package/dist/testing/conformance/boundary.d.ts +1 -1
- package/dist/testing/conformance/boundary.d.ts.map +1 -1
- package/dist/testing/conformance/boundary.js +55 -50
- package/dist/testing/conformance/boundary.js.map +1 -1
- package/dist/testing/conformance/client/_fixtures.d.ts +7 -5
- package/dist/testing/conformance/client/_fixtures.d.ts.map +1 -1
- package/dist/testing/conformance/client/_fixtures.js +17 -8
- package/dist/testing/conformance/client/_fixtures.js.map +1 -1
- package/dist/testing/conformance/client/adversity.d.ts.map +1 -1
- package/dist/testing/conformance/client/adversity.js +28 -22
- package/dist/testing/conformance/client/adversity.js.map +1 -1
- package/dist/testing/conformance/client/boundary.d.ts +2 -2
- package/dist/testing/conformance/client/boundary.d.ts.map +1 -1
- package/dist/testing/conformance/client/boundary.js +19 -16
- package/dist/testing/conformance/client/boundary.js.map +1 -1
- package/dist/testing/conformance/client/delivery.d.ts +5 -5
- package/dist/testing/conformance/client/delivery.d.ts.map +1 -1
- package/dist/testing/conformance/client/delivery.js +77 -73
- package/dist/testing/conformance/client/delivery.js.map +1 -1
- package/dist/testing/conformance/client/index.d.ts +2 -2
- package/dist/testing/conformance/client/index.d.ts.map +1 -1
- package/dist/testing/conformance/client/index.js +1 -1
- package/dist/testing/conformance/client/index.js.map +1 -1
- package/dist/testing/conformance/client/rpc-semantics.d.ts.map +1 -1
- package/dist/testing/conformance/client/rpc-semantics.js +31 -37
- package/dist/testing/conformance/client/rpc-semantics.js.map +1 -1
- package/dist/testing/conformance/client/runner.d.ts +38 -32
- package/dist/testing/conformance/client/runner.d.ts.map +1 -1
- package/dist/testing/conformance/client/runner.js +36 -45
- package/dist/testing/conformance/client/runner.js.map +1 -1
- package/dist/testing/conformance/client/schema-conformance.d.ts +8 -8
- package/dist/testing/conformance/client/schema-conformance.d.ts.map +1 -1
- package/dist/testing/conformance/client/schema-conformance.js +37 -35
- package/dist/testing/conformance/client/schema-conformance.js.map +1 -1
- package/dist/testing/conformance/client/suite.d.ts.map +1 -1
- package/dist/testing/conformance/client/suite.js +4 -3
- package/dist/testing/conformance/client/suite.js.map +1 -1
- package/dist/testing/conformance/delivery.d.ts.map +1 -1
- package/dist/testing/conformance/delivery.js +127 -140
- package/dist/testing/conformance/delivery.js.map +1 -1
- package/dist/testing/conformance/dispatcher-concurrency.js +12 -12
- package/dist/testing/conformance/dispatcher-concurrency.js.map +1 -1
- package/dist/testing/conformance/env.d.ts +9 -0
- package/dist/testing/conformance/env.d.ts.map +1 -1
- package/dist/testing/conformance/env.js +16 -3
- package/dist/testing/conformance/env.js.map +1 -1
- package/dist/testing/conformance/presence.d.ts.map +1 -1
- package/dist/testing/conformance/presence.js +35 -24
- package/dist/testing/conformance/presence.js.map +1 -1
- package/dist/testing/conformance/registry.d.ts +1 -1
- package/dist/testing/conformance/registry.d.ts.map +1 -1
- package/dist/testing/conformance/registry.js +1 -1
- package/dist/testing/conformance/registry.js.map +1 -1
- package/dist/testing/conformance/rpc-semantics.d.ts +12 -12
- package/dist/testing/conformance/rpc-semantics.d.ts.map +1 -1
- package/dist/testing/conformance/rpc-semantics.js +131 -90
- package/dist/testing/conformance/rpc-semantics.js.map +1 -1
- package/dist/testing/conformance/runner.d.ts +2 -2
- package/dist/testing/conformance/runner.d.ts.map +1 -1
- package/dist/testing/conformance/runner.js +5 -10
- package/dist/testing/conformance/runner.js.map +1 -1
- package/dist/testing/conformance/schema-conformance.d.ts +3 -40
- package/dist/testing/conformance/schema-conformance.d.ts.map +1 -1
- package/dist/testing/conformance/schema-conformance.js +75 -235
- package/dist/testing/conformance/schema-conformance.js.map +1 -1
- package/dist/testing/conformance/suite.d.ts +1 -1
- package/dist/testing/conformance/suite.d.ts.map +1 -1
- package/dist/testing/conformance/suite.js +17 -18
- package/dist/testing/conformance/suite.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/models/dispatch.d.ts +5 -5
- package/dist/testing/models/dispatch.d.ts.map +1 -1
- package/dist/testing/models/dispatch.js +50 -59
- package/dist/testing/models/dispatch.js.map +1 -1
- package/dist/testing/models/state.d.ts +5 -5
- package/dist/testing/models/state.d.ts.map +1 -1
- package/dist/testing/models/state.js +14 -1
- package/dist/testing/models/state.js.map +1 -1
- package/dist/testing/test-client.d.ts +51 -40
- package/dist/testing/test-client.d.ts.map +1 -1
- package/dist/testing/test-client.js +154 -122
- package/dist/testing/test-client.js.map +1 -1
- package/dist/testing/test-server.d.ts +5 -5
- package/dist/testing/test-server.d.ts.map +1 -1
- package/dist/testing/test-server.js +11 -15
- package/dist/testing/test-server.js.map +1 -1
- package/dist/testing/toxics/client.d.ts.map +1 -1
- package/dist/testing/toxics/client.js +9 -3
- package/dist/testing/toxics/client.js.map +1 -1
- package/dist/testing/toxics/profile.d.ts.map +1 -1
- package/dist/testing/toxics/profile.js +4 -1
- package/dist/testing/toxics/profile.js.map +1 -1
- package/dist/types.d.ts +3 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/validators.d.ts +366 -101
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +23 -30
- package/dist/validators.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/dist/schema/events.d.ts +0 -213
- package/dist/schema/events.d.ts.map +0 -1
- package/dist/schema/events.js +0 -122
- package/dist/schema/events.js.map +0 -1
- package/dist/schema/methods/push.d.ts +0 -21
- package/dist/schema/methods/push.d.ts.map +0 -1
- package/dist/schema/methods/push.js +0 -28
- package/dist/schema/methods/push.js.map +0 -1
- package/dist/schema/surfaces.d.ts +0 -55
- package/dist/schema/surfaces.d.ts.map +0 -1
- package/dist/schema/surfaces.js +0 -55
- package/dist/schema/surfaces.js.map +0 -1
|
@@ -9,23 +9,30 @@
|
|
|
9
9
|
* Principle 3: every property body is `Effect<void, PropertyFailure>`.
|
|
10
10
|
*/
|
|
11
11
|
import * as fc from "fast-check";
|
|
12
|
-
import { Effect, Ref } from "effect";
|
|
12
|
+
import { Effect, Either, Ref } from "effect";
|
|
13
13
|
import { ErrorCodes } from "../../schema/errors.js";
|
|
14
|
-
import {
|
|
14
|
+
import { AppSessionClosedNotificationDefinition, ConversationArchivedNotificationDefinition, ConversationCreatedNotificationDefinition, ConversationUnarchivedNotificationDefinition, ConversationUpdatedNotificationDefinition, MessageReceivedNotificationDefinition, } from "../../schema/notifications.js";
|
|
15
15
|
import { AppsCloseSession, AppsCreate, AppsRegister, } from "../../schema/methods/apps.js";
|
|
16
16
|
import { ConversationsArchive, ConversationsCreate, ConversationsUnarchive, ConversationsUpdate, } from "../../schema/methods/conversations.js";
|
|
17
17
|
import { MessagesSend } from "../../schema/methods/messages.js";
|
|
18
|
+
import { AgentId, ConversationId, conversationId as makeConversationId, } from "../../schema/primitives.js";
|
|
19
|
+
import { RpcResponseError } from "../errors.js";
|
|
20
|
+
import { isNotificationFrame } from "../codec.js";
|
|
18
21
|
import { makeTestClient } from "../test-client.js";
|
|
19
22
|
import { registerTestAgent } from "../agent-registration.js";
|
|
20
23
|
import { PropertyDeferred, PropertyInvariantViolation, PropertyUnavailable, assertProperty, registerProperty, } from "./registry.js";
|
|
21
|
-
import { sendUntypedRpc } from "./_helpers.js";
|
|
24
|
+
import { leftOrNull, requireRight, sendUntypedRpc } from "./_helpers.js";
|
|
22
25
|
const CATEGORY = "delivery";
|
|
23
26
|
const DEFAULT_TIMEOUT_MS = 5000;
|
|
24
27
|
const DEFAULT_CAPTURE_CAPACITY = 256;
|
|
28
|
+
const DEFAULT_PROPERTY_NUM_RUNS = 3;
|
|
29
|
+
const DATE_ID_RADIX = 36;
|
|
25
30
|
const MAX_N = 4;
|
|
26
31
|
const CONVERSATION_LIFECYCLE_PROPERTY = "conversation-lifecycle";
|
|
27
32
|
const APP_SESSION_CLOSE_LIFECYCLE_PROPERTY = "app-session-close-lifecycle";
|
|
28
33
|
const ARCHIVE_LIFECYCLE_PROPERTY = "archive-lifecycle";
|
|
34
|
+
const STORE_AND_REPLAY_PROPERTY = "store-and-replay";
|
|
35
|
+
const TASK_BOUNDARY_ISOLATION_PROPERTY = "task-boundary-isolation";
|
|
29
36
|
function violation(name, reason) {
|
|
30
37
|
return new PropertyInvariantViolation({ category: CATEGORY, name, reason });
|
|
31
38
|
}
|
|
@@ -39,104 +46,110 @@ function firstParticipant(fixture, propertyName) {
|
|
|
39
46
|
: Effect.succeed(participant);
|
|
40
47
|
}
|
|
41
48
|
function sendText(actor, conversationId, text) {
|
|
42
|
-
return actor.client.sendRpc(MessagesSend
|
|
49
|
+
return actor.client.sendRpc(MessagesSend, {
|
|
43
50
|
conversationId,
|
|
44
51
|
parts: [{ type: "text", text }],
|
|
45
52
|
});
|
|
46
53
|
}
|
|
47
54
|
function archiveConversation(actor, conversationId) {
|
|
48
|
-
return actor.client.sendRpc(ConversationsArchive
|
|
55
|
+
return actor.client.sendRpc(ConversationsArchive, { conversationId });
|
|
49
56
|
}
|
|
50
57
|
function updateConversationName(actor, conversationId, name) {
|
|
51
|
-
return actor.client.sendRpc(ConversationsUpdate
|
|
58
|
+
return actor.client.sendRpc(ConversationsUpdate, {
|
|
52
59
|
conversationId,
|
|
53
60
|
name,
|
|
54
61
|
});
|
|
55
62
|
}
|
|
56
63
|
function unarchiveConversation(actor, conversationId) {
|
|
57
|
-
return actor.client.sendRpc(ConversationsUnarchive
|
|
64
|
+
return actor.client.sendRpc(ConversationsUnarchive, { conversationId });
|
|
58
65
|
}
|
|
59
|
-
function
|
|
66
|
+
function waitForConversationCreatedNotification(observer, conversationId, propertyName) {
|
|
60
67
|
return Effect.gen(function* () {
|
|
61
68
|
const event = yield* observer.client
|
|
62
|
-
.
|
|
69
|
+
.waitForNotification(ConversationCreatedNotificationDefinition, DEFAULT_TIMEOUT_MS)
|
|
63
70
|
.pipe(Effect.mapError((e) => violation(propertyName, `created event missing: ${e.message}`)));
|
|
64
|
-
const data = event.
|
|
71
|
+
const data = event.params;
|
|
65
72
|
if (data?.conversation?.id !== conversationId) {
|
|
66
|
-
return yield* Effect.fail(violation(propertyName, `bad created event payload: ${JSON.stringify(event.
|
|
73
|
+
return yield* Effect.fail(violation(propertyName, `bad created event payload: ${JSON.stringify(event.params)}`));
|
|
67
74
|
}
|
|
68
75
|
});
|
|
69
76
|
}
|
|
70
|
-
function
|
|
77
|
+
function waitForConversationUpdatedNotification(observer, conversationId, name, propertyName) {
|
|
71
78
|
return Effect.gen(function* () {
|
|
72
79
|
const event = yield* observer.client
|
|
73
|
-
.
|
|
80
|
+
.waitForNotification(ConversationUpdatedNotificationDefinition, DEFAULT_TIMEOUT_MS)
|
|
74
81
|
.pipe(Effect.mapError((e) => violation(propertyName, `updated event missing: ${e.message}`)));
|
|
75
|
-
const data = event.
|
|
82
|
+
const data = event.params;
|
|
76
83
|
if (data?.conversation?.id !== conversationId ||
|
|
77
84
|
data.conversation.name !== name) {
|
|
78
|
-
return yield* Effect.fail(violation(propertyName, `bad updated event payload: ${JSON.stringify(event.
|
|
85
|
+
return yield* Effect.fail(violation(propertyName, `bad updated event payload: ${JSON.stringify(event.params)}`));
|
|
79
86
|
}
|
|
80
87
|
});
|
|
81
88
|
}
|
|
82
|
-
function
|
|
89
|
+
function waitForMessageReceivedNotification(observer, conversationId, propertyName) {
|
|
83
90
|
return Effect.gen(function* () {
|
|
84
91
|
const event = yield* observer.client
|
|
85
|
-
.
|
|
92
|
+
.waitForNotification(MessageReceivedNotificationDefinition, DEFAULT_TIMEOUT_MS)
|
|
86
93
|
.pipe(Effect.mapError((e) => violation(propertyName, `message event missing: ${e.message}`)));
|
|
87
|
-
const data = event.
|
|
94
|
+
const data = event.params;
|
|
88
95
|
if (data?.message?.conversationId !== conversationId) {
|
|
89
|
-
return yield* Effect.fail(violation(propertyName, `bad message event payload: ${JSON.stringify(event.
|
|
96
|
+
return yield* Effect.fail(violation(propertyName, `bad message event payload: ${JSON.stringify(event.params)}`));
|
|
90
97
|
}
|
|
91
98
|
});
|
|
92
99
|
}
|
|
93
|
-
function
|
|
100
|
+
function waitForAppSessionClosedNotification(observer, sessionId, closedBy, propertyName) {
|
|
94
101
|
return Effect.gen(function* () {
|
|
95
102
|
const event = yield* observer.client
|
|
96
|
-
.
|
|
103
|
+
.waitForNotification(AppSessionClosedNotificationDefinition, DEFAULT_TIMEOUT_MS)
|
|
97
104
|
.pipe(Effect.mapError((e) => violation(propertyName, `session closed event missing: ${e.message}`)));
|
|
98
|
-
const data = event.
|
|
105
|
+
const data = event.params;
|
|
99
106
|
if (data?.sessionId !== sessionId || data.closedBy !== closedBy) {
|
|
100
|
-
return yield* Effect.fail(violation(propertyName, `bad session closed event payload: ${JSON.stringify(event.
|
|
107
|
+
return yield* Effect.fail(violation(propertyName, `bad session closed event payload: ${JSON.stringify(event.params)}`));
|
|
101
108
|
}
|
|
102
109
|
});
|
|
103
110
|
}
|
|
104
111
|
function waitForArchivedEvent(observer, conversationId, byAgentId, propertyName) {
|
|
105
112
|
return Effect.gen(function* () {
|
|
106
113
|
const event = yield* observer.client
|
|
107
|
-
.
|
|
114
|
+
.waitForNotification(ConversationArchivedNotificationDefinition, DEFAULT_TIMEOUT_MS)
|
|
108
115
|
.pipe(Effect.mapError((e) => violation(propertyName, `archive event missing: ${e.message}`)));
|
|
109
|
-
const data = event.
|
|
116
|
+
const data = event.params;
|
|
110
117
|
if (data?.conversationId !== conversationId ||
|
|
111
118
|
typeof data.archivedAt !== "string" ||
|
|
112
119
|
data.by !== byAgentId) {
|
|
113
|
-
return yield* Effect.fail(violation(propertyName, `bad archive event payload: ${JSON.stringify(event.
|
|
120
|
+
return yield* Effect.fail(violation(propertyName, `bad archive event payload: ${JSON.stringify(event.params)}`));
|
|
114
121
|
}
|
|
115
122
|
});
|
|
116
123
|
}
|
|
117
124
|
function waitForUnarchivedEvent(observer, conversationId, byAgentId, propertyName) {
|
|
118
125
|
return Effect.gen(function* () {
|
|
119
126
|
const event = yield* observer.client
|
|
120
|
-
.
|
|
127
|
+
.waitForNotification(ConversationUnarchivedNotificationDefinition, DEFAULT_TIMEOUT_MS)
|
|
121
128
|
.pipe(Effect.mapError((e) => violation(propertyName, `unarchive event missing: ${e.message}`)));
|
|
122
|
-
const data = event.
|
|
129
|
+
const data = event.params;
|
|
123
130
|
if (data?.conversationId !== conversationId || data.by !== byAgentId) {
|
|
124
|
-
return yield* Effect.fail(violation(propertyName, `bad unarchive event payload: ${JSON.stringify(event.
|
|
131
|
+
return yield* Effect.fail(violation(propertyName, `bad unarchive event payload: ${JSON.stringify(event.params)}`));
|
|
125
132
|
}
|
|
126
133
|
});
|
|
127
134
|
}
|
|
128
135
|
function assertConversationRejectsMessages(actor, conversationId, propertyName) {
|
|
129
136
|
return Effect.gen(function* () {
|
|
130
137
|
const outcome = yield* sendText(actor, conversationId, "must-fail-while-archived").pipe(Effect.either);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
const outcomeViolation = Either.match(outcome, {
|
|
139
|
+
onRight: () => violation(propertyName, "messages/send succeeded while archived"),
|
|
140
|
+
onLeft: (error) => {
|
|
141
|
+
if (error instanceof RpcResponseError &&
|
|
142
|
+
error.code === ErrorCodes.ConversationArchived) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
const errorLabel = error instanceof RpcResponseError
|
|
146
|
+
? `${error._tag}/${error.code}`
|
|
147
|
+
: error._tag;
|
|
148
|
+
return violation(propertyName, `messages/send returned ${errorLabel}, expected ConversationArchived`);
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
if (outcomeViolation !== null) {
|
|
152
|
+
return yield* Effect.fail(outcomeViolation);
|
|
140
153
|
}
|
|
141
154
|
});
|
|
142
155
|
}
|
|
@@ -162,7 +175,7 @@ function acquireConversation(ctx, n, namePrefix) {
|
|
|
162
175
|
const owner = yield* acquireClient(ctx, `${namePrefix}-owner`);
|
|
163
176
|
const participants = yield* Effect.forEach(Array.from({ length: clamped }, (_, i) => i), (i) => acquireClient(ctx, `${namePrefix}-p${i}`), { concurrency: clamped });
|
|
164
177
|
const createResult = yield* owner.client
|
|
165
|
-
.sendRpc(ConversationsCreate
|
|
178
|
+
.sendRpc(ConversationsCreate, {
|
|
166
179
|
type: "group",
|
|
167
180
|
name: `${namePrefix}-conv`,
|
|
168
181
|
participants: participants.map((p) => ({
|
|
@@ -171,15 +184,16 @@ function acquireConversation(ctx, n, namePrefix) {
|
|
|
171
184
|
})),
|
|
172
185
|
})
|
|
173
186
|
.pipe(Effect.either);
|
|
174
|
-
|
|
175
|
-
return yield* Effect.fail(`conversations/create failed: ${createResult.left._tag}`);
|
|
176
|
-
}
|
|
177
|
-
const created = createResult.right;
|
|
187
|
+
const created = (yield* requireRight(createResult, (error) => `conversations/create failed: ${error._tag}`));
|
|
178
188
|
const conversationId = created.conversation?.id;
|
|
179
189
|
if (typeof conversationId !== "string" || conversationId.length === 0) {
|
|
180
190
|
return yield* Effect.fail(`conversations/create returned no conversation.id`);
|
|
181
191
|
}
|
|
182
|
-
return {
|
|
192
|
+
return {
|
|
193
|
+
owner,
|
|
194
|
+
participants,
|
|
195
|
+
conversationId: makeConversationId(conversationId),
|
|
196
|
+
};
|
|
183
197
|
});
|
|
184
198
|
}
|
|
185
199
|
/**
|
|
@@ -192,22 +206,22 @@ function acquireConversation(ctx, n, namePrefix) {
|
|
|
192
206
|
*/
|
|
193
207
|
export function registerFanOutCardinality(ctx) {
|
|
194
208
|
registerProperty(ctx, CATEGORY, "fan-out-cardinality", "messages/send ⇒ exactly N inbound message events (one per connection)", assertProperty(CATEGORY, "fan-out-cardinality", () => fc.assert(fc.asyncProperty(fc.integer({ min: 2, max: 3 }), (n) => Effect.runPromise(Effect.scoped(Effect.gen(function* () {
|
|
195
|
-
const fixture = yield* acquireConversation(ctx, n, "fan").pipe(Effect.mapError((e) =>
|
|
209
|
+
const fixture = yield* acquireConversation(ctx, n, "fan").pipe(Effect.mapError((e) => violation("fan-out-cardinality", `fixture: ${e}`)));
|
|
196
210
|
const send = yield* fixture.owner.client
|
|
197
|
-
.sendRpc(MessagesSend
|
|
211
|
+
.sendRpc(MessagesSend, {
|
|
198
212
|
conversationId: fixture.conversationId,
|
|
199
213
|
parts: [{ type: "text", text: "fan-out-ping" }],
|
|
200
214
|
})
|
|
201
215
|
.pipe(Effect.either);
|
|
202
|
-
if (send
|
|
216
|
+
if (leftOrNull(send) !== null) {
|
|
203
217
|
return { kind: "send-failed" };
|
|
204
218
|
}
|
|
205
219
|
yield* Effect.sleep("250 millis");
|
|
206
220
|
const observed = yield* Effect.forEach(fixture.participants, (p) => p.client.snapshot);
|
|
207
221
|
const counts = observed.map((snap) => snap.filter((s) => s.kind === "inbound" &&
|
|
208
|
-
s.frame
|
|
209
|
-
|
|
210
|
-
s.frame.
|
|
222
|
+
s.frame !== null &&
|
|
223
|
+
isNotificationFrame(s.frame) &&
|
|
224
|
+
s.frame.method.includes("message")).length);
|
|
211
225
|
return { kind: "ok", counts };
|
|
212
226
|
})).pipe(Effect.map((result) => {
|
|
213
227
|
if (result.kind !== "ok")
|
|
@@ -215,7 +229,10 @@ export function registerFanOutCardinality(ctx) {
|
|
|
215
229
|
// Exact-cardinality predicate. Duplicates and drops both fail.
|
|
216
230
|
return (result.counts.length === fixture_n(n) &&
|
|
217
231
|
result.counts.every((c) => c === 1));
|
|
218
|
-
})))), {
|
|
232
|
+
})))), {
|
|
233
|
+
seed: ctx.seed,
|
|
234
|
+
numRuns: ctx.opts.numRuns ?? DEFAULT_PROPERTY_NUM_RUNS,
|
|
235
|
+
})));
|
|
219
236
|
}
|
|
220
237
|
function fixture_n(requested) {
|
|
221
238
|
return Math.min(Math.max(1, requested), MAX_N);
|
|
@@ -245,24 +262,24 @@ function fixture_n(requested) {
|
|
|
245
262
|
* from the git history and remove the #186 pointer.
|
|
246
263
|
*/
|
|
247
264
|
export function registerStoreAndReplay(ctx) {
|
|
248
|
-
registerProperty(ctx, CATEGORY,
|
|
265
|
+
registerProperty(ctx, CATEGORY, STORE_AND_REPLAY_PROPERTY, "every messages/send lands in a live participant's capture buffer (basic-delivery-landing; #186 tracks C2 offline-replay)", Effect.scoped(Effect.gen(function* () {
|
|
249
266
|
const fixture = yield* acquireConversation(ctx, 1, "sr").pipe(Effect.mapError((e) => new PropertyInvariantViolation({
|
|
250
267
|
category: CATEGORY,
|
|
251
|
-
name:
|
|
268
|
+
name: STORE_AND_REPLAY_PROPERTY,
|
|
252
269
|
reason: `fixture: ${e}`,
|
|
253
270
|
})));
|
|
254
271
|
const participant = fixture.participants[0];
|
|
255
272
|
if (participant === undefined) {
|
|
256
273
|
return yield* Effect.fail(new PropertyInvariantViolation({
|
|
257
274
|
category: CATEGORY,
|
|
258
|
-
name:
|
|
275
|
+
name: STORE_AND_REPLAY_PROPERTY,
|
|
259
276
|
reason: "fixture missing participant",
|
|
260
277
|
}));
|
|
261
278
|
}
|
|
262
279
|
const sent = 3;
|
|
263
280
|
for (let i = 0; i < sent; i++) {
|
|
264
281
|
yield* fixture.owner.client
|
|
265
|
-
.sendRpc(MessagesSend
|
|
282
|
+
.sendRpc(MessagesSend, {
|
|
266
283
|
conversationId: fixture.conversationId,
|
|
267
284
|
parts: [{ type: "text", text: `sr-${i}` }],
|
|
268
285
|
})
|
|
@@ -271,13 +288,13 @@ export function registerStoreAndReplay(ctx) {
|
|
|
271
288
|
yield* Effect.sleep("350 millis");
|
|
272
289
|
const snap = yield* participant.client.snapshot;
|
|
273
290
|
const delivered = snap.filter((s) => s.kind === "inbound" &&
|
|
274
|
-
s.frame
|
|
275
|
-
|
|
276
|
-
s.frame.
|
|
291
|
+
s.frame !== null &&
|
|
292
|
+
isNotificationFrame(s.frame) &&
|
|
293
|
+
s.frame.method.includes("message")).length;
|
|
277
294
|
if (delivered < sent) {
|
|
278
295
|
return yield* Effect.fail(new PropertyInvariantViolation({
|
|
279
296
|
category: CATEGORY,
|
|
280
|
-
name:
|
|
297
|
+
name: STORE_AND_REPLAY_PROPERTY,
|
|
281
298
|
reason: `sent ${sent}, live participant observed ${delivered}`,
|
|
282
299
|
}));
|
|
283
300
|
}
|
|
@@ -290,22 +307,24 @@ export function registerPayloadOpacity(ctx) {
|
|
|
290
307
|
fc
|
|
291
308
|
.string({ minLength: 4, maxLength: 24 })
|
|
292
309
|
.filter((s) => !/[\\" \n\r\t]/.test(s)), (text) => Effect.runPromise(Effect.scoped(Effect.gen(function* () {
|
|
293
|
-
const fixture = yield* acquireConversation(ctx, 1, "po").pipe(Effect.mapError((e) =>
|
|
310
|
+
const fixture = yield* acquireConversation(ctx, 1, "po").pipe(Effect.mapError((e) => violation("payload-opacity", `fixture: ${e}`)));
|
|
294
311
|
const participant = fixture.participants[0];
|
|
295
312
|
if (participant === undefined)
|
|
296
313
|
return false;
|
|
297
|
-
yield* fixture.owner.client
|
|
298
|
-
.sendRpc(MessagesSend.name, {
|
|
314
|
+
yield* fixture.owner.client.sendRpc(MessagesSend, {
|
|
299
315
|
conversationId: fixture.conversationId,
|
|
300
316
|
parts: [{ type: "text", text }],
|
|
301
|
-
})
|
|
302
|
-
.pipe(Effect.either);
|
|
317
|
+
});
|
|
303
318
|
yield* Effect.sleep("250 millis");
|
|
304
319
|
const snap = yield* participant.client.snapshot;
|
|
305
320
|
return snap.some((s) => s.kind === "inbound" &&
|
|
306
|
-
s.frame
|
|
321
|
+
s.frame !== null &&
|
|
322
|
+
isNotificationFrame(s.frame) &&
|
|
307
323
|
s.raw.includes(text));
|
|
308
|
-
})).pipe(Effect.catchAll(() => Effect.succeed(false))))), {
|
|
324
|
+
})).pipe(Effect.catchAll(() => Effect.succeed(false))))), {
|
|
325
|
+
seed: ctx.seed,
|
|
326
|
+
numRuns: ctx.opts.numRuns ?? DEFAULT_PROPERTY_NUM_RUNS,
|
|
327
|
+
})));
|
|
309
328
|
}
|
|
310
329
|
/**
|
|
311
330
|
* Hook-gated delivery — admission verbs are awaitable, the verdict
|
|
@@ -332,13 +351,11 @@ export function registerPayloadOpacity(ctx) {
|
|
|
332
351
|
export function registerHookGatedDelivery(ctx) {
|
|
333
352
|
registerProperty(ctx, CATEGORY, "hook-gated-delivery", "deny drops; patch mutates recipient view; attached conv enters hooks", Effect.scoped(Effect.gen(function* () {
|
|
334
353
|
const fixture = yield* acquireAppSessionFixture(ctx, "hgd", "hook-gated-delivery").pipe(Effect.either);
|
|
335
|
-
|
|
336
|
-
return yield* Effect.fail(fixture.left);
|
|
337
|
-
}
|
|
354
|
+
yield* requireRight(fixture, (error) => error);
|
|
338
355
|
// Codex review (#327, finding 4): the protocol fixture cannot
|
|
339
356
|
// drive the deny/patch/attach scenarios end-to-end (no DB seam
|
|
340
357
|
// to inspect the recipient view; `apps/attachConversation` is a
|
|
341
|
-
//
|
|
358
|
+
// client-originated RPC but the assertion needs a server-internal observation
|
|
342
359
|
// the conformance contract does not expose). When a future
|
|
343
360
|
// fixture extension makes apps/create reachable, surface a
|
|
344
361
|
// typed Deferred so the suite reports honest coverage instead
|
|
@@ -363,9 +380,7 @@ export function registerHookGatedDelivery(ctx) {
|
|
|
363
380
|
export function registerMultiAppFifoShortCircuit(ctx) {
|
|
364
381
|
registerProperty(ctx, CATEGORY, "multi-app-fifo-short-circuit", "two apps; first denies; second hook is NOT invoked", Effect.scoped(Effect.gen(function* () {
|
|
365
382
|
const fixture = yield* acquireAppSessionFixture(ctx, "mfs", "multi-app-fifo-short-circuit").pipe(Effect.either);
|
|
366
|
-
|
|
367
|
-
return yield* Effect.fail(fixture.left);
|
|
368
|
-
}
|
|
383
|
+
yield* requireRight(fixture, (error) => error);
|
|
369
384
|
// Codex review (#327, finding 5): once apps/create succeeds, the
|
|
370
385
|
// FIFO short-circuit assertion requires registering a SECOND
|
|
371
386
|
// app on the same hook and observing the second handler is NOT
|
|
@@ -393,12 +408,11 @@ function acquireAppSessionFixture(ctx, namePrefix, propertyName) {
|
|
|
393
408
|
defaultTimeoutMs: DEFAULT_TIMEOUT_MS,
|
|
394
409
|
captureCapacity: DEFAULT_CAPTURE_CAPACITY,
|
|
395
410
|
}).pipe(Effect.mapError((e) => unavailable(`app client acquire: ${String(e)}`)));
|
|
396
|
-
const appId = `${namePrefix}-${Date.now().toString(
|
|
397
|
-
const registerOutcome = yield* sendUntypedRpc(appClient, AppsRegister
|
|
411
|
+
const appId = `${namePrefix}-${Date.now().toString(DATE_ID_RADIX)}`;
|
|
412
|
+
const registerOutcome = yield* sendUntypedRpc(appClient, AppsRegister, {
|
|
398
413
|
manifest: {
|
|
399
414
|
appId,
|
|
400
415
|
name: `Hook-gated app ${appId}`,
|
|
401
|
-
permissions: { required: [], optional: [] },
|
|
402
416
|
conversations: [
|
|
403
417
|
{ key: "main", name: "Main", participantFilter: "all" },
|
|
404
418
|
],
|
|
@@ -408,9 +422,7 @@ function acquireAppSessionFixture(ctx, namePrefix, propertyName) {
|
|
|
408
422
|
},
|
|
409
423
|
},
|
|
410
424
|
}).pipe(Effect.either);
|
|
411
|
-
|
|
412
|
-
return yield* Effect.fail(unavailable(`apps/register failed: ${registerOutcome.left._tag}`));
|
|
413
|
-
}
|
|
425
|
+
yield* requireRight(registerOutcome, (error) => unavailable(`apps/register failed: ${error._tag}`));
|
|
414
426
|
const senderAgent = yield* registerTestAgent({
|
|
415
427
|
baseUrl: ctx.realServer.baseUrl,
|
|
416
428
|
name: `${namePrefix}-sender`,
|
|
@@ -423,16 +435,14 @@ function acquireAppSessionFixture(ctx, namePrefix, propertyName) {
|
|
|
423
435
|
captureCapacity: DEFAULT_CAPTURE_CAPACITY,
|
|
424
436
|
}).pipe(Effect.mapError((e) => unavailable(`sender client acquire: ${String(e)}`)));
|
|
425
437
|
const createOutcome = yield* senderClient
|
|
426
|
-
.sendRpc(AppsCreate
|
|
438
|
+
.sendRpc(AppsCreate, { appId, invitedAgentIds: [] })
|
|
427
439
|
.pipe(Effect.either);
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const session = createOutcome.right
|
|
435
|
-
.session;
|
|
440
|
+
const createResult = yield* requireRight(createOutcome, (error) => unavailable(
|
|
441
|
+
// Most common cause: owner_user_id is null on the sender (see
|
|
442
|
+
// app-host.ts:629). The default `startCoreTestServer` does not
|
|
443
|
+
// configure `devModeUserId`; B.9 fills the gap via DB seeding.
|
|
444
|
+
`apps/create failed (likely sender owner_user_id null; B.9 covers via DB seeding): ${error._tag}`));
|
|
445
|
+
const session = createResult.session;
|
|
436
446
|
const sessionId = session?.id;
|
|
437
447
|
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
438
448
|
return yield* Effect.fail(unavailable(`apps/create returned no session.id`));
|
|
@@ -462,20 +472,17 @@ function acquireAppSessionCloseFixture(ctx) {
|
|
|
462
472
|
defaultTimeoutMs: DEFAULT_TIMEOUT_MS,
|
|
463
473
|
captureCapacity: DEFAULT_CAPTURE_CAPACITY,
|
|
464
474
|
}).pipe(Effect.mapError((e) => unavailable(`app client acquire: ${String(e)}`)));
|
|
465
|
-
const appId = `close-life-${Date.now().toString(
|
|
466
|
-
const registerOutcome = yield* sendUntypedRpc(appClient, AppsRegister
|
|
475
|
+
const appId = `close-life-${Date.now().toString(DATE_ID_RADIX)}`;
|
|
476
|
+
const registerOutcome = yield* sendUntypedRpc(appClient, AppsRegister, {
|
|
467
477
|
manifest: {
|
|
468
478
|
appId,
|
|
469
479
|
name: `Close lifecycle app ${appId}`,
|
|
470
|
-
permissions: { required: [], optional: [] },
|
|
471
480
|
conversations: [
|
|
472
481
|
{ key: "main", name: "Main", participantFilter: "all" },
|
|
473
482
|
],
|
|
474
483
|
},
|
|
475
484
|
}).pipe(Effect.either);
|
|
476
|
-
|
|
477
|
-
return yield* Effect.fail(unavailable(`apps/register failed: ${registerOutcome.left._tag}`));
|
|
478
|
-
}
|
|
485
|
+
yield* requireRight(registerOutcome, (error) => unavailable(`apps/register failed: ${error._tag}`));
|
|
479
486
|
const initiatorAgent = yield* registerTestAgent({
|
|
480
487
|
baseUrl: ctx.realServer.baseUrl,
|
|
481
488
|
name: "clinit",
|
|
@@ -501,44 +508,42 @@ function acquireAppSessionCloseFixture(ctx) {
|
|
|
501
508
|
captureCapacity: DEFAULT_CAPTURE_CAPACITY,
|
|
502
509
|
}).pipe(Effect.mapError((e) => unavailable(`invitee client acquire: ${String(e)}`)));
|
|
503
510
|
const createOutcome = yield* initiatorClient
|
|
504
|
-
.sendRpc(AppsCreate
|
|
511
|
+
.sendRpc(AppsCreate, {
|
|
505
512
|
appId,
|
|
506
513
|
invitedAgentIds: [inviteeAgent.agentId],
|
|
507
514
|
})
|
|
508
515
|
.pipe(Effect.either);
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
}
|
|
512
|
-
const session = createOutcome.right.session;
|
|
516
|
+
const createResult = yield* requireRight(createOutcome, (error) => unavailable(`apps/create failed (likely agents lack owner_user_id): ${error._tag}`));
|
|
517
|
+
const session = createResult.session;
|
|
513
518
|
const sessionId = session?.id;
|
|
514
519
|
const mainConversationId = session?.conversations?.["main"];
|
|
515
520
|
if (typeof sessionId !== "string" ||
|
|
516
521
|
typeof mainConversationId !== "string") {
|
|
517
|
-
return yield* Effect.fail(violation(propertyName, `apps/create response missing session id or main conversation: ${JSON.stringify(
|
|
522
|
+
return yield* Effect.fail(violation(propertyName, `apps/create response missing session id or main conversation: ${JSON.stringify(createResult)}`));
|
|
518
523
|
}
|
|
519
524
|
return {
|
|
520
525
|
initiator: { agent: initiatorAgent, client: initiatorClient },
|
|
521
526
|
invitee: { agent: inviteeAgent, client: inviteeClient },
|
|
522
527
|
sessionId,
|
|
523
|
-
conversationId: mainConversationId,
|
|
528
|
+
conversationId: makeConversationId(mainConversationId),
|
|
524
529
|
};
|
|
525
530
|
});
|
|
526
531
|
}
|
|
527
532
|
/** Task-boundary isolation — conversation A's events don't leak into B. */
|
|
528
533
|
export function registerTaskBoundaryIsolation(ctx) {
|
|
529
|
-
registerProperty(ctx, CATEGORY,
|
|
534
|
+
registerProperty(ctx, CATEGORY, TASK_BOUNDARY_ISOLATION_PROPERTY, "participants in conversation B observe zero leaks from conversation A", Effect.scoped(Effect.gen(function* () {
|
|
530
535
|
const fxA = yield* acquireConversation(ctx, 1, "iso-a").pipe(Effect.mapError((e) => new PropertyInvariantViolation({
|
|
531
536
|
category: CATEGORY,
|
|
532
|
-
name:
|
|
537
|
+
name: TASK_BOUNDARY_ISOLATION_PROPERTY,
|
|
533
538
|
reason: `fixture A: ${e}`,
|
|
534
539
|
})));
|
|
535
540
|
const fxB = yield* acquireConversation(ctx, 1, "iso-b").pipe(Effect.mapError((e) => new PropertyInvariantViolation({
|
|
536
541
|
category: CATEGORY,
|
|
537
|
-
name:
|
|
542
|
+
name: TASK_BOUNDARY_ISOLATION_PROPERTY,
|
|
538
543
|
reason: `fixture B: ${e}`,
|
|
539
544
|
})));
|
|
540
545
|
yield* fxA.owner.client
|
|
541
|
-
.sendRpc(MessagesSend
|
|
546
|
+
.sendRpc(MessagesSend, {
|
|
542
547
|
conversationId: fxA.conversationId,
|
|
543
548
|
parts: [{ type: "text", text: "iso-leak-canary" }],
|
|
544
549
|
})
|
|
@@ -552,7 +557,7 @@ export function registerTaskBoundaryIsolation(ctx) {
|
|
|
552
557
|
if (leaked) {
|
|
553
558
|
return yield* Effect.fail(new PropertyInvariantViolation({
|
|
554
559
|
category: CATEGORY,
|
|
555
|
-
name:
|
|
560
|
+
name: TASK_BOUNDARY_ISOLATION_PROPERTY,
|
|
556
561
|
reason: `conversation ${fxA.conversationId} leaked into outsider ${outsider.agent.agentId}`,
|
|
557
562
|
}));
|
|
558
563
|
}
|
|
@@ -572,33 +577,23 @@ export function registerConversationLifecycle(ctx) {
|
|
|
572
577
|
registerProperty(ctx, CATEGORY, CONVERSATION_LIFECYCLE_PROPERTY, "create/send/update/archive/unarchive lifecycle is observable and enforced", Effect.scoped(Effect.gen(function* () {
|
|
573
578
|
const fixture = yield* acquirePropertyConversation(ctx, CONVERSATION_LIFECYCLE_PROPERTY, "life");
|
|
574
579
|
const participant = yield* firstParticipant(fixture, CONVERSATION_LIFECYCLE_PROPERTY);
|
|
575
|
-
yield*
|
|
580
|
+
yield* waitForConversationCreatedNotification(participant, fixture.conversationId, CONVERSATION_LIFECYCLE_PROPERTY);
|
|
576
581
|
const firstSend = yield* sendText(fixture.owner, fixture.conversationId, "lifecycle-before-update").pipe(Effect.either);
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
}
|
|
580
|
-
yield* waitForMessageReceivedEvent(participant, fixture.conversationId, CONVERSATION_LIFECYCLE_PROPERTY);
|
|
582
|
+
yield* requireRight(firstSend, (error) => violation(CONVERSATION_LIFECYCLE_PROPERTY, `messages/send failed before archive: ${error._tag}`));
|
|
583
|
+
yield* waitForMessageReceivedNotification(participant, fixture.conversationId, CONVERSATION_LIFECYCLE_PROPERTY);
|
|
581
584
|
const updatedName = `Lifecycle ${ctx.seed}`;
|
|
582
585
|
const update = yield* updateConversationName(fixture.owner, fixture.conversationId, updatedName).pipe(Effect.either);
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
}
|
|
586
|
-
yield* waitForConversationUpdatedEvent(participant, fixture.conversationId, updatedName, CONVERSATION_LIFECYCLE_PROPERTY);
|
|
586
|
+
yield* requireRight(update, (error) => violation(CONVERSATION_LIFECYCLE_PROPERTY, `conversations/update failed: ${error._tag}`));
|
|
587
|
+
yield* waitForConversationUpdatedNotification(participant, fixture.conversationId, updatedName, CONVERSATION_LIFECYCLE_PROPERTY);
|
|
587
588
|
const archive = yield* archiveConversation(fixture.owner, fixture.conversationId).pipe(Effect.either);
|
|
588
|
-
|
|
589
|
-
return yield* Effect.fail(violation(CONVERSATION_LIFECYCLE_PROPERTY, `archive failed: ${archive.left._tag}`));
|
|
590
|
-
}
|
|
589
|
+
yield* requireRight(archive, (error) => violation(CONVERSATION_LIFECYCLE_PROPERTY, `archive failed: ${error._tag}`));
|
|
591
590
|
yield* waitForArchivedEvent(participant, fixture.conversationId, fixture.owner.agent.agentId, CONVERSATION_LIFECYCLE_PROPERTY);
|
|
592
591
|
yield* assertConversationRejectsMessages(participant, fixture.conversationId, CONVERSATION_LIFECYCLE_PROPERTY);
|
|
593
592
|
const unarchive = yield* unarchiveConversation(fixture.owner, fixture.conversationId).pipe(Effect.either);
|
|
594
|
-
|
|
595
|
-
return yield* Effect.fail(violation(CONVERSATION_LIFECYCLE_PROPERTY, `unarchive failed: ${unarchive.left._tag}`));
|
|
596
|
-
}
|
|
593
|
+
yield* requireRight(unarchive, (error) => violation(CONVERSATION_LIFECYCLE_PROPERTY, `unarchive failed: ${error._tag}`));
|
|
597
594
|
yield* waitForUnarchivedEvent(participant, fixture.conversationId, fixture.owner.agent.agentId, CONVERSATION_LIFECYCLE_PROPERTY);
|
|
598
595
|
const resumedSend = yield* sendText(participant, fixture.conversationId, "lifecycle-after-unarchive").pipe(Effect.either);
|
|
599
|
-
|
|
600
|
-
return yield* Effect.fail(violation(CONVERSATION_LIFECYCLE_PROPERTY, `messages/send failed after unarchive: ${resumedSend.left._tag}`));
|
|
601
|
-
}
|
|
596
|
+
yield* requireRight(resumedSend, (error) => violation(CONVERSATION_LIFECYCLE_PROPERTY, `messages/send failed after unarchive: ${error._tag}`));
|
|
602
597
|
})));
|
|
603
598
|
}
|
|
604
599
|
/**
|
|
@@ -610,16 +605,14 @@ export function registerAppSessionCloseLifecycle(ctx) {
|
|
|
610
605
|
registerProperty(ctx, CATEGORY, APP_SESSION_CLOSE_LIFECYCLE_PROPERTY, "apps/closeSession archives app conversations and broadcasts session close", Effect.scoped(Effect.gen(function* () {
|
|
611
606
|
const fixture = yield* acquireAppSessionCloseFixture(ctx);
|
|
612
607
|
const close = yield* fixture.initiator.client
|
|
613
|
-
.sendRpc(AppsCloseSession
|
|
608
|
+
.sendRpc(AppsCloseSession, { sessionId: fixture.sessionId })
|
|
614
609
|
.pipe(Effect.either);
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
if (close.right.closed !== true) {
|
|
619
|
-
return yield* Effect.fail(violation(APP_SESSION_CLOSE_LIFECYCLE_PROPERTY, `apps/closeSession returned unexpected result: ${JSON.stringify(close.right)}`));
|
|
610
|
+
const closeResult = yield* requireRight(close, (error) => violation(APP_SESSION_CLOSE_LIFECYCLE_PROPERTY, `apps/closeSession failed: ${error._tag}`));
|
|
611
|
+
if (closeResult.closed !== true) {
|
|
612
|
+
return yield* Effect.fail(violation(APP_SESSION_CLOSE_LIFECYCLE_PROPERTY, `apps/closeSession returned unexpected result: ${JSON.stringify(closeResult)}`));
|
|
620
613
|
}
|
|
621
614
|
yield* waitForArchivedEvent(fixture.invitee, fixture.conversationId, fixture.initiator.agent.agentId, APP_SESSION_CLOSE_LIFECYCLE_PROPERTY);
|
|
622
|
-
yield*
|
|
615
|
+
yield* waitForAppSessionClosedNotification(fixture.invitee, fixture.sessionId, fixture.initiator.agent.agentId, APP_SESSION_CLOSE_LIFECYCLE_PROPERTY);
|
|
623
616
|
yield* assertConversationRejectsMessages(fixture.initiator, fixture.conversationId, APP_SESSION_CLOSE_LIFECYCLE_PROPERTY);
|
|
624
617
|
})));
|
|
625
618
|
}
|
|
@@ -636,20 +629,14 @@ export function registerArchiveLifecycle(ctx) {
|
|
|
636
629
|
const fixture = yield* acquirePropertyConversation(ctx, ARCHIVE_LIFECYCLE_PROPERTY, "arch");
|
|
637
630
|
const participant = yield* firstParticipant(fixture, ARCHIVE_LIFECYCLE_PROPERTY);
|
|
638
631
|
const archive = yield* archiveConversation(fixture.owner, fixture.conversationId).pipe(Effect.either);
|
|
639
|
-
|
|
640
|
-
return yield* Effect.fail(violation(ARCHIVE_LIFECYCLE_PROPERTY, `archive failed: ${archive.left._tag}`));
|
|
641
|
-
}
|
|
632
|
+
yield* requireRight(archive, (error) => violation(ARCHIVE_LIFECYCLE_PROPERTY, `archive failed: ${error._tag}`));
|
|
642
633
|
yield* waitForArchivedEvent(participant, fixture.conversationId, fixture.owner.agent.agentId, ARCHIVE_LIFECYCLE_PROPERTY);
|
|
643
634
|
yield* assertConversationRejectsMessages(participant, fixture.conversationId, ARCHIVE_LIFECYCLE_PROPERTY);
|
|
644
635
|
const unarchive = yield* unarchiveConversation(fixture.owner, fixture.conversationId).pipe(Effect.either);
|
|
645
|
-
|
|
646
|
-
return yield* Effect.fail(violation(ARCHIVE_LIFECYCLE_PROPERTY, `unarchive failed: ${unarchive.left._tag}`));
|
|
647
|
-
}
|
|
636
|
+
yield* requireRight(unarchive, (error) => violation(ARCHIVE_LIFECYCLE_PROPERTY, `unarchive failed: ${error._tag}`));
|
|
648
637
|
yield* waitForUnarchivedEvent(participant, fixture.conversationId, fixture.owner.agent.agentId, ARCHIVE_LIFECYCLE_PROPERTY);
|
|
649
638
|
const resumedSend = yield* sendText(participant, fixture.conversationId, "must-succeed-after-unarchive").pipe(Effect.either);
|
|
650
|
-
|
|
651
|
-
return yield* Effect.fail(violation(ARCHIVE_LIFECYCLE_PROPERTY, `messages/send failed after unarchive: ${resumedSend.left._tag}`));
|
|
652
|
-
}
|
|
639
|
+
yield* requireRight(resumedSend, (error) => violation(ARCHIVE_LIFECYCLE_PROPERTY, `messages/send failed after unarchive: ${error._tag}`));
|
|
653
640
|
})));
|
|
654
641
|
}
|
|
655
642
|
//# sourceMappingURL=delivery.js.map
|