@optimystic/db-p2p 1.0.0-beta.1 → 1.0.0-beta.3

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.
Files changed (34) hide show
  1. package/dist/src/cluster/cluster-repo.d.ts +46 -11
  2. package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
  3. package/dist/src/cluster/cluster-repo.js +188 -102
  4. package/dist/src/cluster/cluster-repo.js.map +1 -1
  5. package/dist/src/libp2p-key-network.d.ts.map +1 -1
  6. package/dist/src/libp2p-key-network.js +7 -0
  7. package/dist/src/libp2p-key-network.js.map +1 -1
  8. package/dist/src/logger.d.ts.map +1 -1
  9. package/dist/src/logger.js +13 -6
  10. package/dist/src/logger.js.map +1 -1
  11. package/dist/src/repo/cluster-coordinator.d.ts +42 -0
  12. package/dist/src/repo/cluster-coordinator.d.ts.map +1 -1
  13. package/dist/src/repo/cluster-coordinator.js +50 -9
  14. package/dist/src/repo/cluster-coordinator.js.map +1 -1
  15. package/dist/src/repo/coordinator-repo.d.ts +74 -7
  16. package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
  17. package/dist/src/repo/coordinator-repo.js +327 -80
  18. package/dist/src/repo/coordinator-repo.js.map +1 -1
  19. package/dist/src/storage/storage-repo.d.ts +15 -0
  20. package/dist/src/storage/storage-repo.d.ts.map +1 -1
  21. package/dist/src/storage/storage-repo.js +28 -0
  22. package/dist/src/storage/storage-repo.js.map +1 -1
  23. package/dist/src/testing/mesh-harness.d.ts +15 -0
  24. package/dist/src/testing/mesh-harness.d.ts.map +1 -1
  25. package/dist/src/testing/mesh-harness.js +21 -4
  26. package/dist/src/testing/mesh-harness.js.map +1 -1
  27. package/package.json +2 -2
  28. package/src/cluster/cluster-repo.ts +2749 -2662
  29. package/src/libp2p-key-network.ts +7 -0
  30. package/src/logger.ts +14 -6
  31. package/src/repo/cluster-coordinator.ts +1170 -1113
  32. package/src/repo/coordinator-repo.ts +2940 -2675
  33. package/src/storage/storage-repo.ts +30 -0
  34. package/src/testing/mesh-harness.ts +37 -4
