Apr 27, 1-2 PM (44)
Apr 27, 2-3 PM (52)
Apr 27, 3-4 PM (42)
Apr 27, 4-5 PM (36)
Apr 27, 5-6 PM (26)
Apr 27, 6-7 PM (13)
Apr 27, 7-8 PM (26)
Apr 27, 8-9 PM (13)
Apr 27, 9-10 PM (16)
Apr 27, 10-11 PM (42)
Apr 27, 11-12 AM (28)
Apr 28, 12-1 AM (17)
Apr 28, 1-2 AM (8)
Apr 28, 2-3 AM (4)
Apr 28, 3-4 AM (5)
Apr 28, 4-5 AM (5)
Apr 28, 5-6 AM (8)
Apr 28, 6-7 AM (8)
Apr 28, 7-8 AM (37)
Apr 28, 8-9 AM (54)
Apr 28, 9-10 AM (59)
Apr 28, 10-11 AM (53)
Apr 28, 11-12 PM (56)
Apr 28, 12-1 PM (49)
Apr 28, 1-2 PM (54)
Apr 28, 2-3 PM (69)
Apr 28, 3-4 PM (31)
Apr 28, 4-5 PM (14)
Apr 28, 5-6 PM (47)
Apr 28, 6-7 PM (9)
Apr 28, 7-8 PM (9)
Apr 28, 8-9 PM (14)
Apr 28, 9-10 PM (20)
Apr 28, 10-11 PM (34)
Apr 28, 11-12 AM (29)
Apr 29, 12-1 AM (13)
Apr 29, 1-2 AM (1)
Apr 29, 2-3 AM (1)
Apr 29, 3-4 AM (6)
Apr 29, 4-5 AM (1)
Apr 29, 5-6 AM (4)
Apr 29, 6-7 AM (12)
Apr 29, 7-8 AM (45)
Apr 29, 8-9 AM (75)
Apr 29, 9-10 AM (49)
Apr 29, 10-11 AM (28)
Apr 29, 11-12 PM (51)
Apr 29, 12-1 PM (39)
Apr 29, 1-2 PM (21)
Apr 29, 2-3 PM (67)
Apr 29, 3-4 PM (25)
Apr 29, 4-5 PM (36)
Apr 29, 5-6 PM (16)
Apr 29, 6-7 PM (10)
Apr 29, 7-8 PM (14)
Apr 29, 8-9 PM (13)
Apr 29, 9-10 PM (17)
Apr 29, 10-11 PM (25)
Apr 29, 11-12 AM (29)
Apr 30, 12-1 AM (6)
Apr 30, 1-2 AM (8)
Apr 30, 2-3 AM (1)
Apr 30, 3-4 AM (6)
Apr 30, 4-5 AM (2)
Apr 30, 5-6 AM (8)
Apr 30, 6-7 AM (15)
Apr 30, 7-8 AM (17)
Apr 30, 8-9 AM (100)
Apr 30, 9-10 AM (19)
Apr 30, 10-11 AM (50)
Apr 30, 11-12 PM (120)
Apr 30, 12-1 PM (69)
Apr 30, 1-2 PM (45)
Apr 30, 2-3 PM (117)
Apr 30, 3-4 PM (29)
Apr 30, 4-5 PM (34)
Apr 30, 5-6 PM (9)
Apr 30, 6-7 PM (20)
Apr 30, 7-8 PM (23)
Apr 30, 8-9 PM (28)
Apr 30, 9-10 PM (13)
Apr 30, 10-11 PM (25)
Apr 30, 11-12 AM (15)
May 01, 12-1 AM (18)
May 01, 1-2 AM (15)
May 01, 2-3 AM (6)
May 01, 3-4 AM (7)
May 01, 4-5 AM (3)
May 01, 5-6 AM (5)
May 01, 6-7 AM (8)
May 01, 7-8 AM (13)
May 01, 8-9 AM (24)
May 01, 9-10 AM (16)
May 01, 10-11 AM (16)
May 01, 11-12 PM (17)
May 01, 12-1 PM (39)
May 01, 1-2 PM (32)
May 01, 2-3 PM (19)
May 01, 3-4 PM (16)
May 01, 4-5 PM (25)
May 01, 5-6 PM (11)
May 01, 6-7 PM (20)
May 01, 7-8 PM (22)
May 01, 8-9 PM (65)
May 01, 9-10 PM (15)
May 01, 10-11 PM (40)
May 01, 11-12 AM (61)
May 02, 12-1 AM (6)
May 02, 1-2 AM (11)
May 02, 2-3 AM (5)
May 02, 3-4 AM (8)
May 02, 4-5 AM (6)
May 02, 5-6 AM (2)
May 02, 6-7 AM (2)
May 02, 7-8 AM (14)
May 02, 8-9 AM (7)
May 02, 9-10 AM (8)
May 02, 10-11 AM (11)
May 02, 11-12 PM (7)
May 02, 12-1 PM (7)
May 02, 1-2 PM (3)
May 02, 2-3 PM (14)
May 02, 3-4 PM (9)
May 02, 4-5 PM (27)
May 02, 5-6 PM (9)
May 02, 6-7 PM (29)
May 02, 7-8 PM (11)
May 02, 8-9 PM (14)
May 02, 9-10 PM (1)
May 02, 10-11 PM (20)
May 02, 11-12 AM (18)
May 03, 12-1 AM (8)
May 03, 1-2 AM (1)
May 03, 2-3 AM (4)
May 03, 3-4 AM (7)
May 03, 4-5 AM (1)
May 03, 5-6 AM (4)
May 03, 6-7 AM (32)
May 03, 7-8 AM (5)
May 03, 8-9 AM (1)
May 03, 9-10 AM (3)
May 03, 10-11 AM (10)
May 03, 11-12 PM (11)
May 03, 12-1 PM (16)
May 03, 1-2 PM (11)
May 03, 2-3 PM (2)
May 03, 3-4 PM (2)
May 03, 4-5 PM (5)
May 03, 5-6 PM (0)
May 03, 6-7 PM (5)
May 03, 7-8 PM (6)
May 03, 8-9 PM (8)
May 03, 9-10 PM (15)
May 03, 10-11 PM (23)
May 03, 11-12 AM (16)
May 04, 12-1 AM (4)
May 04, 1-2 AM (4)
May 04, 2-3 AM (10)
May 04, 3-4 AM (9)
May 04, 4-5 AM (5)
May 04, 5-6 AM (6)
May 04, 6-7 AM (5)
May 04, 7-8 AM (28)
May 04, 8-9 AM (24)
May 04, 9-10 AM (43)
May 04, 10-11 AM (32)
May 04, 11-12 PM (55)
May 04, 12-1 PM (28)
May 04, 1-2 PM (1)
3,616 commits this week Apr 27, 2026 - May 04, 2026
chore(testnet): align cardano_node_adversary pins to origin/main master
Pulls in master's current shared-image versions:
- sidecar:1ff6913       (post legacy-probe delete, #119)
- tracer-sidecar:5271661 (fork-tree probe build)
- configurator + log-tailer + tracer + cardano-node digests already match
- tx-generator from master is intentionally not added — adversary
  testnet runs nodes only

The adversary container itself stays pinned to its own SHA
(adversary:b75cfe3) since master has no adversary equivalent.

Layer 3 of #123 (perturbation metric emit from finally_tips_agree.sh)
is dropped: that script was deleted on main by #119, the cluster-wide
"did the cluster fork" oracle now lives in tracer-sidecar's fork-tree
probe. Re-implementing the perturbation metric on top of that surface
is a follow-up.
feat(adversary): emit Antithesis SDK assertions to prove the attacker fired
Adds Adversary.SDK with Reachable / Sometimes assertion emitters that
write to \$ANTITHESIS_OUTPUT_DIR/sdk.jsonl (default /tmp/sdk.jsonl).
Wires two assertions into app/Main.hs:

  - reachable("adversary_chain_sync_started", {target_host, point, limit})
    fires once per invocation before connectToNode. Antithesis report
    will show, segmented by target_host, "the adversary fired against
    pN at least once". A host that never gets attacked is visible as
    a missing Reachable hit.

  - sometimes(true|false, "adversary_chain_sync_completed",
              {target_host, tip|reason})
    fires once per invocation on completion. true on clean exit,
    false on connect/protocol failure. Sometimes-true vs Sometimes-
    false buckets quantify how often the adversary actually completed
    a full --limit sync vs being cut short by chaos.

Layer 1 of three for issue #123.
sidecar: delete legacy convergence probes (#119)
Removes:
  - components/sidecar/composer/convergence/eventually_converged.sh
  - components/sidecar/composer/convergence/finally_tips_agree.sh
  - components/sidecar/composer/convergence/serial_driver_tip_agreement.sh
  - components/sidecar/composer/convergence/helper_{sdk,tip_probe}_lib.sh
  - eventually-converged + flaky-chain-sync wrappers from
    sidecar's docker-image.nix (their target scripts are gone)

These were the strict-tip-equality probes flagged in #84 and #119:
they compare hashes at instant T and false-positive on healthy mid-
propagation state. The cluster-wide invariant they were trying to
express is now enforced by tracer-sidecar's fork-tree probe (the
'cluster fork depth < k' AlwaysOrUnreachable assertion plus the
'cluster fork observed' Sometimes coverage check, both passing on
the verification run for this branch).

scripts/smoke-test.sh: drop the eventually_converged.sh exec; the
cardano-cli tip ping above already proves each producer is alive
and serving the chain.

Closes #119 (gates #84 / #81 closure).
tracer-sidecar: wire ForkTree into Spec (#119 step 3)
Adds cluster-wide fork-depth probe to the Spec:

- Extends State with forkTree, forkObserved, forkExceededK
- updateForkTree rule: parses AddedToCurrentChain /
  SwitchedToAFork into Tip records, feeds them to ForkTree
  (recordExtension / setTip), and updates the two derived
  flags
- Sometimes assertion 'cluster fork observed' fires once
  cluster fork depth has been > 0 — proves fault injection
  drives the fork path
- AlwaysOrUnreachable assertion 'cluster fork depth < k'
  fires false the moment depth crosses k = 432

Golden output regenerated to include the two new
declarations.

Phase 1 of #119 (in-memory probe). Persistence (#119 step 4)
and master compose mount (step 5) follow.
tracer-sidecar: accept newer node trace field names
cardano-node 10.7+ ships two breaking changes to the
ChainDB.AddBlockEvent JSON payload that silently dropped
events from any node running a newer version:

  - 'newTipSelectView' renamed to 'newSuffixSelectView'
    (and 'oldTipSelectView' to 'oldSuffixSelectView')
  - inside that view, 'chainLength' renamed to 'blockNo' and
    'kind' changed from 'PraosChainSelectView' to
    'PraosTiebreakerView' (with an extra 'weightBoost' field)

The master testnet pins three different cardano-node images
spanning both schemas.  Before this fix, only the older p1
image was decoded; p2 and p3's events failed FromJSON and
were silently skipped, leaving tracer-sidecar with a
single-host view of the cluster.

Both old and new field names are now accepted (case
fallthrough on .:?).  No semantic change for older nodes.

This was already the right fix on its own merits, and is a
strict prerequisite for the #119 fork-tree probe (which
needs at least two hosts to ever report a non-zero cluster
fork depth).
tracer-sidecar: add pure ForkTree module + tests
ForkTreeState tracks per-host current tips and a global
parent map. Edges are recorded on AddedToCurrentChain
(producer's own extension always captures the true parent);
SwitchedToAFork only updates the host's tip without
recording an edge.

clusterForkDepth = max(tip.chainLength) - commonAncestor.chainLength,
where commonAncestor walks each host's ancestry back (capped
at maxDepth) and intersects to find the deepest shared block.

8 hspec unit tests cover: empty state, sequential extension,
agreement, 1-block fork, root-only common ancestor, deep 5-block
divergence, setTip without edge, depth-cap truncation.

Part of #119 — pure algebra commit; wiring + persistence in
follow-up commits on this branch.
test(uplc-evaluator): address Copilot review comments
- Drop unused waitForError import (was triggering -Wall unused-import).
- Rename local errorPath shadow → errorFilePath in 3 invalid-UUID test
  cases (the local binding is a String-derived path; the imported helper
  takes a UUID, so they cannot be unified — just unshadow).
- Remove stale "(5 second timeout)" comments; the timeout is now driven
  by defaultWaitMs and the comments would mislead future debugging.
- Reword waitForFile haddock: the doesFileExist probe runs *after*
  watcher registration, not before, to cover events that fired before
  we were listening.
fix(darwin): pass CXXFLAGS to node-gyp to suppress Apple Clang 15 enum error
Apple Clang 15+ rejects static_cast<enum>(-1) in constant expressions
(Wenum-constexpr-conversion), causing blake-hash and node-hid to fail
in the Darwin node_modules build. NIX_CFLAGS_COMPILE doesn't reach
node-gyp since it invokes the compiler directly, bypassing the Nix CC
wrapper. Set CXXFLAGS and npm_config_cxxflags before the install scripts
loop — both are read directly by node-gyp.