Skip to content

test(governance): run the ban-chain e2e simulation tests in CI#4450

Merged
sanity merged 1 commit into
mainfrom
test-4301-ban-chain
Jun 16, 2026
Merged

test(governance): run the ban-chain e2e simulation tests in CI#4450
sanity merged 1 commit into
mainfrom
test-4301-ban-chain

Conversation

@sanity

@sanity sanity commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Problem

Issue #4301 asks for an end-to-end simulation-network test of the governance ban chain (rate-limit reject → MAD flag → Normal → … → Evicted → Banned → wire-traffic drop), as the required behavioral gate before flipping governance into Enforce mode on gateways.

The tests themselves already exist: the sim_e2e_tests module in crates/core/src/contract/governance.rs (added in PR #4309) contains governance_ban_chain_end_to_end and popular_contract_with_subscribers_not_evicted. They drive the full production wiring inside a run_controlled_simulation network (1 gateway + 5 nodes):

  • governance_ban_chain_end_to_end — floods an abuser contract with heavy UPDATEs (cost flows through the real Executor → Ring::commit_state_write → report_contract_resource_usage → GovernanceManager::ingest_cost path, driven by the per-node governance_reaper_loop on virtual time), asserts the abuser lands on the per-node ContractBanList (the wire-boundary enforcement signal that node.rs consults to drop banned traffic) and reaches the terminal Banned state, and asserts every honest contract is NOT banned (no collateral damage).
  • popular_contract_with_subscribers_not_evicted — the tracking: contract + peer resource-usage governance #4296 false-positive control: a same-cost contract with many live downstream subscribers is NOT banned on its host, while the zero-beneficiary abuser IS.

The gap this PR closes: those tests never actually ran in CI, so the gate was not enforced and the tests could silently rot. The module is gated behind #[cfg(all(test, feature = "simulation_tests"))] and lives in the lib — it must, because it uses pub(crate) accessors (Ring::governance, Ring::contract_ban_list, the test-only hosting_manager_* counters) that an external tests/ integration binary cannot reach. But:

  • the workspace test job runs the lib tests without simulation_tests, so the module is compiled out there; and
  • the Simulation job enables simulation_tests but only runs specific --test <integration_binary> targets, which excludes lib tests.

So the module fell through the crack between the two jobs and was dead in CI.

Solution

Add --lib to the Simulation job's build (--no-run) and run steps so the lib test binary is compiled and executed alongside the integration binaries. To avoid re-running the ~3000 ordinary freenet lib unit tests (already covered by the workspace test job), the run step restricts execution with a nextest filterset:

kind(test) | (kind(lib) & test(sim_e2e_tests))

i.e. all integration tests plus only the governance sim e2e lib tests.

No production code changes — this is a CI/test wiring fix only.

Testing

Ran the two tests locally under the CI feature set; both pass deterministically:

cargo nextest run -p freenet --no-default-features \
  --features "trace,websocket,redb,wasmtime-backend,testing,simulation_tests" \
  --lib -E 'test(sim_e2e_tests)'
# 2 tests run: 2 passed
#   governance_ban_chain_end_to_end            115.5s
#   popular_contract_with_subscribers_not_evicted  88.3s

Verified via cargo nextest list that the filterset selects exactly the integration tests plus the two sim e2e lib tests (not the other lib unit tests).

Closes #4301

[AI-assisted - Claude]

## Problem

Issue #4301 asks for an end-to-end simulation-network test of the
governance ban chain (rate-limit reject -> MAD flag -> Normal -> ...
-> Evicted -> Banned -> wire-traffic drop), as the required behavioral
gate before flipping governance into Enforce mode on gateways.

The tests themselves already exist: `sim_e2e_tests` in
crates/core/src/contract/governance.rs (added in PR #4309) contains
`governance_ban_chain_end_to_end` and
`popular_contract_with_subscribers_not_evicted`. They drive the full
production wiring inside a `run_controlled_simulation` network
(1 gateway + 5 nodes), assert the abuser lands on the per-node
ContractBanList (the wire-boundary enforcement signal) and reaches the
terminal Banned state, and assert honest / popular-with-subscribers
contracts are NOT banned (no collateral damage).

The gap: those tests never actually ran in CI, so the gate was not
enforced and the tests could silently rot. The module is gated behind
`#[cfg(all(test, feature = "simulation_tests"))]` and lives in the lib
(it must -- it uses `pub(crate)` accessors like `Ring::governance`,
`Ring::contract_ban_list`, and the test-only `hosting_manager_*`
counters that an external tests/ integration binary cannot reach). But:

- the workspace test job runs the lib tests WITHOUT `simulation_tests`,
  so the module is compiled out there; and
- the Simulation job enables `simulation_tests` but only runs specific
  `--test <integration_binary>` targets, which excludes lib tests.

So the module fell through the crack between the two jobs.

## Solution

Add `--lib` to the Simulation job's build (`--no-run`) and run steps so
the lib test binary is compiled and executed alongside the integration
binaries. To avoid re-running the ~3000 ordinary freenet lib unit tests
(already covered by the workspace test job), the run step restricts
execution with a nextest filterset:

    kind(test) | (kind(lib) & test(sim_e2e_tests))

i.e. all integration tests plus only the governance sim e2e lib tests.

No production code changes; this is a CI/test wiring fix only.

## Testing

Ran the two tests locally under the CI feature set and they pass
deterministically:

    cargo nextest run -p freenet --no-default-features \
      --features "trace,websocket,redb,wasmtime-backend,testing,simulation_tests" \
      --lib -E 'test(sim_e2e_tests)'
    # 2 tests run: 2 passed (governance_ban_chain_end_to_end 115.5s,
    #               popular_contract_with_subscribers_not_evicted 88.3s)

Verified the filterset selects exactly the integration tests plus the
two sim e2e lib tests via `cargo nextest list`.

Closes #4301

[AI-assisted - Claude]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Rule Review: No issues found

Rules checked: git-workflow.md
Files reviewed: 1 (.github/workflows/ci.yml)

No rule violations detected.

Assessment details:

  • Commit messagetest(governance): run the ban-chain e2e simulation tests in CI uses the valid test: prefix, is under 72 characters, and the diff comments explain the WHY (issue Phase 7 follow-up: end-to-end simulation test for governance ban chain #4301, pub(crate) accessor constraint preventing use of external test binaries). ✓
  • Single logical change — all modifications are confined to one file and one coherent purpose (enabling --lib + filterset to include in-crate simulation tests in CI). ✓
  • Filterset correctness-E 'kind(test) | (kind(lib) & test(sim_e2e_tests))' correctly targets mod sim_e2e_tests at crates/core/src/contract/governance.rs:2236 and no other modules match that pattern. ✓
  • --lib consistency — flag is added symmetrically to both the --no-run build step and the run step. ✓
  • Inline comments — explain non-obvious constraints (why pub(crate) accessors require lib-level tests, why the filterset avoids re-running 3000 unit tests), which is the project's stated bar for when comments are warranted. ✓
  • Scope — purely a CI/test infrastructure fix; no Rust source changes to audit for unwrap, spawns, retry loops, or similar patterns. ✓

Rule review against .claude/rules/. WARNING findings block merge.

@sanity

sanity commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator Author

Multi-model review — clean

Risk tier: this touches CI configuration (a high-risk surface per the project review rules), so I ran the full review even though the diff is small and test-only. As a subagent I ran the lenses serially.

External model (Codex, gpt-5.5) — clean, no introduced correctness issues. Codex independently reproduced the nextest filterset behavior in a scratch crate and confirmed kind(test) | (kind(lib) & test(sim_e2e_tests)) selects all integration tests plus only the sim_e2e_tests lib tests (excluding ordinary lib unit tests). Verdict: "The workflow change correctly includes the library test target and uses a nextest filter that runs integration tests plus only the intended simulation e2e lib tests. I did not identify any introduced correctness issues in the patch."

Claude lenses (serial):

  • Code-first: the --no-run build step compiles all --lib + --test targets; the run step's -E filter then restricts execution. Consistent.
  • Skeptical: no integration-test regression — previously the run had no -E and ran all tests in the four --test binaries; kind(test) matches exactly those, so coverage is unchanged, plus the 2 sim e2e lib tests. The ~3000 ordinary lib unit tests (already covered by the workspace test job) are NOT re-run.
  • Testing: adds coverage, removes none. Both tests are deterministic (fixed seeds, run_controlled_simulation, seed-derived data — no RNG / wall-clock) and pass locally (governance_ban_chain_end_to_end 115.5s, popular_contract_with_subscribers_not_evicted 88.3s).
  • Big-picture: Phase 7 follow-up: end-to-end simulation test for governance ban chain #4301's intent is that the ban-chain sim test acts as a real gate before the Enforce flip. The tests already existed (PR fix(governance): measure benefit as live beneficiary stock, not decaying subscribe-events (#4296) #4309) but never ran in any CI job — making them run is exactly what fulfills the issue; writing a duplicate test would be wrong. These tests run on PR-level CI and inherit the same non-release-merge_group skip as every other sim test (Skip Simulation and NAT Validation jobs in merge_group #3973), which is the intended, consistent behavior.

No blocking findings. Proceeding once CI is green.

[AI-assisted - Claude]

@sanity sanity added this pull request to the merge queue Jun 16, 2026
Merged via the queue into main with commit f48d967 Jun 16, 2026
16 checks passed
@sanity sanity deleted the test-4301-ban-chain branch June 16, 2026 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Phase 7 follow-up: end-to-end simulation test for governance ban chain

1 participant