CalCOFI.io CalCOFI.io Workflows

Portal status — what needs a fresh upload

Every publisher’s output against what each portal holds, after every release

Author

CalCOFI

Published

2026-09-16

1 Why this page exists

The four publishers run after every promoted release, and each rebuilds a dataset’s output only when that dataset’s rows, metadata or the publisher’s code changed (calcofi4db::publish_fingerprint()). Two of the four portals then take a deliberate, manual step — an EDI deposit and an OBIS-USA IPT upload — and the other two publish from the pipeline when a flag says so. Whether a portal is behind is therefore a comparison, not a memory: the bytes built now against the bytes the portal was last given (calcofi4db::publish_upload_status()). This page makes that comparison for every dataset on every portal, and its first table is the to-do list.

upload_status is about the portal of record, never about our own bucket. Every package, archive and file listed here is already built and staged publicly under gs://calcofi-db/publish/ (or calcofi-files-public/netcdf/) — that is what a provider reviews. never deposited therefore means EDI has no such package / the IPT has no such resource yet, not that the bytes are missing from GCS. The staged column is the copy that does exist.

portal the copy it holds is recorded in an upload is
EDI metadata/edi_packages.csv (content_hash, built_from) CALCOFI_PUBLISH_EDI=true + EDI credentials, re-rendering publish_to-edi.qmd; refused while the record lacks a required field
OBIS (via the OBIS-USA IPT) each archive’s {dataset_key}_manifest.json (uploaded_hash) manual, after the provider agrees (Decision 21) — docs/portals.qmd § OBIS
netCDF (calcofi-files-public/netcdf/) the site’s {dataset}/manifests.json CALCOFI_PUBLISH=true, re-rendering publish_to-netcdf.qmd; unchanged bytes are never re-uploaded
ERDDAP (erddap.calcofi.io) data/erddap/deploy_status.json automatic unless CALCOFI_DEPLOY=false / CALCOFI_ERDDAP_DEPLOY=false

2 Setup

Code
librarian::shelf(dplyr, glue, jsonlite, knitr, purrr, readr, tibble, here, quiet = TRUE)
here <- here::here
options(readr.show_col_types = FALSE)
devtools::load_all(here::here("../calcofi4db"))

RELEASE_PREFIX <- Sys.getenv("CALCOFI_RELEASE_PREFIX", "ducklake/releases")
STAGING        <- grepl("staging", RELEASE_PREFIX, fixed = TRUE)
BASE_HTTPS     <- "https://storage.googleapis.com/calcofi-db"
RELEASE <- Sys.getenv("CALCOFI_RELEASE_VERSION", "")
if (!nzchar(RELEASE))
  RELEASE <- trimws(readLines(glue("{BASE_HTTPS}/{RELEASE_PREFIX}/latest.txt"), warn = FALSE)[1])
NETCDF_SITE <- "https://storage.calcofi.io/calcofi-files-public/netcdf"
OUT <- here("data/publish/portal_status.csv")
dir.create(dirname(OUT), recursive = TRUE, showWarnings = FALSE)

read_json_or_null <- function(p) tryCatch(jsonlite::fromJSON(p, simplifyVector = FALSE),
                                          error = function(e) NULL)
# the browse pages are rebuilt unless this is a staging run or the whole post-release
# chain is a dry run (the ERDDAP publisher's CALCOFI_DEPLOY convention)
REFRESH_INDEX    <- !STAGING && !identical(tolower(Sys.getenv("CALCOFI_DEPLOY", "true")), "false")
NO_REFRESH_INDEX <- !REFRESH_INDEX
cat(glue("release : {RELEASE}{if (STAGING) ' (STAGING)' else ''}"), "\n")
release : v2026.09.11 

3 EDI

