Skip to content

feat(v2): Phase 1 — schema registry & versioning (/api/v2)#219

Merged
JonnyTran merged 13 commits into
developfrom
feat/v2-schema-registry
Jul 7, 2026
Merged

feat(v2): Phase 1 — schema registry & versioning (/api/v2)#219
JonnyTran merged 13 commits into
developfrom
feat/v2-schema-registry

Conversation

@JonnyTran

Copy link
Copy Markdown
Member

Phase 1 of 6 — Schema-centric data model

Stands up the Schema entity (the v2 "Dataset") and its object-store-backed, versioned Pandera body as an isolated /api/v2 module, alongside untouched v1. Implements the Phase 1 plan from the design spec.

What's included

  • models/v2/Schema + SchemaVersion ORM models (registry pointer + lineage + denormalized columns_cache; review_widgets overlay).
  • Alembic migrationschemas / schema_versions tables (additive, beside v1).
  • contexts/v2/schema_bodies.py — pure Pandera helpers: derive_columns_cache + null/missing-tolerant validate_record_fields.
  • contexts/v2/schemas.py — schema CRUD + object-store-backed publish_version (uploads body, derives cache, advances current_version_id, links lineage).
  • api/v2//api/v2 schema router (CRUD, version publishing, GET .../columns) gated by a new SchemaPolicy mirroring DatasetPolicy (owner always; admin+member for writes; member for reads). Mounted as a separate api_v2 sub-app.
  • Tests — 26 passing, isolated under tests/integration/**/v2/ with a v2-aware conftest.

Notable decisions / deviations (documented in spec §13)

  • Review widget via side map, not Pandera body. Pandera 0.32 / pandas 3.0 drop Column.metadata through to_json, so the per-column review widget is carried out-of-band in review_widgets (the plan's documented fallback).
  • Null/precision-safe validation. pa.Int is numpy int64 (can't hold None); validation separates nulls, enforces missing required columns, and converts numpy→native via .item()/ISO (no lossy to_json), preserving high-precision floats + datetimes for the Phase-2 record.fields JSONB.
  • Dialect-aware circular FK. schemas.current_version_id → schema_versions.id is added only on non-SQLite (SQLite can't ALTER-add constraints; the test suite runs on SQLite). publish_version flushes the version before pointing at it to avoid the FK cycle.
  • Tests under tests/integration/ (not tests/unit/) so the v2 suite runs without the legacy OpenSearch session fixture — keeping v2 genuinely isolated.
  • put_object now propagates the S3 VersionId (was always NULL) so object_version_id is populated.

Review

roborev reviewed each commit; 4 findings addressed (lossy coercion, missing-required enforcement, S3 VersionId, model test coverage). Accepted/deferred (Low): concurrent-publish race (Phase-1 inline sync; hardened at job-queue offload) and v1-consistent 404-vs-403 on fetch-then-authorize.

Out of scope (later phases)

Records + bulk-upsert (2), LanceDB index (3), annotation v2 (4), queues (5), v1→v2 migrator + retirements (6).

JonnyTran added 12 commits June 27, 2026 07:20
Pandera 0.32/pandas 3.0 drops Column.metadata through to_json, so the review
widget is carried via a review_widgets side map (spec §13). validate_record_fields
separates nulls so a None in a nullable numpy-int column no longer fails coercion.
Adds review_widgets JSONB overlay on SchemaVersion per spec §13 (Pandera to_json
drops Column.metadata, so review widgets are carried out-of-band).
Includes review_widgets column; the circular schemas.current_version_id FK is added
only on non-SQLite dialects (SQLite can't ALTER-add constraints; tests run on SQLite).
Adds a one-directional Schema.workspace relationship so the SubFactory pattern
(and FK population) works as in DatasetFactory.
SchemaVersionCreate/Read carry review_widgets (spec §13).
publish_version flushes the new version before pointing schema.current_version_id at
it (avoids the schemas<->schema_versions FK cycle and an unset version id). Threads
review_widgets into the stored version and derived columns_cache (spec §13).
…r-workspace authz

SchemaPolicy mirrors DatasetPolicy (owner always; admin+member for writes). Mounts a
separate api_v2 sub-app at /api/v2. Adds an isolated tests/integration conftest with a
v2-aware async_client (overrides get_async_db + get_s3_client on api_v2) and no
OpenSearch fixture.
…VersionId)

- validate_record_fields: convert numpy->native via .item()/ISO instead of lossy
  to_json (preserves high-precision floats + datetimes); reject omitted required cols.
- put_object: propagate S3 VersionId so schema_versions.object_version_id is populated.
- Add model default/uniqueness + float/datetime/missing-required tests.
- Document accepted/deferred findings (publish race, 404-vs-403, commit granularity).
@JonnyTran JonnyTran requested a review from a team as a code owner June 27, 2026 18:54
@vercel

vercel Bot commented Jun 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
extralit-frontend Ignored Ignored Preview Jul 7, 2026 2:04am

frame.iloc[0] collapses the validated row into a single Series whose dtype is
the columns' common type; an int64 cell alongside a float64 column upcasts to
float, silently degrading integer fidelity for record.fields. Extract each cell
per-column (frame[col].iloc[0]) instead. Adds an Int+Float (no string column)
regression test. Addresses roborev job 62.
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