Skip to content

feat(ingestion): add the Van Essen domain rules and adapter - #846

Merged
jirhiker merged 1 commit into
stagingfrom
feat/van-essen-domain-layer
Aug 19, 2026
Merged

feat(ingestion): add the Van Essen domain rules and adapter#846
jirhiker merged 1 commit into
stagingfrom
feat/van-essen-domain-layer

Conversation

@jirhiker

Copy link
Copy Markdown
Member

Task 3.1. domain/van_essen.py plus sources/san_acacia/adapter.py — 28 new
tests, no database and no network.

Narrower than the plan said

The draft had this converting drillingDepth from centimetres and building a
WGS84 point from lat/lng. The live MonitoringPoint payload is
{id, name} — no depth, no coordinates — so those functions would have had no
input. Geometry and construction come from the Ocotillo records a point
reconciles against, which is consistent with ingestion never creating wells.
I corrected the plan rather than writing functions with no callers.

What it does

  • Reading timestamp → timezone-aware UTC. Naive is read as UTC, since the API
    documents UTC and does not always mark it. Reading it as local would shift
    every observation by the machine's offset — and differently on a laptop than
    in a container.
  • Centimetres → feet via the existing domain/units.convert_cm_to_ft.
  • Deterministic external keys from the vendor's numeric id, not the name.
    SO-0125 is a Bureau point id and can be corrected; the numeric id is what
    the vendor's URLs use and what a re-run must resolve to the same record.
  • Errors subclass ValueError, matching the per-row contract the CSV importers
    already expect.

ADR4 layering is asserted by a test that inspects the import graph, rather than
by reading the file: no fastapi, sqlalchemy, pydantic, httpx, db,
api, schemas, or services.

What the adapter refuses

Both cases would otherwise produce plausible numbers rather than an error, which
is the failure mode this source is most prone to:

Refused Why
reference != 3 The datum is chosen at request time and cannot be recovered from the row
unit != "cm" An unconverted value is wrong by 30.48× and still reads as a believable depth

Per-record failures are collected, not raised — one unparseable reading costs
that reading, not the series.

Judgement calls worth review

Negative depths are kept. Depth below ground goes negative when water stands
above ground, which happens in these riparian wells at high flow. Clamping would
erase real data.

None levels pass through as gaps, but the adapter then refuses the row —
there is nothing to store. That is a failure entry, not silence, so gaps show up
in the metadata count.

The module docstring lists every value the mapping invents rather than
reads — datum, unit, timezone — since inventing is where a mapping goes quietly
wrong.

Note

Running tests/ locally needs MODE=development; a .env with
AUTHENTIK_DISABLE_AUTHENTICATION=1 and MODE=staging aborts collection. That
is pre-existing and unrelated. 77 tests pass across both directories.

🤖 Generated with Claude Code

Turns diver readings into Ocotillo values: timestamps to timezone-aware UTC,
centimetres to feet, and deterministic external keys. Pure functions, no
database and no network, per ADR4 -- asserted by a test that checks the import
graph rather than by reading the file.

Narrower than the plan described. The draft had this converting drillingDepth
and building a point from lat/lng, but the live MonitoringPoint payload is
{id, name}: no depth, no coordinates. Those functions would have had no input,
so the plan is corrected rather than the functions written.

The adapter refuses a row whose reference is not ground surface, and one whose
unit is not centimetres. Both would otherwise produce plausible numbers instead
of an error -- the datum is chosen at request time and is not recoverable from
the row, and an unconverted centimetre value reads as a believable depth while
being wrong by a factor of 30.48.

External keys use the vendor's numeric id, not the name. SO-0125 is a Bureau
point id and can be corrected; the numeric id is what the vendor's URLs use and
what a re-run has to resolve to the same record.

Negative depths are kept: water stands above ground in these riparian wells at
high flow, and clamping would erase real data.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Coverage

79.63% total — gate is 75%.

Coverage for the Python files changed in this PR
Name Stmts Miss Cover Missing
automated_ingestion/sources/san_acacia/adapter.py 31 1 97% 52
domain/van_essen.py 37 0 100%
TOTAL 68 1 99%

@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Your pull request is automatically being deployed to Dagster Cloud.

Location Status Link Updated
ocotillo-automated-ingestion View in Cloud Aug 19, 2026 at 05:44 AM (UTC)

@jirhiker
jirhiker merged commit 34c4b1f into staging Aug 19, 2026
10 checks passed
@jirhiker
jirhiker deleted the feat/van-essen-domain-layer branch August 19, 2026 05:43
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.

1 participant