Skip to content

[codex] Reshape well details response around field events#660

Merged
jirhiker merged 6 commits into
stagingfrom
jir-well-details-api-fix
Apr 20, 2026
Merged

[codex] Reshape well details response around field events#660
jirhiker merged 6 commits into
stagingfrom
jir-well-details-api-fix

Conversation

@jirhiker

Copy link
Copy Markdown
Member

Summary

  • restructure the well details payload so field events are the primary nested data source
  • remove redundant top-level well details fields that are now represented under field_events
  • narrow endpoint-specific response models so nested well screens and latest sample data do not include unrelated thing payloads
  • move payload timing into a context manager and keep field events ordered newest-first

Response Shape Updates

  • replace the separate field_event_participants list with top-level field_events
  • remove recent_groundwater_level_observations from the well details response
  • remove latest_field_event_sample from the well details response
  • keep participants, activities, samples, and observations nested under each field event
  • return well screens without an embedded thing object in the well details payload

Why

The old response split related field-event data across several top-level fields, which duplicated information and made the client stitch the event model back together. Returning field events directly makes the payload match the domain structure and removes redundant response branches.

Validation

  • pytest tests/test_thing.py -k "water_well_details_payload"
  • black schemas/thing.py schemas/well_details.py services/well_details_helper.py tests/test_thing.py
  • flake8 schemas/thing.py schemas/well_details.py services/well_details_helper.py tests/test_thing.py (fails on pre-existing E501 line-length violations in these files)

@jirhiker

