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

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 (54) hide show
  1. package/README.md +288 -75
  2. package/dist/index.cjs +2342 -44
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +14060 -4206
  5. package/dist/index.d.ts +14060 -4206
  6. package/dist/index.js +2220 -43
  7. package/dist/index.js.map +1 -1
  8. package/docs/schema/v2/well.schema.json +1043 -17
  9. package/docs/spec/v2/format-reference.md +507 -41
  10. package/docs/spec/v2/interoperability.md +44 -27
  11. package/docs/spec/v2/object-schemas.md +983 -113
  12. package/docs/spec/v2/overview.md +122 -6
  13. package/docs/spec/v2/water-quality.md +483 -0
  14. package/examples/README.md +83 -0
  15. package/examples/belem-pa-condominio-outorga.well +961 -0
  16. package/examples/belem-pa-monitoramento-posto.well +1141 -0
  17. package/examples/belem-pa-pirabas-abastecimento.well +1751 -0
  18. package/examples/belem-pa-poco-colmatado.well +496 -0
  19. package/examples/belem-pa-poco-raso-abandonado.well +388 -0
  20. package/examples/belem-pa-qualidade-agua-acida.well +895 -0
  21. package/examples/colatina-es-gnaisse-rural.well +1047 -0
  22. package/examples/coluna-mg-cristalino-abastecimento.well +1437 -0
  23. package/examples/estrela-doeste-sp-bauru-serra-geral.well +919 -0
  24. package/examples/extremoz-rn-barreiras-raso.well +623 -0
  25. package/examples/gastao-vidigal-sp-dados-inconsistentes.well +222 -0
  26. package/examples/index.json +452 -0
  27. package/examples/irece-ba-carste-bambui.well +861 -0
  28. package/examples/lagoa-santa-mg-carste-abastecimento.well +1087 -0
  29. package/examples/minas-novas-mg-cadastro-incompleto.well +157 -0
  30. package/examples/quixeramobim-ce-cristalino-salobro.well +989 -0
  31. package/examples/rinopolis-sp-estratigrafico-guarani.well +287 -0
  32. package/examples/santarem-pa-jorrante-alter-do-chao.well +554 -0
  33. package/examples/sao-gabriel-rs-cacimba.well +360 -0
  34. package/examples/sete-lagoas-mg-carste-industrial.well +410 -0
  35. package/examples/thumbs/belem-pa-condominio-outorga.svg +1 -0
  36. package/examples/thumbs/belem-pa-monitoramento-posto.svg +1 -0
  37. package/examples/thumbs/belem-pa-pirabas-abastecimento.svg +1 -0
  38. package/examples/thumbs/belem-pa-poco-colmatado.svg +1 -0
  39. package/examples/thumbs/belem-pa-poco-raso-abandonado.svg +1 -0
  40. package/examples/thumbs/belem-pa-qualidade-agua-acida.svg +1 -0
  41. package/examples/thumbs/colatina-es-gnaisse-rural.svg +1 -0
  42. package/examples/thumbs/coluna-mg-cristalino-abastecimento.svg +1 -0
  43. package/examples/thumbs/estrela-doeste-sp-bauru-serra-geral.svg +1 -0
  44. package/examples/thumbs/extremoz-rn-barreiras-raso.svg +1 -0
  45. package/examples/thumbs/gastao-vidigal-sp-dados-inconsistentes.svg +1 -0
  46. package/examples/thumbs/irece-ba-carste-bambui.svg +1 -0
  47. package/examples/thumbs/lagoa-santa-mg-carste-abastecimento.svg +1 -0
  48. package/examples/thumbs/minas-novas-mg-cadastro-incompleto.svg +1 -0
  49. package/examples/thumbs/quixeramobim-ce-cristalino-salobro.svg +1 -0
  50. package/examples/thumbs/rinopolis-sp-estratigrafico-guarani.svg +1 -0
  51. package/examples/thumbs/santarem-pa-jorrante-alter-do-chao.svg +1 -0
  52. package/examples/thumbs/sao-gabriel-rs-cacimba.svg +1 -0
  53. package/examples/thumbs/sete-lagoas-mg-carste-industrial.svg +1 -0
  54. package/package.json +5 -3
@@ -1,6 +1,49 @@
1
- # `.well` File Format Specification — Version 2.1: Object Schemas
1
+ # `.well` File Format Specification — Version 2.3: Object Schemas
2
2
 
3
- **See also:** [overview.md](./overview.md) · [format-reference.md](./format-reference.md) · [interoperability.md](./interoperability.md)
3
+ **See also:** [overview.md](./overview.md) · [format-reference.md](./format-reference.md) · [interoperability.md](./interoperability.md) · [water-quality.md](./water-quality.md)
4
+
5
+ ---
6
+
7
+ ## Common Types _(since v2.3)_
8
+
9
+ ### `Attachment`
10
+
11
+ The `.well` format is not a file container. Attachments are referenced by URL. Since v2.3, `Attachment` is a common type used in several places.
12
+
13
+ | Field | Type | Required | Description |
14
+ | --------------- | ------ | -------- | ------------------------------------------------------------------------------------------ |
15
+ | `id` | string | yes | Unique within its owning `attachments` array. UUID v4 recommended. |
16
+ | `uri` | string | yes | Full HTTPS URL. Relative paths are not permitted. |
17
+ | `media_type` | string | yes | MIME type (e.g. `image/jpeg`, `application/pdf`). |
18
+ | `document_type` | string | no | What the document is. See format-reference.md § `Attachment.document_type`. _(since v2.3)_ |
19
+ | `filename` | string | no | Original filename for display. |
20
+ | `description` | string | no | Caption or content description. |
21
+ | `sha256` | string | no | SHA-256 hash of the file in lowercase hex. Consumers SHOULD validate after download. |
22
+
23
+ #### Where attachments are allowed
24
+
25
+ | Location | Purpose |
26
+ | ----------------------------------- | --------------------------------------------------------------------------- |
27
+ | Root `attachments[]` | Documents about the well as a whole, not tied to any record. _(since v2.3)_ |
28
+ | `history_logs[].attachments` | Supporting documents or photos of a log entry. |
29
+ | `permits[].attachments` | The legal document (portaria, certificate). _(since v2.3)_ |
30
+ | `pump_installations[].attachments` | Pump curves, invoices, photos. _(since v2.3)_ |
31
+ | `meters[].attachments` | Installation photos, invoices, certificates. _(since v2.3)_ |
32
+ | `hydrodynamic_events[].attachments` | Field sheets, logger exports. _(since v2.3)_ |
33
+ | `aquifer_analysis[].attachments` | Interpretation reports. _(since v2.3)_ |
34
+ | `water_samples[].attachments` | Laboratory reports (`lab_report`), field sheets, photos. _(since v2.3)_ |
35
+
36
+ An attachment belongs to the record it documents. A document that concerns several records is repeated on each; the repetition is one URI and one hash, and the hash guarantees both copies point to the same file. The root array is not a registry, and records do not 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`, `meters`, `hydrodynamic_events`, `aquifer_analysis` or `water_samples` entries.
37
+
38
+ `Attachment.id` is unique within its owning array: the root `attachments[]`, or the `attachments` array of one record. The same id may appear under different records.
39
+
40
+ #### URL resolvability
41
+
42
+ The `uri` field is a reference, not a guarantee. URLs may become unreachable over time; consumers MUST handle fetch failures gracefully and MUST NOT treat them as file-format errors. When `sha256` is present, consumers that successfully fetch the attachment MUST validate the hash and MUST reject content that fails validation. Producers SHOULD include `sha256` for any attachment intended for long-term preservation.
43
+
44
+ ### Date duration
45
+
46
+ Relative deadlines and recurrences (`permits[].conditions[].due_after`, `recurrence`) are ISO 8601 durations restricted to date components: `PnY`, `PnM`, `PnW`, `PnD` and their combinations, such as `P1Y6M`. At least one component is required. Time components (`T…`) are malformed. Durations are added to calendar dates, never to instants; see format-reference.md § Datetime Conventions.
4
47
 
5
48
  ---
6
49
 
@@ -10,12 +53,12 @@
10
53
 
11
54
  A drilled interval of the borehole. Multiple entries describe a telescoping borehole.
12
55
 
13
- | Field | Type | Required | Description |
14
- | ----------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
15
- | `from` | number | yes | Start depth in meters. |
16
- | `to` | number | yes | End depth in meters. |
17
- | `diameter` | number | yes | Borehole diameter in millimeters. |
18
- | `drilling_method` | string | no | Free text description of the method used (e.g. `rotary`, `percussion`, `cable_tool`, `auger`, `air_hammer`). These example values are common terms, not an enforced enumeration — any free text is valid. |
56
+ | Field | Type | Required | Description |
57
+ | ----------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------- |
58
+ | `from` | number | yes | Start depth in meters. |
59
+ | `to` | number | yes | End depth in meters. |
60
+ | `diameter` | number | yes | Borehole diameter in millimeters. |
61
+ | `drilling_method` | string | no | Drilling method. Open vocabulary: see [format-reference.md](format-reference.md) § `bore_hole[].drilling_method`. |
19
62
 
20
63
  ```json
21
64
  { "from": 0, "to": 80, "diameter": 250, "drilling_method": "rotary" }
@@ -27,12 +70,12 @@ A drilled interval of the borehole. Multiple entries describe a telescoping bore
27
70
 
28
71
  Steel or plastic casing installed inside the borehole.
29
72
 
30
- | Field | Type | Required | Description |
31
- | ---------- | ------ | -------- | ------------------------------------- |
32
- | `from` | number | yes | Start depth in meters. |
33
- | `to` | number | yes | End depth in meters. |
34
- | `type` | string | yes | Casing material. Free Text |
35
- | `diameter` | number | yes | Casing outer diameter in millimeters. |
73
+ | Field | Type | Required | Description |
74
+ | ---------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------- |
75
+ | `from` | number | yes | Start depth in meters. |
76
+ | `to` | number | yes | End depth in meters. |
77
+ | `type` | string | yes | Casing material. Open vocabulary: see [format-reference.md](format-reference.md) § Construction materials. |
78
+ | `diameter` | number | yes | Casing outer diameter in millimeters. |
36
79
 
37
80
  ---
38
81
 
@@ -40,13 +83,13 @@ Steel or plastic casing installed inside the borehole.
40
83
 
41
84
  A transition piece connecting two casing or screen sections of different diameters.
