Skip to content

Latest commit

 

History

History
228 lines (154 loc) · 33.5 KB

RULES.md

File metadata and controls

228 lines (154 loc) · 33.5 KB

DLE Explorer programming rules

Read-only SPA for the isolated CoNET-DLE lab. Not Blockscout. Not a tip VM browser.

Public host: https://dle.conet.network (authorized). Do not invent extra dle.* hostnames.

After any Explorer programming or display-spec change, update this file in the same task (conet-dle-write-back-subproject.mdc).

Freeze qualification display boundary (2026-09-23)

Explorer may display the 30-day clock, seating, heartbeat, lab certificate, and on-demand overlays as non-green evidence, but must not present any of them as production qualification. The production result is fail-closed until the structured seven-node report proves consistent release/roster/snapshot/freeze state, committed Archive Certificate/hash-index evidence, current production BFT prevote/precommit/certificate evidence, and production (C_G) with an L1 archive group-id view. Trade is out of scope for this round; a mock Trade flow must remain explicitly laboratory-only.

The current captured result is pilot/evidence/conet-dle-p23-live-2026-08/qualification-report-2026-09-23.json with verdict PARTIAL_SUCCESS_NOT_QUALIFIED.

Home metrics (2026-08-16)

The first metric row is:

Slot Label Value Notes
1 Chain ID 0x44c45 CoNET-DLE Testnet EIP-155 eth_chainId. Hint = CoNET-DLE Testnet. No “Decimal 281,669. Not CoNET L1 224422.” Under the value: Group ID capsule = bootstrap L1 registerTxHash 0x3076a806…6f2ad0. Click opens CoNET L1 Blockscout /tx/{hash} via openExternalUrl. Not tip.hash.
2 Clusters liveGroupCount Live archive groups (G_e). Genesis is 1. After lab M6 fission = 2.
3 Archives roster length · 5+2 Home = official G1 voting seats only (officialVoting === true, always 7). P11 / G2 / Seoul extras are not Home seats. /archives lists all lab archive IPs (G1 + G2 + extras), grouped.
4 Archive Certificate Available / Empty Tip finality object.

Removed: Home Tip height MetricCard. Archive Certificate height on NFT 42 is written to 0x1 after AC and does not grow. Showing it as a dashboard number is misleading.

Kept: the Tip hash capsule under the metric row (DLE /hash/ lookup), not a height panel. That capsule is not the Chain ID L1 register tx.

Chain ID + Group ID capsule

  • Value in the card: CoNET-DLE Testnet EIP-155 hex (0x44c45). Hint: CoNET-DLE Testnet.
  • Capsule under it: label Group ID; value = L1 bootstrap group register tx (BOOTSTRAP_GROUP_REGISTER_TX_HASH in config/l1Routing.ts), copied from the CoNET deploy snapshot. Do not ../.. import deployments/.
  • Click: https://mainnet.conet.network/tx/{hash} through this subproject’s openExternalUrl. Copy writes the full 32-byte hash.
  • Not lab decimal 281669, not CoNET L1 chain id 224422 as hint text, not L1 storage uint 1, not dle_tip.hash / AC valueHash.

Clusters semantics

  • Clusters = (G_e) = distinct live groupIds on the lab route table (including the genesis group).
  • No fission ⇒ 1. Creating asset / storage / trade lab chains copies NFT 42’s Group ID (bootstrap register tx hash) and must not increment this number.
  • A later fission that introduces a new Group ID increments (G_e) by 1. Production Group ID is that group’s L1 register tx hash. Lab M6 + G2 L1 register + host cutover (2026-08-16): hosts emit 0xf781f2c23fe3b3dac09dc3e1929016b0af200ee93978e916df64d750876d5153 as hop1.ownGroupId / liveGroupIds. canonicalGroupId still maps leftover laboratory keccak / 2 / 0x2 onto that tx. Show the canonical hash under Clusters with a Blockscout /tx/ link. The Chain ID Group ID capsule stays the first-group bootstrap tx only.

Trusted fields (Explorer must not ../.. import runtime):

GET /health          → liveGroupCount, liveGroupIds
GET /api/v2/dle      → same at top level and under archive

Parse only a trusted integer >= 1. Missing field, timeout, or non-2xx: keep last trusted value or default 1. Never treat failure as 0 or empty.

