Skip to content

Test Suite 8 — Persistence

mchristegh edited this page Jul 10, 2026 · 1 revision
Harness function suite8() in test-scripts/test-harness.js
Checks 18 (the # column below reconciles)
Kind Asynchronous — includes a real ~550 ms wait to simulate an outage past the staleness window

Proves the persist/restore lifecycle end to end using the real cycle.js serialization: state writing, the event-silent quick restore, override survival, the wall-clock outage restore, the transition-silent rule, and file cleanup. All scenarios share one node id (persist-a) across successive instances to model redeploys — except the cleanup scenarios, which use their own ids.

Baseline config (applies unless a scenario says otherwise): persistence on, plain numeric node — mean aggregation, Above-mode, trigger 60 / release 55, quorum 2, staleness 400 ms, Hold policy, heartbeat off.

Traceability convention: the Check column is the harness's literal PASS/FAIL string — a failing line in the test output can be searched in this document verbatim. This document moves with the harness: a new, renamed, or removed check lands here in the same change.


8.1 Write and quick restore

Instance A latches at mean 65 and applies settrigger 62; it closes and instance B constructs with the same id while everything is still fresh.

# Check Protects
1 state file written Meaningful state changes persist to <userDir>/sensorconsensus-state/<id>
2 quick restore is event-silent A redeploy with fresh data produces zero events
3 latch restored consensusState: "triggered" survives the restart
4 aggregate recomputed from restored values The aggregate is recomputed from restored source values, not stored stale
5 source roster restored Both sources return with their identities
6 restored quorum satisfied Freshness re-evaluation found the quick restore healthy

8.2 Override survival across restart

Instance B releases, then lands the mean at 61.5 — between the config trigger (60) and the persisted override (62).

# Check Protects
7 settrigger override survives restart (61.5 vs 62 must not trigger) The discriminating check: only the persisted override explains staying untriggered above the config threshold
8 ...and 62.5 vs 62 triggers The restored override is fully live, not merely present

8.3 Outage restore

After instance B closes, a ~550 ms wait exceeds the 400 ms staleness window before instance C constructs.

# Check Protects
9 outage restore stales both sources Restored staleness is judged against wall-clock time, not the persisted flags
10 restore sourcestale is internally sourced No live message caused these — source: "internal"
11 regression: restore sourcestale shows pre-update quorum:true The restore path matches the live expiry path's documented envelope nuance (quorum seeded before the dispatches)
12 outage restore announces quorumlost A degraded restore is announced, not silently adopted
13 restore is transition-silent (no trigger/release) Restore never fires Trigger/Release by itself — first genuine transition comes from live evaluation
14 outage restore status: yellow ring, held latch prefix intact The exact status string `Triggered

8.4 Cleanup lifecycle

Separate node ids exercising the file lifecycle.

# Check Protects
15 persist-b state file written Precondition for the removal check
16 close(removed) deletes the state file Deleting the node from the flow cleans up its file
17 persist-c file survives non-removal close A redeploy close keeps the file — that's what restore reads
18 constructing with persist:false deletes stale state file Turning persistence off cleans up leftovers rather than orphaning them

Clone this wiki locally