@mailwoman/bdc 8.5.0 → 9.0.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/out/schema.d.ts +15 -17
- package/out/schema.d.ts.map +1 -1
- package/out/schema.js.map +1 -1
- package/out/sdk/build-bdc.d.ts +17 -17
- package/out/sdk/build-bdc.d.ts.map +1 -1
- package/out/sdk/build-bdc.js +26 -29
- package/out/sdk/build-bdc.js.map +1 -1
- package/out/sdk/common.d.ts +5 -5
- package/out/sdk/data-collection.d.ts +2 -2
- package/out/sdk/download.d.ts +4 -4
- package/out/sdk/download.js +4 -4
- package/out/sdk/filing-landscape.d.ts +12 -19
- package/out/sdk/filing-landscape.d.ts.map +1 -1
- package/out/sdk/filing-landscape.js +14 -22
- package/out/sdk/filing-landscape.js.map +1 -1
- package/out/sdk/list-files.d.ts +1 -1
- package/out/sdk/list-files.js +1 -1
- package/out/sdk/nearest-infrastructure.d.ts +10 -11
- package/out/sdk/nearest-infrastructure.d.ts.map +1 -1
- package/out/sdk/nearest-infrastructure.js +10 -11
- package/out/sdk/nearest-infrastructure.js.map +1 -1
- package/out/sdk/plausibility.d.ts +31 -31
- package/out/sdk/plausibility.d.ts.map +1 -1
- package/out/sdk/plausibility.js +33 -35
- package/out/sdk/plausibility.js.map +1 -1
- package/package.json +6 -6
- package/schema.ts +15 -17
- package/sdk/build-bdc.ts +42 -45
- package/sdk/common.ts +5 -5
- package/sdk/data-collection.ts +2 -2
- package/sdk/download.ts +4 -4
- package/sdk/filing-landscape.ts +14 -22
- package/sdk/list-files.ts +1 -1
- package/sdk/nearest-infrastructure.ts +10 -11
- package/sdk/plausibility.ts +43 -45
|
@@ -4,15 +4,14 @@
|
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
6
|
* `nearestInfrastructure` — a coverage-paired k-nearest read over the telecom-infrastructure POI
|
|
7
|
-
* categories (`telecom_exchange`/`tower_comms
|
|
8
|
-
*
|
|
9
|
-
* table (
|
|
10
|
-
* real infrastructure to this claimed Broadband Serviceable Location, and does OUR layer even
|
|
11
|
-
* survey evidence for that area" in one call.
|
|
7
|
+
* categories (`telecom_exchange`/`tower_comms` — `@mailwoman/poi-taxonomy` categories, populated by the
|
|
8
|
+
* `--source osm` extractor) that a caller can join against ANY layer's own `layer_coverage`
|
|
9
|
+
* survey-completeness table (decision 7). Typical caller: a BDC filing scorer that wants "what's the
|
|
10
|
+
* nearest real infrastructure to this claimed Broadband Serviceable Location, and does OUR layer even
|
|
11
|
+
* have survey evidence for that area" in one call.
|
|
12
12
|
*
|
|
13
|
-
* Two
|
|
14
|
-
* `@mailwoman/core/layers` actually expose
|
|
15
|
-
* documents" instruction):
|
|
13
|
+
* Two shapes below are not the obvious ones, and both are forced by what `poi-lookup.ts` and
|
|
14
|
+
* `@mailwoman/core/layers` actually expose:
|
|
16
15
|
*
|
|
17
16
|
* - **`poiLookup` is an already-open {@link POILookup}, not a `POILookupOpts` this function
|
|
18
17
|
* constructs itself.** `POILookup`'s constructor eagerly loads the poi-taxonomy category dictionary
|
|
@@ -22,14 +21,14 @@
|
|
|
22
21
|
* `poi.db` ONCE and reuse the same `POILookup` — this wrapper takes that shape: the caller owns
|
|
23
22
|
* `POILookup`'s open/dispose lifecycle (`using poiLookup = new POILookup(...)`), we just call
|
|
24
23
|
* `.search()` on it.
|
|
25
|
-
* - **`nearestInfrastructure` is `async`, not
|
|
24
|
+
* - **`nearestInfrastructure` is `async`, not sync.** `readLayerCoverage`
|
|
26
25
|
* (`@mailwoman/core/layers`) is `Promise`-returning — every layer-contract read in this codebase is
|
|
27
26
|
* (`readLayerManifest`, `filingLandscape` itself) — so pairing each POI hit with its coverage cell
|
|
28
27
|
* means awaiting one `readLayerCoverage` call per hit. A sync signature can't await that.
|
|
29
28
|
*
|
|
30
29
|
* {@link res9ShortCellToRes6Parent} (exported by `filing-landscape.ts`; see that file's docstring for
|
|
31
|
-
* why the res-
|
|
32
|
-
*
|
|
30
|
+
* why the res-6 parent is reconstructed from the STORED res-9 cell rather than recomputed from the
|
|
31
|
+
* centroid) turns each hit's res-9 cell into the res-6 cell every layer in this repo aggregates
|
|
33
32
|
* coverage at (poi.db's own convention; `bdc.db`'s `BDC_COVERAGE_H3_RESOLUTION` matches it
|
|
34
33
|
* deliberately — see `schema.ts`). `POI_H3_RESOLUTION` (`poi-lookup.ts`) is ALSO 9, so the two layers'
|
|
35
34
|
* spines agree without this module hardcoding a resolution of its own.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nearest-infrastructure.d.ts","sourceRoot":"","sources":["../../sdk/nearest-infrastructure.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"nearest-infrastructure.d.ts","sourceRoot":"","sources":["../../sdk/nearest-infrastructure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,EAAqB,KAAK,YAAY,EAAE,KAAK,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AACzG,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,2CAA2C,CAAA;AAC7F,OAAO,EAA+B,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAKnF;;;;;GAKG;AACH,eAAO,MAAM,wCAAwC,KAAK,CAAA;AAE1D;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,YAAY,GAAG,SAAS,CAAA;CAClC;AAED,MAAM,WAAW,4BAA4B;IAC5C,MAAM,EAAE,YAAY,CAAA;IACpB;;;OAGG;IACH,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAC1C,SAAS,EAAE,SAAS,EACpB,UAAU,EAAE,cAAc,CAAC,qBAAqB,CAAC,EACjD,OAAO,EAAE,4BAA4B,GACnC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAkC9B"}
|
|
@@ -4,15 +4,14 @@
|
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
6
|
* `nearestInfrastructure` — a coverage-paired k-nearest read over the telecom-infrastructure POI
|
|
7
|
-
* categories (`telecom_exchange`/`tower_comms
|
|
8
|
-
*
|
|
9
|
-
* table (
|
|
10
|
-
* real infrastructure to this claimed Broadband Serviceable Location, and does OUR layer even
|
|
11
|
-
* survey evidence for that area" in one call.
|
|
7
|
+
* categories (`telecom_exchange`/`tower_comms` — `@mailwoman/poi-taxonomy` categories, populated by the
|
|
8
|
+
* `--source osm` extractor) that a caller can join against ANY layer's own `layer_coverage`
|
|
9
|
+
* survey-completeness table (decision 7). Typical caller: a BDC filing scorer that wants "what's the
|
|
10
|
+
* nearest real infrastructure to this claimed Broadband Serviceable Location, and does OUR layer even
|
|
11
|
+
* have survey evidence for that area" in one call.
|
|
12
12
|
*
|
|
13
|
-
* Two
|
|
14
|
-
* `@mailwoman/core/layers` actually expose
|
|
15
|
-
* documents" instruction):
|
|
13
|
+
* Two shapes below are not the obvious ones, and both are forced by what `poi-lookup.ts` and
|
|
14
|
+
* `@mailwoman/core/layers` actually expose:
|
|
16
15
|
*
|
|
17
16
|
* - **`poiLookup` is an already-open {@link POILookup}, not a `POILookupOpts` this function
|
|
18
17
|
* constructs itself.** `POILookup`'s constructor eagerly loads the poi-taxonomy category dictionary
|
|
@@ -22,14 +21,14 @@
|
|
|
22
21
|
* `poi.db` ONCE and reuse the same `POILookup` — this wrapper takes that shape: the caller owns
|
|
23
22
|
* `POILookup`'s open/dispose lifecycle (`using poiLookup = new POILookup(...)`), we just call
|
|
24
23
|
* `.search()` on it.
|
|
25
|
-
* - **`nearestInfrastructure` is `async`, not
|
|
24
|
+
* - **`nearestInfrastructure` is `async`, not sync.** `readLayerCoverage`
|
|
26
25
|
* (`@mailwoman/core/layers`) is `Promise`-returning — every layer-contract read in this codebase is
|
|
27
26
|
* (`readLayerManifest`, `filingLandscape` itself) — so pairing each POI hit with its coverage cell
|
|
28
27
|
* means awaiting one `readLayerCoverage` call per hit. A sync signature can't await that.
|
|
29
28
|
*
|
|
30
29
|
* {@link res9ShortCellToRes6Parent} (exported by `filing-landscape.ts`; see that file's docstring for
|
|
31
|
-
* why the res-
|
|
32
|
-
*
|
|
30
|
+
* why the res-6 parent is reconstructed from the STORED res-9 cell rather than recomputed from the
|
|
31
|
+
* centroid) turns each hit's res-9 cell into the res-6 cell every layer in this repo aggregates
|
|
33
32
|
* coverage at (poi.db's own convention; `bdc.db`'s `BDC_COVERAGE_H3_RESOLUTION` matches it
|
|
34
33
|
* deliberately — see `schema.ts`). `POI_H3_RESOLUTION` (`poi-lookup.ts`) is ALSO 9, so the two layers'
|
|
35
34
|
* spines agree without this module hardcoding a resolution of its own.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nearest-infrastructure.js","sourceRoot":"","sources":["../../sdk/nearest-infrastructure.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"nearest-infrastructure.js","sourceRoot":"","sources":["../../sdk/nearest-infrastructure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,iBAAiB,EAAiD,MAAM,wBAAwB,CAAA;AACzG,OAAO,EAAE,iBAAiB,EAAkB,MAAM,2CAA2C,CAAA;AAC7F,OAAO,EAAE,cAAc,EAAkC,MAAM,oBAAoB,CAAA;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AAEpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AAEjE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wCAAwC,GAAG,EAAE,CAAA;AAiC1D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAC1C,SAAoB,EACpB,UAAiD,EACjD,OAAqC;IAErC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAA;IAExD,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC;QAC7B,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,MAAM,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE;QAC/B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,wCAAwC;KACtE,CAAC,CAAA;IAEF,MAAM,kBAAkB,GAAwB,EAAE,CAAA;IAElD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,GAAG,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC7B,8FAA8F;YAC9F,8FAA8F;YAC9F,oFAAoF;YACpF,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;QAC5F,CAAC;QAED,MAAM,MAAM,GAAG,cAAc,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,SAAS,EAAE,iBAAiB,CAAW,CAAC,CAAA;QACrG,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,UAAU,EAAE,yBAAyB,CAAC,MAAM,CAAC,CAAC,CAAA;QAEvF,kBAAkB,CAAC,IAAI,CAAC;YACvB,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,oFAAoF;YACpF,SAAS,EAAE,GAAG,CAAC,SAAU;YACzB,MAAM;YACN,QAAQ;SACR,CAAC,CAAA;IACH,CAAC;IAED,OAAO,kBAAkB,CAAA;AAC1B,CAAC"}
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* `plausibilityCheck` (
|
|
7
|
-
* `filingLandscape` (
|
|
8
|
-
* broadband-service claim, under the registry-backed doctrine's positive-evidence-only
|
|
9
|
-
* §4): a BDC filing or a nearby infrastructure hit can RAISE confidence; their absence
|
|
10
|
-
* read as "unknown" or "no supporting evidence found, coverage permitting" — NEVER as
|
|
11
|
-
* The four §7-2b acceptance gates
|
|
12
|
-
* them but doesn't assert them itself.
|
|
6
|
+
* `plausibilityCheck` (spec §3.2/§4) — the heart of the BDC plausibility vertical. Composes
|
|
7
|
+
* `filingLandscape` (`bdc/sdk/filing-landscape.ts`) + `nearestInfrastructure` into ONE evidence bundle
|
|
8
|
+
* over a single broadband-service claim, under the registry-backed doctrine's positive-evidence-only
|
|
9
|
+
* invariant (spec §4): a BDC filing or a nearby infrastructure hit can RAISE confidence; their absence
|
|
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.
|
|
13
13
|
*
|
|
14
14
|
* **Claim resolution (decision 4).** A claim's spatial key resolves two INDEPENDENT ways:
|
|
15
15
|
*
|
|
@@ -88,25 +88,26 @@
|
|
|
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 (Gate 2
|
|
91
|
+
* corroboration (§7-2b Gate 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
|
-
* than the alternative (treating the missing axis as inert and reporting `"high"` off filing alone)
|
|
95
|
-
*
|
|
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.
|
|
96
96
|
*
|
|
97
|
-
* **
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
97
|
+
* **The per-layer coverage-resolution sanity check.** Neither bdc.db's nor poi.db's `layer_manifest`
|
|
98
|
+
* records the COVERAGE-cell h3 resolution (6) that `res9ShortCellToRes6Parent` hardcodes on both sides
|
|
99
|
+
* — only each layer's ROW-spine resolution (9, `spineKeys.h3.resolution`) is ever recorded. Closing
|
|
100
|
+
* that gap properly needs an addition to the layer contract itself (`@mailwoman/core/layers`), which
|
|
101
|
+
* does not exist yet. What IS practical and
|
|
102
102
|
* cheap: each manifest is a single-row table already read at most once per call here, so whenever a layer is
|
|
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
106
|
* silently mis-joins a coverage cell. This is TWO-SIDED, not gated 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
|
-
* is derived from `BDC_H3_RESOLUTION` regardless of whether `bdcDB` is wired at all
|
|
109
|
-
*
|
|
108
|
+
* is derived from `BDC_H3_RESOLUTION` regardless of whether `bdcDB` is wired at all — comparing each manifest
|
|
109
|
+
* against the constant, rather than the two manifests against each other, is what makes a single-layer call
|
|
110
|
+
* checkable at all. It
|
|
110
111
|
* can NOT catch a layer whose row spine is 9 but whose COVERAGE cells were derived at some OTHER resolution than 6
|
|
111
112
|
* — that gap needs the schema addition, not a runtime assertion.
|
|
112
113
|
*/
|
|
@@ -148,12 +149,12 @@ export type PlausibilityEvidence = {
|
|
|
148
149
|
layer?: string;
|
|
149
150
|
};
|
|
150
151
|
/**
|
|
151
|
-
* One evidence channel's survey-completeness state for THIS claim, WITH the reason a non-`"covered"` state applies
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
152
|
+
* One evidence channel's survey-completeness state for THIS claim, WITH the reason a non-`"covered"` state applies.
|
|
153
|
+
* `coverage_confidence` alone folds several genuinely different situations into the same
|
|
154
|
+
* `"low"`/`"insufficient_survey_data"` verdict (a tech with no physical falsifier at all vs. a real poi survey gap vs.
|
|
155
|
+
* a geoid-only claim with no coordinate to search from); this axis state is what tells them apart. `"not_applicable"`
|
|
156
|
+
* and `"no_coordinate"` are only ever produced for the physical axis; the filing axis only ever reaches `"covered"`,
|
|
157
|
+
* `"layer_missing"`, or `"cell_unsurveyed"`.
|
|
157
158
|
*/
|
|
158
159
|
export type PlausibilityCoverageAxisState = "covered"
|
|
159
160
|
/**
|
|
@@ -180,7 +181,7 @@ export type PlausibilityCoverageAxisState = "covered"
|
|
|
180
181
|
| "not_applicable";
|
|
181
182
|
/**
|
|
182
183
|
* Per-axis attribution for {@link PlausibilityBundle.coverage_confidence} — see {@link PlausibilityCoverageAxisState}.
|
|
183
|
-
*
|
|
184
|
+
* Reported alongside `coverage_confidence`, never in place of it: the coarse field stays the stable public surface.
|
|
184
185
|
*/
|
|
185
186
|
export interface PlausibilityCoverageDetail {
|
|
186
187
|
filing: PlausibilityCoverageAxisState;
|
|
@@ -191,8 +192,8 @@ export interface PlausibilityBundle {
|
|
|
191
192
|
evidence_found: PlausibilityEvidence[];
|
|
192
193
|
coverage_confidence: "high" | "low" | "insufficient_survey_data";
|
|
193
194
|
/**
|
|
194
|
-
* Per-axis WHY behind `coverage_confidence
|
|
195
|
-
*
|
|
195
|
+
* Per-axis WHY behind `coverage_confidence`. ALWAYS present, mirroring `block_resolution`'s always-present
|
|
196
|
+
* discipline.
|
|
196
197
|
*/
|
|
197
198
|
coverage_detail: PlausibilityCoverageDetail;
|
|
198
199
|
/**
|
|
@@ -219,7 +220,7 @@ export interface GeocodeLike {
|
|
|
219
220
|
lon: number | null;
|
|
220
221
|
}
|
|
221
222
|
/**
|
|
222
|
-
* The already-open infra layer this scorer composes against
|
|
223
|
+
* The already-open infra layer this scorer composes against {@link nearestInfrastructure}. The caller owns BOTH
|
|
223
224
|
* handles' open/dispose lifecycle (mirrors `nearestInfrastructure`'s own `using poiLookup = new POILookup(...)`
|
|
224
225
|
* precedent). `contractDB` is used two ways: passed straight through to `nearestInfrastructure` (per-hit coverage), and
|
|
225
226
|
* read directly here (the whole-cell coverage check this module needs for `coverage_confidence`, independent of whether
|
|
@@ -235,10 +236,9 @@ export interface PlausibilityDeps {
|
|
|
235
236
|
geocode?: (address: string) => Promise<GeocodeLike>;
|
|
236
237
|
}
|
|
237
238
|
/**
|
|
238
|
-
* Tech → physical-plant category mapping
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
* {@link physicalCategoriesForTechnology}).
|
|
239
|
+
* Tech → physical-plant category mapping. Fiber implies the three infrastructure-extension categories a fiber network
|
|
240
|
+
* plausibly touches; the three fixed-wireless codes imply a comms tower; every other code maps to `[]` — no physical
|
|
241
|
+
* falsifier is claimed for it (see {@link physicalCategoriesForTechnology}).
|
|
242
242
|
*/
|
|
243
243
|
export declare const PLAUSIBILITY_TECH_PHYSICAL_CATEGORIES: Readonly<Record<number, readonly string[]>>;
|
|
244
244
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plausibility.d.ts","sourceRoot":"","sources":["../../sdk/plausibility.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"plausibility.d.ts","sourceRoot":"","sources":["../../sdk/plausibility.ts"],"names":[],"mappings":"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"}
|
package/out/sdk/plausibility.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* `plausibilityCheck` (
|
|
7
|
-
* `filingLandscape` (
|
|
8
|
-
* broadband-service claim, under the registry-backed doctrine's positive-evidence-only
|
|
9
|
-
* §4): a BDC filing or a nearby infrastructure hit can RAISE confidence; their absence
|
|
10
|
-
* read as "unknown" or "no supporting evidence found, coverage permitting" — NEVER as
|
|
11
|
-
* The four §7-2b acceptance gates
|
|
12
|
-
* them but doesn't assert them itself.
|
|
6
|
+
* `plausibilityCheck` (spec §3.2/§4) — the heart of the BDC plausibility vertical. Composes
|
|
7
|
+
* `filingLandscape` (`bdc/sdk/filing-landscape.ts`) + `nearestInfrastructure` into ONE evidence bundle
|
|
8
|
+
* over a single broadband-service claim, under the registry-backed doctrine's positive-evidence-only
|
|
9
|
+
* invariant (spec §4): a BDC filing or a nearby infrastructure hit can RAISE confidence; their absence
|
|
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.
|
|
13
13
|
*
|
|
14
14
|
* **Claim resolution (decision 4).** A claim's spatial key resolves two INDEPENDENT ways:
|
|
15
15
|
*
|
|
@@ -88,25 +88,26 @@
|
|
|
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 (Gate 2
|
|
91
|
+
* corroboration (§7-2b Gate 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
|
-
* than the alternative (treating the missing axis as inert and reporting `"high"` off filing alone)
|
|
95
|
-
*
|
|
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.
|
|
96
96
|
*
|
|
97
|
-
* **
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
97
|
+
* **The per-layer coverage-resolution sanity check.** Neither bdc.db's nor poi.db's `layer_manifest`
|
|
98
|
+
* records the COVERAGE-cell h3 resolution (6) that `res9ShortCellToRes6Parent` hardcodes on both sides
|
|
99
|
+
* — only each layer's ROW-spine resolution (9, `spineKeys.h3.resolution`) is ever recorded. Closing
|
|
100
|
+
* that gap properly needs an addition to the layer contract itself (`@mailwoman/core/layers`), which
|
|
101
|
+
* does not exist yet. What IS practical and
|
|
102
102
|
* cheap: each manifest is a single-row table already read at most once per call here, so whenever a layer is
|
|
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
106
|
* silently mis-joins a coverage cell. This is TWO-SIDED, not gated 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
|
-
* is derived from `BDC_H3_RESOLUTION` regardless of whether `bdcDB` is wired at all
|
|
109
|
-
*
|
|
108
|
+
* is derived from `BDC_H3_RESOLUTION` regardless of whether `bdcDB` is wired at all — comparing each manifest
|
|
109
|
+
* against the constant, rather than the two manifests against each other, is what makes a single-layer call
|
|
110
|
+
* checkable at all. It
|
|
110
111
|
* can NOT catch a layer whose row spine is 9 but whose COVERAGE cells were derived at some OTHER resolution than 6
|
|
111
112
|
* — that gap needs the schema addition, not a runtime assertion.
|
|
112
113
|
*/
|
|
@@ -125,10 +126,9 @@ import { BroadbandTechnologyCategory, BroadbandTechnologyCategoryToCodeSet, Broa
|
|
|
125
126
|
*/
|
|
126
127
|
const FIXED_WIRELESS_CODES = BroadbandTechnologyCategoryToCodeSet[BroadbandTechnologyCategory.FixedWireless];
|
|
127
128
|
/**
|
|
128
|
-
* Tech → physical-plant category mapping
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* {@link physicalCategoriesForTechnology}).
|
|
129
|
+
* Tech → physical-plant category mapping. Fiber implies the three infrastructure-extension categories a fiber network
|
|
130
|
+
* plausibly touches; the three fixed-wireless codes imply a comms tower; every other code maps to `[]` — no physical
|
|
131
|
+
* falsifier is claimed for it (see {@link physicalCategoriesForTechnology}).
|
|
132
132
|
*/
|
|
133
133
|
export const PLAUSIBILITY_TECH_PHYSICAL_CATEGORIES = {
|
|
134
134
|
[BroadbandTechnologyCode.OpticalCarrierFiber]: ["telecom_exchange", "telecom_cabinet", "data_center"],
|
|
@@ -204,18 +204,17 @@ function combineCoverage(filingState, physicalState) {
|
|
|
204
204
|
return "low";
|
|
205
205
|
}
|
|
206
206
|
/**
|
|
207
|
-
* See the module docstring's
|
|
207
|
+
* See the module docstring's coverage-resolution note. Throws when a WIRED layer's manifest disagrees with
|
|
208
208
|
* `BDC_H3_RESOLUTION` — the single constant `plausibilityCheck` actually uses at runtime to derive both the
|
|
209
209
|
* filing-lookup cell (bdc side, via `pointCell`) and the coverage-cell join key `readLayerCoverage` is read against
|
|
210
210
|
* (poi side, via `res9ShortCellToRes6Parent(pointCell)`).
|
|
211
211
|
*
|
|
212
|
-
*
|
|
213
|
-
* only
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
* entirely, not just a disagreement between two present layers.
|
|
212
|
+
* Checked independently PER LAYER, whenever THAT layer is wired — not only when `bdcDB` and `poi` are wired together. A
|
|
213
|
+
* poi-only call still needs poi's own recorded resolution checked, because `pointCell` is computed unconditionally from
|
|
214
|
+
* `BDC_H3_RESOLUTION` and still drives the poi coverage-cell read below. Comparing each layer directly against the
|
|
215
|
+
* constant, rather than the two manifests against each other, is also strictly stronger: it catches a layer built under
|
|
216
|
+
* a since-changed `BDC_H3_RESOLUTION` even when the OTHER layer is absent entirely, not just a disagreement between two
|
|
217
|
+
* present layers.
|
|
219
218
|
*/
|
|
220
219
|
async function assertLayerSpineResolution(layer, contractDB, expectedResolution) {
|
|
221
220
|
const manifest = await readLayerManifest(contractDB);
|
|
@@ -256,9 +255,9 @@ export async function plausibilityCheck(claim, deps) {
|
|
|
256
255
|
const pointCell = point
|
|
257
256
|
? shortCellToInt(latLngToCell(point.coordinates[1], point.coordinates[0], BDC_H3_RESOLUTION))
|
|
258
257
|
: undefined;
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
//
|
|
258
|
+
// Cheap, one-time per-layer sanity check — see the module docstring's coverage-resolution note. Runs
|
|
259
|
+
// independently per WIRED layer, not only when both are present: a poi-only call still joins poi's coverage
|
|
260
|
+
// table against a BDC_H3_RESOLUTION-derived cell (below) and must not do so unchecked.
|
|
262
261
|
if (deps.bdcDB) {
|
|
263
262
|
await assertLayerSpineResolution("bdc", asContractDB(deps.bdcDB), BDC_H3_RESOLUTION);
|
|
264
263
|
}
|
|
@@ -305,9 +304,8 @@ export async function plausibilityCheck(claim, deps) {
|
|
|
305
304
|
else if (!point) {
|
|
306
305
|
// Geoid-only claim, no coordinate resolvable — see the module docstring's claim-resolution note. A real
|
|
307
306
|
// capability gap, not a missing-layer abstain: no evidence entry is fabricated, but the axis still
|
|
308
|
-
// degrades honestly for coverage_confidence
|
|
309
|
-
//
|
|
310
|
-
// finding 1).
|
|
307
|
+
// degrades honestly for coverage_confidence, naming ITS OWN reason in `coverage_detail` rather than
|
|
308
|
+
// folding into the same generic "unknown" as `"layer_missing"`.
|
|
311
309
|
physicalCoverage = "no_coordinate";
|
|
312
310
|
}
|
|
313
311
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plausibility.js","sourceRoot":"","sources":["../../sdk/plausibility.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"plausibility.js","sourceRoot":"","sources":["../../sdk/plausibility.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mailwoman/bdc",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0",
|
|
4
4
|
"description": "FCC Broadband Data Collection (BDC) availability data — fetch/parse/ingest provider and bdc.db layer reader",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bdc",
|
|
@@ -78,11 +78,11 @@
|
|
|
78
78
|
"test": "vitest run"
|
|
79
79
|
},
|
|
80
80
|
"dependencies": {
|
|
81
|
-
"@mailwoman/core": "
|
|
82
|
-
"@mailwoman/filer": "
|
|
83
|
-
"@mailwoman/resolver-wof-sqlite": "
|
|
84
|
-
"@mailwoman/spatial": "
|
|
85
|
-
"@mailwoman/tiger": "
|
|
81
|
+
"@mailwoman/core": "9.0.0",
|
|
82
|
+
"@mailwoman/filer": "9.0.0",
|
|
83
|
+
"@mailwoman/resolver-wof-sqlite": "9.0.0",
|
|
84
|
+
"@mailwoman/spatial": "9.0.0",
|
|
85
|
+
"@mailwoman/tiger": "9.0.0",
|
|
86
86
|
"h3-js": "^4.5.0",
|
|
87
87
|
"kysely": "^0.29.4",
|
|
88
88
|
"type-fest": "^5.8.0",
|
package/schema.ts
CHANGED
|
@@ -71,32 +71,30 @@ export interface BDCAvailabilityTable {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
* Provider dictionary keyed on `provider_id`. Populated by
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* read time, not write time.
|
|
74
|
+
* Provider dictionary keyed on `provider_id`. Populated by the registry join (2a decision 8) behind the optional
|
|
75
|
+
* `BuildBDCOptions.providers` (`bdc/sdk/build-bdc.ts`'s `populateBDCProviderTable`); when that option is omitted (the
|
|
76
|
+
* default), this table stays empty. No FK constraint against `bdc_availability.provider_id` — SQLite doesn't enforce
|
|
77
|
+
* FKs without `PRAGMA foreign_keys`, and the join happens at read time, not write time.
|
|
79
78
|
*
|
|
80
79
|
* **Decision 6 — this table is an explicitly LOSSY denormalization, not the source of truth.** `provider_id` is the PK
|
|
81
80
|
* (one row per provider), but the FCC's BDC provider list lets one `provider_id` carry MULTIPLE `frn` values — and
|
|
82
|
-
* conflicting `holding_company` strings — across its rows (
|
|
83
|
-
*
|
|
81
|
+
* conflicting `holding_company` strings — across its rows (`parseProviderList` preserves every one of them; see
|
|
82
|
+
* `filer/sdk/provider-list.ts`). A single-row-per-provider table cannot express that cardinality. `filer.db`
|
|
84
83
|
* (`@mailwoman/filer`) is the source of truth: it retains every `provider_id`↔`frn` (and
|
|
85
84
|
* `provider_id`↔`holding_company_name`) edge, never folded or last-wins. When `bdc.db` is built with
|
|
86
85
|
* `BuildBDCOptions.providers` supplied:
|
|
87
86
|
*
|
|
88
87
|
* - `frn` holds only the PRIMARY FRN — the one carrying the most recent Form 499 filing date, per
|
|
89
88
|
* `@mailwoman/filer/sdk`'s `readFRNFilingCandidates` + `pickPrimaryFRN` (imported into `build-bdc.ts`, never
|
|
90
|
-
* reimplemented —
|
|
91
|
-
* would
|
|
92
|
-
* `filer.db`.
|
|
93
|
-
* - `holding_company` gets the SAME single-distinct-value shortcut `frn` gets
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* `frn`'s primary pick already applies.
|
|
89
|
+
* reimplemented — that query's half-open `valid_from`/`valid_to` scoping is easy to get wrong, and a second
|
|
90
|
+
* implementation would be a second place to get it wrong). Every OTHER FRN that `provider_id` carries is discarded
|
|
91
|
+
* here but stays fully recoverable from `filer.db`.
|
|
92
|
+
* - `holding_company` gets the SAME single-distinct-value shortcut `frn` gets: when a `provider_id`'s rows carry exactly
|
|
93
|
+
* one distinct non-null `holding_company` string, there is no conflict to resolve, so it's populated directly — no
|
|
94
|
+
* rule needed, same as a single-FRN provider needs no `filerDB` query. When they carry MORE than one distinct value,
|
|
95
|
+
* that ambiguity is the real conflict decision 6 refuses to paper over with last-wins (`holding_company` has no
|
|
96
|
+
* most-recent-filing-date rule the way `frn` does), so it stays NULL and every discarded value remains recoverable
|
|
97
|
+
* from `filer.db`'s `holding_company_name` edges — the identical discipline `frn`'s primary pick already applies.
|
|
100
98
|
* - `brand_name` stays NULL unconditionally: the provider list carries no brand-name column at all, primary or otherwise,
|
|
101
99
|
* so there is nothing to populate it from.
|
|
102
100
|
*/
|