42
85
 
43
- | Field | Type | Required | Description |
44
- | ----------- | ------ | -------- | ------------------------------------------------ |
45
- | `from` | number | yes | Start depth in meters. |
46
- | `to` | number | yes | End depth in meters. |
47
- | `diam_from` | number | yes | Diameter at top in millimeters. |
48
- | `diam_to` | number | yes | Diameter at bottom in millimeters. |
49
- | `type` | string | yes | Reducer type material and description. Free Text |
86
+ | Field | Type | Required | Description |
87
+ | ----------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------- |
88
+ | `from` | number | yes | Start depth in meters. |
89
+ | `to` | number | yes | End depth in meters. |
90
+ | `diam_from` | number | yes | Diameter at top in millimeters. |
91
+ | `diam_to` | number | yes | Diameter at bottom in millimeters. |
92
+ | `type` | string | yes | Reducer material. Open vocabulary: see [format-reference.md](format-reference.md) § Construction materials. |
50
93
 
51
94
  ---
52
95
 
@@ -54,13 +97,14 @@ A transition piece connecting two casing or screen sections of different diamete
54
97
 
55
98
  Slotted or wire-wound screen section.
56
99
 
57
- | Field | Type | Required | Description |
58
- | ------------- | ------ | -------- | ------------------------------------------- |
59
- | `from` | number | yes | Start depth in meters. |
60
- | `to` | number | yes | End depth in meters. |
61
- | `type` | string | yes | Screen type/material description. Free text |
62
- | `diameter` | number | yes | Screen outer diameter in millimeters. |
63
- | `screen_slot` | number | yes | Slot opening size in millimeters. |
100
+ | Field | Type | Required | Description |
101
+ | ------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
102
+ | `from` | number | yes | Start depth in meters. |
103
+ | `to` | number | yes | End depth in meters. |
104
+ | `type` | string | yes | Screen material. Open vocabulary: see [format-reference.md](format-reference.md) § Construction materials. The screen design goes in `slot_type`. |
105
+ | `diameter` | number | yes | Screen outer diameter in millimeters. |
106
+ | `screen_slot` | number | yes | Slot opening size in millimeters. |
107
+ | `slot_type` | string | no | Screen design _(since v2.3)_. Open vocabulary: see [format-reference.md](format-reference.md) § `well_screen[].slot_type`. |
64
108
 
65
109
  > **v1 migration:** v1's `screen_slot_mm` field is renamed to `screen_slot` in v2. The value is in millimeters before and after — no conversion needed. See § Units for the rule that screen slot is always in millimeters regardless of any application's display preference.
66
110
 
@@ -96,14 +140,14 @@ Material placed in the annular space between casing and borehole wall.
96
140
 
97
141
  Centralizers clamped to a casing or screen string to keep it concentric in the borehole, so the gravel pack and annular seal have uniform thickness. Each entry describes a depth interval over which centralizers are installed at a regular spacing, which is how drilling reports usually give them.
98
142
 
99
- | Field | Type | Required | Description |
100
- | ------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------- |
101
- | `from` | number | yes | Start depth in meters (depth of the first centralizer). |
102
- | `to` | number | yes | End depth in meters (depth of the last centralizer). `from === to` denotes a single centralizer. |
103
- | `spacing` | number | no | Spacing between consecutive centralizers in meters. Must be positive. Omit when the spacing is unknown. |
104
- | `type` | string | yes | Centralizer type. Recommended: `spring_bow`, `rigid`, `semi_rigid`, `polymer`. Non-canonical values use `x-`. |
105
- | `diameter` | number | no | As-built outer diameter in millimeters. |
106
- | `description` | string | no | Free-text description (e.g. material, manufacturer). |
143
+ | Field | Type | Required | Description |
144
+ | ------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------- |
145
+ | `from` | number | yes | Start depth in meters (depth of the first centralizer). |
146
+ | `to` | number | yes | End depth in meters (depth of the last centralizer). `from === to` denotes a single centralizer. |
147
+ | `spacing` | number | no | Spacing between consecutive centralizers in meters. Must be positive. Omit when the spacing is unknown. |
148
+ | `type` | string | yes | Centralizer type. Open vocabulary: see [format-reference.md](format-reference.md) § `centralizers[].type`. |
149
+ | `diameter` | number | no | As-built outer diameter in millimeters. |
150
+ | `description` | string | no | Free-text description (e.g. material, manufacturer). |
107
151
 
108
152
  - The array is **optional**. v2.0 documents without it remain valid.
109
153
  - Individual positions are derived from `from`, `to`, and `spacing` (`from`, `from + spacing`, … up to `to`). The count is derived and MUST NOT be stored.
@@ -116,12 +160,12 @@ Centralizers clamped to a casing or screen string to keep it concentric in the b
116
160
 
117
161
  Concrete wellhead pad. **All dimensions are in meters**.
118
162
 
119
- | Field | Type | Required | Description |
120
- | ----------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
121
- | `type` | string | yes | Free text description of the pad, typically its material (e.g. `concrete`) but may also describe its shape (e.g. `circular`) or both. Not an enforced enumeration. |
122
- | `width` | number | yes | Width in meters. |
123
- | `thickness` | number | yes | Thickness in meters. |
124
- | `length` | number | yes | Length in meters. |
163
+ | Field | Type | Required | Description |
164
+ | ----------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
165
+ | `type` | string | yes | Pad material. Open vocabulary: see [format-reference.md](format-reference.md) § `cement_pad.type`; other free text (e.g. a shape such as `circular`) remains valid. |
166
+ | `width` | number | yes | Width in meters. |
167
+ | `thickness` | number | yes | Thickness in meters. |
168
+ | `length` | number | yes | Length in meters. |
125
169
 
126
170
  > Note: A typical residential cement pad has dimensions on the order of `1.0` meter. Applications presenting these values in non-metric units (e.g. feet for US users) must convert `cement_pad` dimensions along with all other length fields.
127
171
 
@@ -238,15 +282,26 @@ The `type` field accepts any string. Non-canonical values SHOULD use the `x-` pr
238
282
 
239
283
  Only `id`, `type`, and `datetime` are required. All others are optional for all types.
240
284
 
241
- | Field | Type | Required | Description |
242
- | ----------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------- |
243
- | `id` | string | yes | Unique within `hydrodynamic_events`. UUID v4 recommended. |
244
- | `type` | string | yes | Event type. |
245
- | `datetime` | string | yes | RFC 3339 datetime with mandatory UTC offset (e.g. `"2006-03-14T08:00:00-03:00"`). See § Datetime Conventions. |
246
- | `sequence` | integer | no | Tiebreaker for events sharing the same instant. Lower values sort first. |
247
- | `operator` | string | no | Person or company conducting the measurement or test. |
248
- | `equipment` | string | no | Equipment description. |
249
- | `notes` | string | no | Free-text observations. |
285
+ | Field | Type | Required | Description |
286
+ | ------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------- |
287
+ | `id` | string | yes | Unique within `hydrodynamic_events`. UUID v4 recommended. |
288
+ | `type` | string | yes | Event type. |
289
+ | `datetime` | string | yes | RFC 3339 datetime with mandatory UTC offset (e.g. `"2006-03-14T08:00:00-03:00"`). See § Datetime Conventions. |
290
+ | `sequence` | integer | no | Tiebreaker for events sharing the same instant. Lower values sort first. |
291
+ | `operator` | string | no | Person or company conducting the measurement or test. |
292
+ | `equipment` | string | no | Equipment description. |
293
+ | `notes` | string | no | Free-text observations. |
294
+ | `corrects` | string | no | `hydrodynamic_events[].id` of the event this one retracts. See below. _(since v2.3)_ |
295
+ | `attachments` | `Attachment[]` | no | Field sheets, logger exports. See § Attachment. _(since v2.3)_ |
296
+
297
+ ### Corrections _(since v2.3)_
298
+
299
+ `hydrodynamic_events` is a ledger: an erroneous event is never edited in place. The correction is a new event whose `corrects` holds the id of the retracted event.
300
+
301
+ - A retracted event stays in the file but is excluded from every derivation (current static level, analyses, charts).
302
+ - Chains are allowed (C corrects B, which corrected A); only the last uncorrected entry counts.
303
+ - A `corrects` cycle is malformed and emits a warning. A `corrects` value that does not resolve is a dangling reference.
304
+ - An `aquifer_analysis` whose `source_event_ids` or `static_level_source_id` points to a retracted event emits a warning naming both ids.
250
305
 
251
306
  ---
252
307
 
@@ -256,7 +311,7 @@ Only `id`, `type`, and `datetime` are required. All others are optional for all
256
311
  | ------------------------ | --------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
257
312
  | `static_level` | number | yes | Depth to water surface from ground level, in meters. Negative when the level is above ground (flowing artesian). See § Level sign convention. |
258
313
  | `static_level_precision` | number | no | One-sigma precision of `static_level`. |
259
- | `measurement_method` | string | no | Recommended: `electric_probe`, `pressure_transducer`, `air_line`, `tape`. |
314
+ | `measurement_method` | string | no | Open vocabulary: see [format-reference.md](format-reference.md) § `hydrodynamic_events[].measurement_method`. |
260
315
  | `steps` | `PumpingStep[]` | no | At most one step. For an informal brief pump observation during the visit — not a controlled test. Use `constant_rate` for a formal test. |
261
316
  | `recovery` | `RecoveryPhase` | no | Recovery after the optional pumping step. |
262
317
 
@@ -341,36 +396,37 @@ Static level is not reliably measurable during air-lift and SHOULD be omitted.
341
396
 
342
397
  An array of interpreted aquifer parameter sets. Multiple entries may coexist, representing different methods or analysts.
343
398
 