Copy link
Copy Markdown
Member Author
{
  "well": {
    "id": 6003,
    "created_at": "2026-02-27T17:34:20Z",
    "release_status": "public",
    "name": "MG-030",
    "site_name": null,
    "thing_type": "water-well",
    "current_location": {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [-107.8512, 33.1584]
      },
      "properties": {
        "county": "Sierra",
        "state": "NM"
      },
      "release_status": "private"
    },
    "first_visit_date": "2024-05-10",
    "groups": [],
    "monitoring_status": "active",
    "links": [
      {
        "thing_id": 6003,
        "relation": "legacy",
        "alternate_id": "MG-030",
        "alternate_organization": "NMBGMR"
      }
    ],
    "monitoring_frequencies": [],
    "general_notes": [],
    "sampling_procedure_notes": [],
    "site_notes": [],
    "well_purposes": ["monitoring"],
    "well_depth": 120.0,
    "well_depth_unit": "ft",
    "well_depth_source": "measured",
    "historic_depth_to_water": [
      "historic depth to water: 12 ft",
      "historic depth to water: 18 ft"
    ],
    "hole_depth": 130.0,
    "hole_depth_unit": "ft",
    "well_casing_diameter": 6.0,
    "well_casing_diameter_unit": "in",
    "well_casing_depth": 110.0,
    "well_casing_depth_unit": "ft",
    "well_casing_materials": ["PVC"],
    "well_completion_date": "2020-06-01",
    "well_completion_date_source": "driller log",
    "well_driller_name": "Example Drilling",
    "well_construction_method": "rotary",
    "well_construction_method_source": "driller log",
    "well_pump_type": "submersible",
    "well_pump_depth": 95.0,
    "well_pump_depth_unit": "ft",
    "well_status": "active",
    "open_status": true,
    "datalogger_suitability_status": "suitable",
    "measuring_point_height": 5.0,
    "measuring_point_height_unit": "ft",
    "measuring_point_description": "Top of casing",
    "aquifers": [],
    "water_notes": [],
    "construction_notes": [],
    "contacts": [],
    "permissions": [],
    "formation_completion_code": null,
    "nma_formation_zone": null,
    "well_location_note": [
      "turn left at the cattle guard",
      "use the south gate"
    ]
  },
  "contacts": [
    {
      "id": 101,
      "created_at": "2026-02-27T17:40:00Z",
      "release_status": "public",
      "contact_name": "Jane Smith",
      "contact_organization": null,
      "emails": [
        {
          "id": 201,
          "created_at": "2026-02-27T17:40:01Z",
          "release_status": "public",
          "email": "jane@example.org"
        }
      ],
      "phones": [
        {
          "id": 301,
          "created_at": "2026-02-27T17:40:02Z",
          "release_status": "public",
          "phone_number": "555-123-4567"
        }
      ],
      "addresses": []
    }
  ],
  "sensors": [
    {
      "id": 401,
      "created_at": "2026-02-27T17:41:00Z",
      "release_status": "public",
      "sensor_model": "Levelogger 5"
    }
  ],
  "deployments": [
    {
      "id": 501,
      "created_at": "2026-02-27T17:42:00Z",
      "release_status": "public",
      "thing_id": 6003,
      "sensor_id": 401,
      "installation_date": "2026-02-01",
      "removal_date": null,
      "sensor": {
        "id": 401,
        "created_at": "2026-02-27T17:41:00Z",
        "release_status": "public",
        "sensor_model": "Levelogger 5"
      }
    }
  ],
  "well_screens": [
    {
      "id": 701,
      "created_at": "2026-02-27T17:43:00Z",
      "release_status": "public",
      "thing_id": 6003,
      "aquifer_system_id": 10,
      "aquifer_system": "Santa Fe Group",
      "aquifer_type": "bedrock",
      "geologic_formation_id": 22,
      "geologic_formation": "QTsf",
      "screen_depth_bottom": 110.0,
      "screen_depth_bottom_unit": "ft",
      "screen_depth_top": 90.0,
      "screen_depth_top_unit": "ft",
      "screen_type": "slotted pvc",
      "screen_description": "primary production interval"
    }
  ],
  "field_events": [
    {
      "id": 801,
      "created_at": "2026-02-27T17:45:00Z",
      "release_status": "public",
      "thing_id": 6003,
      "event_date": "2026-02-27T17:45:00Z",
      "notes": "Monthly groundwater check",
      "field_event_participants": [
        {
          "id": 901,
          "created_at": "2026-02-27T17:45:10Z",
          "release_status": "public",
          "field_event_id": 801,
          "contact_id": 101,
          "participant_role": "sampler",
          "participant": {
            "id": 101,
            "created_at": "2026-02-27T17:40:00Z",
            "release_status": "public",
            "contact_name": "Jane Smith",
            "contact_organization": null
          }
        }
      ],
      "field_activities": [
        {
          "id": 1001,
          "created_at": "2026-02-27T17:45:20Z",
          "release_status": "public",
          "field_event_id": 801,
          "activity_type": "groundwater level",
          "notes": "Steel tape measurement",
          "samples": [
            {
              "id": 1101,
              "created_at": "2026-02-27T17:45:30Z",
              "release_status": "public",
              "contact": {
                "id": 101,
                "created_at": "2026-02-27T17:40:00Z",
                "release_status": "public",
                "contact_name": "Jane Smith",
                "contact_organization": null
              },
              "sample_date": "2026-02-27T17:45:30Z",
              "sample_name": "MG-030-gwl-20260227",
              "sample_matrix": "water",
              "sample_method": "Steel-tape measurement",
              "qc_type": "Normal",
              "notes": "Clear access to casing",
              "depth_top": null,
              "depth_bottom": null,
              "observations": [
                {
                  "id": 1201,
                  "created_at": "2026-02-27T17:45:40Z",
                  "release_status": "public",
                  "sample_id": 1101,
                  "sensor_id": 401,
                  "observation_datetime": "2026-02-27T17:45:40Z",
                  "parameter": {
                    "id": 1,
                    "created_at": "2025-01-01T00:00:00Z",
                    "release_status": "public",
                    "parameter_name": "groundwater level"
                  },
                  "value": 14.2,
                  "unit": "ft",
                  "nma_data_quality": null,
                  "depth_to_water_bgs": 9.2,
                  "measuring_point_height": 5.0,
                  "groundwater_level_reason": "Water level not affected"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

@jirhiker jirhiker marked this pull request as ready for review April 17, 2026 15:38
Copilot AI review requested due to automatic review settings April 17, 2026 15:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reshapes the /water-well/{thing_id}/details response to make field_events the primary nested structure, removing previously redundant top-level well-detail fields and tightening nested response payloads.

Changes:

  • Replace top-level “latest sample” / “recent observations” / “field_event_participants” branches with a top-level field_events list containing nested participants, activities, samples, and observations.
  • Remove embedded thing data from well_screens in the well details payload by introducing WellScreenBaseResponse.
  • Refactor payload-stage timing into a context manager and keep field events ordered newest-first.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
services/well_details_helper.py Reworks payload assembly to load and return field events (with nested data) and removes now-redundant “latest/recent” branches; introduces a context-managed timing helper.
schemas/well_details.py Updates the well details response model to expose field_events and adjusts nested response shapes.
schemas/thing.py Splits well screen response into a base schema (no thing) plus the full schema (includes thing).
schemas/sample.py Adds a well-details-specific sample response model variant.
tests/test_thing.py Updates well details tests to assert the new field_events-centric response shape and removal of thing from well screens.

Comment thread schemas/well_details.py Outdated
Comment thread schemas/well_details.py
Comment thread services/well_details_helper.py
Comment thread services/well_details_helper.py
Comment thread schemas/sample.py Outdated
Comment thread tests/test_thing.py Outdated
@jirhiker

Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

1 similar comment
@jirhiker

Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

Copilot AI review requested due to automatic review settings April 19, 2026 15:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Comment thread tests/test_thing.py
Comment on lines +745 to +750
later_field_event = FieldEvent(
thing_id=water_well_thing.id,
event_date="2025-01-02T00:00:00Z",
notes="later field event",
release_status="draft",
)

Copilot AI Apr 19, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this new test, FieldEvent.event_date is a timezone-aware datetime column; passing an ISO string ("2025-01-02T00:00:00Z") relies on DB/driver coercion and can break on some backends. Use an actual datetime (e.g., datetime(..., tzinfo=timezone.utc)) for event_date to keep the test portable and type-correct.

Copilot uses AI. Check for mistakes.
Comment thread tests/test_thing.py
session.delete(later_field_event)
session.commit()


Copilot AI Apr 19, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are whitespace-only lines after the finally block here. This can introduce new flake8 W293/W291 failures; please remove the trailing spaces/blank whitespace-only lines.

Suggested change

Copilot uses AI. Check for mistakes.
Comment thread tests/test_thing.py
Comment on lines +738 to +742
def test_get_water_well_details_payload_limits_field_events(
water_well_thing,
field_event,
):
from db import FieldEvent

Copilot AI Apr 19, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The /details response no longer returns latest_field_event_sample or top-level field_event_participants (they’ve been moved under field_events). There is still a test later in this file (test_get_water_well_details_payload_includes_imported_water_level_staff) asserting those removed keys, which will fail with the new response shape. Update that test to assert against the new field_events[..].field_activities[..].samples[..].contact and field_events[..].field_event_participants structure.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 19, 2026 15:46
@jirhiker jirhiker removed the request for review from Copilot April 19, 2026 15:46
@jeremyzilar

Copy link
Copy Markdown
Contributor

What needs to change on the front-end to make this possible? And will they need to change at the same time?

@jirhiker

Copy link
Copy Markdown
Member Author

@jeremyzilar this doesn't break anything on the front end, it just exposes all the field_events as a list of dicts. field events are sorted in desc order. the field_participants are included in the field_events payload

@jeremyzilar jeremyzilar left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jirhiker jirhiker merged commit 18aeff3 into staging Apr 20, 2026
6 checks passed
@jirhiker jirhiker deleted the jir-well-details-api-fix branch April 20, 2026 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants