hiero-ledger / hiero-ledger/hiero-consensus-node

Hand-craft a deterministic test for SCN-001 (same-round judge ancestry stall)

Open
#27,104 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
406
Forks
226
Avg merge
3d 4h
Merged PRs (30d)
210

Description

## Background

`scenarios/SCN-001-same-round-judge-ancestry-stalls-consensus.md` documents a verified
near-miss: under the pre-fix carve-out in `ConsensusImpl#recalculateAndVote`, a judge of
the just-decided round with another same-round judge in its ancestry could end up with a
`roundCreated` smaller than a recalculated ancestor's, violating INV-001 and halting
consensus.

No deterministic test exists. SCN-001 specifies the one that should: build the exact
J1 → A → J2 graph, drive a roster change crafted to promote the intermediate non-judge
under the new roster, assert the inversion appears pre-fix and not post-fix. Caught
originally only by an intermittent JRS test, since retired. `related.tests` is empty;
`verification` is `observed`.

Proof of concept for the epic. **No new framework** — use `TestIntake`,
`TestingEventBuilder`, and the `DeGenTest` style directly. Building it by hand tells us
what the `HandGraph` DSL needs.

## Acceptance Criteria

1. New test in `consensus-hashgraph-impl/src/test/.../consensus/` builds SCN-001's
**Setup** shape: judges `J1`, `J2` of the same round with `J1` an ancestor of `J2`,
and non-judge `A` strictly between them on the ancestry chain.
2. Drives `R_old` → `R_new` such that `A` strongly sees a supermajority of the decided
round's witnesses under `R_new` but not under `R_old`. Use `TestIntake#loadSnapshot`
on a `TestIntake` built with `R_new` — the pattern in
`ConsensusEngineContractTest#bigRosterChangeTest`.
3. Expected values are literals with a derivation comment in the vocabulary of
`concepts/rounds-and-witnesses.md`, `strongly-seeing.md`, `judges.md`. Nothing
captured from a run.
4. Asserts INV-001 directly: `roundCreated(parent) <= roundCreated(child)` for every
event after the metadata reset, via `EventImpl#getRoundCreated()`.
5. Asserts the expected per-round judge set by name, via
`ConsensusRound#getSnapshot().judgeIds()` mapped to the graph's readable hashes.
6. Reverting the `recalculateAndVote` mitigation locally fails the test with a message
naming the inverted ancestor/descendant pair. Record the message in the PR. (A
committed known-bad variant is the epic's mutation-gate follow-on.)
7. Deterministic — no `Randotron`-dependent expectations. Runs in the standard unit test
task, sub-second.
8. Same PR updates SCN-001 frontmatter: `related.tests` cites the test, `verification`
→ `test-reproduced`, Open Questions resolved or narrowed. Follow
`docs/consensus-layer/CLAUDE.md` — do not hand-edit `last_reviewed`.
9. PR description notes what was painful to author by hand, as input to sub-task 2.

## Dependencies

None. Blocks sub-task 2.

Contributor guide

Open the contributing guide

Research direction

Start with scenarios/SCN-001-same-round-judge-ancestry-stalls-consensus.md and the test patterns in ConsensusEngineContractTest#bigRosterChangeTest, using TestIntake, TestingEventBuilder, and the DeGenTest style. Build the J1 → A → J2 setup and roster transition, then run the standard unit test task. Done means the test deterministically checks INV-001 and judge sets, fails against the reverted mitigation, and updates SCN-001 frontmatter as required by docs/consensus-layer/CLAUDE.md.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
distributed-systems, testing
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.