Skip to content

ci: add spec-tests sync workflows - #610

Merged
GalRogozinski merged 32 commits into
mainfrom
spec-test-ci
Aug 11, 2026
Merged

ci: add spec-tests sync workflows#610
GalRogozinski merged 32 commits into
mainfrom
spec-test-ci

Conversation

@vaclav-ssvlabs

@vaclav-ssvlabs vaclav-ssvlabs commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds GitHub Actions workflows to automatically sync generated spec test JSON files to the dedicated spec-tests repository.

  • generate-spec-tests composite action: sets up Go, runs generators for ssv/qbft/types spectests, copies output to ../spec-tests
  • sync-spec-tests-pr: on PR open/synchronize, pushes generated files to a matching branch in spec-tests repo and creates/updates a mirrored PR
  • sync-spec-tests-merge: on push to main, regenerates files and merges the corresponding spec-tests PR
  • test.yaml: bumped to ubuntu-24.04, node24-compatible action versions

Motivation

  1. The specs are a dependency for ssv-node implementation. The jsons blow up the size of the dependency to an unacceptable level. Compilation errors may occur.
  2. Small changes in spec make huge changes in jsons. This is problematic for modern tools and humans.

GalRogozinski and others added 6 commits February 2, 2026 18:33
Adds GitHub Actions workflows to automatically sync generated spec test
JSON files to a dedicated spec-tests repository on PR open and merge.

- generate-spec-tests composite action: sets up Go, runs generators for
  ssv/qbft/types spectests, copies output to ../spec-tests
- sync-spec-tests-pr: on PR open/sync, pushes generated files to a
  matching branch in spec-tests repo and creates/updates a PR
- sync-spec-tests-merge: on push to main, regenerates files and merges
  the corresponding spec-tests PR
