@welldot/core 0.4.0-next.20261015.d7c7365 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +59 -19
  2. package/dist/index.cjs +344 -178
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +9203 -5704
  5. package/dist/index.d.ts +9203 -5704
  6. package/dist/index.js +334 -178
  7. package/dist/index.js.map +1 -1
  8. package/docs/reference/fgdc-textures.md +15 -0
  9. package/docs/schema/v2/well.schema.json +128 -11
  10. package/docs/spec/v1/well-format.md +26 -0
  11. package/docs/spec/v2/format-reference.md +170 -45
  12. package/docs/spec/v2/interoperability.md +25 -4
  13. package/docs/spec/v2/object-schemas.md +243 -96
  14. package/docs/spec/v2/overview.md +92 -9
  15. package/docs/spec/v2/water-quality.md +26 -3
  16. package/examples/README.md +12 -0
  17. package/examples/belem-pa-condominio-outorga.well +2 -1
  18. package/examples/belem-pa-monitoramento-posto.well +2 -1
  19. package/examples/belem-pa-pirabas-abastecimento.well +2 -2
  20. package/examples/belem-pa-poco-colmatado.well +2 -1
  21. package/examples/belem-pa-poco-raso-abandonado.well +2 -1
  22. package/examples/belem-pa-qualidade-agua-acida.well +2 -1
  23. package/examples/colatina-es-gnaisse-rural.well +2 -2
  24. package/examples/coluna-mg-cristalino-abastecimento.well +2 -2
  25. package/examples/estrela-doeste-sp-bauru-serra-geral.well +2 -1
  26. package/examples/extremoz-rn-barreiras-raso.well +2 -1
  27. package/examples/gastao-vidigal-sp-dados-inconsistentes.well +2 -1
  28. package/examples/irece-ba-carste-bambui.well +2 -1
  29. package/examples/lagoa-santa-mg-carste-abastecimento.well +2 -2
  30. package/examples/minas-novas-mg-cadastro-incompleto.well +2 -1
  31. package/examples/quixeramobim-ce-cristalino-salobro.well +2 -2
  32. package/examples/rinopolis-sp-estratigrafico-guarani.well +2 -1
  33. package/examples/santarem-pa-jorrante-alter-do-chao.well +2 -1
  34. package/examples/sao-gabriel-rs-cacimba.well +2 -1
  35. package/examples/sete-lagoas-mg-carste-industrial.well +2 -1
  36. package/package.json +1 -1
@@ -1,14 +1,101 @@
1
- # `.well` File Format Specification — Version 2.3: Format Reference
1
+ # `.well` File Format Specification — Version 2.4: Format Reference
2
2
 
3
3
  **See also:** [overview.md](./overview.md) · [object-schemas.md](./object-schemas.md) · [interoperability.md](./interoperability.md) · [water-quality.md](./water-quality.md)
4
4
 
