Skip to content

Commit c312317

Browse files
fix(boot): identity-match run re-adoption, not length-only (Test-#11 class)
At boot, when state.activeRunNumber wasn't restored from snapshot, the working set (results.json) was adopted onto a candidate saved run `cand` whenever candData.length === results.length — LENGTH ONLY. Two different full audits of the same ~1052-node chain have identical length, so an interrupted/unsaved working set aliased a saved run's number and a later save overwrote that saved run (the "Test #11" corruption). Fix: require an order-independent content match too — an address|timestamp|mbps key over all rows (each result carries a unique-per-run timestamp). Err STRICT: when the key differs, mint a fresh number (getNextRunNumber, always > max, never collides/overwrites) instead of adopting `cand`. A false-negative is harmless (cosmetic new number); only the old false-positive caused data loss. Adversarially reviewed: timestamps survive the JSON save/load round-trip and genuinely differ between audits; legit restart-after-complete still reuses the right number (saveResults writes identical data to both files); composes correctly with the reserved-number saveCurrentRun fix. Test suite green (188/31/45/35).
1 parent d947f8c commit c312317

1 file changed

Lines changed: 10 additions & 1 deletion

File tree

server.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,16 @@ function rehydrateState(results) {
11331133
const cand = index.activeRun != null ? index.activeRun
11341134
: (index.runs.length > 0 ? index.runs[index.runs.length - 1].number : null);
11351135
const candData = cand != null ? loadRun(cand) : null;
1136-
const reused = candData && candData.length === results.length;
1136+
// Strengthen "is the working set the SAME run as `cand`?" beyond length:
1137+
// two DIFFERENT audits of the same chain set have identical length but
1138+
// different per-node timestamps/speeds. Matching on length alone aliased
1139+
// them, so a later save overwrote a real saved run (the "Test #11"
1140+
// corruption). Compare an order-independent content key; err STRICT (fresh
1141+
// number when unsure) — a fresh number can never overwrite a saved run.
1142+
const _runKey = rows => rows.map(r => `${r.address}|${r.timestamp || ''}|${r.actualMbps == null ? 'x' : r.actualMbps}`).sort().join('\n');
1143+
const reused = candData
1144+
&& candData.length === results.length
1145+
&& _runKey(candData) === _runKey(results);
11371146
state.activeRunNumber = reused ? cand : getNextRunNumber();
11381147
// When we assigned a FRESH number (not reusing a saved run), reserve it by
11391148
// persisting it into the snapshot immediately. getNextRunNumber() only

0 commit comments

Comments
 (0)