@kahwee/sf-map-svg 5.0.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ User-visible changes are recorded here. Unreleased entries describe changes on `
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 5.1.0 — 2026-11-05
8
+
9
+ - Add official November 2026 precinct aggregates (`data/elections/precincts-<report time>.json` with a time-ordered `precincts-index.json`) and the 2022 precinct boundaries (`data/precincts-2022.json`), reconciled with the department's summary report. Only aggregates are committed, never the ballot-level export. Export the boundaries as `precinctMaps` from `@kahwee/sf-map-svg/data` and `@kahwee/sf-map-svg/data/precincts`; results snapshots stay Pages data.
10
+ - Update Biome to 2.6.3 and the aligned Storybook packages to 10.6.4.
11
+ - Gate library output replacement on Bun source checking, then emit JavaScript, declarations, and JSON with TypeScript `--noCheck`; install pinned Bun in every build job.
12
+ - Align Storybook on 10.6.3 and Vitest/browser/coverage tooling on 5.0.5, with compatible dependency updates for current security fixes.
13
+ - Record identical-output library build benchmarks alongside the earlier build-reuse measurements.
14
+ - Reuse completed library builds in CI demo, Storybook, coverage, and Pages steps; retain fresh builds for standalone commands and archive packing.
15
+ - Add a reproducible compilation-phase benchmark that checks emitted-output equivalence.
16
+ - Use Bun for consumer, Storybook, and website project checks; run them once in the Bun CI job instead of repeating them in the Node matrix.
17
+ - Add a Pages precinct results page (`precincts.html`) that shades the 514 precincts by any contest in the latest official snapshot, and compact the committed precinct snapshot to about 0.6 MB with a 5 KB reconciliation fixture.
18
+ - Fix election page checks on 390 px phones and in macOS Chromium, and wait for the scrollbar gutter in popover checks.
19
+
7
20
  ## 5.0.0 — 2026-10-19
8
21
 
9
22
  - Breaking: controller `setMode` and `setSource` preserve the camera; remove their `{ resetView }` argument. Call `camera.reset()` or `camera.fit()` explicitly.
package/README.md CHANGED
@@ -81,7 +81,7 @@ function disposeMap() {
81
81
  }
82
82
  ```
83
83
 
84
- `createMap(data, options)` returns a controller. Use `map.element` for mounting, `map.configure({ features, layers, controls, appearance, mode, source, year, labels })` for runtime switches, `map.camera` for pan/zoom/fit/reset, and `map.on()` for typed events. Appearance can change live while preserving camera, selection, and focus. `getResolvedConfiguration()` explains effective layers; `getCapabilities()` reports supplied geography. SFAR realtor neighborhoods are the default when supplied; SF Find and analysis are explicit alternate sources. The `/data/full` preset includes all three collections and historical districts.
84
+ `createMap(data, options)` returns a controller. Use `map.element` for mounting, `map.configure({ features, layers, controls, appearance, mode, source, year, labels })` for runtime switches, `map.camera` for pan/zoom/fit/reset, and `map.on()` for typed events. Appearance can change live while preserving camera, selection, and focus. `getResolvedConfiguration()` explains effective layers; `getCapabilities()` reports supplied geography. SFAR realtor neighborhoods are the default when supplied; SF Find and analysis are explicit alternate sources. The `/data/full` preset includes all three collections and historical districts. `precinctMaps[2022]` from `@kahwee/sf-map-svg/data/precincts` holds the 514 Department of Elections precinct boundaries (data only, not a rendered layer).
85
85
 
