Listening for events…

Scope freeze — coral_reef_station Locationdex (6th Locationdex kind)

Decided 2026-06-27 (Mike pasted the data.gov record + ruled "build small standalone Locationdex now"). Source = EPA's 2011 probabilistic coral-reef condition survey along the southern coast of Puerto Rico. The 6th Locationdex kind (docs/locationdex-framework.md) after neutron_monitor, tide_gauge, magnetic_observatory, streamgauge, radiation_monitor. The slot is a PLACE: one reef survey station.

This one broke the session's NARS water-quality pattern (it's coral-reef ecology, not water chemistry; one region; one year), so the shape was an explicit categorization call — Mike chose a standalone Locationdex over parking it.

Slot

One (reef station) slot. Slot id is namespaced by survey: <survey_id>-<station> (e.g. pr2011-1), so stations from different surveys never collide in the file-per-slot store. Region

  • survey year are slot fields, not the slot key.

This is an EXPANDING kind (Mike, 2026-06-27: "this will definitely not be the last coral reef survey"). The build is a multi-survey registry from the start (SURVEYS dict in the build script): adding a same-format survey = one registry entry; a survey whose sheets differ in shape gets its own per-sheet reader feeding the shared aggregators + dossier (written against the real file, not a guessed schema). build() clears and fully rebuilds the kind dir from source each run, so renamed/removed slots never linger.

Surveys loaded (2):

  • pr2011 — EPA 2011 probabilistic reef survey, Puerto Rico southern coast, 64 stations.
  • usvi2009 — EPA 2009 targeted assessment of 13 stations along an east-west human-disturbance gradient around Charlotte Amalie Port, St. Thomas, USVI (station codes WCA/MCA/ECA = west / mid / east of the port). Added 2026-06-30 from the data.gov 2009-usvi record Mike pasted. Its four core sheets (station + stony coral + fish + rugosity) are the same shape as PR2011, so it reused the default reader with no new code beyond one SURVEYS entry. Publication: Oliver et al. 2018, Environmental Monitoring and Assessment 190:213.

Source

Data.gov record: https://catalog.data.gov/dataset/2011-pr-survey-data. Seven per-taxon xlsx workbooks on EPA's pasteur host (10.23719/1407509). v1 carries the three headline reef-condition layers + station info; secondary taxa deferred.

Measured reality — IN (bright line feedback_measured_reality_only)

Every value carried is a direct field measurement, all IN:

  • Stony coral (per colony): % live tissue, bleached / diseased tallies, height, max diameter, colony count, taxa richness, colony density.
  • Fish (per species, belt transect): counts by size class → total individuals, species richness, density.
  • Rugosity: draped-length / linear-distance transect ratio (structural complexity index).
  • Invertebrates (USVI2009, per belt transect): mobile-invert counts (queen conch, spiny / slipper lobster, crabs, Diadema, other sea urchins) → per-category counts + density. A category never recorded at a station is null, kept distinct from a measured zero.
  • Sponges + gorgonians (USVI2009, per quadrant): per-colony census, counts by raw type code (G gorgonian / S sponge / N), mean height + diameter, density over the sampled quadrant area.

The survey's design-based regional condition characterization (the probabilistic population estimate) is not in these raw files and is not carried — consistent with holding out the NARS condition estimates.

