Roadmap

This is the single canonical list of work that has been proposed, designed, or partially shipped, plus the rationale for each deferral and what would unblock it. The Current State page is the snapshot of what’s implemented today; this page is the snapshot of what’s known to be missing. Items are grouped by area, not by release. Each entry has the same shape:
  • Status — Proposed (no code), Designed (ADR shipped), Partial (some code landed), Deferred (decided to skip in current scope).
  • What — short description.
  • Why deferred — what made us stop short.
  • Unblocks on — concrete prerequisite that would let work resume.

Schema diff and migration generation

Tracking ADR 0004.

cratestack migrate verify

  • Status: Designed
  • What: CI gate that replays the generated migration history against an ephemeral Postgres / SQLite and confirms the resulting schema matches the committed snapshot byte-for-byte. Required to make the diff generator trustworthy: without it, snapshot tampering and hand-edited applied migrations go undetected.
  • Why deferred: Needs ephemeral database spawning. Postgres needs Docker via testcontainers (CI infrastructure decision); SQLite in-memory is trivial but ships in the same slice for parity.
  • Unblocks on: Decision on the testcontainers dependency footprint, or a pluggable Spawner trait that lets the user supply their own ephemeral instances.

cratestack migrate drift

  • Status: Partial — the crate-boundary question is resolved and Postgres live-DB introspection now exists, but the standalone, repeatable, strictly-read-only operator command described below is still unbuilt.
  • What: Operator-facing command that introspects a live database and reports differences from the committed snapshot. Strictly read-only; never generates a migration from live state. For “did someone hotfix production?”
  • What actually shipped: cratestack-migrate gained a postgres-introspect-gated introspect::postgres module (issue #204) that reads a live sqlx_postgres::PgPool into the same Projections IR the diff engine already compares — no more crate-boundary question, and no cratestack-migrate-introspect-{pg,sqlite} split was needed. It powers cratestack migrate baseline (issue #205), a related-but-distinct command: a one-time, Postgres-only adoption step that introspects a live DB, prints a drift report grouped by table, writes the initial snapshot, and seeds a synthetic cratestack_migrations row — see the migrations guide and crates/cratestack-migrate/README.md in the source repo. baseline is not the repeatable, snapshot-already-exists “did someone hotfix production?” tool this entry originally described.
  • Why deferred: A standalone cratestack migrate drift subcommand — read-only, runs repeatedly against an already-baselined database, never writes a snapshot or a migrations-table row — hasn’t been built. SQLite/embedded introspection also remains out of scope (no long-lived “existing production database” story exists for embedded targets today, per docs/design/migrate-baseline.md §6 in the source repo).
  • Unblocks on: Deciding whether migrate baseline --strict (already Postgres-only, already produces a drift report) is extended into a genuinely repeatable read-only mode, or whether drift ships as its own thin command reusing the same introspect::postgres + diff_projections pipeline.

DropEnumVariant

  • Status: Designed
  • What: Diff op + Postgres emission for removing a single enum variant. Multi-step: create new type, ALTER COLUMN … TYPE new_enum USING (…) on every referencing table, drop old type.
  • Why deferred: Postgres has no DROP VALUE, so the migration is a sequence of ops + a backfill plan for any rows already holding the dropped variant. The IR-level sequencing is tractable; the backfill is the developer’s responsibility but the generator should at least scaffold the swap-dance.
  • Unblocks on: Designing the IR shape for multi-op sequences with a hand-written up.pre.sql slot for the backfill.

Views and materialized views

Tracking ADR 0003 — the view block, @@materialized, and the migration IR ops (CreateView/ReplaceView/DropView/CreateMaterializedView/DropMaterializedView) have all shipped; see Current State and the Views reference for the current surface. The one genuinely deferred item in this area:

Time-based and event-driven materialized-view refresh

  • Status: Deferred
  • What: @@materialized(refresh = "5m") for scheduler-driven refresh; event-driven refresh wired to ModelEvent streams with debounce.
  • Why deferred: CrateStack has no scheduler primitive yet, and spawning tokio::task from the macro is the wrong layer. Event-driven refresh additionally needs a debounce-window configuration the schema can’t naturally express. Both are application-layer concerns until proven otherwise.
  • Unblocks on: A scheduler primitive (separate proposal), and a concrete use case that justifies framework-level refresh trigger semantics over app-level cron / job-runner code.

Multi-database server support

MySQL and SQLite-via-sqlx for the server backend

  • Status: Partial (architectural seam in place)
  • What: include_server_schema!(..., db = Postgres) already accepts a db = … argument. MySQL and SQLite-via-sqlx are non-breaking future additions.
  • Why deferred: Postgres is the only wired implementation today; each additional backend needs its own SQL emitter and dialect tests.
  • Unblocks on: Concrete demand. The seam is wide enough that adding a backend doesn’t require a rewrite.

Transport and codecs

transport rest and transport rpc are both shipped today — see Current State. They are the only two transports: protobuf/gRPC support was removed in 0.8.5 (ADR 0017). The items below are the remaining deferred seams, not a list of missing transports.

COSE transport envelope

  • Status: Designed
  • What: COSE envelope layer over the existing CBOR codec — signed / encrypted bodies for service-to-service authentication and message integrity.
  • Why deferred: Unimplemented seam in the transport architecture; the codec layer is ready for it but the envelope wiring isn’t done.
  • Unblocks on: A concrete use case that needs envelope-level crypto rather than transport-level TLS.

Negotiated multi-codec routing

  • Status: Partial
  • What: End-to-end content negotiation between JSON and CBOR on a per-route basis, including Accept-header–driven response codec selection.
  • Why deferred: Routing is partially spiked; codec implementations themselves (JSON, CBOR) are first-class. The negotiation is the remaining seam.
  • Unblocks on: Closing the routing seam.

WebSocket binding + subscriptions for transport rpc schemas

  • Status: Designed, runtime pending — the next cool upgrade for the transport surface.
  • What: A GET /rpc/ws upgrade for transport rpc schemas, multiplexing Request / Response / StreamItem / StreamEnd / Cancel / Error frames over a long-lived channel. Unlocks subscriptionsmodel.<X>.subscribe ops that stream ModelEvent<X> frames over the bus until the client cancels — and any future bidirectional-stream call shape.
  • Why deferred: The HTTP surface of the RPC binding shipped feature-complete in PRs #20–#24. Streaming was clearly motivated (list-return procedures, audit feeds, paginated reads — concrete shapes that fell out of the existing sequence encoder). Subscriptions are not yet — CrateStack’s audit and event-bus consumers today are server-to-server and poll or consume from the audit sink, not over a WS channel; external clients are the natural fit but no concrete consumer is asking for them right now.
  • Unblocks on: A concrete subscription use case from a CrateStack consumer. The wire-side design is fully captured in ADR 0005 §3.4 and stays as the target; what’s missing is (a) a @@subscribe schema directive — OpKind::Subscription already exists in cratestack-core, no .cstack syntax produces it; (b) the WS frame loop in the macro-emitted dispatcher; (c) CratestackEventBus per-subscription bounded-buffer fan-out.

Embedded SQLite

@@audit and @@emit on embedded

  • Status: Designed (currently no-ops)
  • What: Local-journal and local-event-bus implementations for @@audit and @@emit in include_embedded_schema!, needed for sync-engine wiring.
  • Why deferred: Both attributes parse and codegen cleanly today but emit no-ops on the embedded backend. The full implementation depends on the sync-engine surface, which is itself unscheduled.
  • Unblocks on: Sync engine design.

Binary-size feature gating for embedded-only builds

  • Status: Partial workaround in place
  • What: Allow consumers of the umbrella cratestack crate to opt out of the sqlx / tokio stack on embedded-only builds.
  • Why deferred: Workspace-level feature plumbing across many crates. The workaround today is: depend directly on cratestack-macros + cratestack-rusqlite to shed the server-side weight.
  • Unblocks on: Feature-flag audit across the workspace.

Validators

Fractional bounds for @range on Decimal

  • Status: Designed
  • What: @range(min: 0.01) on amount Decimal. Today the parser only accepts i64 literal bounds, so fractional bounds aren’t expressible despite Decimal being the natural use case.
  • Why deferred: Parser change to accept fractional literals; lives outside the banking-readiness track. Documented as such in validators.
  • Unblocks on: Parser slice that adds fractional-literal support.

Policy and exposure

Richer exposure controls and field-level policy

  • Status: Partial
  • What: Broader exposure controls beyond the current policy subset, plus some field-level policy features still deferred.
  • Why deferred: The shipped policy subset is what banks need today; remaining features depend on use cases that haven’t surfaced yet.
  • Unblocks on: Concrete asks from production users.

How this list is maintained

When a slice ships, move it from this page to Current State and remove it here. When a new piece of work is proposed (ADR, design doc, or PR), add it here with Status: Proposed until it lands or gets explicitly closed. Items that get decided “not now” but still have value remain here as Deferred with a clear “Unblocks on” line — that’s what distinguishes deferred from rejected.
  1. Current State — what’s implemented today
  2. Banking Readiness — the regulated-workload primitive set
  3. Release Track — versioning and stability expectations