344
- | Field | Type | Required | Description |
345
- | ------------------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
346
- | `id` | string | yes | Unique within `aquifer_analysis`. |
347
- | `datetime` | string | yes | RFC 3339 datetime with mandatory UTC offset. |
348
- | `analyst` | string | no | Name of the hydrogeologist. |
349
- | `source_event_ids` | string[] | yes | IDs of source `hydrodynamic_events` from this same file. See § Cross-reference and Uniqueness Rules. |
350
- | `method` | string | no | See vocabulary below. |
351
- | `static_level` | number | no | Static level used as reference, in meters. |
352
- | `static_level_precision` | number | no | One-sigma precision of `static_level`. |
353
- | `static_level_source_id` | string | no | ID of the event from which `static_level` was taken. |
354
- | `dynamic_level` | number | no | Stabilized dynamic level in meters. |
355
- | `dynamic_level_precision` | number | no | One-sigma precision of `dynamic_level`. |
356
- | `flow_rate` | number | no | Flow rate associated with `dynamic_level`, in m³/h. |
357
- | `flow_rate_precision` | number | no | One-sigma precision of `flow_rate`. |
358
- | `max_flow_rate` | number | no | Maximum recommended sustained extraction rate in m³/h, as judged by the analyst from the source events. This is an interpretive recommendation, not the test rate. Distinct from `flow_rate`, which is the rate actually applied during the test that produced `dynamic_level`. |
359
- | `max_flow_rate_precision` | number | no | One-sigma precision of `max_flow_rate` in m³/h. |
360
- | `max_flow_rate_basis` | string | no | Free-text justification: safety factor applied, regulatory framework referenced (e.g. `"80% of test rate per ANA practice"`, `"limited by available drawdown to top of screen"`), or assumptions about long-term recharge. |
361
- | `specific_capacity` | number | no | `Q/s` in m³/h per m (i.e. m²/h). |
362
- | `transmissivity` | number | no | Aquifer transmissivity `T` in m²/s. |
363
- | `storativity` | number | no | Dimensionless storativity `S`. |
364
- | `hydraulic_conductivity` | number | no | Hydraulic conductivity `K` in m/s. Requires `aquifer_thickness`. |
365
- | `aquifer_thickness` | number | no | Saturated aquifer thickness in meters. |
366
- | `jacob_b` | number | no | Formation loss coefficient from Jacob's equation. |
367
- | `jacob_c` | number | no | Well loss coefficient from Jacob's equation. |
368
- | `well_efficiency_pct` | number | no | Well efficiency as a percentage. |
369
- | `notes` | string | no | Methodology notes, assumptions, data quality remarks. |
399
+ | Field | Type | Required | Description |
400
+ | ------------------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
401
+ | `id` | string | yes | Unique within `aquifer_analysis`. |
402
+ | `datetime` | string | yes | RFC 3339 datetime with mandatory UTC offset. |
403
+ | `analyst` | string | no | Name of the hydrogeologist. |
404
+ | `source_event_ids` | string[] | yes | IDs of source `hydrodynamic_events` from this same file. See § Cross-reference and Uniqueness Rules. |
405
+ | `method` | string | no | See vocabulary below. |
406
+ | `static_level` | number | no | Static level used as reference, in meters. |
407
+ | `static_level_precision` | number | no | One-sigma precision of `static_level`. |
408
+ | `static_level_source_id` | string | no | ID of the event from which `static_level` was taken. |
409
+ | `dynamic_level` | number | no | Stabilized dynamic level in meters. |
410
+ | `dynamic_level_precision` | number | no | One-sigma precision of `dynamic_level`. |
411
+ | `flow_rate` | number | no | Flow rate associated with `dynamic_level`, in m³/h. |
412
+ | `flow_rate_precision` | number | no | One-sigma precision of `flow_rate`. |
413
+ | `max_flow_rate` | number | no | Maximum recommended sustained extraction rate in m³/h, as judged by the analyst from the source events. This is an interpretive recommendation, not the test rate. Distinct from `flow_rate`, which is the rate actually applied during the test that produced `dynamic_level`. |
414
+ | `max_flow_rate_precision` | number | no | One-sigma precision of `max_flow_rate` in m³/h. |
415
+ | `max_flow_rate_basis` | string | no | Free-text justification: safety factor applied, regulatory framework referenced (e.g. `"80% of test rate per ANA practice"`, `"limited by available drawdown to top of screen"`), or assumptions about long-term recharge. |
416
+ | `specific_capacity` | number | no | `Q/s` in m³/h per m (i.e. m²/h). |
417
+ | `transmissivity` | number | no | Aquifer transmissivity `T` in m²/s. |
418
+ | `storativity` | number | no | Dimensionless storativity `S`. |
419
+ | `hydraulic_conductivity` | number | no | Hydraulic conductivity `K` in m/s. Requires `aquifer_thickness`. |
420
+ | `aquifer_thickness` | number | no | Saturated aquifer thickness in meters. |
421
+ | `jacob_b` | number | no | Formation loss coefficient from Jacob's equation. |
422
+ | `jacob_c` | number | no | Well loss coefficient from Jacob's equation. |
423
+ | `well_efficiency_pct` | number | no | Well efficiency as a percentage. |
424
+ | `attachments` | `Attachment[]` | no | Interpretation reports. See § Attachment. _(since v2.3)_ |
425
+ | `notes` | string | no | Methodology notes, assumptions, data quality remarks. |
370
426
 
371
427
  ### `method` — Recommended values
372
428
 
373
- `cooper_jacob`, `theis`, `neuman`, `hantush`, `birsoy_summers`, `eden_hazel`, `visual_inspection`. Non-canonical values SHOULD use the `x-` prefix.
429
+ `cooper_jacob`, `theis`, `neuman`, `hantush`, `birsoy_summers`, `eden_hazel`, `visual_inspection`; labels in [format-reference.md](format-reference.md) § `aquifer_analysis[].method`. Non-canonical values SHOULD use the `x-` prefix.
374
430
 
375
431
  ---
376
432
 
@@ -392,12 +448,22 @@ The following values are **never stored**. Applications compute them on demand.
392
448
 
393
449
  ## Querying Current State
394
450
 
395
- **Current static level (NE):** Filter all events where `static_level` is present, sort by `datetime` descending (UTC-normalized), take the first result.
451
+ **Current static level (NE):** Exclude retracted events (§ Corrections), filter the remaining events where `static_level` is present, sort by `datetime` descending (UTC-normalized), take the first result.
396
452
 
397
453
  **Current specific capacity:** Find the most recent `aquifer_analysis` with `specific_capacity` present.
398
454
 
399
455
  **Current transmissivity:** Find the most recent `aquifer_analysis` with `transmissivity` present.
400
456
 
457
+ **Recommended maximum flow:** Read the most recent `aquifer_analysis[].max_flow_rate`, with `max_flow_rate_basis` and `max_flow_rate_precision`.
458
+
459
+ **Current pump:** The `pump_installations` entry without `removed_at`. See § `pump_installations[]`.
460
+
461
+ **Current meter(s):** The `meters` entries without `removed_at`. More than one open meter is valid (secondary meters) but emits a warning. See § `meters[]`.
462
+
463
+ **Regime in force:** The `operating_regime` entry with the latest `effective_from` not after the instant of interest. Before the first entry, the regime is unknown. See § `operating_regime[]`.
464
+
465
+ **Current well status:** The `status` of the `history_logs` entry of category `status_change` with the latest `datetime`. With no `status_change` entry, the status is **unknown** — applications MUST NOT assume `active`. See § `history_logs[]` — `status_change`.
466
+
401
467
  ---
402
468
 
403
469
  ## `history_logs[]`
@@ -413,28 +479,30 @@ These timestamps may differ substantially: a maintenance intervention `datetime`
413
479
 
414
480
  ### Categories
415
481
 
416
- | `category` | Portuguese (BR) | Description |
417
- | --------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
418
- | `maintenance` | Manutenção | Physical intervention: pump replacement, casing repair, cleaning, redevelopment. |
419
- | `inspection` | Inspeção | Site visit without physical alteration: visual survey, camera inspection, sample collection. |
420
- | `incident` | Incidente | Unplanned event: partial collapse, contamination, prolonged drought, vandalism. |
421
- | `event` | Evento | Generic milestone: construction completion, commissioning, deactivation, reactivation, ownership transfer, rehabilitation, data-integrity repair. |
422
- | `change_of_use` | Mudança de uso | _(since v2.1)_ The well's purpose changed (e.g. production → monitoring). Update `well_purpose` to the new use and log the change here. |
482
+ | `category` | Portuguese (BR) | Description |
483
+ | --------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
484
+ | `maintenance` | Manutenção | Physical intervention or service task: pump replacement, casing repair, cleaning, redevelopment, meter calibration. Carries the category-specific fields below _(since v2.3)_. |
485
+ | `inspection` | Inspeção | Site visit without physical alteration: visual survey, camera inspection, sample collection. |
486
+ | `incident` | Incidente | Unplanned event: partial collapse, contamination, prolonged drought, vandalism. |
487
+ | `event` | Evento | Generic milestone: construction completion, commissioning, change of use, ownership transfer, rehabilitation, data-integrity repair. |
488
+ | `status_change` | Mudança de situação | _(since v2.3)_ The well's operating status changed (e.g. active → inactive). Carries the category-specific fields below. |
423
489
 
424
490
  Vocabulary is open. Non-canonical values SHOULD use the `x-` prefix.
425
491
 
426
492
  ### `HistoryLogEntry`
427
493
 
428
- | Field | Type | Required | Description |
429
- | ------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
430
- | `id` | string | yes | Unique within `history_logs`. |
431
- | `datetime` | string | yes | RFC 3339 datetime with mandatory UTC offset. When the logged event occurred. |
432
- | `updated_at` | string | no | RFC 3339 datetime with mandatory UTC offset. When this entry was most recently created or edited. When omitted, treated as equal to `datetime`. Producers SHOULD set this field whenever they create or modify an entry. |
433
- | `category` | string | yes | Event category. |
434
- | `description` | string | yes | Free-text account: work performed, findings, or incident narrative. |
435
- | `author` | string | no | Person or company responsible for the record. |
436
- | `severity` | string | no | Recommended: `low`, `medium`, `high`, `critical`. |
437
- | `attachments` | `Attachment[]` | no | Supporting documents or photos. |
494
+ | Field | Type | Required | Description |
495
+ | ------------------------ | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
496
+ | `id` | string | yes | Unique within `history_logs`. |
497
+ | `datetime` | string | yes | RFC 3339 datetime with mandatory UTC offset. When the logged event occurred. |
498
+ | `updated_at` | string | no | RFC 3339 datetime with mandatory UTC offset. When this entry was most recently created or edited. When omitted, treated as equal to `datetime`. Producers SHOULD set this field whenever they create or modify an entry. |
499
+ | `category` | string | yes | Event category. |
500
+ | `description` | string | yes | Free-text account: work performed, findings, or incident narrative. |
501
+ | `author` | string | no | Person or company responsible for the record. |
502
+ | `severity` | string | no | Open vocabulary: see [format-reference.md](format-reference.md) § `history_logs[].severity`. |
503
+ | `attachments` | `Attachment[]` | no | Supporting documents or photos. See § Attachment. |
504
+ | `hydrodynamic_event_ids` | string[] | no | _(since v2.3)_ `hydrodynamic_events[].id`s holding the data produced or observed by this entry. Valid on every category. See § Data links. |
505
+ | `sample_ids` | string[] | no | _(since v2.3)_ `water_samples[].id`s collected or concerned by this entry. Valid on every category. See § Data links. |
438
506
 
