Skip to content

Workflow & the three contracts

How we make changes. The one rule that governs everything: change the contract before the code. This is Extended Spec-Driven Development (SDD). The full reference is SDD workflow; this page is the practical day-to-day.

The environment

There is one stack — no dev/production split. The app image ships the full toolchain and the repo is bind-mounted, so host edits hot-reload and you never pip install by hand:

make up                               # build + start the stack (GPU auto-detected)
docker compose exec app make ci       # run the offline gate inside the container

On a host without an NVIDIA GPU/toolkit, make up automatically layers docker-compose.cpu.yml so the stack still starts (make up-cpu forces it).

The three contracts

This product has three sources of truth that are protected. Each has a change-it-first rule and a CI gate:

Contract Source of truth After you change it Gate
API specs/openapi.yaml make generate → regenerates Pydantic models make test-contracts (schemathesis)
DB schema Alembic migrations alembic upgrade head make migrate-test (up/down round-trip)
Model/training specs/schemas/training_dataset.schema.json + the eval gate a training run registers an adapter the eval gate (held-out score)

Why three and not one: this is self-hosted (you upgrade customers' databases, so migrations are mandatory, not optional) with a training core (an unverified fine-tune must never auto-serve, so the eval gate is a hard gate). See Learning the system for what the eval gate measures.

Recipes

Adding or changing an API endpoint

  1. Edit specs/openapi.yaml first (the SSOT).
  2. make generate — regenerate adapta/models/generated/models.py. Never hand-edit generated files.
  3. Implement the handler in adapta/api/v1/* and the logic in adapta/services/*.
  4. make check-models (drift gate) and make test-contracts (schemathesis against a live server) must pass.

Changing the database schema

  1. Change the ORM in adapta/db/models.py.
  2. Autogenerate a migration, then review it (autogenerated ≠ correct).
  3. make migrate-test — the up→down→up round-trip must pass on seeded data.

Changing training / the eval gate

  1. The dataset shape is governed by specs/schemas/training_dataset.schema.json; the gate semantics are documented in that file's $comment (the Pillar-3 SSOT). Update it if you change the gate's meaning.
  2. Don't rewrite the training loop or inference engine internals — wrap/call them (hard constraint).
  3. Update tests/test_eval_gate.py.

The CI gates

Two gates run in .github/workflows/ci.yml:

  • fast (every push, offline, no infra) — check-leaks, lint, lint-imports, coverage (with an enforced floor), validate-spec, check-models, import smoke, console build, and mkdocs build --strict (the docs gate — a broken internal link fails here).
  • full (PR→main and push→main, live stack) — migrate-test, boot smoke, contract tests, integration tests.

Run the fast gate locally before pushing: docker compose exec app make ci.

Definition of done

A change is done only when: (1) the contract changed first if it touched API/schema/model; (2) the relevant gate is green in CI, not just locally; (3) no detail=str(e) was reintroduced (make check-leaks); (4) generated artifacts were regenerated, not hand-edited; (5) docs were updated in the same change.

Console visual documentation

make screenshots and make gif regenerate the screenshots and hero GIF committed to docs/screenshots/. Re-run them whenever you change the console UI — they are the visual changelog for reviewers and users.

Prerequisites (once, on the host):

cd e2e && npm install && npx playwright install chromium
# ffmpeg must be on PATH

Usage (stack must be up):

make console-build  # rebuild adapta/console/dist/ (always needed after source changes)
make screenshots    # console-build + seed + capture 9 PNGs at 1440×900 → docs/screenshots/
make gif            # console-build + seed + record walkthrough → docs/screenshots/hero.gif

make screenshots and make gif both depend on console-build and run it automatically — the console is a compiled Svelte SPA and the container serves the pre-built adapta/console/dist/ directory, so a stale build produces screenshots with stale content. Both seed demo data fresh on each run (wipes existing projects → creates 3). Commit the updated docs/screenshots/ files alongside the console change. These targets are host-only and never run in CI.

For coding style, branch/commit conventions, and the contributor checklist, see CONTRIBUTING.md.