# Marine research observation JSON, version 1

This format imports an existing research record into the local page. It does not connect to sensors, decode a vendor's native sonar files, store files remotely, derive sound speed, or calculate sound propagation. A successful import means that the declared format is valid; it does not verify the measurements, calibration or provenance.

Each file describes one original source and declares that source as **measured** or **synthetic**. Keep sources and classifications in separate files. A synthetic file remains visibly synthetic after import. Model output is not accepted as a measured observation. There are no default observations.

## Document

The root object has exactly these keys:

| Key | Required value |
| --- | --- |
| `schema` | `"spacetime-marine-observations-v1"` |
| `source` | Object with `classification`, `title`, `originalFormat`, `reference` |
| `observations` | Array of 1–1,000 normalized records |

`source.classification` is `"measured"` or `"synthetic"`. `title` identifies the source. `originalFormat` names the original record format before normalization; it does not imply native format support. `reference` is a source citation, record identifier or URL, or explicit `null` when unknown. Reference text is preserved and is not fetched.

The file limit is **2 MiB of UTF-8 JSON**. Each profile allows at most **4,096 samples**; a file allows at most **20,000 profile samples** in total. The byte limit also applies. Unknown keys and unsupported schema versions are rejected rather than silently discarded.

## Common record fields

Every record contains these keys, plus the fields for its kind below:

| Key | Required value |
| --- | --- |
| `id` | Nonempty string, unique within the file, at most 128 characters |
| `kind` | `"water-column-profile"` or `"hydrographic-depth"` |
| `timeUtc` | Actual UTC date/time with seconds and `Z`, such as the notation `YYYY-MM-DDTHH:mm:ssZ`; optional 1–3 fractional second digits |
| `location` | `{ "latitude": number, "longitude": number, "reference": "WGS84" }` |
| `sensor` | `{ "id": string, "model": string-or-null, "calibration": { "reference": string-or-null, "timeUtc": UTC-string-or-null } }` |

The objects above use type notation; they are not a sample observation dataset. Latitude and longitude are decimal degrees within −90…90 and −180…180. Local timestamps, offsets other than `Z`, impossible calendar dates and leap-second notation are rejected. The importer does not assume a time zone or transform a coordinate system.

Calibration reference should identify the producer's calibration certificate, procedure or retained record. Unknown calibration is explicit `null`, which produces a warning. A timestamp alone does not establish calibration. Sensor identity and source metadata are retained exactly as supplied.

## Measurement object

Each supplied measurement has exactly four keys:

| Key | Meaning |
| --- | --- |
| `value` | Finite JSON number, without string coercion |
| `unit` | One of the units permitted for that field below |
| `reference` | The field's explicitly declared scale or reference |
| `uncertainty` | `null`, or `{ "value": nonnegative-number, "unit": same-unit-as-measurement, "reference": string }` |

Uncertainty reference should state the producer's statistical meaning or method, including coverage factor where relevant. The importer does not assume that a magnitude means one standard deviation, an expanded uncertainty or a confidence bound. Use `"unknown"` when its basis is unknown. **Null uncertainty means unknown, not zero.** Missing fields, `NaN`, infinity, fill-value strings and null measurement values are rejected. A missing profile channel is represented by `null` for the whole channel.

## Water-column profiles

A profile record adds `samples`, an array whose entries have exactly `depth`, `temperature`, `salinity` and `soundSpeed`. `depth` is required. The other channels may be `null`, but each sample must contain at least one of them.

| Channel | Unit | Reference | Value constraint |
| --- | --- | --- | --- |
| `depth` | `"m"` | `"sea-surface"`, `"sensor"` or `"unknown"` | Nonnegative; positive downward from the declared reference |
| `temperature` | `"degC"` | `"ITS-90"`, `"IPTS-68"` or `"unknown"` | Finite number |
| `salinity` | `"1"` | `"PSS-78"` or `"unknown"` | Nonnegative |
| `salinity` | `"g/kg"` | `"absolute-salinity"` or `"unknown"` | Nonnegative |
| `soundSpeed` | `"m/s"` | `"in-situ-measured"` | Positive; already measured, not calculated by this importer |

Practical and absolute salinity are distinct quantities and are not converted or substituted. The unit/reference pairing follows [TEOS-10's distinction between Practical and Absolute Salinity](https://www.teos-10.org/).

Depth order and repeated depth levels are retained. The importer does not sort a cast, infer missing channels, estimate sound speed or independently screen physical plausibility. An unknown reference remains unknown and produces a warning.

## Recorded hydrographic depths

A `hydrographic-depth` record adds:

- `depth`: a measurement object with unit `"m"` and reference `"vertical-datum"`.
- `verticalDatum`: `{ "name": string, "reference": string-or-null }`.

Depth is positive downward from the named vertical datum. A negative value is retained as above that datum. For a known datum, both its name and defining reference are required; identify its local realization, station and epoch when relevant. Tidal and other vertical datums are distinct reference surfaces; see [NOAA's datum guidance](https://www.geodesy.noaa.gov/docs/datums.html).

When the datum is unknown, use exactly `{ "name": "unknown", "reference": null }`. Such a record is retained with an explicit warning and cannot be aligned with another depth source. The importer never assumes mean sea level, chart datum or a water-level correction.

These are already processed, recorded hydrographic depth observations with producer-supplied provenance. Raw acoustic returns, beam packets, travel-time processing, acoustic propagation, instrument operation and navigation/control are outside this format.