Legacy /health (unupgraded archives): parseLiveGroupIds / parseClusterCount must run canonicalGroupId on each id before unique-count. [dle.lab.group.v1] and [dle.lab.group.v1, 0x3076…] are one cluster. Prefer unique canonical liveGroupIds over a raw liveGroupCount that double-counted aliases. parseWaitingPool / parseSelectionLog canonicalize groupId. parseArchiveInfo defaults missing chainName to CoNET-DLE Testnet. Copy canonicalGroupId / sameGroupId in explorer/src/protocol.ts — do not ../.. import runtime.

Home hint copy (English):

  • clusterCount <= 1 → Genesis cluster — no fission yet
  • else → N live archive groups after fission

Implementation: HomePage.tsx MetricCard Clusters; useArchiveFeed.ts + parseClusterCount / parseLiveGroupIds; default GENESIS_CLUSTER_COUNT = 1.

Home chrome (2026-08-28)

Home must not render:

  • the Archive endpoint form (URL input + Use endpoint)
  • the Why this is not Blockscout explainer panel

Public SPA uses same-origin https://dle.conet.network. Local default remains http://127.0.0.1:27101 from explorer config, not a Home form. setArchiveUrl may stay in the feed hook for tests / stored URL; it is not a Home control.

Hash lookup (2026-08-16 M7)

/hash/:hash pills must distinguish first-class kinds. A hit on tipStateRoot / membershipRoot shows Tip state root / Membership root, not Archive Certificate.

locator.kind Pill
ac Archive Certificate
prevoteQc Prevote QC
tipStateRoot Tip state root
membershipRoot Membership root

Not-found copy: these roots are first-class kinds; a hit returns the typed object, not the AC. Do not ../.. import runtime kinds — copy the English labels in HashLookupPage.tsx.

Loading (2026-08-28)

Until lookup / proof returns, /hash/:hash must show a spinning Loader2 and Loading hash detail… (role="status", aria-busy). Changing the hash must clear the previous detail immediately. Do not use an auto-dismiss Toast.

Certificates (2026-08-16 P6)

Certificates page may show laboratory new-chain counts from trusted /health:

Field Meaning
newchainCount Accepted Mode A lab chains
newchainArchivePending (Q_V) passed, per-chain AC not yet formed
newchainArchiveCertified Per-chainNftId 4-of-5 AC present
newchainValidatorQuorum Lab (Q_V) size (5)
newchainValidatorQuorumEip712 Lab (Q_V) uses EIP-712 ArchiveValidatorQuorumAttest (P18); not production
newchainHmacForgeable false after P18 cutover; disk HMAC (Q_V) keep-only
newchainOfficialStandbysReady Lab overlay: two official standbys signed EIP-712 readiness (P22); extra fd-08 does not count
newchainStandbyReadyEip712 Lab new-chain accept gate uses EIP-712 readiness; not production OperatorDomain / 30-day
warmupStartedAt Operator warmup stamp (ISO). Read-only. Not 30-day qualification
pilotStartedAt Operator 30-day clock stamp (ISO). Live 2026-08-18T09:53:58.092Z. Not qualification
clockIsNotQualification Always treat as true for UI. Clock ≠ PilotQualificationGate
pilotQualified Certificates JSON always shows false when any clock field is present. Never paint as qualified

Home Clusters stays (G_e). A new-chain AC must not change NFT 42 tip / eth_blockNumber. New-chain AC is not an L1 birth certificate and not 30-day qualification. Failed health keeps last trusted snapshot. SelectionLog attests on this page are lab EIP-712 ArchiveOnDemandAttest (P17); do not paint them as HMAC or as 30-day qualification. The on-demand lab beacon is freeze-then-bind lab keccak (P19), not production CL RANDAO. Do not paint ondemandLabBeaconAfterFreeze as live RANDAO. Wait hooks are not intra-group gossip (P20); lab HTTP is not production DePIN gossip. Do not paint ondemandHookNotGossip as production gossip. New-chain (Q_V) on this page is lab EIP-712 ArchiveValidatorQuorumAttest (P18); do not paint newchainValidatorQuorumEip712 as production. P22 may expose newchainOfficialStandbysReady / newchainStandbyReadyEip712 on /health; do not paint them as seating, production OperatorDomain, or the 30-day gate. Extra fd-08 does not count. Do not change archiveSeating.ts.

