@xmbl/state-machine 0.1.2 → 0.1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmbl/state-machine",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "exports": {
@@ -0,0 +1,12 @@
1
+ // OUTCOME TEST: applied_tx_count after the convergence primitive. The metric the whole fleet reads.
2
+ const { StateMachine } = await import("../index.js");
3
+ const sm = new StateMachine({ dbPath: null });
4
+ sm._dbOpen = false;
5
+ const anchors = Array.from({ length: 3941 }, (_, i) => ({ event: 'task.created', hash: 'h' + i, ts: 1000 + i }));
6
+ const r = await sm.rebuildFromCanonical(anchors);
7
+ const s = sm.getStatistics();
8
+ console.log(`ROOT ${r.state_root.slice(0,10)} applied(returned) ${r.applied} applied_tx_count(published) ${s.totalTransactions}`);
9
+ // idempotence: the same set twice must not double the count
10
+ const r2 = await sm.rebuildFromCanonical(anchors);
11
+ console.log(`SECOND PASS same set: root ${r2.state_root.slice(0,10)} applied_tx_count ${sm.getStatistics().totalTransactions}`);
12
+ process.exit(0);
@@ -273,10 +273,22 @@ export class StateMachine extends EventEmitter {
273
273
  await this.stateTree.clear();
274
274
  this.diffs = [];
275
275
  this._diffIndex.clear();
276
+ // ⛔ RECORD A DIFF FOR EVERY ANCHOR APPLIED, or applied_tx_count IS ZERO BY CONSTRUCTION. This loop wrote
277
+ // straight into the tree and never touched `this.diffs`, which it had just emptied — and
278
+ // getStatistics().totalTransactions is transactionLog.length + diffs.length. So the moment a node runs the
279
+ // convergence primitive, the number the whole fleet reads as "is this node applying anything" resets to 0
280
+ // and STAYS 0 no matter how many anchors it applied. MEASURED 2026-09-15: this node held a correct root
281
+ // over 3,941 applied anchors and published applied_tx_count 0; across the fleet 42 of 46 reporting nodes
282
+ // read 0, and a design ruling was written on the premise that 41 of them had "applied nothing". They had.
283
+ // The diff is not bookkeeping — it is the same StateDiff the block path records, keyed by the anchor's own
284
+ // content, so a rebuild and a live apply of the same anchor upsert to ONE row rather than two.
276
285
  for (const a of list) {
277
286
  if (!a || !a.event || !a.hash) { out.skipped++; continue; }
278
287
  try {
279
- await this.stateTree.insert(`anchor:${a.event}:${a.hash}`, { ts: a.ts ?? null });
288
+ const key = `anchor:${a.event}:${a.hash}`;
289
+ const value = { ts: a.ts ?? null };
290
+ await this.stateTree.insert(key, value);
291
+ this._recordDiff(new StateDiff(key, { [key]: value }));
280
292
  out.applied++;
281
293
  } catch { out.skipped++; }
282
294
  }