Development¶
Prerequisites¶
- Python 3.12+
- uv package manager
Install Dependencies¶
This installs everything — dev tools, docs, UI, Flight SQL drivers, and type stubs.
Run Tests¶
uv run pytest # all tests
uv run pytest tests/unit/ # unit tests only
uv run pytest tests/integration/ # integration tests only
uv run pytest -k "test_revenue" # by name pattern
Code Quality¶
Build Documentation¶
Project Structure¶
src/orionbelt/
api/ REST API (FastAPI routers, middleware, schemas)
ast/ SQL AST node definitions (frozen dataclasses)
compiler/ Compilation pipeline (resolution, star, cfl, codegen)
dialect/ 8 SQL dialect implementations (self-registering)
models/ Pydantic v2 models (semantic model, query, errors)
obsl/ OBSL-Core RDF graph exporter and SPARQL engine
parser/ YAML loader, reference resolver, semantic validator
service/ Session manager, model store
ui/ Gradio web interface
Changing the OBML model¶
OBML is the single source of truth for the project. Every type, enum, and field is mirrored across several dependent artifacts that must move together:
- Pydantic models —
src/orionbelt/models/semantic.py(andmodels/query.py,models/errors.py) - JSON schema —
schema/obml-schema.json(andschema/query-schema.json) - Ontology —
ontology/obsl.ttl(class + properties) andobsl.shacl.ttl - OSI converter —
packages/osi-orionbelt(custom_extensions round-trip) - MkDocs + REST API docs, and tests/fixtures
The contract manifest¶
schema/obml-contract.yml is a hand-maintained manifest that records the OBML
field surface in one place: every enum and class, and per field its camelCase
alias, whether it appears in the JSON schema (json_schema), its ontology
property (ontology_property), and OSI round-trip behaviour (osi_roundtrip).
Schema validation at the API boundary¶
The API validates raw model and query payloads against the published JSON
Schemas before processing them (see api/schema_guards.py). Coverage spans
every OBML/QueryObject ingestion point: session and shortcut model-load and
query endpoints, the oneshot batch (its inline model_yaml and each query),
and the MODEL_FILES startup preload. Model documents validate against
obml-schema.json, query payloads against query-schema.json. A contract
violation returns HTTP 422 (or fails startup for MODEL_FILES). SQL-input
surfaces (OBSQL / pgwire / Flight) are out of scope: they receive SQL, not
OBML/QueryObject JSON, and build a trusted QueryObject internally. This makes the JSON Schema a load-bearing
gate that every real request exercises - so the published contract stays
provably correct and external consumers can rely on the same rules the engine
enforces. The schemas are camelCase-only; snake_case keys that Pydantic would
otherwise coerce are rejected at the boundary.
Keeping the manifest honest¶
tests/unit/test_obml_contract.py keeps the manifest in sync with the live
Pydantic models, the JSON schema, and the ontology. Adding or removing a
field on the Pydantic models without updating the manifest fails this test -
that is the intended early-warning gate that you also need to touch the other
dependents.
When you change OBML:
- Update the Pydantic model in
models/semantic.py. - Add/update the field (or enum value) in
schema/obml-contract.yml. Setjson_schema/ontology_propertyto match the schema and ontology you are about to update. If a field should never be part of the contract, add it toMANIFEST_FIELD_EXCLUSIONSin the test with a comment. - Update the JSON schema, ontology, OSI converter, docs, and fixtures.
- Run
uv run pytest tests/unit/test_obml_contract.py(plus the schema and OSI drift tests) until green.