Seating vs reachability (2026-08-16)

Whitepaper §5.2.0f / runtime RULES.md §ArchiveSyncQualificationV1.

GET /health alive, lastQuorumOk, lastPeerOk, and heartbeats prove reachability only. Explorer MUST NOT label a host as seating-qualified / SyncQualified / “caught up” from those fields.

Laboratory ArchiveStateChallengeV1 is implemented. Merge health.syncQualification + health.syncRoster. A green seating pill is allowed only when seatingQualified === true. Sync phase labels use SYNCING / CLAIMED_SYNC / STATE_CHALLENGE / QUALIFIED / REJECTED. Home Seating gauge uses that same boolean; Quorum remains heartbeat / BFT AC reachability. Do not call HTTP liveness “archive qualification”. Prefer GET /liveness for process-up; full /health includes sync.health() and must not be the deploy probe. Green pills on a split hashIndexRoot / lastACRef are not a seated group — compare the four roots before treating the row as wipe-safe. Lab P9 landed (2026-08-17): every hosted chainNftId (health.labCgOpening === 'all-hosted'; unique opening 2103). That is not the production 30-day (C_G) open. Do not scrape /sync/opening or rebuild challenges from Explorer. This is not the 30-day PilotQualificationGate.

P8c landed: /health no longer rebuilds pendingChallenge. Explorer still scrapes /health for syncQualification.phase / seatingQualified + syncRoster only — do not add a second seating poll or read pendingChallenge from health. Green pills on a split hashIndexRoot / lastACRef are not wipe-safe. P8d landed: random wipe fd-05+fd-06; join-window leaf stayed 5194; no ERR_SYNC_CHALLENGE_STALE. P10 landed: /health may also expose hasUnseatedActive / alignedQualifiedCount (read-only). Do not scrape /sync/opening for P10. A REJECTED active is unseated — do not paint it green. Do not treat a voter-missing reject as a candidate fault. P11 landed: extra joiner fd-08 is outside official 5+2 — Home Archives stays 7. Do not paint an 8th voting seat. Live accept 2026-08-17T07:52:17Z: joiner QUALIFIED, official seven still QUALIFIED. P12 landed: seating votes are lab EIP-712; do not paint seatingEip712 as production. Green pills stay seatingQualified === true only. P13 landed: challenge freeze-then-bind is lab-labeled (labBeaconAfterFreeze / notProductionBeacon). Do not paint those flags as production CL RANDAO. P14 landed: lab freezer hosted-set / labCgOpening is not production (C_G). Do not paint productionCgAvailable or an injected L1 small-set as a live L1 full scan. P15 landed: challenge / opening are lab EIP-712 (challengeEip712). Do not paint challengeEip712 as production. P16 landed: BFT AC votes are lab EIP-712 ArchiveBftVote (bftEip712). Do not paint bftEip712 as a frozen L1 wrapper or corpus SSZ. P17 landed: on-demand attests are lab EIP-712 ArchiveOnDemandAttest (ondemandEip712). Do not paint ondemandEip712 / endorsed as 30-day qualification or a production beacon. The on-demand lab beacon was keccak after freeze at P17. P18 landed: new-chain (Q_V) is lab EIP-712 ArchiveValidatorQuorumAttest (newchainValidatorQuorumEip712). Do not paint newchainValidatorQuorumEip712 as production secp256k1 or 30-day qualification. P19 landed: on-demand beacon is freeze-then-bind lab keccak (ondemandLabBeaconAfterFreeze). Do not paint it as live CL RANDAO. P20 landed: wait hooks are not intra-group gossip (ondemandHookNotGossip). Do not paint lab HTTP hook as production DePIN gossip. P21 landed: certificate may expose hashIndexRoot; overlay hashIndexCommittedInAc is lab display when AC root ≠ ZERO32. Tree views stay committedInAc: false. Do not paint overlay as production AC commitment or the 30-day gate. P22 landed: /health may expose standbyReadyEip712 / officialStandbysReady / newchainOfficialStandbysReady / newchainStandbyReadyEip712. Extra fd-08 does not count. Do not paint those as seating, production OperatorDomain, or the 30-day gate. Do not change archiveSeating.ts. Green pills stay seatingQualified === true only.

