# Telos Validator Checker Requirements

## Source Review

Sources reviewed:

- Live page: https://infinitybloc.io/validators
- Source repository: https://github.com/molty365/infinitybloc-site
- Relevant repository files:
  - `validators.html`
  - `scripts/validate_bps.py`
  - `validation/latest.json`
  - `validation/history.json`

The live page is a static dashboard for Telos block producer validation. It does not validate producers directly in the browser. It consumes JSON snapshots generated by a scheduled validation process and renders summary metrics, a historical performance chart, and a searchable producer table.

## Product Goal

Create a standalone web app that presents the same validator-checking results as the Infinity Bloc validators page while using neutral styling and a fresh implementation.

The app must let a user answer these questions quickly:

- Which registered Telos block producers are currently passing mainnet SSL and API checks?
- Which producers expose working testnet endpoints?
- How do API latency, CPU benchmark time, and missed block counts trend over recent validation runs?
- Which producers are active schedule producers versus standby producers?
- What validation errors were observed for failing producers?

## Data Inputs

### Latest Snapshot

The app must load a latest validation snapshot. It should support `data/latest.json` for local snapshots and may fall back to `https://infinitybloc.io/validation/latest.json` for live public data.

Required top-level fields:

- `generatedAt`: ISO timestamp for the validation run.
- `totalProducers`: total count of validated active producers.
- `producers`: array of producer validation results.

Required producer fields:

- `owner`: Telos producer account name.
- `scheduleType`: `active` or `standby`.
- `total_votes`: vote weight string from chain data.
- `url`: registered producer URL.
- `is_active`: chain active flag.
- `sslVerified`: mainnet SSL check result.
- `apiVerified`: mainnet API check result.
- `apiResponseMs`: mainnet API response time in milliseconds, or `-1` when unavailable.
- `sslVerifiedTestNet`: testnet SSL check result.
- `apiVerifiedTestNet`: testnet API check result.
- `apiResponseMsTestNet`: testnet API response time in milliseconds, or `-1` when unavailable.
- `missedBlocksPerRotation`: current missed block count per rotation.
- `lifetimeMissedBlocks`: lifetime missed blocks.
- `lifetimeProducedBlocks`: lifetime produced blocks.
- `timesKicked`: chain kick count.
- `p2pEndpoint`: seed endpoint when available.
- `org`: parsed BP metadata from `bp.json`.
- `validationErrors`: array of human-readable validation errors.
- `checkedAt`: ISO timestamp for the producer check.

### History Snapshot

The app must optionally load historical validation data. It should support `data/history.json` for local snapshots and may fall back to `https://infinitybloc.io/validation/history.json` for live public data.

Required shape:

```json
{
  "runs": [
    {
      "t": "ISO timestamp",
      "bps": {
        "producername": 123
      },
      "missed": {
        "producername": 0
      },
      "cpu": {
        "producername": 300
      }
    }
  ]
}
```

History fields:

- `runs[].t`: run timestamp.
- `runs[].bps`: mainnet API latency by producer, in milliseconds.
- `runs[].missed`: missed blocks per rotation by producer.
- `runs[].cpu`: optional CPU benchmark timing by producer, in microseconds.

The upstream source keeps up to 56 runs, approximately 14 days at a 6-hour cadence.

## Validation Process Requirements

The data generation process is external to the browser app. The source repository uses `scripts/validate_bps.py`, which performs these operations:

- Fetch active producer schedule from `https://mainnet.telos.net/v1/chain/get_producer_schedule`.
- Fetch all registered producers through `https://mainnet.telos.net/v1/chain/get_producers`.
- Keep producers where `is_active == 1`.
- Tag producers as `active` if they appear in the current active schedule, otherwise `standby`.
- Resolve each producer metadata file through `chains.json` and fallback to `/bp.json`.
- Select an SSL API endpoint by preferring query nodes, then producer nodes, then seed nodes.
- Check mainnet SSL validity.
- Check mainnet API health through `/v1/chain/get_info` and record response time.
- If a testnet path exists in `chains.json`, repeat SSL and API checks for testnet.
- Record seed P2P endpoint when available.
- Preserve validation errors for missing files, failed SSL, failed API, and missing endpoints.
- Optionally push benchmark transactions to measure CPU execution time by block producer.
- Append history entries containing API latency, missed blocks, and optional CPU timing.

