# Lighter: L2BEAT stage history audit, 2026-04-27 to 2026-10-27

## 1. Window, sources, method, baseline

- **Window audited:** 2026-04-27T00:00Z to 2026-10-27 (snapshot date). Code observed at `l2beat/l2beat` `main` = `b3346aafa392488900d7a556a206cfabc7acf611` (committed 2026-10-27T14:34:49Z). The last `main` commit before the window is `c3d6e4c33386c6063ff070dc7f4e557d93725dca`.
- **Baseline (last `main` commit before the window):** `25765a155af6d210da1dab371efaf34753727132` (2026-04-24T17:41:43Z). Before the window, the last edit to `lighter.ts` was `cd3312b2` (2026-04-21). Earlier edits were `2cfcb29c` ("Lighter escape hatch rosette to red", 2026-04-17) and `e43d1589` ("Lighter escape hatch downgrade", 2026-04-14). Both came **before** the window.
- **Method:**
  1. Ran `git log` on `packages/config/src/projects/lighter/lighter.ts` from the baseline to `main`. This found 30 commits in the window, each diffed and filtered for stage, checklist, warning, type and capability lines.
  2. Read the shared evaluator (`common/stages/stage.ts`, `getStage.ts`/`getRollupStage.ts`), the countdown (`global/countdowns.ts`), the label mapping (`processing/utils/getStage.ts`) and the frontend badge/section (`StageBadge.tsx`, `StageCell.tsx`, `StageSection.tsx`) at the baseline, and diffed each of them up to `main`.
  3. Fetched archived L2BEAT project pages from the Wayback Machine. These are the **observed** website labels. All other labels below are **calculated** from the code.
- **Code date vs publication date:** commit dates are the dates code was merged to `main`. The deploy time is not in git. The only evidence of publication dates is the Wayback snapshots listed below.

## 2. Checkpoints (chronological)

Abbreviations: `lighter.ts` = `packages/config/src/projects/lighter/lighter.ts`; `S0/S1/S2` = the stage0/stage1/stage2 checklists.