5
+ ## Overview
6
+
7
+ 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).
8
+
9
+ ## Table of contents
10
+
11
+ - [`.well` File Format Specification — Version 2.4: Format Reference](#well-file-format-specification--version-24-format-reference)
12
+ - [Overview](#overview)
13
+ - [Table of contents](#table-of-contents)
14
+ - [Top-level Structure](#top-level-structure)
15
+ - [Absent values _(since v2.4)_](#absent-values-since-v24)
16
+ - [Versioning](#versioning)
17
+ - [Parser version handling](#parser-version-handling)
18
+ - [Deprecation Policy](#deprecation-policy)
19
+ - [Field lifecycle](#field-lifecycle)
20
+ - [Parser behavior](#parser-behavior)
21
+ - [Vocabulary value promotion](#vocabulary-value-promotion)
22
+ - [Canonical deprecation registry](#canonical-deprecation-registry)
23
+ - [Top-level Fields](#top-level-fields)
24
+ - [Core identity](#core-identity)
25
+ - [v2 additions](#v2-additions)
26
+ - [v2.1 additions](#v21-additions)
27
+ - [v2.3 additions](#v23-additions)
28
+ - [Block kinds _(since v2.3)_](#block-kinds-since-v23)
29
+ - [Naming rules _(since v2.3)_](#naming-rules-since-v23)
30
+ - [Datetime Conventions](#datetime-conventions)
31
+ - [Instants known only by date _(since v2.3)_](#instants-known-only-by-date-since-v23)
32
+ - [Ordering and ties](#ordering-and-ties)
33
+ - [Recommended vocabularies](#recommended-vocabularies)
34
+ - [`well_type` — Recommended values](#well_type--recommended-values)
35
+ - [`well_purpose` — Recommended values _(since v2.1)_](#well_purpose--recommended-values-since-v21)
36
+ - [`bore_hole[].drilling_method` — Recommended values _(since v2.3)_](#bore_holedrilling_method--recommended-values-since-v23)
37
+ - [Construction materials — Recommended values _(since v2.3)_](#construction-materials--recommended-values-since-v23)
38
+ - [`well_screen[].slot_type` — Recommended values _(since v2.3)_](#well_screenslot_type--recommended-values-since-v23)
39
+ - [`centralizers[].type` — Recommended values _(since v2.1)_](#centralizerstype--recommended-values-since-v21)
40
+ - [`cement_pad.type` — Recommended values _(since v2.3)_](#cement_padtype--recommended-values-since-v23)
41
+ - [`pump_installations[].type` — Recommended values _(since v2.3)_](#pump_installationstype--recommended-values-since-v23)
42
+ - [`pump_installations[].power_source` — Recommended values _(since v2.3)_](#pump_installationspower_source--recommended-values-since-v23)
43
+ - [`permits[].type` — Recommended values _(since v2.3)_](#permitstype--recommended-values-since-v23)
44
+ - [`permits[].water_use` — Recommended values _(since v2.3)_](#permitswater_use--recommended-values-since-v23)
45
+ - [`permits[].conditions[].category` — Recommended values _(since v2.3)_](#permitsconditionscategory--recommended-values-since-v23)
46
+ - [`permits[].history[].type` — Recommended values _(since v2.3)_](#permitshistorytype--recommended-values-since-v23)
47
+ - [`meters[].type` — Recommended values _(since v2.3)_](#meterstype--recommended-values-since-v23)
48
+ - [`production[]` — Recommended values _(since v2.3)_](#production--recommended-values-since-v23)
49
+ - [`water_samples[]` — Recommended values _(since v2.3)_](#water_samples--recommended-values-since-v23)
50
+ - [`hydrodynamic_events[].measurement_method` — Recommended values](#hydrodynamic_eventsmeasurement_method--recommended-values)
51
+ - [`aquifer_analysis[].method` — Recommended values](#aquifer_analysismethod--recommended-values)
52
+ - [`history_logs[].category` — Recommended values](#history_logscategory--recommended-values)
53
+ - [`history_logs[].severity` — Recommended values](#history_logsseverity--recommended-values)
54
+ - [`history_logs[].maintenance_type` — Recommended values _(since v2.3)_](#history_logsmaintenance_type--recommended-values-since-v23)
55
+ - [`history_logs[].status` — Allowed values _(since v2.3)_](#history_logsstatus--allowed-values-since-v23)
56
+ - [`Attachment.document_type` — Recommended values _(since v2.3)_](#attachmentdocument_type--recommended-values-since-v23)
57
+ - [`well_id`](#well_id)
58
+ - [Numeric ID conversion](#numeric-id-conversion)
59
+ - [Uniqueness](#uniqueness)
60
+ - [`location`](#location)
61
+ - [`LocationProperties`](#locationproperties)
62
+ - [`elevation_datum` — Recommended values](#elevation_datum--recommended-values)
63
+ - [CRS scope](#crs-scope)
64
+ - [Units](#units)
65
+ - [Canonical units](#canonical-units)
66
+ - [Field-to-unit binding (normative)](#field-to-unit-binding-normative)
67
+ - [Water quality units _(since v2.3)_](#water-quality-units-since-v23)
68
+ - [Level sign convention](#level-sign-convention)
69
+ - [Diameter and the as-built convention](#diameter-and-the-as-built-convention)
70
+ - [Screen slot](#screen-slot)
71
+ - [Rationale](#rationale)
72
+ - [Water quality parameter vocabulary _(since v2.3)_](#water-quality-parameter-vocabulary-since-v23)
73
+ - [`profiles`](#profiles)
74
+ - [Profile schema requirements](#profile-schema-requirements)
75
+ - [Example: a regulatory water quality profile _(since v2.3)_](#example-a-regulatory-water-quality-profile-since-v23)
76
+ - [Profile validation](#profile-validation)
77
+ - [Extensibility](#extensibility)
78
+ - [Custom fields — `x-` prefix](#custom-fields--x--prefix)
79
+ - [Custom top-level blocks — `x-` prefix required](#custom-top-level-blocks--x--prefix-required)
80
+ - [Custom vocabulary values — `x-` prefix](#custom-vocabulary-values--x--prefix)
81
+ - [Offline packaging _(since v2.4)_](#offline-packaging-since-v24)
82
+ - [Cross-reference and Uniqueness Rules](#cross-reference-and-uniqueness-rules)
83
+ - [Uniqueness scope](#uniqueness-scope)
84
+ - [Cross-array references](#cross-array-references)
85
+ - [Dangling references](#dangling-references)
86
+ - [Repeated records _(since v2.4)_](#repeated-records-since-v24)
87
+ - [Duplicate IDs within a scope](#duplicate-ids-within-a-scope)
88
+ - [`id` field convention](#id-field-convention)
89
+ - [Precision and Uncertainty](#precision-and-uncertainty)
90
+ - [Supported precision fields](#supported-precision-fields)
91
+
5
92
  ---
6
93
 
7
94
  ## Top-level Structure
8
95
 
9
96
  ```json
10
97
  {
11
- "version": 2,
98
+ "version": "2.4",
12
99
  "@context": "https://welldot.org/context/v2.jsonld",
13
100
 
14
101
  "well_id": [ ... ],
@@ -51,6 +138,12 @@
51
138
  }
52
139
  ```
53
140
 
141
+ ### Absent values _(since v2.4)_
142
+
143
+ An optional field without a value is omitted, never written as `null`. A `null` in an optional field is malformed. Absent means unknown.
144
+
145
+ Readers accept `null` in `aquifer_analysis[].storativity` only in files whose `version` is the integer `2`, and treat it as absent.
146
+
54
147
  ---
55
148
 
56
149
  ## Versioning
@@ -59,14 +152,23 @@
59
152
  | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
60
153
  | `1` | Initial release — constructive and geologic data only |
61
154
  | `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. |
155
+ | `"2.4"` | Version written as the string `"M.m"` (_since v2.4_). Read as v2; the integer `2` means v2.0 to v2.3. |
62
156
 
63
- Minor revisions (`2.1`, `2.3`, …) are additive and do not change the `version` integer: a v2.3 document still 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.
157
+ 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.
64
158
 
65
159
  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.
66
160
 
161
+ _(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.
162
+
163
+ **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.
164
+
67
165
  ### Parser version handling
68
166
 
69
- The `version` field is an integer and must always be present.
167
+ 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+$`.
168
+
169
+ - 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.
170
+ - 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.
171
+ - Any minor of major `2` (`"2.4"`, a future `"2.9"`) is read as v2. Unknown members follow § Extensibility.
70
172
 
71
173
  - 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.
72
174
  - 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.
@@ -131,15 +233,15 @@ Each minor revision of this spec MUST include a "Deprecations" subsection in its
131
233
 
132
234
  ### Core identity
133
235
 
134
- | Field | Type | Required | Description |
135
- | ------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
136
- | `version` | integer | yes | Format version. Must be `2` for this spec. |
137
- | `well_type` | string | yes | Construction method of the well. See vocabulary below. |
138
- | `name` | string | no | Well name or local identifier. |
139
- | `well_driller` | string | no | Name of the drilling company or individual. |
140
- | `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. |
141
- | `obs` | string | no | Free-text observations about the well. |
142
- | `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. |
236
+ | Field | Type | Required | Description |
237
+ | ------------------- | ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
238
+ | `version` | integer \| string | yes | Format version. v2.4 files write `"2.4"`. |
239
+ | `well_type` | string | yes | Construction method of the well. See vocabulary below. |
240
+ | `name` | string | no | Well name or local identifier. |
241
+ | `well_driller` | string | no | Name of the drilling company or individual. |
242
+ | `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. |
243
+ | `obs` | string | no | Free-text observations about the well. |
244
+ | `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. |
143
245
 
144
246
  ### v2 additions
145
247
 
@@ -165,7 +267,7 @@ Each minor revision of this spec MUST include a "Deprecations" subsection in its
165
267
  | `pump_installations` | `PumpInstallation[]` | no | Pump installation history (installation block). See object-schemas.md § `pump_installations[]`. |
166
268
  | `permits` | `Permit[]` | no | Legal instruments governing abstraction (mutable record block). See object-schemas.md § `permits[]`. |
167
269
  | `meters` | `Meter[]` | no | Totalizer (hidrômetro) installation history (installation block). See object-schemas.md § `meters[]`. |
168
- | `production` | `ProductionEntry[]` | no | Append-only ledger of meter readings and declared volumes (ledger block). See object-schemas.md § `production[]`. |
270
+ | `production` | `ProductionEntry[]` | no | Ledger of meter readings and declared volumes (ledger block). See object-schemas.md § `production[]`. |
169
271
  | `operating_regime` | `OperatingRegime[]` | no | Declared operating regimes, each in force from `effective_from` (mutable record block). See object-schemas.md § `operating_regime[]`. |
170
272
  | `water_samples` | `WaterSample[]` | no | Water samples and their field and laboratory results (ledger block). See water-quality.md. |
171
273
 
@@ -173,11 +275,11 @@ Each minor revision of this spec MUST include a "Deprecations" subsection in its
173
275
 
174
276
  Every top-level array is one of three kinds. The kind decides how records are corrected.
175
277
 
176
- | Kind | Blocks | Correction | Edit tracking |
177
- | -------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------- | --------------------------------------- |
178
- | Ledger | `hydrodynamic_events`, `production`, `water_samples` | Append a new entry with `corrects` pointing to the retracted entry. Never edit in place. | None needed; the ledger is the history. |
179
- | Mutable record | `history_logs`, `permits`, `operating_regime` | Edit in place. | `updated_at` (instant) on the record. |
180
- | Installation | `pump_installations`, `meters` | Edit in place. | `updated_at` (instant) on the record. |
278
+ | Kind | Blocks | Correction | Edit tracking |
279
+ | -------------- | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
280
+ | 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. |
281
+ | Mutable record | `history_logs`, `permits`, `operating_regime` | Edit in place. | `updated_at` (instant) on the record. |
282
+ | Installation | `pump_installations`, `meters` | Edit in place. | `updated_at` (instant) on the record. |
181
283
 
182
284
  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.
183
285
 
@@ -204,7 +306,7 @@ Constructive and geologic arrays describe the well as built and are edited in pl
204
306
 
205
307
  The `.well` format distinguishes two kinds of temporal values:
206
308
 
207
- **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. The well site's timezone is not stored separately; calendar dates are sortable lexicographically and applications MUST NOT attempt to derive an instant from them.
309
+ **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.
208
310
 
209
311
  **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:
210
312
 
@@ -219,7 +321,7 @@ The `.well` format distinguishes two kinds of temporal values:
219
321
  - `operating_regime[].effective_from`, `updated_at` _(since v2.3)_
220
322
  - `water_samples[].datetime`, `laboratory.received_at`, `results[].analyzed_at`, `results[].validation.validated_at` _(since v2.3)_
221
323
 
222
- Validity and deadline checks compare calendar dates, never UTC instants. When an instant must be compared with a calendar date — for example a condition fulfillment's `datetime` against its `due_date` — the instant's local date is the date part of the string, in the offset it carries. Producers SHOULD therefore write such instants in the well site's local offset.
324
+ 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.
223
325
 
224
326
  Relative deadlines and recurrences are ISO 8601 date durations (`P90D`, `P6M`, `P1Y6M`); see object-schemas.md § Date duration.
225
327
 
@@ -465,7 +567,7 @@ Recommended values for `sample_type`, `sampling_method`, `sampling_point.type` a
465
567
 
466
568
  ## `hydrodynamic_events[].measurement_method` — Recommended values
467
569
 
468
- Used by `spot_measurement` events.
570
+ Used by `spot_measurement` and `logger_series` _(since v2.4)_ events.
469
571
 
470
572
  | Value | English | Portuguese (BR) |
471
573
  | --------------------- | ------------------- | --------------------- |
@@ -546,19 +648,19 @@ The well's current status is the `status` of the `status_change` entry with the
546
648
 
547
649
  ## `Attachment.document_type` — Recommended values _(since v2.3)_
548
650
 
549
- | Value | Portuguese (BR) | Typical location |
550
- | -------------------- | ------------------------------------------- | --------------------- |
551
- | `drilling_report` | Relatório de perfuração / relatório técnico | Root |
552
- | `as_built_drawing` | Perfil construtivo as-built | Root |
553
- | `registry_record` | Ficha cadastral (SIAGAS, CNARH) | Root |
554
- | `photo` | Fotografia | Any |
555
- | `permit_document` | Portaria / certificado de outorga | `permits` |
556
- | `condition_evidence` | Comprovante de cumprimento de condicionante | `history_logs` |
557
- | `pump_curve` | Curva da bomba | `pump_installations` |
558
- | `field_sheet` | Planilha de campo | `hydrodynamic_events` |
559
- | `test_report` | Relatório de teste de bombeamento | `aquifer_analysis` |
560
- | `lab_report` | Laudo laboratorial | `water_samples` |
561
- | `invoice` | Nota fiscal | Any |
651
+ | Value | Portuguese (BR) | Typical location |
652
+ | -------------------- | ------------------------------------------- | ------------------------------------- |
653
+ | `drilling_report` | Relatório de perfuração / relatório técnico | Root |
654
+ | `as_built_drawing` | Perfil construtivo as-built | Root |
655
+ | `registry_record` | Ficha cadastral (SIAGAS, CNARH) | Root |
656
+ | `photo` | Fotografia | Any |
657
+ | `permit_document` | Portaria / certificado de outorga | `permits` |
658
+ | `condition_evidence` | Comprovante de cumprimento de condicionante | `permits[].conditions[].fulfillments` |
659
+ | `pump_curve` | Curva da bomba | `pump_installations` |
660
+ | `field_sheet` | Planilha de campo | `hydrodynamic_events` |
661
+ | `test_report` | Relatório de teste de bombeamento | `aquifer_analysis` |
662
+ | `lab_report` | Laudo laboratorial | `water_samples` |
663
+ | `invoice` | Nota fiscal | Any |
562
664
 
563
665
  The vocabulary is open; non-canonical values SHOULD use the `x-` prefix.
564
666
 
@@ -574,7 +676,7 @@ Array of authority-scoped identifiers linking the well to external registries. A
574
676
  | `id` | string | yes | The identifier as issued by the authority. |
575
677
  | `primary` | boolean | no | Marks the canonical identifier. At most one entry may have `primary: true`. |
576
678
 
577
- When `primary` is omitted on all entries, the first entry is canonical. Parsers MUST warn when multiple entries have `primary: true`.
679
+ 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`.
578
680
 
579
681
  ### Numeric ID conversion
580
682
 
@@ -619,6 +721,7 @@ The three primary measurements — `lat`, `lng`, `elevation` — are top-level f
619
721
  | `lng_precision` | number | no | One-sigma precision of `lng` in decimal degrees. |
620
722
  | `elevation_precision` | number | no | One-sigma precision of `elevation` in meters. |
621
723
  | `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. |
724
+ | `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)_ |
622
725
 
623
726
  ### `elevation_datum` — Recommended values
624
727
 
@@ -665,7 +768,7 @@ All numeric values in a `.well` file are in **SI**. The format does not encode u
665
768
  | Diameter | millimeter | `mm` | number |
666
769
  | Volumetric flow rate | cubic meter per hour | `m3/h` | number |
667
770
  | Elapsed time, duration | minute | `min` | number |
668
- | Daily operating time | hour | `h` | number (0–24) |
771
+ | Daily operating time | hour | `h` | number (above 24 read as 24) |
669
772
  | Volume | cubic meter | `m3` | number |
670
773
  | Power | kilowatt | `kW` | number |
671
774
  | Voltage | volt | `V` | number |
@@ -708,6 +811,7 @@ UCUM is the **Unified Code for Units of Measure**, the international machine-par
708
811
  - `hydrodynamic_events[].static_level`, `static_level_precision`
709
812
  - `PumpingStep.readings[].depth`, `depth_precision`
710
813
  - `RecoveryPhase.readings[].depth`, `depth_precision`
814
+ - `logger_series.sensor_depth`, `readings[].depth`, `depth_precision`, `depth_min`, `depth_max` _(since v2.4)_
711
815
  - `aquifer_analysis[].static_level`, `static_level_precision`
712
816
  - `aquifer_analysis[].dynamic_level`, `dynamic_level_precision`
713
817
  - `aquifer_analysis[].aquifer_thickness`
@@ -742,6 +846,7 @@ UCUM is the **Unified Code for Units of Measure**, the international machine-par
742
846
  - `PumpingStep.duration`
743
847
  - `LevelReading.elapsed`
744
848
  - `recovery_only.pumping_duration`
849
+ - `logger_series.interval` _(since v2.4)_
745
850
  - `water_samples[].purge.duration`, `purge.readings[].elapsed` _(since v2.3)_
746
851
 
747
852
  **Cubic meter (`m3`)** — volume _(since v2.3)_:
@@ -874,7 +979,7 @@ See [water-quality.md](water-quality.md) § Regulatory profiles.
874
979
 
875
980
  ### Custom fields — `x-` prefix
876
981
 
877
- 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.
982
+ 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)_
878
983
 
879
984
  ```json
880
985
  {
@@ -892,11 +997,11 @@ Fields without the `x-` prefix that are not defined in this spec are technically
892
997
 
893
998
  ### Custom top-level blocks — `x-` prefix required
894
999
 
895
- Top-level blocks not defined in this spec MUST use the `x-` prefix. Parsers MUST preserve and ignore unrecognized top-level keys.
1000
+ 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.
896
1001
 
897
1002
  ```json
898
1003
  {
899
- "version": 2,
1004
+ "version": "2.4",
900
1005
  "x-gas_monitoring": [ ... ],
901
1006
  "x-geophysical_logs": [ ... ]
902
1007
  }
@@ -916,6 +1021,18 @@ Parsers MUST treat `x-` prefixed vocabulary values as valid. Promotion from `x-`
916
1021
 
917
1022
  ---
918
1023
 
1024
+ ## Offline packaging _(since v2.4)_
1025
+
1026
+ 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`.
1027
+
1028
+ - The `.well` file sits at the archive root, and the attachments sit at relative paths inside the archive.
1029
+ - In this mode an `Attachment.uri` MAY be a relative path to the file inside the archive, and `sha256` is required.
1030
+ - Outside a package, `uri` stays an absolute URL. A relative `uri` in a bare `.well` file is not valid.
1031
+
1032
+ 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.
1033
+
1034
+ ---
1035
+
919
1036
  ## Cross-reference and Uniqueness Rules
920
1037
 
921
1038
  The `.well` format uses string IDs to link records across arrays. This section is the single normative source for ID semantics.
@@ -935,9 +1052,9 @@ Each ID-bearing array maintains its **own uniqueness scope**. The ID namespaces
935
1052
  - `permits[].monthly_schedule[].month` and `permits[].volume_limits[].period` — unique within one permit _(since v2.3)_
936
1053
  - `meters[].id` — unique within `meters` _(since v2.3)_
937
1054
  - `production[].id` — unique within `production` _(since v2.3)_
938
- - `operating_regime[].id` — unique within `operating_regime`; `operating_regime[].effective_from` is also unique within the block _(since v2.3)_
1055
+ - `operating_regime[].id` — unique within `operating_regime` _(since v2.3)_. `operating_regime[].effective_from` is not unique: duplicates are a warning _(since v2.4)_
939
1056
  - `water_samples[].id` — unique within `water_samples` _(since v2.3)_
940
- - `attachments[].id` — unique within its owning array: the root `attachments`, or the `attachments` array of one record (`history_logs`, `permits`, `pump_installations`, `hydrodynamic_events`, `aquifer_analysis`, `water_samples`). The same id may appear under different records.
1057
+ - `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.
941
1058
  - `well_id[]` — uniqueness is on the composite key `(authority, id)`, not on `id` alone
942
1059
 
943
1060
  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.
@@ -965,7 +1082,7 @@ The following fields hold references to IDs in other arrays:
965
1082
  | `water_samples[].static_level_event_id` | `hydrodynamic_events[].id` | Same file only |
966
1083
  | `water_samples[].sampling_point.pump_installation_id` | `pump_installations[].id` | Same file only |
967
1084
 
968
- 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`, `pump_installations`, `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.
1085
+ 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.
969
1086
 
970
1087
  Cross-file references are not supported in v2.
971
1088
 
@@ -975,7 +1092,15 @@ A **dangling reference** is a reference field whose value does not match any ID
975
1092
 
976
1093
  - Dangling references MUST emit a warning naming the referring field, the referring object's ID, and the missing target ID.
977
1094
  - 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.
978
- - Applications SHOULD surface dangling references to the user as a data-integrity concern and offer to either (a) update the analysis to remove the reference, or (b) restore the missing event.
1095
+ - 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)_
1096
+
1097
+ ### Repeated records _(since v2.4)_
1098
+
1099
+ Collective permits and campaign blanks apply to several wells, so they are repeated in each well's file.
1100
+
1101
+ - Copies MUST share the same `id` and SHOULD have identical content.
1102
+ - Consumers MAY merge copies by `id`.
1103
+ - 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.
979
1104
 
980
1105
  ### Duplicate IDs within a scope
981
1106
 
@@ -1031,4 +1156,4 @@ Laboratory reports usually give an expanded uncertainty U with a coverage factor
1031
1156
 
1032
1157
  ---
1033
1158
 
1034
- _`.well` Format Specification v2.3_
1159
+ _`.well` Format Specification v2.4_
@@ -1,7 +1,28 @@
1
- # `.well` File Format Specification — Version 2.3: Interoperability
1
+ # `.well` File Format Specification — Version 2.4: Interoperability
2
2
 
3
3
  **See also:** [overview.md](./overview.md) · [format-reference.md](./format-reference.md) · [object-schemas.md](./object-schemas.md) · [water-quality.md](./water-quality.md)
4
4
 
5
+ ## Overview
6
+
7
+ This part of the `.well` v2.4 specification covers how `.well` connects to other standards and tools: the reserved JSON-LD `@context` and its publication plan, how the format maps onto the OGC GroundWaterML 2 (GWML2) model, and validating files against the published JSON Schema.
8
+
9
+ ## Table of contents
10
+
11
+ - [JSON-LD Context (Reserved)](#json-ld-context-reserved)
12
+ - [v2.0 parser requirements](#v20-parser-requirements)
13
+ - [Recommended usage](#recommended-usage)
14
+ - [Context publication plan](#context-publication-plan)
15
+ - [Versioning and stability](#versioning-and-stability)
16
+ - [Optional fallback](#optional-fallback)
17
+ - [Relationship to GWML2](#relationship-to-gwml2)
18
+ - [Authoritative references](#authoritative-references)
19
+ - [Scope correspondence](#scope-correspondence)
20
+ - [Conceptual alignment](#conceptual-alignment)
21
+ - [Class mapping (informative)](#class-mapping-informative)
22
+ - [Notes on the mapping](#notes-on-the-mapping)
23
+ - [Profiles for regulatory adoption](#profiles-for-regulatory-adoption)
24
+ - [Schema Validation](#schema-validation)
25
+
5
26
  ---
6
27
 
7
28
  ## JSON-LD Context (Reserved)
@@ -158,7 +179,7 @@ A complete, normative mapping will be published as a separate document once the
158
179
  ### Notes on the mapping
159
180
 
160
181
  - **Wells vs. boreholes in GWML2.** GWML2 distinguishes a `GW_Well` (the construction with hydrogeological purpose) from a `Borehole` (the physical hole). A single `.well` document conflates both since it describes one composite installation. A `.well → GWML2` converter must emit both features and link them; a `GWML2 → .well` converter must merge them.
161
- - **Aquifer tests in GWML2.** GWML2-AquiferTest uses TimeseriesML (OGC 15-042r2) for time-series readings and O&M's `OM_Observation` pattern for individual measurements. The `.well` event types (`spot_measurement`, `constant_rate`, `step_drawdown`, `airlift`, `recovery_only`) are pragmatic field-record categories with no direct GWML2 counterpart; a converter must decompose each into one or more `GW_AquiferTest` features with appropriate `OM_Observation` results.
182
+ - **Aquifer tests in GWML2.** GWML2-AquiferTest uses TimeseriesML (OGC 15-042r2) for time-series readings and O&M's `OM_Observation` pattern for individual measurements. The `.well` event types (`spot_measurement`, `constant_rate`, `step_drawdown`, `airlift`, `recovery_only` and, since v2.4, `logger_series`) are pragmatic field-record categories with no direct GWML2 counterpart; a converter must decompose each into one or more `GW_AquiferTest` features with appropriate `OM_Observation` results. A `logger_series` is not a test: a converter maps it to a TimeseriesML series of `OM_Observation` results on the well, without a `GW_AquiferTest`.
162
183
  - **Hydrogeological units.** `.well` stores `lithology[].geologic_unit` and `aquifer_unit` as free-text strings. In GWML2 these resolve to references to `GW_HydrogeologicalUnit` features, which in real GWML2 deployments are typically catalogued in national registries (e.g. French BDLISA, Canadian GIN). A `.well → GWML2` converter SHOULD resolve these strings to authoritative unit URIs when a national vocabulary is available; absent that, it emits inline `GW_HydrogeologicalUnit` features with `gml:name` set to the string value.
163
184
  - **Water samples as specimens.** A `water_samples` entry corresponds to an O&M `SF_Specimen` taken from the well (the sampled feature), with `datetime` as the sampling time and `sampling_point` as the sampling location along the well. Each result is an `OM_Measurement` whose observed property is the parameter (a CAS or `welldot` term URI), whose result is the value in the code's canonical unit, and whose procedure is `method`. GWML2-Constituent describes the constituents of a fluid body rather than individual analyses, so a converter maps `.well` results to O&M observations on the specimen and derives constituent statements only when needed. Censoring (`qualifier`), detection and quantification limits, `lab_flags` and `validation` have no direct GWML2 counterpart and travel as result quality metadata or `x-` extensions. Field QA/QC links (`parent_sample_id`), purge data and chain of custody are outside GWML2 scope. Limits and exceedances are never part of the file and have no mapping.
164
185
  - **History logs are outside GWML2 scope.** GWML2 models the well as a static feature and its observations as a time-series. Maintenance interventions, incidents, status changes (`status_change`), permit condition fulfillment, and operational events are not represented. The same holds for the v2.3 operational blocks (`permits`, `meters`, `production`, `operating_regime`): metered production is an abstraction record, not an aquifer observation. A converter SHOULD preserve `.well` `history_logs` in a GeoSciML observation event sequence or as an `x-` extension on the GWML2 side, but full lossless round-trip is not guaranteed.
@@ -184,7 +205,7 @@ Files MAY include a `$schema` field referencing this URL:
184
205
  ```json
185
206
  {
186
207
  "$schema": "https://welldot.org/schema/v2/well.schema.json",
187
- "version": 2,
208
+ "version": "2.4",
188
209
  ...
189
210
  }
190
211
  ```
@@ -193,4 +214,4 @@ The schema is generated from the Zod validators in `@welldot/core` to prevent dr
193
214
 
194
215
  ---
195
216
 
196
- _`.well` Format Specification v2.3_
217
+ _`.well` Format Specification v2.4_