diff --git a/.agents/skills/adopt-upstream-eip/SKILL.md b/.agents/skills/adopt-upstream-eip/SKILL.md index 034a5191c6d..feab958c20b 100644 --- a/.agents/skills/adopt-upstream-eip/SKILL.md +++ b/.agents/skills/adopt-upstream-eip/SKILL.md @@ -173,6 +173,12 @@ stay independent until a deliberate merge. ## 3. Adopt the EIP in the framework +Create the fork before adopting anything into it. Where `` +has no directory under `src/ethereum/forks/` yet, or no class in the +testing package, add them as exact replicas of `` in a +separate commit. The adoption then shows the EIPs as the only deviations +from the parent Monad fork, which is what the diff has to make visible. + In `packages/testing/src/execution_testing/forks/forks/forks.py`, declare `` **after** `` (so the name resolves) with the EIP mixins first: diff --git a/.agents/skills/merge-eip-branches/SKILL.md b/.agents/skills/merge-eip-branches/SKILL.md new file mode 100644 index 00000000000..6b1814d616c --- /dev/null +++ b/.agents/skills/merge-eip-branches/SKILL.md @@ -0,0 +1,166 @@ +--- +name: merge-eip-branches +description: Consolidate single-EIP adoption branches into one Monad fork that adopts all of them. +--- + +# Merge EIP Adoption Branches + +Consolidate several single-EIP adoption branches into one fork that adopts +all of them. Run this skill before starting such a merge. Each source +branch was built by `/adopt-upstream-eip`, alone, against its own upstream +EIP branch, so no source branch knows what the combined fork does. + +## Inputs + +- The source branches, and `` they all target. +- ``, the branch they merge into. Example: `forks/monad_nine`. +- `` and its upstream integration branch, which already has every + EIP composed. Example: `upstream/forks/amsterdam`. + +## Read First + +`/adopt-upstream-eip` defines the fork shape, the shared-file cost rules, +the step-12 cleanup list and the definition of done. This skill only covers +what the merge adds. + +## 1. Prepare + +```bash +git worktree add -b origin/ +git branch --unset-upstream +``` + +Merge into a fresh worktree, and never check out or rewrite a source +branch. Note which commits already landed on `` after the +source branches were cut: a branch carrying its own copy of one of them +conflicts, and ``'s version wins. + +```bash +git log --oneline $(git merge-base origin/ )..origin/ +``` + +## 2. Merge + +Merge the largest branch first, then the rest, with real merge commits. +Squashing or cherry-picking hides which branch each conflict came from. + +```bash +git merge --no-ff # once per source branch +``` + +`--no-ff` keeps the merge commit even when `` has not moved +since the branch was cut, where a plain merge would fast-forward. + +## 3. Resolve the Conflicts Git Reports + +Expect these, in rising order of thought needed: + +- **`.github/configs/feature.yaml`** — every branch appends its own entry + at the same point. Keep all entries for now; step 5 collapses them. +- **`forks.py`, the `` declaration** — each branch declares the + class with one mixin. The merged class lists every mixin ahead of the + parent fork, in ascending EIP order. Drop any dead `pass` left after + `follows()`. +- **CI files already on ``** — keep the base branch's version. +- **`src/ethereum/forks//`** — two EIPs changing the same file. + Resolve against the upstream integration branch, not against either + branch alone. + +What must merge silently: the `follows()` trait, the +`BaseForkMeta._is_subclass_of` walk, the `ValidAtTransitionTo` guard and the +exclusion conftests. They are byte-identical across branches by design. +Check afterwards that one copy of each survived. + +## 4. Find the Silent Merges + +This is the main risk. Two branches editing the same file at different +lines merge cleanly and produce behavior neither branch had. Git reports +nothing. + +Find the candidates from the upstream spec changes, over the +`..` range each adoption recorded for its +EIP. Do not derive the range from the integration branch: upstream merges +some EIP branches with a merge commit, which makes the branch tip the +merge base and the diff empty. + +```bash +for n in ; do + echo "### EIP-$n" + git diff --stat .. -- src/ethereum/forks/ +done +``` + +Any file listed under two EIPs needs reading in full on the merge branch. +Where one EIP removes what another adds, the merged file must match the +upstream integration branch, which already has both. + +Two shapes seen in practice: + +- One EIP adds a log for a state change a later EIP removes. Git keeps + both: a log for something that no longer happens. +- Two branches add the same conftest hook at different offsets, one after + the imports and one appended. Git keeps both hook definitions in one + module. + +Also read every file the merge touched outside `src/ethereum/forks/monad*` +and `tests/monad*`, whether or not git flagged it. + +## 5. Clean Up the Scaffolding + +Follow `/adopt-upstream-eip` step 12, driven by what the merged fork now +adopts: + +- Delete the exclusion conftest for each adopted EIP's suite. Those suites + must now be selected and pass. +- Collapse the per-branch feature entries into one. When the branch name + follows `eips//eip-+`, the feature name must carry the same + numbers in the same order: `check_release_matrix.py` matches the sequence + as a literal string. The script falls back to every feature when the + name does not match and still exits zero, so only its printed list + proves the name: + + ```bash + python3 .github/scripts/check_release_matrix.py "" \ + | grep 'features=\["monad_eip+"\]' + ``` + +- Revert expectation scaffolding written for an intermediate fork shape. A + test edit that only made a fork with EIP-A but without EIP-B green is + scaffolding once B joins. + +To test whether an edit was scaffolding, revert it and diff against the +base branch: + +```bash +git revert --no-commit && git diff origin/ -- +``` + +An empty diff only shows the revert is clean: nothing else depends on the +edit. Whether it was scaffolding is decided by filling the suites it +touched on the merged fork; keep the revert when they pass and keep the +edit when they fail. Reverting cleanly needs the source branch to have +kept scaffolding in its own commit; a commit mixing scaffolding with +permanent change has to be undone by hand. + +Keep gates on a capability (`fork.is_eip_enabled()`, `fork >= +MONAD_EIGHT`) that stay true on the merged fork. They are permanent. + +## 6. Validate + +Run `/adopt-upstream-eip`'s step-3 shape check, its step-5 `--collect-only` +selection check, then the full-suite fill for the fork. The full suite +matters: the merge changes which suites select the fork. + +Measure any exclusion that survived the cleanup, one suite at a time, by +stripping its hook and filling that suite. State which ones you did not get +to measure. + +## Definition of Done + +- Every source branch merged, with the merge commits kept. +- Each file two EIPs touched read in full and matched against the upstream + integration branch. +- One copy of each shared addition; no duplicated hook or trait. +- Adopted suites selected and passing; their exclusions deleted. +- One feature entry, its name matching the branch's EIP sequence. +- Full-suite fill green, with any unmeasured exclusion named. diff --git a/.claude/skills/merge-eip-branches b/.claude/skills/merge-eip-branches new file mode 120000 index 00000000000..4db213f200a --- /dev/null +++ b/.claude/skills/merge-eip-branches @@ -0,0 +1 @@ +../../.agents/skills/merge-eip-branches \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 063a9287dde..7b5c170566b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -57,6 +57,7 @@ skills as `/name` commands through symlinked folders in `.claude/skills/`. - Implementing an EIP or modifying fork code in `src/` → run `/implement-eip` first - Adopting a single upstream EIP into a work-in-progress Monad fork → run `/adopt-upstream-eip` first - Merging upstream changes into `from-upstream` → run `/merge-from-upstream` first +- Consolidating several single-EIP adoption branches into one fork → run `/merge-eip-branches` first - Modifying GitHub Actions workflows → run `/edit-workflow` first - Assessing EIP complexity or scope → run `/assess-eip` - Working on EIP test coverage or checklists → run `/eip-checklist` first @@ -74,6 +75,7 @@ skills as `/name` commands through symlinked folders in `.claude/skills/`. - `/implement-eip` — fork structure, import rules, adding opcodes/precompiles/tx types - `/adopt-upstream-eip` — adopt one upstream EIP into a work-in-progress Monad fork and release its fixtures - `/merge-from-upstream` — merge upstream, propagate the changes to the Monad forks, verify the fixture set +- `/merge-eip-branches` — consolidate single-EIP adoption branches into one Monad fork - `/edit-workflow` — GitHub Actions conventions and version pinning - `/assess-eip` — structured EIP complexity assessment - `/eip-checklist` — EIP testing checklist system for tracking coverage