86
86
  See [controller options, events, and lifecycle](docs/API.md#interactive-maps),
87
87
  [examples](docs/EXAMPLES.md), and [consumer integration](docs/consumer-integration.md).
@@ -122,7 +122,7 @@ and [coordinate units](docs/API.md#coordinates-and-units).
122
122
 
123
123
  Canonical geography is in [`data/`](data/README.md), with provenance in [`SOURCES.md`](SOURCES.md). The public `/data` entry exposes lookup, catalog, district maps, and source-specific neighborhood collections. These are deeply frozen; clone before editing.
124
124
 
125
- Install with `pnpm install --frozen-lockfile`. Bun 1.4.3 is pinned in `.bun-version`; `pnpm test:bun` checks compiled-package imports and static rendering. Strict TypeScript 7.0.2 declarations and packed consumers remain part of the Node/pnpm checks. See the [contributing guide](CONTRIBUTING.md) for architecture and the [validation and release runbook](https://github.com/kahwee/sf-map-svg/blob/main/docs/maintenance.md) for checks, browser inspection, and publishing. If you are upgrading from v2, follow the [v3 migration guide](docs/migration-v3.md).
125
+ Install with `pnpm install --frozen-lockfile`. Bun 1.4.4 is pinned in `.bun-version` for development builds and type checks; `pnpm test:bun` also checks compiled-package imports and static rendering. Strict TypeScript 7.0.2 declarations and packed consumers remain part of the Node/pnpm checks. See the [contributing guide](CONTRIBUTING.md) for architecture and the [validation and release runbook](https://github.com/kahwee/sf-map-svg/blob/main/docs/maintenance.md) for checks, browser inspection, and publishing. If you are upgrading from v2, follow the [v3 migration guide](docs/migration-v3.md).
126
126
 
127
127
  ## Browser checks and marker performance
128
128
 
@@ -237,3 +237,18 @@ pnpm benchmark:markers --counts=2000 --mode=neighborhoods \
237
237
  ## CI maintenance
238
238
 
239
239
  [GitHub Actions maintenance](.github/ACTIONS.md) covers workflows, parallel checks, action versions, and weekly updates.
240
+
241
+ Project type checks use Bun: `pnpm check:types:built` checks compiled-package
242
+ consumers, Storybook, and the website in parallel after a build. `pnpm check` runs
243
+ the full gate. CI runs `check:node` on Node 24/26 and these Bun checks once in the
244
+ Bun job. TypeScript remains responsible for declaration emission and packed-package
245
+ consumer compatibility tests. Published consumers do not need Bun.
246
+
247
+ On the session’s Linux executor, three-run median project checks measured
248
+ 0.402/0.688/0.209 seconds with Bun for consumers/stories/website, versus
249
+ 3.156/4.110/2.496 seconds with `pnpm exec tsc -p <project>`. These include command
250
+ startup; they do not predict hosted CI duration.
251
+
252
+ CI reuses completed library output for demos, Storybook, and Pages. Standalone
253
+ commands still build from a clean checkout. See the [toolchain benchmark report](docs/toolchain-benchmarks.md)
254
+ for raw samples, output-equivalence checks, and reproducible commands.
package/SOURCES.md CHANGED
@@ -177,3 +177,56 @@ index is https://sfelections.org/results/20121106/detail.php .
177
177
  reconciles all 2002, 2012, and 2022 district totals. The election JSON files
178
178
  are Pages datasets; the historical district maps retain their existing
179
179
  display geometry, and no precinct polygons or raw workbook data are shipped.
180
+
181
+ ## November 2026 ballot and pending results
182
+
183
+ Downloaded November 4, 2026 UTC (November 3 Pacific):
184
+ https://media.api.sf.gov/documents/N26_EN_VIP.pdf .
185
+ `elections/2026-11-03.json` records its SHA-256 and verification time. Printed
186
+ page 248 lists all 14 state, one regional and ten local measures. Pages 24–51
187
+ supply candidate statement names. The official roster at
188
+ https://www.sf.gov/candidates-november-3-2026-general-election was verified
189
+ on November 4 UTC to complete the 15 displayed candidate contests, adding
190
+ Charles Hoelter, Manuel Noris-Barrera, Philip Louis Wing, Nicholas Berg and
191
+ Jamo Muhammad. The California Secretary of State certified list, downloaded
192
+ November 4 UTC from
193
+ https://elections.cdn.sos.ca.gov/statewide-elections/2026-general/cert-list-candidates.pdf
194
+ (certified August 27, 2026; SHA-256 in the feed), supplies nine additional
195
+ state/Board of Equalization contests on printed pages 1–2 and 13 Supreme Court
196
+ and First Appellate District retention contests on pages 33–34. The latter
197
+ explicitly includes San Francisco County and matches SF pamphlet pp. 246–247.
198
+ Other appellate districts are excluded. Printed candidate coverage does not
199
+ assert independently verified late statewide write-in qualifications.
200
+ The November results endpoint
201
+ https://www.sfelections.org/results/20261103w/index.html returned HTTP 403;
202
+ no November vote totals, report time, winners or geographic results are asserted.
203
+ The existing 2022 supervisorial boundaries are reused only for ballot district
204
+ selection, with neutral fills. See `elections/README.md` for the feed contract
205
+ and the ingestion blocker. Historical snapshots remain separate elections.
206
+
207
+
208
+ The independent California Secretary of State public media index at
209
+ https://media.sos.ca.gov/media/json-endpoints.csv identifies the November 3,
210
+ 2026 election and links JSON reports. Downloaded November 4 UTC: the reports
211
+ still carry the November 2, 6:28 p.m. zero-report time. The adapter extracts
212
+ only exact San Francisco County rows for 40 supported state/federal candidate, proposition and judicial
213
+ contests. It does not use statewide totals, infer precinct boundaries, or map
214
+ county totals onto districts. Actual extracted fixtures and their URLs are
215
+ recorded in `test/fixtures/sos/README.md`. Zero reports stay pending, and report
216
+ time is preserved verbatim separately from fetch time.
217
+
218
+ ### November 2026 plain-language ballot descriptions (verified November 3, 2026 Pacific)
219
+
220
+ - SF official voter pamphlet: https://media.api.sf.gov/documents/N26_EN_VIP.pdf — printed pp. 52–53 (regional transit), 64 (A), 70–71 (B), 78 (C), 84 (D), 94–95 (E), 100–101 (F), 108 (G), 124–125 (H), 132–133 (I), 144 (J). Summaries use impartial digests, not campaign arguments. PDF viewer page numbers are two higher than printed pages.
221
+ - California Secretary of State official November 3, 2026 voter guide: https://vig.cdn.sos.ca.gov/2026/general/pdf/complete-vig.pdf, downloaded November 4 UTC; SHA-256 `9509a4e3ac10b09e3c36d8b9b6c5d2f3935af3c7e2473c392b64352811cac1d8`. Official titles/summaries and Legislative Analyst analysis: printed pp. 14 (1), 20–23 (2), 26–27 (3), 30 (4), 34–37 (5), 40–41 (37), 44 (38), 48–51 (39), 54–55 (40), 58–59 (41), 62–63 (42), 66–67 (43), 70–71 (44), 74–77 (45).
222
+ - `shortTitle`, `summary`, and `summarySource` in the shared election feed preserve official full titles and source page provenance. Descriptions are neutral paraphrases; no endorsements or outcome predictions.
223
+
224
+ The November 3 impartiality review checked all 25 descriptions against the official digests and legislative analyses. Clarifications include SF C printed pp. 78–79 (freeze annual increases, not all contributions), F p. 100 (Board objection), E p. 94 (60-day default approval); California 2 pp. 22–23, 38 pp. 44–45, 39 p. 50, 40 pp. 54–55, 41 pp. 58–59, 43 pp. 66–67, 44 pp. 70–71 (operative scope/waivers pp. 153–156), and 45 pp. 75–76. Each feed record carries its revised printed-page reference.
225
+
226
+ Report-history points preserve only actual validated source counts and their distinct first observation times. Tests use explicitly synthetic mutations of the official zero-report fixtures; no synthetic counts or history points are in the checked-in ballot seed or deployed as results.
227
+
228
+ ## November 2026 precinct results and boundaries
229
+
230
+ - `data/elections/precincts-<report time>.json`, such as `precincts-2026-11-03-230421.json` (local department clock, `YYYY-MM-DD-HHmmss`), aggregates the San Francisco Department of Elections cast vote record export `CVR_Export_20261103231904.zip` (downloaded November 5, 2026; the department's report time was supplied as 11/3/2026 11:04:21 PM, kept verbatim with no timezone conversion) to per-precinct, per-contest counts in a compact format (`precincts[id].c[contestIndex] = [undervotes, overvotes, ...votes in option order]`, with `contests[]` giving each index's options; schema version 2, about 0.6 MB). Generate it with `scripts/import-cvr-precincts.mjs --zip <export> --report-time "<M/D/YYYY h:mm:ss AM|PM>" --out-dir data/elections`. Each report time keeps its own file, and `data/elections/precincts-index.json` lists them in time order; consumers read `latest`, the newest report time. The export, which is ballot-level, is an ingestion input and is never committed; its SHA-256 is recorded in the file. Counts use each ballot card's current record (`Modified` when adjudicated). Ranked-choice contests count a single rank-1 mark only, matching the department's first-round figures. These are not winners.
231
+ - Reconciliation: `test/election-precincts.test.mjs` sums the precincts and compares every candidate and option of all 65 contests with the official Election Summary Report 4 (`test/fixtures/sfelections/summary-report-4.json`, a 5 KB extract of the report's option totals made with `scripts/extract-summary-totals.mjs`, with the XML's SHA-256 recorded; 514 of 514 precincts reported). Every total matches exactly. Five precincts have no ballots in the export and are absent from the file.
232
+ - `data/precincts-2022.json` holds the 514 polygons of DataSF "Election Precincts - Current, Defined 2022" (`d6x4-hefw`, https://data.sfgov.org/resource/d6x4-hefw.geojson, downloaded November 5, 2026), reduced to the precinct ID with coordinates rounded to six decimals. All 514 IDs match the export's precinct manifest exactly.
@@ -4,6 +4,7 @@ export { districtMaps } from './districts.js';
4
4
  export { highways } from './highways.js';
5
5
  export { landmarks } from './landmarks.js';
6
6
  export { getNeighborhood, neighborhoodCollections, neighborhoodSources } from './lookup.js';
7
+ export { precinctMaps } from './precincts.js';
7
8
  export { getRealtorNeighborhood, neighborhoods } from './realtor.js';
8
9
  export { keyRoads } from './roads.js';
9
10
  export { bartStations } from './stations.js';
@@ -4,6 +4,7 @@ export { districtMaps } from './districts.js';
4
4
  export { highways } from './highways.js';
5
5
  export { landmarks } from './landmarks.js';
6
6
  export { getNeighborhood, neighborhoodCollections, neighborhoodSources } from './lookup.js';
7
+ export { precinctMaps } from './precincts.js';
7
8
  export { getRealtorNeighborhood, neighborhoods } from './realtor.js';
8
9
  export { keyRoads } from './roads.js';
9
10
  export { bartStations } from './stations.js';