@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 +1 -1
- package/src/applied-count.test.mjs +12 -0
- package/src/state-machine.js +13 -1
package/package.json
CHANGED
|
@@ -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);
|
package/src/state-machine.js
CHANGED
|
@@ -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
|
-
|
|
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
|
}
|