Code
edi_csv <- here(if (STAGING) "data/edi-staging" else "data/edi", "manifest.csv")
edi <- if (file.exists(edi_csv)) read_csv(edi_csv, col_types = cols(.default = "c"), na = "") else NULL
edi_rows <- if (is.null(edi) || !nrow(edi)) tibble() else edi |>
  transmute(
    portal = "edi", dataset_key, built_from = version, checked_version,
    upload_status, needs_upload = as.logical(needs_upload),
    blocked_by = if_else(nzchar(coalesce(eml_blocking, "")),
                         paste("record incomplete:", eml_blocking), ""),
    how  = "CALCOFI_PUBLISH_EDI=true + EDI credentials, re-render publish_to-edi.qmd",
    link = glue("{BASE_HTTPS}/publish/edi/{dataset_key}/{dataset_key}_{version}/"))
if (nrow(edi_rows)) kable(edi_rows |> select(dataset_key, built_from, upload_status, blocked_by)) else
  cat("no EDI manifest yet\n")
dataset_key built_from upload_status blocked_by
calcofi_bottle v2026.09.11 never uploaded record incomplete: no_license (open: Q10)
calcofi_ctd-cast v2026.09.11 never uploaded record incomplete: no_license (open: Q28)
calcofi_mets v2026.09.11 never uploaded record incomplete: no_license (open: Q29)

4 OBIS

Code
obis_dir <- here(if (STAGING) "data/darwincore-staging" else "data/darwincore")
mans <- Sys.glob(file.path(obis_dir, "*_manifest.json"))
obis_rows <- map_dfr(mans, function(p) {
  m <- read_json_or_null(p)
  if (is.null(m)) return(NULL)
  st <- publish_upload_status(m$content_hash %||% NA_character_, m$uploaded_hash %||% NA_character_)
  # a resource can be on OBIS from before manifests stamped `uploaded_hash`
  # (swfsc_ichthyo, 2026-04): it is not "never uploaded", its copy is just unverifiable
  on_portal <- !is.null(m$ipt_resource) || !is.null(m$obis_dataset_id)
  if (on_portal && is.null(m$uploaded_hash))
    st$upload_status <- "on OBIS; the uploaded copy's hash was never recorded"
  tibble(
    portal = "obis", dataset_key = m$dataset_key, built_from = m$version,
    checked_version = m$checked_version %||% m$version,
    upload_status = st$upload_status, needs_upload = st$needs_upload,
    blocked_by = if (!on_portal) "provider agreement (Decision 21); no IPT resource yet" else
      if (is.null(m$uploaded_hash)) "stamp uploaded_utc + uploaded_hash in the manifest at the next upload" else "",
    how  = "manual OBIS-USA IPT upload — docs/portals.qmd § OBIS",
    link = glue("{BASE_HTTPS}/publish/dwca/{m$dataset_key}/{m$archive}"))
})
# a candidate that failed its checks has no manifest, and is listed rather than dropped
plan_csv <- file.path(obis_dir, "publish_plan.csv")
if (file.exists(plan_csv)) {
  cand <- read_csv(plan_csv, col_types = cols(.default = "c"))$dataset_key
  missing <- setdiff(cand, obis_rows$dataset_key)
  if (length(missing)) obis_rows <- bind_rows(obis_rows, tibble(
    portal = "obis", dataset_key = missing, built_from = NA, checked_version = NA,
    upload_status = "not built", needs_upload = FALSE,
    blocked_by = "no archive: failed dwc_check() — see publish_to-obis.html",
    how = "", link = ""))
}
if (nrow(obis_rows)) kable(obis_rows |> select(dataset_key, built_from, upload_status, blocked_by)) else
  cat("no Darwin Core archives built yet\n")
dataset_key built_from upload_status blocked_by
calcofi_phyllosoma v2026.09.11 never uploaded provider agreement (Decision 21); no IPT resource yet
calcofi_phytoplankton v2026.09.11 never uploaded provider agreement (Decision 21); no IPT resource yet
cce-lter_euphausiids v2026.09.11 never uploaded provider agreement (Decision 21); no IPT resource yet
cce-lter_zoodb v2026.09.11 never uploaded provider agreement (Decision 21); no IPT resource yet
cce-lter_zooscan v2026.09.11 never uploaded provider agreement (Decision 21); no IPT resource yet
cdfw_dungeness-crab v2026.09.11 never uploaded provider agreement (Decision 21); no IPT resource yet
farallon_bird-mammal v2026.09.11 never uploaded provider agreement (Decision 21); no IPT resource yet
sio_mesopelagic-fish v2026.09.11 never uploaded provider agreement (Decision 21); no IPT resource yet
swfsc_cufes v2026.09.11 never uploaded provider agreement (Decision 21); no IPT resource yet
swfsc_ichthyo v2026.09.11 on OBIS; the uploaded copy’s hash was never recorded stamp uploaded_utc + uploaded_hash in the manifest at the next upload

