{
  "schema": "datachain.erpc.fleet-status/v1",
  "generated_at": 1793494673,
  "generated_at_iso": "2026-11-01T00:57:53Z",
  "writer": {
    "id": "blue",
    "rpc": "http://127.0.0.1:8545",
    "public_edge": "https://erpc.datachain.network",
    "status": "healthy",
    "block_hex": "0x5417c8"
  },
  "edge": {
    "public_url": "https://erpc.datachain.network",
    "status": "healthy",
    "sample_ok": 10,
    "sample_n": 10,
    "sample_fail": 0,
    "fail_ratio": 0.0,
    "fail_ratio_threshold": 0.4,
    "resolved_a": [
      "159.65.208.206"
    ],
    "degraded_since": null,
    "degraded_for_secs": 0,
    "external_probes": {
      "enabled": true,
      "peers": [
        {
          "peer_id": "cerber-tanastok",
          "region": "gandi-paris",
          "resolver_ip": "159.65.208.206",
          "target_url": "https://erpc.datachain.network",
          "sample_n": 35,
          "sample_ok": 35,
          "sample_fail": 0,
          "fail_ratio": 0.0,
          "reports": 3,
          "last_report_at": 1793494400,
          "last_reason": null,
          "age_secs": 273,
          "status": "ok",
          "reasons": {
            "http_502": 0,
            "http_503": 0,
            "http_504": 0,
            "timeout": 0,
            "connect_error": 0,
            "tls_error": 0,
            "empty_body": 0,
            "body_hash_mismatch": 0,
            "missing_signature": 0,
            "bad_scheme": 0,
            "stale_or_future": 0,
            "untrusted_key": 0,
            "bad_signature": 0
          }
        }
      ],
      "peer_count": 1,
      "reports_in_window": 3,
      "malformed_lines": 1,
      "oldest_report_at": 1793493797,
      "newest_report_at": 1793494400,
      "ingest_path": "/var/lib/datachain-rope/fleet/external-probes.ndjson",
      "degraded_since": null,
      "degraded_for_secs": 0,
      "sustain_secs": 180,
      "fail_ratio_threshold": 0.1,
      "min_peers_for_escalation": 2,
      "window_secs": 900,
      "generated_at": 1793494673,
      "degraded_peer_count": 0,
      "degraded_peer_ids": [],
      "escalate": false
    },
    "note": "Peers must AND writer.status with edge.status - local writer healthy can coexist with public HTTPS 502s (nginx/DNS settle). edge.external_probes carries the multi-vantage-point view fed by cerber-* peers (spec: docs/EDGE_EXTERNAL_PROBES_INGEST_SPEC_v1.md)."
  },
  "readers": [
    {
      "url": "http://92.243.25.119:8545",
      "role": "reader"
    },
    {
      "url": "http://157.230.18.45:8545",
      "role": "reader"
    },
    {
      "url": "http://167.172.106.174:8545",
      "role": "reader"
    }
  ],
  "public_read_rpc_urls": [
    "https://erpc.datachain.network/v1/read"
  ],
  "unhealthy": [],
  "peer_sample_block_hex": "0x5417c8",
  "self_heal": {
    "unhealthy_since": null,
    "unhealthy_for_secs": 0,
    "deadline_secs": 900,
    "escalate_to_cerber": false,
    "escalate_reason_external_probes": false,
    "writer_restart_typical_secs": 420,
    "startup_grace_secs": 300,
    "writer_service_age_secs": 19318,
    "estimated_recovery_secs": 0,
    "estimated_recovery_at": null,
    "recommended_deadline_padding_secs": 0,
    "note": "CERBER pages when escalate_to_cerber is true (writer/edge non-healthy past deadline_secs, currently 900s). Swap clients MUST pad from recommended_deadline_padding_secs / estimated_recovery_at instead: writer=starting|healing still has pad>0 while escalate stays false. public_read_rpc_urls is the attester-only HTTPS reader (no BLUE) for FallbackProvider."
  },
  "last_heal": {
    "reason": "ok",
    "restarts_last_hour": 0
  },
  "ghost_reclaim": {
    "enabled": true,
    "reclaimed_total": 9683,
    "last_reclaim_at": 1792790974,
    "last_reclaim_count": 17,
    "last_reclaim_hashes": [],
    "last_scan_ghosts_found": 0,
    "last_scan_error": "none",
    "note": "Every HA tick diffs attester txpools vs BLUE; ghost raw txs are eth_sendRawTransaction'd into the sealer (2026-07-29)."
  },
  "writer_ingress": {
    "accept_queue": {
      "current": 0,
      "max": 4096,
      "saturated": false
    },
    "process": {
      "rss_bytes": 1179025408,
      "swap_bytes": 0,
      "threads": 31
    },
    "sigkills_1h": 0,
    "nginx_5m": {
      "total_requests": 35450,
      "status_5xx": 28,
      "upstream_timeouts": 4
    },
    "restarts_1h": 0,
    "note": "Writer ingress diagnostics (Ask D, 2026-09-08). accept_queue.current -> ss Recv-Q on :8545, saturated iff >=80% of max. process.rss_bytes/threads -> /proc/PID/status for datachain-rope. sigkills_1h -> journalctl grep for signal 9/OOM/killed-by (root cause class of the 2026-09-08 14:19Z anvil-vps writer death). nginx_5m -> docker logs rope-nginx grep for POST-path 5xx and 'upstream timed out'; ratio = status_5xx/total_requests. restarts_1h -> internal fleet-ha bucket. Any field = -1 means the collection source is broken on this host (needs ops attention, not a healthy zero). CERBER R12 SHOULD page on sigkills_1h > 0 OR on sustained accept_queue.saturated=true OR on nginx_5m ratio > 0.05 for 3 consecutive ticks (~90s)."
  },
  "notes": [
    "eth_* reads fail over via nginx rpc_read_failover when BLUE times out",
    "eth_sendRawTransaction and all rope_* stay pinned to BLUE (no dual-writer)",
    "txpool_* is primary-only so public pending matches the sealer mempool",
    "ghost_reclaim injects attester-only mempool txs into BLUE automatically",
    "sick BLUE self-heals via systemctl restart datachain-rope.service",
    "edge.* is sampled every HA tick against the public HTTPS URL (not loopback)",
    "users must never edit MetaMask RPC - wallets pull https://dcscan.io/api/v1/network/config",
    "https://erpc.datachain.network/v1/read is attester-only (GREEN/DO); never send writes there",
    "writer_ingress.* gives DCSwap CERBER the SSH-free view of writer health (Ask D, 2026-09-08)"
  ]
}
