@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,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-`RpcMethodName` arbitrary and the `allRpcMethods` walker.
|
|
3
|
+
*
|
|
4
|
+
* Tier A's A5 (RpcMap coverage) and Tier B's B1 (model equivalence) both
|
|
5
|
+
* iterate every method name. Centralizing the iterator here keeps the
|
|
6
|
+
* property bodies compiler-checked against `RpcMap`.
|
|
7
|
+
*/
|
|
8
|
+
import * as fc from "fast-check";
|
|
9
|
+
import { type RpcMap, type RpcMethodName } from "../../rpc-registry.js";
|
|
10
|
+
/**
|
|
11
|
+
* A single drawn RPC invocation: the method name carries through to the
|
|
12
|
+
* reference model so it can pick the matching reducer.
|
|
13
|
+
*/
|
|
14
|
+
export interface ArbitraryRpcCall<M extends RpcMethodName = RpcMethodName> {
|
|
15
|
+
readonly method: M;
|
|
16
|
+
readonly params: RpcMap[M]["params"];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Ordered list of every `RpcMethodName`. Exposed so properties can assert
|
|
20
|
+
* "every method exercised at least once" without going through `RpcMap`
|
|
21
|
+
* directly.
|
|
22
|
+
*/
|
|
23
|
+
export declare const allRpcMethods: ReadonlyArray<RpcMethodName>;
|
|
24
|
+
/** Arbitrary of a valid params tree for a single, fixed RPC. */
|
|
25
|
+
export declare function arbitraryCallFor<M extends RpcMethodName>(method: M): fc.Arbitrary<ArbitraryRpcCall<M>>;
|
|
26
|
+
/**
|
|
27
|
+
* Arbitrary that draws any method name + matching params. Used by Tier A
|
|
28
|
+
* A5 and by Tier E E2's cross-RPC fuzz.
|
|
29
|
+
*/
|
|
30
|
+
export declare function arbitraryAnyCall(): fc.Arbitrary<ArbitraryRpcCall>;
|
|
31
|
+
/**
|
|
32
|
+
* The set of `RpcMethodName`s the reference model predicts `_tag: "ok"`
|
|
33
|
+
* for on `initialReferenceState` — derived mechanically at module load
|
|
34
|
+
* by probing `applyCall` with a single drawn params value per method.
|
|
35
|
+
*
|
|
36
|
+
* Per architect #197 §2.2: this is NOT a hand-curated list. Methods
|
|
37
|
+
* move in/out of the confident set automatically when `applyCall`'s
|
|
38
|
+
* `allowNoEvents` / `uncertainError` split moves, so the sampling
|
|
39
|
+
* distribution tracks the model.
|
|
40
|
+
*
|
|
41
|
+
* **Param-invariance contract:** every kept method is treated as
|
|
42
|
+
* oracle-confident for every params value. If a future `applyCall`
|
|
43
|
+
* amendment branches on `call.params`, the safety-net guard in
|
|
44
|
+
* `registerModelEquivalence` (rpc-semantics.ts) fires loudly on the
|
|
45
|
+
* first non-confident draw and the derivation must widen from the
|
|
46
|
+
* single-probe form to an `fc.sample`-based invariant check.
|
|
47
|
+
*/
|
|
48
|
+
export declare const confidentOracleMethods: ReadonlyArray<RpcMethodName>;
|
|
49
|
+
/**
|
|
50
|
+
* Draw a call from the model's confident-oracle set. Per architect
|
|
51
|
+
* #197 §2.2 literal shape: `fc.constantFrom(...kept).chain(
|
|
52
|
+
* arbitraryCallFor)`. Probe at module load uses the same
|
|
53
|
+
* `arbitraryCallFor(m)` generator as execution — so confidence is
|
|
54
|
+
* checked on the same distribution the property exercises.
|
|
55
|
+
*
|
|
56
|
+
* If a kept method turns out to be param-sensitive under a later
|
|
57
|
+
* draw (model predicts ok for the one probe sample but rejects a
|
|
58
|
+
* subsequent arbitrary-drawn params), the safety-net guard in
|
|
59
|
+
* `registerModelEquivalence` raises `PropertyInvariantViolation`
|
|
60
|
+
* pointing at this file — the fix is to widen the derivation (probe
|
|
61
|
+
* K > 1 samples and keep only methods where every probe predicts ok)
|
|
62
|
+
* per the architect's contract. Single-probe is sufficient when
|
|
63
|
+
* `applyCall` is method-only (today).
|
|
64
|
+
*/
|
|
65
|
+
export declare function arbitraryConfidentCall(): fc.Arbitrary<ArbitraryRpcCall>;
|
|
66
|
+
//# sourceMappingURL=rpc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../../../src/testing/arbitraries/rpc.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,aAAa,EACnB,MAAM,uBAAuB,CAAC;AAK/B;;;GAGG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,aAAa,GAAG,aAAa;IACvE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;CACtC;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,aAAa,CAEtD,CAAC;AAKF,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,aAAa,EACtD,MAAM,EAAE,CAAC,GACR,EAAE,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAYnC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,EAAE,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAKjE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,sBAAsB,EAAE,aAAa,CAAC,aAAa,CAY5D,CAAC;AAEL;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,IAAI,EAAE,CAAC,SAAS,CAAC,gBAAgB,CAAC,CASvE"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-`RpcMethodName` arbitrary and the `allRpcMethods` walker.
|
|
3
|
+
*
|
|
4
|
+
* Tier A's A5 (RpcMap coverage) and Tier B's B1 (model equivalence) both
|
|
5
|
+
* iterate every method name. Centralizing the iterator here keeps the
|
|
6
|
+
* property bodies compiler-checked against `RpcMap`.
|
|
7
|
+
*/
|
|
8
|
+
import * as fc from "fast-check";
|
|
9
|
+
import { rpcMethods, } from "../../rpc-registry.js";
|
|
10
|
+
import { applyCall } from "../models/dispatch.js";
|
|
11
|
+
import { initialReferenceState } from "../models/state.js";
|
|
12
|
+
import { arbitraryForParams } from "./from-typebox.js";
|
|
13
|
+
/**
|
|
14
|
+
* Ordered list of every `RpcMethodName`. Exposed so properties can assert
|
|
15
|
+
* "every method exercised at least once" without going through `RpcMap`
|
|
16
|
+
* directly.
|
|
17
|
+
*/
|
|
18
|
+
export const allRpcMethods = rpcMethods.map((m) => m.name);
|
|
19
|
+
// Precomputed lookup from wire name → manifest, so `arbitraryCallFor` is O(1).
|
|
20
|
+
const methodByName = new Map(rpcMethods.map((m) => [m.name, m]));
|
|
21
|
+
/** Arbitrary of a valid params tree for a single, fixed RPC. */
|
|
22
|
+
export function arbitraryCallFor(method) {
|
|
23
|
+
const def = methodByName.get(method);
|
|
24
|
+
if (def === undefined) {
|
|
25
|
+
throw new Error(`arbitraryCallFor: unknown method ${String(method)}`);
|
|
26
|
+
}
|
|
27
|
+
return arbitraryForParams(def.paramsSchema).map((params) => ({
|
|
28
|
+
method,
|
|
29
|
+
params: params,
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Arbitrary that draws any method name + matching params. Used by Tier A
|
|
34
|
+
* A5 and by Tier E E2's cross-RPC fuzz.
|
|
35
|
+
*/
|
|
36
|
+
export function arbitraryAnyCall() {
|
|
37
|
+
if (allRpcMethods.length === 0) {
|
|
38
|
+
throw new Error("arbitraryAnyCall: rpcMethods empty");
|
|
39
|
+
}
|
|
40
|
+
return fc.constantFrom(...allRpcMethods).chain((m) => arbitraryCallFor(m));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The set of `RpcMethodName`s the reference model predicts `_tag: "ok"`
|
|
44
|
+
* for on `initialReferenceState` — derived mechanically at module load
|
|
45
|
+
* by probing `applyCall` with a single drawn params value per method.
|
|
46
|
+
*
|
|
47
|
+
* Per architect #197 §2.2: this is NOT a hand-curated list. Methods
|
|
48
|
+
* move in/out of the confident set automatically when `applyCall`'s
|
|
49
|
+
* `allowNoEvents` / `uncertainError` split moves, so the sampling
|
|
50
|
+
* distribution tracks the model.
|
|
51
|
+
*
|
|
52
|
+
* **Param-invariance contract:** every kept method is treated as
|
|
53
|
+
* oracle-confident for every params value. If a future `applyCall`
|
|
54
|
+
* amendment branches on `call.params`, the safety-net guard in
|
|
55
|
+
* `registerModelEquivalence` (rpc-semantics.ts) fires loudly on the
|
|
56
|
+
* first non-confident draw and the derivation must widen from the
|
|
57
|
+
* single-probe form to an `fc.sample`-based invariant check.
|
|
58
|
+
*/
|
|
59
|
+
export const confidentOracleMethods = (() => {
|
|
60
|
+
// `models/dispatch.ts` imports `ArbitraryRpcCall` as a type-only
|
|
61
|
+
// reference, so the values imported above (`applyCall`,
|
|
62
|
+
// `initialReferenceState`) are safe to call at module load.
|
|
63
|
+
const kept = [];
|
|
64
|
+
for (const method of allRpcMethods) {
|
|
65
|
+
const [sample] = fc.sample(arbitraryCallFor(method), 1);
|
|
66
|
+
if (sample === undefined)
|
|
67
|
+
continue;
|
|
68
|
+
const outcome = applyCall(initialReferenceState, sample).outcome;
|
|
69
|
+
if (outcome._tag === "ok")
|
|
70
|
+
kept.push(method);
|
|
71
|
+
}
|
|
72
|
+
return kept;
|
|
73
|
+
})();
|
|
74
|
+
/**
|
|
75
|
+
* Draw a call from the model's confident-oracle set. Per architect
|
|
76
|
+
* #197 §2.2 literal shape: `fc.constantFrom(...kept).chain(
|
|
77
|
+
* arbitraryCallFor)`. Probe at module load uses the same
|
|
78
|
+
* `arbitraryCallFor(m)` generator as execution — so confidence is
|
|
79
|
+
* checked on the same distribution the property exercises.
|
|
80
|
+
*
|
|
81
|
+
* If a kept method turns out to be param-sensitive under a later
|
|
82
|
+
* draw (model predicts ok for the one probe sample but rejects a
|
|
83
|
+
* subsequent arbitrary-drawn params), the safety-net guard in
|
|
84
|
+
* `registerModelEquivalence` raises `PropertyInvariantViolation`
|
|
85
|
+
* pointing at this file — the fix is to widen the derivation (probe
|
|
86
|
+
* K > 1 samples and keep only methods where every probe predicts ok)
|
|
87
|
+
* per the architect's contract. Single-probe is sufficient when
|
|
88
|
+
* `applyCall` is method-only (today).
|
|
89
|
+
*/
|
|
90
|
+
export function arbitraryConfidentCall() {
|
|
91
|
+
if (confidentOracleMethods.length === 0) {
|
|
92
|
+
throw new Error("arbitraryConfidentCall: model has zero confident-oracle methods; flag needs-structural-rework");
|
|
93
|
+
}
|
|
94
|
+
return fc
|
|
95
|
+
.constantFrom(...confidentOracleMethods)
|
|
96
|
+
.chain((method) => arbitraryCallFor(method));
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=rpc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../../src/testing/arbitraries/rpc.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EACL,UAAU,GAGX,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAWvD;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAiC,UAAU,CAAC,GAAG,CACvE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACd,CAAC;AAEF,+EAA+E;AAC/E,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAEjE,gEAAgE;AAChE,MAAM,UAAU,gBAAgB,CAC9B,MAAS;IAET,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,oCAAoC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,kBAAkB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,GAAG,CAC7C,CAAC,MAAM,EAAE,EAAE,CACT,CAAC;QACC,MAAM;QACN,MAAM,EAAE,MAA6B;KACtC,CAAU,CACd,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,EAAE,CAAC,YAAY,CAAC,GAAG,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAiC,CAAC,GAAG,EAAE;IACxE,iEAAiE;IACjE,wDAAwD;IACxD,4DAA4D;IAC5D,MAAM,IAAI,GAAoB,EAAE,CAAC;IACjC,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QACxD,IAAI,MAAM,KAAK,SAAS;YAAE,SAAS;QACnC,MAAM,OAAO,GAAG,SAAS,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC;QACjE,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC,EAAE,CAAC;AAEL;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,sBAAsB;IACpC,IAAI,sBAAsB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,+FAA+F,CAChG,CAAC;IACJ,CAAC;IACD,OAAO,EAAE;SACN,YAAY,CAAC,GAAG,sBAAsB,CAAC;SACvC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonicalization primitives — narrow, composable building blocks for
|
|
3
|
+
* body-compare property assertions.
|
|
4
|
+
*
|
|
5
|
+
* Per architect #197 §3: properties that compare response bodies route
|
|
6
|
+
* through a named canonical-projection function that normalizes order
|
|
7
|
+
* **only where the protocol spec marks it unordered**. These primitives
|
|
8
|
+
* let the property author that projection without reaching for a
|
|
9
|
+
* blanket deep-sort that would hide real re-ordering regressions inside
|
|
10
|
+
* nested arrays.
|
|
11
|
+
*
|
|
12
|
+
* Callers cite the spec clause for each array they sort, in JSDoc on
|
|
13
|
+
* the projection. Reviewer spot-checks during stamina pass.
|
|
14
|
+
*
|
|
15
|
+
* No blanket `canonicalizeUnordered` helper: picking which arrays to
|
|
16
|
+
* sort is a spec decision, not an ergonomic default.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Sort a JSON-array by the canonical stringification of each element.
|
|
20
|
+
* Shallow: does NOT recurse into elements. Caller composes with
|
|
21
|
+
* `sortObjectKeysDeep` per element if element-wise key-order stability
|
|
22
|
+
* matters. Preserves input immutability (returns a fresh array).
|
|
23
|
+
*/
|
|
24
|
+
export declare function sortJsonArray(arr: ReadonlyArray<unknown>): ReadonlyArray<unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* Deep key-sort on objects; array order preserved at every depth.
|
|
27
|
+
* Use before final `JSON.stringify` so key-order noise does not break
|
|
28
|
+
* byte-compare. Safe to apply over any payload.
|
|
29
|
+
*/
|
|
30
|
+
export declare function sortObjectKeysDeep(value: unknown): unknown;
|
|
31
|
+
/**
|
|
32
|
+
* Final stable serialization: `sortObjectKeysDeep → JSON.stringify`.
|
|
33
|
+
* Intended as the last step after the property has applied whatever
|
|
34
|
+
* array-scoped sorts its spec citation allows. Array order is
|
|
35
|
+
* preserved; object key order is normalized.
|
|
36
|
+
*/
|
|
37
|
+
export declare function canonicalJson(value: unknown): string;
|
|
38
|
+
//# sourceMappingURL=canonicalize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonicalize.d.ts","sourceRoot":"","sources":["../../src/testing/canonicalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,aAAa,CAAC,OAAO,CAAC,GAC1B,aAAa,CAAC,OAAO,CAAC,CAIxB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAS1D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEpD"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonicalization primitives — narrow, composable building blocks for
|
|
3
|
+
* body-compare property assertions.
|
|
4
|
+
*
|
|
5
|
+
* Per architect #197 §3: properties that compare response bodies route
|
|
6
|
+
* through a named canonical-projection function that normalizes order
|
|
7
|
+
* **only where the protocol spec marks it unordered**. These primitives
|
|
8
|
+
* let the property author that projection without reaching for a
|
|
9
|
+
* blanket deep-sort that would hide real re-ordering regressions inside
|
|
10
|
+
* nested arrays.
|
|
11
|
+
*
|
|
12
|
+
* Callers cite the spec clause for each array they sort, in JSDoc on
|
|
13
|
+
* the projection. Reviewer spot-checks during stamina pass.
|
|
14
|
+
*
|
|
15
|
+
* No blanket `canonicalizeUnordered` helper: picking which arrays to
|
|
16
|
+
* sort is a spec decision, not an ergonomic default.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Sort a JSON-array by the canonical stringification of each element.
|
|
20
|
+
* Shallow: does NOT recurse into elements. Caller composes with
|
|
21
|
+
* `sortObjectKeysDeep` per element if element-wise key-order stability
|
|
22
|
+
* matters. Preserves input immutability (returns a fresh array).
|
|
23
|
+
*/
|
|
24
|
+
export function sortJsonArray(arr) {
|
|
25
|
+
const keyed = arr.map((el) => ({ el, key: canonicalJson(el) }));
|
|
26
|
+
keyed.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
|
|
27
|
+
return keyed.map((k) => k.el);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Deep key-sort on objects; array order preserved at every depth.
|
|
31
|
+
* Use before final `JSON.stringify` so key-order noise does not break
|
|
32
|
+
* byte-compare. Safe to apply over any payload.
|
|
33
|
+
*/
|
|
34
|
+
export function sortObjectKeysDeep(value) {
|
|
35
|
+
if (Array.isArray(value))
|
|
36
|
+
return value.map(sortObjectKeysDeep);
|
|
37
|
+
if (value === null || typeof value !== "object")
|
|
38
|
+
return value;
|
|
39
|
+
const out = {};
|
|
40
|
+
for (const key of Object.keys(value).sort()) {
|
|
41
|
+
const v = value[key];
|
|
42
|
+
out[key] = sortObjectKeysDeep(v);
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Final stable serialization: `sortObjectKeysDeep → JSON.stringify`.
|
|
48
|
+
* Intended as the last step after the property has applied whatever
|
|
49
|
+
* array-scoped sorts its spec citation allows. Array order is
|
|
50
|
+
* preserved; object key order is normalized.
|
|
51
|
+
*/
|
|
52
|
+
export function canonicalJson(value) {
|
|
53
|
+
return JSON.stringify(sortObjectKeysDeep(value));
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=canonicalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonicalize.js","sourceRoot":"","sources":["../../src/testing/canonicalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC3B,GAA2B;IAE3B,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,aAAa,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAChE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAC/D,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5C,MAAM,CAAC,GAAa,KAA2C,CAAC,GAAG,CAAC,CAAC;QACrE,GAAG,CAAC,GAAG,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded, ordered capture buffers. TestClient captures every frame the
|
|
3
|
+
* real server replied with; TestServer captures every frame a real client
|
|
4
|
+
* pushed in. Both are append-only ring buffers exposed as `Effect` Streams
|
|
5
|
+
* so property code can `Stream.take` or `Stream.filter` without racing the
|
|
6
|
+
* underlying fiber.
|
|
7
|
+
*
|
|
8
|
+
* Exhaustiveness: `CaptureKind` discriminates inbound vs outbound so the
|
|
9
|
+
* same buffer can record both sides when a primitive is proxied through
|
|
10
|
+
* Toxiproxy (Tier D).
|
|
11
|
+
*/
|
|
12
|
+
import { Effect, Stream } from "effect";
|
|
13
|
+
import type { AnyFrame, MalformedFrameKind } from "./codec.js";
|
|
14
|
+
export type CaptureKind = "inbound" | "outbound";
|
|
15
|
+
/**
|
|
16
|
+
* One recorded event. `frame` is `null` when the capture is a raw-bytes
|
|
17
|
+
* record that failed to decode — Tier A's A4 property asserts on both the
|
|
18
|
+
* raw bytes and the typed `FrameSchemaError` that fired.
|
|
19
|
+
*/
|
|
20
|
+
export interface CapturedFrame {
|
|
21
|
+
readonly at: number;
|
|
22
|
+
readonly kind: CaptureKind;
|
|
23
|
+
readonly raw: string;
|
|
24
|
+
readonly frame: AnyFrame | null;
|
|
25
|
+
readonly malformed: MalformedFrameKind | null;
|
|
26
|
+
}
|
|
27
|
+
/** Opaque handle to a running buffer; held by TestClient / TestServer. */
|
|
28
|
+
export interface CaptureBuffer {
|
|
29
|
+
readonly snapshot: Effect.Effect<ReadonlyArray<CapturedFrame>>;
|
|
30
|
+
readonly stream: Stream.Stream<CapturedFrame>;
|
|
31
|
+
readonly clear: Effect.Effect<void>;
|
|
32
|
+
/** @internal — used by primitives to append. Not exported from barrel. */
|
|
33
|
+
readonly _publish: (entry: CapturedFrame) => Effect.Effect<void>;
|
|
34
|
+
/** @internal — soft capacity so `mergeCaptures` can fan messages out safely. */
|
|
35
|
+
readonly _capacity: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Ring-buffer + PubSub implementation. The Ref holds the bounded
|
|
39
|
+
* array; PubSub fans each append out to every subscriber so `stream`
|
|
40
|
+
* behaves as a live tail.
|
|
41
|
+
*/
|
|
42
|
+
export declare function makeCaptureBuffer(opts: {
|
|
43
|
+
readonly capacity: number;
|
|
44
|
+
}): Effect.Effect<CaptureBuffer>;
|
|
45
|
+
/**
|
|
46
|
+
* Multiplex captures across many connections — used by Tier C properties
|
|
47
|
+
* where N real clients emit concurrently and the property asserts on the
|
|
48
|
+
* merged ordered stream.
|
|
49
|
+
*
|
|
50
|
+
* Semantics:
|
|
51
|
+
* - `snapshot` returns every buffer's current contents concatenated and
|
|
52
|
+
* sorted by `at` (stable for equal timestamps by buffer index).
|
|
53
|
+
* - `stream` is `Stream.mergeAll(stream...)` — live events in arrival order.
|
|
54
|
+
* - `clear` clears every upstream buffer.
|
|
55
|
+
*/
|
|
56
|
+
export declare function mergeCaptures(buffers: ReadonlyArray<CaptureBuffer>): Effect.Effect<CaptureBuffer>;
|
|
57
|
+
/** Internal hook used by primitives to push a decode failure as-bytes. */
|
|
58
|
+
export declare function recordMalformed(buffer: CaptureBuffer, raw: string, kind: MalformedFrameKind): Effect.Effect<void>;
|
|
59
|
+
/** Internal hook: push a successfully-decoded frame. */
|
|
60
|
+
export declare function recordFrame(buffer: CaptureBuffer, kind: CaptureKind, raw: string, frame: AnyFrame): Effect.Effect<void>;
|
|
61
|
+
//# sourceMappingURL=captures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captures.d.ts","sourceRoot":"","sources":["../../src/testing/captures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,MAAM,EAAO,MAAM,EAAU,MAAM,QAAQ,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE/D,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,UAAU,CAAC;AAEjD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,GAAG,IAAI,CAAC;CAC/C;AAED,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC;IAC/D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpC,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjE,gFAAgF;IAChF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAID;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAwB/B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,aAAa,CAAC,aAAa,CAAC,GACpC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAkC9B;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,kBAAkB,GACvB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAQrB;AAED,wDAAwD;AACxD,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,QAAQ,GACd,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAQrB"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded, ordered capture buffers. TestClient captures every frame the
|
|
3
|
+
* real server replied with; TestServer captures every frame a real client
|
|
4
|
+
* pushed in. Both are append-only ring buffers exposed as `Effect` Streams
|
|
5
|
+
* so property code can `Stream.take` or `Stream.filter` without racing the
|
|
6
|
+
* underlying fiber.
|
|
7
|
+
*
|
|
8
|
+
* Exhaustiveness: `CaptureKind` discriminates inbound vs outbound so the
|
|
9
|
+
* same buffer can record both sides when a primitive is proxied through
|
|
10
|
+
* Toxiproxy (Tier D).
|
|
11
|
+
*/
|
|
12
|
+
import { Effect, Ref, Stream, PubSub } from "effect";
|
|
13
|
+
const startTime = Date.now();
|
|
14
|
+
/**
|
|
15
|
+
* Ring-buffer + PubSub implementation. The Ref holds the bounded
|
|
16
|
+
* array; PubSub fans each append out to every subscriber so `stream`
|
|
17
|
+
* behaves as a live tail.
|
|
18
|
+
*/
|
|
19
|
+
export function makeCaptureBuffer(opts) {
|
|
20
|
+
return Effect.gen(function* () {
|
|
21
|
+
const cap = Math.max(1, opts.capacity);
|
|
22
|
+
const ref = yield* Ref.make([]);
|
|
23
|
+
const pubsub = yield* PubSub.sliding(cap);
|
|
24
|
+
const publish = (entry) => Effect.gen(function* () {
|
|
25
|
+
yield* Ref.update(ref, (cur) => {
|
|
26
|
+
const next = cur.length >= cap ? cur.slice(1) : cur.slice();
|
|
27
|
+
return [...next, entry];
|
|
28
|
+
});
|
|
29
|
+
yield* PubSub.publish(pubsub, entry);
|
|
30
|
+
});
|
|
31
|
+
const buf = {
|
|
32
|
+
snapshot: Ref.get(ref),
|
|
33
|
+
stream: Stream.fromPubSub(pubsub),
|
|
34
|
+
clear: Ref.set(ref, []),
|
|
35
|
+
_publish: publish,
|
|
36
|
+
_capacity: cap,
|
|
37
|
+
};
|
|
38
|
+
return buf;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Multiplex captures across many connections — used by Tier C properties
|
|
43
|
+
* where N real clients emit concurrently and the property asserts on the
|
|
44
|
+
* merged ordered stream.
|
|
45
|
+
*
|
|
46
|
+
* Semantics:
|
|
47
|
+
* - `snapshot` returns every buffer's current contents concatenated and
|
|
48
|
+
* sorted by `at` (stable for equal timestamps by buffer index).
|
|
49
|
+
* - `stream` is `Stream.mergeAll(stream...)` — live events in arrival order.
|
|
50
|
+
* - `clear` clears every upstream buffer.
|
|
51
|
+
*/
|
|
52
|
+
export function mergeCaptures(buffers) {
|
|
53
|
+
return Effect.gen(function* () {
|
|
54
|
+
const merged = yield* makeCaptureBuffer({
|
|
55
|
+
capacity: buffers.reduce((sum, b) => sum + b._capacity, 0) || 1,
|
|
56
|
+
});
|
|
57
|
+
// Return a view that aggregates snapshots on demand rather than a live
|
|
58
|
+
// merged copy: the source buffers are authoritative.
|
|
59
|
+
const snapshot = Effect.gen(function* () {
|
|
60
|
+
const snaps = yield* Effect.forEach(buffers, (b) => b.snapshot, {
|
|
61
|
+
concurrency: "unbounded",
|
|
62
|
+
});
|
|
63
|
+
const flat = snaps.flat();
|
|
64
|
+
return [...flat].sort((a, b) => a.at - b.at);
|
|
65
|
+
});
|
|
66
|
+
const stream = Stream.mergeAll(buffers.map((b) => b.stream), { concurrency: "unbounded" });
|
|
67
|
+
const clear = Effect.forEach(buffers, (b) => b.clear, {
|
|
68
|
+
concurrency: "unbounded",
|
|
69
|
+
}).pipe(Effect.asVoid);
|
|
70
|
+
return {
|
|
71
|
+
snapshot,
|
|
72
|
+
stream,
|
|
73
|
+
clear,
|
|
74
|
+
_publish: merged._publish,
|
|
75
|
+
_capacity: merged._capacity,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/** Internal hook used by primitives to push a decode failure as-bytes. */
|
|
80
|
+
export function recordMalformed(buffer, raw, kind) {
|
|
81
|
+
return buffer._publish({
|
|
82
|
+
at: Date.now() - startTime,
|
|
83
|
+
kind: "inbound",
|
|
84
|
+
raw,
|
|
85
|
+
frame: null,
|
|
86
|
+
malformed: kind,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/** Internal hook: push a successfully-decoded frame. */
|
|
90
|
+
export function recordFrame(buffer, kind, raw, frame) {
|
|
91
|
+
return buffer._publish({
|
|
92
|
+
at: Date.now() - startTime,
|
|
93
|
+
kind,
|
|
94
|
+
raw,
|
|
95
|
+
frame,
|
|
96
|
+
malformed: null,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=captures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captures.js","sourceRoot":"","sources":["../../src/testing/captures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AA6BrD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAE7B;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAEjC;IACC,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAA+B,EAAE,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAgB,GAAG,CAAC,CAAC;QAEzD,MAAM,OAAO,GAAG,CAAC,KAAoB,EAAuB,EAAE,CAC5D,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC7B,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;gBAC5D,OAAO,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,CAAC;YAC1B,CAAC,CAAC,CAAC;YACH,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEL,MAAM,GAAG,GAAkB;YACzB,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;YACtB,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;YACjC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC;YACvB,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,GAAG;SACf,CAAC;QACF,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAqC;IAErC,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACzB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,iBAAiB,CAAC;YACtC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC;SAChE,CAAC,CAAC;QAEH,uEAAuE;QACvE,qDAAqD;QACrD,MAAM,QAAQ,GAAgD,MAAM,CAAC,GAAG,CACtE,QAAQ,CAAC;YACP,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE;gBAC9D,WAAW,EAAE,WAAW;aACzB,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/C,CAAC,CACF,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAC5B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAC5B,EAAE,WAAW,EAAE,WAAW,EAAE,CAC7B,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE;YACpD,WAAW,EAAE,WAAW;SACzB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAEvB,OAAO;YACL,QAAQ;YACR,MAAM;YACN,KAAK;YACL,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,SAAS,EAAE,MAAM,CAAC,SAAS;SACJ,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,eAAe,CAC7B,MAAqB,EACrB,GAAW,EACX,IAAwB;IAExB,OAAO,MAAM,CAAC,QAAQ,CAAC;QACrB,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;QAC1B,IAAI,EAAE,SAAS;QACf,GAAG;QACH,KAAK,EAAE,IAAI;QACX,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC;AACL,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,WAAW,CACzB,MAAqB,EACrB,IAAiB,EACjB,GAAW,EACX,KAAe;IAEf,OAAO,MAAM,CAAC,QAAQ,CAAC;QACrB,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;QAC1B,IAAI;QACJ,GAAG;QACH,KAAK;QACL,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frame codec for the testing primitives.
|
|
3
|
+
*
|
|
4
|
+
* Satisfies §5.A1/A2/A3/A4 and Invariant I3: every frame crossing a
|
|
5
|
+
* primitive is `Value.Check`-validated before it is surfaced to property
|
|
6
|
+
* code. Malformed-frame arbitraries are generated *here* so Tier A can
|
|
7
|
+
* inject bit-flips, truncations, and oversized frames without leaking the
|
|
8
|
+
* malformation strategy into the primitives.
|
|
9
|
+
*/
|
|
10
|
+
import { Effect } from "effect";
|
|
11
|
+
import { type RequestFrame, type ResponseFrame, type EventFrame } from "../schema/frames.js";
|
|
12
|
+
import { FrameSchemaError } from "./errors.js";
|
|
13
|
+
/**
|
|
14
|
+
* Valid-frame kinds exposed on the wire. The string literal discriminator
|
|
15
|
+
* matches the `type` field in `RequestFrameSchema` / `ResponseFrameSchema`
|
|
16
|
+
* and the outer `type: "event"` sentinel for `EventFrameSchema`.
|
|
17
|
+
*/
|
|
18
|
+
export type AnyFrame = ({
|
|
19
|
+
readonly type: "request";
|
|
20
|
+
} & RequestFrame) | ({
|
|
21
|
+
readonly type: "response";
|
|
22
|
+
} & ResponseFrame) | ({
|
|
23
|
+
readonly type: "event";
|
|
24
|
+
} & EventFrame);
|
|
25
|
+
/**
|
|
26
|
+
* Kinds of malformation Tier A / Tier D-slicer can inject. Each maps to a
|
|
27
|
+
* deterministic mutation driven by fast-check so shrinks reproduce.
|
|
28
|
+
*/
|
|
29
|
+
export type MalformedFrameKind = "bit-flip" | "truncated" | "oversized" | "invalid-utf8" | "missing-required-field" | "extra-property";
|
|
30
|
+
/** Serialize a typed frame to the wire bytes. */
|
|
31
|
+
export declare function encodeFrame(frame: AnyFrame): string;
|
|
32
|
+
/**
|
|
33
|
+
* Parse + `Value.Check` an inbound frame. `FrameSchemaError` captures
|
|
34
|
+
* the failing branch so Tier A can assert "drop or typed error, never
|
|
35
|
+
* crash."
|
|
36
|
+
*/
|
|
37
|
+
export declare function decodeFrame(raw: string, direction: "outbound" | "inbound"): Effect.Effect<AnyFrame, FrameSchemaError>;
|
|
38
|
+
/**
|
|
39
|
+
* Produce a malformed wire payload from a valid frame. The mutation is
|
|
40
|
+
* deterministic given the `kind` + `seed`; replaying with the same seed
|
|
41
|
+
* reproduces the exact bytes. Used by Tier A (A4) and Tier D (D3).
|
|
42
|
+
*/
|
|
43
|
+
export declare function malformFrame(base: AnyFrame, kind: MalformedFrameKind, seed: number): string;
|
|
44
|
+
//# sourceMappingURL=codec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../src/testing/codec.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAChB,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAAG,YAAY,CAAC,GAC7C,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAAG,aAAa,CAAC,GAC/C,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,UAAU,CAAC,CAAC;AAE9C;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAC1B,UAAU,GACV,WAAW,GACX,WAAW,GACX,cAAc,GACd,wBAAwB,GACxB,gBAAgB,CAAC;AAErB,iDAAiD;AACjD,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAEnD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,UAAU,GAAG,SAAS,GAChC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAiF3C;AAaD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,kBAAkB,EACxB,IAAI,EAAE,MAAM,GACX,MAAM,CAoDR"}
|