# `.well` File Format Specification — Version 2.4: Format Reference

**See also:** [overview.md](./overview.md) · [object-schemas.md](./object-schemas.md) · [interoperability.md](./interoperability.md) · [water-quality.md](./water-quality.md)

## Overview

This part of the `.well` v2.4 specification defines the file as a whole: the top-level structure and fields, how versions and deprecations work, datetime conventions, the recommended values of every open vocabulary, `well_id` and `location`, the canonical units and which unit each field uses, `profiles`, the `x-` extension rules, cross-reference and uniqueness rules, and precision fields. The objects inside each block are specified in [object-schemas.md](./object-schemas.md).

## Table of contents

- [`.well` File Format Specification — Version 2.4: Format Reference](#well-file-format-specification--version-24-format-reference)
  - [Overview](#overview)
  - [Table of contents](#table-of-contents)
  - [Top-level Structure](#top-level-structure)
    - [Absent values _(since v2.4)_](#absent-values-since-v24)
  - [Versioning](#versioning)
    - [Parser version handling](#parser-version-handling)
  - [Deprecation Policy](#deprecation-policy)
    - [Field lifecycle](#field-lifecycle)
    - [Parser behavior](#parser-behavior)
    - [Vocabulary value promotion](#vocabulary-value-promotion)
    - [Canonical deprecation registry](#canonical-deprecation-registry)
  - [Top-level Fields](#top-level-fields)
    - [Core identity](#core-identity)
    - [v2 additions](#v2-additions)
    - [v2.1 additions](#v21-additions)
    - [v2.3 additions](#v23-additions)
    - [Block kinds _(since v2.3)_](#block-kinds-since-v23)
    - [Naming rules _(since v2.3)_](#naming-rules-since-v23)
  - [Datetime Conventions](#datetime-conventions)
    - [Instants known only by date _(since v2.3)_](#instants-known-only-by-date-since-v23)
    - [Ordering and ties](#ordering-and-ties)
  - [Recommended vocabularies](#recommended-vocabularies)
  - [`well_type` — Recommended values](#well_type--recommended-values)
  - [`well_purpose` — Recommended values _(since v2.1)_](#well_purpose--recommended-values-since-v21)
  - [`bore_hole[].drilling_method` — Recommended values _(since v2.3)_](#bore_holedrilling_method--recommended-values-since-v23)
  - [Construction materials — Recommended values _(since v2.3)_](#construction-materials--recommended-values-since-v23)
  - [`well_screen[].slot_type` — Recommended values _(since v2.3)_](#well_screenslot_type--recommended-values-since-v23)
  - [`centralizers[].type` — Recommended values _(since v2.1)_](#centralizerstype--recommended-values-since-v21)
  - [`cement_pad.type` — Recommended values _(since v2.3)_](#cement_padtype--recommended-values-since-v23)
  - [`pump_installations[].type` — Recommended values _(since v2.3)_](#pump_installationstype--recommended-values-since-v23)
  - [`pump_installations[].power_source` — Recommended values _(since v2.3)_](#pump_installationspower_source--recommended-values-since-v23)
  - [`permits[].type` — Recommended values _(since v2.3)_](#permitstype--recommended-values-since-v23)
  - [`permits[].water_use` — Recommended values _(since v2.3)_](#permitswater_use--recommended-values-since-v23)
  - [`permits[].conditions[].category` — Recommended values _(since v2.3)_](#permitsconditionscategory--recommended-values-since-v23)
  - [`permits[].history[].type` — Recommended values _(since v2.3)_](#permitshistorytype--recommended-values-since-v23)
  - [`meters[].type` — Recommended values _(since v2.3)_](#meterstype--recommended-values-since-v23)
  - [`production[]` — Recommended values _(since v2.3)_](#production--recommended-values-since-v23)
  - [`water_samples[]` — Recommended values _(since v2.3)_](#water_samples--recommended-values-since-v23)
  - [`hydrodynamic_events[].measurement_method` — Recommended values](#hydrodynamic_eventsmeasurement_method--recommended-values)
  - [`aquifer_analysis[].method` — Recommended values](#aquifer_analysismethod--recommended-values)
  - [`history_logs[].category` — Recommended values](#history_logscategory--recommended-values)
  - [`history_logs[].severity` — Recommended values](#history_logsseverity--recommended-values)
  - [`history_logs[].maintenance_type` — Recommended values _(since v2.3)_](#history_logsmaintenance_type--recommended-values-since-v23)
  - [`history_logs[].status` — Allowed values _(since v2.3)_](#history_logsstatus--allowed-values-since-v23)
  - [`Attachment.document_type` — Recommended values _(since v2.3)_](#attachmentdocument_type--recommended-values-since-v23)
  - [`well_id`](#well_id)
    - [Numeric ID conversion](#numeric-id-conversion)
    - [Uniqueness](#uniqueness)
  - [`location`](#location)
    - [`LocationProperties`](#locationproperties)
    - [`elevation_datum` — Recommended values](#elevation_datum--recommended-values)
    - [CRS scope](#crs-scope)
  - [Units](#units)
    - [Canonical units](#canonical-units)
    - [Field-to-unit binding (normative)](#field-to-unit-binding-normative)
    - [Water quality units _(since v2.3)_](#water-quality-units-since-v23)
    - [Level sign convention](#level-sign-convention)
    - [Diameter and the as-built convention](#diameter-and-the-as-built-convention)
    - [Screen slot](#screen-slot)
    - [Rationale](#rationale)
  - [Water quality parameter vocabulary _(since v2.3)_](#water-quality-parameter-vocabulary-since-v23)
  - [`profiles`](#profiles)
    - [Profile schema requirements](#profile-schema-requirements)
    - [Example: a regulatory water quality profile _(since v2.3)_](#example-a-regulatory-water-quality-profile-since-v23)
    - [Profile validation](#profile-validation)
  - [Extensibility](#extensibility)
    - [Custom fields — `x-` prefix](#custom-fields--x--prefix)
    - [Custom top-level blocks — `x-` prefix required](#custom-top-level-blocks--x--prefix-required)
    - [Custom vocabulary values — `x-` prefix](#custom-vocabulary-values--x--prefix)
  - [Offline packaging _(since v2.4)_](#offline-packaging-since-v24)
  - [Cross-reference and Uniqueness Rules](#cross-reference-and-uniqueness-rules)
    - [Uniqueness scope](#uniqueness-scope)
    - [Cross-array references](#cross-array-references)
    - [Dangling references](#dangling-references)
    - [Repeated records _(since v2.4)_](#repeated-records-since-v24)
    - [Duplicate IDs within a scope](#duplicate-ids-within-a-scope)
    - [`id` field convention](#id-field-convention)
  - [Precision and Uncertainty](#precision-and-uncertainty)
    - [Supported precision fields](#supported-precision-fields)

---

## Top-level Structure

```json
{
  "version": "2.4",
  "@context": "https://welldot.org/context/v2.jsonld",

  "well_id": [ ... ],
  "location": { ... },

  "name": "...",
  "well_type": "...",
  "well_purpose": [ ... ],
  "well_driller": "...",
  "construction_date": "YYYY-MM-DD",
  "obs": "...",

  "profiles": [ ... ],

  "bore_hole": [ ... ],
  "well_case": [ ... ],
  "reduction": [ ... ],
  "well_screen": [ ... ],
  "surface_case": [ ... ],
  "hole_fill": [ ... ],
  "centralizers": [ ... ],
  "cement_pad": { ... },

  "lithology": [ ... ],
  "fractures": [ ... ],
  "caves": [ ... ],

  "hydrodynamic_events": [ ... ],
  "aquifer_analysis": [ ... ],
  "history_logs": [ ... ],

  "attachments": [ ... ],
  "pump_installations": [ ... ],
  "permits": [ ... ],
  "meters": [ ... ],
  "production": [ ... ],
  "operating_regime": [ ... ],

  "water_samples": [ ... ]
}
```

### Absent values _(since v2.4)_

An optional field without a value is omitted, never written as `null`. A `null` in an optional field is malformed. Absent means unknown.

Readers accept `null` in `aquifer_analysis[].storativity` only in files whose `version` is the integer `2`, and treat it as absent.

---

## Versioning

| Version | Description                                                                                                                                                                                                                                                           |
| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `1`     | Initial release — constructive and geologic data only                                                                                                                                                                                                                 |
| `2`     | Adds location, well_id (array), profiles, texture object, hydrodynamic_events, aquifer_analysis, history_logs, optional @context, \*\_precision fields, and extensibility conventions. Tightens unit semantics: all values are canonical SI, no per-file declaration. |
| `"2.4"` | Version written as the string `"M.m"` (_since v2.4_). Read as v2; the integer `2` means v2.0 to v2.3.                                                                                                                                                                 |

Minor revisions (`2.1`, `2.3`, …) are additive. Up to v2.3 they did not change the `version` integer: a v2.3 document declares `"version": 2`. A v2.0 parser reading a v2.1 document sees the v2.1 fields (`well_purpose`, `centralizers`) as unrecognized members without the `x-` prefix. Per § Extensibility it MUST preserve them and MUST NOT reject the file, and it SHOULD emit a warning.

The same rule applies to v2.3: a v2.0 or v2.1 parser reading a v2.3 document sees `attachments`, `pump_installations`, `permits`, `meters`, `production`, `operating_regime`, `water_samples`, `hydrodynamic_events[].corrects`, the `history_logs` data links (`hydrodynamic_event_ids`, `sample_ids`) and category-specific fields (`maintenance`, `status_change`) and the nested `attachments` arrays as unrecognized members. It MUST preserve them, MUST NOT reject the file, and SHOULD emit a warning. Such a parser does not know `corrects`, so it may still count a retracted event; this is the expected degradation.

_(since v2.4)_ The version is written as the string `"M.m"` (for example `"2.4"`). Versions are compared as two integers, never as text: `"2.10"` is greater than `"2.9"`. Patch levels (`"2.4.1"`) are not allowed. The integer `2` means v2.0 to v2.3 with the revision unknown, and it remains valid for reading. There is no separate `spec_version` field.

**Intentional break.** A parser of `@welldot/core` 0.4.0 or earlier rejects `"2.4"` files because it only accepts the integers `1` and `2`. This is the one intentional exception to the minor-revision compatibility rule above. Upgrade readers before writing v2.4 files.

### Parser version handling

The `version` field MUST be written by producers. It takes one of three forms: the integer `1`, the integer `2`, or a string `"M.m"` matching `^\d+\.\d+$`.

- A `version` that is none of these forms (`2.4` as a JSON number, `"2.4.1"`, `"v2.4"`, `"2"`) is malformed. A parser MUST reject the file with an error that names the value.
- A major other than `1` or `2` (`3`, `"3.0"`) is unsupported. A parser MUST reject the file with an error that names the value.
- Any minor of major `2` (`"2.4"`, a future `"2.9"`) is read as v2. Unknown members follow § Extensibility.

- A v2 parser encountering `version: 1` MUST apply the v1-to-v2 normalizations listed in the changes section and treat the document as v2-equivalent for all subsequent processing.
- A v1 parser encountering `version: 2` MUST reject the file with a clear error indicating an unsupported format version. v1 parsers MUST NOT attempt partial reads of v2 documents.
- Either parser encountering an unrecognized integer version MUST reject the file with a clear error.
- A file without a `version` field SHOULD be rejected. Parsers MAY emit a warning and attempt to read the file as v1 if all required v1 fields are present and no v2-specific blocks are detected, but this fallback behavior is implementation-specific and not guaranteed by the spec.

Files with `version: 1` MUST NOT contain any v2-only blocks (`hydrodynamic_events`, `aquifer_analysis`, `history_logs`, `attachments`, `pump_installations`, `permits`, `meters`, `production`, `operating_regime`, `water_samples`, `profiles`, `well_id` as array, `location` object, `@context`). A v1 file containing such fields is malformed.

---

## Deprecation Policy

The `.well` format evolves in two version dimensions:

- **Major versions** (`1`, `2`, `3`, …): may remove deprecated fields and introduce breaking changes. Each major version has its own canonical JSON Schema URL.
- **Minor revisions** within a major version (`2.0`, `2.1`, …): additive only. Minor revisions may introduce new fields, new vocabulary values, and **deprecation markers** for existing fields. Minor revisions MUST NOT remove fields, change field semantics, or break round-trip compatibility for files conforming to earlier minor revisions of the same major version.

### Field lifecycle

A field moves through three states:

1. **Active** — defined and recommended by the current minor revision.
2. **Deprecated** — still defined and still valid, but flagged for removal in the next major version. Deprecation is announced in a minor revision (e.g. introduced in v2.0, deprecated in v2.1).
3. **Removed** — no longer defined. May only occur in a new major version (e.g. removed in v3.0).

Each deprecation announcement MUST include, in the spec text for the relevant field:

- The minor revision in which the field was deprecated (e.g. _"Deprecated in v2.1"_).
- The major version in which the field will be removed (e.g. _"Will be removed in v3.0"_).
- The replacement field or pattern, when applicable.
- A v2-to-vNext normalization rule that parsers for the next major version MUST implement to read files using the deprecated field.

### Parser behavior

Parsers conformant to the version that introduced a deprecation:

- MUST accept the deprecated field as valid input.
- MUST preserve the deprecated field on round-trip unless explicitly migrating the document to a newer version.
- SHOULD emit a warning when encountering a deprecated field, naming the replacement.
- MAY offer a migration mode that rewrites the field to its replacement in place. Migration mode MUST be opt-in (e.g. an explicit flag passed to the parser), not the default behavior of read operations.

Parsers for the major version after removal:

- MUST apply the documented normalization when reading older files (e.g. a v3 parser reading a v2 file that used a v2-deprecated field).
- MUST NOT accept the removed field name in files declaring the new major version (e.g. a file with `version: 3` containing a v2-deprecated field is malformed).

### Vocabulary value promotion

When a vocabulary value previously available only with the `x-` prefix is promoted to canonical (e.g. `x-slug_test` becomes `slug_test`):

- The minor revision that performs the promotion MUST document both forms as equivalent.
- Parsers from that revision onward MUST treat both forms as equivalent for the remainder of the major version.
- The `x-` prefixed form is implicitly deprecated upon promotion and will be removed in the next major version, following the standard field lifecycle.

### Canonical deprecation registry

Each minor revision of this spec MUST include a "Deprecations" subsection in its changelog listing all fields and vocabulary values deprecated in that revision, with their replacement and removal timeline. The v2.0 release contains no deprecations.

---

## Top-level Fields

### Core identity

| Field               | Type              | Required | Description                                                                                                                                                                                                                                     |
| ------------------- | ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `version`           | integer \| string | yes      | Format version. v2.4 files write `"2.4"`.                                                                                                                                                                                                       |
| `well_type`         | string            | yes      | Construction method of the well. See vocabulary below.                                                                                                                                                                                          |
| `name`              | string            | no       | Well name or local identifier.                                                                                                                                                                                                                  |
| `well_driller`      | string            | no       | Name of the drilling company or individual.                                                                                                                                                                                                     |
| `construction_date` | string            | no       | ISO 8601 calendar date of well completion (`YYYY-MM-DD`). Date-only by design — time of day for construction completion is not meaningful at the precision the well registry cares about. Interpreted as the local civil date at the well site. |
| `obs`               | string            | no       | Free-text observations about the well.                                                                                                                                                                                                          |
| `well_depth`        | number            | no       | The well's current usable depth in meters from ground level, as measured or reported. May be less than the deepest constructive element (see `bore_hole`) due to siltation, debris, or partial backfill.                                        |

### v2 additions

| Field      | Type                      | Required | Description                                                                  |
| ---------- | ------------------------- | -------- | ---------------------------------------------------------------------------- |
| `@context` | string \| array \| object | no       | JSON-LD context. Reserved field; see § JSON-LD Context.                      |
| `well_id`  | `WellId[]`                | no       | Array of authority-scoped identifiers. See § well_id.                        |
| `location` | `Location`                | no       | Geographic position and elevation. See § location.                           |
| `profiles` | string[]                  | no       | Array of JSON Schema URLs declaring conformance to profiles. See § profiles. |

### v2.1 additions

| Field          | Type            | Required | Description                                                      |
| -------------- | --------------- | -------- | ---------------------------------------------------------------- |
| `well_purpose` | string[]        | no       | Intended use(s) of the well. See § well_purpose.                 |
| `centralizers` | `Centralizer[]` | no       | Casing/screen centralizers. See object-schemas.md § Centralizer. |

### v2.3 additions

| Field                | Type                 | Required | Description                                                                                                                           |
| -------------------- | -------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `attachments`        | `Attachment[]`       | no       | Documents about the well as a whole, not tied to any record. See object-schemas.md § Attachment.                                      |
| `pump_installations` | `PumpInstallation[]` | no       | Pump installation history (installation block). See object-schemas.md § `pump_installations[]`.                                       |
| `permits`            | `Permit[]`           | no       | Legal instruments governing abstraction (mutable record block). See object-schemas.md § `permits[]`.                                  |
| `meters`             | `Meter[]`            | no       | Totalizer (hidrômetro) installation history (installation block). See object-schemas.md § `meters[]`.                                 |
| `production`         | `ProductionEntry[]`  | no       | Ledger of meter readings and declared volumes (ledger block). See object-schemas.md § `production[]`.                                 |
| `operating_regime`   | `OperatingRegime[]`  | no       | Declared operating regimes, each in force from `effective_from` (mutable record block). See object-schemas.md § `operating_regime[]`. |
| `water_samples`      | `WaterSample[]`      | no       | Water samples and their field and laboratory results (ledger block). See water-quality.md.                                            |

### Block kinds _(since v2.3)_

Every top-level array is one of three kinds. The kind decides how records are corrected.

| Kind           | Blocks                                               | Correction                                                                                                                  | Edit tracking                                                                               |
| -------------- | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| Ledger         | `hydrodynamic_events`, `production`, `water_samples` | MAY be edited in place (NOT RECOMMENDED after export). `corrects` is the recommended mechanism for measurement corrections. | `updated_at` where the block defines it; a `corrects` entry is the history of a correction. |
| Mutable record | `history_logs`, `permits`, `operating_regime`        | Edit in place.                                                                                                              | `updated_at` (instant) on the record.                                                       |
| Installation   | `pump_installations`, `meters`                       | Edit in place.                                                                                                              | `updated_at` (instant) on the record.                                                       |

Constructive and geologic arrays describe the well as built and are edited in place. `aquifer_analysis` entries are interpretations: a new interpretation is a new entry, and earlier ones coexist.

**Ledger corrections.** A ledger entry referenced by any `corrects` field is excluded from every derivation but stays in the file. Chains are allowed (C corrects B, which corrected A); only the last uncorrected entry counts. A `corrects` cycle is malformed and emits a warning. An `aquifer_analysis` whose `source_event_ids` or `static_level_source_id` points to a retracted event emits a warning naming both ids.

**Installation pattern.** Installation blocks describe equipment present in the well for a period, with `installed_at` (required) and `removed_at` (absent means currently installed).

- `removed_at` earlier than or equal to `installed_at` is malformed and emits a warning.
- Each entry is one installation, not one piece of equipment. A unit pulled and reinstalled gets a new entry with the same `serial`.
- Overlapping open installations in the same block emit a warning, not an error. Standby pumps and secondary meters exist.

### Naming rules _(since v2.3)_

- No unit in a field name. Units are bound by the field-to-unit table (§ Units).
- `flow_rate` is the canonical name for a volumetric rate; nameplate values use the `rated_` prefix (`rated_flow_rate`, `rated_head`, `rated_power`).
- `from` / `to` are reserved for depth intervals in meters. Time intervals use `period_start` / `period_end`.
- References to another array end in `_id` (single) or `_ids` (array), plus the two relationship fields `corrects` and `supersedes`.

**`supersedes` vs `corrects`.** `supersedes` expresses legal succession between two valid permits and appears only on `permits`. It is not a correction mechanism: `corrects` retracts ledger entries.

---

## Datetime Conventions

The `.well` format distinguishes two kinds of temporal values:

**Calendar dates** — `YYYY-MM-DD`, no time, no offset. Used for `construction_date` and, since v2.3, for legal documents: `permits[].issued_at`, `valid_from`, `valid_until`, `renewal_requested_at`; `permits[].conditions[].first_due`, `last_due`; `permits[].conditions[].fulfillments[].due_date`; and `permits[].history[].date`, `due_date`. Interpreted as the local civil date at the well site. Calendar dates are sortable lexicographically and applications MUST NOT attempt to derive an instant from them.

**Instants** — RFC 3339 datetime strings with a mandatory UTC offset (e.g. `2006-03-14T08:00:00-03:00` or `2006-03-14T11:00:00Z`). Used for all event, analysis, and log timestamps:

- `hydrodynamic_events[].datetime`
- `aquifer_analysis[].datetime`
- `history_logs[].datetime`
- `history_logs[].updated_at`
- `pump_installations[].installed_at`, `removed_at`, `updated_at` _(since v2.3)_
- `permits[].updated_at`, `permits[].history[].updated_at`, `permits[].conditions[].fulfillments[].datetime`, `updated_at` _(since v2.3)_
- `meters[].installed_at`, `removed_at`, `updated_at` _(since v2.3)_
- `production[].datetime` (`meter_reading`); `production[].period_start`, `period_end` (`estimated_volume`) _(since v2.3)_
- `operating_regime[].effective_from`, `updated_at` _(since v2.3)_
- `water_samples[].datetime`, `laboratory.received_at`, `results[].analyzed_at`, `results[].validation.validated_at` _(since v2.3)_

Validity and deadline checks compare calendar dates, never UTC instants. When an instant is compared with a calendar date — for example a condition fulfillment's `datetime` against its `due_date` — the instant's local date is the instant converted to `location.properties.timezone` _(since v2.4)_. Without `timezone`, it is the date part of the string, in the offset it carries; producers SHOULD then write such instants in the well site's local offset. A file without `timezone` whose permits have condition fulfillments emits a warning.

Relative deadlines and recurrences are ISO 8601 date durations (`P90D`, `P6M`, `P1Y6M`); see object-schemas.md § Date duration.

### Instants known only by date _(since v2.3)_

Laboratory reports often give only the date of receipt or analysis. Such an instant is written at 00:00 local time at the well site, and a sibling field named after it with the `_resolution` suffix is set to `"day"`:

```json
{ "analyzed_at": "2026-09-17T00:00:00-03:00", "analyzed_at_resolution": "day" }
```

- Consumers MUST ignore the time of day when `_resolution` is `day`. Ordering, holding-time and deadline calculations on that field use day resolution.
- `day` is the only allowed value; any other value is malformed. An absent `_resolution` means the instant is exact.
- In v2.3 the convention applies to `water_samples[].laboratory.received_at` and `water_samples[].results[].analyzed_at`. It is the candidate general convention for any instant known only by its date.

A datetime without an offset (naked `YYYY-MM-DDTHH:MM:SS`) is malformed and parsers MUST reject it. Time zone abbreviations (`EST`, `BRT`) are not RFC 3339 and MUST NOT be used.

### Ordering and ties

Instants are ordered by absolute UTC instant, not by the lexical form of the string. The strings `2006-03-14T08:00:00-03:00` and `2006-03-14T11:00:00Z` represent the same instant and tie for ordering purposes.

When two events share the same instant, the optional `sequence` integer breaks the tie (lower values sort first). When two events share the same instant and no `sequence` is provided, ordering is implementation-defined; producers SHOULD provide `sequence` when authoring events with identical instants.

---

## Recommended vocabularies

Many string fields are **open**: they accept any value, but recommend a vocabulary for interoperability. The sections below list each one. Non-canonical values SHOULD use the `x-` prefix, and tools MUST preserve unrecognized values and display them as-is.

Every recommended vocabulary is also published as data by `@welldot/core` (e.g. `PERMIT_TYPES`, `CONSTRUCTION_MATERIALS`, `SAMPLE_TYPES`), each entry carrying its `value` and display labels keyed by BCP 47 language tag (at least `en` and `pt`). The field types use the `OpenVocab<T>` pattern (`T | (string & {})`): the recommended values are typed while any other string stays valid. The Portuguese column in the tables below may be more descriptive than the short display label.

## `well_type` — Recommended values

The `well_type` field accepts any string and describes the well's **construction method**. The values below are the recommended vocabulary for interoperability. Tools should treat unrecognized values gracefully.

| Value                  | Portuguese (BR)         | Description                                    |
| ---------------------- | ----------------------- | ---------------------------------------------- |
| `tubular`              | Tubular                 | Conventional rotary or percussion drilled well |
| `hand_dug`             | Cacimba / poço escavado | Manually excavated well or cistern             |
| `horizontal`           | Horizontal              | Horizontal or sub-horizontal well              |
| `infiltration_gallery` | Galeria de infiltração  | Horizontal subsurface infiltration gallery     |
| `artesian`             | Artesiano               | **Deprecated in v2.1** — see below             |

Non-canonical values SHOULD use the `x-` prefix (e.g. `x-radial_collector`).

**`artesian` (deprecated in v2.1, removal in v3).** Artesianism is a hydraulic condition, not a construction method: an artesian well is usually a `tubular` well. A flowing artesian condition is recorded as a `hydrodynamic_events` entry whose `static_level` is negative (see § Level sign convention), and applications derive the label from it. Parsers MUST continue to accept `well_type: "artesian"` and MUST NOT rewrite it. Authoring tools SHOULD offer to migrate it to the actual construction method on edit.

---

## `well_purpose` — Recommended values _(since v2.1)_

`well_purpose` is an optional array of strings giving the well's current intended use(s). A well may have more than one purpose (e.g. `["production", "monitoring"]`). Changes of use over time belong in `history_logs` (category `event`). Non-canonical values SHOULD use the `x-` prefix.

| Value                   | Portuguese (BR)                 | Description                                                      |
| ----------------------- | ------------------------------- | ---------------------------------------------------------------- |
| `production`            | Produção / captação             | Water supply abstraction                                         |
| `monitoring`            | Poço de monitoramento           | Groundwater level and/or quality monitoring                      |
| `piezometer`            | Piezômetro                      | Measures hydraulic head at a discrete depth interval             |
| `water_level_indicator` | INA — indicador de nível d'água | Open standpipe for water table readings (typically geotechnical) |
| `observation`           | Poço de observação              | Observation well for aquifer tests on a nearby pumping well      |
| `exploration`           | Pesquisa / exploratório         | Investigation or test well                                       |
| `injection`             | Injeção / recarga               | Managed aquifer recharge or injection                            |
| `dewatering`            | Rebaixamento                    | Construction or mining dewatering                                |

---

## `bore_hole[].drilling_method` — Recommended values _(since v2.3)_

| Value        | English    | Portuguese (BR)    |
| ------------ | ---------- | ------------------ |
| `rotary`     | Rotary     | Rotativo           |
| `percussion` | Percussion | Percussão          |
| `cable_tool` | Cable tool | Percussão a cabo   |
| `auger`      | Auger      | Trado              |
| `air_hammer` | Air hammer | Martelo pneumático |

Non-canonical values SHOULD use the `x-` prefix.

## Construction materials — Recommended values _(since v2.3)_

Shared by `well_case[].type`, `well_screen[].type`, `reduction[].type` and `pump_installations[].riser_material`.

| Value               | English           | Portuguese (BR) |
| ------------------- | ----------------- | --------------- |
| `pvc`               | PVC               | PVC             |
| `geomechanical_pvc` | Geomechanical PVC | PVC geomecânico |
| `carbon_steel`      | Carbon steel      | Aço carbono     |
| `galvanized_steel`  | Galvanized steel  | Aço galvanizado |
| `stainless_steel`   | Stainless steel   | Aço inox        |
| `fiberglass`        | Fiberglass        | Fibra de vidro  |

Non-canonical values SHOULD use the `x-` prefix.

## `well_screen[].slot_type` — Recommended values _(since v2.3)_

The screen design, independent of its material (`well_screen[].type`).

| Value             | English         | Portuguese (BR)           |
| ----------------- | --------------- | ------------------------- |
| `continuous_slot` | Continuous slot | Espiralado (tipo Johnson) |
| `slotted`         | Slotted         | Ranhurado                 |
| `bridge_slot`     | Bridge slot     | Tipo ponte                |
| `louver`          | Louver          | Veneziana                 |
| `perforated`      | Perforated      | Perfurado                 |
| `nold`            | Nold type       | Tipo Nold                 |

`continuous_slot` is the wire-wrapped (wire-wound) screen. `nold` is the steel screen sold under that trade designation (_filtro tipo Nold_). Non-canonical values SHOULD use the `x-` prefix.

## `centralizers[].type` — Recommended values _(since v2.1)_

| Value              | English          | Portuguese (BR)   |
| ------------------ | ---------------- | ----------------- |
| `spring_bow`       | Spring bow       | Mola (spring bow) |
| `rigid`            | Rigid            | Rígido            |
| `semi_rigid`       | Semi-rigid       | Semirrígido       |
| `polymer`          | Polymer          | Polimérico        |
| `carbon_steel`     | Carbon steel     | Aço carbono       |
| `galvanized_steel` | Galvanized steel | Aço galvanizado   |
| `stainless_steel`  | Stainless steel  | Aço inox          |

The steel values name rigid centralizers by their material. Non-canonical values SHOULD use the `x-` prefix.

## `cement_pad.type` — Recommended values _(since v2.3)_

| Value                 | English             | Portuguese (BR) |
| --------------------- | ------------------- | --------------- |
| `concrete`            | Concrete            | Concreto        |
| `reinforced_concrete` | Reinforced concrete | Concreto armado |
| `cement`              | Cement              | Cimento         |
| `mortar`              | Mortar              | Argamassa       |

`type` describes the pad material; other free text (e.g. a shape) remains valid.

---

## `pump_installations[].type` — Recommended values _(since v2.3)_

| Value                | Portuguese (BR)        | Description                                       |
| -------------------- | ---------------------- | ------------------------------------------------- |
| `submersible`        | Bomba submersa         | Electric submersible pump.                        |
| `vertical_turbine`   | Bomba de eixo vertical | Surface motor with line shaft.                    |
| `jet`                | Bomba injetora         | Surface jet pump.                                 |
| `progressive_cavity` | Bomba helicoidal       | Progressive cavity pump, common with solar power. |
| `hand_pump`          | Bomba manual           |                                                   |
| `compressor_airlift` | Compressor (air-lift)  | Permanent airlift production.                     |

Solar is a `power_source`, never a `type`. Non-canonical values SHOULD use the `x-` prefix.

## `pump_installations[].power_source` — Recommended values _(since v2.3)_

| Value    | Portuguese (BR)      |
| -------- | -------------------- |
| `grid`   | Rede elétrica        |
| `solar`  | Solar (fotovoltaico) |
| `diesel` | Gerador a diesel     |
| `hybrid` | Híbrido              |

## `permits[].type` — Recommended values _(since v2.3)_

| Value                | Portuguese (BR)                        | Description                         |
| -------------------- | -------------------------------------- | ----------------------------------- |
| `abstraction_permit` | Outorga de direito de uso              | Grant to abstract groundwater.      |
| `preliminary_permit` | Outorga prévia / declaração de reserva | Permission before drilling.         |
| `exemption`          | Dispensa / uso insignificante          | Formal exemption for small users.   |
| `registration`       | Cadastro (e.g. CNARH)                  | Registration without a grant.       |
| `dewatering_permit`  | Outorga para rebaixamento              | Mining and construction dewatering. |
| `drilling_permit`    | Autorização de perfuração              | Authorization to drill the well.    |

`renewal` is not a type: a renewal is a new permit of the same type whose `supersedes` points to the previous one. Non-canonical values SHOULD use the `x-` prefix.

## `permits[].water_use` — Recommended values _(since v2.3)_

| Value          | Portuguese (BR)                        |
| -------------- | -------------------------------------- |
| `human_supply` | Abastecimento público / consumo humano |
| `industrial`   | Industrial                             |
| `mining`       | Mineração                              |
| `irrigation`   | Irrigação                              |
| `livestock`    | Dessedentação animal                   |
| `commercial`   | Comercial / serviços                   |

`water_use` describes what the abstracted water is for; `well_purpose` describes the well's role.

## `permits[].conditions[].category` — Recommended values _(since v2.3)_

| Value                    | Portuguese (BR)            | Covers                                                                     |
| ------------------------ | -------------------------- | -------------------------------------------------------------------------- |
| `monitoring`             | Monitoramento              | Water level, flow, abstracted volume and water quality monitoring/sampling |
| `reporting`              | Relatórios e declarações   | Periodic reports and volume/flow declarations submitted to the authority   |
| `equipment_installation` | Instalação de equipamentos | Meters (hidrômetro), level gauges, sampling taps, telemetry                |
| `well_protection`        | Proteção do poço           | Sanitary slab, seal, protection perimeter, wellhead closure                |
| `environmental`          | Ambiental                  | Environmental measures, compensation, licensing of the activity            |
| `legal`                  | Legal / administrativo     | Renewal request, fees, registrations, document submissions                 |

Non-canonical values SHOULD use the `x-` prefix.

## `permits[].history[].type` — Recommended values _(since v2.3)_

| Value          | Portuguese (BR)                  |
| -------------- | -------------------------------- |
| `filing`       | Protocolo / requerimento         |
| `process`      | Andamento do processo / despacho |
| `notification` | Notificação / ofício             |
| `fee`          | Taxa / emolumento                |
| `inspection`   | Vistoria                         |
| `decision`     | Decisão / publicação             |
| `renewal`      | Renovação                        |

Non-canonical values SHOULD use the `x-` prefix. The administrative `status` of a permit is a closed vocabulary; see object-schemas.md § `permits[]` — Administrative status.

## `meters[].type` — Recommended values _(since v2.3)_

| Value             | Portuguese (BR)         |
| ----------------- | ----------------------- |
| `mechanical`      | Hidrômetro mecânico     |
| `electromagnetic` | Medidor eletromagnético |
| `ultrasonic`      | Medidor ultrassônico    |

Non-canonical values SHOULD use the `x-` prefix.

## `production[]` — Recommended values _(since v2.3)_

**`type`** — the entry discriminator: `meter_reading` (a totalizer register value) or `estimated_volume` (a volume estimated for a period, without a meter). Non-canonical entry types SHOULD use the `x-` prefix; parsers preserve them and exclude them from volume derivations.

**`source`** (`meter_reading`):

| Value       | Portuguese (BR) |
| ----------- | --------------- |
| `manual`    | Leitura manual  |
| `telemetry` | Telemetria      |

**`method`** (`estimated_volume`) — the basis of the estimate. Descriptive only: it never changes how the volume is counted.

| Value            | Portuguese (BR)           | Description                                                        |
| ---------------- | ------------------------- | ------------------------------------------------------------------ |
| `flow_time`      | Vazão × tempo de operação | Flow rate times operating time (hour meter, operating regime).     |
| `energy`         | Consumo de energia        | Derived from the pump's energy consumption.                        |
| `user_statement` | Informado pelo usuário    | Stated by the owner or operator, without a documented calculation. |

## `water_samples[]` — Recommended values _(since v2.3)_

Recommended values for `sample_type`, `sampling_method`, `sampling_point.type` and `sampling_point.device` are listed in [water-quality.md](water-quality.md) § Recommended values.

## `hydrodynamic_events[].measurement_method` — Recommended values

Used by `spot_measurement` and `logger_series` _(since v2.4)_ events.

| Value                 | English             | Portuguese (BR)       |
| --------------------- | ------------------- | --------------------- |
| `electric_probe`      | Electric probe      | Sonda elétrica        |
| `pressure_transducer` | Pressure transducer | Transdutor de pressão |
| `air_line`            | Air line            | Linha de ar           |
| `tape`                | Tape                | Trena                 |

Non-canonical values SHOULD use the `x-` prefix.

## `aquifer_analysis[].method` — Recommended values

| Value               | English           | Portuguese (BR) |
| ------------------- | ----------------- | --------------- |
| `cooper_jacob`      | Cooper-Jacob      | Cooper-Jacob    |
| `theis`             | Theis             | Theis           |
| `neuman`            | Neuman            | Neuman          |
| `hantush`           | Hantush           | Hantush         |
| `birsoy_summers`    | Birsoy-Summers    | Birsoy-Summers  |
| `eden_hazel`        | Eden-Hazel        | Eden-Hazel      |
| `visual_inspection` | Visual inspection | Inspeção visual |

Non-canonical values SHOULD use the `x-` prefix.

## `history_logs[].category` — Recommended values

| Value           | Portuguese (BR)     | Category-specific fields                                              |
| --------------- | ------------------- | --------------------------------------------------------------------- |
| `maintenance`   | Manutenção          | `maintenance_type`, `pump_installation_id`, `meter_id` _(since v2.3)_ |
| `inspection`    | Inspeção            | —                                                                     |
| `incident`      | Incidente           | —                                                                     |
| `event`         | Evento              | —                                                                     |
| `status_change` | Mudança de situação | `status` _(since v2.3)_                                               |

Descriptions are in object-schemas.md § `history_logs[]`. Category-specific fields MUST be absent on entries of other categories; their presence emits a warning. Non-canonical values SHOULD use the `x-` prefix.

## `history_logs[].severity` — Recommended values

| Value      | English  | Portuguese (BR) |
| ---------- | -------- | --------------- |
| `low`      | Low      | Baixa           |
| `medium`   | Medium   | Média           |
| `high`     | High     | Alta            |
| `critical` | Critical | Crítica         |

Non-canonical values SHOULD use the `x-` prefix.

## `history_logs[].maintenance_type` — Recommended values _(since v2.3)_

| Value               | Portuguese (BR)             |
| ------------------- | --------------------------- |
| `inspection`        | Inspeção                    |
| `cleaning`          | Limpeza                     |
| `redevelopment`     | Redesenvolvimento           |
| `disinfection`      | Desinfecção                 |
| `pump_service`      | Manutenção da bomba         |
| `meter_calibration` | Aferição do hidrômetro      |
| `video_inspection`  | Filmagem / perfilagem ótica |
| `level_measurement` | Medição de nível            |
| `pump_test`         | Teste de bombeamento        |
| `water_sampling`    | Coleta de água              |

Non-canonical values SHOULD use the `x-` prefix.

## `history_logs[].status` — Allowed values _(since v2.3)_

Used by entries of category `status_change`. This is a **closed vocabulary**: `status` MUST be one of the five values below. Any other value, including an `x-` value, is a schema error and the file is rejected.

| Value            | Portuguese (BR)        | Semantics                               |
| ---------------- | ---------------------- | --------------------------------------- |
| `active`         | Ativo / em operação    | Normal operation.                       |
| `maintenance`    | Em manutenção          | Temporarily out of service for work.    |
| `inactive`       | Paralisado             | Out of service, recoverable.            |
| `decommissioned` | Desativado / tamponado | Permanently closed and properly sealed. |
| `abandoned`      | Abandonado             | Left without proper sealing.            |

The well's current status is the `status` of the `status_change` entry with the latest `datetime`; with no such entry, the status is unknown.

## `Attachment.document_type` — Recommended values _(since v2.3)_

| Value                | Portuguese (BR)                             | Typical location                      |
| -------------------- | ------------------------------------------- | ------------------------------------- |
| `drilling_report`    | Relatório de perfuração / relatório técnico | Root                                  |
| `as_built_drawing`   | Perfil construtivo as-built                 | Root                                  |
| `registry_record`    | Ficha cadastral (SIAGAS, CNARH)             | Root                                  |
| `photo`              | Fotografia                                  | Any                                   |
| `permit_document`    | Portaria / certificado de outorga           | `permits`                             |
| `condition_evidence` | Comprovante de cumprimento de condicionante | `permits[].conditions[].fulfillments` |
| `pump_curve`         | Curva da bomba                              | `pump_installations`                  |
| `field_sheet`        | Planilha de campo                           | `hydrodynamic_events`                 |
| `test_report`        | Relatório de teste de bombeamento           | `aquifer_analysis`                    |
| `lab_report`         | Laudo laboratorial                          | `water_samples`                       |
| `invoice`            | Nota fiscal                                 | Any                                   |

The vocabulary is open; non-canonical values SHOULD use the `x-` prefix.

---

## `well_id`

Array of authority-scoped identifiers linking the well to external registries. A well may be registered in multiple national, regional, or institutional registries simultaneously.

| Field       | Type    | Required | Description                                                                       |
| ----------- | ------- | -------- | --------------------------------------------------------------------------------- |
| `authority` | string  | yes      | Name of the issuing registry or institution (e.g. `"SIAGAS"`, `"ANA"`, `"NGWD"`). |
| `id`        | string  | yes      | The identifier as issued by the authority.                                        |
| `primary`   | boolean | no       | Marks the canonical identifier. At most one entry may have `primary: true`.       |

Producers SHOULD mark exactly one entry `primary: true`. The rule "the first entry is canonical" applies only as a fallback when no entry is marked, because it is fragile when the order changes. Parsers MUST warn when multiple entries have `primary: true`.

### Numeric ID conversion

All `id` values are strings. When the source identifier from an external system is an integer, the string representation MUST be the canonical base-10 representation with no leading zeros, no thousands separator, and no locale-specific formatting. The integer `42` becomes `"42"`, not `"042"` or `"42,"`.

When the source identifier is a fixed-width string with significant leading zeros (e.g. `"00042819"` from a registry where width carries meaning), the original string MUST be preserved verbatim. Composite identifiers containing significant leading zeros in their numeric portion (e.g. SIAGAS `"SP-0042819"`) MUST be preserved as-is.

### Uniqueness

The combination `(authority, id)` MUST be unique within the `well_id` array. See § Cross-reference and uniqueness rules for the duplicate-handling policy.

```json
"well_id": [
  { "authority": "SIAGAS", "id": "SP-0042819", "primary": true },
  { "authority": "ANA",    "id": "02000.001234/2006-78" },
  { "authority": "utility-internal", "id": "PP-01" }
]
```

---

## `location`

Geographic position and elevation of the wellhead. Supersedes the v1 top-level `lat`, `lng`, and `elevation` fields.

The three primary measurements — `lat`, `lng`, `elevation` — are top-level fields on the location object for ergonomics. All ancillary metadata (datum, CRS, precision, source CRS) lives under a nested `properties` object.

| Field        | Type                 | Required | Description                                                                                                            |
| ------------ | -------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `lat`        | number               | yes      | Latitude in decimal degrees.                                                                                           |
| `lng`        | number               | yes      | Longitude in decimal degrees.                                                                                          |
| `elevation`  | number               | no       | Wellhead elevation in meters above the WGS84 reference ellipsoid (or the datum named in `properties.elevation_datum`). |
| `properties` | `LocationProperties` | no       | Ancillary metadata. When absent, all defaults apply.                                                                   |

### `LocationProperties`

| Field                 | Type   | Required | Description                                                                                                                                                       |
| --------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `elevation_datum`     | string | no       | Reference datum for `elevation`. See vocabulary below. Default: `wgs84_ellipsoid`.                                                                                |
| `crs`                 | string | no       | EPSG code of the coordinate reference system. Must be a geographic (not projected) CRS. Default: `"EPSG:4326"` (WGS84).                                           |
| `lat_precision`       | number | no       | One-sigma precision of `lat` in decimal degrees.                                                                                                                  |
| `lng_precision`       | number | no       | One-sigma precision of `lng` in decimal degrees.                                                                                                                  |
| `elevation_precision` | number | no       | One-sigma precision of `elevation` in meters.                                                                                                                     |
| `original_crs`        | string | no       | EPSG code of the source CRS, preserved for traceability when source data was in a projected CRS that the converter transformed to geographic. Informational only. |
| `timezone`            | string | no       | IANA time zone of the well site (e.g. `America/Belem`). A value that is not a valid IANA name is malformed. _(since v2.4)_                                        |

### `elevation_datum` — Recommended values

| Value             | Description                                                                                                                                  |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `wgs84_ellipsoid` | WGS84 reference ellipsoidal height. Default.                                                                                                 |
| `egm2008`         | Earth Gravitational Model 2008 geoid                                                                                                         |
| `egm96`           | Earth Gravitational Model 1996 geoid                                                                                                         |
| `local_msl`       | Local mean sea level (imprecise; specific datum SHOULD be named via `x-` prefix, e.g. `x-imbituba` for Brazil's national vertical reference) |

When `elevation_datum` is omitted, parsers MUST assume `wgs84_ellipsoid`.

### CRS scope

Only geographic coordinate reference systems are permitted in `properties.crs`. Projected CRS values (e.g. UTM zones) are not valid. If source data uses a projected CRS, the converting application MUST transform to geographic coordinates before writing the file. The `original_crs` field MAY be populated with the source CRS for traceability.

```json
"location": {
  "lat": -1.4558,
  "lng": -48.5039,
  "elevation": 12.5,
  "properties": {
    "elevation_datum": "wgs84_ellipsoid",
    "crs": "EPSG:4326",
    "lat_precision": 0.0001,
    "lng_precision": 0.0001,
    "elevation_precision": 0.5,
    "original_crs": "EPSG:31983"
  }
}
```

---

## Units

All numeric values in a `.well` file are in **SI**. The format does not encode unit declarations; the units below are the single, canonical interpretation for every field of the corresponding kind. No file may override these.

### Canonical units

| Quantity                 | Unit                                               | UCUM                                           | Stored as                                |
| ------------------------ | -------------------------------------------------- | ---------------------------------------------- | ---------------------------------------- |
| Depth, length, elevation | meter                                              | `m`                                            | number                                   |
| Diameter                 | millimeter                                         | `mm`                                           | number                                   |
| Volumetric flow rate     | cubic meter per hour                               | `m3/h`                                         | number                                   |
| Elapsed time, duration   | minute                                             | `min`                                          | number                                   |
| Daily operating time     | hour                                               | `h`                                            | number (above 24 read as 24)             |
| Volume                   | cubic meter                                        | `m3`                                           | number                                   |
| Power                    | kilowatt                                           | `kW`                                           | number                                   |
| Voltage                  | volt                                               | `V`                                            | number                                   |
| Cross-sectional area     | square millimeter                                  | `mm2`                                          | number                                   |
| Mass concentration       | milligram per liter                                | `mg/L`                                         | number _(since v2.3)_                    |
| Electrical conductivity  | microsiemens per centimeter at 25 °C               | `uS/cm`                                        | number _(since v2.3)_                    |
| Temperature              | degree Celsius                                     | `Cel`                                          | number _(since v2.3)_                    |
| Redox potential          | millivolt                                          | `mV`                                           | number _(since v2.3)_                    |
| Turbidity                | NTU, FNU, FAU, FTU (by parameter code)             | —                                              | number _(since v2.3)_                    |
| Color                    | Hazen unit (uH = mg Pt-Co/L)                       | —                                              | number _(since v2.3)_                    |
| Microbiological count    | MPN/100 mL, CFU/100 mL, CFU/mL (by parameter code) | `{MPN}/(100.mL)`, `{CFU}/(100.mL)`, `{CFU}/mL` | number _(since v2.3)_                    |
| Activity concentration   | becquerel per liter                                | `Bq/L`                                         | number _(since v2.3)_                    |
| Filter pore size         | micrometer                                         | `um`                                           | number _(since v2.3)_                    |
| Transmissivity           | square meter per second                            | `m2/s`                                         | number                                   |
| Hydraulic conductivity   | meter per second                                   | `m/s`                                          | number                                   |
| Pressure                 | kilopascal                                         | `kPa`                                          | number                                   |
| Angle (azimuth, dip)     | degree                                             | `deg`                                          | number (0–360 for azimuth, 0–90 for dip) |
| Geographic coordinates   | decimal degree (WGS84)                             | `deg`                                          | number                                   |
| Calendar date            | ISO 8601                                           | —                                              | string `YYYY-MM-DD`                      |
| Instant                  | RFC 3339 with UTC offset                           | —                                              | string                                   |

UCUM is the **Unified Code for Units of Measure**, the international machine-parseable unit standard used by OGC SWE and the scientific community. The UCUM column above documents the canonical encoding of each unit for use in JSON-LD contexts, profile schemas, and downstream interoperability — it is not encoded in `.well` files themselves.

### Field-to-unit binding (normative)

**Meter (`m`)** — all depths, lengths, and elevations:

- `well_depth`
- `bore_hole[].from`, `bore_hole[].to`
- `well_case[].from`, `well_case[].to`
- `reduction[].from`, `reduction[].to`
- `well_screen[].from`, `well_screen[].to`
- `surface_case[].from`, `surface_case[].to`
- `hole_fill[].from`, `hole_fill[].to`
- `centralizers[].from`, `centralizers[].to`, `centralizers[].spacing`
- `cement_pad.width`, `cement_pad.length`, `cement_pad.thickness`
- `lithology[].from`, `lithology[].to`
- `fractures[].depth`, `fractures[].depth_precision`
- `caves[].from`, `caves[].to`
- `hydrodynamic_events[].static_level`, `static_level_precision`
- `PumpingStep.readings[].depth`, `depth_precision`
- `RecoveryPhase.readings[].depth`, `depth_precision`
- `logger_series.sensor_depth`, `readings[].depth`, `depth_precision`, `depth_min`, `depth_max` _(since v2.4)_
- `aquifer_analysis[].static_level`, `static_level_precision`
- `aquifer_analysis[].dynamic_level`, `dynamic_level_precision`
- `aquifer_analysis[].aquifer_thickness`
- `location.elevation`, `location.properties.elevation_precision`
- `pump_installations[].intake_depth`, `rated_head`, `electrical.cable_length` _(since v2.3)_
- `water_samples[].sampling_point.depth`, `depth_precision`, `from`, `to` _(since v2.3)_

**Millimeter (`mm`)** — all diameters and slot openings:

- `bore_hole[].diameter`
- `well_case[].diameter`
- `reduction[].diam_from`, `reduction[].diam_to`
- `well_screen[].diameter`, `well_screen[].screen_slot`
- `surface_case[].diameter`
- `hole_fill[].diameter`
- `centralizers[].diameter`
- `pump_installations[].riser_diameter` _(since v2.3)_
- `meters[].nominal_diameter` _(since v2.3)_

**Cubic meter per hour (`m3/h`)** — all volumetric flow rates:

- `PumpingStep.rate`, `rate_precision`
- `aquifer_analysis[].flow_rate`, `flow_rate_precision`
- `recovery_only.pumping_rate`
- `pump_installations[].rated_flow_rate` _(since v2.3)_
- `permits[].flow_rate`, `permits[].monthly_schedule[].flow_rate` _(since v2.3)_
- `operating_regime[].flow_rate` _(since v2.3)_
- `water_samples[].purge.flow_rate` _(since v2.3)_

**Minute (`min`)** — all elapsed times and durations:

- `PumpingStep.duration`
- `LevelReading.elapsed`
- `recovery_only.pumping_duration`
- `logger_series.interval` _(since v2.4)_
- `water_samples[].purge.duration`, `purge.readings[].elapsed` _(since v2.3)_

**Cubic meter (`m3`)** — volume _(since v2.3)_:

- `permits[].volume_limits[].volume`
- `meters[].max_reading`
- `production[].reading` (`meter_reading`), `production[].volume` (`estimated_volume`)
- `water_samples[].purge.volume`

**Hour (`h`)** — daily operating time _(since v2.3)_:

- `permits[].daily_operating_time`, `permits[].monthly_schedule[].daily_operating_time`
- `operating_regime[].daily_operating_time`

The minute remains the canonical unit for elapsed time and durations. The hour is bound only to `daily_operating_time`, which regulators always express in hours.

**Square meter per second (`m2/s`)** — transmissivity:

- `aquifer_analysis[].transmissivity`

**Meter per second (`m/s`)** — hydraulic conductivity:

- `aquifer_analysis[].hydraulic_conductivity`

**Kilopascal (`kPa`)** — pressure:

- `LevelReading.pressure`

**Kilowatt (`kW`)** — power _(since v2.3)_:

- `pump_installations[].rated_power`

**Volt (`V`)** — voltage _(since v2.3)_:

- `pump_installations[].electrical.voltage`

**Square millimeter (`mm2`)** — cross-sectional area _(since v2.3)_:

- `pump_installations[].electrical.cable_section`

**Degree Celsius (`Cel`)** — temperature _(since v2.3)_:

- `water_samples[].laboratory.received_temperature`

**Micrometer (`um`)** — filter pore size _(since v2.3)_:

- `water_samples[].results[].filtration.pore_size`

**Unit by parameter code** _(since v2.3)_ — `water_samples[].results[].value`, `detection_limit`, `quantification_limit`, `value_precision` and `purge.readings[].value` are in the canonical unit of the result's parameter (see water-quality.md § Units).

**Degree (`deg`)** — angles and geographic coordinates:

- `fractures[].azimuth`, `fractures[].dip`
- `location.lat`, `location.lng`, `location.properties.lat_precision`, `location.properties.lng_precision`

**Unitless** — dimensionless or domain-specific values:

- `aquifer_analysis[].storativity` (dimensionless)
- `aquifer_analysis[].jacob_b`, `jacob_c` (composite units; treated as the units required to make the standard Jacob equation balance with stored `flow_rate` and `length`)
- `aquifer_analysis[].well_efficiency_pct` (percentage, 0–100)
- `aquifer_analysis[].specific_capacity` (derived ratio in m³/h per m, i.e. `m2/h`)
- Lithology `color` (CSS hex string)
- `pump_installations[].stages`, `electrical.phases` (counts)
- `permits[].monthly_schedule[].month`, `days`; `permits[].conditions[].occurrences` (counts)
- `operating_regime[].days_per_week` (count, 1–7)

### Water quality units _(since v2.3)_

Water quality results take their unit from the parameter code; only `x-` vocabulary codes declare `unit` (UCUM). The unit-by-code rule and regional unit normalization are specified in [water-quality.md](water-quality.md) § Units.

### Level sign convention

Depths are measured from ground level (0) and increase downward. Water levels above ground level are therefore **negative**. This applies to `static_level`, `LevelReading.depth`, and `aquifer_analysis[].static_level` / `dynamic_level`. A negative static level is how a flowing artesian condition is recorded (see § `well_type`). This convention was implicit in v2.0 and is made explicit in v2.1 without changing semantics. It does not apply to `pump_installations[].intake_depth`, which is an equipment depth and is always positive.

### Diameter and the as-built convention

Diameters in casing, screens, surface case, and hole fill are stored as the **as-built outer diameter in millimeters**, not as nominal manufacturer designations. A casing sold as "6 inch" with a real outer diameter of 168.3 mm is recorded as `168.3`, not `152.4` (the literal conversion of 6 inches to mm). Nominal-to-actual mapping for common pipe and screen sizes is a market convention handled by applications — typically by the converter or input form — not by the file format.

### Screen slot

`well_screen[].screen_slot` is in millimeters like every other diameter field. US-market slot-number designations (e.g. "20 slot" = 0.020 inch = 0.508 mm) are an input convenience handled by applications, not encoded in the file. The v1 field name `screen_slot_mm` was a legacy artifact and is renamed to `screen_slot` in v2; the value is in millimeters before and after.

### Rationale

An interchange format with configurable units multiplies the number of valid encodings of the same well, complicates equality and comparison, and introduces a class of bugs where the declared units do not match the stored values. The `.well` format is designed to be a canonical machine representation: one well, one encoding. Display units, input units, and locale-specific notation are concerns of the applications that read and write `.well` files, not of the format itself. This separation matches the design of GeoJSON (WGS84 only), RFC 3339 (UTC offsets always present), and most modern interchange formats.

Producers receiving non-SI source data (imperial drilling reports, US gpm flow measurements, inch casing designations, slot-number screens) MUST convert to SI before writing. Consumers presenting the data to users in non-SI units MUST convert on read.

Conversion utilities for the common transformations are provided in `@welldot/core` under the `units` module — m ↔ ft, mm ↔ in, m³/h ↔ L/s, m³/h ↔ US gpm, m²/s ↔ m²/d, DD ↔ DMS, slot-number ↔ mm, cv/hp ↔ kW, L / ft³ / US gal ↔ m³, µg/L ↔ mg/L, mS/m ↔ µS/cm, and similar.

---

## Water quality parameter vocabulary _(since v2.3)_

The `welldot` parameter vocabulary (98 codes), its rules, the CAS equivalences and the treatment of limit sets are specified in [water-quality.md](water-quality.md) § Parameter vocabulary.

---

## `profiles`

An optional array of HTTPS URLs declaring formal extensions to the spec that the file conforms to. Each URL MUST resolve to a JSON Schema document.

```json
"profiles": [
  "https://welldot.org/profiles/brazil-ana/v1/schema.json",
  "https://inspire.ec.europa.eu/schemas/gwhyd/4.0/profile.json"
]
```

### Profile schema requirements

- Each URL MUST be an HTTPS URL resolving to a JSON Schema document (`Content-Type: application/schema+json` or `application/json`).
- The schema SHOULD extend the canonical `.well` v2 schema via `allOf` + `$ref`, but this is not required.
- The schema MAY link to human documentation via its `description` field or a custom `x-documentation` field pointing to a Markdown or PDF URL.
- Profiles MAY impose additional required fields, constrain vocabulary values, or mandate the use of specific `x-` extensions for a regulatory context.

### Example: a regulatory water quality profile _(since v2.3)_

See [water-quality.md](water-quality.md) § Regulatory profiles.

### Profile validation

- If a profile URL is unreachable, returns a non-JSON document, or fails to parse as JSON Schema, the profile is silently ignored. Parsers MUST NOT reject files whose profile URLs are unavailable.
- A profile-aware parser SHOULD validate the file against each reachable profile schema and surface failures as **warnings**, not errors. Conformance is asserted by the author, not enforced by the spec.
- Profile URLs SHOULD be versioned via path segments or schema-internal `$id` to ensure stability.

---

## Extensibility

### Custom fields — `x-` prefix

Any implementer may add custom fields to any object by prefixing the field name with `x-`. This convention is established by OpenAPI 3.x and JSON Schema. Parsers MUST preserve and ignore `x-` fields they do not recognize. Sub-properties within an `x-` object do not need to be prefixed. For application extensions, `x-<vendor>-<name>` is RECOMMENDED (e.g. `x-welldot-custom`), so tools that both use `x-custom` do not collide. _(since v2.4)_

```json
{
  "id": "b2c3d4e5-...",
  "type": "constant_rate",
  "datetime": "2006-03-14T08:00:00-03:00",
  "x-siagas": {
    "registro": "SP-0042819",
    "processo_ana": "02000.001234/2006-78"
  }
}
```

Fields without the `x-` prefix that are not defined in this spec are technically non-conformant. Parsers MUST NOT reject such files but SHOULD emit a warning.

### Custom top-level blocks — `x-` prefix required

Top-level blocks not defined in this spec MUST use the `x-` prefix. For application extensions, `x-<vendor>-<name>` is RECOMMENDED (e.g. `x-welldot-custom`), so tools that both use `x-custom` do not collide. _(since v2.4)_ Parsers MUST preserve and ignore unrecognized top-level keys.

```json
{
  "version": "2.4",
  "x-gas_monitoring": [ ... ],
  "x-geophysical_logs": [ ... ]
}
```

### Custom vocabulary values — `x-` prefix

Open vocabulary fields in this spec (`type` in `hydrodynamic_events`, `category` in `history_logs`, `vocabulary` in `texture` and in water quality `parameter` (as `x-…` vocabularies), `method` in `aquifer_analysis`, `well_type`, and any other field documented as accepting any string; not closed vocabularies such as `history_logs[].status`) SHOULD use the `x-` prefix when the value is non-canonical — i.e. not listed in the recommended vocabulary of this spec.

Parsers MUST treat `x-` prefixed vocabulary values as valid. Promotion from `x-` form to canonical form follows the Deprecation Policy (see § Deprecation Policy — Vocabulary value promotion).

```json
{ "type": "x-slug_test" }
{ "category": "x-site_visit" }
{ "method": "x-theis_recovery" }
```

---

## Offline packaging _(since v2.4)_

A `.well` file references its attachments by absolute URL, and HTTPS links may expire. For regulators and long-term archiving, a `.well` file MAY be delivered as an offline package: a ZIP archive with the extension `.wellz`.

- The `.well` file sits at the archive root, and the attachments sit at relative paths inside the archive.
- In this mode an `Attachment.uri` MAY be a relative path to the file inside the archive, and `sha256` is required.
- Outside a package, `uri` stays an absolute URL. A relative `uri` in a bare `.well` file is not valid.

The package is a delivery wrapper, not a second format: the `.well` file inside it is an ordinary `.well` file. Validators and parsers read the `.well` alone, so the schema keeps `uri` as a URL; resolving relative paths and checking `sha256` is the job of the tool that opens the package.

---

## Cross-reference and Uniqueness Rules

The `.well` format uses string IDs to link records across arrays. This section is the single normative source for ID semantics.

### Uniqueness scope

Each ID-bearing array maintains its **own uniqueness scope**. The ID namespaces are independent:

- `hydrodynamic_events[].id` — unique within `hydrodynamic_events`
- `aquifer_analysis[].id` — unique within `aquifer_analysis`
- `history_logs[].id` — unique within `history_logs`
- `pump_installations[].id` — unique within `pump_installations` _(since v2.3)_
- `permits[].id` — unique within `permits` _(since v2.3)_
- `permits[].conditions[].id` — unique within the `conditions` array of one permit _(since v2.3)_
- `permits[].conditions[].fulfillments[].id` — unique within the `fulfillments` array of one condition _(since v2.3)_
- `permits[].history[].id` — unique within the `history` array of one permit _(since v2.3)_
- `permits[].monthly_schedule[].month` and `permits[].volume_limits[].period` — unique within one permit _(since v2.3)_
- `meters[].id` — unique within `meters` _(since v2.3)_
- `production[].id` — unique within `production` _(since v2.3)_
- `operating_regime[].id` — unique within `operating_regime` _(since v2.3)_. `operating_regime[].effective_from` is not unique: duplicates are a warning _(since v2.4)_
- `water_samples[].id` — unique within `water_samples` _(since v2.3)_
- `attachments[].id` — unique within its owning array: the root `attachments`, or the `attachments` array of one record (`history_logs`, `permits`, `permits[].history`, `permits[].conditions[].fulfillments`, `pump_installations`, `meters`, `hydrodynamic_events`, `aquifer_analysis`, `water_samples`). The same id may appear under different records.
- `well_id[]` — uniqueness is on the composite key `(authority, id)`, not on `id` alone

An ID value MAY repeat across different arrays without conflict (e.g. an event and an analysis MAY both use the ID `"001"`), though distinct values are recommended for clarity.

### Cross-array references

The following fields hold references to IDs in other arrays:

| Reference field                                       | Points to                  | Resolution scope |
| ----------------------------------------------------- | -------------------------- | ---------------- |
| `aquifer_analysis[].source_event_ids[]`               | `hydrodynamic_events[].id` | Same file only   |
| `aquifer_analysis[].static_level_source_id`           | `hydrodynamic_events[].id` | Same file only   |
| `hydrodynamic_events[].corrects`                      | `hydrodynamic_events[].id` | Same file only   |
| `production[].corrects`                               | `production[].id`          | Same file only   |
| `production[].meter_id`                               | `meters[].id`              | Same file only   |
| `permits[].supersedes`                                | `permits[].id`             | Same file only   |
| `history_logs[].pump_installation_id`                 | `pump_installations[].id`  | Same file only   |
| `history_logs[].meter_id`                             | `meters[].id`              | Same file only   |
| `history_logs[].hydrodynamic_event_ids[]`             | `hydrodynamic_events[].id` | Same file only   |
| `history_logs[].sample_ids[]`                         | `water_samples[].id`       | Same file only   |
| `permits[].conditions[].fulfillments[].event_id`      | `hydrodynamic_events[].id` | Same file only   |
| `permits[].conditions[].fulfillments[].sample_id`     | `water_samples[].id`       | Same file only   |
| `water_samples[].corrects`                            | `water_samples[].id`       | Same file only   |
| `water_samples[].parent_sample_id`                    | `water_samples[].id`       | Same file only   |
| `water_samples[].static_level_event_id`               | `hydrodynamic_events[].id` | Same file only   |
| `water_samples[].sampling_point.pump_installation_id` | `pump_installations[].id`  | Same file only   |

Root `attachments` is not a registry: records never reference root attachments by id. Nor is it an aggregate: it holds only general files about the well as a whole (e.g. the drilling report), never copies of the attachments of `history_logs`, `permits` (including their `history` entries and condition `fulfillments`), `pump_installations`, `meters`, `hydrodynamic_events`, `aquifer_analysis` or `water_samples` entries. A document that concerns several records is repeated on each; `sha256` guarantees both copies point to the same file.

Cross-file references are not supported in v2.

### Dangling references

A **dangling reference** is a reference field whose value does not match any ID in the target array.

- Dangling references MUST emit a warning naming the referring field, the referring object's ID, and the missing target ID.
- Dangling references MUST NOT cause file rejection. Events may be legitimately deleted from history (regulatory retention rules, GDPR-style erasure) leaving analyses that reference them stranded.
- Consumers MUST preserve unresolved references when re-exporting and MUST NOT remove them silently. Removing a reference is always a deliberate user action, never a side effect of import or export. _(since v2.4)_

### Repeated records _(since v2.4)_

Collective permits and campaign blanks apply to several wells, so they are repeated in each well's file.

- Copies MUST share the same `id` and SHOULD have identical content.
- Consumers MAY merge copies by `id`.
- A fulfillment's `event_id` or `sample_id` resolves only in the file of the well that produced it. In the other copies it is an expected unresolved reference and emits no warning.

### Duplicate IDs within a scope

A **duplicate ID** occurs when two records in the same uniqueness scope share the same ID (or, for `well_id`, the same `(authority, id)` pair).

Duplicate IDs are **malformed but recoverable**:

- Parsers MUST NOT silently accept duplicate IDs. The file is considered malformed.
- Parsers MUST NOT silently rewrite duplicate IDs. Automatic renaming would change the object graph in a way that downstream references cannot detect.
- Interactive applications MUST surface the duplication to the user with sufficient context to decide:
  - The IDs in conflict
  - A summary of each conflicting record (datetime, type, key fields)
  - The choices: **merge** (keep one, discard the other), **rename** (assign a new ID to one of them, updating any references in the same file), or **abort load**.
- Non-interactive parsers (batch importers, server-side validators) MUST reject the file with a clear error rather than guess.
- Any user-confirmed resolution MUST be logged as a `history_logs` entry with `category: "event"` describing what was changed.

The objective is deterministic load behavior: a `.well` file MUST produce the same object graph across all conformant parsers under default settings. User-mediated repair is the only path that can deviate from this, and it must be explicit.

### `id` field convention

All `id` fields are `string` type. UUID v4 is recommended for new records. Sequential strings (e.g. `"evt-001"`) are valid for manually authored files. Numeric IDs from external systems are converted per the rule documented in § well_id (Numeric ID conversion).

---

## Precision and Uncertainty

Optional one-sigma precision qualifiers are defined for the most consequential measurement fields. Parsers that do not recognize them ignore them per the foreign-members rule.

The precision field name is the measurement field name suffixed with `_precision`. The unit of the precision value is the unit of the measurement it qualifies.

### Supported precision fields

| Measurement     | Precision field           | Defined on                            |
| --------------- | ------------------------- | ------------------------------------- |
| `lat`           | `lat_precision`           | `LocationProperties`                  |
| `lng`           | `lng_precision`           | `LocationProperties`                  |
| `elevation`     | `elevation_precision`     | `LocationProperties`                  |
| `static_level`  | `static_level_precision`  | events, `AquiferAnalysis`             |
| `dynamic_level` | `dynamic_level_precision` | `AquiferAnalysis`                     |
| `depth`         | `depth_precision`         | `LevelReading`, `Fracture`            |
| `rate`          | `rate_precision`          | `PumpingStep`                         |
| `flow_rate`     | `flow_rate_precision`     | `AquiferAnalysis`                     |
| `depth`         | `depth_precision`         | `SamplingPoint` _(since v2.3)_        |
| `value`         | `value_precision`         | water quality `Result` _(since v2.3)_ |

All precision fields are optional. When omitted, the measurement value carries no documented precision. Precision is the one-sigma standard deviation in the same unit as the measurement.

Laboratory reports usually give an expanded uncertainty U with a coverage factor k (typically k = 2). Converters store `value_precision = U / k`, never U itself.

```json
{ "depth": 44.8, "depth_precision": 0.01 }
```

---

_`.well` Format Specification v2.4_
