Skip to content

[codex] Refine EIP fork timeline model#346

Draft
dionysuzx wants to merge 1 commit into
mainfrom
codex/combine-eip-timeline-proposed-presented
Draft

[codex] Refine EIP fork timeline model#346
dionysuzx wants to merge 1 commit into
mainfrom
codex/combine-eip-timeline-proposed-presented

Conversation

@dionysuzx

Copy link
Copy Markdown
Contributor

What changed

Refines the fork relationship timeline model so each field has a narrower domain meaning:

  • keeps statusHistory as the inclusion state machine for fork status transitions
  • replaces mixed presentationHistory entries with generic discussionHistory call references
  • moves headliner-specific proposal and presentation metadata into headlinerCandidacy
  • derives the rendered EIP timeline from those domain records and dedupes discussion/headliner presentation rows when the same call/date is already represented by a status transition
  • migrates the existing EIP JSON records and schema to the new shape

Why

Issue #242 called out that a standalone Presented timeline entry is not useful when it duplicates a proposal/status reference, and that the old statusHistory / presentationHistory split was mixing responsibilities through event enums.

The new boundary keeps persistence simple: inclusion status transitions remain separate from non-transition discussion references. The UI gets a complete timeline by projection instead of requiring the raw domain model to be one all-purpose event log.

Validation

  • npm test
  • npm run check
  • npm run build

Fixes #242

@netlify

netlify Bot commented Jun 19, 2026

Copy link
Copy Markdown

Deploy Preview for eth-forkcast ready!

Name Link
🔨 Latest commit c2e213a
🔍 Latest deploy log https://app.netlify.com/projects/eth-forkcast/deploys/6a35d7a7aaa6340008df288a
😎 Deploy Preview https://deploy-preview-346--eth-forkcast.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 93 (no change from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (no change from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@dionysuz-bot

Copy link
Copy Markdown

No blocking issues found.

The domain split is aligned with the stated intent: statusHistory stays focused on inclusion transitions, headliner metadata moves into headlinerCandidacy, and the timeline projection is now a small tested functional core instead of React component logic. The migration also appears internally consistent, with no stale persisted presentationHistory / isHeadliner / wasHeadlinerCandidate fields left in the source data.

Validation run locally:

  • npm test passed
  • npm run check passed
  • npm run build passed

Copy link
Copy Markdown
Contributor Author

After taking another pass at the domain boundary, I think we should tweak the headliner side before merging.

The current split is directionally right: statusHistory should stay focused on fork inclusion transitions, and headliner selection should not be folded into that enum/state machine. Headliner selection is an orthogonal process: an EIP can be scheduled/declined/considered while also having been a headliner candidate or selected headliner.

The part that still feels muddled is headlinerCandidacy. It compresses several temporal facts into one object:

  • object presence means “was ever a headliner candidate”
  • proposal is a dated proposal event
  • presentation is a dated call event
  • selected is an outcome encoded as a boolean

That makes the reader infer lifecycle semantics from field presence. Against our modeling principles, I think a scoped headliner history is the cleaner boundary:

statusHistory        // inclusion lifecycle
headlinerHistory     // headliner candidacy lifecycle
discussionHistory    // non-lifecycle discussion references

For example:

headlinerHistory?: Array<
  | { type: 'proposed'; date: string; link: string }
  | { type: 'presented'; date: string; call: ProtocolCallReference; timestamp?: number }
  | { type: 'selected'; date?: string; call?: ProtocolCallReference; timestamp?: number }
  | { type: 'notSelected'; date?: string; call?: ProtocolCallReference; timestamp?: number }
  | { type: 'withdrawn'; date?: string; call?: ProtocolCallReference; timestamp?: number }
>;

I do not think this overextends enums if it stays scoped to the headliner lifecycle. It gives proposal/presentation/selection a natural temporal home, avoids boolean inference like selected: false, and keeps discussionHistory for ordinary call references instead of making headlinerCandidacy.presentation a second call-reference domain.