@@ -223,13 +223,15 @@ export declare class ClusterMember implements ICluster {
223
223
  */
224
224
  getExecutedPendResult(messageHash: string): PendResult | undefined;
225
225
  /**
226
- * Commit-shaped sibling of {@link getExecutedPendResult}: local storage's verdict for a commit
227
- * operation applied during consensus, when this member retained one. `CoordinatorRepo.commit`
228
- * consults it after a locally-executed commit-consensus a retained refusal whose cause a local
229
- * re-read confirms as a rival holding the requested revision is returned to the writer as a
230
- * retryable conflict instead of the fabricated success the ahead-divergence tolerance would
231
- * otherwise imply. Same availability caveats as the pend accessor: in-memory only, absent for
232
- * pre-restart applies, pruned on the executed-transaction TTL.
226
+ * Commit-shaped sibling of {@link getExecutedPendResult}: this member's post-reconcile durable
227
+ * verdict for a commit operation applied during consensus, when it retained one `success: true`
228
+ * iff local storage holds the committed revision under the record's action for every block the
229
+ * commit named, after the apply and any behind-reconcile it triggered. `CoordinatorRepo.commit`
230
+ * reads it after a locally-executed commit-consensus, both as this node's own contribution to the
231
+ * durable-holder count its durability gate needs, and for a retained refusal whose cause a
232
+ * local re-read confirms as a rival holding the requested revision — as the trigger for a
233
+ * retryable conflict answer. Same availability caveats as the pend accessor: in-memory only,
234
+ * absent for pre-restart applies, pruned on the executed-transaction TTL.
233
235
  */
234
236
  getExecutedCommitResult(messageHash: string): CommitResult | undefined;
235
237
  /**
@@ -247,10 +249,12 @@ export declare class ClusterMember implements ICluster {
247
249
  update(record: ClusterRecord): Promise<ClusterRecord>;
248
250
  private processUpdate;
249
251
  /**
250
- * Add this member's own conflict-shaped pend verdict to a record's {@link ClusterRecord.applyOutcomes},
251
- * when storage produced one for this transaction. A success, a bare-reason fault, or no retained
252
- * verdict at all leaves the record untouched the coordinator's rule is "an entry means retry",
253
- * so an entry that does not mean retry must not exist.
252
+ * Add this member's own apply verdicts to a record's {@link ClusterRecord.applyOutcomes}, when
253
+ * storage produced any for this transaction. The two arms follow the rules on
254
+ * {@link MemberApplyOutcome}: the pend arm carries ONLY a conflict-shaped refusal (a success, a
255
+ * bare-reason fault, or no retained verdict leaves it off the coordinator's rule is "an entry
256
+ * means retry", so an entry that does not mean retry must not exist); the commit arm carries the
257
+ * retained durable verdict whatever it says, because the coordinator counts the successes.
254
258
  *
255
259
  * The member never signs this and never writes another peer's entry.
256
260
  */
@@ -585,8 +589,39 @@ export declare class ClusterMember implements ICluster {
585
589
  * mid-commit `internalCommit` fault (`success:false` with a bare `reason`, no
586
590
  * `missing`) is propagated so {@link handleConsensus} rolls back the executed marker
587
591
  * and rethrows — exactly like an unexpected thrown fault.
592
+ *
593
+ * Tolerated is not the same as acknowledged. Whatever shape a commit's apply took, this
594
+ * member retains one post-reconcile durable verdict for it ({@link durableCommitVerdict}) and
595
+ * reports it to the coordinator, whose durability gate (`CoordinatorRepo.commit`) acknowledges
596
+ * the writer only when a majority of the cohort reports holding the revision.
588
597
  */
589
598
  private applyConsensusOperation;
599
+ /**
600
+ * Apply one consensus commit to local storage, tolerating every divergence shape the way the
601
+ * doc comment on {@link applyConsensusOperation} describes and reconciling the behind ones.
602
+ * Returns storage's own result — or, for the thrown missing-pend shape, which produces no
603
+ * `CommitResult` at all, a refusal built from the throw — so {@link durableCommitVerdict} works
604
+ * from one uniform shape. Genuine faults (a bare-reason returned failure, an unrecognized throw)
605
+ * propagate so {@link handleConsensus} rolls back the executed marker and rethrows.
606
+ */
607
+ private applyCommitToStorage;
608
+ /**
609
+ * The durable verdict for a consensus commit: `applied` itself when storage landed it (a
610
+ * success from `StorageRepo.commit` means every block is committed, or already was, under this
611
+ * action), otherwise a fresh look at what local storage holds NOW — after the reconcile the
612
+ * refusal triggered. Durable means every block in `commit.blockIds` records `commit.rev` under
613
+ * `commit.actionId`. A refusal that is not durable is returned as-is, so the coordinating node
614
+ * can still classify its own member's ahead-shaped refusal against a rival. A read fault counts
615
+ * as not durable: the gate this feeds fails toward retry.
616
+ */
617
+ private durableCommitVerdict;
618
+ /**
619
+ * True when local storage records `commit.rev` of `blockId` under `commit.actionId`. Read from
620
+ * the revision index (the {@link IRevisionActionReader} capability) so a member whose `latest` has
621
+ * since moved past the revision still counts as holding it; a repo without the capability is
622
+ * judged on `latest` alone.
623
+ */
624
+ private holdsCommittedRevision;
590
625
  /**
591
626
  * Applies a consensus-ordered invalidation on this member: dedup → certificate verification →
592
627
  * capture the invalidation's commit cert (for reactivity reuse) → delegate the compensating write +
@@ -1 +1 @@
1
- {"version":3,"file":"cluster-repo.d.ts","sourceRoot":"","sources":["../../../src/cluster/cluster-repo.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cluster-repo.d.ts","sourceRoot":"","sources":["../../../src/cluster/cluster-repo.ts"],"names":[],"mappings":"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"}
@@ -99,13 +99,17 @@ export class ClusterMember {
99
99
  // a pend that every member refused (rival pending action, or the revision already taken) must
100
100
  // reach the writer as a conflict, not a win. Pruned alongside executedTransactions (same TTL).
101
101
  executedPendResults = new Map();
102
- // Local storage's verdict for a COMMIT operation applied during consensus (messageHash ->
103
- // CommitResult). Retained so the coordinator can detect when the ahead-divergence tolerance in
102
+ // This member's POST-RECONCILE durable verdict for a COMMIT operation applied during consensus
103
+ // (messageHash -> CommitResult): whether local storage holds the committed revision under the
104
+ // record's action once the apply — and any behind-reconcile it triggered — has run. Two readers,
105
+ // which must see the same answer: the coordinating node reads its own member's directly
106
+ // (getExecutedCommitResult), every other member's reaches the coordinator on the response record
107
+ // (withOwnApplyOutcome → ClusterRecord.applyOutcomes[peer].commit). Together they feed the
108
+ // durability gate in CoordinatorRepo.commit, which acknowledges a commit only when a majority of
109
+ // the cohort reports holding it — consensus votes were never evidence of storage. A retained
110
+ // refusal also lets the coordinator detect when the ahead-divergence tolerance in
104
111
  // applyConsensusOperation swallowed a refusal whose real cause was a RIVAL action holding the
105
- // requested revision the commit-tier acknowledgement hole: a commit that assembled consensus
106
- // inside every member's signed-but-not-yet-applied window is refused by every member's storage
107
- // at apply, and without this verdict the coordinator fabricates a success no member durably
108
- // stored. Pruned alongside executedTransactions (same TTL).
112
+ // requested revision. Pruned alongside executedTransactions (same TTL).
109
113
  executedCommitResults = new Map();
110
114
  // Conflict-shaped pend refusals this member's storage produced at consensus-apply, keyed by the
111
115
  // refused action's id rather than by messageHash. The messageHash-keyed map above cannot serve the
@@ -243,13 +247,15 @@ export class ClusterMember {
243
247
  return this.executedPendResults.get(messageHash);
244
248
  }
245
249
  /**
246
- * Commit-shaped sibling of {@link getExecutedPendResult}: local storage's verdict for a commit
247
- * operation applied during consensus, when this member retained one. `CoordinatorRepo.commit`
248
- * consults it after a locally-executed commit-consensus a retained refusal whose cause a local
249
- * re-read confirms as a rival holding the requested revision is returned to the writer as a
250
- * retryable conflict instead of the fabricated success the ahead-divergence tolerance would
251
- * otherwise imply. Same availability caveats as the pend accessor: in-memory only, absent for
252
- * pre-restart applies, pruned on the executed-transaction TTL.
250
+ * Commit-shaped sibling of {@link getExecutedPendResult}: this member's post-reconcile durable
251
+ * verdict for a commit operation applied during consensus, when it retained one `success: true`
252
+ * iff local storage holds the committed revision under the record's action for every block the
253
+ * commit named, after the apply and any behind-reconcile it triggered. `CoordinatorRepo.commit`
254
+ * reads it after a locally-executed commit-consensus, both as this node's own contribution to the
255
+ * durable-holder count its durability gate needs, and for a retained refusal whose cause a
256
+ * local re-read confirms as a rival holding the requested revision — as the trigger for a
257
+ * retryable conflict answer. Same availability caveats as the pend accessor: in-memory only,
258
+ * absent for pre-restart applies, pruned on the executed-transaction TTL.
253
259
  */
254
260
  getExecutedCommitResult(messageHash) {
255
261
  return this.executedCommitResults.get(messageHash);
@@ -472,21 +478,28 @@ export class ClusterMember {
472
478
  return currentRecord;
473
479
  }
474
480
  /**
475
- * Add this member's own conflict-shaped pend verdict to a record's {@link ClusterRecord.applyOutcomes},
476
- * when storage produced one for this transaction. A success, a bare-reason fault, or no retained
477
- * verdict at all leaves the record untouched the coordinator's rule is "an entry means retry",
478
- * so an entry that does not mean retry must not exist.
481
+ * Add this member's own apply verdicts to a record's {@link ClusterRecord.applyOutcomes}, when
482
+ * storage produced any for this transaction. The two arms follow the rules on
483
+ * {@link MemberApplyOutcome}: the pend arm carries ONLY a conflict-shaped refusal (a success, a
484
+ * bare-reason fault, or no retained verdict leaves it off the coordinator's rule is "an entry
485
+ * means retry", so an entry that does not mean retry must not exist); the commit arm carries the
486
+ * retained durable verdict whatever it says, because the coordinator counts the successes.
479
487
  *
480
488
  * The member never signs this and never writes another peer's entry.
481
489
  */
482
490
  withOwnApplyOutcome(record) {
483
- const verdict = this.executedPendResults.get(record.messageHash);
484
- if (verdict === undefined || verdict.success || !isConflictFailure(verdict)) {
491
+ const pend = this.executedPendResults.get(record.messageHash);
492
+ const commit = this.executedCommitResults.get(record.messageHash);
493
+ const own = {
494
+ ...(pend !== undefined && !pend.success && isConflictFailure(pend) ? { pend } : {}),
495
+ ...(commit !== undefined ? { commit } : {})
496
+ };
497
+ if (Object.keys(own).length === 0) {
485
498
  return record;
486
499
  }
487
500
  return {
488
501
  ...record,
489
- applyOutcomes: { ...record.applyOutcomes, [this.peerId.toString()]: { pend: verdict } }
502
+ applyOutcomes: { ...record.applyOutcomes, [this.peerId.toString()]: own }
490
503
  };
491
504
  }
492
505
  /**
@@ -1750,6 +1763,11 @@ export class ClusterMember {
1750
1763
  * mid-commit `internalCommit` fault (`success:false` with a bare `reason`, no
1751
1764
  * `missing`) is propagated so {@link handleConsensus} rolls back the executed marker
1752
1765
  * and rethrows — exactly like an unexpected thrown fault.
1766
+ *
1767
+ * Tolerated is not the same as acknowledged. Whatever shape a commit's apply took, this
1768
+ * member retains one post-reconcile durable verdict for it ({@link durableCommitVerdict}) and
1769
+ * reports it to the coordinator, whose durability gate (`CoordinatorRepo.commit`) acknowledges
1770
+ * the writer only when a majority of the cohort reports holding the revision.
1753
1771
  */
1754
1772
  async applyConsensusOperation(record, operation) {
1755
1773
  const messageHash = record.messageHash;
@@ -1776,7 +1794,17 @@ export class ClusterMember {
1776
1794
  // conflict-shaped refusals are kept — a bare-reason fault is local trouble, not evidence
1777
1795
  // that a rival holds the blocks, and must not veto the cohort's commit.
1778
1796
  if (!result.success && isConflictFailure(result)) {
1779
- this.refusedPendActions.set(operation.pend.actionId, this.now());
1797
+ // `Date.now()`, not the injected `this.now()`: the prune sweep and the executed-marker
1798
+ // timestamps this retention shares a TTL with are both on the wall clock, and a mixed
1799
+ // pair would prune on the first sweep (or never) under an injected clock.
1800
+ this.refusedPendActions.set(operation.pend.actionId, Date.now());
1801
+ }
1802
+ else if (result.success) {
1803
+ // A later apply of the SAME action that storage accepted retires the refusal: the
1804
+ // retention means "the last thing my storage said about this action's pend was no",
1805
+ // and a stale yes-then-no would veto the commit of an action this member now holds
1806
+ // pended, whenever any unrelated rival happens to sit on one of its blocks.
1807
+ this.refusedPendActions.delete(operation.pend.actionId);
1780
1808
  }
1781
1809
  if (!result.success) {
1782
1810
  log('cluster-member:consensus-pend-diverged', {
@@ -1822,87 +1850,16 @@ export class ClusterMember {
1822
1850
  membershipVersion: record.membershipVersion
1823
1851
  });
1824
1852
  }
1825
- let result;
1826
- try {
1827
- result = await this.storageRepo.commit(commit, undefined, proof);
1828
- }
1829
- catch (err) {
1830
- // `StorageRepo.commit` throws (rather than returning success:false) when
1831
- // the pending action is missing the canonical "behind" signal: this
1832
- // member reached commit-consensus without the matching pend (cohort drift).
1833
- if (isMissingPendingActionError(err)) {
1834
- log('cluster-member:consensus-commit-diverged', {
1835
- messageHash,
1836
- actionId: commit.actionId,
1837
- divergence: 'behind',
1838
- reason: err.message
1839
- });
1840
- // We hold no revision of these blocks; pull the committed revision from a
1841
- // cohort peer so the block is no longer under-replicated. Best-effort:
1842
- // failures are logged inside, never thrown (a throw would reset the stream).
1843
- await this.reconcileDivergentCommit(record, commit);
1844
- return;
1845
- }
1846
- throw err;
1847
- }
1848
- // Retain the verdict either way (see getExecutedCommitResult): a success confirms local
1849
- // durability, and an ahead-shaped refusal is the only evidence the coordinator has that
1850
- // the tolerance below swallowed a rival's win at the requested revision. The
1851
- // missing-pending throw path above retains nothing — no CommitResult exists there, and
1852
- // the coordinator's fabricated-success fallback plus cohort reconcile is the right shape
1853
- // for a member that is genuinely behind.
1854
- this.executedCommitResults.set(messageHash, result);
1855
- if (!result.success) {
1856
- // success:false is a StaleFailure. `missing` ⇒ ahead/stale divergence
1857
- // (we already hold ≥ this rev): tolerate, do NOT reconcile downward. A
1858
- // missing-base reason ⇒ behind divergence, reconcile (below). Any other bare
1859
- // `reason` with no `missing` ⇒ a genuine internalCommit fault: propagate so
1860
- // handleConsensus rolls back the executed marker and rethrows.
1861
- //
1862
- // NOTE: this 'ahead' tolerance is what turns a rival's commit that somehow reaches
1863
- // consensus into a reported success no member durably stored (consensus without
1864
- // durability — the commit-tier acknowledgement hole). It must stay: a member
1865
- // genuinely ahead of a redelivered/lagging commit is the common, correct case. The
1866
- // guards live UPSTREAM: `validateCommitRevisions` rejects the rival at the promise
1867
- // round, `CoordinatorRepo.commit` returns lost races as retryable conflicts instead
1868
- // of re-driving them, and the verdict retained just above (getExecutedCommitResult)
1869
- // lets the coordinating node convert its OWN member's rival-confirmed refusal into a
1870
- // conflict answer — that last guard is what closes the signed-but-not-yet-applied
1871
- // window, where two commits for one revision both assemble consensus because signing
1872
- // drops each member's reservation before applying advances its storage —
1873
- // `validateCommitAgainstRefusedPend` now refuses to sign that commit in the first
1874
- // place on any member that refused its pend. If consensus-without-durability is ever
1875
- // observed again, look at those guards' remaining abstain residuals (capability-less
1876
- // or history-truncated storage; a member whose refusal has aged out of retention),
1877
- // not at this branch.
1878
- if (result.missing?.length) {
1879
- log('cluster-member:consensus-commit-diverged', {
1880
- messageHash,
1881
- actionId: commit.actionId,
1882
- divergence: 'ahead',
1883
- reason: result.reason,
1884
- hasMissing: true
1885
- });
1886
- return;
1887
- }
1888
- // This member holds no materializable base for one of the blocks, so
1889
- // `StorageRepo.commit` REFUSED rather than record a revision it could never serve.
1890
- // Same "behind" divergence as a missing pend — and the same cure: pull the committed
1891
- // revision from a cohort peer. Reconciling here (after commit released its per-block
1892
- // latches) is what makes refusing safe; fetching inside the commit path would deadlock
1893
- // against the latch `saveReplicatedBlock` needs to persist what it fetched.
1894
- if (isMissingBaseRevisionFailure(result)) {
1895
- log('cluster-member:consensus-commit-diverged', {
1896
- messageHash,
1897
- actionId: commit.actionId,
1898
- divergence: 'behind',
1899
- reason: result.reason
1900
- });
1901
- await this.reconcileDivergentCommit(record, commit);
1902
- return;
1903
- }
1904
- throw new Error(`Consensus commit for action ${commit.actionId} failed: ${result.reason ?? 'unknown reason'}`);
1905
- }
1853
+ const applied = await this.applyCommitToStorage(record, commit, proof);
1854
+ // Retain the POST-RECONCILE durable verdict (see getExecutedCommitResult and
1855
+ // withOwnApplyOutcome): what this member's storage holds NOW, after any behind-reconcile the
1856
+ // apply triggered — not what the first apply attempt said. A member that pulled the
1857
+ // revision from a cohort peer is a durable holder and reports one; a member that could not
1858
+ // is not, whichever shape its refusal took. The coordinator's durability gate counts these
1859
+ // verdicts its own member's through getExecutedCommitResult, every other member's off the
1860
+ // response record and the two readers must see the same answer, hence one verdict,
1861
+ // computed once, retained here for both.
1862
+ this.executedCommitResults.set(messageHash, await this.durableCommitVerdict(commit, applied));
1906
1863
  return;
1907
1864
  }
1908
1865
  if ('invalidate' in operation) {
@@ -1910,6 +1867,135 @@ export class ClusterMember {
1910
1867
  return;
1911
1868
  }
1912
1869
  }
1870
+ /**
1871
+ * Apply one consensus commit to local storage, tolerating every divergence shape the way the
1872
+ * doc comment on {@link applyConsensusOperation} describes and reconciling the behind ones.
1873
+ * Returns storage's own result — or, for the thrown missing-pend shape, which produces no
1874
+ * `CommitResult` at all, a refusal built from the throw — so {@link durableCommitVerdict} works
1875
+ * from one uniform shape. Genuine faults (a bare-reason returned failure, an unrecognized throw)
1876
+ * propagate so {@link handleConsensus} rolls back the executed marker and rethrows.
1877
+ */
1878
+ async applyCommitToStorage(record, commit, proof) {
1879
+ const messageHash = record.messageHash;
1880
+ let result;
1881
+ try {
1882
+ result = await this.storageRepo.commit(commit, undefined, proof);
1883
+ }
1884
+ catch (err) {
1885
+ // `StorageRepo.commit` throws (rather than returning success:false) when
1886
+ // the pending action is missing — the canonical "behind" signal: this
1887
+ // member reached commit-consensus without the matching pend (cohort drift).
1888
+ if (isMissingPendingActionError(err)) {
1889
+ log('cluster-member:consensus-commit-diverged', {
1890
+ messageHash,
1891
+ actionId: commit.actionId,
1892
+ divergence: 'behind',
1893
+ reason: err.message
1894
+ });
1895
+ // We hold no revision of these blocks; pull the committed revision from a
1896
+ // cohort peer so the block is no longer under-replicated. Best-effort:
1897
+ // failures are logged inside, never thrown (a throw would reset the stream).
1898
+ await this.reconcileDivergentCommit(record, commit);
1899
+ return { success: false, reason: err.message };
1900
+ }
1901
+ throw err;
1902
+ }
1903
+ if (result.success) {
1904
+ return result;
1905
+ }
1906
+ // success:false is a StaleFailure. `missing` ⇒ ahead/stale divergence
1907
+ // (we already hold ≥ this rev): tolerate, do NOT reconcile downward. A
1908
+ // missing-base reason ⇒ behind divergence, reconcile (below). Any other bare
1909
+ // `reason` with no `missing` ⇒ a genuine internalCommit fault: propagate so
1910
+ // handleConsensus rolls back the executed marker and rethrows.
1911
+ //
1912
+ // NOTE: this 'ahead' tolerance is what turns a rival's commit that somehow reaches
1913
+ // consensus into a member-side no-op rather than a stream reset. It must stay: a member
1914
+ // genuinely ahead of a redelivered/lagging commit is the common, correct case. What keeps
1915
+ // the tolerance from turning into an acknowledged write no member stored is downstream:
1916
+ // the durable verdict retained by the caller reports this member as NOT holding the
1917
+ // revision (unless the revision index names this very action — an ahead member that did
1918
+ // land it), and `CoordinatorRepo.commit`'s durability gate acknowledges only a majority of
1919
+ // such reports; a retained refusal whose cause a local re-read confirms as a rival at the
1920
+ // requested revision is answered as a retryable conflict there. Upstream,
1921
+ // `validateCommitRevisions` rejects the rival at the promise round and
1922
+ // `validateCommitAgainstRefusedPend` refuses to sign the commit of a pend this member
1923
+ // refused. If consensus-without-durability is ever observed again, look at the gate's
1924
+ // inputs (a member reporting a durable success it does not hold, or a majority that is
1925
+ // genuinely durable on a forked lineage), not at this branch.
1926
+ if (result.missing?.length) {
1927
+ log('cluster-member:consensus-commit-diverged', {
1928
+ messageHash,
1929
+ actionId: commit.actionId,
1930
+ divergence: 'ahead',
1931
+ reason: result.reason,
1932
+ hasMissing: true
1933
+ });
1934
+ return result;
1935
+ }
1936
+ // This member holds no materializable base for one of the blocks, so
1937
+ // `StorageRepo.commit` REFUSED rather than record a revision it could never serve.
1938
+ // Same "behind" divergence as a missing pend — and the same cure: pull the committed
1939
+ // revision from a cohort peer. Reconciling here (after commit released its per-block
1940
+ // latches) is what makes refusing safe; fetching inside the commit path would deadlock
1941
+ // against the latch `saveReplicatedBlock` needs to persist what it fetched.
1942
+ if (isMissingBaseRevisionFailure(result)) {
1943
+ log('cluster-member:consensus-commit-diverged', {
1944
+ messageHash,
1945
+ actionId: commit.actionId,
1946
+ divergence: 'behind',
1947
+ reason: result.reason
1948
+ });
1949
+ await this.reconcileDivergentCommit(record, commit);
1950
+ return result;
1951
+ }
1952
+ throw new Error(`Consensus commit for action ${commit.actionId} failed: ${result.reason ?? 'unknown reason'}`);
1953
+ }
1954
+ /**
1955
+ * The durable verdict for a consensus commit: `applied` itself when storage landed it (a
1956
+ * success from `StorageRepo.commit` means every block is committed, or already was, under this
1957
+ * action), otherwise a fresh look at what local storage holds NOW — after the reconcile the
1958
+ * refusal triggered. Durable means every block in `commit.blockIds` records `commit.rev` under
1959
+ * `commit.actionId`. A refusal that is not durable is returned as-is, so the coordinating node
1960
+ * can still classify its own member's ahead-shaped refusal against a rival. A read fault counts
1961
+ * as not durable: the gate this feeds fails toward retry.
1962
+ */
1963
+ async durableCommitVerdict(commit, applied) {
1964
+ if (applied.success) {
1965
+ return applied;
1966
+ }
1967
+ try {
1968
+ for (const blockId of commit.blockIds) {
1969
+ if (!(await this.holdsCommittedRevision(blockId, commit))) {
1970
+ return applied;
1971
+ }
1972
+ }
1973
+ }
1974
+ catch (err) {
1975
+ log('cluster-member:consensus-commit-durability-read-error', {
1976
+ actionId: commit.actionId,
1977
+ rev: commit.rev,
1978
+ error: err.message
1979
+ });
1980
+ return applied;
1981
+ }
1982
+ log('cluster-member:consensus-commit-durable-after-reconcile', { actionId: commit.actionId, rev: commit.rev });
1983
+ return { success: true };
1984
+ }
1985
+ /**
1986
+ * True when local storage records `commit.rev` of `blockId` under `commit.actionId`. Read from
1987
+ * the revision index (the {@link IRevisionActionReader} capability) so a member whose `latest` has
1988
+ * since moved past the revision still counts as holding it; a repo without the capability is
1989
+ * judged on `latest` alone.
1990
+ */
1991
+ async holdsCommittedRevision(blockId, commit) {
1992
+ const reader = this.storageRepo;
1993
+ if (typeof reader.getRevisionAction === 'function') {
1994
+ return await reader.getRevisionAction(blockId, commit.rev) === commit.actionId;
1995
+ }
1996
+ const latest = (await this.storageRepo.get({ blockIds: [blockId] }))[blockId]?.state?.latest;
1997
+ return latest?.rev === commit.rev && latest.actionId === commit.actionId;
1998
+ }
1913
1999
  /**
1914
2000
  * Applies a consensus-ordered invalidation on this member: dedup → certificate verification →
1915
2001
  * capture the invalidation's commit cert (for reactivity reuse) → delegate the compensating write +