439
507
  ### `updated_at` semantics
440
508
 
@@ -443,22 +511,428 @@ Vocabulary is open. Non-canonical values SHOULD use the `x-` prefix.
443
511
  - When a producer modifies only the `id` (e.g. during duplicate-resolution), it SHOULD NOT update `updated_at`, since the substantive content of the entry has not changed.
444
512
  - The `updated_at` field is not retroactive: parsers reading a v1 or early-v2.0 file without `updated_at` MUST NOT synthesize one.
445
513
 
446
- ### `Attachment`
514
+ `Attachment` is a common type since v2.3; see § Common Types — `Attachment`.
447
515
 
448
- The `.well` format is not a file container. Attachments are referenced by URL.
516
+ ### Data links _(since v2.3)_
449
517
 
450
- | Field | Type | Required | Description |
451
- | ------------- | ------ | -------- | ------------------------------------------------------------------------------------ |
452
- | `id` | string | yes | Unique within the parent log entry's `attachments` array. |
453
- | `uri` | string | yes | Full HTTPS URL. Relative paths are not permitted. |
454
- | `media_type` | string | yes | MIME type (e.g. `image/jpeg`, `application/pdf`). |
455
- | `filename` | string | no | Original filename for display. |
456
- | `description` | string | no | Caption or content description. |
457
- | `sha256` | string | no | SHA-256 hash of the file in lowercase hex. Consumers SHOULD validate after download. |
518
+ A log entry records that something was done or observed; measured values belong in their own block and are referenced by id, never copied into the log. `hydrodynamic_event_ids` and `sample_ids` link an entry of any category to that data: a `level_measurement` maintenance points to its `spot_measurement` event, a `pump_test` to its `constant_rate` or `step_drawdown` event, a `water_sampling` task or an `inspection` visit to the samples it collected (a sample, its field duplicate and a blank are three ids), and an `incident` to the sample that revealed a contamination. The log keeps what the data block does not: crew, cost, invoices and the narrative of the task.
458
519
 
459
- ### URL resolvability
520
+ Both fields are arrays of distinct ids from this same file. An id that does not resolve emits a warning. A link to a ledger entry that was later retracted (`corrects`) is not rewritten; consumers resolve it to the entry in force when needed.
460
521
 
