Dan Trapp

Data intelligence / Energy infrastructure

Queue Intel OS

A cleaner way to read ISO interconnection queue pressure.

A prototype that ingests public ISO queue files, normalizes projects, tracks movement, and ranks where developers would enter behind the most queued capacity.

Status

Prototype

Timeline

Built as a focused market wedge

Domain

Energy infrastructure

Why

Data intelligence

Queue Intel OS dashboard showing interconnection risk signals
Queue movement and interconnection risk dashboardPrototype

Stack

Languages, services, data sources, and operating pieces behind the build.

Next.jsTypeScriptPythonPostgresPublic ISO data

Code Proof

What The Build Actually Contains

Sources

ISO files

Pipeline

Python

Model

Queue events

Surface

Risk table

Product proof

Queue Intel OS dashboard showing interconnection risk signals
Queue movement and interconnection risk dashboard

Implementation

Code Behind The Surface

Normalize the messy queue files

py

The first job was making different ISO exports behave like one product model.

FIELD_ALIASES = {
    "queue_id": ["Queue ID", "Queue Number", "project_number"],
    "sponsor": ["Interconnecting Entity", "Interconnecting Customer", "developer"],
    "mw": ["Capacity (MW)", "Project Size (MW)", "Requested MW", "Queue MW"],
    "poi_name": ["POI", "Point of Interconnection", "Interconnection Location"],
}

def normalize_row(iso: IsoCode, row: dict[str, Any]) -> QueueProject:
    normalized = {field: _first(row, aliases) for field, aliases in FIELD_ALIASES.items()}
    queue_id = str(normalized.get("queue_id") or _hash(row)[:12])

    return QueueProject(
        project_id=f"{iso.value}:{queue_id}",
        iso=iso,
        queue_id=queue_id,
        sponsor=_clean(normalized.get("sponsor")),
        mw=_float(normalized.get("mw")),
        poi_name=_clean(normalized.get("poi_name")),
        raw_row_hash=_hash(row),
    )

Find what changed

py

A static queue is useful. A moving queue is where the signal lives: new projects, withdrawals, and capacity changes.

def detect_events(previous: list[QueueProject], current: list[QueueProject]) -> list[QueueEvent]:
    previous_by_id = {project.project_id: project for project in previous}
    current_by_id = {project.project_id: project for project in current}
    events: list[QueueEvent] = []

    for project_id, project in current_by_id.items():
        old = previous_by_id.get(project_id)
        if old is None:
            events.append(_event(EventType.NEW_PROJECT, project, "Not present", project.status, "..."))
            continue

        if (old.status or "").lower() != (project.status or "").lower():
            event_type = EventType.WITHDRAWAL if "withdraw" in (project.status or "").lower() else EventType.STATUS_CHANGE
            events.append(_event(event_type, project, old.status, project.status, "..."))

        if old.mw != project.mw:
            events.append(_event(EventType.MW_CHANGE, project, f"{old.mw} MW", f"{project.mw} MW", "..."))

    return _dedupe_events(events)

Rank cluster pressure

ts

The UI ranks crowded POIs, sponsor concentration, churn, and queue-ahead pressure.

return applyPressureRanks(rows.map((row) => computeClusterRisk(mapRiskInput(row))))
  .filter((risk) => isMeaningfulText(risk.clusterName))
  .sort(
    (a, b) =>
      b.riskScore - a.riskScore ||
      (a.pressureRank ?? 100) - (b.pressureRank ?? 100) ||
      (b.queueAheadMw ?? 0) - (a.queueAheadMw ?? 0)
  )
  .slice(0, 50);

function pressureMetric(risk: ReturnType<typeof computeClusterRisk>) {
  if (risk.queueAheadMw && risk.queueAheadMw > 0) {
    return risk.queueAheadMw * 10 + risk.activeProjectCount;
  }
  return risk.activeProjectCount;
}

Project Logic

Why This Exists

The point is not to show another screen. It is to show the gap, the build constraint, and the proof of work.

Mission

Can public interconnection queues become a usable decision layer?

Interconnection queues are public, but hard to use. Developers, investors, and analysts need to see capacity pressure, project movement, and crowded entry points.

Build

What Had To Work

I built a prototype that normalizes queue records, tracks movement across updates, and surfaces where a developer would enter behind the most queued capacity.

Why It Matters

PJM / MISO / ERCOT

Turns ISO queue noise into a go/no-go market-entry view for developers and investors.

Hard Parts

Public data needs product shape

Different ISOs publish different shapes, labels, and update rhythms. The constraint is making the data comparable without pretending it is cleaner than it is.

Rows are cheap. Judgment is the product.

A table of 4,000 projects becomes useful when the interface flags important movement, crowded clusters, and sponsor changes.

The UI had to feel like an analyst

The dashboard leads with filters, risk metrics, recent signals, and a clear explanation of why each event matters. That is the difference between data access and decision support.

Decisions

Use snapshots so change over time is visible.
Normalize sponsor and POI names early so change detection is not polluted by label drift.
Rank movement by capacity, event type, cluster pressure, and sponsor history.
Show the reason beside the score so the product earns trust.

Next Move

I would add historical queue snapshots, project-level change alerts, ISO-by-ISO comparisons, and developer watchlists. I would also validate which ranking factors best predict congestion risk or commercial attractiveness.

Tell Me About Your Project

Bring Me The Bottleneck.
I’ll Build The Answer.

Tell me what people are trying to do, where the current path breaks, and what kind of useful answer should exist.

Market Gap

Demand exists, but the answer is missing.

Workflow Drag

The work is still too manual, slow, or scattered.

Product Wedge

A small surface could prove the larger opportunity.

Quick Note