# Lodestar × Gloas: EIP-8282, EIP-7688, EIP-8045, EIP-8061 spec-conformance review

Item `lodestar`, batch `cl-misc`. This is a read-only review of public sources. No node, network or test was run. Source code was read from shallow git clones; commit hashes came from `api.github.com`.

## 1. Pins

| Repo | Ref | Commit (pinned) | Commit date |
|---|---|---|---|
| ChainSafe/lodestar | `unstable` | `e4b4f615e68c1a4ea7c57632e6ed8d824624573f` | 2026-10-27T17:31:55Z |
| ethereum/consensus-specs | `master` | `8a80ffa82bd49aac0dd6db17f9e8150aa257fbc2` | 2026-10-27T16:28:12Z |
| Consensys/teku (the name `Consensys-Incorporated/teku` redirects here) | `master` | `2c35574b3373cbe8ad121a768d98f066aec05b73` | 2026-10-27T16:51:17Z |
| consensus-specs tag `v1.7.0-beta.4` | tag | `aa16bb4c156184e9548a997d53efaf2a228a6304` | — |

Citation convention:
- `LS:path#La-Lb` means `https://github.com/ChainSafe/lodestar/blob/e4b4f615e68c1a4ea7c57632e6ed8d824624573f/path#La-Lb`.
- `CS:file#La-Lb` means `https://github.com/ethereum/consensus-specs/blob/8a80ffa82bd49aac0dd6db17f9e8150aa257fbc2/specs/gloas/file#La-Lb`.
- `TK:path#La-Lb` means `https://github.com/Consensys/teku/blob/2c35574b3373cbe8ad121a768d98f066aec05b73/path#La-Lb`.

**Which spec version Lodestar targets:** `v1.7.0-beta.4`.
- `LS:packages/beacon-node/test/spec-tests-version.json#L3` contains `"specVersion": "v1.7.0-beta.4"`.
- The onboarding code links to `v1.7.0-alpha.8/specs/gloas/fork.md` (`LS:packages/state-transition/src/slot/upgradeStateToGloas.ts#L179`). Its logic is the beta.4 version.

**How master differs from beta.4:** I diffed the four Gloas spec files the brief names, plus `fork.md`.
- `validator.md`, `p2p-interface.md` and `weak-subjectivity.md` are identical.
- `beacon-chain.md` differs in one docstring typo only (`EIP-7521` → `EIP-7251`, line 1481).
- `fork.md` differs in `onboard_builders_from_pending_deposits`, from consensus-specs PR #5736 "Separate builder and validator deposits at the Gloas fork" (merged 2026-10-26T19:16:28Z).
- **Lodestar lags master on that onboarding change** (candidate C1).

## 2. Candidates

### C1: spec-version lag. Builder onboarding at the Gloas fork follows beta.4, not master (PR #5736)

