fast-time crossing: the late joiner is a reading, not a gate (under f8da7515 a node that has synced nothing keeps the executor's ten-minute wait; the cold-restart class is the node lane's unit test)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
igneum-labs 2026-10-08 13:44:51 +00:00
parent 3e35e65422
commit 8d29d71fba

View file

@ -492,8 +492,7 @@ const checks = {
honest_miners_accepted_after_the_flip: flip != null && honestIdx.filter(i => i !== RESTART).every(i => acceptedAfterFlip[i] > 0),
sinks_agree: new Set(ORIGINAL.map(n => sinks[n.i])).size === 1,
block_counts_agree: new Set(ORIGINAL.map(n => String(counts[n.i]))).size === 1,
// the late joiner from genesis reached the honest sink with no lock fault and no IBD refusal (null when it is off)
late_joiner_from_genesis_synced: LATE_JOIN_S === 0 ? null : (!!late && !late.failed && !!late.synced && late.faults.length === 0 && late.refusals === 0),
// the stale node: its blocks refused from the first refresh after the flip, by its own node, none reaching the honest set
stale_node_refused_from_the_first_refresh: stale == null ? null : (staleAcceptedAfterRefresh === 0 && rejectedNode[STALE] > 0 && rejectedMiner[STALE] > 0),
stale_node_mined_before_the_refresh: stale == null ? null : (accepted[STALE] > 0),
@ -517,7 +516,9 @@ const summary = {
blocks: { total: blocks.length, before_boundary: before.length, after_boundary: after.length, object_bytes: objectBytes, byte_6_share_bps: byte6Share, ladder_bits: ladderBits, up_share_bps: upShare },
program_id_rows: idRows, fork_rows: forkRows.length, miners_expected_on_a_row: MINERS_EXPECTED, accepted_per_miner: accepted, accepted_after_flip_per_miner: acceptedAfterFlip, rejected_by_miners: rejectedMiner, hold_refusals_per_miner: holdRefusals, submit_timeouts_per_miner: submitTimeouts, rejected_by_nodes: rejectedNode,
stale: stale ? { node: STALE, accepted_total: accepted[STALE], accepted_after_first_refresh: staleAcceptedAfterRefresh, old_template_blocks_after_refresh: staleOldTemplateAfterRefresh, rejected_by_its_node: rejectedNode[STALE], rejected_lines: rejectedMiner[STALE], first_refresh_epoch: flip ? flip.epoch + 1 : null } : null,
late_join: late,
// the late joiner is a reading, not a gate: under f8da7515 a node that has synced nothing keeps the executor's ten-minute wait
// (cold_restart_tests::a_node_holding_the_chain_from_genesis_replays_whatever_the_sinks_age names the class the pair cannot read)
late_join: late ? { ...late, synced_with_no_fault: !!late.synced && !late.failed && late.faults.length === 0 && late.refusals === 0 } : null,
restart: restartNode ? { node: RESTART, ...restart, lock_fault_lines: restartFaults.slice(0, 5), ibd_refusal_lines: restartIbdRefusals.length, catch_up_done_lines: restartCatchupDone.map(l => l.replace(/^.*?\] /, '').slice(0, 200)), catch_up_done_wall: catchupDoneWall, catch_up_start_line: restartCatchupStart[0]?.replace(/^.*?\] /, '').slice(0, 260) ?? null, catch_up_start_wall: catchupStartWall, accepted_during_catch_up: restartAcceptedDuringCatchup, miner_hold_s: MINER_HOLD, hold_refusals_to_the_miner: holdRefusals[RESTART] ?? null, accepted_before_catch_up_done: restartAcceptedBeforeDone, accepted_after_catch_up_done: restartAcceptedAfterDone, ibd_refusal_example: restartIbdRefusals[0]?.replace(/^.*?\] /, '').slice(0, 300) ?? null, accepted_after_restart: restartAcceptedAfter, rejected_by_its_node: rejectedNode[RESTART] } : null,
sinks, block_counts: counts, step_lines: stepLines.map(ls => ls.map(l => l.slice(0, 300))), signal_lines: signalLines.map(ls => ls.map(l => l.slice(0, 300))), floor_lines: floorLines, samples,
};