|
1 |
+#!/usr/bin/env bash |
|
2 |
+# post-upgrade.sh [step…] — data repair after the 2026-09-12 claim-first upgrade, run from the laptop against the data node. |
|
3 |
+# steps (default: all, in order): |
|
4 |
+# baseline dci quality + dci snapshot (flags + snapshot BEFORE repairs) |
|
5 |
+# repair scripts/quality-apply.ts --hide-false-positives --fix-slugs --link-campuses |
|
6 |
+# reprocess dci reprocess <every connector> --stale (offline, from archived bodies; new parser versions) |
|
7 |
+# unbacked scripts/quality-apply.ts --null-unbacked-mw (after reprocess: figures with no site-scoped current claim) |
|
8 |
+# refresh dci refresh-stats + dci rank + dci quality + dci snapshot |
|
9 |
+# audit largest values (section 120 of the brief) printed for review |
|
10 |
+# Everything is idempotent; projects are hidden, never deleted; the pre-upgrade pg_dump is in /srv/dci/backups/pg. |
|
11 |
+set -euo pipefail |
|
12 |
+source "$(dirname "${BASH_SOURCE[0]}")/lib.sh" |
|
13 |
+steps=("$@"); [[ ${#steps[@]} -eq 0 ]] && steps=(baseline repair reprocess unbacked refresh audit) |
|
14 |
+has() { local s; for s in "${steps[@]}"; do [[ $s == "$1" ]] && return 0; done; return 1; } |
|
15 |
+ |
|
16 |
+# `cli` service runs the worker image; scripts/ is not baked into the image → bind-mount it |
|
17 |
+CLI="$(compose_prefix data) run --rm -T" |
|
18 |
+CLI_SCRIPTS="$(compose_prefix data) run --rm -T -v $REMOTE_DIR/scripts:/app/scripts cli node /app/node_modules/tsx/dist/cli.mjs /app/scripts" |
|
19 |
+dci() { remote data "$CLI cli $*"; } |
|
20 |
+script() { remote data "$CLI_SCRIPTS/$*"; } |
|
21 |
+psqlq() { remote data "docker exec -i dci-postgres-1 psql -U dci -d dci -Atc \"$1\""; } |
|
22 |
+ |
|
23 |
+if has baseline; then |
|
24 |
+ log "baseline: quality sweep + snapshot" |
|
25 |
+ dci quality | tail -20 |
|
26 |
+ dci snapshot | tail -8 |
|
27 |
+fi |
|
28 |
+if has repair; then |
|
29 |
+ log "repair: hide vetoed projects, fix slugs, link campuses" |
|
30 |
+ script quality-apply.ts --hide-false-positives --fix-slugs --link-campuses | tail -40 |
|
31 |
+fi |
|
32 |
+if has reprocess; then |
|
33 |
+ log "reprocess: every connector, stale documents only (offline)" |
|
34 |
+ ids=$(psqlq "select string_agg(id, ' ' order by id) from connectors where enabled") |
|
35 |
+ for id in $ids; do |
|
36 |
+ remote data "$CLI cli reprocess $id --stale 2>&1 | grep -E 'reprocess → |selected' | tail -2" || true |
|
37 |
+ done |
|
38 |
+fi |
|
39 |
+if has unbacked; then |
|
40 |
+ log "unbacked: null project figures no site-scoped current claim backs" |
|
41 |
+ script quality-apply.ts --null-unbacked-mw | tail -20 |
|
42 |
+fi |
|
43 |
+if has refresh; then |
|
44 |
+ log "refresh: stats, rankings, quality, snapshot" |
|
45 |
+ dci refresh-stats | tail -1 |
|
46 |
+ dci rank | tail -1 |
|
47 |
+ dci quality | tail -20 |
|
48 |
+ dci snapshot | tail -8 |
|
49 |
+fi |
|
50 |
+if has audit; then |
|
51 |
+ log "audit: largest values" |
|
52 |
+ psqlq "select 'FAC-OPER' k, f.name, f.it_capacity_mw, f.total_power_mw, f.capacity_scope, f.capacity_semantics, f.record_scope from facilities f where f.merged_into is null and f.status in ('operational','partially_operational','expansion') order by coalesce(f.it_capacity_mw, f.total_power_mw) desc nulls last limit 12" |
|
53 |
+ psqlq "select 'FAC-CONSTR' k, f.name, coalesce(f.planned_power_mw, f.it_capacity_mw, f.total_power_mw) mw, f.capacity_scope from facilities f where f.merged_into is null and f.status = 'under_construction' order by 3 desc nulls last limit 8" |
|
54 |
+ psqlq "select 'PRJ-MW' k, p.name, p.planned_mw, p.capacity_scope, p.project_class, p.evidence_level, left(p.source_url, 80) from projects p where p.merged_into is null and not p.hidden order by p.planned_mw desc nulls last limit 12" |
|
55 |
+ psqlq "select 'PRJ-INV' k, p.name, p.investment_usd/1e9 inv_b, p.investment_scope, p.project_class from projects p where p.merged_into is null and not p.hidden order by p.investment_usd desc nulls last limit 8" |
|
56 |
+ psqlq "select 'OP-PIPE' k, o.name, o.stats->>'plannedMw' planned, o.stats->>'constructionMw' construction, o.stats->>'projectPlannedMw' project_mw from operators o order by coalesce((o.stats->>'projectPlannedMw')::float,0) + coalesce((o.stats->>'plannedMw')::float,0) desc limit 8" |
|
57 |
+ psqlq "select 'METRO-PIPE' k, m.name, m.stats->>'plannedMw' planned, m.stats->>'constructionMw' construction, m.stats->>'projectPlannedMw' project_mw from metros m order by coalesce((m.stats->>'projectPlannedMw')::float,0) + coalesce((m.stats->>'plannedMw')::float,0) desc limit 8" |
|
58 |
+ psqlq "select 'TOTALS' k, (select count(*) from facilities where merged_into is null), (select count(*) from projects where merged_into is null and not hidden), (select count(*) from projects where hidden), (select count(*) from claims), (select count(*) from claims where status='unscoped'), (select count(*) from quality_flags where status='open')" |
|
59 |
+fi |
|
60 |
+log "post-upgrade done" |
|
61 |
|