spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1/** Admin claim reads / status changes. Changing a claim's status never rewrites an entity column: the worker's next reconciliation does. */2import type { ClaimDTO } from "@dci/core";3import { CAPACITY_COLUMN } from "@dci/core";4import { pg, claimCols, andAll, page, type Fragment } from "../../lib/sql.js";5import { int, num, reqStr, str, type Row } from "../../lib/rows.js";6import { claimDto } from "../../lib/dto.js";78export interface ClaimFilters { subjectType?: string; subjectId?: string; status?: string; predicate?: string; page?: number; perPage?: number }910export async function listClaims(f: ClaimFilters): Promise<{ items: ClaimDTO[]; total: number; page: number; perPage: number }> {11 const sql = pg();12 const pg_ = page(f.page, f.perPage, 500, 50);13 const c: Fragment[] = [];14 if (f.subjectType) c.push(sql`k.subject_type = ${f.subjectType}`);15 if (f.subjectId) c.push(sql`k.subject_id = ${f.subjectId}`);16 if (f.status && f.status !== "all") c.push(sql`k.status = ${f.status}`);17 if (f.predicate) c.push(sql`k.predicate = ${f.predicate}`);18 const rows = await sql<Row[]>`select ${claimCols(sql)}, count(*) over() as total from claims k left join sources s on s.id = k.source_id where ${andAll(sql, c)} order by k.last_observed desc, k.id limit ${pg_.perPage} offset ${pg_.offset}`;19 return { items: rows.map((r) => claimDto(r, false)), total: rows.length ? int(rows[0]!.total) : 0, page: pg_.page, perPage: pg_.perPage };20}2122const FACILITY_COL: Record<string, string> = { itCapacityMw: "it_capacity_mw", totalPowerMw: "total_power_mw", plannedPowerMw: "planned_power_mw", utilityCapacityMw: "utility_capacity_mw", gridConnectionMw: "grid_connection_mw", ultimateCampusMw: "ultimate_campus_mw" };2324/** Set a claim status; when a rejected claim was backing a displayed facility MW column, a quality flag is raised (column untouched). */25export async function setClaimStatus(id: string, status: "current" | "rejected" | "review", reason: string | null): Promise<{ claim: ClaimDTO; flagged: boolean } | null> {26 const sql = pg();27 const rows = await sql<Row[]>`update claims set status = ${status}, rejection_reason = ${status === "rejected" ? reason : null} where id = ${id} returning id`;28 if (!rows[0]) return null;29 const full = (await sql<Row[]>`select ${claimCols(sql)} from claims k left join sources s on s.id = k.source_id where k.id = ${id}`)[0]!;30 let flagged = false;31 if (status === "rejected" && (str(full.subject_type) === "facility" || str(full.subject_type) === "campus")) {32 const camel = (CAPACITY_COLUMN as Record<string, string | null>)[reqStr(full.predicate)] ?? null;33 const col = camel ? FACILITY_COL[camel] : null;34 const v = num(full.value);35 if (col && v != null) {36 const fac = (await sql<Row[]>`select ${sql(col)} as v, name from facilities where id = ${reqStr(full.subject_id)}`)[0];37 const cur = num(fac?.v);38 if (fac && cur != null && Math.abs(cur - v) < 1e-9) {39 await sql`insert into quality_flags (id, entity_type, entity_id, claim_id, code, severity, field, message, details, priority, status, dedupe_key)40 values (${"flg_" + id.replace(/^clm_/, "").slice(0, 24)}, ${reqStr(full.subject_type)}, ${reqStr(full.subject_id)}, ${id}, 'claim_rejected_backing_value', 'warn', ${camel}, ${`rejected claim (${reqStr(full.predicate)} = ${v}) is still the displayed ${camel} value — re-reconcile`}, ${JSON.stringify({ claimId: id, value: v, reason })}::jsonb, 60, 'open', ${"claim_rejected:" + id})41 on conflict (dedupe_key) do update set status = 'open', message = excluded.message, details = excluded.details, updated_at = now()`;42 flagged = true;43 }44 }45 }46 return { claim: claimDto(full, false), flagged };47}48