5 netCDF

A file counts as published for this release when the site’s manifests.json lists the release, and its bytes are online when any listed release carries the local file’s sha256 — an unchanged file is never uploaded twice, only listed.

Code
sides <- Sys.glob(here("data/netcdf/*.fingerprint.json"))
nc_rows <- map_dfr(sides, function(p) {
  s  <- read_json_or_null(p)
  ds <- sub("\\.fingerprint\\.json$", "", basename(p))
  nc <- sub("\\.fingerprint\\.json$", ".nc", p)
  if (is.null(s) || !file.exists(nc)) return(NULL)
  rel  <- read_json_or_null(glue("{NETCDF_SITE}/{ds}/manifests.json"))$releases %||% list()
  sha  <- digest::digest(nc, algo = "sha256", file = TRUE)
  online <- any(vapply(rel, function(r) identical(r$sha256, sha), logical(1)))
  listed <- any(vapply(rel, function(r) identical(r$version, RELEASE), logical(1)))
  status <- if (online && listed) "current" else if (online) "bytes online; release not listed" else
    "not online"
  tibble(portal = "netcdf", dataset_key = ds, built_from = s$built_from, checked_version = RELEASE,
         upload_status = status, needs_upload = !(online && listed), blocked_by = "",
         how  = "CALCOFI_PUBLISH=true, re-render publish_to-netcdf.qmd (+ scripts/build_netcdf_index.R)",
         link = glue("{NETCDF_SITE}/{ds}/"))
})
if (nrow(nc_rows)) kable(nc_rows |> select(dataset_key, built_from, upload_status)) else
  cat("no netCDF fingerprints yet — publish_to-netcdf.qmd has not run since change detection\n")
dataset_key built_from upload_status
calcofi_bottle v2026.09.11 current
calcofi_ctd-cast_full v2026.09.11 current
calcofi_ctd-cast v2026.09.11 current
calcofi_dic v2026.09.11 current
calcofi_mets v2026.09.11 current
calcofi_phyllosoma v2026.09.11 current
calcofi_phytoplankton v2026.09.11 current
cce-lter_euphausiids v2026.09.11 current
cce-lter_picoplankton-bacteria v2026.09.11 current
cce-lter_zoodb v2026.09.11 current
cce-lter_zooscan v2026.09.11 current
cdfw_dungeness-crab v2026.09.11 current
farallon_bird-mammal v2026.09.11 current
sio_mesopelagic-fish v2026.09.11 current
sio_pic-zooplankton v2026.09.11 current
swfsc_cufes v2026.09.11 current
swfsc_ichthyo v2026.09.11 current

6 ERDDAP

Code
es <- read_json_or_null(here("data/erddap/deploy_status.json"))
erddap_rows <- if (is.null(es)) tibble() else {
  served <- es$deployed_release %||% NA_character_
  tibble(portal = "erddap", dataset_key = "(all)", built_from = RELEASE, checked_version = RELEASE,
         upload_status = if (identical(served, RELEASE)) "current" else
           glue("serves {served %||% 'an unknown release'}"),
         needs_upload = !identical(served, RELEASE), blocked_by = "",
         how  = "re-render publish_to-erddap.qmd without CALCOFI_DEPLOY=false",
         link = "https://erddap.calcofi.io/erddap/")
}
if (nrow(erddap_rows)) kable(erddap_rows |> select(upload_status, how)) else
  cat("no ERDDAP deploy status yet — publish_to-erddap.qmd has not run since it began recording one\n")
