Skip to content
Merged
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
3 changes: 2 additions & 1 deletion crates/turborepo-repository/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ Repository root

Key types:
- `PackageGraph` - Graph of workspace packages and their dependencies
- `PackageInfo` - Metadata about a single package
- `RepositoryKnowledge` - Immutable authority for package and aggregate identities, paths, kinds, and toolchain provenance
- `PackageInfo` - Temporary JavaScript-shaped manifest compatibility payload; not package identity or path authority
- `PackageManager` - Abstraction over npm/pnpm/yarn/bun

## Notes
Expand Down
6 changes: 3 additions & 3 deletions crates/turborepo-repository/src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ pub enum CargoPackageKind {
/// Build, run, and verification tasks execute
/// `cargo <verb> --package=<crate>`.
Entrypoint,
/// The synthetic user-named workspace package hosting workspace-scoped
/// The user-named workspace aggregate hosting workspace-scoped
/// verification tasks (`cargo test --workspace`, ...).
Workspace,
}
Expand All @@ -358,11 +358,11 @@ pub enum CargoPackageKind {
pub struct CargoPackageDetails {
pub kind: CargoPackageKind,
/// The crate's deliverable targets (empty for libraries and the
/// workspace package).
/// workspace aggregate).
pub deliverables: Vec<Deliverable>,
pub manifest_alters_output_layout: bool,
/// The crate's directory, repo-root-relative in unix form (empty for
/// the synthetic workspace package).
/// the workspace aggregate).
pub dir: String,
/// A conservative transitive closure of declared local dependencies. This
/// is separate from the package graph because Cargo permits dev-dependency
Expand Down
10 changes: 5 additions & 5 deletions crates/turborepo-repository/src/toolchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@ impl fmt::Display for ToolchainId {
///
/// Identity and source facts feed [`crate::knowledge::RepositoryKnowledge`].
/// `descriptor` remains temporary compatibility input for relationship
/// classification, JavaScript lockfile state, and task consumers. JavaScript
/// packages retain their parsed manifest; native producers can contribute
/// normalized relationships separately without synthesizing JavaScript
/// dependency maps. Cargo still supplies an empty descriptor until task
/// compatibility payloads are removed.
/// classification and JavaScript construction paths. JavaScript packages retain
/// their parsed manifest; native producers can contribute normalized
/// relationships and tasks separately without synthesizing JavaScript
/// dependency maps. Cargo still supplies an empty descriptor only because graph
/// assembly currently requires a compatibility payload for every scope.
#[derive(Debug, Clone)]
pub struct DiscoveredPackage {
/// Real user-facing identity, extracted by the native producer. `None`
Expand Down
49 changes: 27 additions & 22 deletions crates/turborepo/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,15 +292,18 @@ membership/workspace/resolution triggers) combined with active toolchain
Native discovery output contributes package/scope observations to repository
knowledge, while a
`Toolchain` continues to answer ecosystem-specific behavioral questions such as
what command a task runs and what hash wiring a task derives. All lookups go through the
entrypoint selection, derived task I/O, affectedness, and prune rendering. Native
task availability and commands come from immutable repository catalogs. Remaining
behavioral lookups go through the
`ToolchainRegistry` (carried by the `PackageGraph`); `ToolchainId` is an
open string identifier, not a closed enum; and trait methods are
coarse-grained and data-in/data-out, keeping the door open to out-of-process
plugin adapters. JavaScript is the first, production implementation: its
discovery, script command construction, and phantom-task detection flow
through the trait. Machinery that predates the abstraction and has no trait
surface yet (package-manager resolution for dependency splitting, the JS
lockfile closure phase) is documented as known debt in the module.
discovery produces package, relationship, task, contract, change, and prune
knowledge without runtime task-command callbacks. Machinery that predates the
abstraction and has no trait surface yet (package-manager resolution for
dependency splitting and the JS lockfile closure phase) is documented as known
debt in the module.

Toolchain-derived I/O receives the same task-scoped arguments as execution plus
a narrow, platform-aware startup-environment projection keyed by toolchain.
Expand Down Expand Up @@ -348,19 +351,21 @@ whether anything changed; Cargo decides how and in what order to build.**
*Entrypoints* (crates with `bin`/`cdylib`/`staticlib` targets) are the
workspace's deliverables. *Libraries* exist in the package graph and expose
filtered build and verification tasks. Unfiltered builds prefer entrypoints
because Cargo builds their library dependency closures implicitly. A synthetic
*workspace* scope — named by the user via `[workspace.metadata] name` in
because Cargo builds their library dependency closures implicitly. A
user-named *workspace* scope — declared via `[workspace.metadata] name` in
the root Cargo.toml, a hard requirement — is an aggregate in repository
knowledge. Its compatibility package depends on every crate and hosts
knowledge. Its normalized relationships point to every crate, and it hosts
workspace-scoped verification verbs.
- **Execution and entrypoint selection** (`Toolchain::task_command` and
- **Execution and entrypoint selection** (`NativeTaskKnowledge`, native command
resolution in `turborepo-task-executor`, and
`Toolchain::select_task_entrypoints`): crate-scoped build and verification
tasks run `cargo <verb> --package=<crate> --locked`; entrypoints also expose
`run`/`dev`. Unfiltered builds prefer entrypoints, falling back to libraries
when the workspace has no entrypoints. Unfiltered verification uses the synthetic workspace package:
when the workspace has no entrypoints. Unfiltered verification uses the Cargo
workspace aggregate:
`<name>#test` runs `cargo test --workspace --locked`, `<name>#lint` runs
`cargo clippy --workspace --locked`, etc. Filtered runs use their selected
crates; selecting only the workspace package uses its workspace command.
crates; selecting only the workspace aggregate uses its workspace command.
`RunBuilder` combines filter mode with the resolved package scope to derive
task-specific exclusions. `EngineBuilder` applies package-level exclusions
before traversal; task-level filtering defers selection until after matching
Expand All @@ -371,11 +376,11 @@ whether anything changed; Cargo decides how and in what order to build.**
(except `cargo run`) share a mutually-exclusive serial group: concurrent
cargo processes serialize on the build-directory lock anyway, so the
executor runs one at a time without the "waiting for file lock" noise. Run
summaries derive display commands from the same verb tables via
`Toolchain::task_display_command`, so display cannot drift from execution.
- **Task registration** (`Toolchain::registered_tasks`): every crate implicitly
summaries read the same resolved native command catalog as execution, so
display cannot drift from execution.
- **Task registration** (`NativeTaskKnowledge`): every crate implicitly
registers `build`; entrypoints with exactly one binary also register `run`
and its `dev` alias. Every crate and the workspace package register `test`, `check`,
and its `dev` alias. Every crate and the workspace aggregate register `test`, `check`,
`clippy`/`lint`, `bench`, and `doc`/`docs`. These act as empty task definitions
at the lowest precedence, so normal
`tasks` entries configure or override them and package configuration can
Expand All @@ -398,15 +403,15 @@ whether anything changed; Cargo decides how and in what order to build.**
configuration, native compiler and
archiver settings (including target-qualified forms), and platform SDK
selection. Arbitrary variables consumed by project-specific build scripts
remain explicit task `env` configuration. The workspace package hashes all
remain explicit task `env` configuration. The workspace aggregate hashes all
crate directories instead of default-hashing the repo root.
`$TURBO_DEFAULT$` in a Cargo task's `inputs` means "everything turbo
derives automatically", so extra inputs (e.g. a file embedded via
`include_str!` from outside any crate directory) are additive.
- **External dependencies** (`turborepo-lockfiles/src/cargo.rs`): locked
registry/git packages and the compiler itself flow through the same
external-dependency hash JS packages use
(`PackageInfo.transitive_dependencies`). Each crate's closure is computed
`ExternalResolutionGeneration` and resolution fingerprint used by JavaScript
packages. Each crate's closure is computed
from `Cargo.lock` (identity = version + source + checksum, so git rev
bumps count). Source-qualified lockfile edges distinguish identical
name/version packages from different registries or git references, so each
Expand Down Expand Up @@ -493,7 +498,7 @@ whether anything changed; Cargo decides how and in what order to build.**
synchronization failures are warnings. In docker layout,
the json layer carries the root manifest, each kept crate's `Cargo.toml`, and
finalized lock; sources go to the full layer. A
package anchored at the repo root (the synthetic workspace package) is not
aggregate anchored at the repo root (the Cargo workspace scope) is not
a pruneable target.

- **Compile cache** (`Toolchain::compile_cache_env`, consumed by
Expand Down Expand Up @@ -565,9 +570,9 @@ The core task graph consists of:
(`futureFlags.experimentalTaskCommand`) in one place
(`resolve_command_override`, `turborepo-engine`'s
`builder/definitions.rs`), across five precedence levels: Package
Configuration `command` → root `pkg#task` `command` → package-authored
script (`Toolchain::authors_task`) → unscoped root default (per-toolchain
maps fan out by toolchain id) → the toolchain's own resolution. The
Configuration `command` → root `pkg#task` `command` → authored native task
from `NativeTaskKnowledge` → unscoped root default (per-toolchain maps fan out
by toolchain id) → the catalog's synthesized native command. The
resolved override is authoritative in both directions — an argv executes
even where the toolchain defines nothing, an opt-out never executes even
where it does — and feeds global-deps hashing, the TUI task list, the
Expand Down
Loading