Skip to content

feat: document and enforce config field lifecycle (immutable/append-only/mutable)#1265

Open
geoknee wants to merge 1 commit into
mainfrom
feat/config-field-lifecycle
Open

feat: document and enforce config field lifecycle (immutable/append-only/mutable)#1265
geoknee wants to merge 1 commit into
mainfrom
feat/config-field-lifecycle

Conversation

@geoknee

@geoknee geoknee commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

What

Chain config TOMLs mix values that are fixed at genesis and can never change (e.g. chain_id, block_time, the [genesis] block) with values that evolve over time (hardfork activations, role rotations, contract upgrades). Nothing told a reader — or CI — which is which. This PR makes the distinction explicit and enforced.

How

Three layers, all driven by one source of truth:

  1. Struct tags + doc comment (ops/internal/config/chain.go) — every Chain field carries a lifecycle:"immutable|append-only|mutable" tag, plus guidance on classifying new fields. This is the source of truth.
  2. Human-readable contract (superchain/configs/README.md) — a new "Field lifecycle" section with a table and examples.
  3. CI enforcementconfig.CheckImmutableFields compares old vs new configs based on the tags, and TestImmutableFieldsUnchanged (ops/internal/manage) runs it against every changed superchain/configs/*.toml, diffing against the merge-base (mirroring the existing codegen check).

The lifecycle rules

Lifecycle Rule Examples
immutable Never changes once a chain is registered chain_id, block_time, seq_window_size, max_sequencer_drift, gas_paying_token, [genesis]
append-only New entries may be added; a not-yet-active activation may be re-scheduled, but one already in the past is frozen [hardforks]
mutable May change freely [roles], [addresses], RPCs, superchain_level, data_availability_type, [optimism], …

The append-only rule is time-aware on purpose: hardfork activations are routinely pushed out while still in the future (e.g. jovian_time was rescheduled twice via merged PRs). A naive "freeze any set value" rule would have falsely rejected those legitimate PRs. Past activations are on-chain history and stay frozen.

Classifications were verified against repo history (e.g. data_availability_type legitimately changed eth-da → alt-da on lyra; eip1559 params changed on worldchain → both correctly mutable).

Testing

  • Unit tests cover each lifecycle, the past/future hardfork distinction, and a guard that fails if a new Chain field is added without a tag.
  • The git-aware test was verified end-to-end: changing a past hardfork or an immutable field is rejected with a clear message; pushing out a future hardfork is allowed.
  • go test ./internal/config/... ./internal/manage/, go vet, gofmt all clean.

🤖 Generated with Claude Code

…nly/mutable)

Chain config TOMLs mix values that are fixed at genesis and can never change
(e.g. chain_id, block_time, the genesis block) with values that evolve over
time (hardfork activations, role rotations, contract upgrades). Nothing told a
reader — or CI — which is which.

This change makes the distinction explicit and enforced:

- Each Chain field carries a `lifecycle` struct tag (immutable / append-only /
  mutable) with a doc comment explaining the contract and how to classify new
  fields. This is the source of truth.
- superchain/configs/README.md gains a "Field lifecycle" table documenting the
  contract for humans.
- config.CheckImmutableFields compares an old and new config, driven by the
  tags: immutable fields must be unchanged; hardfork activations are
  append-only with a time rule — a not-yet-active activation may be added or
  re-scheduled, but one already in the past is frozen (it is on-chain history).
- TestImmutableFieldsUnchanged (ops/internal/manage) enforces this in CI by
  diffing every changed superchain/configs/*.toml against the merge-base,
  mirroring the existing codegen check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@geoknee geoknee requested a review from a team as a code owner June 24, 2026 10:41
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.

1 participant