upload_status how
current re-render publish_to-erddap.qmd without CALCOFI_DEPLOY=false

7 What needs a fresh upload

Code
status <- bind_rows(edi_rows, obis_rows, nc_rows, erddap_rows) |>
  mutate(release = RELEASE, .before = 1) |>
  arrange(desc(needs_upload), portal, dataset_key)
# "never uploaded" read as "not on GCS" in a provider meeting (2026-09-16). The
# comparison is against the portal of record, so say which portal, and show the staged
# copy that does exist beside it.
status <- status |>
  mutate(upload_status = case_when(
    upload_status == "never uploaded" & portal == "edi"  ~ "never deposited at EDI (staged on GCS)",
    upload_status == "never uploaded" & portal == "obis" ~ "never uploaded to the OBIS-USA IPT (staged on GCS)",
    upload_status == "not online"                        ~ "not yet on calcofi-files-public/netcdf",
    .default = upload_status))

write_csv(status, OUT, na = "")
if (!STAGING) put_gcs_file(OUT, "gs://calcofi-db/publish/portal_status.csv")
gs://calcofi-db/publish/portal_status.csv
Code
due <- status |> filter(needs_upload)
cat(glue("{nrow(due)} of {nrow(status)} portal copies need a fresh upload for {RELEASE}",
         "{if (nrow(due)) paste0(' (', paste(sort(unique(due$portal)), collapse = ', '), ')') else ''}"), "\n")
13 of 31 portal copies need a fresh upload for v2026.09.11 (edi, obis) 
Code
if (nrow(due))
  kable(due |> select(portal, dataset_key, built_from, upload_status, blocked_by, how, staged = link),
        caption = "due: never deposited, or changed since the last deposit")
due: never deposited, or changed since the last deposit
portal dataset_key built_from upload_status blocked_by how staged
edi calcofi_bottle v2026.09.11 never deposited at EDI (staged on GCS) record incomplete: no_license (open: Q10) CALCOFI_PUBLISH_EDI=true + EDI credentials, re-render publish_to-edi.qmd https://storage.googleapis.com/calcofi-db/publish/edi/calcofi_bottle/calcofi_bottle_v2026.09.11/
edi calcofi_ctd-cast v2026.09.11 never deposited at EDI (staged on GCS) record incomplete: no_license (open: Q28) CALCOFI_PUBLISH_EDI=true + EDI credentials, re-render publish_to-edi.qmd https://storage.googleapis.com/calcofi-db/publish/edi/calcofi_ctd-cast/calcofi_ctd-cast_v2026.09.11/
edi calcofi_mets v2026.09.11 never deposited at EDI (staged on GCS) record incomplete: no_license (open: Q29) CALCOFI_PUBLISH_EDI=true + EDI credentials, re-render publish_to-edi.qmd https://storage.googleapis.com/calcofi-db/publish/edi/calcofi_mets/calcofi_mets_v2026.09.11/
obis calcofi_phyllosoma v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet manual OBIS-USA IPT upload — docs/portals.qmd § OBIS https://storage.googleapis.com/calcofi-db/publish/dwca/calcofi_phyllosoma/calcofi_phyllosoma_v2026.09.11.zip
obis calcofi_phytoplankton v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet manual OBIS-USA IPT upload — docs/portals.qmd § OBIS https://storage.googleapis.com/calcofi-db/publish/dwca/calcofi_phytoplankton/calcofi_phytoplankton_v2026.09.11.zip
obis cce-lter_euphausiids v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet manual OBIS-USA IPT upload — docs/portals.qmd § OBIS https://storage.googleapis.com/calcofi-db/publish/dwca/cce-lter_euphausiids/cce-lter_euphausiids_v2026.09.11.zip
obis cce-lter_zoodb v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet manual OBIS-USA IPT upload — docs/portals.qmd § OBIS https://storage.googleapis.com/calcofi-db/publish/dwca/cce-lter_zoodb/cce-lter_zoodb_v2026.09.11.zip
obis cce-lter_zooscan v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet manual OBIS-USA IPT upload — docs/portals.qmd § OBIS https://storage.googleapis.com/calcofi-db/publish/dwca/cce-lter_zooscan/cce-lter_zooscan_v2026.09.11.zip
obis cdfw_dungeness-crab v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet manual OBIS-USA IPT upload — docs/portals.qmd § OBIS https://storage.googleapis.com/calcofi-db/publish/dwca/cdfw_dungeness-crab/cdfw_dungeness-crab_v2026.09.11.zip
obis farallon_bird-mammal v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet manual OBIS-USA IPT upload — docs/portals.qmd § OBIS https://storage.googleapis.com/calcofi-db/publish/dwca/farallon_bird-mammal/farallon_bird-mammal_v2026.09.11.zip
obis sio_mesopelagic-fish v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet manual OBIS-USA IPT upload — docs/portals.qmd § OBIS https://storage.googleapis.com/calcofi-db/publish/dwca/sio_mesopelagic-fish/sio_mesopelagic-fish_v2026.09.11.zip
obis swfsc_cufes v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet manual OBIS-USA IPT upload — docs/portals.qmd § OBIS https://storage.googleapis.com/calcofi-db/publish/dwca/swfsc_cufes/swfsc_cufes_v2026.09.11.zip
obis swfsc_ichthyo v2026.09.11 on OBIS; the uploaded copy’s hash was never recorded stamp uploaded_utc + uploaded_hash in the manifest at the next upload manual OBIS-USA IPT upload — docs/portals.qmd § OBIS https://storage.googleapis.com/calcofi-db/publish/dwca/swfsc_ichthyo/swfsc_ichthyo_v2026.09.11.zip
Code
kable(status |> select(portal, dataset_key, built_from, checked_version, upload_status, blocked_by, staged = link),
      caption = glue("every portal copy, {RELEASE} (data/publish/portal_status.csv)"))
