Release date: 2026-08-25
sample is unique on its key โ the 4,855-duplicate bug is fixed, and a gate now guards it
An earlier same-day cut of v2026.08.25 shipped sample with 1,472,100 rows for 1,467,245 distinct sample_keys โ 3,345 bottles,
150 casts, 133 ichthyo sites and 13 underway samples appeared twice, identical except for a
seafloor_depth_m differing in the 11th decimal. The seafloor stamp (new in that release) collapsed
positions with unique() but joined them back with merge(), which compares coordinates as
15-significant-digit strings โ two positions differing past that digit both matched every sample at
either. Nothing checked sample for uniqueness; the release only warned on ship and cruise.
76,320 obs rows (35,047 bottle, 31,057 CTD, 6,032 zooscan, 1,482 ichthyo, โฆ) joined twice through
those samples, so any count or join keyed on sample over-counted them by exactly 2ร.
sampleis unique onsample_keyagain (calcofi4db 3.23.3 maps positions back by exact index and errors on a duplicate), andcheck_core_pk_unique()fails the release on any core table that is not unique on its primary key.- Consumers: anything built from v2026.08.25 (the cruise, hex and CTD apps' local databases, the station portal's derived JSON) over-counted those 4,855 samples until rebuilt on this release.
Release tables are content-addressed, and written deterministically
Between v2026.08.14 and v2026.08.25 only 52 MB of the 2.09 GB release was byte-identical, and
tables whose row counts had not changed (obs_mets_full, taxon, cruise, measurement_type)
still differed byte-for-byte: the release writes carried no total order and ran multi-threaded.
Every released table is now written by one function with a unique ORDER BY, a single writer
thread and pinned parquet options, so the same rows always give the same bytes.
- Schema: the provenance columns (
_source_file,_source_row,_source_uuid,_ingested_at) thatcruise,ship,lookupand a few reference tables still carried are no longer in the release โ_ingested_atchanged on every ingest and would have made every table look changed.lookupandspatial_attributeare exported from the assembled database like every other table instead of being copied from the ingest bucket. catalog.jsonkeepsname/rows/partitioned/supplementaland adds, per table,content_hash,bytesandobjects[]โ one entry per parquet object with itspath,bytes,sha256,content_hashandsince(the first release that shipped that content; for partitioned tables, per partition). Consumers that only read table names are unaffected.- Uploads: an object whose content is unchanged since the previous release is reused (GCS server-side copy) rather than uploaded; a release's upload is now its delta.
- Where the bytes live. Each object is stored once, under
gs://calcofi-db/ducklake/tables/{table}/{content_hash}/{table}.parquet(partitioned tables:โฆ/{table}/{col}={value}/{content_hash}/data_0.parquet), and every release whose catalog points at it shares it. The familiarreleases/{version}/parquet/{table}.parquetpath is a real copy only for the promoted version and the consolidated ones (below); onhttps://storage.calcofi.io/calcofi-db/โฆa legacy path that has no copy redirects (302) to the canonical object while it exists. Resolve tables throughcatalog.jsonobjects[].pathโcalcofi4r::cc_release_sources()(1.11.0),calcofi4py.release_sources()(0.4.0), and the same rule in db-query, db-viz-station, ctd-transects, db-viz-hex, the apps, ERDDAP's parquet sync and the PostgreSQLrelease.*views โ rather than building the path by hand.
Archive thinning: consolidated and retired versions
28 releases held 157 GB, most of it byte-identical tables re-uploaded under a new version
directory. versions.json now says which versions keep their parquet: consolidated: true for
v2026.04.08 (last per-dataset schema), v2026.05.14 (docs examples pin it), v2026.06.26,
v2026.07.17, v2026.08.14 and v2026.08.25, plus always the promoted version and the one before
it (metadata/release_policy.yml). Every other version keeps its catalog.json,
metadata.json, relationships.json and RELEASE_NOTES.md โ the record stays complete โ and
loses its parquet/; its entry carries retired: {retired_utc, to, reason} naming the nearest
kept version, cc_get_db() and cc_get_db (py) refuse it with that name, and its release page
says so. Pin a consolidated version for reproducibility; pin any other and plan to move.
A quality flag now reaches every consumer, not just the database
Ralf Goericke reported a 2.18 ml/L oxygen spike at 1,144 m on station 080.0 160.0 in the
station data finder. The value is real and was already flagged: bottle 198640 of cast 7644
(cruise 5508BD, R/V Black Douglas, 3 Sep 1955) carries O_qual = 8 (suspect) in the CalCOFI
Bottle Database. Two gaps let it through. The registry mapped o_qual onto oxygen_ml_l and
oxygen_saturation but not oxygen_umol_kg โ the form the app plots โ so the flag was dropped at
ingest; and no consumer filtered on measurement_qual at all.
oxygen_umol_kgnow carrieso_qual; the CTD unit-conversion siblings (oxygen_umol_kg_1/2,oxygen_saturation_1/2,potential_temperature_1/2) carry their sensor'sox1q/ox2q/temp1q/temp2q. The bottle ingest writes8, not8.0, like the CTD ingest.- The pre-QC
r_*bottle types deliberately stay unflagged (Q09 to the provider): code 6 "OK but taken from CTD" describes a substitution made during QC and would mislabel ~36k rows. - Consumers: one NULL-safe predicate per language โ
calcofi4r::cc_qual_ok_sql()(1.9.0),calcofi4py.qual_ok_sql()(0.3.7), db-queryqualOkSQL()โ applied in db-viz-station, db-viz-hex, ctd-transects, ctd-viz, db-query and the calcofi4r matchers/transects. On this release it excludes 35,587 bottle, 6,138 CTD and 51 DIC rows. Flagged values remain in the database with their codes; nothing is deleted.
cruise_key is the cruise's designated month, resolved by date span
YYYY-MM in cruise_key was each cast's or tow's own calendar month. A CalCOFI cruise
routinely straddles a month boundary (5508BD ran 7 Aug โ 25 Sep 1955; 184 of the 664 bottle
cruises span two months) and the neighbouring month is usually a real cruise of the same ship,
so the shorn-off casts landed on the wrong cruise with no FK ever failing: v2026.08.14 released 664
source bottle cruises as 799 keys, with 5,941 of 35,644 casts on a key their own source
disagrees with. Seven other ingests keyed tows the same way.
- The ichthyo ingest stamps every reference cruise's observed
date_min/date_max(new columns oncruise); every other ingest resolves span containment first (same ship, ยฑ 3 d โ no two cruises of one ship overlap), then the source's own designation (bottleCruise= YYYYMM), then the event month. Bottle: 799 โ 657 keys; 5508BD is 34 casts and 5509BD 22, as in the source. - The reference wins when sources disagree on a designation (ichthyo calls the 9 Feb โ 29 Mar 1984 Jordan cruise 8403, the bottle database 8402); the bottle notebook reports those cases.
- Second-order bug fixed on the way: the bottle CSV reader typed the all-digit
Cruisecolumn as DOUBLE ('195508.0'), which silently defeated the designation step on the first attempt.
Depth is a coordinate, and it is now bounded
The previous release contained a CTD "cast" with scans at 14,671 m over a 101 m seafloor โ a
fluorometer test dip (0010_001d) from the db-csvs/orig/ folder of the 2000-10 New Horizon
archive, which the tier classifier matched by substring. Its 17,964 dbar pressure value had been
deleted by the declared bound; the depth derived from it had not, because bounds apply to values,
not coordinates.
sample.seafloor_depth_m(new column): bilinear GEBCO 2025 depth at every sample position (positive down, 0 on land, NULL outside the raster โ 99.5 % of samples have one).- Release gates: a depth beyond 6,500 m (the
pressureceiling) or NaN/negative fails the release (0 violations); samples deeper than the deepest GEBCO cell within one cell of their position + 10 m are reported and ratcheted (DEPTH_SEAFLOOR_OVER_MAX = 694, only ever down) โ all but the test cast are 1949โ1975 casts and tows on slopes and canyons with minute-rounded positions, so the measurement is fine and the place is imprecise. Never deleted. - The CTD ingest excludes superseded
orig*/uncorrected/exports (every cast in them is also in the top-level file, except that test dip) but keepsseparate_runs/(20-1104SH's casts 031โ036 exist nowhere else).
Two calcofi.org archives arrived with casts nobody can place
The 19-9604JD and 19-9608NH FinalQC archives, fetched from calcofi.org for the first time, carry
9,225 "RATHBURN CORE STN" scans with -99 positions and the station name in the line/station
columns. They cannot enter sample/obs; the ingest now lists and drops them under a 0.2 %
ratchet instead of failing (Q27 asks whether coordinates exist). R's default 60 s download timeout,
which truncated every ~30 MB calcofi.org fetch at 15โ25 MB, is now one hour.
Packages: calcofi4db 3.20.1, calcofi4r 1.9.0, calcofi4py 0.3.7. Consumers rebuilt:
db-viz-station, ctd-transects (both had a broken DuckDB installer step, | sh โ | bash),
db-viz-hex, h3t API, db-viz-cruise, ERDDAP, db-query, ctd-qaqc, and ctd-viz โ whose prep_db.R
had needed the retired ctd_cast/ctd_thin/ctd_summary parquet since the core consolidation
and had served a 2026-05-15 database for three releases; it now builds from sample/obs.
Open: ERDDAP flag_values/flag_meanings on measurement_qual; netCDF *_qc companions.
Contents (generated)
| table | rows | |
|---|---|---|
cruise |
691 | |
dataset |
16 | |
dataset_taxon |
1,910 | |
grid |
218 | |
lookup |
26 | |
measurement_type |
200 | |
obs |
26,261,931 | partitioned |
obs_attribute |
452,789 | |
region |
4 | |
sample |
1,467,245 | |
sample_measurement |
589,603 | |
ship |
49 | |
spatial |
13,206 | |
spatial_attribute |
148,461 | |
taxon |
2,125 | |
taxon_group |
151 | |
obs_ctd_full |
271,394,164 | supplemental |
obs_mets_full |
19,927,416 | supplemental |
18 tables, 320,260,205 rows, 2.10 GB.
Datasets (16): calcofi_bottle, calcofi_ctd-cast, calcofi_dic, calcofi_mets, calcofi_phyllosoma, calcofi_phytoplankton, cce-lter_euphausiids, cce-lter_picoplankton-bacteria, cce-lter_zoodb, cce-lter_zooscan, cdfw_dungeness-crab, farallon_bird-mammal, sio_mesopelagic-fish, sio_pic-zooplankton, swfsc_cufes, swfsc_ichthyo
Validation: 28 pass / 0 fail / 4 skip (consumer-contract suite, 2026-08-25T14:06:36Z).
How to cite
CalCOFI (2026). CalCOFI Integrated Database, release v2026.08.25 [Data set]. Scripps Institution of Oceanography, NOAA Fisheries, and California Department of Fish and Wildlife. https://calcofi.io/db-schema/?v=v2026.08.25
Cite the source datasets you use alongside the release:
calcofi_bottleโ CalCOFI. (2023). CalCOFI Bottle Database 194903-202105. CalCOFI.org. ยท license pendingcalcofi_ctd-castโ CalCOFI. (2023). CalCOFI CTD Cast Files. CalCOFI.org. ยท license pendingcalcofi_dicโ Keeling, C.D.; Lueker, T.J.; Emanuele, G.; Dickson, A.G.; Martz, T.R.; Wolfe, W.H.; Mau, A. (2025). Discrete profile dissolved inorganic carbon, total alkalinity, water temperature and salinity measurements for CalCOFI (NCEI Accession 0301029). NOAA NCEI. https://doi.org/10.25921/3w9f-jd72 ยท CC BY 4.0calcofi_metsโ CalCOFI. Underway (METS) TSG/Meteorology Data. CalCOFI.org. ยท license pendingcalcofi_phyllosomaโ citation pending ยท license pendingcalcofi_phytoplanktonโ citation pending ยท license pendingcce-lter_euphausiidsโ citation pending ยท license pendingcce-lter_picoplankton-bacteriaโ Landry, M. (2004-2023). Picoplankton and Bacteria Abundance (CalCOFI Cruise). CCE LTER. ยท license pendingcce-lter_zoodbโ citation pending ยท license pendingcce-lter_zooscanโ citation pending ยท license pendingcdfw_dungeness-crabโ Rogers-Bennett, L.; Jones, E.; Klemmedson, A. (2026). CDFW Dungeness Crab Megalopae from archived CalCOFI plankton samples (1949-2014). California Department of Fish and Wildlife, published through CalCOFI / Scripps Institution of Oceanography. ยท CC BY 4.0farallon_bird-mammalโ citation pending ยท license pendingsio_mesopelagic-fishโ Koslow, J. Anthony (2016). CalCOFI Trawl Data. In California Cooperative Oceanic Fisheries Investigations (CalCOFI): Acoustic and Trawl Data. UC San Diego Library Digital Collections. https://doi.org/10.6075/J0BZ64DH ยท CC BY 4.0sio_pic-zooplanktonโ citation pending ยท license pendingswfsc_cufesโ citation pending ยท license pendingswfsc_ichthyoโ NOAA Fisheries SWFSC. CalCOFI Ichthyoplankton Database. ยท license pending
Access
con <- calcofi4r::cc_get_db(version = "v2026.08.25")
con = calcofi4py.cc_get_db("v2026.08.25")
Parquet: https://storage.googleapis.com/calcofi-db/ducklake/releases/v2026.08.25/parquet/{table}.parquet;
full history: RELEASES.md.