multi: extract kernel/package layers (forge, kiln)
commit
fdcdc31multi: extract kernel/package layers (forge, kiln)
Kernel owns mechanism (ref store, envelope, gates, effects, sync); packages own types and policy. comment → ents-forge, toolchain → ents-kiln. Dependency direction substrate → kernel → packages → cli, enforced in CI.
Assisted-by: Claude:claude-sonnet-5
Reviews
No reviews of this commit yet — record a verdict below.
Start a review
Cargo.lock
@@ -136,6 +136,33 @@
version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "cargo-platform"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0061da739915fae12ea00e16397555ed4371a6bb285431aab930f61b0aa4ba"
+dependencies = [
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "cargo_metadata"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9"
+dependencies = [
+ "camino",
+ "cargo-platform",
+ "semver",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.18",
+]
[[package]]
name = "cfg-if"
@@ -474,7 +501,6 @@
name = "ents-anchor"
version = "0.0.0"
dependencies = [
- "ents-model",
"facet",
"facet-git-tree",
"gix",
@@ -504,6 +530,27 @@
"thiserror 2.0.18",
]
+[[package]]
+name = "ents-forge"
+version = "0.0.0"
+dependencies = [
+ "ents-anchor",
+ "ents-model",
+ "ents-receive",
+ "ents-testutil",
+ "facet",
+ "facet-git-tree",
+ "figue",
+ "gix",
+ "gix-hash",
+ "gix-object",
+ "gix-ref-store",
+ "proptest",
+ "rstest",
+ "thiserror 2.0.18",
+ "uuid",
+]
+
[[package]]
name = "ents-gate"
version = "0.0.0"
@@ -521,6 +568,25 @@
"thiserror 2.0.18",
]
+[[package]]
+name = "ents-kiln"
+version = "0.0.0"
+dependencies = [
+ "ents-effect",
+ "ents-model",
+ "ents-receive",
+ "ents-testutil",
+ "facet",
+ "facet-git-tree",
+ "figue",
+ "gix",
+ "gix-hash",
+ "gix-object",
+ "gix-ref-store",
+ "rstest",
+ "tempfile",
+]
+
[[package]]
name = "ents-model"
version = "0.0.0"
@@ -970,9 +1036,12 @@
name = "git-ents"
version = "0.0.0"
dependencies = [
+ "cargo_metadata",
"ents-anchor",
"ents-effect",
+ "ents-forge",
"ents-gate",
+ "ents-kiln",
"ents-model",
"ents-query",
"ents-receive",
@@ -2756,6 +2825,10 @@
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
+dependencies = [
+ "serde",
+ "serde_core",
+]
[[package]]
name = "serde"
@@ -2764,6 +2837,7 @@
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
+ "serde_derive",
]
[[package]]
@@ -2786,6 +2860,19 @@
"syn",
]
+[[package]]
+name = "serde_json"
+version = "1.0.150"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
+dependencies = [
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
[[package]]
name = "sha1"
version = "0.10.6"
@@ -3513,3 +3600,9 @@
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b142a20ec14a91d5bc708c1dc21b080c550113d8aa77afa29635673a65dd02c5"
+
+[[package]]
+name = "zmij"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
Cargo.toml
@@ -1,16 +1,18 @@
[workspace]
resolver = "3"
members = [
- "crates/ents-anchor",
- "crates/ents-effect",
- "crates/ents-gate",
- "crates/ents-model",
- "crates/ents-query",
- "crates/ents-receive",
- "crates/ents-sync",
- "crates/ents-testutil",
- "crates/git-ents",
- "crates/gix-ref-store",
+ "crates/kernel/ents-anchor",
+ "crates/kernel/ents-effect",
+ "crates/kernel/ents-gate",
+ "crates/kernel/ents-model",
+ "crates/kernel/ents-query",
+ "crates/kernel/ents-receive",
+ "crates/kernel/ents-sync",
+ "crates/kernel/ents-testutil",
+ "crates/cli/git-ents",
+ "crates/forge/ents-forge",
+ "crates/kiln/ents-kiln",
+ "crates/substrate/gix-ref-store",
]
[workspace.package]
@@ -23,15 +25,17 @@
missing_docs = "warn"
[workspace.dependencies]
-ents-anchor = { path = "crates/ents-anchor" }
-ents-effect = { path = "crates/ents-effect" }
-ents-gate = { path = "crates/ents-gate" }
-ents-model = { path = "crates/ents-model" }
-ents-query = { path = "crates/ents-query" }
-ents-receive = { path = "crates/ents-receive" }
-ents-sync = { path = "crates/ents-sync" }
-ents-testutil = { path = "crates/ents-testutil" }
-gix-ref-store = { path = "crates/gix-ref-store" }
+ents-anchor = { path = "crates/kernel/ents-anchor" }
+ents-effect = { path = "crates/kernel/ents-effect" }
+ents-forge = { path = "crates/forge/ents-forge" }
+ents-gate = { path = "crates/kernel/ents-gate" }
+ents-kiln = { path = "crates/kiln/ents-kiln" }
+ents-model = { path = "crates/kernel/ents-model" }
+ents-query = { path = "crates/kernel/ents-query" }
+ents-receive = { path = "crates/kernel/ents-receive" }
+ents-sync = { path = "crates/kernel/ents-sync" }
+ents-testutil = { path = "crates/kernel/ents-testutil" }
+gix-ref-store = { path = "crates/substrate/gix-ref-store" }
arborium = { version = "2.18", default-features = false, features = [
"lang-rust",
"lang-toml",
@@ -57,6 +61,7 @@
acdc-converters-terminal = { git = "https://github.com/nlopes/acdc", rev = "6ae19bc2e6f0fa4254a3e9ebd1c3d2f6c7caafde" }
askama = "0.16"
axum = "0.8"
+cargo_metadata = "0.23"
figue = "5.0.0-rc.5"
facet = { version = "0.50.0-rc.0", features = ["reflect"] }
facet-pretty = "0.50.0-rc.5"
docs/abstractions.adoc
@@ -233,6 +233,31 @@
'''''
+== Layering (consequence of the abstractions)
+
+The crate graph is four layers, each depending only on the layer(s) before it: substrate, kernel, package, CLI.
+Dependencies point one way; a lower layer never depends on a higher one, checked mechanically (`layering.rs`, run in CI alongside every other test).
+
+* *Substrate* — `gix-ref-store`: the pluggable `RefStore` seam gitoxide itself does not provide.
+Extends git, not the forge; carries the `gix-` prefix per the Composition section's own rule.
+* *Kernel* — `ents-model`, `ents-anchor`, `ents-gate`, `ents-effect`, `ents-query`, `ents-receive`, `ents-sync`, `ents-testutil`.
+Owns mechanism: typed ref-store access and refs/meta layout primitives, signing and authorship, the entity envelope (typed trees, id assignment), gate execution and composition semantics, effect dispatch, adoption/inbox mechanics, yank, sync/receive plumbing, hooks.
+The kernel is declarative and generic — it defines *how* any entity is stored, verified, and run, never *which* entities exist.
+* *Package* — `ents-forge` (issues, comments, review/release/check types as they land), `ents-kiln` (toolchains).
+Owns types and policy: the domain entity structs, and any package-specific gate or effect definitions.
+A package depends on kernel crates freely, and on other packages never — `ents-forge` and `ents-kiln` do not depend on each other.
+* *CLI* — `git-ents`: the composition root.
+Depends on the kernel directly (for kernel-owned commands: `setup`, `members`, `account`, `effect`, `inbox`, `redact`, `hook`) and on every installed package (for `comment`, from `ents-forge`; `toolchain`, from `ents-kiln`).
+Mounts each package's subcommand grammar through one convention (`crate::package::Package`, in `git-ents`): a package owns its own figue action enum, defined in its own crate, and the CLI's top-level subcommand enum references that type directly — a compile-time pairing, not a runtime plugin registry, because the argument grammar is resolved from a `#[derive(Facet)]` shape at compile time, with nothing to register dynamically.
+
+The one-way rule is absolute, not just directional-on-average: a kernel crate must not depend on a package crate in any form — not a normal dependency, not a dev-dependency, not a build-dependency, not behind a feature flag.
+`ents-testutil` in particular must not know a package's types; a package needing test fixtures beyond the kernel's generic ones adds them inside its own crate, not by teaching `ents-testutil` its vocabulary.
+
+Ref-namespace segments (`refs/meta/issues/*`, `refs/meta/comments/*`, `refs/meta/toolchains/*`, and so on) stay kernel-reserved regardless of which layer owns the entity stored there: every namespace is minted by one function in `ents_model::namespace`, and a package calls that function rather than inventing its own ref layout.
+This is what keeps `meta-ref.granularity` and `meta-ref.namespace` a single, auditable surface even as entity types move between crates — a package can gain or lose ownership of a type without the ref layout itself ever needing to change.
+
+'''''
+
== Derived, not fundamental
Instances and consequences of the six, listed for orientation:
crates/ents-gate/src/verdict.rs → crates/kernel/ents-gate/src/verdict.rs
crates/ents-testutil/src/lib.rs → crates/kernel/ents-testutil/src/lib.rs
crates/ents-model/src/error.rs → crates/kernel/ents-model/src/error.rs
crates/git-ents/src/root.rs → crates/cli/git-ents/src/root.rs
crates/ents-query/src/error.rs → crates/kernel/ents-query/src/error.rs
crates/git-ents/tests/account.rs → crates/cli/git-ents/tests/account.rs
crates/ents-query/src/parse.rs → crates/kernel/ents-query/src/parse.rs
crates/ents-anchor/src/anchor.rs → crates/kernel/ents-anchor/src/anchor.rs
crates/git-ents/src/commands/setup.rs → crates/cli/git-ents/src/commands/setup.rs
crates/ents-effect/Cargo.toml → crates/kernel/ents-effect/Cargo.toml
crates/git-ents/tests/toolchain.rs → crates/cli/git-ents/tests/toolchain.rs
crates/ents-model/src/toolchain.rs → crates/kernel/ents-model/src/toolchain.rs
crates/ents-testutil/src/counting.rs → crates/kernel/ents-testutil/src/counting.rs
crates/ents-query/tests/monotone.proptest-regressions → crates/kernel/ents-query/tests/monotone.proptest-regressions
crates/git-ents/tests/reconcile.rs → crates/cli/git-ents/tests/reconcile.rs
crates/ents-query/tests/eval.rs → crates/kernel/ents-query/tests/eval.rs
crates/ents-gate/src/config.rs → crates/kernel/ents-gate/src/config.rs
crates/ents-query/src/ast.rs → crates/kernel/ents-query/src/ast.rs
crates/ents-model/src/comment.rs → crates/kernel/ents-model/src/comment.rs
crates/ents-model/src/member.rs → crates/kernel/ents-model/src/member.rs
crates/ents-anchor/src/util.rs → crates/kernel/ents-anchor/src/util.rs
crates/ents-query/src/rev.rs → crates/kernel/ents-query/src/rev.rs
crates/git-ents/tests/common/mod.rs → crates/cli/git-ents/tests/common/mod.rs
crates/ents-testutil/src/keys.rs → crates/kernel/ents-testutil/src/keys.rs
crates/gix-ref-store/src/error.rs → crates/substrate/gix-ref-store/src/error.rs
crates/ents-testutil/src/refs.rs → crates/kernel/ents-testutil/src/refs.rs
crates/ents-anchor/src/fixture.rs → crates/kernel/ents-anchor/src/fixture.rs
crates/ents-receive/src/reconcile.rs → crates/kernel/ents-receive/src/reconcile.rs
crates/ents-gate/tests/gate.rs → crates/kernel/ents-gate/tests/gate.rs
crates/git-ents/tests/cli_help.rs → crates/cli/git-ents/tests/cli_help.rs
crates/gix-ref-store/src/store.rs → crates/substrate/gix-ref-store/src/store.rs
crates/ents-query/src/eval.rs → crates/kernel/ents-query/src/eval.rs
crates/ents-gate/src/verify.rs → crates/kernel/ents-gate/src/verify.rs
crates/ents-sync/src/objects.rs → crates/kernel/ents-sync/src/objects.rs
crates/ents-effect/src/docker.rs → crates/kernel/ents-effect/src/docker.rs
crates/ents-sync/src/error.rs → crates/kernel/ents-sync/src/error.rs
crates/ents-query/src/lib.rs → crates/kernel/ents-query/src/lib.rs
crates/ents-gate/src/object.rs → crates/kernel/ents-gate/src/object.rs
crates/gix-ref-store/tests/conformance.rs → crates/substrate/gix-ref-store/tests/conformance.rs
crates/ents-model/src/effect.rs → crates/kernel/ents-model/src/effect.rs
crates/ents-query/tests/grammar.rs → crates/kernel/ents-query/tests/grammar.rs
crates/ents-query/Cargo.toml → crates/kernel/ents-query/Cargo.toml
crates/ents-model/Cargo.toml → crates/kernel/ents-model/Cargo.toml
crates/git-ents/src/main.rs → crates/cli/git-ents/src/main.rs
crates/ents-query/tests/monotone.rs → crates/kernel/ents-query/tests/monotone.rs
crates/gix-ref-store/src/loose.rs → crates/substrate/gix-ref-store/src/loose.rs
crates/ents-testutil/src/commit.rs → crates/kernel/ents-testutil/src/commit.rs
crates/ents-model/src/redaction.rs → crates/kernel/ents-model/src/redaction.rs
crates/git-ents/tests/redact.rs → crates/cli/git-ents/tests/redact.rs
crates/git-ents/tests/comment.rs → crates/cli/git-ents/tests/comment.rs
crates/ents-anchor/src/projection.rs → crates/kernel/ents-anchor/src/projection.rs
crates/git-ents/tests/worktree_update.rs → crates/cli/git-ents/tests/worktree_update.rs
crates/ents-gate/src/error.rs → crates/kernel/ents-gate/src/error.rs
crates/ents-sync/Cargo.toml → crates/kernel/ents-sync/Cargo.toml
crates/ents-effect/src/results.rs → crates/kernel/ents-effect/src/results.rs
crates/git-ents/src/commands/mod.rs → crates/cli/git-ents/src/commands/mod.rs
crates/gix-ref-store/src/lib.rs → crates/substrate/gix-ref-store/src/lib.rs
crates/git-ents/src/commands/inbox.rs → crates/cli/git-ents/src/commands/inbox.rs
crates/ents-gate/Cargo.toml → crates/kernel/ents-gate/Cargo.toml
crates/ents-receive/src/sink.rs → crates/kernel/ents-receive/src/sink.rs
crates/ents-effect/src/definition.rs → crates/kernel/ents-effect/src/definition.rs
crates/git-ents/tests/members.rs → crates/cli/git-ents/tests/members.rs
crates/git-ents/src/exe.rs → crates/cli/git-ents/src/exe.rs
crates/ents-effect/src/toolchain.rs → crates/kernel/ents-effect/src/toolchain.rs
Diff truncated (over 1 MiB).