every portal copy, v2026.09.11 (data/publish/portal_status.csv)
portal dataset_key built_from checked_version upload_status blocked_by staged
edi calcofi_bottle v2026.09.11 v2026.09.11 never deposited at EDI (staged on GCS) record incomplete: no_license (open: Q10) https://storage.googleapis.com/calcofi-db/publish/edi/calcofi_bottle/calcofi_bottle_v2026.09.11/
edi calcofi_ctd-cast v2026.09.11 v2026.09.11 never deposited at EDI (staged on GCS) record incomplete: no_license (open: Q28) https://storage.googleapis.com/calcofi-db/publish/edi/calcofi_ctd-cast/calcofi_ctd-cast_v2026.09.11/
edi calcofi_mets v2026.09.11 v2026.09.11 never deposited at EDI (staged on GCS) record incomplete: no_license (open: Q29) https://storage.googleapis.com/calcofi-db/publish/edi/calcofi_mets/calcofi_mets_v2026.09.11/
obis calcofi_phyllosoma v2026.09.11 v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet https://storage.googleapis.com/calcofi-db/publish/dwca/calcofi_phyllosoma/calcofi_phyllosoma_v2026.09.11.zip
obis calcofi_phytoplankton v2026.09.11 v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet https://storage.googleapis.com/calcofi-db/publish/dwca/calcofi_phytoplankton/calcofi_phytoplankton_v2026.09.11.zip
obis cce-lter_euphausiids v2026.09.11 v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet https://storage.googleapis.com/calcofi-db/publish/dwca/cce-lter_euphausiids/cce-lter_euphausiids_v2026.09.11.zip
obis cce-lter_zoodb v2026.09.11 v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet https://storage.googleapis.com/calcofi-db/publish/dwca/cce-lter_zoodb/cce-lter_zoodb_v2026.09.11.zip
obis cce-lter_zooscan v2026.09.11 v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet https://storage.googleapis.com/calcofi-db/publish/dwca/cce-lter_zooscan/cce-lter_zooscan_v2026.09.11.zip
obis cdfw_dungeness-crab v2026.09.11 v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet https://storage.googleapis.com/calcofi-db/publish/dwca/cdfw_dungeness-crab/cdfw_dungeness-crab_v2026.09.11.zip
obis farallon_bird-mammal v2026.09.11 v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet https://storage.googleapis.com/calcofi-db/publish/dwca/farallon_bird-mammal/farallon_bird-mammal_v2026.09.11.zip
obis sio_mesopelagic-fish v2026.09.11 v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet https://storage.googleapis.com/calcofi-db/publish/dwca/sio_mesopelagic-fish/sio_mesopelagic-fish_v2026.09.11.zip
obis swfsc_cufes v2026.09.11 v2026.09.11 never uploaded to the OBIS-USA IPT (staged on GCS) provider agreement (Decision 21); no IPT resource yet https://storage.googleapis.com/calcofi-db/publish/dwca/swfsc_cufes/swfsc_cufes_v2026.09.11.zip
obis swfsc_ichthyo v2026.09.11 v2026.09.11 on OBIS; the uploaded copy’s hash was never recorded stamp uploaded_utc + uploaded_hash in the manifest at the next upload https://storage.googleapis.com/calcofi-db/publish/dwca/swfsc_ichthyo/swfsc_ichthyo_v2026.09.11.zip
erddap (all) v2026.09.11 v2026.09.11 current https://erddap.calcofi.io/erddap/
netcdf calcofi_bottle v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/calcofi_bottle/
netcdf calcofi_ctd-cast v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/calcofi_ctd-cast/
netcdf calcofi_ctd-cast_full v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/calcofi_ctd-cast_full/
netcdf calcofi_dic v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/calcofi_dic/
netcdf calcofi_mets v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/calcofi_mets/
netcdf calcofi_phyllosoma v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/calcofi_phyllosoma/
netcdf calcofi_phytoplankton v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/calcofi_phytoplankton/
netcdf cce-lter_euphausiids v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/cce-lter_euphausiids/
netcdf cce-lter_picoplankton-bacteria v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/cce-lter_picoplankton-bacteria/
netcdf cce-lter_zoodb v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/cce-lter_zoodb/
netcdf cce-lter_zooscan v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/cce-lter_zooscan/
netcdf cdfw_dungeness-crab v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/cdfw_dungeness-crab/
netcdf farallon_bird-mammal v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/farallon_bird-mammal/
netcdf sio_mesopelagic-fish v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/sio_mesopelagic-fish/
netcdf sio_pic-zooplankton v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/sio_pic-zooplankton/
netcdf swfsc_cufes v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/swfsc_cufes/
netcdf swfsc_ichthyo v2026.09.11 v2026.09.11 current https://storage.calcofi.io/calcofi-files-public/netcdf/swfsc_ichthyo/

