@serfab/quereus-plugin-sereus 1.3.0 → 1.5.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/cluster-size.d.ts +115 -19
- package/dist/cluster-size.js +145 -31
- package/dist/cluster-size.js.map +1 -1
- package/dist/compose-strand.js +19 -0
- package/dist/compose-strand.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/plugin-browser.js +23 -23
- package/dist/plugin-browser.js.map +4 -4
- package/package.json +8 -8
- package/src/cluster-size.ts +171 -32
- package/src/compose-strand.ts +19 -0
- package/src/index.ts +1 -0
package/dist/cluster-size.d.ts
CHANGED
|
@@ -5,6 +5,81 @@ import type { NodeOptions } from '@optimystic/db-p2p';
|
|
|
5
5
|
* local storage without forming a cluster). A validation floor, not a default.
|
|
6
6
|
*/
|
|
7
7
|
export declare const MIN_CLUSTER_SIZE = 2;
|
|
8
|
+
/**
|
|
9
|
+
* How long ONE cohort peer gets to answer ONE read-path request, in milliseconds — both
|
|
10
|
+
* networks' `clusterPolicy.cohortQueryTimeoutMs`. It sets the latest-revision query a read
|
|
11
|
+
* runs when its local copy may be stale (`CoordinatorRepo.queryClusterForLatest`) and the
|
|
12
|
+
* archive fetch that follows it (`fetchArchiveFromPeer`); Optimystic ties the two to one
|
|
13
|
+
* field because they are the same round trip to the same peer. Optimystic's own default is
|
|
14
|
+
* 1000 ms, a LAN-shaped budget, and it deliberately left that default alone — choosing the
|
|
15
|
+
* value for a deployment of phones is the embedder's job.
|
|
16
|
+
*
|
|
17
|
+
* **Why 5000.** Optimystic GitHub #22, reported by a sereus-based chat app: two parties that
|
|
18
|
+
* reach each other only through a public circuit relay have a round trip near 1.8 s, and a
|
|
19
|
+
* fresh stream (dial or reuse, protocol select, send, receive) cannot finish inside a second.
|
|
20
|
+
* At a cohort of two there is exactly one peer to ask, so one late answer leaves the read with
|
|
21
|
+
* nothing to corroborate against and it is declined. 5000 covers 1.8 s with room for the Noise
|
|
22
|
+
* handshake, the relay hops and a phone's pure-JS crypto (cadre-core's
|
|
23
|
+
* `NetworkConfig.noiseCrypto`), and it is the value Optimystic's own note advises for that
|
|
24
|
+
* link. The whole-pass reconcile bound Optimystic derives from it (`max(5000, 5 x this)`)
|
|
25
|
+
* becomes 25 s.
|
|
26
|
+
*
|
|
27
|
+
* **Measured** 2026-09-26, one Windows developer machine, two relay-only `CadreNode`s on one
|
|
28
|
+
* shared loopback dedicated relay, the one-way outbound frame delay raised to 900 ms
|
|
29
|
+
* (`pipelined` mode — see `docs/testing.md` → "Where measurements live") AFTER the strand had
|
|
30
|
+
* formed and first synced, for a round trip near 1.8 s. A machine that had joined, gone away
|
|
31
|
+
* while the other wrote, then re-attached over its own stale store and read the row written
|
|
32
|
+
* while it was away. Declined reads over that journey, after the delay was raised: **18 at
|
|
33
|
+
* Optimystic's 1000 ms, 2 at 5000 ms.** A declined read is
|
|
34
|
+
* `cluster-fetch:peers-silent { silent: 1, consulted: 2 }` followed by
|
|
35
|
+
* `cluster-fetch:no-quorum`, retried about a second later until one lands; at 5000 the
|
|
36
|
+
* corroboration succeeded instead (`cluster-fetch:local-current`). Both journeys COMPLETED at
|
|
37
|
+
* either value, which is why no committed scenario gates this — 900 ms is not where it breaks,
|
|
38
|
+
* and above it a run breaks on redialling instead. The recipe for re-measuring is in
|
|
39
|
+
* `docs/testing.md` → "Where measurements live".
|
|
40
|
+
*
|
|
41
|
+
* **What it costs**, in the terms Optimystic's own field doc uses: a peer that is truly gone
|
|
42
|
+
* now holds a read of a block missing locally for up to 5 s before the read is declined
|
|
43
|
+
* instead of 1 s. A joining machine's first sync runs several such consults, so it is the cost
|
|
44
|
+
* that binds — and the first-sync band measured at BOTH deadlines, against the 120 s budget it
|
|
45
|
+
* has to fit, is recorded once, on `DEFAULT_STRAND_FIRST_SYNC_TIMEOUT_MS` in cadre-core's
|
|
46
|
+
* `strand-first-sync-gate.ts`. At 5000 against the 30 s budget that preceded 120 s, this change
|
|
47
|
+
* would have turned a slow-but-working join into the very `StrandAwaitingFirstSyncError` the
|
|
48
|
+
* report named. 3000 is the fallback if that margin ever goes — still 1.7x the reported round
|
|
49
|
+
* trip, and a doomed consult costs 40% less.
|
|
50
|
+
*
|
|
51
|
+
* **What else it lengthens, which the first-sync budget is only the largest case of.** Every
|
|
52
|
+
* cadre-core deadline that wraps an Optimystic read or commit was sized when one silent peer
|
|
53
|
+
* cost 1 s and a whole reconcile pass cost 5 s; those are now 5 s and 25 s. Two consequences
|
|
54
|
+
* are already true rather than hypothetical:
|
|
55
|
+
*
|
|
56
|
+
* - The inbound membership admission gate reads the control database uncached and FAILS OPEN
|
|
57
|
+
* after 2 s (`ADMISSION_DECISION_TIMEOUT_MS`, cadre-core's
|
|
58
|
+
* `membership-connection-gater.ts`), so a decision whose read consults a silent peer can no
|
|
59
|
+
* longer settle inside that deadline at all: an unplaced peer is admitted at the connection
|
|
60
|
+
* layer for the whole 5 s instead of roughly 1 s. It is admitted to nothing more than a
|
|
61
|
+
* connection — the per-protocol stream gates still decide, and unplaced relay reservations
|
|
62
|
+
* stay capped (`MAX_UNAUTHORIZED_RELAY_RESERVATIONS`) — which is why this is a widened cost
|
|
63
|
+
* and not a hole. `backlog/debt-cadre-deadlines-sized-against-old-optimystic-bounds` owns
|
|
64
|
+
* the audit of the rest.
|
|
65
|
+
* - `CONTROL_READ_RETRY_BUDGET_MS` (1500 ms) now terminates the control-read retry loop after
|
|
66
|
+
* the FIRST attempt whenever that attempt burned this deadline, so a read failing that way
|
|
67
|
+
* gets no second presentation. Its own doc carries the coupling.
|
|
68
|
+
*
|
|
69
|
+
* **One value for both networks, not two.** The reason to widen is the link, and a phone's
|
|
70
|
+
* control node and its strand nodes share it; nothing about control traffic or strand traffic
|
|
71
|
+
* argues for different numbers. A host that needs another value moves both at once —
|
|
72
|
+
* cadre-core's `NetworkConfig.cohortQueryTimeoutMs`, threaded to {@link controlClusterPolicy}
|
|
73
|
+
* and {@link strandClusterPolicy}.
|
|
74
|
+
*
|
|
75
|
+
* NOTE: this number and the first-sync budget are coupled, and the margin between them is about
|
|
76
|
+
* 2.6x today. Re-measure the first-sync band before raising this again, or when a deployment's
|
|
77
|
+
* first sync grows more collections than the two-table scenario measured above —
|
|
78
|
+
* `DEFAULT_STRAND_FIRST_SYNC_TIMEOUT_MS` carries the result and `docs/testing.md` the recipe.
|
|
79
|
+
* Nothing warns when the margin goes; the symptom is `StrandAwaitingFirstSyncError` on a join
|
|
80
|
+
* that was progressing normally, which is the failure this pair of numbers exists to end.
|
|
81
|
+
*/
|
|
82
|
+
export declare const COHORT_READ_DEADLINE_MS = 5000;
|
|
8
83
|
/**
|
|
9
84
|
* How many nodes each block of the **control** (cadre membership) database is replicated
|
|
10
85
|
* to. Chosen to exceed any party's node count, so in practice every control block lands
|
|
@@ -110,6 +185,10 @@ export declare const CONTROL_REPLICATION_BREADTH = 16;
|
|
|
110
185
|
* whether this node believes a repair answer), which is exactly why the two are now separate
|
|
111
186
|
* numbers rather than one.
|
|
112
187
|
*
|
|
188
|
+
* `cohortQueryTimeoutMs` is declared for the same reason it is declared on the strand policy —
|
|
189
|
+
* the link, not the network ({@link COHORT_READ_DEADLINE_MS}). Absent it, Optimystic's LAN-shaped
|
|
190
|
+
* 1000 ms would leave a control read over a relayed link with no corroborating answer in time.
|
|
191
|
+
*
|
|
113
192
|
* The `satisfies` is load-bearing: without it a mistyped or obsolete key would compile at both
|
|
114
193
|
* this definition and every consumer, because TypeScript only excess-property-checks fresh
|
|
115
194
|
* object literals, not a shared constant handed to `clusterPolicy`.
|
|
@@ -118,6 +197,7 @@ export declare const CONTROL_CLUSTER_POLICY: Readonly<{
|
|
|
118
197
|
allowDownsize: true;
|
|
119
198
|
sizeTolerance: number;
|
|
120
199
|
assumedClusterSize: number;
|
|
200
|
+
cohortQueryTimeoutMs: number;
|
|
121
201
|
}>;
|
|
122
202
|
/**
|
|
123
203
|
* Default number of nodes a **strand** network is told its replication cluster should have.
|
|
@@ -258,12 +338,18 @@ export declare const DEFAULT_STRAND_CLUSTER_SIZE = 4;
|
|
|
258
338
|
* promise that `ceil(0.75 x N)` of its machines are awake, and the admission gate would refuse
|
|
259
339
|
* its writes. Same reason and same warning as {@link CONTROL_CLUSTER_POLICY}'s.
|
|
260
340
|
*
|
|
341
|
+
* `cohortQueryTimeoutMs` is {@link COHORT_READ_DEADLINE_MS}, the same value the control policy
|
|
342
|
+
* declares. That is the one field the two networks deliberately agree on by argument rather than
|
|
343
|
+
* by coincidence: it is a property of the LINK, and a phone's control node and its strand nodes
|
|
344
|
+
* ride the same one.
|
|
345
|
+
*
|
|
261
346
|
* The `satisfies` is load-bearing for the same reason as {@link CONTROL_CLUSTER_POLICY}'s.
|
|
262
347
|
*/
|
|
263
348
|
export declare const STRAND_CLUSTER_POLICY: Readonly<{
|
|
264
349
|
allowDownsize: true;
|
|
265
350
|
sizeTolerance: number;
|
|
266
351
|
assumedClusterSize: number;
|
|
352
|
+
cohortQueryTimeoutMs: number;
|
|
267
353
|
}>;
|
|
268
354
|
/**
|
|
269
355
|
* Resolve the cluster size to hand `createLibp2pNode` for a **strand** network, applying
|
|
@@ -376,27 +462,37 @@ export declare function resolveStrandClusterSize(configured?: number): number;
|
|
|
376
462
|
*/
|
|
377
463
|
export declare function resolveRepairYardstick(servingMachines: number, replicationBreadth: number): number;
|
|
378
464
|
/**
|
|
379
|
-
* {@link CONTROL_CLUSTER_POLICY} with the repair yardstick declared from
|
|
380
|
-
* (see {@link resolveRepairYardstick})
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
465
|
+
* {@link CONTROL_CLUSTER_POLICY} with the block-repair corroboration yardstick declared from
|
|
466
|
+
* `enrolledMachines` (see {@link resolveRepairYardstick}) and the per-peer read deadline replaced
|
|
467
|
+
* by the host's `cohortQueryTimeoutMs`; the frozen base object ITSELF when neither is declared, so
|
|
468
|
+
* identity assertions keep holding — including for the host that passes a `network` block with
|
|
469
|
+
* neither field in it, whose declarations arrive present-but-`undefined`.
|
|
470
|
+
*
|
|
471
|
+
* The count is named `enrolledMachines` here, unlike {@link strandClusterPolicy}'s, because for the
|
|
472
|
+
* CONTROL network the two quantities are one and the same by construction: every enrolled machine
|
|
473
|
+
* runs the control node, so the machines enrolled in the party ARE the machines serving this
|
|
474
|
+
* network.
|
|
387
475
|
*/
|
|
388
|
-
export declare function controlClusterPolicy(
|
|
476
|
+
export declare function controlClusterPolicy(declared?: {
|
|
477
|
+
enrolledMachines?: number;
|
|
478
|
+
cohortQueryTimeoutMs?: number;
|
|
479
|
+
}): NonNullable<NodeOptions['clusterPolicy']>;
|
|
389
480
|
/**
|
|
390
|
-
* {@link STRAND_CLUSTER_POLICY} with the repair yardstick declared from
|
|
391
|
-
* machines that serve THIS strand —
|
|
392
|
-
* {@link resolveStrandClusterSize}, so it is at least
|
|
393
|
-
* two clamps can never cross)
|
|
394
|
-
*
|
|
395
|
-
*
|
|
481
|
+
* {@link STRAND_CLUSTER_POLICY} with the block-repair corroboration yardstick declared from
|
|
482
|
+
* `servingMachines` — the machines that serve THIS strand — capped at this strand's own
|
|
483
|
+
* `clusterSize` (already resolved by {@link resolveStrandClusterSize}, so it is at least
|
|
484
|
+
* {@link MIN_CLUSTER_SIZE} and the formula's two clamps can never cross), and the per-peer read
|
|
485
|
+
* deadline replaced by the host's `cohortQueryTimeoutMs`; the frozen base object ITSELF when
|
|
486
|
+
* neither is declared.
|
|
487
|
+
*
|
|
488
|
+
* **The no-count path is the production path today.** No authenticated per-strand serving count
|
|
396
489
|
* exists, and the party's enrolled-machine count is emphatically not one (see
|
|
397
|
-
* {@link resolveRepairYardstick}'s contract section), so cadre-core
|
|
398
|
-
* strand node runs the frozen constant. The
|
|
399
|
-
* `StartStrandConfig.servingMachines` stay in place as the seam that
|
|
490
|
+
* {@link resolveRepairYardstick}'s contract section), so cadre-core declares no count and every
|
|
491
|
+
* strand node of a host that declared no deadline runs the frozen constant. The field and its
|
|
492
|
+
* threading through `StartStrandConfig.servingMachines` stay in place as the seam that
|
|
400
493
|
* `backlog/feat-strand-yardstick-from-serving-machines` plugs a real count into.
|
|
401
494
|
*/
|
|
402
|
-
export declare function strandClusterPolicy(clusterSize: number,
|
|
495
|
+
export declare function strandClusterPolicy(clusterSize: number, declared?: {
|
|
496
|
+
servingMachines?: number;
|
|
497
|
+
cohortQueryTimeoutMs?: number;
|
|
498
|
+
}): NonNullable<NodeOptions['clusterPolicy']>;
|
package/dist/cluster-size.js
CHANGED
|
@@ -4,6 +4,81 @@
|
|
|
4
4
|
* local storage without forming a cluster). A validation floor, not a default.
|
|
5
5
|
*/
|
|
6
6
|
export const MIN_CLUSTER_SIZE = 2;
|
|
7
|
+
/**
|
|
8
|
+
* How long ONE cohort peer gets to answer ONE read-path request, in milliseconds — both
|
|
9
|
+
* networks' `clusterPolicy.cohortQueryTimeoutMs`. It sets the latest-revision query a read
|
|
10
|
+
* runs when its local copy may be stale (`CoordinatorRepo.queryClusterForLatest`) and the
|
|
11
|
+
* archive fetch that follows it (`fetchArchiveFromPeer`); Optimystic ties the two to one
|
|
12
|
+
* field because they are the same round trip to the same peer. Optimystic's own default is
|
|
13
|
+
* 1000 ms, a LAN-shaped budget, and it deliberately left that default alone — choosing the
|
|
14
|
+
* value for a deployment of phones is the embedder's job.
|
|
15
|
+
*
|
|
16
|
+
* **Why 5000.** Optimystic GitHub #22, reported by a sereus-based chat app: two parties that
|
|
17
|
+
* reach each other only through a public circuit relay have a round trip near 1.8 s, and a
|
|
18
|
+
* fresh stream (dial or reuse, protocol select, send, receive) cannot finish inside a second.
|
|
19
|
+
* At a cohort of two there is exactly one peer to ask, so one late answer leaves the read with
|
|
20
|
+
* nothing to corroborate against and it is declined. 5000 covers 1.8 s with room for the Noise
|
|
21
|
+
* handshake, the relay hops and a phone's pure-JS crypto (cadre-core's
|
|
22
|
+
* `NetworkConfig.noiseCrypto`), and it is the value Optimystic's own note advises for that
|
|
23
|
+
* link. The whole-pass reconcile bound Optimystic derives from it (`max(5000, 5 x this)`)
|
|
24
|
+
* becomes 25 s.
|
|
25
|
+
*
|
|
26
|
+
* **Measured** 2026-09-26, one Windows developer machine, two relay-only `CadreNode`s on one
|
|
27
|
+
* shared loopback dedicated relay, the one-way outbound frame delay raised to 900 ms
|
|
28
|
+
* (`pipelined` mode — see `docs/testing.md` → "Where measurements live") AFTER the strand had
|
|
29
|
+
* formed and first synced, for a round trip near 1.8 s. A machine that had joined, gone away
|
|
30
|
+
* while the other wrote, then re-attached over its own stale store and read the row written
|
|
31
|
+
* while it was away. Declined reads over that journey, after the delay was raised: **18 at
|
|
32
|
+
* Optimystic's 1000 ms, 2 at 5000 ms.** A declined read is
|
|
33
|
+
* `cluster-fetch:peers-silent { silent: 1, consulted: 2 }` followed by
|
|
34
|
+
* `cluster-fetch:no-quorum`, retried about a second later until one lands; at 5000 the
|
|
35
|
+
* corroboration succeeded instead (`cluster-fetch:local-current`). Both journeys COMPLETED at
|
|
36
|
+
* either value, which is why no committed scenario gates this — 900 ms is not where it breaks,
|
|
37
|
+
* and above it a run breaks on redialling instead. The recipe for re-measuring is in
|
|
38
|
+
* `docs/testing.md` → "Where measurements live".
|
|
39
|
+
*
|
|
40
|
+
* **What it costs**, in the terms Optimystic's own field doc uses: a peer that is truly gone
|
|
41
|
+
* now holds a read of a block missing locally for up to 5 s before the read is declined
|
|
42
|
+
* instead of 1 s. A joining machine's first sync runs several such consults, so it is the cost
|
|
43
|
+
* that binds — and the first-sync band measured at BOTH deadlines, against the 120 s budget it
|
|
44
|
+
* has to fit, is recorded once, on `DEFAULT_STRAND_FIRST_SYNC_TIMEOUT_MS` in cadre-core's
|
|
45
|
+
* `strand-first-sync-gate.ts`. At 5000 against the 30 s budget that preceded 120 s, this change
|
|
46
|
+
* would have turned a slow-but-working join into the very `StrandAwaitingFirstSyncError` the
|
|
47
|
+
* report named. 3000 is the fallback if that margin ever goes — still 1.7x the reported round
|
|
48
|
+
* trip, and a doomed consult costs 40% less.
|
|
49
|
+
*
|
|
50
|
+
* **What else it lengthens, which the first-sync budget is only the largest case of.** Every
|
|
51
|
+
* cadre-core deadline that wraps an Optimystic read or commit was sized when one silent peer
|
|
52
|
+
* cost 1 s and a whole reconcile pass cost 5 s; those are now 5 s and 25 s. Two consequences
|
|
53
|
+
* are already true rather than hypothetical:
|
|
54
|
+
*
|
|
55
|
+
* - The inbound membership admission gate reads the control database uncached and FAILS OPEN
|
|
56
|
+
* after 2 s (`ADMISSION_DECISION_TIMEOUT_MS`, cadre-core's
|
|
57
|
+
* `membership-connection-gater.ts`), so a decision whose read consults a silent peer can no
|
|
58
|
+
* longer settle inside that deadline at all: an unplaced peer is admitted at the connection
|
|
59
|
+
* layer for the whole 5 s instead of roughly 1 s. It is admitted to nothing more than a
|
|
60
|
+
* connection — the per-protocol stream gates still decide, and unplaced relay reservations
|
|
61
|
+
* stay capped (`MAX_UNAUTHORIZED_RELAY_RESERVATIONS`) — which is why this is a widened cost
|
|
62
|
+
* and not a hole. `backlog/debt-cadre-deadlines-sized-against-old-optimystic-bounds` owns
|
|
63
|
+
* the audit of the rest.
|
|
64
|
+
* - `CONTROL_READ_RETRY_BUDGET_MS` (1500 ms) now terminates the control-read retry loop after
|
|
65
|
+
* the FIRST attempt whenever that attempt burned this deadline, so a read failing that way
|
|
66
|
+
* gets no second presentation. Its own doc carries the coupling.
|
|
67
|
+
*
|
|
68
|
+
* **One value for both networks, not two.** The reason to widen is the link, and a phone's
|
|
69
|
+
* control node and its strand nodes share it; nothing about control traffic or strand traffic
|
|
70
|
+
* argues for different numbers. A host that needs another value moves both at once —
|
|
71
|
+
* cadre-core's `NetworkConfig.cohortQueryTimeoutMs`, threaded to {@link controlClusterPolicy}
|
|
72
|
+
* and {@link strandClusterPolicy}.
|
|
73
|
+
*
|
|
74
|
+
* NOTE: this number and the first-sync budget are coupled, and the margin between them is about
|
|
75
|
+
* 2.6x today. Re-measure the first-sync band before raising this again, or when a deployment's
|
|
76
|
+
* first sync grows more collections than the two-table scenario measured above —
|
|
77
|
+
* `DEFAULT_STRAND_FIRST_SYNC_TIMEOUT_MS` carries the result and `docs/testing.md` the recipe.
|
|
78
|
+
* Nothing warns when the margin goes; the symptom is `StrandAwaitingFirstSyncError` on a join
|
|
79
|
+
* that was progressing normally, which is the failure this pair of numbers exists to end.
|
|
80
|
+
*/
|
|
81
|
+
export const COHORT_READ_DEADLINE_MS = 5000;
|
|
7
82
|
/**
|
|
8
83
|
* How many nodes each block of the **control** (cadre membership) database is replicated
|
|
9
84
|
* to. Chosen to exceed any party's node count, so in practice every control block lands
|
|
@@ -109,6 +184,10 @@ export const CONTROL_REPLICATION_BREADTH = 16;
|
|
|
109
184
|
* whether this node believes a repair answer), which is exactly why the two are now separate
|
|
110
185
|
* numbers rather than one.
|
|
111
186
|
*
|
|
187
|
+
* `cohortQueryTimeoutMs` is declared for the same reason it is declared on the strand policy —
|
|
188
|
+
* the link, not the network ({@link COHORT_READ_DEADLINE_MS}). Absent it, Optimystic's LAN-shaped
|
|
189
|
+
* 1000 ms would leave a control read over a relayed link with no corroborating answer in time.
|
|
190
|
+
*
|
|
112
191
|
* The `satisfies` is load-bearing: without it a mistyped or obsolete key would compile at both
|
|
113
192
|
* this definition and every consumer, because TypeScript only excess-property-checks fresh
|
|
114
193
|
* object literals, not a shared constant handed to `clusterPolicy`.
|
|
@@ -117,6 +196,7 @@ export const CONTROL_CLUSTER_POLICY = Object.freeze({
|
|
|
117
196
|
allowDownsize: true,
|
|
118
197
|
sizeTolerance: 0.5,
|
|
119
198
|
assumedClusterSize: 2,
|
|
199
|
+
cohortQueryTimeoutMs: COHORT_READ_DEADLINE_MS,
|
|
120
200
|
});
|
|
121
201
|
/**
|
|
122
202
|
* Default number of nodes a **strand** network is told its replication cluster should have.
|
|
@@ -257,12 +337,18 @@ export const DEFAULT_STRAND_CLUSTER_SIZE = 4;
|
|
|
257
337
|
* promise that `ceil(0.75 x N)` of its machines are awake, and the admission gate would refuse
|
|
258
338
|
* its writes. Same reason and same warning as {@link CONTROL_CLUSTER_POLICY}'s.
|
|
259
339
|
*
|
|
340
|
+
* `cohortQueryTimeoutMs` is {@link COHORT_READ_DEADLINE_MS}, the same value the control policy
|
|
341
|
+
* declares. That is the one field the two networks deliberately agree on by argument rather than
|
|
342
|
+
* by coincidence: it is a property of the LINK, and a phone's control node and its strand nodes
|
|
343
|
+
* ride the same one.
|
|
344
|
+
*
|
|
260
345
|
* The `satisfies` is load-bearing for the same reason as {@link CONTROL_CLUSTER_POLICY}'s.
|
|
261
346
|
*/
|
|
262
347
|
export const STRAND_CLUSTER_POLICY = Object.freeze({
|
|
263
348
|
allowDownsize: true,
|
|
264
349
|
sizeTolerance: 0.5,
|
|
265
350
|
assumedClusterSize: MIN_CLUSTER_SIZE,
|
|
351
|
+
cohortQueryTimeoutMs: COHORT_READ_DEADLINE_MS,
|
|
266
352
|
});
|
|
267
353
|
/**
|
|
268
354
|
* Resolve the cluster size to hand `createLibp2pNode` for a **strand** network, applying
|
|
@@ -398,46 +484,74 @@ function asKnownMachineCount(servingMachines) {
|
|
|
398
484
|
: undefined;
|
|
399
485
|
}
|
|
400
486
|
/**
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
*
|
|
405
|
-
* The
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
487
|
+
* The base policy with whatever was declared onto it — or the base object ITSELF, by identity,
|
|
488
|
+
* when nothing was, which is the production path for both networks today and so is provably
|
|
489
|
+
* byte-for-byte the old behaviour.
|
|
490
|
+
*
|
|
491
|
+
* The two spreads are independent, so neither declaration can shadow the other: they arrive from
|
|
492
|
+
* unrelated sources (a node-local machine record, the host's network config) and either may be
|
|
493
|
+
* present alone.
|
|
494
|
+
*
|
|
495
|
+
* `cohortQueryTimeoutMs` is passed through UNVALIDATED, by design. Optimystic already refuses a
|
|
496
|
+
* value that is not a finite number above zero, or is above its `MAX_COHORT_QUERY_TIMEOUT_MS`, and
|
|
497
|
+
* it THROWS where the libp2p node is constructed rather than falling back to its own default — so a
|
|
498
|
+
* second check here would only duplicate a message the host already gets, at a site that cannot
|
|
499
|
+
* name the node being built.
|
|
409
500
|
*/
|
|
410
|
-
|
|
411
|
-
const known = asKnownMachineCount(
|
|
412
|
-
if (known === undefined) {
|
|
413
|
-
return
|
|
501
|
+
function declarePolicy({ base, yardstickCap, machines, cohortQueryTimeoutMs }) {
|
|
502
|
+
const known = asKnownMachineCount(machines);
|
|
503
|
+
if (known === undefined && cohortQueryTimeoutMs === undefined) {
|
|
504
|
+
return base;
|
|
414
505
|
}
|
|
415
506
|
return Object.freeze({
|
|
416
|
-
...
|
|
417
|
-
|
|
507
|
+
...base,
|
|
508
|
+
...(known !== undefined && {
|
|
509
|
+
repairCorroborationClusterSize: resolveRepairYardstick(known, yardstickCap)
|
|
510
|
+
}),
|
|
511
|
+
...(cohortQueryTimeoutMs !== undefined && { cohortQueryTimeoutMs })
|
|
418
512
|
});
|
|
419
513
|
}
|
|
420
514
|
/**
|
|
421
|
-
* {@link
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
*
|
|
515
|
+
* {@link CONTROL_CLUSTER_POLICY} with the block-repair corroboration yardstick declared from
|
|
516
|
+
* `enrolledMachines` (see {@link resolveRepairYardstick}) and the per-peer read deadline replaced
|
|
517
|
+
* by the host's `cohortQueryTimeoutMs`; the frozen base object ITSELF when neither is declared, so
|
|
518
|
+
* identity assertions keep holding — including for the host that passes a `network` block with
|
|
519
|
+
* neither field in it, whose declarations arrive present-but-`undefined`.
|
|
520
|
+
*
|
|
521
|
+
* The count is named `enrolledMachines` here, unlike {@link strandClusterPolicy}'s, because for the
|
|
522
|
+
* CONTROL network the two quantities are one and the same by construction: every enrolled machine
|
|
523
|
+
* runs the control node, so the machines enrolled in the party ARE the machines serving this
|
|
524
|
+
* network.
|
|
525
|
+
*/
|
|
526
|
+
export function controlClusterPolicy(declared = {}) {
|
|
527
|
+
return declarePolicy({
|
|
528
|
+
base: CONTROL_CLUSTER_POLICY,
|
|
529
|
+
yardstickCap: CONTROL_REPLICATION_BREADTH,
|
|
530
|
+
machines: declared.enrolledMachines,
|
|
531
|
+
cohortQueryTimeoutMs: declared.cohortQueryTimeoutMs
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* {@link STRAND_CLUSTER_POLICY} with the block-repair corroboration yardstick declared from
|
|
536
|
+
* `servingMachines` — the machines that serve THIS strand — capped at this strand's own
|
|
537
|
+
* `clusterSize` (already resolved by {@link resolveStrandClusterSize}, so it is at least
|
|
538
|
+
* {@link MIN_CLUSTER_SIZE} and the formula's two clamps can never cross), and the per-peer read
|
|
539
|
+
* deadline replaced by the host's `cohortQueryTimeoutMs`; the frozen base object ITSELF when
|
|
540
|
+
* neither is declared.
|
|
541
|
+
*
|
|
542
|
+
* **The no-count path is the production path today.** No authenticated per-strand serving count
|
|
427
543
|
* exists, and the party's enrolled-machine count is emphatically not one (see
|
|
428
|
-
* {@link resolveRepairYardstick}'s contract section), so cadre-core
|
|
429
|
-
* strand node runs the frozen constant. The
|
|
430
|
-
* `StartStrandConfig.servingMachines` stay in place as the seam that
|
|
544
|
+
* {@link resolveRepairYardstick}'s contract section), so cadre-core declares no count and every
|
|
545
|
+
* strand node of a host that declared no deadline runs the frozen constant. The field and its
|
|
546
|
+
* threading through `StartStrandConfig.servingMachines` stay in place as the seam that
|
|
431
547
|
* `backlog/feat-strand-yardstick-from-serving-machines` plugs a real count into.
|
|
432
548
|
*/
|
|
433
|
-
export function strandClusterPolicy(clusterSize,
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
...STRAND_CLUSTER_POLICY,
|
|
440
|
-
repairCorroborationClusterSize: resolveRepairYardstick(known, clusterSize)
|
|
549
|
+
export function strandClusterPolicy(clusterSize, declared = {}) {
|
|
550
|
+
return declarePolicy({
|
|
551
|
+
base: STRAND_CLUSTER_POLICY,
|
|
552
|
+
yardstickCap: clusterSize,
|
|
553
|
+
machines: declared.servingMachines,
|
|
554
|
+
cohortQueryTimeoutMs: declared.cohortQueryTimeoutMs
|
|
441
555
|
});
|
|
442
556
|
}
|
|
443
557
|
//# sourceMappingURL=cluster-size.js.map
|
package/dist/cluster-size.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cluster-size.js","sourceRoot":"","sources":["../src/cluster-size.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAE9C
|
|
1
|
+
{"version":3,"file":"cluster-size.js","sourceRoot":"","sources":["../src/cluster-size.ts"],"names":[],"mappings":"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"}
|
package/dist/compose-strand.js
CHANGED
|
@@ -113,6 +113,14 @@ export async function composeStrand(db, options, platform) {
|
|
|
113
113
|
log('Using injected libp2p node');
|
|
114
114
|
}
|
|
115
115
|
else {
|
|
116
|
+
// NOTE: this path takes the frozen policy whole, so it takes COHORT_READ_DEADLINE_MS
|
|
117
|
+
// with no way to override it — `StrandConnectionOptions` has no counterpart to
|
|
118
|
+
// cadre-core's `NetworkConfig.cohortQueryTimeoutMs`. Fine today: every production
|
|
119
|
+
// strand comes up through cadre-core, which does thread the field, and this path is
|
|
120
|
+
// the plugin's own connect/e2e route where 5000 ms is the right answer anyway. If a
|
|
121
|
+
// plugin embedder ever needs a different deadline,
|
|
122
|
+
// `strandClusterPolicy(clusterSize, { cohortQueryTimeoutMs: <ms> })` is the call to
|
|
123
|
+
// reach for here.
|
|
116
124
|
const created = await platform.createNode({ networkName, bootstrapNodes, fretProfile, port, clusterSize, clusterPolicy: STRAND_CLUSTER_POLICY, storage });
|
|
117
125
|
createdNode = created;
|
|
118
126
|
node = created;
|
|
@@ -168,6 +176,17 @@ export async function composeStrand(db, options, platform) {
|
|
|
168
176
|
// SEAM: this and the Strand apply above are the single composition point
|
|
169
177
|
// where strand-level declarative DDL is applied. Keep new schema wiring
|
|
170
178
|
// here so it stays a one-location edit across Node, browser, and cadre-core.
|
|
179
|
+
//
|
|
180
|
+
// NOTE: neither apply is retried — a failure tears the strand down and throws,
|
|
181
|
+
// and a later connect builds a fresh `Database` and re-hydrates from storage. A
|
|
182
|
+
// failed apply is normally taken back whole (Quereus unwinds its migration steps
|
|
183
|
+
// and verifies the catalog against a pre-apply fingerprint), so the next connect
|
|
184
|
+
// diffs against the state the apply started from. The sApp schema is the one
|
|
185
|
+
// supplied by the EMBEDDER, and the steps that DISCARD data — dropping a table,
|
|
186
|
+
// dropping a column, narrowing a column's type — are irreversible to Quereus's
|
|
187
|
+
// differ: once one has run, any later step that fails leaves the schema partially
|
|
188
|
+
// migrated instead of restored. No schema in this repo evolves that way, so this
|
|
189
|
+
// is a note for whoever first ships a migration that does.
|
|
171
190
|
if (schema) {
|
|
172
191
|
log('Applying sApp schema for strand %s', strandId);
|
|
173
192
|
await db.exec(`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose-strand.js","sourceRoot":"","sources":["../src/compose-strand.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"compose-strand.js","sourceRoot":"","sources":["../src/compose-strand.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { connectToStrand } from './connect.js';
|
|
2
|
-
export { MIN_CLUSTER_SIZE, CONTROL_REPLICATION_BREADTH, CONTROL_CLUSTER_POLICY, DEFAULT_STRAND_CLUSTER_SIZE, STRAND_CLUSTER_POLICY, resolveStrandClusterSize, resolveRepairYardstick, controlClusterPolicy, strandClusterPolicy } from './cluster-size.js';
|
|
2
|
+
export { MIN_CLUSTER_SIZE, COHORT_READ_DEADLINE_MS, CONTROL_REPLICATION_BREADTH, CONTROL_CLUSTER_POLICY, DEFAULT_STRAND_CLUSTER_SIZE, STRAND_CLUSTER_POLICY, resolveStrandClusterSize, resolveRepairYardstick, controlClusterPolicy, strandClusterPolicy } from './cluster-size.js';
|
|
3
3
|
export { wrapStorageWithCache, disposeStorageCache } from './cached-storage.js';
|
|
4
4
|
export type { StrandConnectionOptions, SereusPluginResult, StrandTransactor } from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { connectToStrand } from './connect.js';
|
|
2
|
-
export { MIN_CLUSTER_SIZE, CONTROL_REPLICATION_BREADTH, CONTROL_CLUSTER_POLICY, DEFAULT_STRAND_CLUSTER_SIZE, STRAND_CLUSTER_POLICY, resolveStrandClusterSize, resolveRepairYardstick, controlClusterPolicy, strandClusterPolicy } from './cluster-size.js';
|
|
2
|
+
export { MIN_CLUSTER_SIZE, COHORT_READ_DEADLINE_MS, CONTROL_REPLICATION_BREADTH, CONTROL_CLUSTER_POLICY, DEFAULT_STRAND_CLUSTER_SIZE, STRAND_CLUSTER_POLICY, resolveStrandClusterSize, resolveRepairYardstick, controlClusterPolicy, strandClusterPolicy } from './cluster-size.js';
|
|
3
3
|
export { wrapStorageWithCache, disposeStorageCache } from './cached-storage.js';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACN,gBAAgB,EAChB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACN,gBAAgB,EAChB,uBAAuB,EACvB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
|