Skip to content

Command/backend/contract architecture; unify commands under commands/ - #53

Open
Seth Ockerman (OckermanSethGVSU) wants to merge 1 commit into
masterfrom
refactor-command-backend-contracts
Open

Command/backend/contract architecture; unify commands under commands/#53
Seth Ockerman (OckermanSethGVSU) wants to merge 1 commit into
masterfrom
refactor-command-backend-contracts

Conversation

@OckermanSethGVSU

Copy link
Copy Markdown
Collaborator

Summary

Reorganizes supernova from a language-oriented layout (crates/, python/) to a command-oriented one, and introduces a language-neutral backend contract system so future nova-load / nova-storm backends (Milvus, Vespa, …) can be added and conformance-checked without touching the user-facing CLI. No new VDB backend is added here — current Qdrant behavior is unchanged and fully preserved.

New layout

commands/            every user-facing nova-* command (Rust + Python together)
  nova-load/         SHIM (Rust): reads vectorstore.type, execs the backend
  nova-storm/        SHIM (Rust): reads target.type, execs the backend
  nova-shim/         shared shim front-controller LIB (not a command)
  nova-contract/     generic language-neutral conformance checker
  nova-inspect/      moved from crates/
  nova-embed, nova-bf, nova-opt, nova-sweep, nova-dist   moved from python/
backends/
  nova-load/qdrant   -> nova-load-qdrant   (moved from crates/nova-load)
  nova-storm/qdrant  -> nova-storm-qdrant  (moved from crates/nova-storm)
  nova-{load,storm}/contracts/rust   shared Rust trait each backend implements
contracts/
  nova-{load,storm}/{v1.yaml,README.md}   canonical language-neutral specs
tests/contracts/     conformance-fixture dirs per command

Two-layer contract enforcement

  1. Compile-time (per language): a Rust backend depends on backends/<cmd>/contracts/rust and implements the shared trait (VectorStore for load, QueryTarget for storm, plus neutral types). A missing or mistyped method won't compile.
  2. Runtime (cross-language): each backend advertises capabilities --json; nova contract check <backend-exe> --contract <yaml> validates it against the neutral spec (--level shape | dry-run | live). This works for a backend in any language — it only ever talks to the executable. Checks target the backend, never the shim.

Keep the three in lockstep when changing a contract: the Rust trait, the v1.yaml, and each backend's capabilities_json().

Dispatch — UX preserved