| UTC date | Commit / observation | Stage inputs before → after | Designation | Stage-0 message (warning bar) |
|---|---|---|---|---|
| 2026-04-22 23:53 | **Observed:** Wayback [20260422235319](https://web.archive.org/web/20260422235319/https://l2beat.com/scaling/projects/lighter) | n/a | **Stage 0** (embedded `"stageConfig":{"stage":"Stage 0","missing":{"nextStage":"Stage 1"…`), Appchain | `{"type":"underReview","text":"The requirement for available node software is under review"}` |
| 2026-04-24 17:41 | **Baseline** [`25765a1`](https://github.com/l2beat/l2beat/blob/25765a155af6d210da1dab371efaf34753727132/packages/config/src/projects/lighter/lighter.ts#L189-L213) | S0: callsItselfRollup, stateRootsPostedToL1, dataAvailabilityOnL1, stateVerificationOnL1 = true; **rollupNodeSourceAvailable = 'UnderReview'** (L194); fraudProofSystemAtLeast5Outsiders = null. S1: principle, usersHave7DaysToExit, usersCanExitWithoutCooperation, securityCouncilProperlySetUp = false; noRedTrustedSetups = true; proverSourcePublished = true; **verifierContractsReproducible = false** (L206); programHashesReproducible = null. S2: all false or null. `type: 'layer2'`, `capability: 'appchain'` | **Calculated: Stage 0**. Stage 1 is missing (principle and 4 requirements false). | underReview: "The requirement for available node software is under review". There is also a separate project `display.warning` (Apr 9 2026 desert-mode text, L44-45). That is not part of the stage. |
| 2026-04-27 15:06 | [`c7d85e3`](https://github.com/l2beat/l2beat/commit/c7d85e3a6da2166c7b378132992639f3ba9fa201) Dailies | no stage-input edit | Stage 0 (calc.) | unchanged |
| 2026-05-04 14:23 | [`3b3f524`](https://github.com/l2beat/l2beat/commit/3b3f5241641397839a98f0475c831a15ef4b1dbf) Dailies | no stage-input edit | Stage 0 (calc.) | unchanged |
| 2026-05-06 11:02 | [`995eebb`](https://github.com/l2beat/l2beat/commit/995eebbdd8d1f4c660341c19a27cbde34be98b24) "Add stages config for validiums & optimiums" | Import renamed `getStage` → `getRollupStage`. The inputs are unchanged. Diffing base `getStage.ts` against `getRollupStage.ts`@995eebb shows only identifier renames (`getStage`→`getRollupStage`, `GetStageOptions`→`GetRollupStageOptions`). The blueprint, upcoming items and logic are identical. | Stage 0 (calc.) | unchanged |
| 2026-05-12 18:44 | **Observed:** Wayback [20260512184447](https://web.archive.org/web/20260512184447/https://l2beat.com/scaling/projects/lighter) | n/a | **Stage 0**, Appchain | underReview message still present, and the desert-mode `display.warning` text is still present |
| 2026-05-19 13:15 | [`307f5c3`](https://github.com/l2beat/l2beat/commit/307f5c3dfdab6a4f88448861a0bb75f0043b762b) Dailies (grvt, myria, lighter…) | S1 `verifierContractsReproducible` **false → true**. Risk view `proposerFailure` PROPOSER_CANNOT_WITHDRAW → PROPOSER_USE_ESCAPE_HATCH_ZK. Project `display.warning` (desert mode) **removed**. DA/escape-hatch text updated (state snapshot published) | **Stage 0 (calc.)**. Stage 1 is still missing (principle, usersHave7DaysToExit, usersCanExitWithoutCooperation, securityCouncilProperlySetUp = false). | underReview message unchanged, because rollupNodeSourceAvailable is still 'UnderReview' |
| 2026-05-23 15:46 | [`abff564`](https://github.com/l2beat/l2beat/commit/abff564c9d5cf273d1708b3509cfd10eb11a791e) "Fix lighter node description" | S0 `rollupNodeSourceAvailable` **'UnderReview' → true**, with `rollupNodeLink: https://github.com/elliottech/lighter-prover/tree/main` added (required when true). All other inputs unchanged. | **Stage 0 (calc.)** | **underReview message removed**: `getMessage` returns undefined when satisfied === true |
| 2026-08-17 12:00 | Countdown `PROJECT_COUNTDOWNS.stageChanges` expires ([countdowns.ts](https://github.com/l2beat/l2beat/blob/25765a155af6d210da1dab371efaf34753727132/packages/config/src/global/countdowns.ts), same value at `main`) | Upcoming S1 items (noRedTrustedSetups, proverSourcePublished, verifierContractsReproducible, programHashesReproducible) become regular requirements. For Lighter these are true or null. | Stage 0 (calc.). Nothing changes, because Lighter was never at Stage 1. | none |
| 2026-08-18 07:17 | [`535fd9f`](https://github.com/l2beat/l2beat/commit/535fd9ff9) "Fix Rollup Stage tests" | Makes `upcoming` an injectable parameter that defaults to the same `UPCOMING_STAGE_REQUIREMENTS`. Evaluation is unchanged. | Stage 0 (calc.) | none |
| 2026-09-14 09:14 | **Observed:** Wayback [20260914091417](https://web.archive.org/web/20260914091417/https://l2beat.com/layer2s/projects/lighter) | n/a | **Stage 0** (`stageConfig.stage = "Stage 0"`, nextStage "Stage 1") | no `message` object; the underReview text is absent |
| 2026-10-12 08:01 | **Observed:** Wayback [20261012080116](https://web.archive.org/web/20261012080116/https://l2beat.com/layer2s/projects/lighter) | n/a | **Stage 0** | no `message`; underReview text absent |
| 2026-10-12 12:51 | [`818bfe8`](https://github.com/l2beat/l2beat/commit/818bfe8d3) "Cap Validium and Optimium stages at Stage 1" | Touches only `getAltDaStage.ts` and alt-DA projects/templates, not `getRollupStage.ts`, `stage.ts` or `lighter.ts`. | Not applicable to Lighter | — |
| 2026-10-27 | `main` [`b3346aa`](https://github.com/l2beat/l2beat/blob/b3346aafa392488900d7a556a206cfabc7acf611/packages/config/src/projects/lighter/lighter.ts#L211-L240) and live page [l2beat.com/layer2s/projects/lighter#stage](https://l2beat.com/layer2s/projects/lighter#stage) | Same inputs as after 2026-05-23 | **Stage 0** both calculated and observed. The live page says "Lighter is a Stage 0 Appchain ZK Rollup": Stage 1 has "4 issues need fixing" (principle, censorable withdrawals, <7d upgrade exit, Security Council) and Stage 2 has 2. There is no under-review notice. | none |

The other 22 `lighter.ts` commits in the window had no stage, checklist, `type`, `capability` or stage-warning edits. These are the dailies and the interop, tracked-txs, governance-text, markdown-extraction and ossification commits (26f3ca6, 92da0dc, 58d130d, 62f0d95, 97882e4, ac2f335, 05f76f8, …). The filtered diff output covered all 30 commits.

### Evaluator facts at baseline (unchanged at `main`)

- [`stage.ts`@25765a1](https://github.com/l2beat/l2beat/blob/25765a155af6d210da1dab371efaf34753727132/packages/config/src/common/stages/stage.ts):
  - `highestStageReached` starts at `'Stage 0'` (L65).
  - Unmet items only populate `missing` when `blueprintStage.name !== 'Stage 0'` (L117, L137-139). So **stage-0 items, including `'UnderReview'`, can never lower the label**. They only produce a `message` of type `underReview` or `warning` (L153-165, L260-276).
  - The label advances only if `missing === undefined` (L195-197).
  - A `downgradePending` timer is set only if the stage has no other missing items (L182-193). Lighter's Stage 1 always had other missing items, so it never had a pending downgrade.
- `git diff 25765a1 b3346aa -- stage.ts` is empty.
- [`processing/utils/getStage.ts`](https://github.com/l2beat/l2beat/blob/25765a155af6d210da1dab371efaf34753727132/packages/config/src/processing/utils/getStage.ts) maps only `stage: 'NotApplicable'` to "Not applicable" and `stage: 'UnderReview'` to "Under review". Those values come from templates (`underReview.ts`, `upcoming.ts`, `opStack`, …), and Lighter's literal config never used them. The file is unchanged at `main`.
- The frontend badge [`StageBadge.tsx`@25765a1](https://github.com/l2beat/l2beat/blob/25765a155af6d210da1dab371efaf34753727132/packages/frontend/src/components/badge/StageBadge.tsx) renders `stageConfig.stage`, plus "Appchain" when `isAppchain`.
  - In the window its only diffs were a color class and tooltip-HTML changes.
  - `StageSection.tsx` shows the `message` as a separate WarningBar (`message.type === 'warning'` ? warning icon : under-review icon) and does not change the badge.
- Lighter has no `reviewStatus`/`isUnderReview` field at baseline or at `main`.

## 3. Answer

**No stage-designation change was found in the window.** Lighter was **Stage 0 (Appchain)** at the baseline and stayed Stage 0 through 2026-10-27:

- **Calculated** at every input change (2026-04-24 baseline, 05-06, 05-19, 05-23), with the evaluator, countdown and display logic checked at each point.
- **Observed** on archived and live L2BEAT pages on 2026-04-22, 05-12, 09-14, 10-12 and 10-27.

Things that did **not** happen in the window:

- **No transition to or from Not applicable or below Stage 0.** The stage was never `NotApplicable` or `UnderReview`.
- **No numerical 0→1 or 1→2 change.** Stage 1 always had unmet requirements: principle, usersHave7DaysToExit, usersCanExitWithoutCooperation and securityCouncilProperlySetUp were all false, and none of them changed in the window.
- **No temporary downgrade and no pending-downgrade timer.** The 2026-08-17 countdown could not affect a Stage 0 project.

Two distinct states existed within Stage 0:

| Period | State |
|---|---|
| Up to 2026-05-23 (code) | "Stage 0 with an under-review notice". `rollupNodeSourceAvailable: 'UnderReview'` produced the message "The requirement for available node software is under review". The badge was still a plain Stage 0. |
| From 2026-05-23 (code) | "Stage 0" with no notice. |

**Were May 19 and May 23 only checklist improvements? Yes.**

- **May 19 (`307f5c3`):** a Stage 1 checklist item went false → true, a risk-view item changed, and the project-level desert-mode `display.warning` was removed. It did not change the label.
- **May 23 (`abff564`):** a Stage 0 requirement went 'UnderReview' → satisfied. This removed only the under-review warning bar and made the requirement show as met. It did not change the label.

The pre-window commits "Lighter escape hatch downgrade" (2026-04-14) and "rosette to red" (2026-04-17) came before the window.

## 4. Gaps and limits

- **Deploy dates:** the dates the May 19 and May 23 code changes went live on l2beat.com are **NOT FOUND**.
  - Wayback shows the under-review text still present on 2026-05-12 and absent by 2026-09-14.
  - There is no archived capture of the project page between 2026-05-12 and 2026-09-14 (CDX query for `/scaling/projects/lighter` and `/layer2s/projects/lighter`, 2026-03-01 to 2026-10-27). So the publication date of the notice's removal is known only to fall within that range.
- **Labels were checked by hand, not by running code.** The calculated labels come from reading the evaluator source at the cited revisions, not from executing L2BEAT's build. They agree with every observed badge.
- **Coverage gaps:**
  - Commits that touch only other files in `projects/lighter/` (discovery and ossification files) were not individually inspected. The stage inputs are literal values in `lighter.ts`, so these files cannot feed the stage.
  - Frontend files other than the badge, cell and section files were not audited.
- **Untested display path:** no evidence was found of any other code path that could override the label (for example an emergency or archive flag), but this was not tested exhaustively.