## Functional Requirements

### Loading and Error States

- The app must load latest validation data before rendering summary metrics or the table.
- The app should load history data when available.
- If latest data cannot load, show a clear error state.
- If history cannot load, keep the table and summary usable while showing an empty chart state.
- If there are no producers, show an empty data state.

### Summary Metrics

The app must display:

- Total registered producers in the latest snapshot.
- Count of mainnet passing producers where `sslVerified && apiVerified`.
- Count of mainnet failing producers.
- Count of testnet passing producers where `sslVerifiedTestNet && apiVerifiedTestNet`.
- Average mainnet API latency across producers with valid positive `apiResponseMs`.
- Count of active schedule producers.

### Performance Chart

The app must provide a historical chart with these modes:

- CPU time, sourced from `runs[].cpu`, measured in microseconds.
- API latency, sourced from `runs[].bps`, measured in milliseconds.
- Missed blocks, sourced from `runs[].missed`, measured as block counts.

Chart requirements:

- Render all producers present in the selected history field.
- Preserve missing data as gaps for CPU mode.
- Span gaps for API latency and missed-block modes when producers are absent in individual runs.
- Show timestamp labels along the x-axis.
- Start the y-axis at zero.
- Provide a producer legend.
- Let users hide or show individual producer series.
- Provide select all and deselect all controls for chart series.
- Show a helpful empty state when there is insufficient history for the selected mode.

### Producer Table

The app must display a producer table with:

- Rank within the current filtered and sorted view.
- Schedule type badge.
- Producer owner.
- Optional country code from `org.location.country`.
- Website link from `org.website` or fallback `url`.
- Mainnet SSL status.
- Mainnet API status.
- Mainnet API latency.
- Testnet SSL status or `None` when no testnet data appears available.
- Testnet API status or `None` when no testnet data appears available.
- Testnet API latency.
- Missed blocks per rotation.
- Validation errors.

### Search, Filter, and Sort

The table must support:

- Text search across owner, candidate name, country, website, URL, and validation error text.
- Filters:
  - All
  - Passing
  - Failing
  - Testnet passing
  - Active
  - Standby
- Sortable columns for schedule type, producer, SSL, API, latency, testnet SSL, testnet API, testnet latency, and missed blocks.
- Sort direction toggling when the active sort column is clicked again.

## Non-Functional Requirements

- The app must be static and runnable from any simple HTTP server.
- The implementation should not depend on the original `validators.html` code.
- The UI should be neutral, accessible, and responsive.
- Table content must remain readable on narrow viewports through horizontal scrolling.
- Numeric values should use tabular alignment where practical.
- External producer data must be escaped before rendering as HTML.
- External links must only be rendered for `http:` and `https:` URLs.

## Acceptance Criteria

- Opening the app through a local HTTP server shows the validator dashboard.
- Summary metrics match the included `data/latest.json` snapshot.
- The performance chart can switch between CPU time, API latency, and missed blocks.
- Producer legend toggles hide and show chart series.
- Select all and deselect all update every chart series.
- Table filters return the expected subsets.
- Table search narrows results without breaking active filters.
- Sorting works for text, boolean, and numeric columns.
- Producer website links open in a new tab.
- Missing testnet data renders as `None` rather than `Fail`.
- Failed latest-data loading shows an error message instead of a broken interface.

## Out of Scope

- Recreating Infinity Bloc branding or visual styling.
- Running Telos chain validation directly in the browser.
- Managing GitHub Actions scheduling.
- Pushing benchmark transactions from the browser.
- Editing or reusing the upstream `validators.html` implementation.
