Skip to content

feat: merge-train/spartan-v5 - #24272

Merged
PhilWindle merged 13 commits into
v5-nextfrom
merge-train/spartan-v5
Jun 26, 2026
Merged

feat: merge-train/spartan-v5#24272
PhilWindle merged 13 commits into
v5-nextfrom
merge-train/spartan-v5

Conversation

@AztecBot

@AztecBot AztecBot commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

BEGIN_COMMIT_OVERRIDE
test(validator-client): deflake integration test with frozen clock (#24259)
test: retry composed cheat code timestamp race (#24279)
refactor(aztec-node): split server.ts into factory + focused modules (#24283)
refactor(testing): route warpL2Time cheat codes through automine debug RPC (#24303)
feat(node): auto-shutdown node on incompatible canonical rollup upgrade (#24269)
test: deflake e2e_offchain_payment reorg reprocessing race (#24309)
feat(e2e): track per-test setup/hook timings (#24281)
chore(tooling): add monitor-pr skill (#24274)
test: deflake epochs_optimistic_proving reorg-during-proving gate (#24308)
END_COMMIT_OVERRIDE

aminsammara and others added 2 commits June 24, 2026 12:11
Replaces the effectively-dead version checker (ENABLE_VERSION_CHECK /
setupVersionChecker) with an auto-shutdown feature gated by a new
ENABLE_AUTO_SHUTDOWN flag (default false).

A node following the canonical rollup polls the rollup's protocol constants
(genesis archive root, VK tree root, protocol contracts hash) every 10 minutes
via the existing VersionChecker primitive, reusing standby mode's
checkRollupCompatibility diff. When the canonical rollup becomes incompatible
(e.g. a v4->v5 upgrade), the node soft-shuts-down its subsystems while leaving
the HTTP health server listening so K8s probes keep passing on the wound-down
pod. softShutdown deliberately does not process.exit or latch shutdownPromise;
it re-arms SIGTERM/SIGINT so a later pod deletion still exits cleanly.

This is the inverse of standby mode (which blocks startup until the canonical
rollup is compatible). Gated by enableAutoShutdown && networkName != local &&
followsCanonicalRollup (ROLLUP_VERSION unset or canonical). Spartan presets
remain opt-in (false).
…24259)

## Motivation

`ValidatorClient Integration` (`validator.integration.test.ts`) flakes
(~7 failures across `next` and `merge-train/spartan-v5`). The block
re-execution deadline is the slot attestation deadline (~24s) checked
against the date provider's clock. `TestDateProvider` advances with real
wall-clock from the `beforeEach` anchor, so the budget is consumed by
the two heavy fixture setups before re-execution runs. On a slow CI box
a block that should re-execute hits the deadline, processes 0 txs, and
is rejected as an empty non-first block — the rejection the mana-limit
test expects only for the overflowing block.

## Approach

Use the frozen `ManualDateProvider` so re-execution can't race
wall-clock. The two tests that depend on a `retryUntil` timing out now
advance the clock past the attestation deadline so the timeout fires
immediately instead of polling the full window. No assertion changed.

## Changes

- **validator-client (tests)**: `validator.integration.test.ts` uses
`ManualDateProvider`; two timeout-dependent tests advance the clock past
the deadline.

Fixes A-1265

@ludamad ludamad left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Auto-approved

@AztecBot

Copy link
Copy Markdown
Collaborator Author

🤖 Auto-merge enabled after 4 hours of inactivity. This PR will be merged automatically once all checks pass.

@AztecBot
AztecBot added this pull request to the merge queue Jun 24, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 24, 2026
Summary:
- Adds a suite-local retry helper for the composed cheat-code timestamp
race.
- Applies it to the sub-slot warpL2TimeAtLeastBy case and reuses it for
the existing one-second warpL2TimeAtLeastTo case.

Testing:
- yarn build
- ONLY_TERM_PARENT=1 TIMEOUT=20m MAKEFILE_TARGET=yarn-project
end-to-end/scripts/run_test.sh compose
src/composed/e2e_cheat_codes.test.ts
@AztecBot
AztecBot added this pull request to the merge queue Jun 25, 2026
@AztecBot

Copy link
Copy Markdown
Collaborator Author

🤖 Auto-merge enabled after 4 hours of inactivity. This PR will be merged automatically once all checks pass.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 25, 2026
spalladino and others added 5 commits June 25, 2026 12:38
…24283)

## Context

`aztec-node/src/aztec-node/server.ts` had grown to ~2100 lines, mixing
node construction, world-state/witness queries, block and checkpoint
reads, and tx-receipt assembly into one file. This follows the recent
`NodePublicCallsSimulator` extraction to keep the file navigable.

## Approach

`AztecNodeService` keeps its public and RPC surface unchanged — every
extracted method now delegates to a focused collaborator. The work is
split into five self-contained, individually-buildable commits:

- Move `createAndSync` to a free `createAztecNodeService` factory in
`factory.ts` (mirrors `createProverNode`), and convert the
~28-positional constructor to a single `AztecNodeServiceDeps` object.
- Extract the world-state/witness query cluster into
`modules/node_world_state_queries.ts`.
- Extract the
`normalizeBlockParameter`/`isBlockTag`/`isCheckpointTag`/`resolveCheckpointParameter`
block-parameter helpers as pure free functions in
`modules/block_parameter.ts`.
- Extract block and checkpoint reads into
`modules/node_block_provider.ts`.
- Extract `getTxReceipt` and receipt assembly into
`modules/node_tx_receipt.ts`.

The deps-object constructor also surfaced a latent bug in the TXE state
machine, which was passing `VERSION`/`CHAIN_ID` into the
`l1ChainId`/`version` slots swapped (harmless until now since both were
`1`); fixed here.
…g RPC (#24303)

## Context

The `warpL2Time*` cheat codes predate the automine sequencer. They drove
time via the `mineBlock` debug RPC plus direct L1 manipulation:
in-process they shortcut to the automine sequencer, but out-of-process
(the only such caller, `composed/e2e_cheat_codes`) they fell back to a
flaky `eth.warp()` + `mineBlock()` retry loop — flaky enough that it
recently needed a `retryOnFutureTimestampRace` band-aid to stay green.
These helpers are only used in test environments running a local
network, which already defaults to an automine sequencer.

## Approach

- Add `warpL2TimeAtLeastTo` / `warpL2TimeAtLeastBy` to the
`AztecNodeDebug` RPC, wired straight to the `AutomineSequencer`'s
queue-serialized `warpTo`/`warpBy`, mirroring how the existing `prove`
debug RPC works. They throw a `BadRequestError` when no automine
sequencer is running.
- `warpL2TimeAtLeastBy` throws on a non-positive duration;
`warpL2TimeAtLeastTo` no-ops on a past target. The latter removes the
future-timestamp race the band-aid worked around, so
`retryOnFutureTimestampRace` is gone.
- `CheatCodes.warpL2Time*` are now thin `@deprecated` forwarders to the
node debug API; the legacy `eth.warp()` + `mineBlock()` fallback and the
`automine` constructor field are removed, and the class-level
deprecation notice is dropped.

## API changes

`AztecNodeDebug` gains `warpL2TimeAtLeastTo(targetTimestamp)` and
`warpL2TimeAtLeastBy(duration)` in the `aztecDebug` RPC namespace.
`CheatCodes.create` no longer takes an `automine` argument.

Fixes A-1289
…de (#24269)

## What

Replaces the effectively-dead version checker (`ENABLE_VERSION_CHECK` /
`setupVersionChecker`) with an **auto-shutdown** feature, gated by a new
`ENABLE_AUTO_SHUTDOWN` flag (default `false`).

A node following the canonical rollup polls the rollup's protocol
constants (genesis archive root, VK tree root, protocol contracts hash)
every 10 minutes via the existing `VersionChecker` primitive, reusing
standby mode's `checkRollupCompatibility` diff. When the canonical
rollup becomes incompatible (e.g. a v4→v5 upgrade), the node
soft-shuts-down its subsystems while leaving the HTTP health server
listening so K8s probes keep passing on the wound-down pod.

This is the **inverse of standby mode**, which blocks startup until the
canonical rollup is compatible.

## How

- **Config rename** `enableVersionCheck`/`ENABLE_VERSION_CHECK` →
`enableAutoShutdown`/`ENABLE_AUTO_SHUTDOWN`, default flipped
`true`→`false`, across `env_var.ts`, `node-lib` config + mapping, and
the `--enable-auto-shutdown` CLI flag.
- **`util.ts`**: removed the dead `setupVersionChecker` (its
node-version arm never fired). Added `softShutdown(logFn,
signalHandlers)`: awaits the registered handlers via `allSettled`, does
**not** `process.exit` or latch `shutdownPromise`, and re-arms
SIGTERM/SIGINT so a later K8s pod deletion exits cleanly with
`ExitCode.ROLLUP_UPGRADE` (78). The main HTTP server is never pushed
onto `signalHandlers`, so `/status` keeps serving and probes stay green.
- **`standby.ts`**: exported `checkRollupCompatibility` and added
`setupAutoShutdown`, which drives `VersionChecker` (600,000 ms) with a
single `rollup` check — `getLatestVersion` returns `compatible` while
constants match, else a mismatch string; on divergence `VersionChecker`
emits `newVersion` → `softShutdown`. Placed here (not `util.ts`) so the
widely-imported `util.ts` doesn't transitively pull in standby's heavy
`@aztec/accounts/testing` / world-state dependencies.
- **`start_node.ts`**: gated by `enableAutoShutdown && networkName !==
'local' && followsCanonicalRollup` (the last covers `ROLLUP_VERSION`
unset or `canonical`).
- **Spartan**: `network-defaults.yml` renamed to `ENABLE_AUTO_SHUTDOWN:
false` for all three presets (opt-in). The generated `networks.ts` is
gitignored and regenerated at build time.
- **Docs**: updated the generated `cli-reference.md` entry.

## Testing

- New `auto_shutdown.test.ts` (6 tests): `softShutdown` awaits all
handlers, never exits, and re-arms SIGTERM/SIGINT to exit 78; plus
`VersionChecker` compatible/incompatible wiring.
- `node-lib/src/config/index.test.ts` (2 tests): `enableAutoShutdown`
defaults to `false` and parses `ENABLE_AUTO_SHUTDOWN`.
- Full `./bootstrap.sh build yarn-project` passes (build, `format
--check`, `lint --check`, `tsgo -b`).
## Problem

`e2e_offchain_payment.test.ts` › "reprocesses an offchain-delivered
payment after an L1 reorg" flakes (CI run `7d8ad07c73ce84e2`) with:

```
expect(received).toBe(expected) // Object.is equality
  Expected: 100n
  Received: 60n
  > 191 |     expect(aliceAfterRollback).toBe(mintAmount);
```

`60n == 100 - 40`: the reverted transfer's effect was still visible to
the PXE when the post-reorg balance was read, instead of the rolled-back
full mint of `100n`.

## Root cause

A race between the `AutomineSequencer`'s automatic re-mine of the
restored transfer tx and the test's post-reorg assertions:

- `forceReorg` → `revertToCheckpoint(6)` prunes block 7 **and** restores
the un-mined transfer to the pending pool (`p2pClient.sync()` in
`runRevert`, `automine_sequencer.ts:629`), then returns. It does not
itself re-mine.
- The sequencer runs a ~50ms mempool poller
(`automine_sequencer.ts:175`, default `pollIntervalMs` 50ms) whose
`buildIfPending` autonomously re-mines block 7 from the restored pool.
- The PXE has `autoSync: true`, so `get_balance(...).simulate()`
re-syncs before every read. Whether Alice's read at line 191 returns
`100n` (PXE at pruned tip, block 6) or `60n` (PXE re-synced to the
re-mined block 7) depends purely on this timing.

The failed log shows `Updated pxe last block to 7` landing between Bob's
read (passes) and Alice's read (fails); the passed log keeps the PXE
pinned at block 6 across both reads. Both runs show `Building automine
checkpoint {checkpointNumber:7, txCount:1}`, confirming the *poller*
drives the re-mine.

## Fix (test only)

`yarn-project/end-to-end/src/e2e_offchain_payment.test.ts`:

- `forceReorg`: `automine.pause()` *before* `revertToCheckpoint`.
`pause()` gates only the mempool poller; explicit ops
(`revertToCheckpoint`, `buildEmptyBlock`) still run. Pausing before the
transfer is restored to the pool means the poller can never enqueue an
auto re-mine, so the post-reorg assertions observe a stable pruned
state.
- Stay paused through the explicit `forceEmptyBlock()`.
`buildEmptyBlock` (`allowEmpty:true`) permits an empty block but still
drains the pending pool, so it deterministically re-mines the restored
transfer with no poller racing it. The existing `retryUntil` still waits
for the PXE re-sync, so the reprocessing behavior under test is
preserved.
- Add an `afterEach` that calls `getAutomineSequencer()?.resume()`
(idempotent), so a pause is never left dangling.

This removes the nondeterministic auto re-mine that raced the assertions
rather than relaxing the `aliceAfterRollback == 100` assertion — which
is behavioral (it verifies the reorg rolled Alice's note state back) and
is kept. Not a skip, not a `.test_patterns.yml` entry.

## Verification

- `yarn build`: exit 0, no type errors.
- Local e2e red/green not run: the race is nondeterministic (a single
local pass would not prove the fix) and the test is infra-heavy. The fix
is grounded in the log timeline (PXE re-sync to block 7 lands between
Bob's and Alice's reads only in the failed run) and the source mechanism
(poller-driven re-mine gated by `paused`; `buildEmptyBlock` still drains
pending), and was cross-checked to confirm it does not break the later
`retryUntil`.
@AztecBot
AztecBot added this pull request to the merge queue Jun 26, 2026
@AztecBot

Copy link
Copy Markdown
Collaborator Author

🤖 Auto-merge enabled after 4 hours of inactivity. This PR will be merged automatically once all checks pass.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 26, 2026
@AztecBot
AztecBot added this pull request to the merge queue Jun 26, 2026
@AztecBot

Copy link
Copy Markdown
Collaborator Author

🤖 Auto-merge enabled after 4 hours of inactivity. This PR will be merged automatically once all checks pass.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 26, 2026
## What

Adds per-test timing capture to the e2e suite (A-1178, Phase 1),
distinguishing **function-level** time inside our `setup()`/`teardown()`
from **hook-level** time across jest's before/after hooks, and uploads
one JSONL file per test to S3 with a `ci.sh` command to pull a run's
timings back.

This is the PR-independent subset that does not depend on the e2e
consolidation reorg (#24201). The reorg-gated pieces (`wait:*`/compute
body split, multi-node/prover-node start attribution) are deliberately
deferred — those files don't exist on this base.

Fixes A-1180

Fixes A-1181

## How

- **`yarn-project/end-to-end/src/shared/timing_env.mjs`** (new) — a
`TimingEnvironment` subclass of foundation's `CustomEnvironment`. Calls
`await super.handleTestEvent()` first (preserves the base env's
unhandled-rejection patching), then times jest-circus events
(`hook_start`/`hook_success`/`hook_failure` by hook type, `test_fn_*`
for the body, `test_start`/`test_done` for total). Installs a collector
on `this.global` and flushes JSONL on env `teardown`. Entirely gated on
`E2E_TIMING_FILE`; a pure delegate otherwise.
- **`package.json`** — `jest.testEnvironment` →
`./shared/timing_env.mjs`.
- **`fixtures/setup.ts`** — wraps the exported `setup()` and the inner
`teardown` closure (both `ctx.teardown()` and the exported
`teardown(context)` funnel through it) in try/finally, pushing their
durations to `globalThis.__e2eTimings`, tagged with the running test (or
`null` during `beforeAll`/`afterAll`).
- **`ci3/exec_test`** — exports `E2E_TIMING_FILE` and, after the test,
uploads the gzipped file via `cache_s3_transfer_to`.
- **`ci3/run_test_cmd`** — passes the attempt's log id to `exec_test` as
`E2E_LOG_ID` (tracks `rotate_log` on retries).
- **`ci.sh`** — new `e2e-timings <ci_log_id> <folder>` command: `aws s3
cp --recursive` the job's prefix and gunzip each file to
`<log_id>.jsonl`.
- `tsconfig.json` / `eslint.config.js` — exclude/ignore the env `.mjs`
(it imports foundation's env across packages and jest loads it from
source), matching how foundation already ignores its own
`src/jest/*.mjs`.

## JSONL schema (one line per test)

```jsonc
{ "suite":"e2e_fees", "name":"pays fee via private payment", "status":"passed",
  "commit":"abc1234", "branch":"merge-train/spartan-v5", "runId":"177...",
  "startedAt":"2026-06-24T12:00:02.000Z",
  "setupFnMs":42000, "beforeHooksMs":47000, "bodyMs":13000,
  "teardownFnMs":2500, "afterHooksMs":3000, "totalMs":63000 }
```

`beforeAll`/`afterAll` (once per describe) are emitted on a single
suite-scoped line with `name: null`.

## Examples from this PR's CI run

```json5
  // type:"test" — per-test, with beforeEach setup on the test line
  { "suite":"epochs_invalidate_block.parallel", "type":"test",
    "name":"e2e_epochs/epochs_invalidate_block proposer invalidates previous checkpoint…",
    "status":"passed", "setupFnMs":14330, "beforeHooksMs":19357, "bodyMs":179667,
    "teardownFnMs":732, "afterHooksMs":765, "totalMs":199797,
    "startedAt":"2026-06-25T12:58:34.643Z",
    "commit":"1925654a900…", "branch":"spl/a-1178-track-running-times", "runId":"28171484400" }
```

```json5
  // type:"suite" — the former name:null line (beforeAll/afterAll for the whole file)
  { "suite":"e2e_amm", "type":"suite", "name":null, "status":"passed",
    "setupFnMs":32591, "beforeHooksMs":61200, "teardownFnMs":102, "afterHooksMs":103, "totalMs":61303,
    "commit":"1925654a900…", "branch":"spl/a-1178-track-running-times", "runId":"28171484400" }
```

## Storage & retrieval

- S3 object:
`s3://aztec-ci-artifacts/logs/e2e-timings/<CI_LOG_ID>/<LOG_ID>.log.gz`
(gzipped JSONL).
- `CI_LOG_ID` = the job's top-level log id (the decimal id in a job's
`ci.aztec-labs.com/<id>` URL) — per-job, so it's collision-free under
grind.
- `LOG_ID` = the test's individual log id, the same id as the test's log
at `ci.aztec-labs.com/<log_id>`, so a test log maps straight to its
timing file.
- Download: `./ci.sh e2e-timings <ci_log_id> <folder>` →
`<folder>/<LOG_ID>.jsonl` per test (the `suite`/`name` fields inside
identify the test).

## Notes

- References A-1178 / A-1179 / A-1180 / A-1181 (Phase-1 subset; no
auto-closing keywords).
- No `ci-no-squash` label — single commit on merge.
@PhilWindle
PhilWindle requested a review from charlielye as a code owner June 26, 2026 08:54
## Motivation

We already have `fix-pr` (fix CI failures) and `rebase-pr` (resolve base
conflicts) as one-shot dev skills.
What's missing is something that *watches* a PR and keeps it healthy
without manual polling — useful while a
large PR sits in review and the base keeps advancing.

## Approach

Adds a `monitor-pr` skill next to its siblings under
`yarn-project/.claude/skills/`. It babysits a PR on a
~10-minute loop until the PR is green and conflict-free, then stops and
reports.

Each iteration runs a small `check-pr.sh` status script (deps: `gh`,
`git`, `jq`) that snapshots PR/base/head,
mergeable state, whether the branch already contains base-merge-commits,
CI state, and any failed checks with
their log links. Then it acts:

- **CI still pending** → reschedule, do nothing.
- **CI failed** → dispatch a fixer agent with full context (failing
checks + log links + repro). Fixes land in
  **new commits — never amended** — then pushed.
- **Conflicts** → resolve them: **rebase by default**, but **merge the
base in if the branch already contains
  base-merge-commits**, then push.
- **Green + conflict-free** → stop and report.

It composes the existing `fix-pr` and `rebase-pr` skills (and
`identify-ci-failures` /
`flaky-test-fixer-by-claude`) rather than re-deriving their logic.

## Changes

- **`yarn-project/.claude/skills/monitor-pr/SKILL.md`** — the skill
definition.
- **`yarn-project/.claude/skills/monitor-pr/check-pr.sh`** — the
status-snapshot script.
…4308)

## Problem

`e2e_epochs/epochs_optimistic_proving.parallel.test.ts` › "handles a
reorg arriving while the top of the epoch is proving" flakes (e.g. CI
runs `a8d5f346e269c668`, `5039f193fa054832`), timing out at:

```
TimeoutError: Timeout awaiting prover-node sees the prune and recreates session with fewer provers
```

## Root cause

The test installs a `beforeTopTreeProve` gate meant to pause top-tree
proving so the L1 reorg lands at a deterministic point (session parked
mid-proof, all sub-trees done). The gate never actually engaged:

- The hook fires from `TopTreeJob.run()` at the `beforeProve` boundary
(`top-tree-job.ts:198`), which runs *after* `EpochSession` has already
flipped the session state from `awaiting-checkpoints` to `awaiting-root`
(`epoch-session.ts:426-431`).
- The gate predicate looked for a job in `awaiting-checkpoints`, so at
hook time it matched nothing and returned early — never blocking.
(`Top-tree proving gated` appears 0 times in both the failed and passed
CI logs.)

With the gate disabled, the reorg raced real, pipelined sub-tree proving
(`top-tree-orchestrator.ts:85-87`), and the outcome depended on epoch
size:

- **Small gated epoch** (epoch 0, 2 checkpoints, near-instant proving):
a sub-tree was still mid-execution when the prune removed its block →
`world-state ... Unable to get meta data for block 2` → the
`EpochSession` caught the error and went terminal `failed`
(`epoch-session.ts:211-218`) → the prune-reconcile
(`recreateInvalidSessions`, `session-manager.ts:266-269`) found it
already terminal and **deleted it without recreating** → the test's wait
for a trimmed session timed out.
- **Large gated epoch** (4 checkpoints): all sub-trees finished before
the prune, so the session was still non-terminal (`awaiting-root`) and
the prune took the clean cancel-then-recreate path — the test passed.

The flake is the small-epoch case, which is exactly the `2 → 1` survivor
transition the test is meant to cover.

## Fix (test only)


`yarn-project/end-to-end/src/e2e_epochs/epochs_optimistic_proving.parallel.test.ts`:

- Query the session for a job in `awaiting-root` (the state it is
actually in when `beforeProve` fires), keeping the `>= 2` checkpoint
condition.
- Resolve a `gateEntered` signal from *inside* the hook, right before
awaiting the gate, so the gate genuinely blocks and the test learns the
gated epoch only once the session is parked.
- Fire the reorg only after `await executeTimeout(() => gateEntered,
...)`, instead of acting on a transient `awaiting-checkpoints`
observation.

This makes the gate do what its comment always claimed:
deterministically park the session at the top-tree boundary (sub-trees
proven, root prove not yet started) before the reorg. That removes the
sub-tree-vs-prune race — when the reorg fires the session is
non-terminal, so the prune always takes the
cancel-and-recreate-with-survivors path the test verifies. No behavioral
assertion is relaxed; the `>= 2` gating and the final "proven up to the
surviving checkpoint" assertions are unchanged. Not a skip, not a
`.test_patterns.yml` entry.

## Verification

- `yarn build`: exit 0; `yarn lint end-to-end`: clean.
- Local run (`ANVIL_PORT=8600`) passed and reproduced the exact
previously-failing condition — it gated epoch 0 with 2 checkpoints, the
gate engaged this time (`Top-tree proving gated for epoch 0`, absent in
both CI logs), and the recreate path ran (`Prover-node trimmed in-flight
session: 2 → 1 tracked checkpoints`), proving up to the surviving
checkpoint.

## Also in this PR

- Refactored the two proving-gate deferred promises to
`promiseWithResolvers` from `@aztec/foundation/promise`, replacing `new
Promise(resolve => { outerVar = resolve })` with escaped `let`
placeholders.
- Added a TypeScript style note to `yarn-project/CLAUDE.md` preferring
`promiseWithResolvers` for promises settled from outside the executor.

## Note

This flake incidentally exposed a separate product edge, tracked
separately and intentionally not bundled into this test fix: if a reorg
prunes a block out from under an in-flight sub-tree, the `EpochSession`
can go terminal `failed`, and `recreateInvalidSessions` drops terminal
sessions without recreating them (unlike the non-terminal
cancel→recreate path).

This is **not a liveness risk**: the network self-heals (a different
prover node proves the epoch, and publishing dedups against the proven
chain), and the affected node itself usually recovers on the next
checkpoint event for the epoch (a path not gated by `lastTickEpoch`) or
on a process restart. It is durably stuck on a single node only in the
narrow case where no further checkpoint event ever arrives for the
epoch, leaving recovery to the periodic tick — which `lastTickEpoch`
blocks. The likely fix is to classify a prune-induced sub-tree read
fault as a cancellation so the session recreates via the existing tested
path, while keeping the `lastTickEpoch` anti-resubmission guard intact.
@PhilWindle
PhilWindle added this pull request to the merge queue Jun 26, 2026
Merged via the queue into v5-next with commit 5239f8c Jun 26, 2026
17 checks passed
mverzilli added a commit that referenced this pull request Jun 26, 2026
## Why

`merge-train/spartan-v5`
([#24272](#24272))
has landed in `v5-next` and been auto-pulled into this train (merge
commit `34209c32`), so the cross-train build break is now live on the
`merge-train/fairies-v5` tip itself — `yarn-project` no longer compiles
(`make: *** [Makefile:359: yarn-project] Error 1`, in `compile_all`).

## Root cause

In `aztec-node/src/aztec-node/server.ts`:

- spartan-v5's
[#24283](#24283)
(`split server.ts into factory + focused modules`) rewrote the imports
and dropped `inspectBlockParameter` — its own uses moved into
`modules/node_world_state_queries.ts`, which imports it correctly.
- This train's
[#24207](#24207)
(`make node.getContract take an optional reference block`) still calls
`inspectBlockParameter(referenceBlock)` in `getContract`'s
reference-block-not-found error.

The auto-merge took spartan-v5's import block, leaving `getContract`
referencing an unimported symbol → `Cannot find name
'inspectBlockParameter'`.

## Fix

Re-add `inspectBlockParameter` to the existing `@aztec/stdlib/block`
import in `server.ts` (it is the only remaining consumer there, and the
symbol is still exported from that module). One-line change; the error
message is unchanged.

Since the train tip already contains spartan-v5's refactor, this PR's
own CI now builds the actual merged tree, so it verifies the fix
directly.

Refs
[#24223](#24223),
[#24207](#24207),
[#24283](#24283).
rangozd pushed a commit to rangozd/aztec-packages that referenced this pull request Aug 5, 2026
RAW cherry-pick of public merge 5239f8c (-m 1). Conflicts committed as git produced them.
Conflicted: ci.sh (usage block). Resolution in fix(port) commit.
rangozd pushed a commit to rangozd/aztec-packages that referenced this pull request Aug 5, 2026
…esolution

Usage block: added AztecProtocol#24272's test-timings line; kept next's kill description (next's filter-token
kill semantics supersede the instance_name form the source line documents).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants