# ECP-0093: `ecp-forge` OP Stack Sepolia testnet and observation consensus rail Status: Draft ## Problem / context `every.channel` now has additive Ethereum-compatible commitments and signatures, but it does not yet have: - a concrete chain-operator path for bringing up a real OP Stack testnet on `ecp-forge`, - a repo-owned bootstrap workflow that matches the current official OP Stack deployment guidance, - an application-level consensus surface for "reality-derived" blocks where witnesses attest to the same observed broadcast epoch, or - a reproducible smoke path that pushes real every.channel archive data through the rail. The current `EveryChannelRail` contract is useful as a compact pointer store, but it does not capture the consensus shape requested by the founder: nodes independently discover an observation from reality, then witnesses sign off on that shared observation hash. ## Decision Adopt a two-part rollout: 1. Stand up an OP Stack Sepolia-anchored testnet on `ecp-forge` using the official OP Stack stack: `op-deployer`, `op-geth`, `op-node`, `op-batcher`, `op-proposer`, `op-challenger`, and optional `op-dispute-mon`. 2. Introduce an application-level observation consensus rail for every.channel: - an `ObservationHeader` is derived from real stream epoch data, - witnesses attest to the derived observation hash, - the observation is finalized when quorum is reached, - full media bytes remain off-chain. This keeps Ethereum as the ordering/finality substrate while making the application-level "block" come from reality, not from arbitrary contract writes. ## Details ### `ecp-forge` OP Stack deployment - Use the official OP Stack deployment topology described in the current Optimism chain-operator tutorial: - Sepolia L1 contracts via `op-deployer`, - `op-geth` + `op-node` sequencer, - `op-batcher`, - `op-proposer`, - `op-challenger`, - optional `op-dispute-mon`. - Host these components on `ecp-forge` via repo-owned NixOS services and pinned official container images. - Keep L2 RPC surfaces private by default; expose P2P only as required for testnet participation. - Default L1 RPC / beacon endpoints may use public Sepolia providers, but deployment and operation require a repo-managed Sepolia private key secret with sufficient ETH. - `op-challenger` and `op-dispute-mon` require a repo-managed Cannon absolute prestate artifact. If the prestate is absent, the core rollup may still run, but the dispute path is intentionally gated off instead of starting with incomplete configuration. ### Observation consensus Introduce a new application-level surface alongside `EveryChannelRail`: - `ObservationHeader` - `streamHash` - `epochHash` - `parentObservationHash` - `dataRoot` - `locatorHash` - `observedUnixMs` - `sequence` - `ObservationHash` - `keccak256(abi.encode(ObservationHeader))` - `ObservationSlot` - `keccak256(abi.encode(streamHash, epochHash))` Witnesses attest to an `ObservationHash`, not directly to arbitrary payloads. This lets the chain finalize the winning observation for a `(stream, epoch)` slot without storing the full manifest, chunk list, PSIP data, or media bytes. ### Witness model For the first testnet tranche: - witness membership is registry-backed, - quorum is fixed and explicit, - no staking or slashing is required, - sending an attestation transaction from a witness address is sufficient "sign off". Off-chain EIP-712 witness signatures may be added later for relayed submission, but they are not a prerequisite for the first live testnet. ### Real-data validation Use real every.channel archive data already present on `ecp-forge` as the smoke source: - derive observation headers from actual archive JSONL entries, - submit them to a local Anvil deployment of the observation ledger, - prove quorum/finalization against production-shaped data before attempting Sepolia rollout. ## Components - `contracts/EveryChannelRail.sol` - compact manifest / transport pointer store (existing rail) - `contracts/EveryChannelWitnessRegistry.sol` - witness membership for observation consensus - `contracts/EveryChannelObservationLedger.sol` - candidate observation storage, attestation tracking, and finalization - `scripts/op-stack/download-op-deployer.sh` - pinned `op-deployer` fetch helper - `scripts/op-stack/setup-rollup.sh` - repo-owned OP Stack bootstrap/config generation - `scripts/op-stack/anvil-reality-smoke.sh` - local smoke against Anvil using real `ecp-forge` archive data - `nix/modules/ec-op-stack.nix` - NixOS service/module surface for `ecp-forge` ## Alternatives considered - Use Base Sepolia directly as the only test environment. Rejected because it validates contract compatibility, but not operation of an every.channel-owned chain. - Wait for a future custom consensus implementation before any chain bring-up. Rejected because it delays operator learning and hides infrastructure problems until late. - Put media bytes or full manifests on chain. Rejected because it is operationally wasteful and not required for observation finalization. ## Rollout / teardown plan 1. Add the observation-ledger contracts and Foundry tests. 2. Add Anvil + real-archive smoke scripts. 3. Add an `ec-op-stack` Nix module and `ecp-forge` integration points. 4. Wire secrets for a Sepolia deployment key on `ecp-forge`. 5. Bring up the OP Stack services on `ecp-forge`. 6. Deploy observation-ledger contracts onto the new chain. 7. Submit real archive-derived observations and verify finalization. Teardown: - disable `services.every-channel.op-stack`, - stop and remove the OP Stack containers/state directories, - preserve the local Anvil smoke path and the additive Ethereum rail code. ## Open questions - Should `ecp-forge` be the only sequencer for the first tranche, or should a second verifier-only peer be provisioned immediately? - When we move beyond a registry-backed witness set, do we want bonds, reputation, or both? - Should finalized observation slots bridge back into the existing manifest/transport pointer contract automatically, or remain a separate ledger surface for the first rollout?