Archives page (/archives, 2026-08-21)

Why the page once showed only 7: the SPA fixture was the official G1 voting roster only. Lab also has G2 (hosts-m6-g2.json, 7 hosts) and extras (P11 fd-08, Seoul standbys). Those were never Home seats and were omitted from /archives.

Group Source Count Home Archives?
G1 pilot/lab/hosts.json 7 (5+2) ✅ officialVoting
G2 pilot/lab/hosts-m6-g2.json 7 ❌ listed only
Extra P11 + Seoul (hosts-seoul-extra.json) 3+ ❌ listed only

Must:

  • /archives lists every lab archive row with public IP (IP …:27101), grouped G1 / G2 / Extra.
  • Home Archives KPI = officialVotingArchives().length (7 only).
  • Fixture: explorer/src/fixtures/labArchives.ts + wallets labArchiveWallets.ts.
  • Hydrate always starts from the full fixture so an old 7-row Local Storage snapshot cannot hide G2/extra.

Must not:

  • Count G2 / Seoul / P11 toward Home Archives.
  • Add Seoul / G2 / P11 to Explorer nginx Mode A voting upstream unless product explicitly expands the official roster.
  • Treat /archives row count as seating / 30-day qualification.

After P11 (Home display)

Official Home Archives stays the 7-domain roster. Extra joiner fd-08 is not an 8th Archives node. Seoul extras are not Home seats either. P12 landed: seating votes are lab EIP-712. Green seating pill remains seatingQualified === true only. Do not paint seatingEip712 / notL1Settled as production OperatorDomain or L1 settle. P13 landed: freeze-then-bind lab beacon is honest-labeled. Do not paint labBeaconAfterFreeze / notProductionBeacon as live CL RANDAO. P15 landed: challenge / opening are lab EIP-712. Do not paint challengeEip712 as production. P16 landed: BFT AC votes are lab EIP-712 ArchiveBftVote. Do not paint bftEip712 as a frozen L1 wrapper or corpus SSZ. P17 landed: on-demand attests are lab EIP-712 ArchiveOnDemandAttest (ondemandEip712). Do not paint ondemandEip712 / endorsed as 30-day qualification or a production beacon. The on-demand lab beacon was keccak after freeze at P17. P18 landed: new-chain (Q_V) is lab EIP-712 ArchiveValidatorQuorumAttest (newchainValidatorQuorumEip712). Do not paint newchainValidatorQuorumEip712 as production secp256k1 or 30-day qualification. P19 landed: on-demand beacon is freeze-then-bind lab keccak. Do not paint ondemandLabBeaconAfterFreeze as live CL RANDAO. P20 landed: wait hooks are not intra-group gossip. Do not paint ondemandHookNotGossip as production DePIN gossip. P21 landed: certificate may expose hashIndexRoot; overlay hashIndexCommittedInAc is lab display. Do not paint overlay as production AC commitment or the 30-day gate. P22 landed: /health may expose standbyReadyEip712 / officialStandbysReady / newchainOfficialStandbysReady. Extra fd-08 does not count. Do not paint those as seating or the 30-day gate. Do not change archiveSeating.ts. Green seating pills stay seatingQualified === true only. P14 landed: do not paint lab 2249 / labCgOpening / productionCgAvailable / an injected small-set as production (C_G). Completing those gates MUST NOT be shown as 30-day qualification. P23 landed (2026-08-17; honest 6/7): keep-data deploy of P12–P22 to official G1. Six hosts LIVE_OK with overlay fields under syncQualification. fd-01 new-chain 409→accept. fd-06 HTTP unstable. Do not claim 7/7 healthy or durable officialStandbysReady. Green pills stay seatingQualified === true only. P24 landed: isolated node.ts new-chain accept uses the same officialStandbysReady callback as lab-cli. P25 landed: Certificates + Home show non-green read-only overlays for officialStandbysReady / hashIndexCommittedInAc (src/lib/labOverlays.ts; parent npm run explorer:test 8/8). Green pills stay seatingQualified === true only. Missing overlay fields omit the chip. Public SPA published (2026-08-18T00:18:49Z): https://dle.conet.network/ serves index-U1o9ul_I.js (replaced stale index-DaEv6psZ.js). Live /health at publish still officialStandbysReady=false (count=1), hashIndexCommittedInAc=false — chips are warn/neutral, not green ready. P25 seating-copy honesty (same gate, not P26): Home Seating gauge + archive detail say lab EIP-712, never lab HMAC (src/lib/labSeatingCopy.ts). Deploy from parent-repo scripts/deployDleExplorer.sh (not this subproject). fd-06 remapped (2026-08-18, not P26): official standby seat keep-data on Explorer host 70.35.205.77 (~/dle-30d-lab :27101; domainId + wallet stay). Leftover 216.225.193.174 is excluded. Do not add 70.35.205.77:27101 to Explorer nginx upstream (standby is not an upstream; this is the Explorer host). Do not stop nginx / on-demand / newchain-user when starting the fd-06 DLE. Scrape 2026-08-18T00:52Z: honest 7/7 GET :27101/liveness; fd-01 /health still officialStandbysReady=false (count=1; ready is not sticky). Fan-out 2026-08-18T00:57Z: official standby envelopes POSTed to 7× /sync/standby-ready (200); six seats flickered ready=true then dropped as inventory grew (leafCount 9141→9145). Peer-stale 2026-08-18T01:03Z: fd-01 / fd-07 still pointed fd-06 at leftover .174. Peer-refresh 2026-08-18T01:10Z: lab:keep-refresh-fd06-peers ok; all official configs now http://70.35.205.77:27101. Seven-seat ready=true flickered at 01:12:01Z then dropped as roots drifted. Split 2026-08-18T07:05Z / 07:08Z: honest 7/7 LIVE_OK; two official standbys on different four roots (fd-06 camp A vs fd-07 camp B, +1 leaf race). Envelope POST cannot make count=2. 08:01Z flicker 6/7 then drop in 21s. Operator authorized inventory freeze via lab:keep-freeze-inventory / POST /sync/inventory-freeze. Engine + tests: runtime:test 157/157; pilot 14/14; explorer:test 8/8. Live freeze 2026-08-18T08:35Z: official 7 + extra fd-08 inventoryFrozen=true reason=operator; honest 7/7 LIVE_OK; officialStandbysReady=true count=2; leaf 9750; pilotStartedAt=null. Evidence: pilot/evidence/conet-dle-p23-live-2026-08/operator-inventory-freeze.json. Explorer nginx must not expose POST /sync/inventory-freeze or POST /sync/pilot-clock. /health may show warmupStartedAt / pilotStartedAt / clockIsNotQualification. Do not paint those as 30-day qualification. Do not add a green clock chip. Green seating pill remains seatingQualified === true only. Do not add .77:27101 to nginx. Operator authorized clock start via npm run lab:start-pilot-clock. Live clock 2026-08-18T09:53:58.092Z (warmupStartedAt=2026-08-14T17:10:16.786Z; pilotQualified=false; clockIsNotQualification=true). Clock ≠ qualification. Explorer clock overlay (2026-08-18, not P26): Certificates + Home show a non-green pilotClockPill from /health.pilotRunning (else derive from pilotStartedAt). Running → warn 30-day clock running (not qualified); explicit null / not started → neutral 30-day clock not started; missing fields omit the chip. pilotQualified: true is ignored. Never tone: 'ok'. Green seating pill remains seatingQualified === true only. Tests: npm run explorer:test 10/10. Public SPA published (2026-08-18T10:15:00Z): https://dle.conet.network/ now serves index-C8IdTq4H.js (replaced pre-clock index-U1o9ul_I.js). Live /health: pilotRunning=true, pilotStartedAt=2026-08-18T09:53:58.092Z, pilotQualified=false, clockIsNotQualification=true. Clock chip is warn, not green qualified. Do not change archiveSeating.ts. Do not paint overlays as production AC / 30-day. Do not invent P26. Runtime scrape 2026-08-18T23:41Z (~13.8h): 8/8 HTTP + clock-aligned + seating QUALIFIED; pilotQualified false; lastQuorumOk 6/8 (fd-07 peer=0); omitted leaf/ready/AC roots ≠ zero/empty. Evidence: pilot/evidence/conet-dle-p23-live-2026-08/runtime-review-2026-08-18T2341Z.json. Reviews: parent src/canvas/dle-mvp-runtime-review-2026-08-18.md · dle-mvp-work-review-2026-08-18.md.

