@moltzap/protocol 2026.401.0 → 2026.425.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/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/rpc-registry.d.ts +446 -0
- package/dist/rpc-registry.d.ts.map +1 -0
- package/dist/rpc-registry.js +67 -0
- package/dist/rpc-registry.js.map +1 -0
- package/dist/rpc.d.ts +42 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +29 -0
- package/dist/rpc.js.map +1 -0
- package/dist/schema/apps.d.ts +86 -0
- package/dist/schema/apps.d.ts.map +1 -0
- package/dist/schema/apps.js +77 -0
- package/dist/schema/apps.js.map +1 -0
- package/dist/schema/contacts.d.ts +8 -14
- package/dist/schema/contacts.d.ts.map +1 -1
- package/dist/schema/contacts.js +9 -15
- package/dist/schema/contacts.js.map +1 -1
- package/dist/schema/conversations.d.ts +15 -8
- package/dist/schema/conversations.d.ts.map +1 -1
- package/dist/schema/conversations.js +18 -7
- package/dist/schema/conversations.js.map +1 -1
- package/dist/schema/delivery.d.ts +1 -4
- package/dist/schema/delivery.d.ts.map +1 -1
- package/dist/schema/delivery.js +2 -3
- package/dist/schema/delivery.js.map +1 -1
- package/dist/schema/errors.d.ts +13 -0
- package/dist/schema/errors.d.ts.map +1 -1
- package/dist/schema/errors.js +14 -0
- package/dist/schema/errors.js.map +1 -1
- package/dist/schema/events.d.ts +112 -85
- package/dist/schema/events.d.ts.map +1 -1
- package/dist/schema/events.js +84 -25
- package/dist/schema/events.js.map +1 -1
- package/dist/schema/identity.d.ts +26 -15
- package/dist/schema/identity.d.ts.map +1 -1
- package/dist/schema/identity.js +10 -14
- package/dist/schema/identity.js.map +1 -1
- package/dist/schema/index.d.ts +4 -2
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +4 -2
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/messages.d.ts +3 -7
- package/dist/schema/messages.d.ts.map +1 -1
- package/dist/schema/messages.js +4 -6
- package/dist/schema/messages.js.map +1 -1
- package/dist/schema/methods/apps.d.ts +123 -0
- package/dist/schema/methods/apps.d.ts.map +1 -0
- package/dist/schema/methods/apps.js +93 -0
- package/dist/schema/methods/apps.js.map +1 -0
- package/dist/schema/methods/auth.d.ts +110 -79
- package/dist/schema/methods/auth.d.ts.map +1 -1
- package/dist/schema/methods/auth.js +88 -91
- package/dist/schema/methods/auth.js.map +1 -1
- package/dist/schema/methods/contacts.d.ts +39 -66
- package/dist/schema/methods/contacts.d.ts.map +1 -1
- package/dist/schema/methods/contacts.js +35 -29
- package/dist/schema/methods/contacts.js.map +1 -1
- package/dist/schema/methods/conversations.d.ts +48 -52
- package/dist/schema/methods/conversations.d.ts.map +1 -1
- package/dist/schema/methods/conversations.js +89 -38
- package/dist/schema/methods/conversations.js.map +1 -1
- package/dist/schema/methods/invites.d.ts +1 -3
- package/dist/schema/methods/invites.d.ts.map +1 -1
- package/dist/schema/methods/invites.js +8 -1
- package/dist/schema/methods/invites.js.map +1 -1
- package/dist/schema/methods/messages.d.ts +12 -44
- package/dist/schema/methods/messages.d.ts.map +1 -1
- package/dist/schema/methods/messages.js +22 -28
- package/dist/schema/methods/messages.js.map +1 -1
- package/dist/schema/methods/presence.d.ts +7 -22
- package/dist/schema/methods/presence.d.ts.map +1 -1
- package/dist/schema/methods/presence.js +12 -6
- package/dist/schema/methods/presence.js.map +1 -1
- package/dist/schema/methods/push.d.ts +8 -6
- package/dist/schema/methods/push.d.ts.map +1 -1
- package/dist/schema/methods/push.js +20 -7
- package/dist/schema/methods/push.js.map +1 -1
- package/dist/schema/methods/system.d.ts +4 -0
- package/dist/schema/methods/system.d.ts.map +1 -0
- package/dist/schema/methods/system.js +11 -0
- package/dist/schema/methods/system.js.map +1 -0
- package/dist/schema/presence.d.ts +1 -12
- package/dist/schema/presence.d.ts.map +1 -1
- package/dist/schema/presence.js +2 -7
- package/dist/schema/presence.js.map +1 -1
- package/dist/schema/surfaces.d.ts +31 -25
- package/dist/schema/surfaces.d.ts.map +1 -1
- package/dist/schema/surfaces.js +40 -21
- package/dist/schema/surfaces.js.map +1 -1
- package/dist/testing/agent-registration.d.ts +49 -0
- package/dist/testing/agent-registration.d.ts.map +1 -0
- package/dist/testing/agent-registration.js +77 -0
- package/dist/testing/agent-registration.js.map +1 -0
- package/dist/testing/arbitraries/frames.d.ts +24 -0
- package/dist/testing/arbitraries/frames.d.ts.map +1 -0
- package/dist/testing/arbitraries/frames.js +36 -0
- package/dist/testing/arbitraries/frames.js.map +1 -0
- package/dist/testing/arbitraries/from-typebox.d.ts +37 -0
- package/dist/testing/arbitraries/from-typebox.d.ts.map +1 -0
- package/dist/testing/arbitraries/from-typebox.js +131 -0
- package/dist/testing/arbitraries/from-typebox.js.map +1 -0
- package/dist/testing/arbitraries/index.d.ts +4 -0
- package/dist/testing/arbitraries/index.d.ts.map +1 -0
- package/dist/testing/arbitraries/index.js +4 -0
- package/dist/testing/arbitraries/index.js.map +1 -0
- package/dist/testing/arbitraries/rpc.d.ts +66 -0
- package/dist/testing/arbitraries/rpc.d.ts.map +1 -0
- package/dist/testing/arbitraries/rpc.js +98 -0
- package/dist/testing/arbitraries/rpc.js.map +1 -0
- package/dist/testing/canonicalize.d.ts +38 -0
- package/dist/testing/canonicalize.d.ts.map +1 -0
- package/dist/testing/canonicalize.js +55 -0
- package/dist/testing/canonicalize.js.map +1 -0
- package/dist/testing/captures.d.ts +61 -0
- package/dist/testing/captures.d.ts.map +1 -0
- package/dist/testing/captures.js +99 -0
- package/dist/testing/captures.js.map +1 -0
- package/dist/testing/codec.d.ts +44 -0
- package/dist/testing/codec.d.ts.map +1 -0
- package/dist/testing/codec.js +170 -0
- package/dist/testing/codec.js.map +1 -0
- package/dist/testing/conformance/__divergence_proofs__/executable-proof-helpers.d.ts +6 -0
- package/dist/testing/conformance/__divergence_proofs__/executable-proof-helpers.d.ts.map +1 -0
- package/dist/testing/conformance/__divergence_proofs__/executable-proof-helpers.js +33 -0
- package/dist/testing/conformance/__divergence_proofs__/executable-proof-helpers.js.map +1 -0
- package/dist/testing/conformance/adversity.d.ts +36 -0
- package/dist/testing/conformance/adversity.d.ts.map +1 -0
- package/dist/testing/conformance/adversity.js +360 -0
- package/dist/testing/conformance/adversity.js.map +1 -0
- package/dist/testing/conformance/boundary.d.ts +56 -0
- package/dist/testing/conformance/boundary.d.ts.map +1 -0
- package/dist/testing/conformance/boundary.js +129 -0
- package/dist/testing/conformance/boundary.js.map +1 -0
- package/dist/testing/conformance/client/_fixtures.d.ts +71 -0
- package/dist/testing/conformance/client/_fixtures.d.ts.map +1 -0
- package/dist/testing/conformance/client/_fixtures.js +102 -0
- package/dist/testing/conformance/client/_fixtures.js.map +1 -0
- package/dist/testing/conformance/client/adversity.d.ts +39 -0
- package/dist/testing/conformance/client/adversity.d.ts.map +1 -0
- package/dist/testing/conformance/client/adversity.js +162 -0
- package/dist/testing/conformance/client/adversity.js.map +1 -0
- package/dist/testing/conformance/client/boundary.d.ts +12 -0
- package/dist/testing/conformance/client/boundary.d.ts.map +1 -0
- package/dist/testing/conformance/client/boundary.js +68 -0
- package/dist/testing/conformance/client/boundary.js.map +1 -0
- package/dist/testing/conformance/client/delivery.d.ts +38 -0
- package/dist/testing/conformance/client/delivery.d.ts.map +1 -0
- package/dist/testing/conformance/client/delivery.js +202 -0
- package/dist/testing/conformance/client/delivery.js.map +1 -0
- package/dist/testing/conformance/client/index.d.ts +16 -0
- package/dist/testing/conformance/client/index.d.ts.map +1 -0
- package/dist/testing/conformance/client/index.js +16 -0
- package/dist/testing/conformance/client/index.js.map +1 -0
- package/dist/testing/conformance/client/rpc-semantics.d.ts +26 -0
- package/dist/testing/conformance/client/rpc-semantics.d.ts.map +1 -0
- package/dist/testing/conformance/client/rpc-semantics.js +145 -0
- package/dist/testing/conformance/client/rpc-semantics.js.map +1 -0
- package/dist/testing/conformance/client/runner.d.ts +258 -0
- package/dist/testing/conformance/client/runner.d.ts.map +1 -0
- package/dist/testing/conformance/client/runner.js +228 -0
- package/dist/testing/conformance/client/runner.js.map +1 -0
- package/dist/testing/conformance/client/schema-conformance.d.ts +25 -0
- package/dist/testing/conformance/client/schema-conformance.d.ts.map +1 -0
- package/dist/testing/conformance/client/schema-conformance.js +123 -0
- package/dist/testing/conformance/client/schema-conformance.js.map +1 -0
- package/dist/testing/conformance/client/suite.d.ts +90 -0
- package/dist/testing/conformance/client/suite.d.ts.map +1 -0
- package/dist/testing/conformance/client/suite.js +209 -0
- package/dist/testing/conformance/client/suite.js.map +1 -0
- package/dist/testing/conformance/coverage-policy.d.ts +8 -0
- package/dist/testing/conformance/coverage-policy.d.ts.map +1 -0
- package/dist/testing/conformance/coverage-policy.js +10 -0
- package/dist/testing/conformance/coverage-policy.js.map +1 -0
- package/dist/testing/conformance/delivery.d.ts +40 -0
- package/dist/testing/conformance/delivery.d.ts.map +1 -0
- package/dist/testing/conformance/delivery.js +231 -0
- package/dist/testing/conformance/delivery.js.map +1 -0
- package/dist/testing/conformance/env.d.ts +3 -0
- package/dist/testing/conformance/env.d.ts.map +1 -0
- package/dist/testing/conformance/env.js +14 -0
- package/dist/testing/conformance/env.js.map +1 -0
- package/dist/testing/conformance/index.d.ts +10 -0
- package/dist/testing/conformance/index.d.ts.map +1 -0
- package/dist/testing/conformance/index.js +10 -0
- package/dist/testing/conformance/index.js.map +1 -0
- package/dist/testing/conformance/registry.d.ts +93 -0
- package/dist/testing/conformance/registry.d.ts.map +1 -0
- package/dist/testing/conformance/registry.js +62 -0
- package/dist/testing/conformance/registry.js.map +1 -0
- package/dist/testing/conformance/rpc-semantics.d.ts +67 -0
- package/dist/testing/conformance/rpc-semantics.d.ts.map +1 -0
- package/dist/testing/conformance/rpc-semantics.js +394 -0
- package/dist/testing/conformance/rpc-semantics.js.map +1 -0
- package/dist/testing/conformance/runner.d.ts +78 -0
- package/dist/testing/conformance/runner.d.ts.map +1 -0
- package/dist/testing/conformance/runner.js +65 -0
- package/dist/testing/conformance/runner.js.map +1 -0
- package/dist/testing/conformance/schema-conformance.d.ts +30 -0
- package/dist/testing/conformance/schema-conformance.d.ts.map +1 -0
- package/dist/testing/conformance/schema-conformance.js +229 -0
- package/dist/testing/conformance/schema-conformance.js.map +1 -0
- package/dist/testing/conformance/suite.d.ts +92 -0
- package/dist/testing/conformance/suite.d.ts.map +1 -0
- package/dist/testing/conformance/suite.js +233 -0
- package/dist/testing/conformance/suite.js.map +1 -0
- package/dist/testing/errors.d.ts +78 -0
- package/dist/testing/errors.d.ts.map +1 -0
- package/dist/testing/errors.js +34 -0
- package/dist/testing/errors.js.map +1 -0
- package/dist/testing/index.d.ts +25 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +37 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/models/dispatch.d.ts +61 -0
- package/dist/testing/models/dispatch.d.ts.map +1 -0
- package/dist/testing/models/dispatch.js +197 -0
- package/dist/testing/models/dispatch.js.map +1 -0
- package/dist/testing/models/index.d.ts +3 -0
- package/dist/testing/models/index.d.ts.map +1 -0
- package/dist/testing/models/index.js +3 -0
- package/dist/testing/models/index.js.map +1 -0
- package/dist/testing/models/state.d.ts +37 -0
- package/dist/testing/models/state.d.ts.map +1 -0
- package/dist/testing/models/state.js +14 -0
- package/dist/testing/models/state.js.map +1 -0
- package/dist/testing/test-client.d.ts +70 -0
- package/dist/testing/test-client.d.ts.map +1 -0
- package/dist/testing/test-client.js +266 -0
- package/dist/testing/test-client.js.map +1 -0
- package/dist/testing/test-server.d.ts +62 -0
- package/dist/testing/test-server.d.ts.map +1 -0
- package/dist/testing/test-server.js +134 -0
- package/dist/testing/test-server.js.map +1 -0
- package/dist/testing/toxics/client.d.ts +52 -0
- package/dist/testing/toxics/client.d.ts.map +1 -0
- package/dist/testing/toxics/client.js +120 -0
- package/dist/testing/toxics/client.js.map +1 -0
- package/dist/testing/toxics/defaults.d.ts +43 -0
- package/dist/testing/toxics/defaults.d.ts.map +1 -0
- package/dist/testing/toxics/defaults.js +9 -0
- package/dist/testing/toxics/defaults.js.map +1 -0
- package/dist/testing/toxics/index.d.ts +4 -0
- package/dist/testing/toxics/index.d.ts.map +1 -0
- package/dist/testing/toxics/index.js +4 -0
- package/dist/testing/toxics/index.js.map +1 -0
- package/dist/testing/toxics/profile.d.ts +69 -0
- package/dist/testing/toxics/profile.d.ts.map +1 -0
- package/dist/testing/toxics/profile.js +57 -0
- package/dist/testing/toxics/profile.js.map +1 -0
- package/dist/types.d.ts +7 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/dist/validators.d.ts +49 -174
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +77 -47
- package/dist/validators.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +18 -40
- package/dist/optional/contact-events.d.ts +0 -3
- package/dist/optional/contact-events.d.ts.map +0 -1
- package/dist/optional/contact-events.js +0 -5
- package/dist/optional/contact-events.js.map +0 -1
- package/dist/optional/contact-methods.d.ts +0 -5
- package/dist/optional/contact-methods.d.ts.map +0 -1
- package/dist/optional/contact-methods.js +0 -5
- package/dist/optional/contact-methods.js.map +0 -1
- package/dist/phone-hash.d.ts +0 -10
- package/dist/phone-hash.d.ts.map +0 -1
- package/dist/phone-hash.js +0 -17
- package/dist/phone-hash.js.map +0 -1
- package/dist/schema/methods/phone-contacts.d.ts +0 -26
- package/dist/schema/methods/phone-contacts.d.ts.map +0 -1
- package/dist/schema/methods/phone-contacts.js +0 -10
- package/dist/schema/methods/phone-contacts.js.map +0 -1
- package/dist/test-client.d.ts +0 -34
- package/dist/test-client.d.ts.map +0 -1
- package/dist/test-client.js +0 -176
- package/dist/test-client.js.map +0 -1
- package/dist/test-fixtures/phone-hashes.d.ts +0 -18
- package/dist/test-fixtures/phone-hashes.d.ts.map +0 -1
- package/dist/test-fixtures/phone-hashes.js +0 -24
- package/dist/test-fixtures/phone-hashes.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-conformance.js","sourceRoot":"","sources":["../../../../src/testing/conformance/client/schema-conformance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side conformance suite entry point.
|
|
3
|
+
*
|
|
4
|
+
* O4 decision: **option (c) — one library, both factories optional.**
|
|
5
|
+
* The architect's target surface is the existing `runConformanceSuite(opts)`
|
|
6
|
+
* extended with a `realClient?` field alongside `realServer?`. The suite
|
|
7
|
+
* registers every server-side property when `realServer` is present and
|
|
8
|
+
* every client-side property when `realClient` is present. A caller that
|
|
9
|
+
* passes both gets the joint run for free; a caller that passes neither
|
|
10
|
+
* fails at option-decode time.
|
|
11
|
+
*
|
|
12
|
+
* This module ships the **client-only** entry — `runClientConformanceSuite`
|
|
13
|
+
* — as the stub the implementer wires in. When `implement-staff` lands the
|
|
14
|
+
* body it folds this into a single extended `runConformanceSuite` whose
|
|
15
|
+
* signature is declared in §Interfaces of the design doc. The stub exists
|
|
16
|
+
* so consumers and CI wiring have a stable symbol to import against while
|
|
17
|
+
* the merge lands.
|
|
18
|
+
*
|
|
19
|
+
* Scope: dependency on `packages/client` or either channel package is
|
|
20
|
+
* forbidden (extends AC13 to AC14). The factory injection pattern keeps
|
|
21
|
+
* the protocol package leaf-of-the-graph.
|
|
22
|
+
*/
|
|
23
|
+
import { Effect, type Scope } from "effect";
|
|
24
|
+
import type { ClientConformanceRunContext, RealClientHandle, RealClientLifecycleError } from "./runner.js";
|
|
25
|
+
import type { RealServerAcquireError, ToxicControlError } from "../../errors.js";
|
|
26
|
+
import type { SuiteResult } from "../suite.js";
|
|
27
|
+
/**
|
|
28
|
+
* Consumer-facing options. Mirror of `ConformanceSuiteOptions` on the
|
|
29
|
+
* server side; only the factory name differs.
|
|
30
|
+
*/
|
|
31
|
+
export interface ClientConformanceSuiteOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Factory for the real MoltZap client under test, owned by the
|
|
34
|
+
* suite's Scope. Receives `testServerUrl` from the suite so the real
|
|
35
|
+
* client can point its WS socket at the bound TestServer substrate.
|
|
36
|
+
*/
|
|
37
|
+
readonly realClient: (args: {
|
|
38
|
+
readonly testServerUrl: string;
|
|
39
|
+
}) => Effect.Effect<RealClientHandle, RealClientLifecycleError, Scope.Scope>;
|
|
40
|
+
/**
|
|
41
|
+
* Toxiproxy control-plane URL. When `null`, adversity properties are
|
|
42
|
+
* registered and surface `PropertyUnavailable`. Mirrors server-side
|
|
43
|
+
* behavior.
|
|
44
|
+
*/
|
|
45
|
+
readonly toxiproxyUrl?: string | null;
|
|
46
|
+
readonly replaySeed?: number;
|
|
47
|
+
readonly numRuns?: number;
|
|
48
|
+
readonly artifactDir?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Default `true`. When `true`, TestServer binds behind Toxiproxy so
|
|
51
|
+
* adversity toxics shape the wire between TestServer and the real
|
|
52
|
+
* client. Set to `false` only for debugging.
|
|
53
|
+
*/
|
|
54
|
+
readonly bindThroughToxiproxy?: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Register every client-side property (A2, A4, B1, B4, C1, C3, C4, D1,
|
|
58
|
+
* D3, D4, D5, D6, E2 — 13 total per spec amendment #200 §5) against
|
|
59
|
+
* `ctx`. Property files in `conformance/client/*.ts` each export one
|
|
60
|
+
* `registerXxxClient` per spec-amendment registrar; this helper is the
|
|
61
|
+
* single call site.
|
|
62
|
+
*/
|
|
63
|
+
export declare function registerAllClientProperties(ctx: ClientConformanceRunContext): void;
|
|
64
|
+
/**
|
|
65
|
+
* End-to-end client-side library entry. Acquires context, registers
|
|
66
|
+
* every client-side property, runs them, closes Scope. Returns a
|
|
67
|
+
* typed `SuiteResult` (reused from server-side — same failure shape).
|
|
68
|
+
*/
|
|
69
|
+
export declare function runClientConformanceSuite(opts: ClientConformanceSuiteOptions): Effect.Effect<SuiteResult, ToxicControlError | RealServerAcquireError | RealClientLifecycleError>;
|
|
70
|
+
/**
|
|
71
|
+
* Joint-run entry — passed both `realServer?` and `realClient?`.
|
|
72
|
+
* Architect target shape per O4 (c). Implementer folds this into
|
|
73
|
+
* `runConformanceSuite` in `../suite.ts` as an extension of
|
|
74
|
+
* `ConformanceSuiteOptions`; the stub declares the joint signature
|
|
75
|
+
* here so the design doc has a concrete symbol to trace.
|
|
76
|
+
*
|
|
77
|
+
* This signature is **not** the final exported surface — the merged
|
|
78
|
+
* `runConformanceSuite` in `../suite.ts` replaces it. Declared here
|
|
79
|
+
* for cold-read traceability only.
|
|
80
|
+
*/
|
|
81
|
+
export interface JointConformanceSuiteOptions {
|
|
82
|
+
readonly realServer?: ClientConformanceSuiteOptions["realClient"] extends never ? never : unknown;
|
|
83
|
+
readonly realClient?: ClientConformanceSuiteOptions["realClient"];
|
|
84
|
+
readonly toxiproxyUrl?: string | null;
|
|
85
|
+
readonly replaySeed?: number;
|
|
86
|
+
readonly numRuns?: number;
|
|
87
|
+
readonly artifactDir?: string;
|
|
88
|
+
readonly bindThroughToxiproxy?: boolean;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=suite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suite.d.ts","sourceRoot":"","sources":["../../../../src/testing/conformance/client/suite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAgB,MAAM,EAAgB,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AAIxE,OAAO,KAAK,EACV,2BAA2B,EAE3B,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,aAAa,CAAC;AAMrB,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA4B/C;;;GAGG;AACH,MAAM,WAAW,6BAA6B;IAC5C;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE;QAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;KAChC,KAAK,MAAM,CAAC,MAAM,CAAC,gBAAgB,EAAE,wBAAwB,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7E;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CACzC;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,2BAA2B,GAC/B,IAAI,CAcN;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,6BAA6B,GAClC,MAAM,CAAC,MAAM,CACd,WAAW,EACX,iBAAiB,GAAG,sBAAsB,GAAG,wBAAwB,CACtE,CA6BA;AA6KD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,6BAA6B,CAAC,YAAY,CAAC,SAAS,KAAK,GAC3E,KAAK,GACL,OAAO,CAAC;IACZ,QAAQ,CAAC,UAAU,CAAC,EAAE,6BAA6B,CAAC,YAAY,CAAC,CAAC;IAClE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CACzC"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side conformance suite entry point.
|
|
3
|
+
*
|
|
4
|
+
* O4 decision: **option (c) — one library, both factories optional.**
|
|
5
|
+
* The architect's target surface is the existing `runConformanceSuite(opts)`
|
|
6
|
+
* extended with a `realClient?` field alongside `realServer?`. The suite
|
|
7
|
+
* registers every server-side property when `realServer` is present and
|
|
8
|
+
* every client-side property when `realClient` is present. A caller that
|
|
9
|
+
* passes both gets the joint run for free; a caller that passes neither
|
|
10
|
+
* fails at option-decode time.
|
|
11
|
+
*
|
|
12
|
+
* This module ships the **client-only** entry — `runClientConformanceSuite`
|
|
13
|
+
* — as the stub the implementer wires in. When `implement-staff` lands the
|
|
14
|
+
* body it folds this into a single extended `runConformanceSuite` whose
|
|
15
|
+
* signature is declared in §Interfaces of the design doc. The stub exists
|
|
16
|
+
* so consumers and CI wiring have a stable symbol to import against while
|
|
17
|
+
* the merge lands.
|
|
18
|
+
*
|
|
19
|
+
* Scope: dependency on `packages/client` or either channel package is
|
|
20
|
+
* forbidden (extends AC13 to AC14). The factory injection pattern keeps
|
|
21
|
+
* the protocol package leaf-of-the-graph.
|
|
22
|
+
*/
|
|
23
|
+
import { Cause, Chunk, Effect, Exit, Option } from "effect";
|
|
24
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
25
|
+
import path from "node:path";
|
|
26
|
+
import { acquireClientRunContext } from "./runner.js";
|
|
27
|
+
import { collectProperties, } from "../registry.js";
|
|
28
|
+
import { conformanceArtifactDirFromEnv } from "../env.js";
|
|
29
|
+
import { isAllowedCoverageGap, } from "../coverage-policy.js";
|
|
30
|
+
import { registerEventWellFormednessClient, registerMalformedFrameHandlingClient, } from "./schema-conformance.js";
|
|
31
|
+
import { registerModelEquivalenceClient, registerRequestIdUniquenessClient, } from "./rpc-semantics.js";
|
|
32
|
+
import { registerFanOutCardinalityClient, registerPayloadOpacityClient, registerTaskBoundaryIsolationClient, } from "./delivery.js";
|
|
33
|
+
import { registerLatencyResilienceClient, registerResetPeerRecoveryClient, registerSlicerFramingClient, registerSlowCloseCleanupClient, registerTimeoutSurfaceClient, } from "./adversity.js";
|
|
34
|
+
import { registerSchemaExhaustiveFuzzClient } from "./boundary.js";
|
|
35
|
+
/**
|
|
36
|
+
* Register every client-side property (A2, A4, B1, B4, C1, C3, C4, D1,
|
|
37
|
+
* D3, D4, D5, D6, E2 — 13 total per spec amendment #200 §5) against
|
|
38
|
+
* `ctx`. Property files in `conformance/client/*.ts` each export one
|
|
39
|
+
* `registerXxxClient` per spec-amendment registrar; this helper is the
|
|
40
|
+
* single call site.
|
|
41
|
+
*/
|
|
42
|
+
export function registerAllClientProperties(ctx) {
|
|
43
|
+
registerEventWellFormednessClient(ctx);
|
|
44
|
+
registerMalformedFrameHandlingClient(ctx);
|
|
45
|
+
registerModelEquivalenceClient(ctx);
|
|
46
|
+
registerRequestIdUniquenessClient(ctx);
|
|
47
|
+
registerFanOutCardinalityClient(ctx);
|
|
48
|
+
registerPayloadOpacityClient(ctx);
|
|
49
|
+
registerTaskBoundaryIsolationClient(ctx);
|
|
50
|
+
registerSchemaExhaustiveFuzzClient(ctx);
|
|
51
|
+
registerLatencyResilienceClient(ctx);
|
|
52
|
+
registerSlicerFramingClient(ctx);
|
|
53
|
+
registerResetPeerRecoveryClient(ctx);
|
|
54
|
+
registerTimeoutSurfaceClient(ctx);
|
|
55
|
+
registerSlowCloseCleanupClient(ctx);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* End-to-end client-side library entry. Acquires context, registers
|
|
59
|
+
* every client-side property, runs them, closes Scope. Returns a
|
|
60
|
+
* typed `SuiteResult` (reused from server-side — same failure shape).
|
|
61
|
+
*/
|
|
62
|
+
export function runClientConformanceSuite(opts) {
|
|
63
|
+
const toxiproxyUrl = opts.toxiproxyUrl ?? null;
|
|
64
|
+
const artifactDir = opts.artifactDir ??
|
|
65
|
+
conformanceArtifactDirFromEnv() ??
|
|
66
|
+
path.resolve(process.cwd(), "conformance-artifacts");
|
|
67
|
+
const tiers = toxiproxyUrl === null ? ["A", "B", "C", "E"] : ["A", "B", "C", "D", "E"];
|
|
68
|
+
return Effect.scoped(Effect.gen(function* () {
|
|
69
|
+
const ctx = yield* acquireClientRunContext({
|
|
70
|
+
tiers,
|
|
71
|
+
realClient: opts.realClient,
|
|
72
|
+
toxiproxyUrl: toxiproxyUrl ?? undefined,
|
|
73
|
+
manageToxiproxy: false,
|
|
74
|
+
replaySeed: opts.replaySeed,
|
|
75
|
+
numRuns: opts.numRuns,
|
|
76
|
+
artifactDir,
|
|
77
|
+
bindThroughToxiproxy: opts.bindThroughToxiproxy,
|
|
78
|
+
});
|
|
79
|
+
registerAllClientProperties(ctx);
|
|
80
|
+
return yield* runAllClientProperties(ctx, artifactDir, allowedClientCoverageGaps(toxiproxyUrl));
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
function allowedClientCoverageGaps(toxiproxyUrl) {
|
|
84
|
+
const gaps = [
|
|
85
|
+
{
|
|
86
|
+
kind: "unavailable",
|
|
87
|
+
id: "adversity/slicer-framing-client",
|
|
88
|
+
reasonIncludes: "slicer toxic property deferred",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
kind: "unavailable",
|
|
92
|
+
id: "adversity/reset-peer-recovery-client",
|
|
93
|
+
reasonIncludes: "reset_peer property deferred",
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
if (toxiproxyUrl === null) {
|
|
97
|
+
gaps.push({
|
|
98
|
+
kind: "unavailable",
|
|
99
|
+
id: "adversity/latency-resilience-client",
|
|
100
|
+
reasonIncludes: "Toxiproxy not provisioned",
|
|
101
|
+
}, {
|
|
102
|
+
kind: "unavailable",
|
|
103
|
+
id: "adversity/slicer-framing-client",
|
|
104
|
+
reasonIncludes: "Toxiproxy not provisioned",
|
|
105
|
+
}, {
|
|
106
|
+
kind: "unavailable",
|
|
107
|
+
id: "adversity/reset-peer-recovery-client",
|
|
108
|
+
reasonIncludes: "Toxiproxy not provisioned",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return gaps;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Execute every registered client property and return a typed
|
|
115
|
+
* `SuiteResult`. Mirrors the server-side `runAllProperties` shape so
|
|
116
|
+
* downstream consumers share one assertion surface.
|
|
117
|
+
*/
|
|
118
|
+
function runAllClientProperties(ctx, artifactDir, allowedCoverageGaps) {
|
|
119
|
+
return Effect.gen(function* () {
|
|
120
|
+
if (!existsSync(artifactDir))
|
|
121
|
+
mkdirSync(artifactDir, { recursive: true });
|
|
122
|
+
const properties = collectProperties(ctx);
|
|
123
|
+
const passed = [];
|
|
124
|
+
const deferred = [];
|
|
125
|
+
const unavailable = [];
|
|
126
|
+
const failed = [];
|
|
127
|
+
for (const p of properties) {
|
|
128
|
+
const id = `${p.category}/${p.name}`;
|
|
129
|
+
const exit = yield* Effect.exit(p.run);
|
|
130
|
+
if (Exit.isSuccess(exit)) {
|
|
131
|
+
passed.push(id);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const failure = firstTypedFailure(exit);
|
|
135
|
+
if (failure === null) {
|
|
136
|
+
const msg = exit.cause.toString();
|
|
137
|
+
failed.push({ name: id, failure: { _tag: "defect", message: msg } });
|
|
138
|
+
writeArtifact(artifactDir, p, ctx.seed, { defect: msg });
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
switch (failure._tag) {
|
|
142
|
+
case "ConformancePropertyDeferred":
|
|
143
|
+
if (isAllowedCoverageGap(allowedCoverageGaps, "deferred", id, failure.followUp)) {
|
|
144
|
+
deferred.push({ name: id, reason: failure.followUp });
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
failed.push({ name: id, failure });
|
|
148
|
+
writeArtifact(artifactDir, p, ctx.seed, failureArtifact(failure));
|
|
149
|
+
break;
|
|
150
|
+
case "ConformancePropertyUnavailable":
|
|
151
|
+
if (isAllowedCoverageGap(allowedCoverageGaps, "unavailable", id, failure.reason)) {
|
|
152
|
+
unavailable.push({ name: id, reason: failure.reason });
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
failed.push({ name: id, failure });
|
|
156
|
+
writeArtifact(artifactDir, p, ctx.seed, failureArtifact(failure));
|
|
157
|
+
break;
|
|
158
|
+
case "ConformancePropertyAssertionFailure":
|
|
159
|
+
case "ConformancePropertyInvariantViolation":
|
|
160
|
+
failed.push({ name: id, failure });
|
|
161
|
+
writeArtifact(artifactDir, p, ctx.seed, failureArtifact(failure));
|
|
162
|
+
break;
|
|
163
|
+
default: {
|
|
164
|
+
const _exhaustive = failure;
|
|
165
|
+
failed.push({
|
|
166
|
+
name: id,
|
|
167
|
+
failure: {
|
|
168
|
+
_tag: "defect",
|
|
169
|
+
message: `unhandled failure tag: ${String(_exhaustive)}`,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return { seed: ctx.seed, passed, deferred, unavailable, failed };
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function firstTypedFailure(exit) {
|
|
179
|
+
if (Exit.isSuccess(exit))
|
|
180
|
+
return null;
|
|
181
|
+
const failures = Cause.failures(exit.cause);
|
|
182
|
+
const head = Chunk.head(failures);
|
|
183
|
+
return Option.getOrNull(head);
|
|
184
|
+
}
|
|
185
|
+
function failureArtifact(failure) {
|
|
186
|
+
switch (failure._tag) {
|
|
187
|
+
case "ConformancePropertyAssertionFailure":
|
|
188
|
+
return { tag: failure._tag, cause: String(failure.cause) };
|
|
189
|
+
case "ConformancePropertyInvariantViolation":
|
|
190
|
+
case "ConformancePropertyUnavailable":
|
|
191
|
+
return { tag: failure._tag, reason: failure.reason };
|
|
192
|
+
case "ConformancePropertyDeferred":
|
|
193
|
+
return { tag: failure._tag, followUp: failure.followUp };
|
|
194
|
+
default: {
|
|
195
|
+
const _exhaustive = failure;
|
|
196
|
+
return { tag: "unknown", value: String(_exhaustive) };
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function writeArtifact(dir, property, seed, payload) {
|
|
201
|
+
const file = path.join(dir, `client-${property.category}-${property.name}.seed.json`);
|
|
202
|
+
writeFileSync(file, JSON.stringify({
|
|
203
|
+
category: property.category,
|
|
204
|
+
name: property.name,
|
|
205
|
+
seed,
|
|
206
|
+
...payload,
|
|
207
|
+
}, null, 2));
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=suite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suite.js","sourceRoot":"","sources":["../../../../src/testing/conformance/client/suite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type CoverageGapKind = "deferred" | "unavailable";
|
|
2
|
+
export interface AllowedCoverageGap {
|
|
3
|
+
readonly kind: CoverageGapKind;
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly reasonIncludes?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function isAllowedCoverageGap(allowed: ReadonlyArray<AllowedCoverageGap>, kind: CoverageGapKind, id: string, reason: string): boolean;
|
|
8
|
+
//# sourceMappingURL=coverage-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage-policy.d.ts","sourceRoot":"","sources":["../../../src/testing/conformance/coverage-policy.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,aAAa,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,aAAa,CAAC,kBAAkB,CAAC,EAC1C,IAAI,EAAE,eAAe,EACrB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,GACb,OAAO,CAMT"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function isAllowedCoverageGap(allowed, kind, id, reason) {
|
|
2
|
+
return allowed.some((gap) => {
|
|
3
|
+
if (gap.kind !== kind || gap.id !== id)
|
|
4
|
+
return false;
|
|
5
|
+
if (gap.reasonIncludes === undefined)
|
|
6
|
+
return true;
|
|
7
|
+
return reason.includes(gap.reasonIncludes);
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=coverage-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage-policy.js","sourceRoot":"","sources":["../../../src/testing/conformance/coverage-policy.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,oBAAoB,CAClC,OAA0C,EAC1C,IAAqB,EACrB,EAAU,EACV,MAAc;IAEd,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QAC1B,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,KAAK,EAAE;YAAE,OAAO,KAAK,CAAC;QACrD,IAAI,GAAG,CAAC,cAAc,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QAClD,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ConformanceRunContext } from "./runner.js";
|
|
2
|
+
/**
|
|
3
|
+
* Fan-out cardinality — spec §5 C1: messages/send ⇒ **exactly** N
|
|
4
|
+
* inbound events (one per connection). Architect §4.4: tightened from
|
|
5
|
+
* `>=1` to `===1`; a server that duplicates events now fails.
|
|
6
|
+
*
|
|
7
|
+
* Empty-counts side channel replaced with an explicit
|
|
8
|
+
* `PropertyInvariantViolation`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function registerFanOutCardinality(ctx: ConformanceRunContext): void;
|
|
11
|
+
/**
|
|
12
|
+
* Store-and-replay — spec §5 C2: offline-then-reconnect delivers the
|
|
13
|
+
* messages sent during the disconnect window.
|
|
14
|
+
*
|
|
15
|
+
* **Status: architect §4.5 option (b) — property split.**
|
|
16
|
+
*
|
|
17
|
+
* Option (a) (reconnect via scope composition) was attempted and is
|
|
18
|
+
* infrastructure-viable: TestClient supports re-opening with the same
|
|
19
|
+
* apiKey/agentId via `Effect.scoped`, no new public primitive needed.
|
|
20
|
+
* However, the current server implementation does not buffer events
|
|
21
|
+
* for offline subscribers (empirical observation against
|
|
22
|
+
* `startCoreTestServer` at commit time): after reconnect, the
|
|
23
|
+
* participant's capture buffer contains zero of the N messages sent
|
|
24
|
+
* during the offline window. This is a server-side gap against spec
|
|
25
|
+
* §5 C2, not a TestClient gap.
|
|
26
|
+
*
|
|
27
|
+
* Per architect §4.5 option (b), this property is scoped to
|
|
28
|
+
* **basic-delivery-landing** — the weaker invariant that N messages
|
|
29
|
+
* sent to a live conversation land in every currently-subscribed
|
|
30
|
+
* participant's capture buffer. The full offline-replay assertion is
|
|
31
|
+
* tracked as a follow-up under epic #186. If/when the server
|
|
32
|
+
* implements C2 replay, flip this body back to the reconnect form
|
|
33
|
+
* from the git history and remove the #186 pointer.
|
|
34
|
+
*/
|
|
35
|
+
export declare function registerStoreAndReplay(ctx: ConformanceRunContext): void;
|
|
36
|
+
/** Payload opacity — sent text appears byte-for-byte in delivered events. */
|
|
37
|
+
export declare function registerPayloadOpacity(ctx: ConformanceRunContext): void;
|
|
38
|
+
/** Task-boundary isolation — conversation A's events don't leak into B. */
|
|
39
|
+
export declare function registerTaskBoundaryIsolation(ctx: ConformanceRunContext): void;
|
|
40
|
+
//# sourceMappingURL=delivery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../../../src/testing/conformance/delivery.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAsFzD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,qBAAqB,GAAG,IAAI,CAuD1E;AAMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,qBAAqB,GAAG,IAAI,CA0DvE;AAED,6EAA6E;AAC7E,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,qBAAqB,GAAG,IAAI,CAgDvE;AAED,2EAA2E;AAC3E,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,qBAAqB,GACzB,IAAI,CAqDN"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delivery — properties that exercise multi-connection invariants
|
|
3
|
+
* against the real server: fan-out cardinality, store-and-replay,
|
|
4
|
+
* payload opacity, and task-boundary isolation.
|
|
5
|
+
*
|
|
6
|
+
* Historical grouping note: spec #181 §5 calls this "Tier C". Code uses
|
|
7
|
+
* semantic names only.
|
|
8
|
+
*
|
|
9
|
+
* Principle 3: every property body is `Effect<void, PropertyFailure>`.
|
|
10
|
+
*/
|
|
11
|
+
import * as fc from "fast-check";
|
|
12
|
+
import { Effect } from "effect";
|
|
13
|
+
import { makeTestClient } from "../test-client.js";
|
|
14
|
+
import { registerTestAgent } from "../agent-registration.js";
|
|
15
|
+
import { PropertyInvariantViolation, assertProperty, registerProperty, } from "./registry.js";
|
|
16
|
+
const CATEGORY = "delivery";
|
|
17
|
+
const DEFAULT_TIMEOUT_MS = 5000;
|
|
18
|
+
const DEFAULT_CAPTURE_CAPACITY = 256;
|
|
19
|
+
const MAX_N = 4;
|
|
20
|
+
function acquireClient(ctx, name) {
|
|
21
|
+
return Effect.gen(function* () {
|
|
22
|
+
const agent = yield* registerTestAgent({
|
|
23
|
+
baseUrl: ctx.realServer.baseUrl,
|
|
24
|
+
name,
|
|
25
|
+
}).pipe(Effect.mapError((e) => `register(${name}): ${e.body}`));
|
|
26
|
+
const client = yield* makeTestClient({
|
|
27
|
+
serverUrl: ctx.realServer.wsUrl,
|
|
28
|
+
agentKey: agent.apiKey,
|
|
29
|
+
agentId: agent.agentId,
|
|
30
|
+
defaultTimeoutMs: DEFAULT_TIMEOUT_MS,
|
|
31
|
+
captureCapacity: DEFAULT_CAPTURE_CAPACITY,
|
|
32
|
+
}).pipe(Effect.mapError((e) => `makeTestClient(${name}): ${String(e)}`));
|
|
33
|
+
return { agent, client };
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function acquireConversation(ctx, n, namePrefix) {
|
|
37
|
+
const clamped = Math.min(Math.max(1, n), MAX_N);
|
|
38
|
+
return Effect.gen(function* () {
|
|
39
|
+
const owner = yield* acquireClient(ctx, `${namePrefix}-owner`);
|
|
40
|
+
const participants = yield* Effect.forEach(Array.from({ length: clamped }, (_, i) => i), (i) => acquireClient(ctx, `${namePrefix}-p${i}`), { concurrency: clamped });
|
|
41
|
+
const createResult = yield* owner.client
|
|
42
|
+
.sendRpc("conversations/create", {
|
|
43
|
+
type: "group",
|
|
44
|
+
name: `${namePrefix}-conv`,
|
|
45
|
+
participants: participants.map((p) => ({
|
|
46
|
+
type: "agent",
|
|
47
|
+
id: p.agent.agentId,
|
|
48
|
+
})),
|
|
49
|
+
})
|
|
50
|
+
.pipe(Effect.either);
|
|
51
|
+
if (createResult._tag === "Left") {
|
|
52
|
+
return yield* Effect.fail(`conversations/create failed: ${createResult.left._tag}`);
|
|
53
|
+
}
|
|
54
|
+
const created = createResult.right;
|
|
55
|
+
const conversationId = created.conversation?.id;
|
|
56
|
+
if (typeof conversationId !== "string" || conversationId.length === 0) {
|
|
57
|
+
return yield* Effect.fail(`conversations/create returned no conversation.id`);
|
|
58
|
+
}
|
|
59
|
+
return { owner, participants, conversationId };
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Fan-out cardinality — spec §5 C1: messages/send ⇒ **exactly** N
|
|
64
|
+
* inbound events (one per connection). Architect §4.4: tightened from
|
|
65
|
+
* `>=1` to `===1`; a server that duplicates events now fails.
|
|
66
|
+
*
|
|
67
|
+
* Empty-counts side channel replaced with an explicit
|
|
68
|
+
* `PropertyInvariantViolation`.
|
|
69
|
+
*/
|
|
70
|
+
export function registerFanOutCardinality(ctx) {
|
|
71
|
+
registerProperty(ctx, CATEGORY, "fan-out-cardinality", "messages/send ⇒ exactly N inbound message events (one per connection)", assertProperty(CATEGORY, "fan-out-cardinality", () => fc.assert(
|
|
72
|
+
// #ignore-sloppy-code-next-line[async-keyword]: fast-check asyncProperty contract requires Promise-returning callback
|
|
73
|
+
fc.asyncProperty(fc.integer({ min: 2, max: 3 }), async (n) => {
|
|
74
|
+
const result = await Effect.runPromise(Effect.scoped(Effect.gen(function* () {
|
|
75
|
+
const fixture = yield* acquireConversation(ctx, n, "fan").pipe(Effect.mapError((e) => new Error(e)));
|
|
76
|
+
const send = yield* fixture.owner.client
|
|
77
|
+
.sendRpc("messages/send", {
|
|
78
|
+
conversationId: fixture.conversationId,
|
|
79
|
+
parts: [{ type: "text", text: "fan-out-ping" }],
|
|
80
|
+
})
|
|
81
|
+
.pipe(Effect.either);
|
|
82
|
+
if (send._tag === "Left") {
|
|
83
|
+
return { kind: "send-failed" };
|
|
84
|
+
}
|
|
85
|
+
yield* Effect.sleep("250 millis");
|
|
86
|
+
const observed = yield* Effect.forEach(fixture.participants, (p) => p.client.snapshot);
|
|
87
|
+
const counts = observed.map((snap) => snap.filter((s) => s.kind === "inbound" &&
|
|
88
|
+
s.frame?.type === "event" &&
|
|
89
|
+
typeof s.frame.event === "string" &&
|
|
90
|
+
s.frame.event.includes("message")).length);
|
|
91
|
+
return { kind: "ok", counts };
|
|
92
|
+
})));
|
|
93
|
+
if (result.kind !== "ok")
|
|
94
|
+
return false;
|
|
95
|
+
// Exact-cardinality predicate. Duplicates and drops both fail.
|
|
96
|
+
return (result.counts.length === fixture_n(n) &&
|
|
97
|
+
result.counts.every((c) => c === 1));
|
|
98
|
+
}), { seed: ctx.seed, numRuns: ctx.opts.numRuns ?? 3 })));
|
|
99
|
+
}
|
|
100
|
+
function fixture_n(requested) {
|
|
101
|
+
return Math.min(Math.max(1, requested), MAX_N);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Store-and-replay — spec §5 C2: offline-then-reconnect delivers the
|
|
105
|
+
* messages sent during the disconnect window.
|
|
106
|
+
*
|
|
107
|
+
* **Status: architect §4.5 option (b) — property split.**
|
|
108
|
+
*
|
|
109
|
+
* Option (a) (reconnect via scope composition) was attempted and is
|
|
110
|
+
* infrastructure-viable: TestClient supports re-opening with the same
|
|
111
|
+
* apiKey/agentId via `Effect.scoped`, no new public primitive needed.
|
|
112
|
+
* However, the current server implementation does not buffer events
|
|
113
|
+
* for offline subscribers (empirical observation against
|
|
114
|
+
* `startCoreTestServer` at commit time): after reconnect, the
|
|
115
|
+
* participant's capture buffer contains zero of the N messages sent
|
|
116
|
+
* during the offline window. This is a server-side gap against spec
|
|
117
|
+
* §5 C2, not a TestClient gap.
|
|
118
|
+
*
|
|
119
|
+
* Per architect §4.5 option (b), this property is scoped to
|
|
120
|
+
* **basic-delivery-landing** — the weaker invariant that N messages
|
|
121
|
+
* sent to a live conversation land in every currently-subscribed
|
|
122
|
+
* participant's capture buffer. The full offline-replay assertion is
|
|
123
|
+
* tracked as a follow-up under epic #186. If/when the server
|
|
124
|
+
* implements C2 replay, flip this body back to the reconnect form
|
|
125
|
+
* from the git history and remove the #186 pointer.
|
|
126
|
+
*/
|
|
127
|
+
export function registerStoreAndReplay(ctx) {
|
|
128
|
+
registerProperty(ctx, CATEGORY, "store-and-replay", "every messages/send lands in a live participant's capture buffer (basic-delivery-landing; #186 tracks C2 offline-replay)", Effect.scoped(Effect.gen(function* () {
|
|
129
|
+
const fixture = yield* acquireConversation(ctx, 1, "sr").pipe(Effect.mapError((e) => new PropertyInvariantViolation({
|
|
130
|
+
category: CATEGORY,
|
|
131
|
+
name: "store-and-replay",
|
|
132
|
+
reason: `fixture: ${e}`,
|
|
133
|
+
})));
|
|
134
|
+
const participant = fixture.participants[0];
|
|
135
|
+
if (participant === undefined) {
|
|
136
|
+
return yield* Effect.fail(new PropertyInvariantViolation({
|
|
137
|
+
category: CATEGORY,
|
|
138
|
+
name: "store-and-replay",
|
|
139
|
+
reason: "fixture missing participant",
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
142
|
+
const sent = 3;
|
|
143
|
+
for (let i = 0; i < sent; i++) {
|
|
144
|
+
yield* fixture.owner.client
|
|
145
|
+
.sendRpc("messages/send", {
|
|
146
|
+
conversationId: fixture.conversationId,
|
|
147
|
+
parts: [{ type: "text", text: `sr-${i}` }],
|
|
148
|
+
})
|
|
149
|
+
.pipe(Effect.either);
|
|
150
|
+
}
|
|
151
|
+
yield* Effect.sleep("350 millis");
|
|
152
|
+
const snap = yield* participant.client.snapshot;
|
|
153
|
+
const delivered = snap.filter((s) => s.kind === "inbound" &&
|
|
154
|
+
s.frame?.type === "event" &&
|
|
155
|
+
typeof s.frame.event === "string" &&
|
|
156
|
+
s.frame.event.includes("message")).length;
|
|
157
|
+
if (delivered < sent) {
|
|
158
|
+
return yield* Effect.fail(new PropertyInvariantViolation({
|
|
159
|
+
category: CATEGORY,
|
|
160
|
+
name: "store-and-replay",
|
|
161
|
+
reason: `sent ${sent}, live participant observed ${delivered}`,
|
|
162
|
+
}));
|
|
163
|
+
}
|
|
164
|
+
})));
|
|
165
|
+
}
|
|
166
|
+
/** Payload opacity — sent text appears byte-for-byte in delivered events. */
|
|
167
|
+
export function registerPayloadOpacity(ctx) {
|
|
168
|
+
registerProperty(ctx, CATEGORY, "payload-opacity", "sent message text appears verbatim in delivered event bytes", assertProperty(CATEGORY, "payload-opacity", () => fc.assert(
|
|
169
|
+
// #ignore-sloppy-code-next-line[async-keyword]: fast-check asyncProperty contract requires Promise-returning callback
|
|
170
|
+
fc.asyncProperty(
|
|
171
|
+
// Exclude JSON-meta chars so a simple substring match is valid.
|
|
172
|
+
fc
|
|
173
|
+
.string({ minLength: 4, maxLength: 24 })
|
|
174
|
+
.filter((s) => !/[\\" \n\r\t]/.test(s)),
|
|
175
|
+
// #ignore-sloppy-code-next-line[async-keyword]: fast-check asyncProperty contract requires Promise-returning callback
|
|
176
|
+
async (text) => {
|
|
177
|
+
const found = await Effect.runPromise(Effect.scoped(Effect.gen(function* () {
|
|
178
|
+
const fixture = yield* acquireConversation(ctx, 1, "po").pipe(Effect.mapError((e) => new Error(e)));
|
|
179
|
+
const participant = fixture.participants[0];
|
|
180
|
+
if (participant === undefined)
|
|
181
|
+
return false;
|
|
182
|
+
yield* fixture.owner.client
|
|
183
|
+
.sendRpc("messages/send", {
|
|
184
|
+
conversationId: fixture.conversationId,
|
|
185
|
+
parts: [{ type: "text", text }],
|
|
186
|
+
})
|
|
187
|
+
.pipe(Effect.either);
|
|
188
|
+
yield* Effect.sleep("250 millis");
|
|
189
|
+
const snap = yield* participant.client.snapshot;
|
|
190
|
+
return snap.some((s) => s.kind === "inbound" &&
|
|
191
|
+
s.frame?.type === "event" &&
|
|
192
|
+
s.raw.includes(text));
|
|
193
|
+
}))).catch(() => false);
|
|
194
|
+
return found;
|
|
195
|
+
}), { seed: ctx.seed, numRuns: ctx.opts.numRuns ?? 3 })));
|
|
196
|
+
}
|
|
197
|
+
/** Task-boundary isolation — conversation A's events don't leak into B. */
|
|
198
|
+
export function registerTaskBoundaryIsolation(ctx) {
|
|
199
|
+
registerProperty(ctx, CATEGORY, "task-boundary-isolation", "participants in conversation B observe zero leaks from conversation A", Effect.scoped(Effect.gen(function* () {
|
|
200
|
+
const fxA = yield* acquireConversation(ctx, 1, "iso-a").pipe(Effect.mapError((e) => new PropertyInvariantViolation({
|
|
201
|
+
category: CATEGORY,
|
|
202
|
+
name: "task-boundary-isolation",
|
|
203
|
+
reason: `fixture A: ${e}`,
|
|
204
|
+
})));
|
|
205
|
+
const fxB = yield* acquireConversation(ctx, 1, "iso-b").pipe(Effect.mapError((e) => new PropertyInvariantViolation({
|
|
206
|
+
category: CATEGORY,
|
|
207
|
+
name: "task-boundary-isolation",
|
|
208
|
+
reason: `fixture B: ${e}`,
|
|
209
|
+
})));
|
|
210
|
+
yield* fxA.owner.client
|
|
211
|
+
.sendRpc("messages/send", {
|
|
212
|
+
conversationId: fxA.conversationId,
|
|
213
|
+
parts: [{ type: "text", text: "iso-leak-canary" }],
|
|
214
|
+
})
|
|
215
|
+
.pipe(Effect.either);
|
|
216
|
+
yield* Effect.sleep("250 millis");
|
|
217
|
+
const outsider = fxB.participants[0];
|
|
218
|
+
if (outsider === undefined)
|
|
219
|
+
return;
|
|
220
|
+
const snap = yield* outsider.client.snapshot;
|
|
221
|
+
const leaked = snap.some((s) => s.kind === "inbound" && s.raw.includes(fxA.conversationId));
|
|
222
|
+
if (leaked) {
|
|
223
|
+
return yield* Effect.fail(new PropertyInvariantViolation({
|
|
224
|
+
category: CATEGORY,
|
|
225
|
+
name: "task-boundary-isolation",
|
|
226
|
+
reason: `conversation ${fxA.conversationId} leaked into outsider ${outsider.agent.agentId}`,
|
|
227
|
+
}));
|
|
228
|
+
}
|
|
229
|
+
})));
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=delivery.js.map
|