461
- The `uri` field is a reference, not a guarantee. URLs may become unreachable over time; consumers MUST handle fetch failures gracefully and MUST NOT treat them as file-format errors. When `sha256` is present, consumers that successfully fetch the attachment MUST validate the hash and MUST reject content that fails validation. Producers SHOULD include `sha256` for any attachment intended for long-term preservation.
522
+ ### Category-specific fields _(since v2.3)_
523
+
524
+ Category-specific fields MUST be absent on entries of other categories; their presence emits a warning. They are optional in the schema: a missing required category field (e.g. `maintenance_type` on a `maintenance` entry) surfaces as a warning, never a rejection.
525
+
526
+ Permit condition fulfillment is not a log category: it is recorded on the condition itself (see § `permits[]` — Condition fulfillment).
527
+
528
+ #### `maintenance`
529
+
530
+ | Field | Type | Required | Description |
531
+ | ---------------------- | ------ | -------- | ------------------------------------------------------------- |
532
+ | `maintenance_type` | string | yes | See format-reference.md § `history_logs[].maintenance_type`. |
533
+ | `pump_installation_id` | string | no | `pump_installations[].id` the task concerns. |
534
+ | `meter_id` | string | no | `meters[].id` the task concerns (e.g. a `meter_calibration`). |
535
+
536
+ The data a task produced is linked with `hydrodynamic_event_ids` / `sample_ids` (see § Data links), never copied into the log.
537
+
538
+ #### `status_change`
539
+
540
+ | Field | Type | Required | Description |
541
+ | -------- | ------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
542
+ | `status` | string (enum) | yes | One of the five values below (closed vocabulary; any other value is rejected). See format-reference.md § `history_logs[].status`. |
543
+
544
+ | Value | Portuguese (BR) | Semantics |
545
+ | ---------------- | ---------------------- | --------------------------------------- |
546
+ | `active` | Ativo / em operação | Normal operation. |
547
+ | `maintenance` | Em manutenção | Temporarily out of service for work. |
548
+ | `inactive` | Paralisado | Out of service, recoverable. |
549
+ | `decommissioned` | Desativado / tamponado | Permanently closed and properly sealed. |
550
+ | `abandoned` | Abandonado | Left without proper sealing. |
551
+
552
+ The current status is the `status` of the `status_change` entry with the latest `datetime`. With no such entry, the status is unknown. `status` is a closed vocabulary: the `x-` extension mechanism does not apply, and a file carrying any other value is rejected.
553
+
554
+ Any non-`status_change` entry dated after a `decommissioned` or `abandoned` status emits a warning. A stopped well is recorded with a `status_change`, never with an `operating_regime` entry whose `flow_rate` is `0`.
555
+
556
+ ---
557
+
558
+ ## `pump_installations[]` _(since v2.3)_
559
+
560
+ An installation block: each entry is one installation of a pump in the well, present from `installed_at` until `removed_at`. Entries are edited in place, and `updated_at` records the last edit. The current pump and its submergence are derived, never stored.
561
+
562
+ - `removed_at` earlier than or equal to `installed_at` is malformed and emits a warning.
563
+ - `installed_by` and `removed_by` name who did the work (person or company, free text). `removed_by` on an entry without `removed_at` carries no meaning and consumers ignore it.
564
+ - Each entry is one installation, not one piece of equipment. A unit pulled and reinstalled gets a new entry with the same `serial`.
565
+ - Overlapping open installations emit a warning, not an error. Standby pumps exist.
566
+
567
+ ### `PumpInstallation`
568
+
569
+ | Field | Type | Required | Unit | Description |
570
+ | ----------------- | ---------------- | -------- | ---- | --------------------------------------------------------------------------- |
571
+ | `id` | string | yes | | Unique within `pump_installations`. UUID v4 recommended. |
572
+ | `installed_at` | string (instant) | yes | | RFC 3339 instant when the pump entered service in this well. |
573
+ | `removed_at` | string (instant) | no | | When it left. Absent means currently installed. |
574
+ | `installed_by` | string | no | | Person or company that installed the pump. |
575
+ | `removed_by` | string | no | | Person or company that removed the pump. Only meaningful with `removed_at`. |
576
+ | `type` | string | yes | | See format-reference.md § `pump_installations[].type`. |
577
+ | `power_source` | string | no | | `grid`, `solar`, `diesel`, `hybrid`, `x-…` |
578
+ | `manufacturer` | string | no | | |
579
+ | `model` | string | no | | |
580
+ | `serial` | string | no | | Links reinstallations of the same unit. |
581
+ | `intake_depth` | number | no | m | Depth of the pump intake (crivo), from ground level. |
582
+ | `rated_flow_rate` | number | no | m³/h | Nameplate duty-point flow. |
583
+ | `rated_head` | number | no | m | Nameplate duty-point head. |
584
+ | `rated_power` | number | no | kW | Motor power. |
585
+ | `stages` | integer | no | | Number of stages. |
586
+ | `riser_diameter` | number | no | mm | Riser pipe (edutor), as-built outer diameter. |
587
+ | `riser_material` | string | no | | Open vocabulary: see format-reference.md § Construction materials. |
588
+ | `check_valve` | boolean | no | | Whether a check valve is installed. |
589
+ | `electrical` | `PumpElectrical` | no | | See below. |
590
+ | `notes` | string | no | | |
591
+ | `updated_at` | string (instant) | no | | Last edit of this record. |
592
+ | `attachments` | `Attachment[]` | no | | Pump curves, invoices, photos. See § Attachment. |
593
+
594
+ ### `PumpElectrical`
595
+
596
+ All fields optional.
597
+
598
+ | Field | Type | Unit |
599
+ | --------------- | ------- | ---------- |
600
+ | `voltage` | number | V |
601
+ | `phases` | integer | `1` or `3` |
602
+ | `cable_section` | number | mm² |
603
+ | `cable_length` | number | m |
604
+
605
+ ### Validation (warnings, never rejection)
606
+
607
+ - `intake_depth` greater than `well_depth`, or below the bottom of the deepest `bore_hole` interval.
608
+ - `intake_depth` inside a `well_screen` interval.
609
+ - More than one entry without `removed_at`.
610
+ - `removed_at` earlier than or equal to `installed_at`.
611
+
612
+ ### Derived values
613
+
614
+ - **Current pump:** the entry without `removed_at`; if all are removed, none.
615
+ - **Submergence:** `intake_depth − dynamic_level`, using the most recent applicable reading during pumping. A negative value means the intake is above the water level.
616
+ - **Time in service per unit:** sum of installation durations sharing a `serial`.
617
+
618
+ ### Rendering
619
+
620
+ Renderers draw the current pump ending at `intake_depth` and its riser from the surface. Earlier installations are not drawn by default.
621
+
622
+ ---
623
+
624
+ ## `permits[]` _(since v2.3)_
625
+
626
+ A mutable record block: each entry transcribes one legal instrument governing abstraction from the well (outorga, dispensa, cadastro), from its request on. Entries are edited in place, and `updated_at` records the last edit. The attached document is authoritative. The administrative `status` set by the authority is stored; the validity status and condition deadlines are always derived, never stored.
627
+
628
+ ### `Permit`
629
+
630
+ | Field | Type | Required | Unit | Description |
631
+ | ---------------------- | ---------------------- | -------- | ---- | ---------------------------------------------------------------------------- |
632
+ | `id` | string | yes | | Unique within `permits`. UUID v4 recommended. |
633
+ | `type` | string | yes | | See format-reference.md § `permits[].type`. |
634
+ | `authority` | string | yes | | Issuing body, e.g. `ANA`, `SEMAS-PA`. Same semantics as `well_id.authority`. |
635
+ | `identifier` | string | no | | Identifier of the granted instrument (portaria, license code), verbatim. |
636
+ | `request_identifier` | string | no | | Identifier of the request or administrative process (protocolo), verbatim. |
637
+ | `status` | string (enum) | no | | Administrative status. Closed vocabulary, see below. Absent means `granted`. |
638
+ | `issued_at` | string (date) | no | | Issue date. |
639
+ | `valid_from` | string (date) | no | | Absent means valid from `issued_at`. |
640
+ | `valid_until` | string (date) | no | | Absent means no fixed expiry. |
641
+ | `renewal_requested_at` | string (date) | no | | Date a renewal request was filed. |
642
+ | `water_use` | string[] | no | | See format-reference.md § `permits[].water_use`. |
643
+ | `flow_rate` | number | no | m³/h | Maximum granted flow. |
644
+ | `daily_operating_time` | number | no | h | Maximum granted daily operating time, 0–24. |
645
+ | `volume_limits` | `VolumeLimit[]` | no | | Only volumes stated in the document. |
646
+ | `monthly_schedule` | `MonthlyGrant[]` | no | | Month-by-month grant. |
647
+ | `conditions` | `PermitCondition[]` | no | | Obligations (condicionantes). |
648
+ | `history` | `PermitHistoryEntry[]` | no | | Administrative steps: filing, process, notifications, fees. |
649
+ | `supersedes` | string | no | | `permits[].id` of the instrument this one legally replaces. |
650
+ | `notes` | string | no | | |
651
+ | `updated_at` | string (instant) | no | | Last edit of this record. |
652
+ | `attachments` | `Attachment[]` | no | | The legal document. See § Attachment. |
653
+
654
+ `water_use` describes what the abstracted water is for. It is distinct from the top-level `well_purpose`, which describes the well's role.
655
+
656
+ A renewal is not a permit type: it is a new permit of the same type whose `supersedes` points to the previous one. `supersedes` expresses legal succession between two valid instruments and is not a correction mechanism.
657
+
658
+ Identifiers are free strings preserved verbatim, because agencies use diverse formats (numbers, letters, slashes). A permit that has only been requested has no `identifier` yet: it is identified by `request_identifier`. At least one of the two SHOULD be present.
659
+
660
+ #### Administrative status
661
+
662
+ `status` records what the authority decided, which dates alone cannot express. It is a closed vocabulary: the `x-` extension mechanism does not apply, and a file carrying any other value is rejected.
663
+
664
+ | Value | Portuguese (BR) | Semantics |
665
+ | ----------- | --------------- | --------------------------------------------------------------- |
666
+ | `requested` | Requerida | Filed and awaiting a decision. No grant yet. |
667
+ | `granted` | Concedida | Issued. The validity status is derived from the dates. Default. |
668
+ | `suspended` | Suspensa | Temporarily halted by the authority. |
669
+ | `revoked` | Revogada | Cancelled by the authority. |
670
+ | `denied` | Indeferida | The request was refused. |
671
+ | `withdrawn` | Cancelada | The request or permit was given up by the holder. |
672
+
673
+ The change itself (notice of suspension, decision) is recorded as a `history` step, with the document attached.
674
+
675
+ ### `PermitHistoryEntry`
676
+
677
+ | Field | Type | Required | Description |
678
+ | ------------- | ---------------- | -------- | ----------------------------------------------------------------------------------- |
679
+ | `id` | string | yes | Unique within the permit's `history`. UUID v4 recommended. |
680
+ | `date` | string (date) | yes | When the step happened. |
681
+ | `type` | string | no | See format-reference.md § `permits[].history[].type`. |
682
+ | `description` | string | yes | What happened: protocol, dispatch, notice, fee, inspection, decision. |
683
+ | `done` | boolean | no | For actionable steps (fee paid, notification answered). Absent means informational. |
684
+ | `due_date` | string (date) | no | Date by which an actionable step must be done. |
685
+ | `updated_at` | string (instant) | no | Last edit of this record. |
686
+ | `attachments` | `Attachment[]` | no | Notices, receipts, protocols. See § Attachment. |
687
+
688
+ A step whose `due_date` has passed and that is not `done` is past due. Applications SHOULD surface it.
689
+
690
+ ### `VolumeLimit`
691
+
692
+ | Field | Type | Required | Unit | Description |
693
+ | -------- | ------ | -------- | ---- | --------------------------------------------------------------- |
694
+ | `period` | string | yes | | `daily`, `monthly`, `annual`. Each period appears at most once. |
695
+ | `volume` | number | yes | m³ | |
696
+
697
+ Volumes implied by flow × time × days are derived and MUST NOT be stored here.
698
+
699
+ ### `MonthlyGrant`
700
+
701
+ | Field | Type | Required | Unit | Description |
702
+ | ---------------------- | ------- | -------- | ---- | --------------------------------------- |
703
+ | `month` | integer | yes | | 1–12, unique within the schedule. |
704
+ | `flow_rate` | number | no | m³/h | |
705
+ | `daily_operating_time` | number | no | h | 0–24. |
706
+ | `days` | integer | no | | Days of operation granted in the month. |
707
+
708
+ When `monthly_schedule` is present, a month absent from it has no abstraction granted. The top-level `flow_rate` and `daily_operating_time` hold the maximum across months; a monthly value above them emits a warning.
709
+
710
+ ### `PermitCondition`
711
+
712
+ | Field | Type | Required | Description |
713
+ | -------------- | ------------------------ | -------- | ---------------------------------------------------------------- |
714
+ | `id` | string | yes | Unique within the permit's `conditions` array. |
715
+ | `description` | string | yes | Text of the condition as written in the document. |
716
+ | `category` | string | no | See format-reference.md § `permits[].conditions[].category`. |
717
+ | `first_due` | string (date) | no | Explicit date of the first deadline. |
718
+ | `due_after` | string (duration) | no | First deadline relative to the permit's start date, e.g. `P90D`. |
719
+ | `recurrence` | string (duration) | no | Interval between deadlines, e.g. `P6M`. Absent means one-time. |
720
+ | `last_due` | string (date) | no | No deadline is generated after this date. |
721
+ | `occurrences` | integer | no | Maximum number of deadlines, counting the first. |
722
+ | `responsible` | string | no | Person or team accountable for meeting the obligation. |
723
+ | `fulfillments` | `ConditionFulfillment[]` | no | Deadlines met. See § Condition fulfillment. |
724
+
725
+ `first_due` and `due_after` are mutually exclusive; a condition carrying both is malformed and `first_due` wins. A condition with neither is undated: it is valid and is displayed, but generates no deadlines. Durations follow § Common Types — Date duration.
726
+
727
+ ### Deadline generation (normative)
728
+
729
+ Applications generate a condition's deadlines as follows.
730
+
731
+ 1. **Start date** of the permit: `valid_from`, else `issued_at`. Without either, `due_after` cannot be resolved and the condition is undated.
732
+ 2. **Anchor**: `first_due`, else start date + `due_after`.
733
+ 3. **Deadline n** (n = 0, 1, 2 …) = anchor + n × `recurrence`, always computed from the anchor, never from the previous deadline. Years and months are added first; when the resulting day does not exist in the target month, that month's last day is used. Weeks and days are then added. Without `recurrence`, only n = 0 exists.
734
+ 4. **Stop** when any limit is reached: `occurrences` deadlines generated; the date passes `last_due`; or the date passes the permit's effective end.
735
+ 5. **Effective end** of the permit: if another permit supersedes it, the day before the successor's start date; otherwise `valid_until`; while the status is `active_pending_renewal`, there is no end. With no end, applications generate deadlines up to a horizon of their choice.
736
+ 6. **Administrative status**: a `requested`, `denied` or `withdrawn` permit generates no deadlines. A `suspended` or `revoked` permit generates none after today; those already due remain.
737
+
738
+ Computing every deadline from the anchor prevents drift: a monthly obligation anchored on 31 January falls on 28 or 29 February and back on 31 March.
739
+
740
+ | Document wording | Encoding |
741
+ | -------------------------------------------- | ------------------------------------------------------ |
742
+ | Install a meter within 90 days | `due_after: "P90D"` |
743
+ | Semiannual report from issuance | `due_after: "P6M", recurrence: "P6M"` |
744
+ | Semiannual report by 31 Jan and 31 Jul | `first_due: "2027-01-31", recurrence: "P6M"` |
745
+ | Monthly level readings during the first year | `due_after: "P1M", recurrence: "P1M", occurrences: 12` |
746
+ | Annual water analysis | `due_after: "P1Y", recurrence: "P1Y"` |
747
+ | Request renewal 90 days before expiry | `first_due` set to that date by the author |
748
+
749
+ ### Condition fulfillment
750
+
751
+ Fulfillment is recorded in the condition's `fulfillments`. Each entry fulfills one deadline, identified by its `due_date`.
752
+
753
+ #### `ConditionFulfillment`
754
+
755
+ | Field | Type | Required | Description |
756
+ | ------------- | ---------------- | -------- | ---------------------------------------------------------------------------------- |
757
+ | `id` | string | yes | Unique within the condition's `fulfillments`. UUID v4 recommended. |
758
+ | `datetime` | string (instant) | yes | When the obligation was fulfilled, e.g. when a report was filed. |
759
+ | `due_date` | string (date) | no | The deadline fulfilled. Absent for undated conditions. |
760
+ | `description` | string | no | |
761
+ | `author` | string | no | Who fulfilled the obligation. |
762
+ | `event_id` | string | no | `hydrodynamic_events[].id` that satisfied the obligation, when applicable. |
763
+ | `sample_id` | string | no | `water_samples[].id` that satisfied the obligation, when applicable. |
764
+ | `updated_at` | string (instant) | no | Last edit of this record. |
765
+ | `attachments` | `Attachment[]` | no | Proof of submission, with `document_type: "condition_evidence"`. See § Attachment. |
766
+
767
+ A water-quality `monitoring` condition is fulfilled by pointing to the sample with `sample_id`.
768
+
769
+ Derived status of each deadline, evaluated on the local civil date at the well site:
770
+
771
+ - **fulfilled** — a fulfillment has its `due_date`. **Fulfilled late** when that fulfillment's local date (the date part of its `datetime`, in the offset it carries) is after `due_date`.
772
+ - **upcoming** — no match and today is on or before `due_date`.
773
+ - **overdue** — no match and today is after `due_date`.
774
+
775
+ An undated condition is fulfilled by an entry without `due_date`. A fulfillment whose `due_date` matches no generated deadline, a fulfillment without `due_date` on a dated condition, or an `event_id` / `sample_id` that does not resolve emits a warning. Conditions belong to their permit: when a permit is superseded, its deadlines stop at its effective end and the successor's conditions take over.
776
+
777
+ ### Permit status (derived)
778
+
779
+ Evaluated on the local civil date at the well site, in order:
780
+
781
+ 1. A stored `status` other than `granted` → that value (`requested`, `suspended`, `revoked`, `denied`, `withdrawn`).
782
+ 2. Another permit `supersedes` it → `superseded`.
783
+ 3. Today is before its start date → `not_yet_valid`.
784
+ 4. `valid_until` is absent, or today is on or before it → `active`.
785
+ 5. `renewal_requested_at` is present and on or before `valid_until` → `active_pending_renewal`.
786
+ 6. Otherwise → `expired`.
787
+
788
+ The lead time a renewal request requires varies by jurisdiction; it is evaluated by applications or regulatory profiles, not by the format.
789
+
790
+ ### Validation (warnings, never rejection)
791
+
792
+ - `valid_until` earlier than the start date.
793
+ - A `supersedes` cycle, or a `supersedes` reference that does not resolve.
794
+ - Two granted, non-superseded permits of the same `type` with overlapping validity.
795
+ - A `daily_operating_time` outside 0–24, on the permit or in `monthly_schedule`.
796
+ - A `monthly_schedule` value above the permit's top-level maximum.
797
+ - A duplicate `month`, `volume_limits` period, condition `id`, `history` `id` or fulfillment `id` within one permit.
798
+ - A condition with both `first_due` and `due_after`.
799
+ - A permit with neither `identifier` nor `request_identifier`, or a granted permit without `identifier`.
800
+ - A condition fulfillment that matches no deadline, or whose `event_id` / `sample_id` does not resolve.
801
+
802
+ A collective grant covering several wells is repeated in each well's file until cross-file references arrive in v3.
803
+
804
+ ---
805
+
806
+ ## `meters[]` _(since v2.3)_
807
+
808
+ An installation block: each entry is one installation of a totalizer (hidrômetro) in the well, present from `installed_at` until `removed_at`. Entries are edited in place, and `updated_at` records the last edit. A meter holds device facts only: every register value, including the installation and removal readings, lives in `production`. The installation-pattern rules of § `pump_installations[]` apply; overlapping open meters emit a warning, not an error, because secondary meters exist.
809
+
810
+ ### `Meter`
811
+
812
+ | Field | Type | Required | Unit | Description |
813
+ | ------------------ | ---------------- | -------- | ---- | ---------------------------------------------------------------------------- |
814
+ | `id` | string | yes | | Unique within `meters`. UUID v4 recommended. |
815
+ | `installed_at` | string (instant) | yes | | RFC 3339 instant when the meter entered service in this well. |
816
+ | `removed_at` | string (instant) | no | | When it left. Absent means currently installed. |
817
+ | `installed_by` | string | no | | Person or company that installed the meter. |
818
+ | `removed_by` | string | no | | Person or company that removed the meter. Only meaningful with `removed_at`. |
819
+ | `type` | string | no | | See format-reference.md § `meters[].type`. |
820
+ | `manufacturer` | string | no | | |
821
+ | `model` | string | no | | |
822
+ | `serial` | string | no | | Links reinstallations of the same unit. |
823
+ | `nominal_diameter` | number | no | mm | Nominal diameter (DN). |
824
+ | `max_reading` | number | no | m³ | Register capacity, used to detect rollover. Greater than 0. |
825
+ | `notes` | string | no | | |
826
+ | `updated_at` | string (instant) | no | | Last edit of this record. |
827
+ | `attachments` | `Attachment[]` | no | | Installation photos, invoices, certificates. See § Attachment. |
828
+
829
+ The register values at installation and removal are recorded as ordinary `meter_reading` entries in `production`, with `datetime` equal to `installed_at` or `removed_at`. Meter calibrations are `history_logs` entries of category `maintenance` with `maintenance_type: "meter_calibration"` and a `meter_id`.
830
+
831
+ ### Validation (warnings, never rejection)
832
+
833
+ - `removed_at` earlier than or equal to `installed_at`.
834
+ - More than one entry without `removed_at`.
835
+ - A `production` reading for this meter outside its installation window.
836
+
837
+ ---
838
+
839
+ ## `production[]` _(since v2.3)_
840
+
841
+ A ledger: the append-only record of water produced by the well. An erroneous entry is never edited in place; the correction is a new entry whose `corrects` holds the id of the retracted entry, following § `hydrodynamic_events[]` — Corrections (retracted entries stay in the file and are excluded from every derivation; chains are allowed; a cycle emits a warning). Entries are discriminated by `type`. Volumes are always derived, never stored as totals.
842
+
843
+ ### Common fields
844
+
845
+ | Field | Type | Required | Description |
846
+ | ---------- | ------- | -------- | -------------------------------------------------------------------------------------- |
847
+ | `id` | string | yes | Unique within `production`. UUID v4 recommended. |
848
+ | `type` | string | yes | `meter_reading` or `estimated_volume`. Non-canonical types SHOULD use the `x-` prefix. |
849
+ | `corrects` | string | no | `production[].id` of the entry this one retracts. |
850
+ | `sequence` | integer | no | Tie-breaker for identical instants, lower first. |
851
+ | `notes` | string | no | |
852
+
853
+ An entry of a known `type` that lacks its required fields is rejected. Entries of unknown (`x-`) types are preserved with their extra members and are excluded from volume derivations.
854
+
855
+ ### `meter_reading`
856
+
857
+ | Field | Type | Required | Unit | Description |
858
+ | ---------- | ---------------- | -------- | ---- | ---------------------------------------------------------------- |
859
+ | `datetime` | string (instant) | yes | | RFC 3339 instant of the reading. |
860
+ | `meter_id` | string | yes | | `meters[].id`. |
861
+ | `reading` | number | yes | m³ | Register value. Meters reading in liters are converted on input. |
862
+ | `source` | string | no | | `manual`, `telemetry`, `x-…` |
863
+
864
+ A totalizer value is cumulative, so telemetry needs no aggregation field: storing fewer points loses no volume. The producing application decides the density written to the file.
865
+
866
+ ### `estimated_volume`
867
+
868
+ A volume produced in a period, estimated without a meter (e.g. before a meter was installed, or while it was out of service).
869
+
870
+ | Field | Type | Required | Unit | Description |
871
+ | -------------- | ---------------- | -------- | ---- | ---------------------------------------------------------------------------------------- |
872
+ | `period_start` | string (instant) | yes | | Start of the declared period. |
873
+ | `period_end` | string (instant) | yes | | End of the declared period. Later than `period_start`. |
874
+ | `volume` | number | yes | m³ | Volume produced in the period. |
875
+ | `method` | string | no | | Basis of the estimate: `flow_time`, `energy`, `user_statement`, `x-…`. Descriptive only. |
876
+
877
+ ### Volume derivation (normative)
878
+
879
+ Corrected entries are ignored throughout. Readings of each meter are ordered by instant, then `sequence`.
880
+
881
+ 1. For consecutive readings r₁, r₂ of the same meter, if r₂ ≥ r₁ the volume is r₂ − r₁.
882
+ 2. If r₂ < r₁ and the meter has `max_reading`, the volume is (`max_reading` − r₁) + r₂ (rollover).
883
+ 3. If r₂ < r₁ and there is no `max_reading`, the interval is unknown and a warning is emitted. It is never negative.
884
+ 4. Volume is never computed across two different meters. When readings exist at the removal and installation instants, coverage is complete up to the removal and from the installation; the gap between them is unmetered and not counted. Without those readings, the volume between the two meters is unknown.
885
+ 5. Production before a meter's first reading is unknown, not zero.
886
+
887
+ ### Precedence
888
+
889
+ - An `estimated_volume` counts only for time not covered by meter readings, prorated linearly by the uncovered fraction of its period. Overlap emits a warning, and the meter wins. `method` plays no part in this rule.
890
+ - Volumes declared to a regulator (annual use declarations) are not production entries. They are the fulfillment of the permit's reporting condition (`permits[].conditions[].fulfillments`), with the declaration attached.
891
+
892
+ ### Derived values
893
+
894
+ Volume per period (day, month, year), prorated linearly by time across period boundaries; average flow over a period; compliance against `permits[].volume_limits` and `monthly_schedule`. None of these are stored.
895
+
896
+ ### Validation (warnings, never rejection)
897
+
898
+ - A reading outside its meter's installation window, or a `meter_id` that does not resolve.
899
+ - A decreasing reading on a meter without `max_reading` (unknown interval).
900
+ - An `estimated_volume` overlapping metered time.
901
+ - An `estimated_volume` whose `period_end` is not later than `period_start`.
902
+ - A `corrects` cycle, or a `corrects` reference that does not resolve.
903
+
904
+ ---
905
+
906
+ ## `operating_regime[]` _(since v2.3)_
907
+
908
+ A mutable record block: each entry declares how the well is intended to run from a given instant. Entries are edited in place, and `updated_at` records the last edit. A change of regime is a new entry; the entry with the latest `effective_from` not after a given instant is the regime in force. There is no end field.
909
+
910
+ ### `OperatingRegime`
911
+
912
+ | Field | Type | Required | Unit | Description |
913
+ | ---------------------- | ---------------- | -------- | ---- | ------------------------------------------------------ |
914
+ | `id` | string | yes | | Unique within `operating_regime`. |
915
+ | `effective_from` | string (instant) | yes | | When the regime takes effect. Unique within the block. |
916
+ | `flow_rate` | number | no | m³/h | |
917
+ | `daily_operating_time` | number | no | h | 0–24. |
918
+ | `days_per_week` | integer | no | | 1–7. |
919
+ | `notes` | string | no | | |
920
+ | `updated_at` | string (instant) | no | | Last edit of this record. |
921
+
922
+ - An absent field means unknown, never zero.
923
+ - A stopped well is recorded with a `history_logs` `status_change`, not a regime with `flow_rate: 0`.
924
+ - `daily_operating_time` outside 0–24 and `days_per_week` outside 1–7 (or not an integer) are schema errors.
925
+
926
+ ### Validation (warnings, never rejection)
927
+
928
+ - Two entries with the same `effective_from`.
929
+ - Regime values above those of the permit active at `effective_from` (`flow_rate`, `daily_operating_time`).
930
+
931
+ ---
932
+
933
+ ## `water_samples[]` _(since v2.3)_
934
+
935
+ A ledger of water samples, each with its field and laboratory results. The full schema — `WaterSample`, `SamplingPoint`, `Purge`, `PurgeReading`, `Laboratory`, `Result`, `Parameter`, `Filtration`, `Validation`, result rules, validation and derived values — is specified in [water-quality.md](water-quality.md).
462
936
 