8 Refresh the browsable storage pages

storage.calcofi.io serves object storage, which has no directory listing: every browsable folder is an index.html object that scripts/build_storage_index.R writes by walking each bucket. Nothing else calls it, and the publishers above create new folders (publish/edi/{dataset}/{dataset}_{version}/, publish/dwca/, netcdf/{dataset}/{version}/) after deploy_consumers.sh has run — so every release left the browse pages one release behind, pointing at version folders that had since been pruned. On 2026-09-16 a provider meeting opened a staged EDI package link and got Not found. while the files sat on GCS. Rebuilding here, at the end of the publishers, is what keeps a link in an email true.

Code
idx <- system2("Rscript", shQuote(here("scripts/build_storage_index.R")),
               stdout = TRUE, stderr = TRUE)
cat(tail(idx, 6), sep = "\n")
if (!is.null(attr(idx, "status")) && attr(idx, "status") != 0)
  warning("build_storage_index.R failed — the browse pages still point at the previous run")
Code
cat("staging run, or CALCOFI_DEPLOY=false — the browse pages under storage.calcofi.io were\n",
    "NOT rebuilt, so a folder published by this run has no index.html yet.\n")
staging run, or CALCOFI_DEPLOY=false — the browse pages under storage.calcofi.io were
 NOT rebuilt, so a folder published by this run has no index.html yet.