**(1) Spec, master** (`CS:fork.md#L65-L121`, https://github.com/ethereum/consensus-specs/blob/8a80ffa82bd49aac0dd6db17f9e8150aa257fbc2/specs/gloas/fork.md):

> During this pass:
> - Only deposits with builder withdrawal credentials can fund builders.
> - Other deposits stay queued, even if a builder uses the same public key.
> - A valid builder registration can use a validator's public key.

```python
    for deposit in state.pending_deposits:
        # Only builder-credential deposits can fund builders at the fork.
        if not is_builder_withdrawal_credential(deposit.withdrawal_credentials):
            pending_deposits.append(deposit)
            continue
        builder_pubkeys = [builder.pubkey for builder in state.builders]
        if deposit.pubkey not in builder_pubkeys:
            if not is_valid_deposit_signature(...):
                # Preserve validator top-ups when no builder can receive them.
                if deposit.pubkey in validator_pubkeys or is_pending_validator(
                    pending_deposits, deposit.pubkey
                ):
                    pending_deposits.append(deposit)
                continue
            add_builder_to_registry(...)
        else:
            ...state.builders[builder_index].balance += deposit.amount
```

beta.4 (`https://raw.githubusercontent.com/ethereum/consensus-specs/v1.7.0-beta.4/specs/gloas/fork.md`, lines 70-119) is different in three ways:
- It first keeps every deposit whose pubkey is an existing validator: `if deposit.pubkey in validator_pubkeys: pending_deposits.append(deposit); continue`.
- It checks `is_builder_withdrawal_credential` only when the pubkey is not yet a builder.
- It keeps a deposit when `is_pending_validator(...)` holds, and checks that before the signature.

**(2) Lodestar** (`LS:packages/state-transition/src/slot/upgradeStateToGloas.ts#L208-L246`):

```ts
    // Deposits for existing validators stay in the pending queue
    if (isValidatorKnown(state, validatorIndex)) {
      pendingDeposits.push(deposit);
      ...
      continue;
    }
    const builderIndex = builderIndexByPubkey.get(pubkeyHex);
    if (builderIndex !== undefined) {
      // Top up an already-onboarded builder
      state.builders.get(builderIndex).balance += deposit.amount;
      ...
      continue;
    }
    if (!isBuilderWithdrawalCredential(deposit.withdrawalCredentials)) {
      pendingDeposits.push(deposit); ... continue;
    }
    if (
      pendingDepositsLookup.hasPendingValidator(state.config, pubkeyHex, state.epochCtx.builderDepositSignatureCache)
    ) {
      pendingDeposits.push(deposit); ... continue;
    }
```

The invalid-signature case then drops the deposit (`#L267-L271`: `if (!isValid) { dropped++; continue; }`).

**(3) When the results differ.** These cases apply to the state produced by the fork upgrade at the first slot of `GLOAS_FORK_EPOCH`, judged against master:
- **(a)** A pending deposit has builder (0xB0) credentials and a valid proof-of-possession, and its pubkey already belongs to a validator.
  - Master registers a new builder and removes the deposit from the queue.
  - Lodestar leaves it queued, so it later tops up the validator.
- **(b)** A pending deposit has non-builder credentials (0x00/0x01/0x02) and its pubkey was onboarded as a builder by an earlier deposit in the same queue.
  - Master leaves it queued; it later creates or tops up a validator.
  - Lodestar adds its amount to the builder's balance and removes it from the queue.
- **(c)** A builder-credential deposit has a valid signature, its pubkey is not yet a builder, and an earlier pending deposit for the same pubkey is a valid validator deposit (`is_pending_validator`).
  - Master registers the builder.
  - Lodestar keeps the deposit queued.

In all three cases `builders`, `pending_deposits` and the state root after the upgrade differ from a master-conformant client. Case (b) also moves validator stake into a builder balance. Any of these can be set up by sending deposits through the deposit contract before the fork.

**(4) Teku** (`TK:ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/gloas/forktransition/GloasStateUpgrade.java#L222-L268`): Teku has the same beta.4 structure as Lodestar, so it **agrees with Lodestar, not with master**.
- `#L224-L227`: "Deposits for existing validators stay in the pending queue". It runs `if (validatorsUtil.getValidatorIndex(state, pubkey).isPresent()) { pendingDeposits.add(deposit); continue; }`.
- `#L230-L237`: `getBuilderIndex(state, pubkey).ifPresentOrElse(builderIndex -> ... copyWithNewBalance(builder.getBalance().plus(deposit.getAmount()))`. This is the top-up, and it runs before the credential check.
- `#L246`: the credential check.
- `#L251`: `pendingValidators.isPendingValidator(pubkey)`, checked before the signature (`#L255`).

**(5) Confidence: high** that the code differs from master; I read both spec versions and the code. **Disproof attempted:**
- I confirmed that no other Lodestar path onboards builders. The only call is `#L123`, `onboardBuildersFromPendingDeposits(stateGloas, metrics)`.
- I confirmed that the brief's statement holds: master and beta.4 differ only in this function, apart from one docstring typo.
- What remains open: whether this "disagrees with the spec" depends on whether the reference is master or the latest release. PR #5736 is merged on master (1 day old) but not in any tag I checked.

**(6) Severity: consensus split** at the fork-transition state root between clients on beta.4 (Lodestar, Teku) and clients on master. The trigger needs pending deposits shaped like (a), (b) or (c) at the fork. Because PR #5736 is one day old, this is a spec-version-lag item rather than a bug in its own right.

**Known-check: known.**
- https://github.com/ChainSafe/lodestar/pull/10428, "fix: route pending deposits by withdrawal credentials at the gloas fork", **open**. Its description covers case (b): "once a builder is registered for a key every later deposit for that key tops up the builder regardless of its withdrawal credentials".
- Related, closed: #9395 (onboard 20k builders), #9861 / #9840 (perf).

---

### C2: EIP-8061 Gloas `compute_min_epochs_for_block_requests` not implemented (p2p retention)

**(1) Spec** (`CS:p2p-interface.md#L246-L262`):

```python
def compute_min_epochs_for_block_requests() -> Epoch:
    # [Modified in Gloas:EIP8061]
    numerator = 3 * CHURN_LIMIT_QUOTIENT_GLOAS * CONSOLIDATION_CHURN_LIMIT_QUOTIENT
    denominator = 2 * CONSOLIDATION_CHURN_LIMIT_QUOTIENT + 3 * CHURN_LIMIT_QUOTIENT_GLOAS
    return MIN_VALIDATOR_WITHDRAWABILITY_DELAY + (numerator // denominator) // 2
```

Computed values:
- Mainnet: 3·32768·65536 // (131072 + 98304) = 28086, then // 2 = 14043, + 256 = **14,299 epochs**.
- Minimal: **262 epochs**.

**(2) Lodestar.** No function computes this. Every fork uses the static config value:
- `LS:packages/config/src/chainConfig/configs/mainnet.ts#L153`: `MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024,`. This is the phase0 value; minimal is 272.
- It is used as the serving lower bound at `LS:packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByHead.ts#L26` (`chain.clock.currentEpoch - chain.config.MIN_EPOCHS_FOR_BLOCK_REQUESTS`).
- It is used as the pruning cutoff at `LS:packages/beacon-node/src/chain/archiveStore/utils/pruneHistory.ts#L20` (`Math.max(currentEpoch - config.MIN_EPOCHS_FOR_BLOCK_REQUESTS, 0)`).
- I found no `computeMinEpochsForBlockRequests` anywhere under `packages/`.

**(3) When the results differ.** After Gloas, Lodestar keeps and serves blocks and envelopes for 33,024 epochs instead of the 14,299 the spec requires. Serving more than the minimum stays compliant.

The observable difference: Lodestar's notion of the "must-serve" window is about 18,700 epochs larger than a spec client's. As a result:
- It does not get the smaller retention.
- It may treat a peer's `ResourceUnavailable` for epochs between 14,299 and 33,024 back as unexpected.

No block, state or gossip verdict changes.

**(4) Teku agrees with Lodestar, not the spec.** `TK:ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/builder/SpecConfigBuilder.java#L1101-L1104` returns `minValidatorWithdrawabilityDelay + churnLimitQuotient / 2`, the phase0 formula, and I found no Gloas override. The search for `getChurnLimitQuotientGloas|getConsolidationChurnLimitQuotient` in main code found only config getters and churn accessors.

**(5) Confidence: high.**
- Disproof attempted: I grepped all of Lodestar `packages/` for the function and for any Gloas-specific value, and found neither.
- Data-column serving uses the separate `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS`, which EIP-8061 does not change.

**(6) Severity: cosmetic** (p2p retention only; no consensus effect).

**Known-check: known.** https://github.com/ChainSafe/lodestar/pull/10120, "feat: reduce `MIN_EPOCHS_FOR_BLOCK_REQUESTS` for gloas", **open**. Related, open: #9965 (pruning policy for envelopes).

---

### Not raised as candidates (checked, and the result is the same as the spec's)

- **N1. Gossip verdict order for over-limit blocks.** Lodestar enforces the EIP-7688 operation and request-count limits when it decodes the SSZ, before any IGNORE check.
  - Code: decode at `LS:packages/beacon-node/src/network/processor/gossipHandlers.ts#L765`, which maps to REJECT in `LS:packages/beacon-node/src/network/gossip/topic.ts#L171-L178`.
  - The spec instead lists the finalized-slot IGNORE before `verify_block_body_operation_limits` (`CS:p2p-interface.md#L590-L603`).
  - So a block that is over a limit **and** at or below the finalized slot gets REJECT from Lodestar and IGNORE in the spec's order.
  - Not raised because the spec explicitly allows this: "*Note*: These checks MAY be performed when deserializing `BeaconBlockBody`." (`CS:p2p-interface.md#L467`), and the same for `ExecutionRequests` (`#L506`).
  - Teku does the same through its schema limits.
- **N2. `apply_parent_execution_payload` length asserts.** The four `assert len(requests.X) <= MAX_*` lines (`CS:beacon-chain.md#L1792-L1795`) are not written out in `LS:packages/state-transition/src/block/processParentExecutionPayload.ts#L50-L102`.
  - The same limits are on the SSZ types (`LS:packages/types/src/gloas/sszTypes.ts#L181-L189`, `#L201-L204`, `#L214-L217`, each with `limit: MAX_*_REQUESTS_PER_PAYLOAD`). Those limits are enforced on decode: PR #10042 (merged) and the test `LS:packages/types/test/unit/gloas/eip7688.test.ts#L106-L177`.
  - Results would differ only for an object built in memory that was never deserialized. That cannot come from peers or from the EL, whose parser uses the same types.
  - Teku does the same, through schema limits (`TK:.../spec/schemas/registry/SchemaRegistryBuilder.java#L492-L497`).
  - The `@chainsafe/ssz` library code was not in the clone. My evidence for decode-time enforcement is Lodestar's tests and PR #10042.
- **N3. Churn slot-duration scaling.** The Gloas churn helpers scale by `getSlotDurationMsAtEpoch(epoch)/getSlotDurationMsAtEpoch(GENESIS)` (`LS:packages/state-transition/src/util/validator.ts#L97-L147`). That scaling is not in Gloas; it comes from a later feature, EIP-8198.
  - The ratio is exactly 1 unless a Heze fork with a different `SLOT_DURATION_MS_HEZE` is scheduled. The reader's check of the configs found `SLOT_DURATION_MS_HEZE` equal to `SLOT_DURATION_MS` on mainnet, minimal and gnosis.
  - So there is no Gloas difference.

### Logic shared with the live Fulu fork

No candidate was found in code shared with Electra/Fulu. That code includes the proposer sampling (`computeProposerIndices`), the lookahead shift, and the pre-Gloas branches of the churn helpers.

## 3. Rules checked and found correct

Lodestar paths are at the pin above. "Teku" gives the corresponding Teku location where I checked it.

| Rule (spec, CS:) | Lodestar (LS:) | Verdict | Teku |
|---|---|---|---|
| `process_builder_deposit_request`: 0xB0 prefix gate before any registry access (`beacon-chain.md#L2334-L2337`, `#L1067-L1072`) | `block/processBuilderDepositRequest.ts#L20-L23`; `util/gloas.ts#L29-L30`: `withdrawalCredentials[0] === BUILDER_WITHDRAWAL_PREFIX`; `params/src/index.ts#L154`: `0xb0` | correct. The gate applies to both first registration and top-up | `.../gloas/execution/ExecutionRequestsProcessorGloas.java#L77-L79` (agrees) |
| New builder: signature over `DepositMessage` with `compute_domain(DOMAIN_BUILDER_DEPOSIT)`, i.e. genesis fork version and zero root (`#L2268-L2285`) | `util/gloas.ts#L281-L296`: `computeDomain(DOMAIN_BUILDER_DEPOSIT, config.GENESIS_FORK_VERSION, ZERO_HASH)`; `params/src/index.ts#L175`: `[14,0,0,0]` | correct | `ExecutionRequestsProcessorGloas.java#L118-L127` (agrees) |
| `PAYLOAD_BUILDER_VERSION = 0`; `execution_address = withdrawal_credentials[12:]`; `deposit_epoch = epoch(state.slot)` | `processBuilderDepositRequest.ts#L29`; `params/src/index.ts#L157`; `block/indexedBuilderState.ts#L36-L48` | correct | `#L108` (agrees) |
| `get_index_for_new_builder`: lowest index with `withdrawable_epoch <= current_epoch and balance == 0` (`#L2287-L2295`) | `indexedBuilderState.ts#L19-L30`, `#L50-L65`. The candidates are ascending and re-checked lazily; within one payload a builder can only become non-reusable (a top-up sets balance > 0 or withdrawable > current) | correct | `.../gloas/helpers/BeaconStateAccessorsGloas.java#L372-L382` (agrees) |
| Top-up resets `withdrawable_epoch` only when `withdrawable_epoch != FAR_FUTURE_EPOCH and balance == 0`, before the balance increase (`#L2352-L2361`) | `processBuilderDepositRequest.ts#L34-L44` | correct | `ExecutionRequestsProcessorGloas.java#L90-L100` (agrees) |
| `process_builder_exit_request`: unknown pubkey, then `is_active_builder` (`deposit_epoch < finalized.epoch`, `withdrawable == FAR`), then `source_address`, then pending balance == 0, then `initiate_builder_exit` (`#L2365-L2384`, `#L1051-L1065`, `#L1523-L1533`) | `block/processBuilderExitRequest.ts#L15-L35`; `util/gloas.ts#L79-L80`, `#L119-L141`, `#L168-L179`. The extra early return in `initiateBuilderExit` (L172) is unreachable here because the builder is already known to be active | correct | `ExecutionRequestsProcessorGloas.java#L130-L161` (agrees) |
| `apply_parent_execution_payload` order: settle payment (current, then previous, then direct append if value > 0), then requests in the order deposits, withdrawals, consolidations, builder_deposits, builder_exits, then availability bit and `latest_block_hash` (`#L1776-L1831`) | `block/processParentExecutionPayload.ts#L50-L102` | correct | `.../gloas/block/BlockProcessorGloas.java#L163-L222` (agrees) |
| `process_parent_execution_payload`: EMPTY parent requires empty requests; FULL parent requires `hash_tree_root(requests) == parent_bid.execution_requests_root` (`#L1833-L1854`) | `processParentExecutionPayload.ts#L18-L39`, `#L123-L132` | correct | — |
| `ExecutionRequests` is a ProgressiveContainer with `active_fields(width=5)`, fields in spec order (`#L968-L982`) | `types/src/gloas/sszTypes.ts#L219-L229` | correct at the type level (merkleization is in `@chainsafe/ssz`, not in the clone) | — |
| `get_execution_requests` (`validator.md#L266-L321`): valid type set including 0x03/0x04, non-empty data, strictly ascending | `beacon-node/src/execution/engine/types.ts#L596-L661` (checks at `#L605-L627`; 0x03/0x04 at `#L642-L655`, which throws pre-Gloas); `params/src/index.ts#L372-L373` | correct | `.../datastructures/execution/ExecutionRequestsDataCodec.java#L43-L104` (agrees) |
| `get_execution_requests_list` (`beacon-chain.md#L2123-L2142`): prefix plus SSZ, skipping empty lists | `engine/types.ts#L557-L590` | correct | — |
| EIP-7688 `is_valid_indexed_attestation` cap `len <= MAX_VALIDATORS_PER_COMMITTEE*MAX_COMMITTEES_PER_SLOT` (`#L1030-L1036`) | `state-transition/src/block/isValidIndexedAttestation.ts#L54-L60` | correct | enforced by the schema limit, `SchemaRegistryBuilder.java#L417-L420` (agrees) |
| EIP-7688 `process_operations` count asserts and `len(deposits)==0` (`#L2228-L2264`) | `block/processOperations.ts#L44-L53` (deposits); other counts through SSZ type limits `sszTypes.ts#L231-L255`, `#L353-L356` | correct in effect (see N2) | `BlockProcessorGloas.java#L395-L416` (schema limits) |
| Gloas gossip size bounds (`p2p-interface.md#L63-L80`) | derived from `sszType.maxSize`: `network/gossip/topic.ts#L157-L166`; equality with the constants is asserted in `types/test/unit/gloas/eip7688.test.ts#L193-L198` | correct (by test assertion; not run) | — |
| Fulu→Gloas list migration keeps the element roots and rebuilds the progressive superstructure | `slot/upgradeStateToGloas.ts#L100-L111`, `#L148-L175` | no difference found (the library is not in the clone) | — |
| EIP-8045 `get_beacon_proposer_indices` excludes slashed validators (`#L1287-L1306`) | `epoch/processProposerLookahead.ts#L24-L36`: `fork >= ForkSeq.gloas ? shuffling.activeIndices.filter((index) => (cache.flags[index] & FLAG_UNSLASHED) !== 0)`; the flag comes from `validator.slashed` at `cache/epochTransitionCache.ts#L272-L278` | correct. Nothing in epoch processing sets `slashed`, and ascending order is preserved | `.../gloas/helpers/BeaconStateAccessorsGloas.java#L85-L94` (agrees) |
| EIP-8045 at the transition: `proposer_lookahead=pre.proposer_lookahead`, copied, not recomputed (`fork.md#L194`). The first two Gloas epochs therefore use the unfiltered Fulu lookahead; the filter applies from fork+2 | `upgradeStateToGloas.ts#L112`; the epoch cache reads the lookahead from state (`cache/epochCache.ts#L427-L435`, `#L754-L761`); epoch processing at the last Fulu slot runs with `fork=fulu` (`stateTransition.ts#L218-L283`) | correct | `GloasStateUpgrade.java#L156` (agrees) |
| All proposer consumers (gossip block, sidecars, duties API, preferences, PTC) read the lookahead or epoch cache; none recompute without the filter | `stateView/beaconStateView.ts#L569-L582`, `chain/validation/block.ts#L278`, `api/impl/validator/index.ts#L1581-L1610` | correct | — |
| EIP-8061 `get_activation_churn_limit` (`#L1442-L1456`) | `util/validator.ts#L97-L111`. It caps before rounding, which is equivalent because the cap is a multiple of 1e9. The float division is exact because the quotient is a power of 2 | correct | `BeaconStateAccessorsGloas.java#L101-L142` (agrees) |
| EIP-8061 `get_exit_churn_limit`, uncapped (`#L1458-L1471`) | `util/validator.ts#L116-L127` | correct | same (agrees) |
| EIP-8061 `get_consolidation_churn_limit`, no floor (`#L1473-L1487`); `process_consolidation_request` churn gate inherited from Electra | `util/validator.ts#L133-L147`; `block/processConsolidationRequest.ts#L49-L52` | correct | same (agrees) |
| EIP-8061 `compute_exit_epoch_and_update_churn` uses exit churn (`#L1489-L1519`) | `util/epoch.ts#L56-L62` (`fork >= ForkSeq.gloas ? getExitChurnLimit(...)`) | correct | `.../gloas/helpers/BeaconStateMutatorsGloas.java#L72-L100` (agrees) |
| EIP-8061 `process_pending_deposits` uses activation churn (`#L1656-L1664`) | `epoch/processPendingDeposits.ts#L28-L30` | correct | `.../gloas/statetransition/epoch/EpochProcessorGloas.java#L72-L75` (agrees) |
| EIP-8061 config values (mainnet 32768 / 65536 / 256e9; minimal 16 / 32 / 128e9) | `config/src/chainConfig/configs/mainnet.ts#L185-L189`, `minimal.ts#L178-L182` | correct | — |
| EIP-8061 `compute_weak_subjectivity_period` (`weak-subjectivity.md#L31-L48`) | `util/weakSubjectivity.ts#L182-L195`. The weights 2/3, 1/3, 1 match, and it reproduces the spec table row (1,048,576 ETH → 620). It uses float division, so it could be off by 1 at an exact integer boundary; WS checks only, not consensus | correct (float caveat) | `.../gloas/weaksubjectivity/WeakSubjectivityCalculatorGloas.java#L41-L53` (agrees) |

## 4. Known-check (ChainSafe/lodestar issues and PRs, open and closed)

Searched with `api.github.com/search/issues?q=repo:ChainSafe/lodestar <query>`. Queries: `onboard builders`, `min_epochs_for_block_requests`, `MIN_EPOCHS_FOR_BLOCK_REQUESTS gloas`, `8061`, `8282`, `8045`, `7688`, `builder deposit request`, `builder exit request`, `gloas operation limits gossip`, `proposer lookahead slashed`, `epbs execution requests`, `1.7.0-beta.4`.

| Item | Status |
|---|---|
| C1 onboarding lag | **known**: https://github.com/ChainSafe/lodestar/pull/10428 (open), "route pending deposits by withdrawal credentials at the gloas fork" |
| C2 min epochs for block requests | **known**: https://github.com/ChainSafe/lodestar/pull/10120 (open); see also #9965 (open) |
| N1 / N2 progressive list limits | related: #10042 "enforce progressive list limits on deserialization" (merged 2026-09-10); #10121 "align gloas progressive list limits with the spec" (open; it says it adopts consensus-specs#5642, which I did not verify); #10080 (merged, legacy deposits rejected on decode) |
| Already indexed (from the brief) | #9337 weak subjectivity for EIP-8061, closed by #9625 (merged); #10042 merged; #9656 closed (progressive list RangeError at fork on glamsterdam-devnet-7) |
| Other related, for context | #9422 EIP-8045 (merged); #9730 next-epoch proposer from lookahead (closed); #9305 EIP-8061 churn (merged); #9390 EIP-7688 (merged); #10180 settle payment before requests (closed); #9558 "Clean up post EIP-8282" (closed); #9626 churn helper naming (open) |

## 5. Not verified

- The `@chainsafe/ssz` progressive merkleization and the decode-time limit enforcement. The library is not in the repo; I relied on Lodestar's tests and PRs.
- The native `@chainsafe/lodestar-z` proposer sampler. I checked only the TypeScript reference `naiveComputeProposerIndex`, at `LS:packages/state-transition/src/util/seed.ts#L69-L86`.
- Public hive or execution-spec-tests results for Glamsterdam devnets. I did not check them for this item.

## 6. URLs read

- https://api.github.com/repos/ChainSafe/lodestar/commits/unstable
- https://api.github.com/repos/ethereum/consensus-specs/commits/master
- https://api.github.com/repos/Consensys/teku/commits/master
- https://github.com/ChainSafe/lodestar, https://github.com/ethereum/consensus-specs, https://github.com/Consensys/teku: shallow git fetch of the pinned commits
- https://raw.githubusercontent.com/ethereum/consensus-specs/v1.7.0-beta.4/specs/gloas/{fork,beacon-chain,validator,p2p-interface,weak-subjectivity}.md
- https://api.github.com/repos/ethereum/consensus-specs/git/ref/tags/v1.7.0-beta.4
- https://api.github.com/repos/ethereum/consensus-specs/pulls/5736
- https://eips.ethereum.org/EIPS/eip-8282, /eip-7688, /eip-8045, /eip-8061: titles only ("Builder Execution Requests", "Forward Compatible Consensus Data Structures", "Exclude Slashed Validators from Proposing", "Increase Exit and Consolidation Churn"). Rules were compared against the consensus-specs text, which links pinned EIP revisions at `CS:beacon-chain.md#L167-L181`.
- https://api.github.com/search/issues (queries listed in §4); https://api.github.com/repos/ChainSafe/lodestar/issues/{10428,10120,10121,10042,9656}