463
937
  ---
464
938
 
@@ -497,15 +971,18 @@ The `uri` field is a reference, not a guarantee. URLs may become unreachable ove
497
971
  "bore_hole": [
498
972
  { "from": 0, "to": 80, "diameter": 250, "drilling_method": "rotary" }
499
973
  ],
500
- "well_case": [{ "from": 0, "to": 60, "type": "steel", "diameter": 200 }],
974
+ "well_case": [
975
+ { "from": 0, "to": 60, "type": "carbon_steel", "diameter": 200 }
976
+ ],
501
977
  "reduction": [],
502
978
  "well_screen": [
503
979
  {
504
980
  "from": 60,
505
981
  "to": 80,
506
- "type": "wire_wound",
982
+ "type": "stainless_steel",
507
983
  "diameter": 150,
508
- "screen_slot": 0.5
984
+ "screen_slot": 0.5,
985
+ "slot_type": "continuous_slot"
509
986
  }
510
987
  ],
511
988
  "surface_case": [{ "from": 0, "to": 3, "diameter": 300 }],
@@ -630,6 +1107,14 @@ The `uri` field is a reference, not a guarantee. URLs may become unreachable ove
630
1107
  "static_level": 31.2,
631
1108
  "measurement_method": "electric_probe",
632
1109
  "notes": "Routine annual monitoring."