nova load ... / nova storm ... / nova sweep ... are unchanged. The shim reads only the backend selector (vectorstore.type / target.type), maps qdrantnova-<cmd>-qdrant, and execs it (process replacement — stdin/stdout/stderr and exit code/signals pass straight through, including storm's single --json summary line). Unknown type → exit 127 with an install hint. The two shims share all logic via nova-shim, so they can't drift.

Adding a future backend = new backends/<cmd>/<name>/ building nova-<cmd>-<name>, implement the trait, advertise capabilities, pass nova contract check. A config with type: <name> then dispatches automatically — no shim change.

Other changes

  • capabilities --json added to both Qdrant backends (kept in lockstep with the specs).
  • Makefile: make load/make storm install both shim and backend; new make contract; make test now also runs contract checks at dry-run level.
  • CI (rust-binaries.yml) + nova-dist updated to build/install both the shim and the backend on fleet workers (a worker needs both).
  • Backend package/binary renamed to nova-<cmd>-qdrant; library crate names kept (nova_load / nova_storm) so internal module paths are unchanged. The neutral StoreError/TargetError drop their qdrant variant; qdrant errors convert at the trait boundary via .map_err(…::backend).
  • Docs updated: README.md, AGENTS.md, and new contracts/*/README.md + commands/README.md.

Testing

  • cargo test: 87 pass (16 suites) — behavior preserved.
  • nova contract check against both backends: PASS (shape/dry-run/live); a negative case (load backend vs storm contract) correctly FAILs with exit 1.
  • Shim dispatch verified: default type, unknown-type → 127, and shim output byte-identical to calling the backend directly (stderr + exit code).
  • nova-bf pytest 352 passed, 1 skipped; nova-sweep pytest 36 passed; nova-embed has no suite (pre-existing).
  • Live Qdrant end-to-end through the shims: load 300 vectors → storm exact search → recall 1.0/1.0/1.0, 0 errors → delete; nova-sweep full load → reindex → storm --json → delete orchestration → 2 rows, 0 errors.
  • nova-embed (MiniLM-L6, CPU) and nova-bf (compute+merge, 54/54 self-match) exercised end-to-end locally; nova-inspect runs from its new path.

Notes / risks

  • Python packages (nova-embed/bf/opt/sweep/dist) and nova-inspect were moved into commands/ too, so the layout is uniformly command-oriented. nova-opt is a WIP tracked on another branch (only git-ignored artifacts in this checkout).
  • nova-dist and the CI release workflow were updated to produce/install both binaries, but the fleet path was not live-tested (AWS/SkyPilot) — the change is mechanical.
  • The nova dispatcher (src/cli/) intentionally stays at the repo root (it's the zero-dep root package); it now also lists backends as nova load-qdrant/storm-qdrant, which is harmless and consistent with its zero-opinion design.

🤖 Generated with Claude Code

… commands/

Reorganize from a language-oriented layout (crates/, python/) to a
command-oriented one, and add a language-neutral backend contract system so
future nova-load / nova-storm backends can be added and conformance-checked
without touching the user-facing CLI. Qdrant behavior is unchanged.

Layout
- commands/ — every user-facing nova-* command (Rust and Python together):
    nova-load, nova-storm : thin Rust SHIMS that read the backend selector from
                            the config and exec the backend, argv intact
    nova-shim             : shared shim front-controller lib (dedups the two
                            shims; dispatch logic defined once, cannot drift)
    nova-contract         : generic language-neutral conformance checker
    nova-inspect          : moved from crates/
    nova-embed, nova-bf, nova-opt, nova-sweep, nova-dist : moved from python/
- backends/ — implementations behind command contracts:
    nova-load/qdrant  -> nova-load-qdrant   (moved from crates/nova-load)
    nova-storm/qdrant -> nova-storm-qdrant  (moved from crates/nova-storm)
    nova-{load,storm}/contracts/rust : shared Rust interface each Rust backend
                                       implements (VectorStore / QueryTarget +
                                       neutral types) — compile-time enforcement
- contracts/ — canonical language-neutral specs (v1.yaml) + docs

Two-layer contract enforcement
- Compile-time: a Rust backend depends on backends/<cmd>/contracts/rust and
  implements the trait; a missing/mistyped method won't build.
- Runtime/cross-language: each backend advertises `capabilities --json`;
  `nova contract check <backend-exe> --contract <yaml>` validates it against the
  neutral spec (levels: shape | dry-run | live). Checks target backends, not shims.

Dispatch (UX preserved)
- `nova load ...` / `nova storm ...` unchanged. The shim reads only
  vectorstore.type / target.type, maps qdrant -> nova-<cmd>-qdrant, and execs it
  (process replacement — stdout/stderr/exit code pass straight through, incl.
  storm's --json line). Unknown type -> exit 127 with an install hint.

Other
- capabilities --json added to both backends (kept in lockstep with the specs).
- Makefile: load/storm install shim + backend; add `contract`; `make test` runs
  contract checks at dry-run level.
- CI + nova-dist updated to build/install both shim and backend on the fleet.
- backend package/binary renamed to nova-<cmd>-qdrant; lib names kept
  (nova_load / nova_storm) so internal module paths are unchanged.

Tests: cargo test (87) green; contract checks pass; nova-bf (352p/1s) and
nova-sweep (36) pytest green; live Qdrant load->storm recall 1.0/1.0/1.0;
nova-embed and nova-bf exercised end-to-end locally.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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