Typed dependency-tree and explain models for cabin tree and
cabin explain.
cabin metadata already exposes the loaded package state as
a deterministic JSON document. This crate adds two
complementary, lower-bandwidth views on the same loaded
PackageGraph + lockfile + active patch / source-replacement
state:
-
[
build_tree] returns a [TreeNode] showing every package in the loaded [PackageGraph] reachable from the selected primary packages, with edges tagged by [cabin_core::DependencyKind] and provenance pulled from the lockfile / active patch set. Renderers ([render_tree_human] / [render_tree_json]) turn the typed tree into either a stable text drawing or a structured JSON document; the JSON document shares its package shape withcabin metadata. -
[
explain_package] / [explain_target] / [explain_source] / [explain_feature] / [explain_build_config] each return a typed [Explanation] answering "why is X selected", "where does X come from", "which feature lit up X", and "what does the build configuration look like for X". Each variant carries only structured data so callers can render either a human-readable summary ([render_explanation_human]) or a stable JSON document ([render_explanation_json]).
Crate boundaries:
- this crate must not run the resolver, parse manifests, or plan builds; it consumes the typed values the orchestration layer hands it;
- it must not perform I/O. The orchestration layer in
cabinis responsible for loading the workspace, the lockfile, and the active patch set; this crate works purely on those typed inputs; - it must not invent new identity for packages. Provenance
comes from
cabin_workspace::PackageKind, the lockfile, the patch set, and the source-replacement settings.
Determinism contract
Every output produced by this crate is deterministic across runs:
- tree children are sorted by
(dependency_kind, package_name, package_version); - explanation paths are sorted by
(length, joined name sequence); - JSON keys are emitted in struct-declaration order;
- paths surfaced through the API are not normalized here — that is the orchestration layer's job.
Anything that mutates the inputs is the orchestration layer's responsibility; this crate only reads them.