hiero-ledger / hiero-ledger/hiero-consensus-node
Hand-craft a deterministic test for SCN-001 (same-round judge ancestry stall)
- 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
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