Runtime scrape 2026-08-20T07:43:59Z (live; historical): seven official seats still on the operator inventory freeze sticky path and the 30-day pilot clock (pilotStartedAt=2026-08-18T09:53:58.092Z). At scrape time: HTTP OK 7/7, clock aligned 7/7, pilotRunning 7/7, seating QUALIFIED / seatingQualified 7/7, pilotQualified true 0/7, formal lastQuorumOk true 6/7. Extra fd-08 is not official. Evidence: pilot/evidence/conet-dle-p23-live-2026-08/runtime-review-2026-08-20T074359Z.json. Canvas: src/canvas/dle-mvp-runtime-review-2026-08-20.md. Do not invent P26 from this scrape.

Runtime scrape 2026-09-01T10:35:23Z (live; mid-window freeze assessment): wall-clock ~46.75% of the 30-day pilot (~336.6h since pilotStartedAt; remaining ~15.97d → target 2026-09-17T09:53:58.092Z). Formal seven still report sticky inventoryFrozen + reason=operator, clock alignment, pilotRunning, and seating QUALIFIED / seatingQualified — all 7/7. pilotQualified remains 0/7. Formal lastQuorumOk true degraded to 2/7 (fd-01, fd-04 only) vs Aug 20 6/7 — reachability observation only; do not treat as seating revocation, inventory unfreeze, or ops authorization. fd-05 reported lastQuorumOk=false with lastPeerOk=0. Formal leafCount / officialStandbysReady were all omit this scrape (omit ≠ 0 / false / emptied inventory). bftProcessStarted / hashIndexCommittedInAc true 0/7. Extra fd-08 still non-official. Public https://dle.conet.network/health may look healthy when upstream is fd-01; one public upstream ≠ fleet mean. Public SPA asset advanced to index-1pwcPW-S.js (was index-C8IdTq4H.js at clock-start); this assessment does not change SPA semantics. Evidence: pilot/evidence/conet-dle-p23-live-2026-08/runtime-review-2026-09-01Tmidwindow.json. Canvas: src/canvas/dle-30d-freeze-midwindow-assessment-2026-09-01.md. Do not invent P26; do not claim PilotQualificationGate passed.