1110
+ },
1111
+ {
1112
+ "id": "e5f6a7b8-c9d0-1234-efab-567890123456",
1113
+ "type": "spot_measurement",
1114
+ "datetime": "2026-09-15T09:10:00-03:00",
1115
+ "static_level": 33.4,
1116
+ "measurement_method": "electric_probe",
1117
+ "notes": "Level before water sampling."
633
1118
  }
634
1119
  ],
635
1120
 
@@ -651,6 +1136,362 @@ The `uri` field is a reference, not a guarantee. URLs may become unreachable ove
651
1136
  }
652
1137
  ],
653
1138
 
1139
+ "attachments": [
1140
+ {
1141
+ "id": "c1d2e3f4-a5b6-7890-cdef-123456789abc",
1142
+ "uri": "https://files.wellmanager.example.com/wells/pp-01/relatorio-perfuracao.pdf",
1143
+ "media_type": "application/pdf",
1144
+ "document_type": "drilling_report",
1145
+ "filename": "relatorio-perfuracao.pdf"
1146
+ }
1147
+ ],
1148
+
1149
+ "pump_installations": [
1150
+ {
1151
+ "id": "e1f2a3b4-c5d6-7890-efab-234567890abc",
1152
+ "installed_at": "2006-03-20T10:00:00-03:00",
1153
+ "removed_at": "2018-06-12T09:30:00-03:00",
1154
+ "installed_by": "Perfurações Silva Ltda.",
1155
+ "removed_by": "Bombas Norte Serviços",
1156
+ "type": "submersible",
1157
+ "power_source": "grid",
1158
+ "rated_power": 11.0,
1159
+ "intake_depth": 52
1160
+ },
1161
+ {
1162
+ "id": "f2a3b4c5-d6e7-8901-fabc-345678901bcd",
1163
+ "installed_at": "2018-06-12T15:00:00-03:00",
1164
+ "updated_at": "2024-03-15T11:42:00-03:00",
1165
+ "type": "submersible",
1166
+ "power_source": "grid",
1167
+ "manufacturer": "Schneider",
1168
+ "model": "ME-25",
1169
+ "intake_depth": 54,
1170
+ "rated_power": 7.36,
1171
+ "riser_diameter": 114.3,
1172
+ "riser_material": "galvanized_steel",
1173
+ "check_valve": true,
1174
+ "electrical": {
1175
+ "voltage": 380,
1176
+ "phases": 3,
1177
+ "cable_section": 10,
1178
+ "cable_length": 70
1179
+ },
1180
+ "attachments": [
1181
+ {
1182
+ "id": "b8c9d0e1-f2a3-4567-bcde-678901234567",
1183
+ "uri": "https://files.wellmanager.example.com/wells/pp-01/attachments/nota-fiscal-bomba-2018.pdf",
1184
+ "media_type": "application/pdf",
1185
+ "document_type": "invoice",
1186
+ "filename": "nota-fiscal-bomba-2018.pdf",
1187
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
1188
+ }
1189
+ ]
1190
+ }
1191
+ ],
1192
+
1193
+ "permits": [
1194
+ {
1195
+ "id": "9a8b7c6d-5e4f-3210-abcd-0123456789ab",
1196
+ "type": "abstraction_permit",
1197
+ "authority": "SEMAS-PA",
1198
+ "identifier": "1234/2025",
1199
+ "request_identifier": "2024/0099-PRT",
1200
+ "status": "granted",
1201
+ "issued_at": "2025-02-10",
1202
+ "valid_until": "2029-02-10",
1203
+ "water_use": ["human_supply"],
1204
+ "flow_rate": 340.0,
1205
+ "daily_operating_time": 20,
1206
+ "volume_limits": [{ "period": "annual", "volume": 2482000 }],
1207
+ "conditions": [
1208
+ {
1209
+ "id": "c1",
1210
+ "description": "Instalar hidrômetro na saída do poço",
1211
+ "category": "equipment_installation",
1212
+ "due_after": "P90D",
1213
+ "responsible": "Equipe de operação",
1214
+ "fulfillments": [
1215
+ {
1216
+ "id": "e2f3a4b5-c6d7-8901-efab-23456789abcd",
1217
+ "datetime": "2025-04-02T10:00:00-03:00",
1218
+ "due_date": "2025-05-11",
1219
+ "description": "Hidrômetro instalado e comunicado ao órgão.",
1220
+ "author": "Equipe de operação"
1221
+ }
1222
+ ]
1223
+ },
1224
+ {
1225
+ "id": "c2",
1226
+ "description": "Relatório semestral de nível e vazão",
1227
+ "category": "reporting",
1228
+ "first_due": "2025-07-31",
1229
+ "recurrence": "P6M"
1230
+ },
1231
+ {
1232
+ "id": "c3",
1233
+ "description": "Análise anual de qualidade da água",
1234
+ "category": "monitoring",
1235
+ "first_due": "2026-09-30",
1236
+ "recurrence": "P1Y",
1237
+ "fulfillments": [
1238
+ {
1239
+ "id": "b5c6d7e8-f9a0-1234-bcde-56789abcdef0",
1240
+ "datetime": "2026-09-22T16:00:00-03:00",
1241
+ "due_date": "2026-09-30",
1242
+ "description": "Laudo LD-4471/26 protocolado no órgão gestor.",
1243
+ "sample_id": "ws-2026-09-a"
1244
+ }
1245
+ ]
1246
+ }
1247
+ ],
1248
+ "history": [
1249
+ {
1250
+ "id": "h-01",
1251
+ "date": "2024-11-04",
1252
+ "type": "filing",
1253
+ "description": "Requerimento de outorga protocolado."
1254
+ },
1255
+ {
1256
+ "id": "h-02",
1257
+ "date": "2024-12-02",
1258
+ "type": "fee",
1259
+ "description": "Taxa de análise do requerimento.",
1260
+ "due_date": "2024-12-20",
1261
+ "done": true
1262
+ },
1263
+ {
1264
+ "id": "h-03",
1265
+ "date": "2025-02-10",
1266
+ "type": "decision",
1267
+ "description": "Portaria 1234/2025 publicada."
1268
+ }
1269
+ ],
1270
+ "attachments": [
1271
+ {
1272
+ "id": "d4e5f6a7-b8c9-0123-defa-456789abcdef",
1273
+ "uri": "https://files.wellmanager.example.com/wells/pp-01/portaria-1234-2025.pdf",
1274
+ "media_type": "application/pdf",
1275
+ "document_type": "permit_document"
1276
+ }
1277
+ ]
1278
+ }
1279
+ ],
1280
+
1281
+ "meters": [
1282
+ {
1283
+ "id": "7c8d9e0f-a1b2-4c3d-8e4f-5a6b7c8d9e0f",
1284
+ "installed_at": "2025-04-02T09:00:00-03:00",
1285
+ "installed_by": "Hidro Serviços",
1286
+ "type": "electromagnetic",
1287
+ "manufacturer": "Incontrol",
1288
+ "model": "VMS Pro",
1289
+ "serial": "EM150-55821",
1290
+ "nominal_diameter": 150,
1291
+ "max_reading": 99999999
1292
+ }
1293
+ ],
1294
+
1295
+ "production": [
1296
+ {
1297
+ "id": "p-0001",
1298
+ "type": "meter_reading",
1299
+ "datetime": "2025-04-02T09:00:00-03:00",
1300
+ "meter_id": "7c8d9e0f-a1b2-4c3d-8e4f-5a6b7c8d9e0f",
1301
+ "reading": 0,
1302
+ "source": "manual"
1303
+ },
1304
+ {
1305
+ "id": "p-0002",
1306
+ "type": "meter_reading",
1307
+ "datetime": "2025-12-31T17:00:00-03:00",
1308
+ "meter_id": "7c8d9e0f-a1b2-4c3d-8e4f-5a6b7c8d9e0f",
1309
+ "reading": 1452300,
1310
+ "source": "telemetry"
1311
+ },
1312
+ {
1313
+ "id": "p-0003",
1314
+ "type": "estimated_volume",
1315
+ "period_start": "2025-01-01T00:00:00-03:00",
1316
+ "period_end": "2025-04-02T09:00:00-03:00",
1317
+ "volume": 436800,
1318
+ "method": "flow_time",
1319
+ "notes": "Regime r-0001 (300 m³/h × 16 h/dia × 91 dias), antes do hidrômetro."
1320
+ },
1321
+ {
1322
+ "id": "p-0004",
1323
+ "type": "meter_reading",
1324
+ "datetime": "2026-06-30T17:00:00-03:00",
1325
+ "meter_id": "7c8d9e0f-a1b2-4c3d-8e4f-5a6b7c8d9e0f",
1326
+ "reading": 2541800,
1327
+ "source": "manual"
1328
+ },
1329
+ {
1330
+ "id": "p-0005",
1331
+ "type": "meter_reading",
1332
+ "datetime": "2026-06-30T17:00:00-03:00",
1333
+ "meter_id": "7c8d9e0f-a1b2-4c3d-8e4f-5a6b7c8d9e0f",
1334
+ "reading": 2451800,
1335
+ "source": "manual",
1336
+ "corrects": "p-0004",
1337
+ "notes": "Corrige erro de digitação na leitura p-0004."
1338
+ }
1339
+ ],
1340
+
1341
+ "operating_regime": [
1342
+ {
1343
+ "id": "r-0001",
1344
+ "effective_from": "2018-06-12T15:00:00-03:00",
1345
+ "flow_rate": 300,
1346
+ "daily_operating_time": 16,
1347
+ "days_per_week": 7
1348
+ },
1349
+ {
1350
+ "id": "r-0002",
1351
+ "effective_from": "2025-04-02T09:00:00-03:00",
1352
+ "flow_rate": 320,
1353
+ "daily_operating_time": 18,
1354
+ "days_per_week": 7,
1355
+ "updated_at": "2025-04-02T12:00:00-03:00"
1356
+ }
1357
+ ],
1358
+
1359
+ "water_samples": [
1360
+ {
1361
+ "id": "ws-2026-09-a",
1362
+ "datetime": "2026-09-15T09:30:00-03:00",
1363
+ "sample_type": "routine",
1364
+ "campaign": "2026-Q3",
1365
+ "sampling_method": "low_flow",
1366
+ "sampling_point": {
1367
+ "type": "in_well",
1368
+ "depth": 65,
1369
+ "device": "low_flow_pump"
1370
+ },
1371
+ "purge": {
1372
+ "duration": 35,
1373
+ "volume": 0.0105,
1374
+ "flow_rate": 0.018,
1375
+ "stabilized": true,
1376
+ "readings": [
1377
+ {
1378
+ "elapsed": 25,
1379
+ "parameter": { "code": "ph", "vocabulary": "welldot" },
1380
+ "value": 4.9
1381
+ },
1382
+ {
1383
+ "elapsed": 30,
1384
+ "parameter": { "code": "ph", "vocabulary": "welldot" },
1385
+ "value": 4.8
1386
+ },
1387
+ {
1388
+ "elapsed": 35,
1389
+ "parameter": { "code": "ph", "vocabulary": "welldot" },
1390
+ "value": 4.8
1391
+ }
1392
+ ]
1393
+ },
1394
+ "static_level_event_id": "e5f6a7b8-c9d0-1234-efab-567890123456",
1395
+ "collected_by": "Field team A",
1396
+ "chain_of_custody": "CC-0918",
1397
+ "laboratory": {
1398
+ "name": "Lab X",
1399
+ "accreditation": "ISO/IEC 17025 #1234",
1400
+ "report_number": "LD-4471/26",
1401
+ "batch_id": "WO-88213",
1402
+ "sample_id": "88213-01",
1403
+ "received_at": "2026-09-15T18:20:00-03:00",
1404
+ "received_temperature": 4.1
1405
+ },
1406
+ "attachments": [
1407
+ {
1408
+ "id": "a1",
1409
+ "uri": "https://files.wellmanager.example.com/wells/pp-01/LD-4471-26.pdf",
1410
+ "media_type": "application/pdf",
1411
+ "document_type": "lab_report"
1412
+ }
1413
+ ],
1414
+ "results": [
1415
+ {
1416
+ "parameter": { "code": "ph", "vocabulary": "welldot" },
1417
+ "value": 4.8,
1418
+ "measured_in": "field"
1419
+ },
1420
+ {
1421
+ "parameter": {
1422
+ "code": "specific_conductance",
1423
+ "vocabulary": "welldot"
1424
+ },
1425
+ "value": 1240,
1426
+ "measured_in": "field"
1427
+ },
1428
+ {
1429
+ "parameter": { "code": "turbidity_fnu", "vocabulary": "welldot" },
1430
+ "value": 3.1,
1431
+ "measured_in": "field"
1432
+ },
1433
+ {
1434
+ "parameter": { "code": "sulfate", "vocabulary": "welldot" },
1435
+ "value": 412,
1436
+ "method": "US EPA 300.0",
1437
+ "measured_in": "lab",
1438
+ "analyzed_at": "2026-09-17T00:00:00-03:00",
1439
+ "analyzed_at_resolution": "day",
1440
+ "validation": { "status": "validated", "validated_by": "QA reviewer" }
1441
+ },
1442
+ {
1443
+ "parameter": { "code": "iron", "vocabulary": "welldot" },
1444
+ "value": 18.6,
1445
+ "fraction": "dissolved",
1446
+ "filtration": { "pore_size": 0.45, "location": "field" },
1447
+ "method": "US EPA 200.8",
1448
+ "measured_in": "lab"
1449
+ },
1450
+ {
1451
+ "parameter": { "code": "cyanide_wad_as_cn", "vocabulary": "welldot" },
1452
+ "qualifier": "estimated",
1453
+ "value": 0.004,
1454
+ "detection_limit": 0.002,
1455
+ "quantification_limit": 0.005,
1456
+ "measured_in": "lab",
1457
+ "lab_flags": ["J"],
1458
+ "validation": { "status": "qualified", "qualifier": "J" }
1459
+ },
1460
+ {
1461
+ "parameter": { "code": "71-43-2", "vocabulary": "cas" },
1462
+ "qualifier": "<",
1463
+ "value": 0.001,
1464
+ "measured_in": "lab"
1465
+ },
1466
+ {
1467
+ "parameter": { "code": "e_coli", "vocabulary": "welldot" },
1468
+ "presence": false,
1469
+ "measured_in": "lab",
1470
+ "analyzed_at": "2026-09-15T19:10:00-03:00"
1471
+ }
1472
+ ]
1473
+ },
1474
+ {
1475
+ "id": "ws-2026-09-b",
1476
+ "datetime": "2026-09-15T09:35:00-03:00",
1477
+ "sample_type": "field_duplicate",
1478
+ "parent_sample_id": "ws-2026-09-a",
1479
+ "campaign": "2026-Q3",
1480
+ "sampling_point": {
1481
+ "type": "in_well",
1482
+ "depth": 65,
1483
+ "device": "low_flow_pump"
1484
+ },
1485
+ "results": [
1486
+ {
1487
+ "parameter": { "code": "sulfate", "vocabulary": "welldot" },
1488
+ "value": 398,
1489
+ "measured_in": "lab"
1490
+ }
1491
+ ]
1492
+ }
1493
+ ],
1494
+
654
1495
  "history_logs": [
655
1496
  {
656
1497
  "id": "d0e1f2a3-b4c5-6789-defa-890123456789",
@@ -660,11 +1501,20 @@ The `uri` field is a reference, not a guarantee. URLs may become unreachable ove
660
1501
  "description": "Well construction completed. Commissioned for public supply by COSANPA. Initial flow rate 340 m³/h via air-lift.",
661
1502
  "author": "Prefeitura Municipal de Belém"
662
1503
  },
1504
+ {
1505
+ "id": "c3d4e5f6-a7b8-9012-cdef-3456789abcde",
1506
+ "datetime": "2006-03-20T10:00:00-03:00",
1507
+ "category": "status_change",
1508
+ "description": "Poço entra em operação após instalação da bomba.",
1509
+ "status": "active"
1510
+ },
663
1511
  {
664
1512
  "id": "a7b8c9d0-e1f2-3456-abcd-567890123456",
665
1513
  "datetime": "2018-06-12T09:30:00-03:00",
666
1514
  "updated_at": "2024-03-15T11:42:00-03:00",
667
1515
  "category": "maintenance",
1516
+ "maintenance_type": "pump_service",
1517
+ "pump_installation_id": "f2a3b4c5-d6e7-8901-fabc-345678901bcd",
668
1518
  "description": "Original 15 CV submersible pump replaced after motor burnout. New pump: Schneider ME-25 10 CV. (Description corrected 2024-03-15: model was ME-25, not ME-22 as originally logged.)",
669
1519
  "author": "Manutenção Rápida Ltda.",
670
1520
  "severity": "high",
@@ -673,11 +1523,31 @@ The `uri` field is a reference, not a guarantee. URLs may become unreachable ove
673
1523
  "id": "b8c9d0e1-f2a3-4567-bcde-678901234567",
674
1524
  "uri": "https://files.wellmanager.example.com/wells/pp-01/attachments/nota-fiscal-bomba-2018.pdf",
675
1525
  "media_type": "application/pdf",
1526
+ "document_type": "invoice",
676
1527
  "filename": "nota-fiscal-bomba-2018.pdf",
677
1528
  "description": "Purchase invoice for replacement pump",
678
1529
  "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
679
1530
  }
680
1531
  ]
