Skip to content

kernel: real SqliteMetadataStore — SQLAlchemy models for all entities + initial migration - #74

Merged
JArmandoAnaya merged 1 commit into
mainfrom
task/3-metadata-store
Jul 26, 2026
Merged

kernel: real SqliteMetadataStore — SQLAlchemy models for all entities + initial migration#74
JArmandoAnaya merged 1 commit into
mainfrom
task/3-metadata-store

Conversation

@JArmandoAnaya

Copy link
Copy Markdown
Contributor

Replaces the bootstrap stub (engine + empty MetaData) with the persistence floor every M1 service sits on.

What landed

  • Tables for all fourteen entities (adapters/_tables.py, private) — flat columns where the model is flat; child tables for batch_asset and annotation_job_asset; JSON for the immutable nested values (annotation_schema.classes, annotation.geometry, release.manifest).
  • Mapping layer (adapters/_mappers.py, private) — one EntityMapping per entity, so no SQLAlchemy type reaches a domain or port signature. adapters/__init__ still exports only SqliteMetadataStore.
  • Port — a generic Repository[T] plus a UnitOfWork, instead of ~50 per-entity methods. Every child entity has exactly one parent FK, so list(parent_id=...) covers every scoped read.
  • Migration 001 (adapters/migrations.py) — an ordered MIGRATIONS list with FORMAT_VERSION derived from it. initialize() runs what is missing and refuses a workspace stamped ahead of this build.
  • Unit of workwith store.unit_of_work() as uow: commits on clean exit, rolls back on any exception.
  • kernel/errors.pyVisionSetError and the three errors this layer raises.
  • DatasetMember / DatasetChange domain models (shapes only; the rules are kernel: DatasetService — promotion from completed batches, mutation change log #11's).
  • docs/persistence.md.

Decisions

  • Hand-rolled versioned DDL, not alembic. A local-first single-file store does not need a migration framework, and format_version would then duplicate alembic_version.
  • classes/geometry/manifest as JSON, membership/progress as child tables — immutable values that rehydrate whole vs. relations edited one row at a time.
  • Timestamps are TEXT holding ISO-8601 with offset. SQLite's DATETIME storage drops the timezone; naive datetimes are rejected at construction.
  • PRAGMA foreign_keys = ON per connection — SQLite ships with foreign keys off, so every FK here would otherwise be decorative. There is a test that fails without the listener.

Scope: persistence only. No services, no state machines, no name-uniqueness rules — those are #4#12.

Gates

Gate Result
uv run pytest 65 passed
uv run ruff check . / ruff format --check . clean, 60 files formatted
uv run mypy src/visionset/kernel no issues, 31 files
uv run mypy src/visionset no issues, 41 files
uv run lint-imports 2 contracts kept, 0 broken
scripts/export_openapi.py no drift

Closes #3

…ration 001

Replaces the bootstrap stub (engine + empty MetaData) with the persistence
floor every M1 service sits on: tables for all fourteen entities, a mapping
layer that keeps SQLAlchemy out of every domain and port signature, a unit of
work scoped to one Project-aggregate operation, and a forward-only migration
mechanism gated by the workspace format_version.
@JArmandoAnaya
JArmandoAnaya merged commit 0acd47b into main Jul 26, 2026
3 checks passed
@JArmandoAnaya
JArmandoAnaya deleted the task/3-metadata-store branch July 26, 2026 11:00
JArmandoAnaya added a commit that referenced this pull request Aug 21, 2026
…ration 001 (#74)

Replaces the bootstrap stub (engine + empty MetaData) with the persistence
floor every M1 service sits on: tables for all fourteen entities, a mapping
layer that keeps SQLAlchemy out of every domain and port signature, a unit of
work scoped to one Project-aggregate operation, and a forward-only migration
mechanism gated by the workspace format_version.
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.

kernel: real SqliteMetadataStore — SQLAlchemy models for all entities + initial migration

1 participant