Dependencies and version propagation
Distinguish dependency ordering, automatic version propagation, and cross-ecosystem depends-on edges.
Semifold places packages from every built-in ecosystem and plugin into one dependency graph. The graph answers two separate questions:
- which package must be processed first for edits, builds, and publishing;
- whether publishing a dependency also requires a release of its dependent.
“Participates in ordering” does not mean “automatically publishes.” This distinction is essential when reading smif status.
Manifest dependencies always participate in ordering
When an adapter can uniquely match a manifest dependency to a package in the same ecosystem, it becomes an internal graph edge. Rust runtime, development, and build dependencies, together with recognized Node.js, Python, and C++ dependencies, all participate in deterministic topological ordering.
Dependencies appear before dependents. Unrelated packages are ordered by stable PackageId, so repeated runs do not produce arbitrary sequences.
Current automatic propagation rules
| Dependency source | Participates in ordering | Automatically releases the dependent |
|---|---|---|
Rust [dependencies] | yes | only when the dependency's new version no longer satisfies the Rust requirement; the dependent receives patch |
| Rust development/build dependency | yes | no |
| Node.js, Python, or C++ manifest dependency | yes | no |
Configured depends-on | yes | yes; the dependent receives patch |
Semifold does not approximate npm, PEP 440, or CMake constraints with Rust semver. Their manifest edges currently determine order only. When a lower-level package release must rebuild and republish a binding, declare depends-on explicitly.
Declare a cross-ecosystem relationship
Reference the dependency's stable PackageId from the dependent package:
[packages.rust-core]
path = "crates/core"
resolver = "rust"
[packages.node-binding]
path = "bindings/node"
resolver = "nodejs"
depends-on = ["rust-core"]This edge has three effects:
rust-coreis edited and published beforenode-binding;- any
rust-corerelease gives an otherwise unchangednode-bindingapatchrelease; - if
node-bindingalready has aminorormajorchangeset, the higher bump remains and the propagation reason is added.
depends-on may also connect packages in the same ecosystem when a manifest cannot express a rebuild or republish relationship.
How names are matched
Manifest dependencies match by ecosystem plus manifest name, not directly by PackageId. Therefore:
- a dependency outside the workspace remains external;
- duplicate manifest names within one ecosystem are ambiguous and fail loading;
- equal names in different ecosystems never create an implicit edge;
depends-onmust use the exactPackageIdfrom configuration.
Diagnose unexpected propagation
Run:
smif statusEvery planned package lists either a direct changeset or a dependency-propagation reason. If the result is surprising, check in order:
- whether the changeset names the correct
PackageId; - whether a Rust runtime requirement still includes the dependency's new version;
- whether each
depends-onrepresents a real republish requirement; - whether manifest names are accidentally duplicated.
Unknown PackageId values and dependency cycles stop planning with structured errors. Remove a cycle from the manifests or configuration; Semifold does not hide it by selecting an arbitrary order.