- test.yaml: bumped to ubuntu-24.04, node24-compatible action versions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces GitHub Actions workflows to automatically sync generated spec-test JSON files from ssv-spec to a dedicated spec-tests repository, plus a composite action to consolidate Go setup and generation steps.

  • generate-spec-tests composite action: Consolidates Go setup and go generate steps previously scattered in test.yaml — clean refactor.
  • sync-spec-tests-pr: On PR open/synchronize, generates spec tests and pushes them to a matching branch in the spec-tests repo, creating or updating a mirrored PR. Has two P2 issues: force-pushing to the mirrored PR branch (violates the project's no-force-push-to-PR-branches policy) and using a bare #PR_NUMBER reference in the PR body that will auto-link to the wrong repo.
  • sync-spec-tests-merge: On push to main, regenerates files and merges the corresponding spec-tests PR. Force-push is also present here. The approach of resolving the original PR via commits/{sha}/pulls is sound; the timing caveat is correctly acknowledged.
  • test.yaml: Pinned to ubuntu-24.04 and node24-compatible action versions — straightforward improvement.
  • Both sync workflows validate SPEC_TESTS_REPO only after the expensive generation step; adding an early check would avoid wasted CI minutes when the variable is misconfigured.

Confidence Score: 4/5

  • Safe to merge after addressing the cross-repo PR link bug and acknowledging the force-push trade-off for auto-generated content.
  • The core automation logic is correct and well-structured. The two remaining items are a broken cross-repo reference in the PR body (easy one-line fix) and the force-push pattern which, while flagged by the custom rule, may be intentional for auto-generated content. Neither blocks the primary sync flow.
  • sync-spec-tests-pr.yaml — contains both the cross-repo reference issue and the force-push pattern.

Important Files Changed

Filename Overview
.github/actions/generate-spec-tests/action.yaml New composite action that sets up Go 1.22, runs go generate for ssv/qbft/types spectests, and copies output to ../spec-tests. Logic is sound; the find+copy pattern safely handles multiple spectest directories.
.github/workflows/sync-spec-tests-pr.yaml On PR open/synchronize, generates spec tests and syncs to a matching branch in spec-tests repo. Two issues: (1) force-push to PR branch overwrites review history per custom rule; (2) cross-repo #PR_NUMBER reference in the PR body will link to the wrong repo.
.github/workflows/sync-spec-tests-merge.yaml On push to main, finds the merged PR by commit SHA, pushes final generated files to the spec-tests branch, then merges the mirrored PR. Force-push is present here too. The API timing caveat is acknowledged in the error message.
.github/workflows/test.yaml Refactored to use the new composite action, pinned to ubuntu-24.04 and node24-compatible action versions. Clean and straightforward improvement.

Sequence Diagram

sequenceDiagram
    participant Dev as Developer
    participant SSV as ssv-spec (GitHub)
    participant GHA as GitHub Actions
    participant ST as spec-tests repo

    Dev->>SSV: Open / push to PR branch
    SSV->>GHA: Trigger sync-spec-tests-pr
    GHA->>GHA: checkout + go generate (ssv/qbft/types)
    GHA->>GHA: Get GitHub App token
    GHA->>ST: git clone spec-tests
    GHA->>ST: git checkout -B {branch} origin/{base}
    GHA->>ST: cp generated files + git commit
    GHA->>ST: git push --force origin {branch}
    GHA->>ST: gh pr create / gh pr edit

    Dev->>SSV: Merge PR to main
    SSV->>GHA: Trigger sync-spec-tests-merge
    GHA->>GHA: checkout + go generate (ssv/qbft/types)
    GHA->>SSV: gh api commits/{SHA}/pulls → PR number + head_ref
    GHA->>GHA: Get GitHub App token
    GHA->>ST: git clone spec-tests
    GHA->>ST: git checkout -B {branch} origin/{branch}
    GHA->>ST: cp final generated files + git commit
    GHA->>ST: git push --force origin {branch}
    GHA->>ST: gh pr merge {spec-tests PR} --merge --delete-branch
Loading

Reviews (1): Last reviewed commit: "ci: add spec-tests sync workflows" | Re-trigger Greptile

Comment thread .github/workflows/sync-spec-tests-pr.yaml Outdated
Comment thread .github/workflows/sync-spec-tests-pr.yaml
Comment thread .github/workflows/sync-spec-tests-pr.yaml Outdated
@GalRogozinski

GalRogozinski commented Apr 5, 2026

Copy link
Copy Markdown
Contributor

Thanks @vaclav-ssvlabs
greptile says:

using a bare #PR_NUMBER reference in the PR body that will auto-link to the wrong repo.

Codex:

  1. sync-spec-tests-pr.yaml can succeed without creating anything, but sync-spec-tests-merge.yaml later assumes the branch/PR exists and will fail.

At sync-spec-tests-pr.yaml:108, the PR sync workflow exits early on git diff --cached --quiet with "No changes to sync" and never pushes the branch or opens the PR. But the merge workflow later hard-requires both to exist at sync-spec-tests-merge.yaml:109 and sync-spec-tests-merge.yaml:131. That means an ssv-spec PR that produces no fixture diff against its base branch can still cause the post-merge main workflow to fail. Either the PR workflow needs to create the mirror branch/PR even for the no-op case, or the merge workflow needs to tolerate them being absent.

Probably non issue but still pasting:
2. Fork PRs will fail because this workflow uses a private-key secret on pull_request.

At sync-spec-tests-pr.yaml:34, the workflow unconditionally calls actions/create-github-app-token using SPEC_TESTS_APP_PRIVATE_KEY, but GitHub does not expose repository secrets to fork-originated pull_request runs. If external contributors are expected to open PRs, this job will fail immediately unless it explicitly skips forks or uses a different event model.

@GalRogozinski

GalRogozinski commented Apr 5, 2026

Copy link
Copy Markdown
Contributor

Hey @vaclav-ssvlabs after the known issues, there may be more.

I recommend the following:

  1. On a ci-stage branch we should merge this and Move jsons to spec-tests repo #602. This way we have the complete feature and we don't need the 3 reviews.
  2. For tests, We need to tweak the environment so that the automation will work w.o main being merged. After we are confident we can collect the 3 reviews and merge to main.

wdyt?

I also opened #619 to fix the no changes edge case. Codex claims the greptile bug is a non-issue, but we should verify.
After you review my PR DM me and let's see if we can properly test this.

Resolve no test has changed edge case
GalRogozinski and others added 3 commits April 9, 2026 12:52
Move jsons to spec-tests repo
# Conflicts:
#	qbft/spectest/generate/state_comparison/tests_MsgSpecTest/qbft message msg identifier len == 0.json
#	qbft/spectest/generate/state_comparison/tests_MsgSpecTest/qbft message msg identifier nil.json
#	qbft/spectest/generate/state_comparison/tests_MsgSpecTest/qbft message msg type unknown.json
#	qbft/spectest/generate/state_comparison/tests_MsgSpecTest/qbft message no signers.json
#	qbft/spectest/generate/state_comparison/tests_MsgSpecTest/qbft message signer 0.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_decide_invalid_full_data.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_decide_invalid_msg.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_decide_no_quorum.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_decide_wrong_msg_type.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_decide_wrong_sig.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_full_flow_after_decided.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_commit.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_commit_past_instance.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_commit_past_round.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_non_duplicate_proposal_past_instance.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_prepare.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_prepare_past_instance.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_prepare_past_round.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_proposal.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_proposal_past_instance.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_proposal_past_round.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_round_change.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_round_change_past_instance.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_late_round_change_past_round.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_process_msg_error.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_start_instance_empty_value.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_start_instance_equal_height_running_instance.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_start_instance_invalid_value.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_start_instance_lower_height.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_start_instance_nil_value.json
#	qbft/spectest/generate/tests/tests.ControllerSpecTest_qbft_controller_start_instance_post_future_decided.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_commit_data_!=_acceptedProposalData.Data.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_commit_data_!=_prepared_data.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_commit_future_round.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_commit_past_round.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_duplicate_prepare_msg_justification.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_duplicate_rc_msg_justification.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_duplicate_rc_msg_justification_(prepared).json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_force_stop_commit_message.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_force_stop_prepare_message.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_force_stop_proposal_message.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_force_stop_round_change_message.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_invalid_full_data.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_invalid_prepare_justification_round.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_invalid_prepare_justification_value.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_invalid_proposal_value_check.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_justification_duplicate_msg.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_justification_invalid_round.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_justification_invalid_sig.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_justification_multi_signer.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_multi_signer,_no_overlap.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_multi_signer,_with_overlap.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_no_prepare_quorum_(prepared).json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_no_previous_accepted_proposal.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_no_previous_proposal_for_prepare.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_no_rc_quorum.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_no_rc_quorum_(prepared).json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_prepare_future_round.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_prepare_multi_signer.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_prepare_prev_round.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_prepare_wrong_data.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_proposal_duplicate_message.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_proposal_duplicate_message_different_value.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_proposal_justification_not_highest.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_proposal_multi_signer.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_proposal_past_round_(not_prev_prepared).json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_proposal_post_decided.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_proposal_post_prepare.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_proposal_rc_msg_invalid.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_proposal_rc_msg_invalid_(prepared).json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_round_change_empty_signer.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_round_change_justification_no_quorum.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_round_change_justification_wrong_round.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_round_change_multi_signers.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_round_change_past_round.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_round_change_past_round_quorum.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_round_change_zero_signer.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_round_cutoff_commit_message.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_round_cutoff_prepare_message.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_round_cutoff_proposal_message.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_round_cutoff_round_change_message.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_second_proposal_for_round.json
#	qbft/spectest/generate/tests/tests.MsgProcessingSpecTest_qbft_message_processing_wrong_proposer.json
#	qbft/spectest/generate/tests/tests.MsgSpecTest_qbft_message_msg_identifier_len_==_0.json
#	qbft/spectest/generate/tests/tests.MsgSpecTest_qbft_message_msg_identifier_nil.json
#	qbft/spectest/generate/tests/tests.MsgSpecTest_qbft_message_msg_type_unknown.json
#	qbft/spectest/generate/tests/tests.MsgSpecTest_qbft_message_no_signers.json
#	qbft/spectest/generate/tests/tests.MsgSpecTest_qbft_message_signer_0.json
#	qbft/spectest/generate/tests/timeout.SpecTest_qbft_timeout_round_15.json
#	ssv/spectest/generate/state_comparison/committee_CommitteeSpecTest/empty committee duty.json
#	ssv/spectest/generate/state_comparison/committee_CommitteeSpecTest/start with no shares for duty.json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/decided/1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/decided/1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/decided/1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/decided/1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/decided/1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/decided/1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/decided/30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/decided/30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/decided/30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/decided/30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/decided/30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/decided/30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 1 successful for 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 1 successful for 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 1 successful for 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 1 successful for 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 1 successful for 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 1 successful for 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 1 successful for 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 1 successful for 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 1 successful for 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 1 successful for 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 1 successful for 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 1 successful for 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 2 successful for 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 2 successful for 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 2 successful for 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 2 successful for 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 2 successful for 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 2 successful for 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 2 successful for 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 2 successful for 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 2 successful for 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 2 successful for 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 2 successful for 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/1 fails 2 successful for 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 1 successful for 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 1 successful for 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 1 successful for 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 1 successful for 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 1 successful for 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 1 successful for 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 1 successful for 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 1 successful for 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 1 successful for 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 1 successful for 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 1 successful for 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 1 successful for 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 2 successful for 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 2 successful for 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 2 successful for 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 2 successful for 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 2 successful for 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 2 successful for 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 2 successful for 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 2 successful for 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 2 successful for 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 2 successful for 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 2 successful for 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/failed_than_successful_duties/2 fails 2 successful for 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/happy_flow/1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/happy_flow/1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/happy_flow/1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/happy_flow/1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/happy_flow/1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/happy_flow/1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/happy_flow/30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/happy_flow/30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/happy_flow/30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/happy_flow/30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/happy_flow/30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/happy_flow/30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_does_not_exist/30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_does_not_exist/30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_does_not_exist/30 attestation 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_does_not_exist/30 attestation 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_does_not_exist/30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_does_not_exist/30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_finished/30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_finished/30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_finished/30 attestation 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_finished/30 attestation 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_finished/30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_finished/30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_not_finished/30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_not_finished/30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_not_finished/30 attestation 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_not_finished/30 attestation 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_not_finished/30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/past_msg_duty_not_finished/30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/proposal_with_consensus_data/30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/proposal_with_consensus_data/30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/proposal_with_consensus_data/30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/proposal_with_consensus_data/30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/proposal_with_consensus_data/30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/proposal_with_consensus_data/30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/1 duties 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/1 duties 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/1 duties 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/1 duties 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/1 duties 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/1 duties 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/1 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/1 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/1 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/1 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/1 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/1 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/2 duties 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/2 duties 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/2 duties 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/2 duties 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/2 duties 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/2 duties 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/2 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/2 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/2 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/2 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/2 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/2 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/4 duties 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/4 duties 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/4 duties 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/4 duties 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/4 duties 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/4 duties 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/4 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/4 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/4 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/4 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/4 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_decided_duties/4 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/1 duties 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/1 duties 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/1 duties 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/1 duties 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/1 duties 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/1 duties 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/1 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/1 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/1 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/1 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/1 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/1 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/2 duties 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/2 duties 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/2 duties 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/2 duties 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/2 duties 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/2 duties 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/2 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/2 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/2 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/2 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/2 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/2 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/4 duties 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/4 duties 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/4 duties 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/4 duties 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/4 duties 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/4 duties 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/4 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/4 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/4 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/4 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/4 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/sequenced_happy_flow_duties/4 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/2 duties 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/2 duties 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/2 duties 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/2 duties 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/2 duties 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/2 duties 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/2 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/2 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/2 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/2 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/2 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/2 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/4 duties 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/4 duties 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/4 duties 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/4 duties 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/4 duties 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/4 duties 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/4 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/4 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/4 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/4 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/4 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_decided_duties/4 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/1 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/1 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/1 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/1 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/1 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/1 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/1 duties 8 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/1 duties 8 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/1 duties 8 attestations 8 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/1 duties 8 attestations 8 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/1 duties 8 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/1 duties 8 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/2 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/2 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/2 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/2 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/2 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/2 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/2 duties 8 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/2 duties 8 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/2 duties 8 attestations 8 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/2 duties 8 attestations 8 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/2 duties 8 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/2 duties 8 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/4 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/4 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/4 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/4 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/4 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/4 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/4 duties 8 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/4 duties 8 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/4 duties 8 attestations 8 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/4 duties 8 attestations 8 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/4 duties 8 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_different_validators/4 duties 8 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/1 duties 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/1 duties 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/1 duties 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/1 duties 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/1 duties 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/1 duties 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/1 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/1 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/1 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/1 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/1 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/1 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/2 duties 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/2 duties 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/2 duties 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/2 duties 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/2 duties 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/2 duties 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/2 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/2 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/2 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/2 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/2 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/2 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/4 duties 1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/4 duties 1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/4 duties 1 attestations 1 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/4 duties 1 attestations 1 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/4 duties 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/4 duties 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/4 duties 30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/4 duties 30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/4 duties 30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/4 duties 30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/4 duties 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/shuffled_happy_flow_duties_with_same_validators/4 duties 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_committee_duty_with_missing_shares/attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_committee_duty_with_missing_shares/attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_committee_duty_with_missing_shares/attestations sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_committee_duty_with_missing_shares/attestations sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_committee_duty_with_missing_shares/sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_committee_duty_with_missing_shares/sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_duty/1 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_duty/1 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_duty/1 attestation 1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_duty/1 attestation 1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_duty/1 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_duty/1 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_duty/30 attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_duty/30 attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_duty/30 attestation 30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_duty/30 attestation 30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_duty/30 sync committee (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/start_duty/30 sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/valid_beacon_vote/30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/valid_beacon_vote/30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/wrong_beacon_vote/30 attestations 30 sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/wrong_beacon_vote/30 attestations 30 sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/wrong_message_ID/attestation (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/wrong_message_ID/attestation (phase0).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/wrong_message_ID/sync committees (electra).json
#	ssv/spectest/generate/state_comparison/committee_MultiCommitteeSpecTest/wrong_message_ID/sync committees (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_finished/aggregator (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_finished/aggregator (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_finished/attester and sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_finished/attester and sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_finished/sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_finished/sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_finished/sync committee aggregator.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_not_finished/aggregator (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_not_finished/aggregator (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_not_finished/attester and sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_not_finished/attester and sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_not_finished/sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_not_finished/sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/duplicate_duty_not_finished/sync committee aggregator.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_consensus_not_started/aggregator (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_consensus_not_started/aggregator (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_consensus_not_started/attester and sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_consensus_not_started/attester and sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_consensus_not_started/sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_consensus_not_started/sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_consensus_not_started/sync committee aggregator.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_finished/aggregator (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_finished/aggregator (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_finished/attester and sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_finished/attester and sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_finished/sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_finished/sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_finished/sync committee aggregator.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_first_height/aggregator.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_first_height/attester and sync committee.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_first_height/sync committee aggregator.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_first_height/sync committee.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_not_decided/aggregator (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_not_decided/aggregator (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_not_decided/attester and sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_not_decided/attester and sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_not_decided/sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_not_decided/sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_not_decided/sync committee aggregator.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_decided/aggregator (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_decided/aggregator (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_decided/attester and sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_decided/attester and sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_decided/sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_decided/sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_decided/sync committee aggregator.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_future_decided/aggregator (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_future_decided/aggregator (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_future_decided/attester and sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_future_decided/attester and sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_future_decided/sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_future_decided/sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_future_decided/sync committee aggregator.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_invalid_decided/aggregator (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_invalid_decided/aggregator (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_invalid_decided/attester and sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_invalid_decided/attester and sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_invalid_decided/sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_invalid_decided/sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_invalid_decided/sync committee aggregator.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_wrong_decided/aggregator (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_wrong_decided/aggregator (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_wrong_decided/attester and sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_wrong_decided/attester and sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_wrong_decided/sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_wrong_decided/sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_post_wrong_decided/sync committee aggregator.json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_valid/aggregator (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_valid/aggregator (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_valid/attester and sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_valid/attester and sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_valid/sync committee (electra).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_valid/sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/newduty_MultiStartNewRunnerDutySpecTest/new_duty_valid/sync committee aggregator.json
#	ssv/spectest/generate/state_comparison/synccommitteeaggregator_SyncCommitteeAggregatorProofSpecTest/sync committee aggregator all are aggregators.json
#	ssv/spectest/generate/state_comparison/synccommitteeaggregator_SyncCommitteeAggregatorProofSpecTest/sync committee aggregator none is aggregator.json
#	ssv/spectest/generate/state_comparison/synccommitteeaggregator_SyncCommitteeAggregatorProofSpecTest/sync committee aggregator some are aggregators.json
#	ssv/spectest/generate/state_comparison/tests_MultiMsgProcessingSpecTest/consensus_decided_invalid_value/aggregator (electra).json
#	ssv/spectest/generate/state_comparison/tests_MultiMsgProcessingSpecTest/consensus_decided_invalid_value/aggregator (phase0).json
#	ssv/spectest/generate/state_comparison/tests_MultiMsgProcessingSpecTest/consensus_decided_invalid_value/attester and sync committee (electra).json
#	ssv/spectest/generate/state_comparison/tests_MultiMsgProcessingSpecTest/consensus_decided_invalid_value/attester and sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/tests_MultiMsgProcessingSpecTest/consensus_decided_invalid_value/sync committee (electra).json
#	ssv/spectest/generate/state_comparison/tests_MultiMsgProcessingSpecTest/consensus_decided_invalid_value/sync committee (phase0).json
#	ssv/spectest/generate/state_comparison/tests_MultiMsgProcessingSpecTest/consensus_decided_invalid_value/sync committee contribution.json
#	ssv/spectest/generate/state_comparison/tests_MultiMsgProcessingSpecTest/consensus_future_decided/aggregator (electra).json
#	ssv/spectest/generate/state_comparison/tests_MultiMsgProcessingSpecTest/consensus_future_decided/aggregator (phase0).json
#	ssv/spectest/generate/state_comparison/tests_MultiMsgProcessingSpecTest/consensus_future_de…
@vaclav-ssvlabs
vaclav-ssvlabs force-pushed the spec-test-ci branch 2 times, most recently from cd855c8 to 7379ff6 Compare May 25, 2026 15:21
The install.sh from golangci-lint master is broken (downloads SBOM but
verifies against tarball checksum). Use the official action instead.

@momosh-ssv momosh-ssv left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for putting this together — moving the JSONs to a dedicated repo is a big quality-of-life win. Spent some time walking through the workflows and the path-resolution helpers to make sure I understood the trust and failure-mode story. A few questions and suggestions below — nothing blocking, mostly things we'd love to talk through.

Comment thread types/testingutils/comparable/helpers.go Outdated
Comment thread .github/workflows/sync-spec-tests-pr.yaml Outdated
Comment thread .github/workflows/sync-spec-tests-pr.yaml
Comment thread qbft/spectest/generate/main.go Outdated
Comment thread .github/workflows/sync-spec-tests-merge.yaml
Comment thread .github/workflows/sync-spec-tests-pr.yaml Outdated
Comment thread .github/workflows/sync-spec-tests-pr.yaml
Comment thread .github/workflows/sync-spec-tests-pr.yaml
Comment thread .github/workflows/sync-spec-tests-pr.yaml
Comment thread .github/workflows/sync-spec-tests-merge.yaml
@vaclav-ssvlabs

Copy link
Copy Markdown
Contributor Author

I reacted to all comments regarding workflow, IMHO, the majority of them as very minor/low-risk things. There are a few of them that are worth pursuing, but since this is my last day, I don't have time to follow up and test all the things. So I will leave the solutions for you guys. Good luck!

@GalRogozinski

GalRogozinski commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Picked up the outstanding review threads from @momosh-ssv now that @vaclav-ssvlabs has moved on. Addressed in ada2cb7:

Thread Action
App token shares a runner with go generate Fixedsync-spec-tests-pr is now two jobs: generate (checkout + go generate + upload tarball, no secrets) and sync (download + push with App token, no ssv-spec checkout).
HEAD_REF ref-shape validation Fixed — strict regex guard before it reaches git checkout -B / git push / gh pr create --head.
gh pr view <branch> can return a closed PR Fixedgh pr list --head ... --state open in both pr.yaml and merge.yaml.
PR_TITLE must stay in env: Fixed — invariant documented above the env: block.
Token left in .git/config, PR-number branch namespacing, empty GENERATED_PATHS, no-PR-on-push-to-main, base-ref drift Dropped by the reviewer as low risk — no change.
go.mod-anchored generator paths Already fixed in cc74c02 and confirmed by the reviewer.

Also swapped the sync commit message from #${PR_NUMBER} to the full PR URL, same auto-link issue Greptile flagged for the PR body.

Note the split adds an artifact round-trip (one tarball, since tens of thousands of small JSONs would be far slower uploaded individually) plus one extra runner start per PR. Worth it to keep the token off the same runner as PR-controlled code.

Verified end to end on ada2cb75d: both jobs green, the artifact round-tripped, and the sync job cloned spec-tests, force-pushed spec-test-ci, and the new gh pr list --state open lookup correctly found and updated the existing ssvlabs/spec-tests#5. (Correcting myself — an earlier version of this comment said the repo variables weren't configured yet. They are; the workflow has been running for real.)


Unrelated defect the verified run exposed, not raised by any reviewer, not fixed here since it changes what this PR ships:

The spec-tests output currently contains every generated file twice, under two different path shapes:

types/tests/....json                          <- written directly by the anchored generator
types/spectest/generate/tests/....json        <- copied from the repo by the composite action

Cause: the merge from main in 5354bf5 resurrected 269 JSON files under ssv/spectest/generate/{tests,state_comparison} and types/spectest/generate/{tests,state_comparison} that 860caf4e2 had deleted (main had regenerated them via #601). The composite action's "Copy generated files to spec-tests output directory" step then rakes those stale files in and mirrors them under the old path.

Since cc74c02, every generator writes straight to ../spec-tests/<module>/... via SpecTestsDirForModule, and every reader resolves through SpecTestsDirFrom — I grepped, nothing reads the in-repo */spectest/generate/{tests,state_comparison} paths any more. So the fix is to delete those 269 dead files and drop the now-redundant copy step from the composite action. Worth confirming main won't just resurrect them again on the next merge.

ssvlabs-spec-test-sync Bot added a commit to ssvlabs/spec-tests that referenced this pull request Jul 27, 2026
The merge in 5354bf5 resurrected 269 generated JSON files under
ssv/spectest/generate/{tests,state_comparison} and
types/spectest/generate/{tests,state_comparison}, which 860caf4 had
deleted. main had regenerated them via #601.

Because the composite action also copied any in-repo
*/spectest/generate/{tests,state_comparison} dir into the output,
spec-tests received every vector twice, under two path shapes:

  types/tests/x.json                        <- anchored generator
  types/spectest/generate/tests/x.json      <- copied from the repo

Since cc74c02 the generators write straight to ../spec-tests/<module>
via SpecTestsDirForModule and MkdirAll their own output, and readers
resolve through SpecTestsDirFrom. Nothing reads the in-repo paths, so
delete the vectors and the redundant copy step, keeping the guard that
generation actually produced output.

Verified: a from-scratch `go generate` yields only <module>/{tests,
state_comparison} (2533 files, no spectest/generate shape), and
`make test` passes on all 8 packages.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ssvlabs-spec-test-sync Bot added a commit to ssvlabs/spec-tests that referenced this pull request Jul 27, 2026

@MatheusFranco99 MatheusFranco99 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed with a focus on correctness and the operational surface this adds. The direction is right and the security reasoning in sync-spec-tests-pr.yaml is genuinely above average for CI work — the generate/sync job split, untrusted values passed via env: rather than spliced into shell, the branch-name shape check, the --state open scoping. Those comments explaining why are valuable; please keep them.

Two themes in the findings:

  1. sync-spec-tests-merge.yaml didn't get the same hardening as the PR workflow. The missing branch-name validation there is reachable and can force-push spec-tests main, bypassing the mirror PR. The root cause is that ~60 lines of sync logic are copy-pasted between the two files and have drifted.
  2. Identity of the mirror branch. Keying it on head.ref makes it non-unique across forks and lets it take a protected name; keying it on the PR number removes both problems and most of the validation burden.

Requesting changes on the first of those. Everything else is either a small fix or a question.

Blocking:

  • force-push-to-main path in sync-spec-tests-merge.yaml
  • extract the shared sync script (root cause of the above)
  • branch naming on head.ref

Non-blocking but worth doing now: concurrency groups on both workflows, SHA-pinning the actions in the token-holding jobs, the make lint / CI version divergence, and the local-development docs.

Open question rather than a finding: whether fork PRs are in scope at all — see my comment on the sync job. As written they fail on missing secrets, and that failure is what makes the merge-time path above dangerous.

One nit on the PR description itself: it says the composite action "copies output to ../spec-tests", but the action's own comment correctly notes the generators write there directly and there's nothing to copy. Worth updating so the description doesn't send the next reader looking for a copy step.

Not raised as findings, for the record: the os.RemoveAll on a path outside the repo, the absence of an override for the hardcoded ../spec-tests, and assorted style nits — discussed and deliberately deferred.

Comment thread .github/workflows/sync-spec-tests-merge.yaml
Comment thread .github/workflows/sync-spec-tests-merge.yaml
Comment thread .github/workflows/sync-spec-tests-pr.yaml
Comment thread .github/workflows/sync-spec-tests-pr.yaml
Comment thread .github/workflows/sync-spec-tests-pr.yaml
Comment thread .github/workflows/sync-spec-tests-merge.yaml
Comment thread .github/workflows/sync-spec-tests-pr.yaml Outdated
Comment thread .github/workflows/lint.yaml Outdated
Comment thread .github/workflows/test.yaml
Comment thread .github/workflows/README.md

@iurii-ssv iurii-ssv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple minor things.

Comment thread .github/workflows/README.md Outdated
Comment thread .github/workflows/README.md Outdated
Comment thread qbft/spectest/run_test.go Outdated

@iurii-ssv iurii-ssv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@MatheusFranco99 MatheusFranco99 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving — re-reviewed at b6380e0.

The blocking finding is closed: `25abb89c8` applies the same shape check and `main`/`master` refusal to `PR_HEAD_REF` before it reaches any `git`/`gh` call, and `750163aec` makes the fork check fail closed, so the force-push-to-`spec-tests`-`main` path is unreachable rather than just narrowed. The two design calls I raised alongside it — the shared sync script and PR-number branch naming — I accept as declined: the divergence that motivated the extraction was the missing validation, and the fork skip plus ssv-spec's one-branch-per-name constraint keeps the collision class out of reach without a policy change. Everything non-blocking landed too: PR-workflow `concurrency`, SHA-pinned actions, `make lint` pinned to v2.12.2 with a working installer, the local-development section, and the duplicate fixture tree dropped in `181b69ca4`.

Resolved all my threads. One item stays open by choice, recorded here rather than as a blocker: `sync-spec-tests-merge.yaml` has no serialization, and since every sync replaces the whole generated tree, the merge order of two closely-spaced ssv-spec merges decides what `spec-tests` `main` ends up holding — the runs do share state through `gh pr merge`, even though they clone into separate tmpdirs and push separate branches. The likely outcome is a loud `gh pr merge` failure on the second mirror PR (its merge base predates the first), which needs a human to unstick. Your per-commit group prevents duplicate runs of the same commit rather than interleaving of different ones; a static group with `cancel-in-progress: false` is what actually serializes, at the cost of the middle-run eviction you described. Happy for that to be a follow-up.

@GalRogozinski
GalRogozinski enabled auto-merge (squash) August 10, 2026 08:27
Add a Running Locally section to the CI workflow docs covering the
<parent-of-ssv-spec>/spec-tests/<module> layout, the generate-before-test
order, and the shared-directory caveat for multiple checkouts. Point to it
from the root README.
make lint-prepare installed 'latest' while lint.yaml pins v2.12.2, so
local and CI could run different linter versions. Pin the Makefile to the
same version via GOLANGCI_LINT_VERSION.
sync-spec-tests-merge.yaml used the merged PR's head ref unvalidated in
git checkout -B, git push --force and gh pr list --head. head.ref is a bare
branch name, so a fork PR opened from the fork's default branch yields
'main'; origin/main always exists, so the missing-mirror-branch check at
line 130 cannot catch it and the run force-pushes generated fixtures onto
spec-tests main outside the mirror PR.

Apply the same shape check and main/master refusal that
sync-spec-tests-pr.yaml already performs, at the point the ref is
resolved.
The install.sh served from the golangci-lint master branch fails checksum
verification for v2 releases, so 'make lint-prepare' pinned to v2.12.2
installed nothing:

  hash_sha256_verify checksum for golangci-lint-2.12.2-darwin-arm64.tar.gz
  did not verify

https://golangci-lint.run/install.sh installs the same pinned version
successfully. Same change as #629, kept together with the version pin so
local and CI stay on one version.
Two pushes in quick succession force-push the same mirror branch with
no ordering, so an older commit's fixtures can land last and leave
the mirror stale until the next push.
Fork PRs get no secrets on pull_request, so the pre-merge sync workflow
never worked for them and the merge workflow failed loudly instead.
Post-merge, fork code is already trusted: a human reviewed and merged
it, and the merge workflow already runs go generate from main in the
same job that holds the App token. Pre-merge mirroring for forks would
let any GitHub user trigger App-token writes to spec-tests without
review, which is the risk this change avoids.
The main/master and unsafe-shape checks on PR_HEAD_REF ran before
is-fork was known, so a fork PR opened from its own default branch
(head ref "main") tripped the protected-name refusal and never
reached the fork sync path. Move the is-fork computation earlier and
skip that validation for fork PRs, since their head ref is never used
as a push/checkout target on the fork path.
…path

Each sync in this step replaces the entire generated tree from main,
so the next same-repo merge already carries a fork's fixtures into
spec-tests. A dedicated fork push path only bought a shorter staleness
window at the cost of a second, unaudited write path into spec-tests
— skip the step for fork-originated merges instead.
Codex review of the fork policy found two defects and one wrong claim:

- jq's 'empty' suppresses the whole object, so head_repo: (.head.repo.full_name
  // empty) collapsed PR_INFO when the head repository is gone (deleted fork),
  making the run exit 'No PR found' and never reaching the fork check. Use ""
  instead.
- Unknown head repo now means 'not this repo': skip the sync. There is no mirror
  branch to finalize in that case, and treating it as same-repo risked pushing to
  an unrelated mirror branch.
- The push step gate is 'is-fork == false' rather than '!= true', so a missing
  output fails closed.

README: the 'next in-repo merge' guarantee was too strong. An in-repo PR with no
fixture diff never pushes a mirror branch, so if it merges next its merge run
fails loudly instead of syncing; the sync lands on the following in-repo merge
that has a mirror branch.
…leanly

- README Files table: ../actions/... not ../.github/actions/..., which
  resolved to .github/.github/actions.
- Drop the link to a GITHUB_APP_SETUP.md that does not exist in this repo;
  point at GitHub's own App registration docs and name the two secrets.
- qbft and types spectest TestJson: t.Fatalf instead of panic on a
  spec-tests dir resolution failure, matching ssv/spectest/run_test.go.
Codex review of the branch found three issues in what we changed:

- 'curl ... | sh' reports the exit status of sh, and sh with empty input
  exits 0, so a failed download looked like a successful install. Download
  to a temp file and run it as an &&-chain instead (verified: a 404 URL now
  exits 56 rather than 0).
- The fork comment in the merge sync claimed fixtures reach spec-tests with
  'the next same-repo merge', contradicting the gap documented in README.md.
- The workflows README overview claimed every in-repo PR keeps a mirror PR
  open; PRs whose fixtures match spec-tests never create one.
Tags are mutable refs: whoever controls the action repo can retag
to different code, which then runs inside jobs holding the spec-tests
App private key. Pin checkout, upload/download-artifact,
create-github-app-token, setup-go, and golangci-lint-action to their
resolved commit SHAs (with the version as a trailing comment).

Add .github/dependabot.yml for the github-actions ecosystem so these
pins keep getting bumped instead of going stale.
github-actions with directory '/' scans .github/workflows and a root
action.yml only, so the setup-go pin in .github/actions/generate-spec-tests
would never be bumped. Add that path explicitly.
@GalRogozinski
GalRogozinski merged commit f741c11 into main Aug 11, 2026
@GalRogozinski
GalRogozinski deleted the spec-test-ci branch August 11, 2026 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants