@mailwoman/bdc 9.2.0 → 9.4.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.
Files changed (83) hide show
  1. package/lib/env.ts +30 -0
  2. package/lib/index.ts +2 -0
  3. package/{sdk → lib/sdk}/build-bdc.ts +86 -117
  4. package/{sdk → lib/sdk}/client.ts +24 -40
  5. package/{sdk → lib/sdk}/common.ts +1 -1
  6. package/{sdk → lib/sdk}/data-collection.ts +2 -2
  7. package/{sdk → lib/sdk}/download.ts +19 -15
  8. package/{sdk → lib/sdk}/filing-dates.ts +3 -3
  9. package/{sdk → lib/sdk}/filing-landscape.ts +8 -12
  10. package/lib/sdk/index.ts +14 -0
  11. package/{sdk → lib/sdk}/list-files.ts +2 -2
  12. package/{sdk → lib/sdk}/nearest-infrastructure.ts +5 -5
  13. package/{sdk → lib/sdk}/parsing.ts +3 -3
  14. package/{sdk → lib/sdk}/plausibility.ts +42 -23
  15. package/out/env.d.ts +24 -0
  16. package/out/env.d.ts.map +1 -0
  17. package/out/env.js +28 -0
  18. package/out/env.js.map +1 -0
  19. package/out/index.d.ts +2 -2
  20. package/out/index.d.ts.map +1 -1
  21. package/out/index.js +2 -2
  22. package/out/index.js.map +1 -1
  23. package/out/schema.d.ts.map +1 -1
  24. package/out/schema.js.map +1 -1
  25. package/out/sdk/build-bdc.d.ts +20 -19
  26. package/out/sdk/build-bdc.d.ts.map +1 -1
  27. package/out/sdk/build-bdc.js +70 -98
  28. package/out/sdk/build-bdc.js.map +1 -1
  29. package/out/sdk/buildings.d.ts.map +1 -1
  30. package/out/sdk/buildings.js.map +1 -1
  31. package/out/sdk/client.d.ts +7 -9
  32. package/out/sdk/client.d.ts.map +1 -1
  33. package/out/sdk/client.js +17 -31
  34. package/out/sdk/client.js.map +1 -1
  35. package/out/sdk/common.d.ts +1 -1
  36. package/out/sdk/common.d.ts.map +1 -1
  37. package/out/sdk/common.js.map +1 -1
  38. package/out/sdk/data-collection.d.ts +2 -2
  39. package/out/sdk/data-collection.d.ts.map +1 -1
  40. package/out/sdk/data-collection.js.map +1 -1
  41. package/out/sdk/download.d.ts +4 -3
  42. package/out/sdk/download.d.ts.map +1 -1
  43. package/out/sdk/download.js +12 -13
  44. package/out/sdk/download.js.map +1 -1
  45. package/out/sdk/filing-dates.d.ts +3 -3
  46. package/out/sdk/filing-dates.d.ts.map +1 -1
  47. package/out/sdk/filing-dates.js +1 -1
  48. package/out/sdk/filing-dates.js.map +1 -1
  49. package/out/sdk/filing-landscape.d.ts +4 -4
  50. package/out/sdk/filing-landscape.d.ts.map +1 -1
  51. package/out/sdk/filing-landscape.js +7 -10
  52. package/out/sdk/filing-landscape.js.map +1 -1
  53. package/out/sdk/index.d.ts +14 -14
  54. package/out/sdk/index.d.ts.map +1 -1
  55. package/out/sdk/index.js +14 -14
  56. package/out/sdk/index.js.map +1 -1
  57. package/out/sdk/list-files.d.ts +2 -2
  58. package/out/sdk/list-files.d.ts.map +1 -1
  59. package/out/sdk/list-files.js +1 -1
  60. package/out/sdk/list-files.js.map +1 -1
  61. package/out/sdk/location.d.ts.map +1 -1
  62. package/out/sdk/location.js.map +1 -1
  63. package/out/sdk/nearest-infrastructure.d.ts +4 -4
  64. package/out/sdk/nearest-infrastructure.d.ts.map +1 -1
  65. package/out/sdk/nearest-infrastructure.js +2 -2
  66. package/out/sdk/nearest-infrastructure.js.map +1 -1
  67. package/out/sdk/parsing.d.ts +3 -3
  68. package/out/sdk/parsing.d.ts.map +1 -1
  69. package/out/sdk/parsing.js +2 -2
  70. package/out/sdk/parsing.js.map +1 -1
  71. package/out/sdk/plausibility.d.ts +32 -14
  72. package/out/sdk/plausibility.d.ts.map +1 -1
  73. package/out/sdk/plausibility.js +15 -12
  74. package/out/sdk/plausibility.js.map +1 -1
  75. package/out/sdk/technologies.d.ts.map +1 -1
  76. package/out/sdk/technologies.js.map +1 -1
  77. package/package.json +65 -16
  78. package/index.ts +0 -2
  79. package/sdk/index.ts +0 -14
  80. /package/{schema.ts → lib/schema.ts} +0 -0
  81. /package/{sdk → lib/sdk}/buildings.ts +0 -0
  82. /package/{sdk → lib/sdk}/location.ts +0 -0
  83. /package/{sdk → lib/sdk}/technologies.ts +0 -0
@@ -5,13 +5,14 @@
5
5
  * @file FCC BDC availability-file download + zip extraction.
6
6
  */
7
7
 
8
- import * as fs from "node:fs/promises"
9
- import * as path from "node:path"
10
-
8
+ import { tryStat } from "@mailwoman/core/fs/readers"
9
+ import { makeDirectories, writeLocalFile } from "@mailwoman/core/fs/writers"
11
10
  import { extractSingleFileZip } from "@mailwoman/core/fs/zip"
11
+ import type { PathBuilderLike } from "path-ts"
12
+ import { resolvePath } from "path-ts/resolve"
12
13
 
13
- import type { BDCClient } from "./client.ts"
14
- import { BDCFilingDataType, type BDCFile } from "./common.ts"
14
+ import type { BDCClient } from "#sdk/client"
15
+ import { BDCFilingDataType, type BDCFile } from "#sdk/common"
15
16
 
16
17
  /**
17
18
  * Download and cache an FCC BDC availability file, extracting its zip-wrapped CSV to `destinationDir`.
@@ -28,15 +29,18 @@ import { BDCFilingDataType, type BDCFile } from "./common.ts"
28
29
  *
29
30
  * @returns The path of the extracted (and now cached) CSV file.
30
31
  */
31
- export async function downloadBDCFile(client: BDCClient, file: BDCFile, destinationDir: string): Promise<string> {
32
- const csvPath = path.join(destinationDir, `${file.fileName}.csv`)
32
+ export async function downloadBDCFile(
33
+ client: BDCClient,
34
+ file: BDCFile,
35
+ destinationDir: PathBuilderLike
36
+ ): Promise<string> {
37
+ const csvPath = resolvePath(destinationDir, `${file.fileName}.csv`)
33
38
 
34
- const alreadyCached = await fs
35
- .access(csvPath)
36
- .then(() => true)
37
- .catch(() => false)
39
+ const alreadyCached = await tryStat(csvPath)
38
40
 
39
- if (alreadyCached) return csvPath
41
+ if (alreadyCached) {
42
+ return csvPath.toString()
43
+ }
40
44
 
41
45
  const zippedArrayBuffer = await client.getArrayBuffer(
42
46
  `/map/downloads/downloadFile/${BDCFilingDataType.Availability}/${file.fileID}`
@@ -44,8 +48,8 @@ export async function downloadBDCFile(client: BDCClient, file: BDCFile, destinat
44
48
 
45
49
  const csvBuffer = await extractSingleFileZip(Buffer.from(zippedArrayBuffer))
46
50
 
47
- await fs.mkdir(destinationDir, { recursive: true })
48
- await fs.writeFile(csvPath, csvBuffer)
51
+ await makeDirectories(destinationDir.toString())
52
+ await writeLocalFile(csvBuffer, csvPath.toString())
49
53
 
50
- return csvPath
54
+ return csvPath.toString()
51
55
  }
@@ -9,7 +9,7 @@
9
9
  * {@linkcode BDCClient}.
10
10
  *
11
11
  * CACHING MOVED TO THE CLIENT. Both the Nexus original (one `<filingType>-dates.json` per filing
12
- * type) and this port's first cut (`dataRootPath("bdc", "cache", "filing-dates.json")`, unfiltered)
12
+ * type) and this port's first version (`dataRootPath("bdc", "cache", "filing-dates.json")`, unfiltered)
13
13
  * hand-rolled a JSON file cache here. `BDCClient` is built on `APIClient` and now carries an on-disk
14
14
  * response cache of its own, so the hand-rolled one was the exact duplication that migration exists to
15
15
  * remove — and it was worse than what replaced it: it had NO expiry, so a machine that resolved a
@@ -18,8 +18,8 @@
18
18
  * per-request cache bypass with the same meaning it always had.
19
19
  */
20
20
 
21
- import type { BDCClient } from "./client.ts"
22
- import type { BDCFilingDataType } from "./common.ts"
21
+ import type { BDCClient } from "#sdk/client"
22
+ import type { BDCFilingDataType } from "#sdk/common"
23
23
 
24
24
  /**
25
25
  * One entry from the FCC BDC's `/map/listAsOfDates` endpoint.
@@ -3,8 +3,8 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * `filing_landscape` reader — the FOUR PRE-REGISTERED ACCEPTANCE GATES this whole phase
7
- * is judged by. See `filing-landscape.test.ts` for the gate tests; this module is only the reader.
6
+ * `filing_landscape` reader — the FOUR PRE-REGISTERED ACCEPTANCE CRITERIA this whole phase
7
+ * is judged by. See `filing-landscape.test.ts` for the criterion tests; this module is only the reader.
8
8
  *
9
9
  * Coverage check (the meaning-of-zero rule): a queried block counts as SURVEYED only when its res-6
10
10
  * coverage cell is present in `layer_coverage` (via `readLayerCoverage`) — `undefined` means the area
@@ -33,13 +33,12 @@
33
33
  * block excluded from `surveyed_block_count` never contributes to `filings` either.
34
34
  */
35
35
 
36
- import type { DatabaseClient } from "@mailwoman/core/kysley/client"
37
36
  import { readLayerCoverage, readLayerManifest } from "@mailwoman/core/layers"
38
- import { expandH3Cell, shortCellToInt, type H3Cell, type H3CellShort } from "@mailwoman/spatial"
39
- import { cellToParent } from "h3-js"
37
+ import { shortCellToParentInt } from "@mailwoman/spatial"
38
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
40
39
  import { sql } from "kysely"
41
40
 
42
- import { BDC_COVERAGE_H3_RESOLUTION, BDC_H3_RESOLUTION, type BDCDatabase } from "../schema.ts"
41
+ import { BDC_COVERAGE_H3_RESOLUTION, BDC_H3_RESOLUTION, type BDCDatabase } from "#schema"
43
42
 
44
43
  /**
45
44
  * Exactly one of `geoids` or `h3Cells` is required — `filingLandscape` throws otherwise.
@@ -145,10 +144,7 @@ END`
145
144
  * coverage-cell derivation (the two MUST share this derivation — see that file's docstring).
146
145
  */
147
146
  export function res9ShortCellToRes6Parent(h3CellShortInt: number): number {
148
- const fullCell = expandH3Cell(h3CellShortInt.toString(16) as H3CellShort, BDC_H3_RESOLUTION)
149
- const parentCell = cellToParent(fullCell, BDC_COVERAGE_H3_RESOLUTION) as H3Cell
150
-
151
- return shortCellToInt(parentCell)
147
+ return shortCellToParentInt(h3CellShortInt, BDC_H3_RESOLUTION, BDC_COVERAGE_H3_RESOLUTION)
152
148
  }
153
149
 
154
150
  /**
@@ -175,7 +171,7 @@ export async function filingLandscape(
175
171
  }
176
172
 
177
173
  // Read (and validate) the manifest FIRST — a broken/missing manifest must throw before any block is
178
- // classified, never fall through to an "unstamped" answer (gate 4).
174
+ // classified, never fall through to an "unstamped" answer (criterion 4).
179
175
  const manifest = await readLayerManifest(db)
180
176
 
181
177
  const requestedUnits: ReadonlyArray<string | number> = query.geoids ?? query.h3Cells!
@@ -206,7 +202,7 @@ export async function filingLandscape(
206
202
  let surveyedBlockCount = 0
207
203
  let unknownBlockCount = 0
208
204
  // Only units that PASS the coverage check feed the census below — a unit with rows but no coverage evidence
209
- // (a corrupted/inconsistent db — see filing-landscape.test.ts's "coverage row deleted" gate) is `unknown`, and
205
+ // (a corrupted/inconsistent db — see filing-landscape.test.ts's "coverage row deleted" case) is `unknown`, and
210
206
  // its rows must not leak into `filings` either: `surveyed_block_count` and the blocks backing `filings` must
211
207
  // always agree, or a caller cross-referencing the two gets a contradiction (an "unknown" block whose filings
212
208
  // still show up looks exactly like the false-negative bug this reader exists to prevent).
@@ -0,0 +1,14 @@
1
+ export * from "#sdk/build-bdc"
2
+ export * from "#sdk/buildings"
3
+ export * from "#sdk/client"
4
+ export * from "#sdk/common"
5
+ export * from "#sdk/data-collection"
6
+ export * from "#sdk/download"
7
+ export * from "#sdk/filing-dates"
8
+ export * from "#sdk/filing-landscape"
9
+ export * from "#sdk/list-files"
10
+ export * from "#sdk/location"
11
+ export * from "#sdk/nearest-infrastructure"
12
+ export * from "#sdk/parsing"
13
+ export * from "#sdk/plausibility"
14
+ export * from "#sdk/technologies"
@@ -11,7 +11,7 @@
11
11
  * ascending by revision (`compareRevisionAsc`) rather than in API order.
12
12
  */
13
13
 
14
- import type { BDCClient } from "./client.ts"
14
+ import type { BDCClient } from "#sdk/client"
15
15
  import {
16
16
  compareRevisionAsc,
17
17
  parseRawBDCFile,
@@ -21,7 +21,7 @@ import {
21
21
  type BDCStateSubCategory,
22
22
  type BDCSummarySubCategory,
23
23
  type RawBDCFile,
24
- } from "./common.ts"
24
+ } from "#sdk/common"
25
25
 
26
26
  export interface RetrieveProviderAvailabilityFilesParams {
27
27
  /**
@@ -34,13 +34,13 @@
34
34
  * spines agree without this module hardcoding a resolution of its own.
35
35
  */
36
36
 
37
- import type { DatabaseClient } from "@mailwoman/core/kysley/client"
38
- import { readLayerCoverage, type CoverageCell, type LayerContractDatabase } from "@mailwoman/core/layers"
39
- import { POI_H3_RESOLUTION, type POILookup } from "@mailwoman/resolver-wof-sqlite/poi-lookup"
37
+ import { readLayerCoverage, type CoverageCell, type LayerContractHandle } from "@mailwoman/core/layers"
38
+ import { POI_H3_RESOLUTION, type POILookup } from "@mailwoman/resolver-wof-sqlite/poi"
40
39
  import { shortCellToInt, type H3Cell, type PointLiteral } from "@mailwoman/spatial"
40
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
41
41
  import { latLngToCell } from "h3-js"
42
42
 
43
- import { res9ShortCellToRes6Parent } from "./filing-landscape.ts"
43
+ import { res9ShortCellToRes6Parent } from "#sdk/filing-landscape"
44
44
 
45
45
  /**
46
46
  * Ring budget default for {@link nearestInfrastructure} — wider than `POILookup`'s own internal `DEFAULT_MAX_RINGS`
@@ -89,7 +89,7 @@ export interface NearestInfrastructureOptions {
89
89
  */
90
90
  export async function nearestInfrastructure(
91
91
  poiLookup: POILookup,
92
- contractDB: DatabaseClient<LayerContractDatabase>,
92
+ contractDB: LayerContractHandle & Pick<DatabaseClient, "destroy">,
93
93
  options: NearestInfrastructureOptions
94
94
  ): Promise<InfrastructureHit[]> {
95
95
  const [longitude, latitude] = options.center.coordinates
@@ -8,9 +8,9 @@
8
8
  * seven columns 2a keeps. Columns 0-2 (`frn`, `provider_id`, `brand_name`) and 9, 11 (`state_usps`,
9
9
  * `h3_res8_id`) are read past and never emitted: `provider_id` comes from the {@linkcode ProviderID}
10
10
  * parameter instead (the FCC partitions availability files per provider, so the caller already knows it),
11
- * and FRN/brand/state/H3 join concerns are a 2c registry-join seam.
11
+ * and FRN/brand/state/H3 join concerns are a 2c registry-join boundary.
12
12
  *
13
- * Two projection decisions are load-bearing and pre-registered. `location_id` (column 3) stays a STRING —
13
+ * Two projection decisions are required and pre-registered. `location_id` (column 3) stays a STRING —
14
14
  * the FCC's values are zero-padded 10-digit strings and `parseInt` would lose the leading zeros (decision
15
15
  * 1). `geoid` (column 10) is a string joining `TIGERBlockTable.GEOID` (decision 3).
16
16
  *
@@ -57,7 +57,7 @@
57
57
  import type { AsyncDataResource } from "spliterator"
58
58
  import { CSVSpliterator } from "spliterator"
59
59
 
60
- import type { ProviderID } from "./common.ts"
60
+ import type { ProviderID } from "#sdk/common"
61
61
 
62
62
  /**
63
63
  * Column positions in the FCC's 12-column availability CSV. Named rather than sliced by offset so a reader can check
@@ -8,8 +8,8 @@
8
8
  * over a single broadband-service claim, under the registry-backed doctrine's positive-evidence-only
9
9
  * invariant (spec §4): a BDC filing or a nearby infrastructure hit can RAISE confidence; their absence
10
10
  * can only ever read as "unknown" or "no supporting evidence found, coverage permitting" — NEVER as
11
- * "implausible." The four §7-2b acceptance gates are asserted in `plausibility.test.ts`'s
12
- * `describe("§7-2b gates")` block; this module is designed for them but doesn't assert them itself.
11
+ * "implausible." The four §7-2b acceptance criteria are asserted in `plausibility.test.ts`'s
12
+ * `describe("§7-2b criteria")` block; this module is designed for them but doesn't assert them itself.
13
13
  *
14
14
  * **Claim resolution (decision 4).** A claim's spatial key resolves two INDEPENDENT ways:
15
15
  *
@@ -24,7 +24,7 @@
24
24
  * - **Physical evidence's search center**: independent of the above — `claim.point` (or the geocoded
25
25
  * `claim.address`) directly, whenever available. A GEOID-ONLY claim (no point, no address) has NO
26
26
  * coordinate to search from: bdc.db stores no public geoid→centroid resolver (deriving one would
27
- * need the same Fabric-adjacent block-centroid machinery the vertical explicitly keeps out of reach
27
+ * need the same Fabric-adjacent block-centroid implementation the vertical explicitly keeps out of reach
28
28
  * — §2.2's boundary), so physical evidence is skipped entirely for that shape of claim. This is a
29
29
  * genuine, documented capability gap, not a missing-layer abstain: `coverage_confidence` still
30
30
  * degrades honestly (see below), but no `PlausibilityEvidence` abstain variant fits "no coordinate
@@ -88,11 +88,11 @@
88
88
  * filing coverage alone — it degrades to filing-covered → `"low"`, filing-unknown/absent →
89
89
  * `"insufficient_survey_data"`. Rationale: spec §4 frames physical co-presence as the vertical's
90
90
  * distinguishing "falsifier that only fires positively" and reserves `"high"` for genuine two-channel
91
- * corroboration (§7-2b Gate 2: "matching filing + nearby plant in covered cells… high"); a tech
91
+ * corroboration (§7-2b criterion 2: "matching filing + nearby plant in covered cells… high"); a tech
92
92
  * that structurally can never offer a second channel should not be able to claim the same top
93
93
  * confidence a fiber claim earns by actually having one available. This reading is more conservative
94
94
  * than the alternative (treating the missing axis as inert and reporting `"high"` off filing alone),
95
- * and nothing pins it: none of the four §7-2b gates exercises a no-physical-falsifier tech code.
95
+ * and nothing pins it: none of the four §7-2b criteria exercises a no-physical-falsifier tech code.
96
96
  *
97
97
  * **The per-layer coverage-resolution sanity check.** Neither bdc.db's nor poi.db's `layer_manifest`
98
98
  * records the COVERAGE-cell h3 resolution (6) that `res9ShortCellToRes6Parent` hardcodes on both sides
@@ -103,7 +103,7 @@
103
103
  * WIRED — `bdcDB`, `poi`, or both, checked independently — {@link assertLayerSpineResolution} compares that one
104
104
  * layer's recorded `spineKeys.h3.resolution` directly against the `BDC_H3_RESOLUTION` constant `pointCell` is
105
105
  * actually derived from, and throws on a mismatch, catching a layer built at a different spine resolution before it
106
- * silently mis-joins a coverage cell. This is TWO-SIDED, not gated on both layers being present together: a
106
+ * silently mis-joins a coverage cell. This is TWO-SIDED, not conditioned on both layers being present together: a
107
107
  * poi-only call still checks poi's own recorded resolution, since `readLayerCoverage`'s poi-side join key (below)
108
108
  * is derived from `BDC_H3_RESOLUTION` regardless of whether `bdcDB` is wired at all — comparing each manifest
109
109
  * against the constant, rather than the two manifests against each other, is what makes a single-layer call
@@ -112,18 +112,14 @@
112
112
  * — that gap needs the schema addition, not a runtime assertion.
113
113
  */
114
114
 
115
- import type { DatabaseClient } from "@mailwoman/core/kysley/client"
116
- import {
117
- readLayerCoverage,
118
- readLayerManifest,
119
- type LayerContractDatabase,
120
- type LayerContractHandle,
121
- } from "@mailwoman/core/layers"
122
- import type { POILookup } from "@mailwoman/resolver-wof-sqlite/poi-lookup"
115
+ import { readLayerCoverage, readLayerManifest, type LayerContractHandle } from "@mailwoman/core/layers"
116
+ import type { Evidence } from "@mailwoman/evidence"
117
+ import type { POILookup } from "@mailwoman/resolver-wof-sqlite/poi"
123
118
  import { shortCellToInt, type H3Cell, type PointLiteral } from "@mailwoman/spatial"
119
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
124
120
  import { latLngToCell } from "h3-js"
125
121
 
126
- import { BDC_H3_RESOLUTION, type BDCDatabase } from "../schema.ts"
122
+ import { BDC_H3_RESOLUTION, type BDCDatabase } from "#schema"
127
123
  import {
128
124
  BDC_SPEED_BUCKET_100_1000,
129
125
  BDC_SPEED_BUCKET_25_100,
@@ -133,13 +129,13 @@ import {
133
129
  res9ShortCellToRes6Parent,
134
130
  speedBucketForDownloadSpeed,
135
131
  type ProviderFilingSummary,
136
- } from "./filing-landscape.ts"
137
- import { nearestInfrastructure, type InfrastructureHit } from "./nearest-infrastructure.ts"
132
+ } from "#sdk/filing-landscape"
133
+ import { nearestInfrastructure, type InfrastructureHit } from "#sdk/nearest-infrastructure"
138
134
  import {
139
135
  BroadbandTechnologyCategory,
140
136
  BroadbandTechnologyCategoryToCodeSet,
141
137
  BroadbandTechnologyCode,
142
- } from "./technologies.ts"
138
+ } from "#sdk/technologies"
143
139
 
144
140
  /**
145
141
  * The three fixed-wireless codes (unlicensed/licensed/licensed-by-rule), read off
@@ -169,10 +165,29 @@ export interface PlausibilityClaim {
169
165
  export type PlausibilityAbstainReason = "requires_build_local_layer" | "requires_bdc_layer" | "insufficient_survey_data"
170
166
 
171
167
  export type PlausibilityEvidence =
172
- | { type: "filing"; filing: ProviderFilingSummary; vintage: string; corroborates: boolean }
173
- | { type: "physical_plant"; hit: InfrastructureHit }
168
+ | {
169
+ kind: "observation"
170
+ type: "filing"
171
+ source: "bdc"
172
+ vintage: string
173
+ filing: ProviderFilingSummary
174
+ corroborates: boolean
175
+ }
176
+ | { kind: "observation"; type: "physical_plant"; source: "poi"; vintage: string; hit: InfrastructureHit }
174
177
  | { type: "abstain"; reason: PlausibilityAbstainReason; layer?: string }
175
178
 
179
+ /**
180
+ * The two non-abstain variants are {@link Evidence} observations wearing their original field names, so a caller that
181
+ * already reads `.filing` keeps working while a caller that wants the shared vocabulary can narrow on `kind`. The
182
+ * abstain variant deliberately does NOT join the union: an abstain is the ABSENCE of evidence plus a reason, which
183
+ * `coverage_confidence` already reports, and minting an evidence object for "we could not look" would put a claim where
184
+ * there is none.
185
+ */
186
+ export type PlausibilitySharedEvidence =
187
+ Extract<PlausibilityEvidence, { kind: "observation" }> extends Evidence
188
+ ? Extract<PlausibilityEvidence, { kind: "observation" }>
189
+ : never
190
+
176
191
  /**
177
192
  * One evidence channel's survey-completeness state for THIS claim, WITH the reason a non-`"covered"` state applies.
178
193
  * `coverage_confidence` alone folds several genuinely different situations into the same
@@ -258,7 +273,7 @@ export interface GeocodeLike {
258
273
  */
259
274
  export interface PlausibilityPOIDeps {
260
275
  lookup: POILookup
261
- contractDB: DatabaseClient<LayerContractDatabase>
276
+ contractDB: LayerContractHandle & Pick<DatabaseClient, "destroy">
262
277
  }
263
278
 
264
279
  export interface PlausibilityDeps {
@@ -368,7 +383,7 @@ function combineCoverage(
368
383
  */
369
384
  async function assertLayerSpineResolution(
370
385
  layer: "bdc" | "poi",
371
- contractDB: LayerContractHandle,
386
+ contractDB: LayerContractHandle & Pick<DatabaseClient, "destroy">,
372
387
  expectedResolution: number
373
388
  ): Promise<void> {
374
389
  const manifest = await readLayerManifest(contractDB)
@@ -454,7 +469,9 @@ export async function plausibilityCheck(claim: PlausibilityClaim, deps: Plausibi
454
469
 
455
470
  for (const filing of landscape.filings) {
456
471
  evidence.push({
472
+ kind: "observation",
457
473
  type: "filing",
474
+ source: "bdc",
458
475
  filing,
459
476
  vintage: landscape.vintage,
460
477
  corroborates: filingCorroborates(filing, claim),
@@ -485,8 +502,10 @@ export async function plausibilityCheck(claim: PlausibilityClaim, deps: Plausibi
485
502
  categoryIDs: [...physicalCategories],
486
503
  })
487
504
 
505
+ const poiVintage = (await readLayerManifest(deps.poi.contractDB)).sourceVintage
506
+
488
507
  for (const hit of hits) {
489
- evidence.push({ type: "physical_plant", hit })
508
+ evidence.push({ kind: "observation", type: "physical_plant", source: "poi", vintage: poiVintage, hit })
490
509
  }
491
510
 
492
511
  const coverageCell = await readLayerCoverage(deps.poi.contractDB, res9ShortCellToRes6Parent(pointCell!))
package/out/env.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * The FCC Broadband Map credentials the BDC client sends.
7
+ */
8
+ import { z } from "zod";
9
+ /**
10
+ * FCC Broadband Map (BDC) public-API credentials (`bdc/lib/sdk/client.ts`) — username + hash_value header auth. Never
11
+ * log their values.
12
+ */
13
+ export declare const PrivateBDCEnvSchema: z.ZodObject<{
14
+ FCC_MAP_USERNAME: z.ZodOptional<z.ZodString>;
15
+ FCC_MAP_API_KEY: z.ZodOptional<z.ZodString>;
16
+ }, z.core.$strip>;
17
+ /**
18
+ * Live BDC credentials over core's. Never log their values.
19
+ */
20
+ export declare const $private: Record<never, never> & Record<string, never> & {
21
+ FCC_MAP_USERNAME?: string | undefined;
22
+ FCC_MAP_API_KEY?: string | undefined;
23
+ };
24
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../lib/env.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;GAGG;AACH,eAAO,MAAM,mBAAmB;;;iBAS9B,CAAA;AAEF;;GAEG;AACH,eAAO,MAAM,QAAQ;;;CAA4C,CAAA"}
package/out/env.js ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * The FCC Broadband Map credentials the BDC client sends.
7
+ */
8
+ import { $private as corePrivate, liveEnv } from "@mailwoman/core/env";
9
+ import { z } from "zod";
10
+ /**
11
+ * FCC Broadband Map (BDC) public-API credentials (`bdc/lib/sdk/client.ts`) — username + hash_value header auth. Never
12
+ * log their values.
13
+ */
14
+ export const PrivateBDCEnvSchema = z.object({
15
+ FCC_MAP_USERNAME: z.string().optional().meta({
16
+ title: "FCC Broadband Map username",
17
+ description: "Username used to authenticate to the FCC Broadband Data Collection API.",
18
+ }),
19
+ FCC_MAP_API_KEY: z.string().optional().meta({
20
+ title: "FCC Broadband Map API key",
21
+ description: "API key hash used to authenticate to the FCC Broadband Data Collection API.",
22
+ }),
23
+ });
24
+ /**
25
+ * Live BDC credentials over core's. Never log their values.
26
+ */
27
+ export const $private = liveEnv(PrivateBDCEnvSchema, corePrivate);
28
+ //# sourceMappingURL=env.js.map
package/out/env.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../lib/env.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,IAAI,WAAW,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AACtE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC;QAC5C,KAAK,EAAE,4BAA4B;QACnC,WAAW,EAAE,yEAAyE;KACtF,CAAC;IACF,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC;QAC3C,KAAK,EAAE,2BAA2B;QAClC,WAAW,EAAE,6EAA6E;KAC1F,CAAC;CACF,CAAC,CAAA;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAA"}
package/out/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from "./schema.ts";
2
- export * from "./sdk/index.ts";
1
+ export * from "#schema";
2
+ export * from "#sdk/index";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,YAAY,CAAA"}
package/out/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export * from "./schema.js";
2
- export * from "./sdk/index.js";
1
+ export * from "#schema";
2
+ export * from "#sdk/index";
3
3
  //# sourceMappingURL=index.js.map
package/out/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,YAAY,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEpC;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACpC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,6BAA6B,EAAE,MAAM,CAAA;IACrC,2BAA2B,EAAE,MAAM,CAAA;IACnC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAA;IAClB,yBAAyB,EAAE,MAAM,CAAA;IACjC;;OAEG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,gBAAgB;IAChC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAED,MAAM,WAAW,WAAY,SAAQ,qBAAqB;IACzD,gBAAgB,EAAE,oBAAoB,CAAA;IACtC,YAAY,EAAE,gBAAgB,CAAA;CAC9B;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAA;AAElC;;;GAGG;AACH,eAAO,MAAM,0BAA0B,IAAI,CAAA;AAE3C;;;;GAIG;AACH,wBAAsB,0BAA0B,CAAC,EAAE,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBvF;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,EAAE,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAQnF;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhF"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../lib/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEpC;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACpC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,6BAA6B,EAAE,MAAM,CAAA;IACrC,2BAA2B,EAAE,MAAM,CAAA;IACnC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAA;IAClB,yBAAyB,EAAE,MAAM,CAAA;IACjC;;OAEG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,gBAAgB;IAChC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAED,MAAM,WAAW,WAAY,SAAQ,qBAAqB;IACzD,gBAAgB,EAAE,oBAAoB,CAAA;IACtC,YAAY,EAAE,gBAAgB,CAAA;CAC9B;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAA;AAElC;;;GAGG;AACH,eAAO,MAAM,0BAA0B,IAAI,CAAA;AAE3C;;;;GAIG;AACH,wBAAsB,0BAA0B,CAAC,EAAE,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBvF;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,EAAE,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAQnF;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhF"}
package/out/schema.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AA+EH;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAA;AAElC;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAA;AAE3C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,EAAuB;IACvE,MAAM,EAAE,CAAC,MAAM;SACb,WAAW,CAAC,kBAAkB,CAAC;SAC/B,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACnD,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SAC9C,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAC;SAC9B,SAAS,CAAC,aAAa,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACvD,SAAS,CAAC,iBAAiB,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SAC3D,SAAS,CAAC,+BAA+B,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACzE,SAAS,CAAC,6BAA6B,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACvE,SAAS,CAAC,aAAa,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACvD,SAAS,CAAC,2BAA2B,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SAClE,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC;SAChC,OAAO,EAAE,CAAA;IAEX,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAA;AAC3G,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,EAAuB;IACnE,MAAM,EAAE,CAAC,MAAM;SACb,WAAW,CAAC,cAAc,CAAC;SAC3B,SAAS,CAAC,aAAa,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;SAC1D,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC;SACxB,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC;SAC/B,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC;SACpC,OAAO,EAAE,CAAA;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,EAAuB;IAChE,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,wBAAwB,CAAC,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAA;AACvG,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../lib/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AA+EH;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAA;AAElC;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAA;AAE3C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,EAAuB;IACvE,MAAM,EAAE,CAAC,MAAM;SACb,WAAW,CAAC,kBAAkB,CAAC;SAC/B,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACnD,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SAC9C,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAC;SAC9B,SAAS,CAAC,aAAa,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACvD,SAAS,CAAC,iBAAiB,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SAC3D,SAAS,CAAC,+BAA+B,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACzE,SAAS,CAAC,6BAA6B,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACvE,SAAS,CAAC,aAAa,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACvD,SAAS,CAAC,2BAA2B,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SAClE,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC;SAChC,OAAO,EAAE,CAAA;IAEX,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAA;AAC3G,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,EAAuB;IACnE,MAAM,EAAE,CAAC,MAAM;SACb,WAAW,CAAC,cAAc,CAAC;SAC3B,SAAS,CAAC,aAAa,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;SAC1D,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC;SACxB,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC;SAC/B,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC;SACpC,OAAO,EAAE,CAAA;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,EAAuB;IAChE,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,wBAAwB,CAAC,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAA;AACvG,CAAC"}
@@ -49,11 +49,11 @@
49
49
  * mid-build crash mustn't cost the previously-good artifact, which is exactly the failure mode
50
50
  * the house rule exists for.
51
51
  */
52
- import { DatabaseClient } from "@mailwoman/core/kysley/client";
53
52
  import type { FilerDatabase } from "@mailwoman/filer";
54
53
  import type { ProviderListRow } from "@mailwoman/filer/sdk";
55
- import type { ProviderID } from "./common.ts";
56
- import { type BDCAvailabilityRow } from "./parsing.ts";
54
+ import { DatabaseClient } from "@mailwoman/sqlite/client";
55
+ import type { ProviderID } from "#sdk/common";
56
+ import { type BDCAvailabilityRow } from "#sdk/parsing";
57
57
  /**
58
58
  * The manifest's `attribution` — names the FCC as the source, then copies the Fabric-boundary sentence verbatim from
59
59
  * `bdc/README.md`'s "CostQuest Fabric boundary" section (backticks stripped — this is plain prose, not markdown).
@@ -61,8 +61,8 @@ import { type BDCAvailabilityRow } from "./parsing.ts";
61
61
  export declare const BDC_ATTRIBUTION: string;
62
62
  export interface BuildBDCOptions {
63
63
  /**
64
- * Injected row source — the test seam (mirrors `BuildPOIOptions.rows`). When given, `csvPaths` is ignored and no
65
- * filesystem read happens.
64
+ * Injected row source — the TEST INJECTION POINT (mirrors `BuildPOIOptions.rows`). When given, `csvPaths` is ignored
65
+ * and no filesystem read happens.
66
66
  */
67
67
  rows?: Iterable<BDCAvailabilityRow> | AsyncIterable<BDCAvailabilityRow>;
68
68
  /**
@@ -94,8 +94,8 @@ export interface BuildBDCOptions {
94
94
  * Resolve a 15-char census block GEOID to its centroid. Injected so tests supply a small fixture `Map` lookup instead
95
95
  * of touching a real TIGER database; the real (CLI-wired) implementation is
96
96
  * {@linkcode createTIGERBlockCentroidLookup}, which reads `tabblock20.GEOID` (uppercase — `TIGERBlockTable`) block
97
- * geometry. Returning `undefined` for an unknown geoid is load-bearing: the materialize pass counts it in
98
- * `unknownGeoids` and skips the row — it must NEVER guess a cell.
97
+ * geometry. Returning `undefined` for an unknown geoid is required: the materialize pass counts it in `unknownGeoids`
98
+ * and skips the row — it must NEVER guess a cell.
99
99
  */
100
100
  blockCentroids: (geoid: string) => {
101
101
  lat: number;
@@ -103,9 +103,9 @@ export interface BuildBDCOptions {
103
103
  } | undefined;
104
104
  onProgress?: (message: string) => void;
105
105
  /**
106
- * Provider-list rows ({@link ProviderListRow}, `@mailwoman/filer/sdk`'s `parseProviderList`) — the test/CLI seam for
107
- * populating `bdc_provider` (2a decision 8 / 3a decision 6). When ABSENT (the default), `bdc_provider` stays empty
108
- * and the rest of the build is untouched: every code path this option touches is gated behind `if
106
+ * Provider-list rows ({@link ProviderListRow}, `@mailwoman/filer/sdk`'s `parseProviderList`) — the test/CLI injection
107
+ * point for populating `bdc_provider` (2a decision 8 / 3a decision 6). When ABSENT (the default), `bdc_provider`
108
+ * stays empty and the rest of the build is untouched: every code path this option touches is conditioned behind `if
109
109
  * (options.providers)`, so omitting it changes nothing. When present, `buildBDCDatabase` groups rows by `providerID`
110
110
  * and inserts one `bdc_provider` row per distinct provider — see {@link BuildBDCOptions.filerDB} for how the primary
111
111
  * FRN is picked when a provider carries more than one, and `schema.ts`'s `BDCProviderTable` docstring for the full
@@ -172,7 +172,7 @@ export interface BuildBDCResult {
172
172
  *
173
173
  * `csvPath` is optional and used ONLY to name the offending file in a thrown error (the direct-buffer unit tests call
174
174
  * this without one; {@linkcode readAvailabilityRowsFromCSVPaths} always supplies it). The `Number.isSafeInteger` guard
175
- * below is load-bearing, not defensive dressing: `bdc_stage.provider_id` is `INTEGER NOT NULL`, and a bare
175
+ * below is required, not defensive dressing: `bdc_stage.provider_id` is `INTEGER NOT NULL`, and a bare
176
176
  * `Number.parseInt` on a non-numeric field (a malformed/re-headered/truncated CSV) silently produces `NaN`. `NaN` binds
177
177
  * to that NOT NULL column as SQLite `NULL`, `INSERT OR IGNORE` then drops the row without a constraint error, and every
178
178
  * dropped row gets counted as `deduped` — the ENTIRE file's rows vanish silently, misreported as ordinary dedup. A
@@ -184,7 +184,7 @@ export declare function peekProviderID(csvBuffer: Buffer, csvPath?: string): Pro
184
184
  * rings for a MultiPolygon. Interior rings/holes are still ignored — a hole moves a block's centroid far less than the
185
185
  * vertex-density skew this replaces, and only 1.0% of measured blocks carry one.
186
186
  *
187
- * This REPLACED the first cut's vertex-average, whose "same res-9 cell for all but pathological shapes" claim was
187
+ * This REPLACED the first version's vertex-average, whose "same res-9 cell for all but pathological shapes" claim was
188
188
  * falsified by measurement over every real TIGER 2020 block in LA + Orange county (118,360 blocks, 2026-08-11): the
189
189
  * vertex-average landed in a different res-9 cell for 11.6% of blocks, p99 displacement 286 m (past the ~174 m cell
190
190
  * edge), max 3.7 km — the tail is TIGER's elongated rural/mountain blocks, whose boundary vertices cluster on the
@@ -201,16 +201,17 @@ export declare function geometryCentroid(geometryJSON: string | null): {
201
201
  } | undefined;
202
202
  /**
203
203
  * The production `blockCentroids` supplier: opens the TIGER blocks database READ-ONLY and probes `tabblock20.GEOID`
204
- * (uppercase) per lookup, decoding its GeoJSON `geometry` column via {@linkcode geometryCentroid}. Kept synchronous
205
- * `BuildBDCOptions.blockCentroids` is a plain sync function (the same sync-by-interface discipline AGENTS.md documents
206
- * for the resolver ladder), so this uses `node:sqlite`'s raw `.prepare()`/`.get()` directly rather than Kysely. The
207
- * connection is left open for the caller's process lifetime (a read-path lookup, not a build) same lifecycle as the
208
- * resolver-wof-sqlite lookups.
204
+ * (uppercase) per lookup, decoding its GeoJSON `geometry` column via {@linkcode geometryCentroid}. The factory awaits
205
+ * its read-only open; the per-lookup probe and the `BuildBDCOptions.blockCentroids` interface stay synchronous — a
206
+ * plain sync function (the same sync-by-interface discipline AGENTS.md documents for the resolver ladder), so the
207
+ * returned closure uses `node:sqlite`'s raw `.prepare()`/`.get()` directly rather than Kysely. The connection is left
208
+ * open for the caller's process lifetime (a read-path lookup, not a build) — same lifecycle as the resolver-wof-sqlite
209
+ * lookups.
209
210
  */
210
- export declare function createTIGERBlockCentroidLookup(tigerDBPath: string): (geoid: string) => {
211
+ export declare function createTIGERBlockCentroidLookup(tigerDBPath: string): Promise<(geoid: string) => {
211
212
  lat: number;
212
213
  lon: number;
213
- } | undefined;
214
+ } | undefined>;
214
215
  /**
215
216
  * Build `bdc.db`: stage (raw dedup) → materialize (resolve `h3_cell` per geoid, skip+count unknown geoids) → drop stage
216
217
  * → geoid index (index-after-load) → coverage → layer manifest → seal → atomic move-into-place. See the module
@@ -1 +1 @@
1
- {"version":3,"file":"build-bdc.d.ts","sourceRoot":"","sources":["../../sdk/build-bdc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAOH,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAY9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAKrD,OAAO,KAAK,EAAO,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAchE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAwB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAQ5E;;;GAGG;AACH,eAAO,MAAM,eAAe,QAEqF,CAAA;AAEjH,MAAM,WAAW,eAAe;IAC/B;;;OAGG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GAAG,aAAa,CAAC,kBAAkB,CAAC,CAAA;IACvE;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAA;IACX;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;;;;;;OAMG;IACH,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;IAC3E,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,aAAa,CAAC,eAAe,CAAC,CAAA;IACtE;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC,aAAa,CAAC,CAAA;IACvC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,cAAc;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,kBAAkB,EAAE,MAAM,CAAA;CAC1B;AA4CD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,UAAU,CA+B9E;AAwDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CA8DtG;AAED;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAC7C,WAAW,EAAE,MAAM,GACjB,CAAC,KAAK,EAAE,MAAM,KAAK;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAS7D;AAmHD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAuTxF"}
1
+ {"version":3,"file":"build-bdc.d.ts","sourceRoot":"","sources":["../../lib/sdk/build-bdc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAcH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAMrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAG3D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAgBzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAwB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAQ5E;;;GAGG;AACH,eAAO,MAAM,eAAe,QAEqF,CAAA;AAEjH,MAAM,WAAW,eAAe;IAC/B;;;OAGG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GAAG,aAAa,CAAC,kBAAkB,CAAC,CAAA;IACvE;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAA;IACX;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;;;;;;OAMG;IACH,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;IAC3E,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,aAAa,CAAC,eAAe,CAAC,CAAA;IACtE;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC,aAAa,CAAC,CAAA;IACvC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,cAAc;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,kBAAkB,EAAE,MAAM,CAAA;CAC1B;AA4CD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,UAAU,CA+B9E;AAuCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CA8DtG;AAED;;;;;;;;GAQG;AACH,wBAAsB,8BAA8B,CACnD,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC,CAStE;AAsHD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAoSxF"}