Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,18 @@ jobs:
with:
tool: ripgrep
- run: ./shepherd/scripts/check-cow-orderbook-only.sh

# Blocking dep-sync gate: the three-grouping crate DAG points strictly
# up, and the carve dependency artefacts (umbrella [patch], git-tag
# pins, per-group Cargo.repo.toml, wit-deps locks) agree wherever they
# exist (scripts/check-dep-sync.sh; docs/design/cross-repo-deps.md).
dep-sync:
name: dep-sync
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: ./.github/actions/rust-setup
- uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2
with:
tool: ripgrep
- run: ./scripts/check-dep-sync.sh
59 changes: 59 additions & 0 deletions docs/design/cross-repo-deps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Cross-repo dependencies

How the three repos source each other after the carve, and how the
transitional umbrella keeps the monorepo building as one workspace until
then. The repos: `nullislabs/nexum-runtime` (the `nexum/` grouping,
including `nexum-world`), `nullislabs/videre-nexum-module` (`videre/`),
and `nullislabs/shepherd` staying as the app-level bundle (`shepherd/`).
Dependencies flow strictly up: shepherd on videre and nexum-runtime,
videre on nexum-runtime, nexum-runtime on neither. Plan:
`docs/design/videre-split-plan.md` (design-notes branch), section 6.2
decisions D9 and D10.

## Transitional umbrella (pre-carve)

- One workspace, one hoisted dependency table, one `Cargo.lock`, atomic
folds across the groupings.
- Member manifests write cross-group Rust dependencies in their final
post-carve form: exact git-tag pins on the owning repo, one tag per
repo.
- The umbrella root `[patch]` table redirects each pinned repo URL to
the in-tree crate, so the monorepo builds the working tree, not the
tag, and stays green through the whole train.
- Each grouping carries `Cargo.repo.toml`, the workspace root it ships
with at carve time; its member list mirrors the umbrella's members
for that grouping.
- Each grouping resolves WIT crate-locally; cross-group WIT is sourced
through `wit-deps` git tags with checked-in locks
(`<group>/wit/deps.toml` plus `deps.lock`).

## Convergence path (decision D9)

1. Git-tag pins, at carve time: cross-repo Rust deps are exact `tag`
pins, cross-repo WIT rides `wit-deps` git tags, locks are committed.
No semver resolution; a bump is an explicit repin downstream.
2. crates.io, once the surfaces stabilise: `nexum-runtime` and the
videre crates publish; downstreams move to caret ranges; the
`[patch]` table and the git pins disappear.
3. wkg/OCI, alongside crates.io: the WIT packages publish to
`ghcr.io/nullislabs`; `wit-deps` git sources become registry
fetches.
4. shepherd stays app-level: it pins upstream tags and never publishes.

## Enforcement

`scripts/check-dep-sync.sh`, blocking as the `dep-sync` CI job and
locally via `just check-dep-sync`:

- the crate DAG points strictly up across the groupings for every
workspace member, including path deps and `wit/` symlinks;
- every umbrella `[patch]` entry targets the owning grouping's in-tree
crate and neutralises a written pin, with no orphans;
- git-tag pins agree on one tag per upstream repo everywhere they are
written;
- each `Cargo.repo.toml` member list mirrors the umbrella's;
- `wit-deps` manifests and locks exist together, stay key-synced, and
their tags agree with the Rust pins and across groups.

A check whose artefact is not yet written skips visibly and starts
enforcing the moment the artefact lands.
5 changes: 5 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ check-venue-agnostic:
check-cow-orderbook-only:
./shepherd/scripts/check-cow-orderbook-only.sh

# Dep-sync gate: the three-grouping crate DAG points strictly up and
# the carve dependency artefacts agree. Blocking in CI.
check-dep-sync:
./scripts/check-dep-sync.sh

# Check the entire workspace
check:
cargo check --target wasm32-wasip2 -p example
Expand Down
3 changes: 2 additions & 1 deletion nexum/crates/nexum-runtime/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
//!
//! `nexum:host` is a leaf package: the host `event` variant carries a
//! status transition as opaque bytes, so the core world resolves against
//! `wit/nexum-host` alone. An extension's bindgen remaps onto the shared
//! `wit/nexum-host` alone; the group `wit/deps.toml` and its lock stay
//! empty. An extension's bindgen remaps onto the shared
//! interfaces here with `with`, so the `Host` impls and the `fault` type
//! its components see are the very ones the core host constructs.
//! `PartialEq` is derived so extension services can compare event payloads.
Expand Down
18 changes: 17 additions & 1 deletion nexum/scripts/check-venue-agnostic.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
# charter symbol
# (nexum:intent|value-flow|VenueAdapter|synthesize_venue|nexum:adapter|PoolRouter)
# and no privileged router field; and nexum:host names no foreign WIT
# package and resolves as a leaf. The opaque-status envelope
# package, resolves as a leaf, and its wit-deps manifest and lock stay
# empty. The opaque-status envelope
# (intent-status-update, its venue id string) is ratified host surface,
# not a leak. Blocking in CI; run locally via `just check-venue-agnostic`.

Expand Down Expand Up @@ -84,4 +85,19 @@ else
printf '\033[1;33m[l1 WARN]\033[0m wasm-tools not found; WIT resolve skipped\n' >&2
fi

# 5. wit-deps manifest: crate-local resolution with an empty, locked
# dependency set; a declared dependency would unmake the leaf.
for f in wit/deps.toml wit/deps.lock; do
if [[ ! -f $f ]]; then
fail "$f missing"
continue
fi
rg -n --no-heading -e '^\s*[^#[:space:]]' "$f"
case $? in
0) fail "$f declares a WIT dependency; nexum:host is a leaf" ;;
1) pass "$f empty" ;;
*) fail "manifest scan errored for $f" ;;
esac
done

exit "$status"
Empty file added nexum/wit/deps.lock
Empty file.
1 change: 1 addition & 0 deletions nexum/wit/deps.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# nexum:host is a leaf package; this manifest stays empty.
Loading