Spaces:
Configuration error
Configuration error
| /** | |
| * Stone specialist registry — the auditability contract. | |
| * | |
| * Each Stone declares the **complete inventory** of specialists it | |
| * could fire on a query, along with the FSM step name (used to join | |
| * against the run trace) and a one-line skip reason for when a | |
| * specialist is absent from a particular run. | |
| * | |
| * v0.4.5 §3: every Stone's expander shows the full intended roster, | |
| * never a filtered subset. A reader who expands a Stone sees what | |
| * could have happened *and* what did. Specialists missing from the | |
| * run output render as `not_invoked` with their registered skip | |
| * reason. | |
| * | |
| * The display name and FSM step name often differ (the trace emits | |
| * `mta_entrance_exposure`, the FSM action is `step_mta_entrances`, | |
| * the Findings adapter writes state key `mta_entrances`). The | |
| * `stepNames` list maps the registry entry to all variants the | |
| * trace might emit so we don't double-count or miss matches. | |
| */ | |
| import type { StoneKey, StoneMember } from '$lib/types/card'; | |
| export type RegistryEntry = { | |
| /** Stable id used when projecting a not_invoked row into the trace. */ | |
| id: string; | |
| /** Display name in the provenance row (italic-serif). */ | |
| name: string; | |
| /** All FSM step names that count as a "fire" for this entry. */ | |
| stepNames: string[]; | |
| /** Default tier when known; not_invoked rows render this color. */ | |
| tier?: StoneMember['tier']; | |
| /** One-line message rendered when the specialist is not_invoked. | |
| * Engineering-honest voice (V0.4.5_SPEC.md §1) — describe the | |
| * precondition that wasn't met, not "no data found". */ | |
| skipReason: string; | |
| }; | |
| export const STONE_REGISTRY: Record<StoneKey, RegistryEntry[]> = { | |
| cornerstone: [ | |
| { | |
| id: 'CORN-001', | |
| name: 'sandy_inundation.lookup', | |
| stepNames: ['sandy', 'sandy_inundation', 'sandy_nta'], | |
| tier: 'empirical', | |
| skipReason: 'Sandy 2012 inundation: query outside NYC bounds', | |
| }, | |
| { | |
| id: 'CORN-002', | |
| name: 'dep_stormwater.lookup', | |
| stepNames: ['dep', 'dep_stormwater', 'dep_extreme_2080_nta', 'dep_moderate_2050_nta', 'dep_moderate_current_nta'], | |
| tier: 'modeled', | |
| skipReason: 'NYC DEP stormwater scenarios: query outside NYC bounds', | |
| }, | |
| { | |
| id: 'CORN-003', | |
| name: 'usgs_hwm.spatial_join', | |
| stepNames: ['ida_hwm', 'ida_hwm_2021'], | |
| tier: 'empirical', | |
| skipReason: 'USGS Ida HWMs: no marks within 800 m of address', | |
| }, | |
| { | |
| id: 'CORN-004', | |
| name: 'prithvi_water.lookup', | |
| stepNames: ['prithvi', 'prithvi_eo_v2'], | |
| tier: 'modeled', | |
| skipReason: 'Prithvi-EO Ida polygons: no polygons within 500 m', | |
| }, | |
| { | |
| id: 'CORN-005', | |
| name: 'microtopo.dem_hand_twi', | |
| stepNames: ['microtopo', 'microtopo_lidar', 'microtopo_nta'], | |
| tier: 'proxy', | |
| skipReason: 'USGS 3DEP DEM: query outside NYC raster coverage', | |
| }, | |
| ], | |
| keystone: [ | |
| { | |
| id: 'KEY-001', | |
| name: 'mta_entrance_exposure', | |
| stepNames: ['mta_entrances', 'mta_entrance_exposure'], | |
| tier: 'empirical', | |
| skipReason: 'no entrances within radius', | |
| }, | |
| { | |
| id: 'KEY-002', | |
| name: 'nycha.development_join', | |
| stepNames: ['nycha', 'nycha_development_exposure'], | |
| tier: 'empirical', | |
| skipReason: 'no NYCHA developments within 1.0 mi', | |
| }, | |
| { | |
| id: 'KEY-003', | |
| name: 'doe.school_join', | |
| stepNames: ['doe_schools', 'doe_school_exposure'], | |
| tier: 'empirical', | |
| skipReason: 'no DOE schools within 1.0 mi', | |
| }, | |
| { | |
| id: 'KEY-004', | |
| name: 'doh.facility_join', | |
| stepNames: ['doh_hospitals', 'doh_hospital_exposure'], | |
| tier: 'empirical', | |
| skipReason: 'no acute-care hospitals within 1.0 mi', | |
| }, | |
| { | |
| id: 'KEY-005', | |
| name: 'pluto.lot_lookup', | |
| stepNames: ['pluto_lookup'], | |
| tier: 'empirical', | |
| skipReason: 'PLUTO join skipped: queried address not in NYC PLUTO dataset', | |
| }, | |
| { | |
| id: 'KEY-006', | |
| name: 'terramind.buildings', | |
| stepNames: ['terramind_buildings', 'terramind_synthesis'], | |
| tier: 'modeled', | |
| skipReason: 'TerraMind Buildings: no eo_chip available for this address (recent <30% cloud Sentinel-2 missing) or no high-confidence prediction', | |
| }, | |
| ], | |
| touchstone: [ | |
| { | |
| id: 'TCH-001', | |
| name: 'floodnet.history', | |
| stepNames: ['floodnet'], | |
| tier: 'empirical', | |
| skipReason: 'FloodNet sensor: no deployments within 600 m', | |
| }, | |
| { | |
| id: 'TCH-002', | |
| name: 'nyc311.flood_complaints', | |
| stepNames: ['nyc311', 'nyc311_nta'], | |
| tier: 'proxy', | |
| skipReason: 'NYC 311: no flood-relevant complaints within 200 m', | |
| }, | |
| { | |
| id: 'TCH-003', | |
| name: 'nws_obs.metar', | |
| stepNames: ['nws_obs'], | |
| tier: 'empirical', | |
| skipReason: 'NWS hourly METAR: nearest ASOS reports no precipitation', | |
| }, | |
| { | |
| id: 'TCH-004', | |
| name: 'noaa_coops.recent', | |
| stepNames: ['noaa_tides'], | |
| tier: 'empirical', | |
| skipReason: 'NOAA tide gauge: nearest station >25 km from address', | |
| }, | |
| { | |
| id: 'TCH-005', | |
| name: 'prithvi_nyc_pluvial', | |
| stepNames: ['prithvi_live', 'prithvi_eo_live'], | |
| tier: 'modeled', | |
| skipReason: 'Prithvi-NYC-Pluvial: no <30% cloud Sentinel-2 chip available in the last 120 d for this address', | |
| }, | |
| { | |
| id: 'TCH-006', | |
| name: 'terramind.lulc', | |
| stepNames: ['terramind_lulc'], | |
| tier: 'synthetic', | |
| skipReason: 'TerraMind LULC: eo_chip fetch returned no Sentinel-2 tile for this address', | |
| }, | |
| ], | |
| lodestone: [ | |
| { | |
| id: 'LOD-001', | |
| name: 'nws_alerts.flood_relevant', | |
| stepNames: ['nws_alerts'], | |
| tier: 'modeled', | |
| skipReason: 'NWS public alerts: no active flood-relevant alerts at this address', | |
| }, | |
| { | |
| id: 'LOD-002', | |
| name: 'ttm_battery_surge.zero_shot', | |
| stepNames: ['ttm_forecast'], | |
| tier: 'modeled', | |
| skipReason: 'Granite TTM r2 zero-shot: forecast not interesting (peak |residual| < 0.3 ft)', | |
| }, | |
| { | |
| id: 'LOD-003', | |
| name: 'ttm_battery_surge.fine_tune', | |
| stepNames: ['ttm_battery_surge'], | |
| tier: 'modeled', | |
| skipReason: 'Granite TTM Battery fine-tune: forecast not interesting (peak |residual| < 0.3 m)', | |
| }, | |
| { | |
| id: 'LOD-004', | |
| name: 'ttm_311_forecast', | |
| stepNames: ['ttm_311_forecast'], | |
| tier: 'modeled', | |
| skipReason: 'NYC 311 weekly forecast: no per-address history to extrapolate', | |
| }, | |
| { | |
| id: 'LOD-005', | |
| name: 'floodnet_forecast', | |
| stepNames: ['floodnet_forecast'], | |
| tier: 'modeled', | |
| skipReason: 'FloodNet sensor recurrence: sensor has < silent-floor historical events; forecast omitted', | |
| }, | |
| { | |
| id: 'LOD-006', | |
| name: 'npcc4.slr_projection', | |
| stepNames: ['npcc4_projection'], | |
| tier: 'modeled', | |
| skipReason: 'NPCC4 SLR projection: not yet wired into FSM (static reference card on hold)', | |
| }, | |
| ], | |
| capstone: [ | |
| { | |
| id: 'CAP-001', | |
| name: 'rag.granite_embedding', | |
| stepNames: ['rag_granite_embedding'], | |
| tier: 'proxy', | |
| skipReason: 'Granite Embedding RAG: no policy retrieval (out-of-NYC scope)', | |
| }, | |
| { | |
| id: 'CAP-002', | |
| name: 'gliner.typed_extraction', | |
| stepNames: ['gliner_extract'], | |
| tier: 'proxy', | |
| skipReason: 'GLiNER typed extraction: no RAG hits to extract over', | |
| }, | |
| { | |
| id: 'CAP-003', | |
| name: 'granite41.compose_briefing', | |
| stepNames: ['reconcile_granite41', 'mellea_reconcile_address', 'reconcile_neighborhood', 'reconcile_development', 'reconcile_live_now'], | |
| tier: 'modeled', | |
| skipReason: 'Reconciler did not run (no grounded data available)', | |
| }, | |
| { | |
| id: 'CAP-004', | |
| name: 'mellea.grounding_check', | |
| stepNames: ['mellea_grounding'], | |
| tier: 'modeled', | |
| skipReason: 'Mellea grounding-check: rolled into reconcile step on this run', | |
| }, | |
| ], | |
| }; | |
| /** Project the registry against the run's actual specialist members. | |
| * Emits a full-roster member list per Stone — present specialists keep | |
| * their live status; absent ones land as `not_invoked` with their | |
| * registered skip reason. */ | |
| export function fillRosterForStone( | |
| stone: StoneKey, | |
| liveMembers: StoneMember[], | |
| ): StoneMember[] { | |
| const registry = STONE_REGISTRY[stone] ?? []; | |
| // Index live members by every step name they could match. | |
| const liveByStep = new Map<string, StoneMember>(); | |
| for (const m of liveMembers) { | |
| liveByStep.set(m.name, m); | |
| } | |
| const out: StoneMember[] = []; | |
| const used = new Set<string>(); | |
| for (const entry of registry) { | |
| let live: StoneMember | undefined; | |
| for (const sn of entry.stepNames) { | |
| const hit = liveByStep.get(sn); | |
| if (hit) { | |
| live = hit; | |
| used.add(sn); | |
| break; | |
| } | |
| } | |
| if (live) { | |
| out.push({ | |
| ...live, | |
| // Override id + name with the registry's display strings so the | |
| // provenance row reads consistently regardless of trace munging. | |
| id: entry.id, | |
| name: entry.name, | |
| tier: live.tier ?? entry.tier ?? null, | |
| }); | |
| } else { | |
| out.push({ | |
| id: entry.id, | |
| name: entry.name, | |
| status: 'not_invoked', | |
| tier: entry.tier ?? null, | |
| note: entry.skipReason, | |
| }); | |
| } | |
| } | |
| // Append any live members that weren't in the registry — they were | |
| // emitted by the FSM but we don't know about them. Surface them | |
| // anyway so we don't silently drop trace rows. | |
| for (const m of liveMembers) { | |
| if (!used.has(m.name)) out.push(m); | |
| } | |
| return out; | |
| } | |