Skip to content

docs: record the sink decision as ADR-0001 - #9

Merged
leiverkus merged 1 commit into
mainfrom
docs/adr-vector-sink
Jul 26, 2026
Merged

docs: record the sink decision as ADR-0001#9
leiverkus merged 1 commit into
mainfrom
docs/adr-vector-sink

Conversation

@leiverkus

Copy link
Copy Markdown
Owner

Documentation only. Establishes docs/adr/ and records the v0.5.0 sink decision. Status is Proposed, not Accepted — the choice is yours; the milestone now lists confirming it as its first task.

Why the roadmap's framing needed replacing

v0.5.0 read "implement PostGISSink or DjangoApiSink, then pick a default". Inspecting Contexta on 2026-07-26 showed that is incomplete in two ways:

The Django API does not exist. djangorestframework is in Contexta's requirements.txt but not in INSTALLED_APPS; urls.py routes only the admin; there is no serializer, viewset or router in the codebase. The milestone was not choosing between two built options.

Both sinks are blocked by the same gap. Every geometry model in Contexta requires a Context foreign key, while Structura emits vectors whose stratum is assigned downstream by an archaeologist. There is no landing zone for context-less geometry — so the sink is not what actually blocks v0.5.

What ADR-0001 proposes

Hand off a GeoPackage; Contexta imports it through its ORM. PostGISSink is withdrawn as a candidate default rather than deferred, because a direct insert bypasses invariants Contexta deliberately keeps in save(): race-safe NumberSequence context numbering (whose docstring records that the legacy max+1 approach was racy), inverse relation edges, attribute validation. DjangoApiSink stays a stub, to be implemented if and when the API exists — it is the right long-term transport, but it is not Structura's to build.

The record is explicit about what this costs: ingestion stops being automatic, two artefacts exist where one could, and v0.5 now openly depends on another repository.

Roadmap and architecture updated

The record is linked from both, so it is reachable from where someone would look:

  • ROADMAP.md v0.5.0 — rescoped around the ADR; first task is confirming it. PostGISSink struck through.
  • ROADMAP.md Open decisions — now points at docs/adr/ for decisions with real alternatives, architecture.md for smaller questions.
  • docs/architecture.md — both the open-decisions entry and the PostGISSink / DjangoApiSink descriptions.

The convention

There was no ADR convention anywhere in the workspace, so docs/adr/README.md states one: four sections, and records are immutable — a superseded decision gets a new file and a status change, never an edit. The value is in Context and Consequences; "we chose PostGIS" is worthless, "we did not, because it bypasses NumberSequence" stops the question being reopened in a year.

Contexta gets a matching ADR-0001 for the landing zone (leiverkus/contexta#2). The two decisions depend on each other and are implemented in different repositories, which is exactly why they are separate records.

Verification

ruff check . clean, mypy src clean on 26 files, 57 passed / 2 skipped. All relative links resolve.

🤖 Generated with Claude Code

ROADMAP v0.5.0 framed persistence as "PostGIS or the Django API, then
pick a default". Inspecting Contexta showed that framing was incomplete
in two ways worth writing down before anyone implements against it.

The Django API does not exist: DRF is in Contexta's requirements.txt but
not in INSTALLED_APPS, urls.py routes only the admin, and there is no
serializer or viewset anywhere. And both candidate sinks hit the same
wall — every geometry model in Contexta requires a Context foreign key,
while Structura emits vectors whose stratum is assigned downstream. There
is no landing zone for context-less geometry, so the sink is not what
actually blocks v0.5.

ADR-0001 proposes the file handoff instead: FileSink writes a GeoPackage,
Contexta imports it through its ORM, and the invariants Contexta keeps in
save() — race-safe context numbering, inverse relation edges, attribute
validation — stay honoured. PostGISSink is withdrawn as a candidate
default rather than deferred.

Status is Proposed, not Accepted: the choice is the project's. The
milestone now lists confirming it as its first task.

Also establishes docs/adr/ and its conventions — there was no ADR
convention anywhere in the workspace. Records are immutable; a superseded
decision gets a new record rather than an edit, so the reasoning survives
the conclusion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@leiverkus
leiverkus merged commit 8957f1c into main Jul 26, 2026
2 checks passed
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