Held out — FoRAM Index (Mike's bright-line call, 2026-06-30)

The USVI2009 package also ships a FoRAM Index (one formula-derived foraminiferal bioindicator value per station: a fixed weighted sum of three foram-group proportions). Held out. Unlike the rugosity index (where the raw draped/linear lengths are in the file and we recompute), the FoRAM file carries only the final index — the underlying foraminiferal counts are not present, so it would be a formula output with no measured basis alongside it. Mike ruled it out under feedback_measured_reality_only (asked as a single decision; the raw-count taxa above were folded in regardless). The cached workbook is retained, so a future version with the raw counts could carry the measured assemblage directly.

Per-station aggregation / gotchas frozen here

  • Density uses the single transect-area value, not a row sum. Every colony in a station shares the one survey transect's area (25 m² for coral, 100 m² for fish); density = count / that area, not count / (rows × area). Getting this wrong would deflate density by the colony count. If a station ever carries more than one distinct transect area, the build sums the distinct values (one transect per area).
  • Fish total = sum across every size-class bin, across all species rows (counts are spread over 25 size bins <5 cm90-95 cm).
  • Bleached / Diseased / Clionid are "Yes" / blank flags → percent-of-colonies tallies.
  • Station ids are integers in the sheets → normalized to a stable string slot key (1.0"1"). USVI2009 ids are already strings (WCA-1), which pass through unchanged.
  • Rugosity index — surveys disagree on the convention, so recompute it. PR2011 stores RI as draped/linear (≥1); USVI2009 stores the reciprocal linear/draped (≤1) for the identical draped (6 m) and linear (~3–5 m) field lengths. Trusting each survey's stored RI column would make the shared mean_rugosity_index field mean opposite things. The build instead recomputes the index from the two measured lengths (larger/smaller, always draped/linear physically, ≥1); the stored RI is only a fallback (also flipped to ≥1) when a survey omits the lengths. Both lengths are direct measurements, so this stays inside the measured-reality line. PR2011's numbers are unchanged by the recompute (its stored RI already equalled draped/linear); only USVI2009 is corrected (e.g. WCA-1 0.60 → 1.66).
  • xlsx via openpyxl (read-only, data_only); curl cache-first (sandbox urllib hang).

Storage

Locationdex sibling storehouse data/location_storehouse/coral_reef_station/, file-per-slot (77 slots is negligible for the shared storehouse_index), via the event_storehouse write-dossier + disk-rebuilt-index machinery (base_dir=location_storehouse). Built by scripts/build_coral_reef_station_locationdex.py. 77 station slots across 2 surveys (64 PR2011 + 13 USVI2009), all with the coral layer (coral % live ≈ 75–90%, bleaching 0–10%, fish richness 14–24 spp, rugosity index 1.07–1.66).

Provenance (normalized: pointer + registry + read-time resolver)

Provenance is NOT embedded per slot. Each slot carries only its sources slug pointer(s) (epa_pr2011_coral_survey / epa_usvi2009_coral_survey); the full metadata (name, url = the data.gov record, doi, publication, source_files) lives once in the central registry (terrapulse.monitor.provenance.KNOWN_SOURCES + the datasources table), keyed by slug. The kind's canonical sources are also in KIND_SOURCES["coral_reef_station"], so a slot resolves even without a per-slot pointer. Resolve at read/serve time with resolve_for_kind("coral_reef_station", slot.get("sources"), conn=...); never store the resolved block on the record. The exact source workbooks stay cached byte-for-byte under data/coral_reef_cache/<survey>/, and the committed registry + SURVEYS dict hold the same URLs/DOIs, so the kind is fully reproducible. This follows the global provenance model (feedback_provenance_every_datum, Mike 2026-07-01: normalized pointer, not an embedded copy).

Deferred (not in v1)

  • PR2011 secondary taxa: invertebrates, gorgonians/sponges, Palythoa — PR2011's other workbooks (USVI2009's inverts + sponges/gorgonians are now folded in; PR2011's remain deferred, files cached, one reader-wiring away).
  • USVI2009 FoRAM Index — held out on the measured-reality line (see the section above), not merely deferred; would need a version carrying the raw foraminiferal counts.
  • Further sibling EPA regional reef surveys (other years / jurisdictions) that keep growing this into a multi-region reef-station network. Two surveys in (PR2011 + USVI2009); the registry is proven to accept same-shape surveys with one entry.
  • Spatial sweep / cross-match (swept=false, cross_match="deferred-v2-locationdex"), as with the other Locationdex kinds.
  • Exact per-transect replication (the v1 density assumes one transect per area value).
Live Feed