So the requested change is: keep statusHistory as-is, but replace headlinerCandidacy with a separate headlinerHistory lifecycle projection.

@dionysuzx dionysuzx force-pushed the codex/combine-eip-timeline-proposed-presented branch from 7085de1 to 7a07598 Compare June 19, 2026 23:22
@dionysuzx

Copy link
Copy Markdown
Contributor Author

@dionysuz-bot please re-review.

I addressed the latest dionysuzx feedback by replacing headlinerCandidacy with scoped headlinerHistory lifecycle events (proposed, presented, selected, notSelected, withdrawn). I also added a small headliner history domain helper so current selected state is derived from the latest lifecycle outcome, migrated the headliner data/schema, and kept status history/discussion history separate.

@dionysuz-bot

Copy link
Copy Markdown

No blocking issues found.

The revised headlinerHistory split addresses the prior modeling concern: statusHistory remains the inclusion lifecycle, headlinerHistory now owns the scoped headliner lifecycle, and discussionHistory stays as ordinary call references. I also checked for stale headlinerCandidacy / presentationHistory / persisted headliner boolean fields and did not find any remaining source-data usage.

Validation run locally:

  • npm test passed
  • npm run lint passed
  • npm run check passed
  • node scripts/validate-eip-metadata.mjs passed
  • npm run build passed

@dionysuzx dionysuzx force-pushed the codex/combine-eip-timeline-proposed-presented branch from 7a07598 to a635080 Compare June 19, 2026 23:47
@dionysuzx

Copy link
Copy Markdown
Contributor Author

@dionysuz-bot please re-review.

I tightened the headliner model further after reconsidering notSelected: per-EIP headlinerHistory now only records candidate-specific facts (proposed, presented, withdrawn). Selected headliners moved to the fork aggregate as networkUpgrade.headlinerSelection.selected.{EL,CL}, so non-selection is derived from finalized fork selection plus candidacy rather than persisted on every losing EIP. Added domain/data tests for the selected slots and removed stale selected/notSelected history from source EIP data.

@dionysuz-bot

Copy link
Copy Markdown

I found one blocking issue.

  • src/data/upgrades.test.ts:2 imports ./eips, which imports generated src/data/eips.json. That file is gitignored (.gitignore:21), and npm test (package.json:19) does not run compile-data first. On a clean checkout after npm ci, npm test fails before running this suite with Cannot find module './eips.json' imported from src/data/eips.ts. This PR adds the first test dependency on the generated EIP aggregate, so the default test command is no longer runnable from a clean checkout. Please either make this test read the source src/data/eips/*.json records directly, or add the needed compile step to the test path.

Validation:

  • npm test fails on clean checkout as above
  • After npm run compile-data: npm test, npm run lint, npm run check, node scripts/validate-eip-metadata.mjs, and npm run build pass.

@dionysuzx dionysuzx force-pushed the codex/combine-eip-timeline-proposed-presented branch from a635080 to c2e213a Compare June 19, 2026 23:58
@dionysuzx

Copy link
Copy Markdown
Contributor Author

@dionysuz-bot please re-review.

Fixed the clean-checkout blocker: src/data/upgrades.test.ts no longer imports generated ./eips; it reads source src/data/eips/*.json records directly, so npm test remains runnable without compile-data.

@dionysuz-bot

Copy link
Copy Markdown

No blocking issues found on re-review.

I verified the clean-checkout blocker is addressed: src/data/upgrades.test.ts reads the source JSON records directly instead of importing generated src/data/eips. After installing dependencies from the lockfile, I ran:

  • npm test - 19 files / 98 tests passed
  • npm run check - passed
  • npm run build - passed

The new split between status transitions, discussions, and headliner history is consistent with the intended domain boundary, and I didn’t see a correctness or maintenance issue that should block this PR.

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.

combine proposed/presented on EIP timeline

2 participants