1532
+ },
1533
+ {
1534
+ "id": "f3a4b5c6-d7e8-9012-fabc-3456789abcde",
1535
+ "datetime": "2026-04-10T14:00:00-03:00",
1536
+ "category": "maintenance",
1537
+ "maintenance_type": "meter_calibration",
1538
+ "meter_id": "7c8d9e0f-a1b2-4c3d-8e4f-5a6b7c8d9e0f",
1539
+ "description": "Aferição do medidor eletromagnético; erro dentro da tolerância.",
1540
+ "author": "Metrologia Norte Ltda."
1541
+ },
1542
+ {
1543
+ "id": "a4b5c6d7-e8f9-0123-abcd-456789abcdef",
1544
+ "datetime": "2026-09-15T09:30:00-03:00",
1545
+ "category": "maintenance",
1546
+ "maintenance_type": "water_sampling",
1547
+ "sample_ids": ["ws-2026-09-a", "ws-2026-09-b"],
1548
+ "hydrodynamic_event_ids": ["e5f6a7b8-c9d0-1234-efab-567890123456"],
1549
+ "description": "Coleta de baixa vazão com duplicata de campo; nível medido antes da coleta.",
1550
+ "author": "Field team A"
681
1551
  }
682
1552
  ]
683
1553
  }
@@ -685,4 +1555,4 @@ The `uri` field is a reference, not a guarantee. URLs may become unreachable ove
685
1555
 
686
1556
  ---
687
1557
 
688
- _Draft — `.well` Format Specification v2.0_
1558
+ _`.well` Format Specification v2.3_