{"cadence":{"authoritative_timestamp":"computed_at on the row \u2014 NOT the cron time","cron":"5 6,12,18,0 * * * (UTC), .github/workflows/dcpi-daily.yml","note":"Do not read this as 'every 6 hours'. Runs start 30-45 minutes after nominal often enough that the as-of stamp is the only trustworthy answer to 'how fresh is this'","observed_drift_minutes":"30-45, routinely","other_triggers":["POST /api/v1/dcpi/recompute (admin key)","the heartbeat refresh","a cold-start recompute when the dashboard renders zero rows"],"schedule":"approximately 4x/day"},"completeness":{"fallbacks_documented":11,"inputs_documented":10,"limitations_documented":11,"revisions_documented":10},"composite_score":{"default_multiplier":1.0,"formula":"excess*0.60 + (100-constraint)*0.30 + (1 - min(ttp,60)/60)*100*0.10, then multiplied by the verdict quality multiplier","ttp_cap_months":60.0,"verdict_multipliers":{"AVOID":0.6,"BUILD":1.0,"CAUTION":0.85,"LOW_SIGNAL":0.35},"weights":{"excess":0.6,"inverse_constraint":0.3,"time_to_power":0.1}},"constraint_score":{"ceilings":{"demand_growth_yoy_pct":12.0,"local_dc_count":40.0,"queue_wait_months":36.0,"reserve_margin_pct":25.0},"direction":"high = MORE constrained = avoid","emergency_points_per_event":20,"local_competition_bonus_weight":0.06,"max_before_outer_clip":106.0,"scoring_time_defaults":{"demand_growth_yoy_pct":3,"emergency_count_30d":0,"queue_wait_months":18,"reserve_margin_pct":12},"weights":{"demand_growth":0.15,"emergencies":0.2,"queue_wait":0.4,"reserve_margin":0.25}},"excess_power_score":{"ceilings":{"btm_headroom_mw":500.0,"curtailment_pct":10.0,"gen_additions_12mo_mw":5000.0,"stranded_capacity_mw":1000.0},"direction":"high = MORE buildable headroom","local_grid_bonus_weight":0.08,"local_grid_subindex":{"generation_ceiling_mw":3000.0,"generation_points":20.0,"kv_points":[[345.0,25.0],[230.0,12.0]],"substation_ceiling":300.0,"substation_points":55.0},"max_before_outer_clip":108.0,"reserve_floor_pct":12.0,"reserve_span_pct":13.0,"scoring_time_defaults":{"btm_headroom_mw":0,"curtailment_pct":0,"gen_additions_12mo_mw":0,"queue_approval_rate_pct":50,"reserve_margin_pct":12,"stranded_capacity_mw":0},"weights":{"btm_headroom":0.1,"curtailment":0.2,"gen_additions":0.2,"queue_approval":0.15,"reserve_margin":0.2,"stranded":0.15}},"fallbacks":[{"effect":"iso_defaults.get(iso, iso_defaults['WECC']) \u2014 an unrecognised ISO silently scores on Western-grid parameters. Cost a real published defect: ~22 Southeast markets published '500 MW behind-the-meter headroom' that was WECC's constant. Now DETECTED (signal_tier -> low) but still not PREVENTED","id":"iso_default_fail_open","where":"routes/dcpi.py gather_metrics_for_market"},{"effect":"inputs that are still None at scoring time take the CONSTRAINT_INPUT_DEFAULTS / EXCESS_INPUT_DEFAULTS values, which are DIFFERENT numbers from iso_defaults \u2014 a fourth tier of constant","id":"scorer_or_literals","where":"compute_constraint_score / compute_excess_power_score"},{"effect":"a hand-calibrated constant overwrites a live-read value. Until 2026-07-29 the field kept its 'live' provenance label; the override now revokes it","id":"slug_override_replaces_live","where":"the slug_overrides metrics.update()"},{"effect":"on the queue-DEPTH PROXY path queue_wait_months is clipped to 12-66 and THEN multiplied by up to 1.35, so the published field can reach 89.1 months","id":"saturation_breaches_queue_band","where":"the local-saturation rewrite"},{"effect":"the 12-66 clip belongs to the queue-depth PROXY, not to the field. When queue_wait_months comes from a per-ISO default or a slug_override it is NEVER clipped to 66 first, so the published value can exceed the 89.1-month proxy ceiling. Three slug_override markets (london, amsterdam, manchester) are STRUCTURALLY above it \u2014 their literals are 144, 120 and 96 months and the saturation rewrite is skipped for them entirely. A few per-ISO-default markets (rotterdam, milan, edinburgh, rome) sit just either side of it and cross in both directions as the saturation multiplier moves on each recompute, so the breach COUNT is not a constant: read local_saturation.queue_wait_markets_over_proxy_ceiling, which is measured per request. These are deliberate calibrations \u2014 London's interconnection queue really is ~12 years \u2014 the DEFECT was publishing 89.1 as the field's ceiling. See queue_wait_fill_paths","id":"queue_wait_constant_paths_are_unclipped","where":"iso_defaults / slug_overrides in routes/dcpi.py"},{"effect":"any state with >=90 GW of active queue pins at the 66-month cap. Texas is ~462 GW, so every Texas market shares one identical value: a saturated live input is functionally a constant.","id":"queue_proxy_saturation","where":"clip(12.0 + active_queue_GW * 0.6, 12, 66) months"},{"effect":"US/CA only, and international state spellings do not match, so intl markets score modeled_estimate. Domestic coverage is partial too \u2014 some states return no queue rows at all","id":"no_international_queue","where":"interconnect_queue"},{"effect":"a DB outage degrades the whole index to constants without a single error surfacing","id":"adapters_swallow_exceptions","where":"every adapter + the saturation block"},{"effect":"per-process, 60s TTL (_LOCAL_INFRA_CACHE unbounded), so two workers can score the same market from different cache states within one run","id":"per_process_caches","where":"_TELEMETRY_CACHE / _QUEUE_STATE_CACHE / _GEN_ADD_STATE_CACHE / _LOCAL_INFRA_CACHE"},{"effect":"a second writer to market_power_scores with a completely different formula and NULL time_to_power / data_basis / signal_tier / method_version. It currently scores ZERO markets (it raises per market inside a swallow-all), so it cannot be the cause of any unrecorded field today","id":"lite_recompute_second_writer","where":"POST /api/v1/dcpi/lite-recompute"},{"effect":"LOW_SIGNAL is a documented filter value carrying a 0.35 composite multiplier, and it has NO WRITER AT ALL. It is accepted by the ?verdict= filter, excluded by default from the leaderboard, counted by iso_snapshot's low_signal_count and rendered as the /dcpi 'Monitoring' tab \u2014 all of which are permanently empty. Until 2026-08-08 the only thing that could emit it was a band table in dchub_self_heal.py, which required a score of exactly 0; iso_defaults guarantee that never happens, so it never fired either. That table is retired (2.3.0) and derive_verdict returns only BUILD, CAUTION or AVOID, so the value is now unreachable BY CONSTRUCTION rather than by arithmetic accident","id":"low_signal_unreachable","where":"derive_verdict"}],"generated_from":"the same Python constants routes/dcpi.py imports to score \u2014 not a transcription","inputs":[{"derivation":"clip(12.0 + active_queue_GW * 0.6, 12, 66) months","live_capable":true,"missing_behaviour":"falls back to iso_defaults[iso]; on a DB error it also falls back, because the adapter cannot distinguish an empty result from a failed query","name":"queue_wait_months","source":"interconnect_queue (active rows per state) via _state_queue_depth","units":"months"},{"derivation":"raw sum; reported, not scored","live_capable":true,"missing_behaviour":"stays null \u2014 never modelled","name":"queue_capacity_mw","source":"interconnect_queue SUM(capacity_mw) of active rows","units":"MW"},{"derivation":"SUM(capacity_mw); regulatory-pending (P)/(L) excluded","live_capable":true,"missing_behaviour":"the scorer reads `or 0`, i.e. it is treated as ZERO additions. That is a penalty, not neutrality","name":"gen_additions_12mo_mw","source":"planned_generators (EIA-860M), statuses (U)/(V)/(T)/(TS) with a planned COD inside the next 12 months","units":"MW"},{"derivation":"effective = anchor + clamp(live_operating_reserve, +/-6.0), floored at 0; telemetry older than 180 minutes is ignored","live_capable":true,"missing_behaviour":"anchor used unchanged and labelled modelled","name":"reserve_margin_pct","source":"modelled ISO planning anchor BLENDED with grid_telemetry","units":"%"},{"derivation":"iso_defaults / slug_overrides constant","live_capable":false,"missing_behaviour":"always modelled \u2014 there is no live source","name":"curtailment_pct","source":null,"units":"%"},{"derivation":"iso_defaults / slug_overrides constant","live_capable":false,"missing_behaviour":"always modelled \u2014 there is no live source","name":"queue_approval_rate_pct","source":null,"units":"%"},{"derivation":"iso_defaults / slug_overrides constant, then down-weighted by local saturation","live_capable":false,"missing_behaviour":"always modelled \u2014 there is no live source","name":"btm_headroom_mw","source":null,"units":"MW"},{"derivation":"present only in a handful of hand-written slug_overrides","live_capable":false,"missing_behaviour":"null -> the scorer reads 0","name":"stranded_capacity_mw","source":null,"units":"MW"},{"derivation":"global default 4.0, then increased by local saturation","live_capable":false,"missing_behaviour":"always modelled \u2014 there is no live source","name":"demand_growth_yoy_pct","source":null,"units":"% YoY"},{"derivation":null,"live_capable":false,"missing_behaviour":"NEVER ASSIGNED ANYWHERE. The scorer reads `or 0`, so 20% of every constraint score is a permanent zero for every market at every signal tier","name":"emergency_count_30d","source":null,"units":"count"}],"known_limitations":["emergency_count_30d is never populated, so 20% of every constraint score is a structural zero","five of the nine score inputs have no live source and are per-ISO constants; demand growth additionally defaults to a single global 4.0","queue_wait_months is queue DEPTH, not a measured wait \u2014 a defensible proxy, published as one, with its 0.6 months/GW calibration stated","that proxy SATURATES: every state at or above 90 GW pins at the 66-month cap, so all Texas markets share one identical value","interconnection-queue coverage is incomplete domestically and absent internationally","roughly 40 curated markets carry hand-calibrated slug_overrides that REPLACE live values","the local saturation index's operational-MW term is under repair (r-status-taxonomy): it is currently an unfiltered SUM over all statuses, so it contains the pipeline it separately reports. No operational-MW figure from DCPI is citeable until that lands","LOW_SIGNAL is documented and multiplier-weighted but unreachable in practice","constraint_score is NOT reproducible from the published fields: demand_growth_yoy_pct and local_dc_count are not emitted on /api/v1/dcpi/scores/<slug> for any market, so up to 21.0 of its 100 points cannot be derived by a third party. composite_score and verdict ARE exactly reproducible","queue_wait_months is bounded at 89.1 months only on the queue-depth PROXY path \u2014 as of this response 5 markets of 323 exceed it, up to 144.0 months. Values fed by a per-ISO default or a slug_override are never clipped to 66 first, so the published field legitimately exceeds it; the three slug_override markets sit well above it and the per-ISO-default markets cross it in both directions as local saturation moves on each recompute","the index publishes 323 markets; the underlying table carries 330 rows. The difference is 7 retired alias twins (unpublished, not deleted). 323 is the index size; 330 is a row count \u2014 cite the first"],"live_counts":{"available":true,"index_size":323,"queue_wait_max":144.0,"queue_wait_over_proxy_ceiling":5,"source":"market_power_scores","table_rows":330},"local_infrastructure_terms":[{"feeds":"excess","name":"local_substation_count","radius_km":40,"source":"substations (HIFLD, US-only)"},{"feeds":"excess","name":"local_max_kv","radius_km":40,"source":"substations MAX(voltage_kv)"},{"feeds":"excess","name":"local_gen_mw","radius_km":60,"source":"gem_power WHERE status='operating' (GEM, global)"},{"feeds":"constraint","name":"local_dc_count","radius_km":25,"source":"discovered_facilities WHERE duplicate_of_id IS NULL"}],"local_saturation":{"applies_to":"markets WITHOUT a hand-calibrated slug_override","breaches_queue_wait_band":true,"ceilings":{"local_facility_count":400.0,"local_operational_mw":8000.0,"local_pipeline_mw":5000.0,"local_provider_count":40.0},"queue_wait_ceiling_note":"89.1 = 66 x 1.35 bounds the queue-depth PROXY path only. queue_wait_months is also filled from unclipped per-ISO defaults and from slug_overrides, and neither is clipped to 66 before publication, so the published field legitimately exceeds this number. See queue_wait_fill_paths and the queue_wait_constant_paths_are_unclipped fallback","queue_wait_fill_paths":[{"ceiling_months":89.1,"clipped_to_66_first":true,"note":"the only path this module can bound analytically","path":"queue_depth_proxy","saturation_applies":true},{"ceiling_months":null,"clipped_to_66_first":false,"note":"iso_defaults[iso] in routes/dcpi.py is an UNCLIPPED per-ISO constant; the saturation multiplier is applied on top of it","path":"iso_default_constant","saturation_applies":true},{"ceiling_months":null,"clipped_to_66_first":false,"note":"a hand-calibrated constant publishes verbatim \u2014 the saturation rewrite is skipped for override markets","path":"slug_override_constant","saturation_applies":false}],"queue_wait_markets_over_proxy_ceiling":5,"queue_wait_proxy_path_ceiling_months":89.1,"queue_wait_published_max_months":144.0,"rewrites_before_scoring":{"btm_headroom_mw":"multiplied by (1 - 0.40 * saturation)","demand_growth_yoy_pct":"increased by (4.0 * saturation) percentage points","queue_wait_months":"multiplied by (0.90 + 0.45 * saturation)"},"scale":"log: ln(1+v) / ln(1+ceiling)","weights":{"local_facility_count":0.4,"local_operational_mw":0.25,"local_pipeline_mw":0.15,"local_provider_count":0.2}},"method_version":"2.3.0","normalisation":"every term is a linear ratio to a stated ceiling, clipped to [0,100], except the log-scaled local saturation index","ok":true,"provenance":{"as_of":"2026-08-08","cite_as":"DC Hub, dchub.cloud","default_v":"published","fallback_url":"https://dchub.cloud","license":"CC-BY-4.0","method":"emitted from util/dcpi_method.py, the constants routes/dcpi.py scores with; method_version=2.3.0","provenance_version":1,"source":"DC Hub Power Index (DCPI) \u2014 scoring method"},"queue_wait_proxy":{"base_months":12.0,"clip_months":[12.0,66.0],"formula":"clip(12.0 + active_queue_GW * 0.6, 12, 66) months","months_per_gw":0.6,"saturates_at_gw":90.0,"saturation_note":"any state with >=90 GW of active queue pins at the 66-month cap. Texas is ~462 GW, so every Texas market shares one identical value: a saturated live input is functionally a constant."},"reproducibility":"composite_score and verdict ARE reproducible from the fields published on /api/v1/dcpi/scores/<slug> using the weights above \u2014 measured exact on every published market (323 as of this response). constraint_score is NOT: two of its five inputs (demand_growth_yoy_pct, weight 0.15, and local_dc_count, bonus weight 0.06) are not columns on market_power_scores and are therefore emitted for no market, so up to 21.0 of its 100 points cannot be derived by a third party \u2014 NO market reproduces exactly, and that is by construction rather than by measurement: the inputs are absent from the schema, not merely missing from some rows. excess_power_score is NOT fully reproducible either: queue_approval_rate_pct and the local grid sub-index terms are not all published per market. See reproducibility_detail","reproducibility_detail":{"first_measured_on":"2026-08-08, all published markets","index_size_at_this_response":323,"recompute_helpers":{"composite":"composite_from_published_fields(...)","constraint_from_published_only":"constraint_derivable_from_published_fields(...)","constraint_full":"constraint_from_published_fields(...)","module":"util/dcpi_method.py","note":"constraint_from_published_fields is named for the promise, not the reality: two of its arguments are NOT published. Use constraint_derivable_from_published_fields to see exactly how far a published payload gets you","verdict":"verdict_from_scores(...)"},"scores":{"composite_score":{"exact_on":"every published market, at every measurement","from":["excess_power_score","constraint_score","time_to_power_months","verdict"],"reproducible":true},"constraint_score":{"exact_on":"no market \u2014 by construction, see why","max_underivable_points":21.0,"observed_residual_points":{"as_of":"2026-08-08","at_the_cap":"johor (21.0 of 41.0 underivable)","max":21.0,"min":1.22,"note":"a dated snapshot. Per-market residuals move whenever local_dc_count or demand growth is rescored, which is up to 4x/day; only the max_underivable_points cap is a standing property, because it is derived from the weights rather than measured"},"published_inputs":["queue_wait_months","reserve_margin_pct","emergency_count_30d"],"remedy":"publish both fields on the scores endpoint \u2014 tracked separately; it needs a schema and writer change, not a documentation change","reproducible":false,"unpublished_input_weights":{"demand_growth_yoy_pct":0.15,"local_dc_count":0.06},"unpublished_inputs":["demand_growth_yoy_pct","local_dc_count"],"why":"neither demand_growth_yoy_pct nor local_dc_count is a column on market_power_scores, so the endpoint's SELECT * cannot emit them. demand_growth_yoy_pct sometimes appears as PROSE inside top_risks_json, but only when it is a top risk, so it is not a field a consumer can rely on"},"excess_power_score":{"reproducible":false,"unpublished_inputs":["queue_approval_rate_pct","local_substation_count","local_max_kv","local_gen_mw"]},"verdict":{"exact_on":"every published market, at every measurement","from":["excess_power_score","constraint_score"],"reproducible":true}}},"revision_policy":{"current_state_table":"market_power_scores holds exactly ONE row per market, forever, with computed_at = NOW(). It is current-state, not an as-of archive","history_endpoint":"/api/v1/dcpi/history (single market is free to cite)","official_series":"dcpi_daily_snapshots \u2014 one point per market per day. A same-day rerun OVERWRITES that day's point","restatement":"a methodology change restates the entire back series implicitly, because there is no as-of archive to restate against. Every such change is enumerated in revisions[]","scores_are_revised_in_place":true,"version_bump_commitment":"method_version bumps on any change to a weight, threshold, normalisation ceiling, verdict band, composite multiplier or input SOURCE. A PATCH bump means labels/metadata only and every score is byte-identical. Normalisation ceilings are otherwise left alone, so a market moving means the market moved"},"revisions":[{"date":"2026-07-17","observed_moves":"midland-tx excess 55.9 -> 60.5, constraint 25.8 -> 22.8","ref":"r-declone-2","restated_back_series":true,"scores_changed":true,"version":"1.8","what":"per-market de-cloning of the ISO-inherited inputs, so markets in one ISO stop sharing identical scores"},{"date":"2026-07-24","observed_moves":"UNMEASURED \u2014 no per-market before/after was captured","ref":"queue+gen adapter rewrite","restated_back_series":true,"scores_changed":true,"version":"1.9","what":"queue_wait_months re-derived from real per-state active queue DEPTH, and gen_additions_12mo_mw repointed from a table that had neither of the columns it queried (so it had been 0 for every market) to planned_generators"},{"date":"2026-07-25","observed_moves":"excess: atlanta 35.6 -> 49.2, chicago 17.6 -> 34.0, phoenix 34.8 -> 62.8, midland-tx 60.5 -> 85.7. The grid did not change on that date; the method did","ref":"r-local-granularity","restated_back_series":true,"scores_changed":true,"version":"2.0","what":"added the bounded local-infrastructure terms: local DC density into constraint (<= +6) and local substation/HV/generation access into excess (<= +8)"},{"date":"2026-07-28","observed_moves":"none \u2014 metadata only","ref":"r-ws3-signal-tier","restated_back_series":false,"scores_changed":false,"version":"2.0","what":"signal_tier persisted per row. Non-numeric and invisible to both scorers, so every score and verdict is byte-identical"},{"date":"2026-07-29","observed_moves":"no score moves. Some override markets flip their published data_basis label from 'mixed' to 'modeled_estimate', which is the correction","ref":"r-ws3-methodology","restated_back_series":false,"scores_changed":false,"version":"2.0.1","what":"this document, emitted from the scorer's own constants; method_version stamped on every score row and daily snapshot; and a provenance correction \u2014 a slug_override that overwrites a live-read value now REVOKES that field's 'live' label instead of keeping it"},{"date":"2026-08-08","observed_moves":"none \u2014 every score, verdict and composite is byte-identical. Documentation only","ref":"r-repro","restated_back_series":false,"scores_changed":false,"version":"2.0.2","what":"three published-accuracy corrections, no scoring change. (1) The reproducibility claim said constraint_score was reproducible from the published fields; measured across all 315 markets, 0 reproduce, because demand_growth_yoy_pct (weight 0.15) and local_dc_count (bonus 0.06) are not columns on market_power_scores and so are published for no market. The claim now names what is reproducible (composite_score and verdict \u2014 315/315 exact) and what is not. (2) known_limitations' index-size entry was a hardcoded '311 markets / 317 rows'; live it is 315 / 322. It is now generated from injected live counts. (3) queue_wait_true_ceiling_months published 89.1 as the ceiling of the published field; several markets exceed it because the per-ISO-default and slug_override paths are not clipped to 66 first. The transform was correct; the ceiling was wrong, and is renamed to the proxy path it actually bounds. The breach count and the field maximum are now measured per request rather than written down, because the per-ISO-default markets cross the line on each recompute"},{"date":"2026-08-08","observed_moves":"22 markets enter the live-sourced 200, displacing 22 that were ranked on twins. Of those 22, only 8 are NEW to the scored table (laurel, lenoir, luckey, maiden, modesto, monroe, salem, west-chester); the other 14 \u2014 including mount-pleasant (3,600 MW) and abilene (3,100 MW) \u2014 already had rows and were being carried by the scored-orphan path with frozen coordinates, so what changes for them is that they are refreshed from the facility table again rather than newly published. None LEAVE the universe, because every displaced slug is already in market_power_scores and is re-adopted by that same orphan path. Facility counts fall for 177 of 178 retained markets (ashburn 308 -> 163, boardman 51 -> 5). 36 centroids move >0.5 km, 6 move >5 km: chattanooga 21.5 km, west-texas 14.2 km, fort-worth 8.2 km, council-bluffs 7.0 km, douglasville 6.2 km, boise 5.9 km. Those shifts re-point the local-infra boxes: west-texas reads local_max_kv 345 -> 138 and local_gen_mw 584 -> 145; fort-worth local_gen_mw 3,059 -> 5,512. The isolated constraint local-density term moves at most 0.8 pts (west-texas -0.8, council-bluffs +0.4, chattanooga +0.3); the excess side moves more, but is not reproducible from the published fields so it is not restated numerically here","ref":"r-universe-dedup","restated_back_series":true,"scores_changed":true,"version":"2.1.0","what":"the market list and the market CENTROID are now built from de-duplicated discovered_facilities rows. 38% of that table (9,459 of 24,859) is twin rows carrying a duplicate_of_id, and the loader counted them: it admitted cities on the >=3-facility bar that did not have 3 real buildings, ranked the fixed 200-market cap on padded counts, and took the coordinate median over duplicated points. No weight, ceiling or verdict band moved \u2014 only which markets exist and where they sit"},{"date":"2026-08-08","observed_moves":"direction is asymmetric by construction: markets whose 25 km box holds pointed-but-unflagged twins score DOWN (competition removed), markets holding flagged-but-unpointed rows score UP (real facilities restored), and a market holding both nets out. The term is bounded, so no market can move more than the 0.06 local-density weight allows. MEASUREMENT BASIS \u2014 the per-market figures for this change were taken on 2026-08-08 against the PRE-2.1.0 market universe: 147 of 316 markets moved (132 down, 15 up, mean |delta| 0.47 points, max 1.5; largest miami 52.8 -> 51.3 and doral 48.2 -> 46.7 on 40 -> 30 facilities, manchester 71.7 -> 70.2 on 38 -> 28; largest rise spokane 44.4 -> 44.9 on 4 -> 7), with ZERO verdicts flipped. Version 2.1.0 then re-pointed the local-infrastructure boxes by moving 36 centroids and swapping 22 markets, and the index now publishes 315 markets, not 316 \u2014 so those per-market deltas are SUPERSEDED as exact values and are recorded here for the shape of the change, not as the current diff. The mechanism, the direction and the bound are unaffected by that re-pointing. NOTE: ref r-sat-dedup applied the same dedup rule to the market SATURATION footprint on this same date and also moved published scores without its own entry here \u2014 a back series diffed across 2026-08-08 carries that change, this one and 2.1.0 together, not any one alone","ref":"r-radius-dedup","restated_back_series":true,"scores_changed":true,"version":"2.2.0","what":"local_dc_count (the 25 km local-competition input) now scopes duplicate visibility on duplicate_of_id, the pointer, instead of the is_duplicate suppression flag. The flag was wrong in both directions: 3,286 rows carry a pointer while UNflagged and were counted twice as competition against themselves, while 1,510 rows are flagged with no pointer \u2014 keeperless suppressions, i.e. real facilities that were dropped from the count. Same predicate the facility lists and the canonical already use. No weight, ceiling or verdict band moved"},{"date":"2026-08-08","observed_moves":"none \u2014 no weight, ceiling, band or input source moved, and every published score and verdict is byte-identical. The 8 rows needed no backfill: the 14:34-14:49 UTC recompute re-scored and stamped them 2.2.0 the same day, which is the method that actually produced their current numbers. Two data-integrity fixes ride along and are NOT score restatements: the two watchdog writers now preserve a stored centroid instead of overwriting it with a dynamic market's NULL, and now write iso_type. The lite two-input approximation is additionally fenced out of rows the full method owns, so it can no longer overwrite a full score while inheriting its version stamp","ref":"r-provenance-writer","restated_back_series":false,"scores_changed":false,"version":"2.2.1","what":"the 2.0.1 entry below claims method_version is stamped on every score row. Measured 2026-08-08 09:24 UTC that was FALSE for 8 published markets \u2014 laurel, lenoir, luckey, maiden, modesto, monroe, salem and west-chester, the 8 rows 2.1.1 describes as new to the table, inserted 08:51 UTC with constraint_score, excess_power_score and verdict but method_version, signal_tier and data_basis_json all NULL. The cause was six hand-written INSERT column lists for one table: only the daily recompute's was updated when the three provenance columns were added, and the gap-filling writer that admits new markets was not. All four full-scorer writes now share one generated statement, so the claim is true by construction rather than by four people remembering"},{"date":"2026-08-08","observed_moves":"MEASURED against live Neon on 2026-08-08 over 324 published rows. The published verdict was OSCILLATING, so the size of the defect depends on which writer ran last: at 15:36 UTC, with a healer last, 221 of 324 (68.2%) carried a verdict these bands cannot produce; at 17:26 UTC the 162 rows the scorer sweep had reached were 162/162 canonical while the 106 it had not were ~33%. That oscillation is the finding \u2014 the scorer wrote the published rule ~4x/day and the healers overwrote it, each undoing the other, and the two armed healers disagreed with EACH OTHER minutes apart (15:36:09 CAUTION=256 AVOID=41 BUILD=27, then 15:36:44 CAUTION=241 BUILD=57 AVOID=32). RETIRING THEM MOVES 220 of 324 markets, and the moves are DIRECTIONAL, not noise: every one is downward toward the published rule. 187 markets served as CAUTION are canonically AVOID (spokane, madison, copenhagen, quincy, helsinki, akron, albany, alpharetta, ashburn, atlanta, aurora, baltimore, bangkok, barcelona, barueri, batam, baton-rouge, altoona, anchorage, andover, asheville, auckland and 165 more), and 33 served as BUILD are canonically CAUTION (appalachia-coal, aurora-co, stockholm, centennial, englewood, los-lunas, enterprise, west-jordan, south-west-jordan, the-dalles, pacific-nw-rural, winnipeg and 21 more). So the index had been reading as more buildable than the scorer found it to be. NO BACKFILL IS NEEDED and none was run: the 17:26 sweep above is direct evidence that the scorer restores every published row to the canonical label on its own, so removing the overwriters is self-correcting within one recompute. A back series diffed across 2026-08-08 carries this alongside 2.1.0, 2.2.0 and ref r-sat-dedup, not any one alone","ref":"r-verdict-one-band","restated_back_series":true,"scores_changed":false,"version":"2.3.0","what":"VERDICT_BANDS is byte-identical to 2.2.1 and no weight, ceiling or multiplier moved. What changed is that these bands are now the ONLY ones in force. dchub_self_heal.py carried four more verdict band tables, hand-typed into that file, no two alike and none matching this module \u2014 and two were armed, rewriting `verdict` on rows matching `published = true OR tier_required IS NULL OR tier_required != 'lite-pro'`, i.e. on the public index, on every heal cycle. All four are retired, along with a fifth job that wrote the label NODATA, which was never in the published alphabet. routes/dcpi.py's derive_verdict \u2014 which imports VERDICT_BANDS \u2014 is now the only producer of a stored verdict. This is the verdict-side twin of 2.2.1: same bug class, same remedy"}],"scale":"both component scores are 0..100","scoring_unchanged_since":"2026-08-08","signal_tier":{"adapter_null_semantics":"the queue and generator adapters cannot distinguish an empty result from a failed query, so silent_adapters is NOT an error count","affects_scores":false,"always_modeled_inputs":["curtailment_pct","queue_approval_rate_pct","btm_headroom_mw","stranded_capacity_mw","demand_growth_yoy_pct","emergency_count_30d"],"never_populated_inputs":["emergency_count_30d"],"null_semantics":"NULL means the writer of that row did not record a tier. Readers MUST surface it as unknown, never coerce it to 'low' \u2014 that would invent a measurement","rule":"full = all 3 live-capable adapters returned data; partial = 1 or 2; low = 0, OR the ISO fell through to the WECC default","scope_note":"'full' means every adapter that CAN be live was live \u2014 NOT that every score input is measured","tracked_adapters":["interconnect_queue","planned_generators","grid_telemetry"]},"source":"util/dcpi_method.py (emitted from the scorer constants)","time_to_power":{"adjustments":[[20.0,0.6],[16.0,0.8]],"default_adjustment":1.0,"formula":"queue_wait_months * reserve-margin adjustment","scarce_adjustment":1.4,"scarce_reserve_pct":10.0,"scoring_time_defaults":{"queue_wait_months":24,"reserve_margin_pct":12}},"verdict":{"bands":[{"constraint_max":50.0,"excess_min":65.0,"verdict":"BUILD"},{"constraint_max":70.0,"excess_min":50.0,"verdict":"CAUTION"}],"fallback":"AVOID","has_neutral_band":false,"low_signal_note":"LOW_SIGNAL exists as a filter value and carries a composite multiplier, but is unreachable in practice \u2014 see fallbacks"}}