Runtime scrape 2026-09-23T15:16:45.701Z (live; final post-window assessment): the wall-clock window ended, but the verdict is partial success / not qualified. Formal seven report HTTP, clock alignment, operator freeze, leafCount=9750, and seating QUALIFIED 7/7; pilotQualified is 0/7, quorum true 3/7, and fd-05 peer count is 0. The observed roster has 9–10 entries, with extra fd-08, fd-09, and fd-10, and views differ across nodes. officialStandbyReadyCount=4 is a classification drift, not four authorized official standbys: the runtime classifier excludes only fd-08, so extra Seoul seats can be counted. Inventory freeze blocks new hash-catalogue writes; it is not roster freeze. The Explorer must not render count 4 as four official standbys or as production readiness, and must continue to paint green seating only when seatingQualified === true. Production gates remain false 0/7. Evidence: pilot/evidence/conet-dle-p23-live-2026-08/runtime-review-2026-09-23Tpostwindow.json.

Mock auction page (/mock-auction, 2026-08)

Detail page (footer hidden). Local mock-L1 /mockl1/* + /trade/* against the configured archive endpoint. Home links with a warn pill Mock auction (local).

MVP round 2: session-only lab private keys may sign sell/buy/attest in the browser (ethers); keys are never written to localStorage / IndexedDB. Order / candidate hashing is mirrored in explorer/src/lib/mockAuctionWire.ts (no runtime import). Archive legality remains Archive-side when RPC custody is configured — the page may pass lab flags only for Archive without MOCK_L1_*.

MVP round 3: when Archive has on-chain settle configured, match timeline may show a real settlementTxHash from MockDleAuctionSettlement.settle (local Hardhat/Anvil). Do not paint lab demo fake hashes as mainnet settles.

MVP round 4: /mock-auction shows a Settlement summary (phase pills + HashCapsule for settlementTxHash) and may POST /trade/settle with executeOnChain so Archive runs authority settle. The browser never holds certificateAuthority / MOCK_L1_AUTHORITY_PRIVATE_KEY. Health pills may show custody: / settle: from /health (tradeRpcCustodyMode, tradeOnChainSettleConfigured).

MVP round 5: /mock-auction may POST /trade/list with the seller session private key (must match sell maker; never persisted) so Archive runs list into escrow. Settlement summary shows listTxHash / listError. Health pill list: from tradeListConfigured / tradeListMode. List before Archive settle when on-chain settle is enabled.

MVP round 6: /mock-auction may POST /trade/approve with the buyer session private key (must match buy maker; never persisted) so Archive runs ERC-20 approve for the quote. Settlement summary shows approveTxHash / approveError. Health pill approve: from tradeApproveConfigured / tradeApproveMode. Prefer list → approve → Archive settle.

MVP round 7: one-shot List → Approve → Settle CTA (fuchsia) runs list then approve then Archive settle with executeOnChain; individual CTAs retained. Archive settle preflight requires listTxHash + approveTxHash (and optional RPC eth_call); preflight 400 does not mark settlement_failed.

MVP round 8: Preflight CTA POSTs read-only /trade/preflight (no phase change); Settlement summary shows certificate fee split (1 bps / scanner / committee); settle / one-shot errors may prefix Preflight:.

MVP round 9: Unlist escrow POSTs /trade/unlist with seller session key (clears listTxHash, sets unlistTxHash; phase unchanged). Mark failed POSTs /trade/settle with outcome: 'failed'. Cancel sell order EIP-191 signs then POSTs /trade/cancel. Settlement summary shows unlistTxHash / unlistError / settlementError. Health pill unlist: from tradeUnlistConfigured / tradeUnlistMode.

MVP round 10: E2E/demo MOCK_L1_*_MODE=recovery (list → fail → unlist). Parent one-shot dle:mock-auction-e2e runs recovery then settle. Explorer copy must distinguish happy path vs recovery (settlement_failed → Unlist).

MVP round 11: Intro + help spell out recovery in English. One-shot Mark failed → Unlist CTA (stops on first 4xx). CI: DLE npm run mock-auction-ci; parent Hardhat test:dle + dle:mock-auction-e2e via .github/workflows/dle-mock-auction-hardhat.yml.

Rule Detail
Scope Local Hardhat/Anvil mock network only
UI May sign client orders/attests/list/approve/unlist/cancel with session keys; may ask Archive to settle/fail via HTTP; does not self-claim Archive legality / quorum; does not hold authority key or broadcast settle txs
Labels Always show mockL1Only / notProductionDepin pills; custody/list/approve/unlist/settle mode from health when trusted; recovery copy must say Unlist after settlement_failed
Forbidden Painting as CoNET mainnet, production DePIN, or live CL RANDAO; persisting private keys; treating demo fake hashes as on-chain settles

Lab new-chain page (/lab-newchain, 2026-08)

Detail page (footer hidden). Not Mock-L1 auction. Connect via EIP-6963 installed-wallet picker (same pattern as https://beamio.app/usdc-topup; ethers BrowserProvider on the chosen provider; no wagmi / WalletConnect). Wallet address fills Mode A user. Primary form classes: Asset (classId=1) and Storage (classId=2); Trade (classId=3) optional.

Rule Detail
Wire Mirror DleLabNewChainRequestV1 in explorer/src/lib/labNewchainWire.ts (aligned with runtime/src/shared/newchain.ts; no runtime import)
Wallet UI explorer/src/lib/injectedWallets.ts + Web3WalletBar: list installed wallets → user picks → eth_requestAccounts on that provider only. Desktop discovery = EIP-6963; do not read window.ethereum before pick (Phantom auto-login). Mobile with no inject: deep-link panel to open this page in MetaMask / Base / OKX / TP
Submit POST {archiveUrl}/newchain/request with schema, labOnly, notProductionDepin, notL1Nft, classId, user, nonce, salt
Submit result UI After loading ends, Submit panel must show outcome in-panel: success → requestId HashCapsule + chainNftId (+ optional valueHash / duplicate); failure → Archive error / reason (e.g. ERR_INVENTORY_FROZEN) + HTTP status. Store in submitResult — do not clear via list/health load() (setError(null) must not wipe submit outcome)
Nonce / salt Internal only — auto-generated (Date.now + random bytes32); not shown, not user-editable; rotate after each successful submit
Read GET /newchain/chains; after Connect, UI shows Your chains (owner) = rows where user equals the wallet (case-insensitive); /health new-chain counts when reachable
Sign Optional personal_sign ownership smoke before POST; Archive does not verify user signature
Storage Web3 session address in memory only; never persist private keys
Labels not L1 NFT / labOnly; predicted chainNftId must never be tip NFT 42
Nginx Public dle.conet.network must proxy Mode A: GET /newchain/chains, GET /newchain/queue, POST /newchain/request → lab upstream :27101 (same pool as /health / /liveness). Do not proxy /newchain/bft (archive peer only). Without these locations, same-origin Submit gets nginx 405 HTML (non-JSON response)
Forbidden Painting as L1 birth certificate, 30-day qualification, Mock auction, or production DePIN; importing runtime; exposing nonce/salt as editable form fields; single “Connect” that blindly uses default window.ethereum; public /newchain/bft

Home pill: Lab new-chain (Web3). Hook: useWeb3Wallet. Tests: explorer/test/lab-newchain-wire.test.ts, explorer/test/injected-wallets.test.ts.

Other Explorer invariants

  • Public HTTPS vhost (2026-08-21 / 2026-08-28): https://dle.conet.network/health connect-timeout (~22s) was not archive extraHealth. Live nginx on 70.35.205.77 had been left on HTTP bootstrap (listen 80 only; no :443; location / try_files SPA). Public :80 200’d HTML; public :443 timed out for /, /health, and /liveness. Certificate already existed (/etc/letsencrypt/live/dle.conet.network/, expiry 2026-11-12). Root cause: scripts/deployDleExplorer.sh always overwrote the live vhost with nginx-dle.conet.network.http-bootstrap.conf first; --skip-tls or a failed TLS step left that as the site. Must: if the Let’s Encrypt cert exists, install the full HTTPS + proxy conf and never leave bootstrap live. --skip-tls means skip certbot only. SPA try_files must not answer /health or /liveness.
  • nginx boot persist (2026-08-28): On 70.35.205.77, nginx.service must stay systemctl enable’d (WantedBy=multi-user.target). Drop-in /etc/systemd/system/nginx.service.d/dle-persist.conf (Restart=always, RestartSec=2s) so the process comes back after reboot or crash. deployDleExplorer.sh installs that drop-in and enable --now. Do not start nginx only from a one-shot SSH/nginx CLI. Do not restart geth / beacon-chain / validator to “keep Explorer up”.
  • Public probes: prefer GET /liveness (process-up). Full /health is extraHealth + clusterView. Nginx /health: proxy_read_timeout 12s, proxy_next_upstream_tries 1 (do not cascade 4×8s). Explorer FETCH_MS is 12s to match. Tokyo fd-05 from .77 can take ~7s; that is not a public connect-timeout.
  • Official G1 nginx upstream (parent-repo scripts/nginx-dle.conet.network.conf): 45.132.74.220:27101, 45.132.74.221:27101, 167.254.243.38:27101, 170.205.39.67:27101. Never proxy excluded IONOS 74.208.224.45 or 198.251.77.98. Do not proxy shared-beacon 216.225.197.189, leftover 216.225.193.174, or standby 212.227.242.207. Do not add Explorer host 70.35.205.77:27101 (fd-06 standby is colocated there). Do not expose POST /sync/inventory-freeze or POST /sync/pilot-clock on Explorer nginx.
  • No top navigation bar. Main pages: title capsule. Detail: circular back button. Tabs in the footer.
  • Refresh: setTimeout chain only. No setInterval.
  • Failed fetches keep the last trusted snapshot (beamio-trusted-vs-untrusted-fetch.mdc).
  • User-visible strings: English.
  • Independent package.json. Do not import runtime, archive-a, or archive-b.
  • Cache only archive URL + last trusted snapshot. No wallet keys on disk. Session keys on /mock-auction and injected Web3 address on /lab-newchain are memory-only and cleared on reload.

Related

  • Archive API: ../runtime/RULES.md §Archive (liveGroupCount) and §ArchiveSyncQualificationV1(/health ≠ seating)
  • Client: ../runtime/src/daemon/RULES.md
  • On-demand (not Clusters): ../runtime/src/shared/ondemand/RULES.md