docs: record the sink decision as ADR-0001 - #9
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
PostGISSinkorDjangoApiSink, then pick a default". Inspecting Contexta on 2026-07-26 showed that is incomplete in two ways:The Django API does not exist.
djangorestframeworkis in Contexta'srequirements.txtbut not inINSTALLED_APPS;urls.pyroutes 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
Contextforeign key, while Structura emits vectors whosestratumis 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.
PostGISSinkis withdrawn as a candidate default rather than deferred, because a direct insert bypasses invariants Contexta deliberately keeps insave(): race-safeNumberSequencecontext numbering (whose docstring records that the legacymax+1approach was racy), inverse relation edges, attribute validation.DjangoApiSinkstays 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.mdv0.5.0 — rescoped around the ADR; first task is confirming it.PostGISSinkstruck through.ROADMAP.mdOpen decisions — now points atdocs/adr/for decisions with real alternatives,architecture.mdfor smaller questions.docs/architecture.md— both the open-decisions entry and thePostGISSink/DjangoApiSinkdescriptions.The convention
There was no ADR convention anywhere in the workspace, so
docs/adr/README.mdstates one: four sections, and records are immutable — a superseded decision gets a new file and a status change, never an edit. The value is inContextandConsequences; "we chose PostGIS" is worthless, "we did not, because it bypassesNumberSequence" 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 srcclean on 26 files, 57 passed / 2 skipped. All relative links resolve.🤖 Generated with Claude Code