DemandSpec
Structured capacity request. A buyer specifies requirements — capacity, jurisdiction, latency, chip class, compliance — and the rights engine matches against ComputeSlot inventory.
Overview
DMTR's existing IOI primitive expresses interest in a known position. DemandSpec inverts that: the buyer describes requirements — capacity, jurisdiction, latency, chip class, compliance, carbon profile — and asks which slots in inventory qualify.
matchDemand(spec, candidates) evaluates each candidate slot against the full rights-engine check set (BIS export controls, OFAC, RIGI, permit stack, water rights, indigenous consultation, data residency, interconnect priority) and returns a ranked list of results with conditional Verdicts attached.
Fields
| Property | Type | Required | Description | Example |
|---|---|---|---|---|
| demand_id | string | Yes | Unique identifier for the RFP. | — |
| tenant_participant_id | string | Yes | The tenant requesting capacity (must exist in the Identity Graph). | — |
| capacity_mw_min | number | Yes | Minimum capacity required, in MW. | — |
| capacity_mw_max | number | No | Upper bound, if any. Slots offering more than max are still surfaced but mw_offered is capped. | — |
| duration_months | integer | Yes | Term length. | — |
| earliest_energization | string | Yes | ISO date — slot must be capable of energizing by this date. | — |
| latency_class | enum | Yes | agnostic | ms_500 | ms_100 | ms_50 | ms_10. Latency-agnostic workloads (post-training, batch inference, thinking models) make LatAm and other long-haul geographies eligible. | — |
| workload_class | enum | Yes | training | post_training | batch_inference | interactive_inference | thinking | general_compute | crypto_mining | other. | — |
| power_quality | enum | Yes | best_effort | interruptible | firm | two_nines | three_nines | four_nines | five_nines. | — |
| chip_class | enum | No | any | hopper_or_better | blackwell_or_better | rubin_or_better | export_controlled_only_a800_h800 | trainium_or_better | tpu_v6_or_better. Drives BIS export-control evaluation. | — |
| geography_filter | object | Yes | Allowed/excluded countries (ISO-2), allowed basins, max RTT to a target hub, target hub IATA. | — |
| compliance_requirements | array | No | bis_export_clean, ofac_clean, itar_equivalent_clean, rigi_eligible, data_residency_country, low_water_only, no_indigenous_dispute, audited_carbon_class, sanctions_screened_supply_chain, five_eyes_only. | — |
| pricing_envelope | object | No | Ceilings: capacity payment per MW-month, blended LCOE per MWh, total term value. | — |
| carbon_class | enum | No | any | low_carbon | renewable_only | additional | removal. | — |
| cfe_matching_request | enum | No | none | annual | monthly | hourly_grid | hourly_site. Hyperscalers under 24/7 carbon-free-energy commitments (Google's 24/7 CFE target and Microsoft's 100/100/0 program, both 2030 commitments) typically require hourly_grid minimum. | — |
| requires_decomposition | boolean | No | If true, partial-fit slots are surfaced (a 200 MW slot can contribute to an 800 MW demand). | — |
| preferred_decomposition_block_mw | number | No | If decomposition is required, the preferred block size for splits. | — |
Example: 1 GW LatAm batch-inference RFP
{
"demand_id": "demand-hyperscaler-2027-q2-latam",
"tenant_participant_id": "hyperscaler-tenant-001",
"status": "open",
"capacity_mw_min": 800,
"capacity_mw_max": 1200,
"duration_months": 60,
"earliest_energization": "2027-06-01",
"latency_class": "agnostic",
"workload_class": "batch_inference",
"power_quality": "interruptible",
"chip_class": "blackwell_or_better",
"geography_filter": {
"allowed_countries": ["AR", "CL", "PY", "UY", "BR"],
"excluded_countries": ["VE"]
},
"compliance_requirements": ["bis_export_clean", "ofac_clean", "rigi_eligible", "audited_carbon_class"],
"carbon_class": "low_carbon",
"requires_decomposition": true,
"preferred_decomposition_block_mw": 100
}The complete fixture is at packages/fixtures/energy/sample-demand-spec.json.
Matching
matchDemand(spec, slots, opts) returns one DemandMatchResult per qualifying slot, sorted by allowed first then by score descending:
import { matchDemand } from "@dmtr/energy/rights-engine";
const results = matchDemand(spec, store.listSlots(), {
tenant: anthropic,
tenantOfacScreenedAt: "2026-04-30",
estimatedProjectValueUsd: 800_000_000,
});
// → [{ slot_id, score, allowed, conditional, missing_compliance, mw_offered, notes }, ...]Score is the fraction of checks that returned pass (vs. fail/conditional/counsel_review). allowed mirrors the underlying Verdict's allowed flag — true unless any check returned fail.
When spec.requires_decomposition === true, slots smaller than capacity_mw_min are still surfaced as long as they meet the preferred_decomposition_block_mw threshold. When false, only slots ≥ capacity_mw_min qualify.
Rights-engine checks
matchDemand calls evaluateSlotForDemand for each candidate, running:
- Interconnect priority — queue position and approved capacity vs. requested
- Permit stack — required permits for the slot's site class
- Water draw — water rights vs. cooling design
- BIS export controls — chip class vs. destination country
- RIGI eligibility — Argentine RIGI certificate and project value threshold
- Indigenous consultation — ILO 169 / FPIC obligations where applicable
- Data residency — slot country vs. demand allow/exclude lists
- OFAC tenant — SDN screening (when a tenant participant is supplied)
Each check produces a CheckResult with status pass, fail, conditional, or counsel_review. The aggregated Verdict follows the same pattern as the core rights engine.
Related concepts
- Run an RFP as a tenant
- AllocationPlan — multi-slot non-binding match output
- Aggregation — L1/L2/L3 composition model
- ComputeSlot
- Rights engine — the core evaluation pattern
Pool tranches
L3 aggregation primitive: seniority layers and deterministic waterfall execution for a capacity pool.
Stage gates
The nine-gate development ladder for compute-ready energy projects: LAND → ENERGY → PERMITS → SUBSTATION → TURBINES → FINANCE → BUILD → ENERGIZE → TENANT. Each transition is gated by prerequisites and recorded with a Verdict.