Skip to content

Commit b4c8d6e

Browse files
committed
docs: expand cargo-first vendoring playbook
1 parent cf70df5 commit b4c8d6e

1 file changed

Lines changed: 196 additions & 45 deletions

File tree

‎docs/dependency-vendoring.md‎

Lines changed: 196 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,247 @@
1-
# Dependency Vendoring
1+
# Dependency Vendoring (Cargo-First)
22

3-
Flow now uses a split model:
3+
This project uses a Cargo-first vendoring model:
44

5-
- `nikivdev/flow-vendor` is the canonical vendored source repo.
6-
- `flow` pins an exact vendor commit in `vendor.lock.toml`.
7-
- `lib/vendor/*` is local materialized source for Cargo path patches.
5+
- Cargo remains the resolver, lockfile authority, and build system.
6+
- Vendored source is owned in `nikivdev/flow-vendor`.
7+
- `flow` pins vendored state by commit in `vendor.lock.toml`.
8+
- `flow` uses `[patch.crates-io]` path overrides into `lib/vendor/*`.
89

9-
## Goals
10+
This gives direct dependency control without giving up Cargo behavior.
1011

11-
- Full dependency ownership and aggressive trim capability.
12-
- Fast iteration in `flow` without polluting `flow` history with vendored source churn.
13-
- Deterministic, lock-pinned hydration from vendor source.
12+
## Why This Model
1413

15-
## Core Files
14+
### Problem
1615

17-
- `vendor.lock.toml`: vendor repo URL/branch/checkout path, pinned commit, crate mapping.
18-
- `scripts/vendor/vendor-repo.sh`: lifecycle orchestration (init/import/hydrate/pin/status/push).
19-
- `lib/vendor-manifest/*.toml`: crate metadata used for update checks.
16+
- crates.io + transitive dependency growth hurts compile times and iteration speed.
17+
- upstream crates can pull convenience dependencies, macros, and features we do not need.
18+
- editing third-party code in-place inside the main repo pollutes history and makes updates hard.
2019

21-
## Vendor Repo Layout (`flow-vendor`)
20+
### Requirements
2221

23-
- `crates/<crate>/`: materialized crate source trees.
24-
- `manifests/<crate>.toml`: per-crate sync metadata.
25-
- `profiles/flow.toml`: crate list for Flow hydration.
22+
- keep Cargo benefits (resolver correctness, lock semantics, ecosystem compatibility),
23+
- gain direct control over dependency source and shape,
24+
- keep upstream sync fast and automatable,
25+
- keep repository history readable.
2626

27-
## Flow Workflow
27+
### Result
2828

29-
1. Initialize vendor checkout (local clone or local bootstrap):
29+
- dependency source churn lives in `flow-vendor`,
30+
- application-level pin and wiring lives in `flow`,
31+
- updates are reproducible and lock-pinned,
32+
- trim/refactor opportunities are local and fast.
3033

31-
```bash
32-
scripts/vendor/vendor-repo.sh init
33-
```
34+
## Benefits
35+
36+
- Faster local iteration by removing unneeded dependency surface area.
37+
- Ability to aggressively trim crates to exactly what `flow` uses.
38+
- Deterministic hydration in CI and local environments from a pinned vendor commit.
39+
- Clean `flow` history: metadata/pins in `flow`, source churn in `flow-vendor`.
40+
- Upstream updates remain scriptable and reviewable.
41+
42+
## Core Files and Their Roles
43+
44+
- `vendor.lock.toml`
45+
- Source of truth for vendor remote, branch, checkout, pinned commit, and crate map.
46+
- `Cargo.toml`
47+
- `[patch.crates-io]` points selected crates to `lib/vendor/<crate>`.
48+
- `Cargo.lock`
49+
- Must resolve vendored crates by path (no registry source for vendored entries).
50+
- `lib/vendor/<crate>`
51+
- Materialized source tree used by Cargo path patches.
52+
- `lib/vendor-manifest/<crate>.toml`
53+
- Per-crate metadata for version/provenance/sync and verification.
54+
- `scripts/vendor/*`
55+
- Toolkit for inhouse, hydrate, status, sync, and vendor-repo operations.
56+
57+
## Repositories
58+
59+
### `flow` repo
60+
61+
- owns pins, manifests, trim logic hooks, and Cargo wiring.
62+
- should not include full vendored source history churn.
63+
64+
### `flow-vendor` repo
3465

35-
2. Import current local materialized crates into vendor repo and pin lock commit:
66+
- canonical storage for vendored crate source (`crates/<crate>`),
67+
- vendored crate manifests (`manifests/<crate>.toml`),
68+
- profile metadata used during hydration.
69+
70+
## Operating Principle: Cargo First
71+
72+
Do not replace Cargo. Use Cargo as the system of record:
73+
74+
- resolve versions through `Cargo.lock`,
75+
- use `cargo update -p <crate> --precise <version>` for deterministic lock rewrites,
76+
- build and validate with normal Cargo commands (`cargo check`, `cargo test --no-run`),
77+
- use vendoring only as controlled source substitution via patches.
78+
79+
## Standard Workflow (One Crate)
80+
81+
Recommended entrypoint:
3682

3783
```bash
38-
scripts/vendor/vendor-repo.sh import-local
84+
/Users/nikiv/code/rise/scripts/vendor-control.sh inhouse --project /Users/nikiv/code/flow <crate> [version]
3985
```
4086

41-
3. Hydrate `lib/vendor/*` from pinned vendor commit:
87+
What this does:
88+
89+
1. Ensures lock entry and Cargo patch wiring.
90+
2. Materializes crate from Cargo cache into `lib/vendor/<crate>`.
91+
3. Stores crate history in `lib/vendor-history/<crate>.git`.
92+
4. Writes `lib/vendor-manifest/<crate>.toml` + `UPSTREAM.toml`.
93+
5. Re-syncs `Cargo.lock` to exact vendored version.
94+
6. Applies trim hooks (`scripts/vendor/apply-trims.sh`).
95+
7. Imports local materialized source into `.vendor/flow-vendor`.
96+
8. Pins `vendor.lock.toml` to new vendor commit.
97+
98+
## Verification and Safety Gates
99+
100+
Run after each vendoring step:
42101

43102
```bash
44-
scripts/vendor/vendor-repo.sh hydrate
45-
# equivalent default path:
46-
scripts/vendor/materialize-all.sh
103+
/Users/nikiv/code/rise/scripts/vendor-control.sh verify --project /Users/nikiv/code/flow
104+
cargo check -q
105+
scripts/vendor/sync-all.sh --important --dry-run
47106
```
48107

49-
4. Inspect lock/checkout/remote state:
108+
`verify` enforces:
109+
110+
- crate exists in `vendor.lock.toml`,
111+
- crate exists in `Cargo.lock`,
112+
- no registry source for vendored crate in `Cargo.lock`,
113+
- one resolved version per vendored crate,
114+
- patch path matches lock materialized path,
115+
- manifest version matches lock version.
116+
117+
## Provenance and Hardening
118+
119+
`inhouse` now records provenance fields in crate manifests:
120+
121+
- `registry_index`
122+
- `cargo_registry_checksum`
123+
- `crate_archive_sha256`
124+
- `checksum_match`
125+
- `upstream_repository`
126+
- `upstream_homepage`
127+
- `history_head`
128+
129+
Use report mode:
50130

51131
```bash
52-
scripts/vendor/vendor-repo.sh status
132+
/Users/nikiv/code/rise/scripts/vendor-control.sh provenance --project /Users/nikiv/code/flow
53133
```
54134

55-
5. Push vendor repo updates:
135+
Use stricter mode when migrating fully:
56136

57137
```bash
58-
scripts/vendor/vendor-repo.sh push
138+
/Users/nikiv/code/rise/scripts/vendor-control.sh verify --project /Users/nikiv/code/flow --strict-provenance
59139
```
60140

61-
6. Re-pin lock to a specific vendor commit if needed:
141+
## Transactional Failure Behavior
142+
143+
`vendor-control.sh inhouse` includes rollback protection by default:
144+
145+
- snapshot relevant files before mutation,
146+
- on failure, restore pre-run `Cargo.toml`, `Cargo.lock`, `vendor.lock.toml`,
147+
- remove newly created manifest/source/history artifacts for failed crate,
148+
- restore prior vendor lock pin.
149+
150+
Escape hatch (not recommended except debugging):
62151

63152
```bash
64-
scripts/vendor/vendor-repo.sh pin <commit>
153+
/Users/nikiv/code/rise/scripts/vendor-control.sh inhouse --project /Users/nikiv/code/flow <crate> --no-rollback
65154
```
66155

67156
## Upstream Sync Loop
68157

69-
Keep existing update policy scripts:
158+
Track updates:
70159

71160
```bash
72161
scripts/vendor/check-upstream.sh --important
73162
scripts/vendor/sync-all.sh --important --dry-run
74-
scripts/vendor/sync-all.sh --important
75163
```
76164

77-
After syncing local vendored crates, import + pin to vendor repo:
165+
Apply updates intentionally:
78166

79167
```bash
168+
scripts/vendor/sync-all.sh --important
80169
scripts/vendor/vendor-repo.sh import-local
170+
git -C .vendor/flow-vendor push origin main
81171
```
82172

83-
## Fallback Mode (Cargo Cache)
173+
Policy:
174+
175+
- patch updates can be frequent,
176+
- minor/major updates happen in explicit review windows (`--allow-minor`, `--allow-major`).
177+
178+
## CI Contract
84179

85-
If you intentionally want the old local-cache materialization path:
180+
CI must hydrate vendored source from `vendor.lock.toml` before Cargo build:
86181

87182
```bash
88-
scripts/vendor/materialize-all.sh --from-cache
183+
scripts/vendor/vendor-repo.sh hydrate
184+
```
185+
186+
Any CI build skipping hydrate can fail with missing `lib/vendor/*` path deps.
187+
188+
## Optimization Strategy (Compile-Time Focus)
189+
190+
For each vendored crate:
191+
192+
1. inspect real usage in `flow` (APIs/types called),
193+
2. remove optional features not used,
194+
3. delete convenience-only dependencies,
195+
4. remove proc-macro convenience layers where reasonable,
196+
5. reduce duplicate major versions where possible,
197+
6. keep trim hooks deterministic and replayable.
198+
199+
Use:
200+
201+
```bash
202+
scripts/vendor/offenders.sh
203+
cargo tree -d
89204
```
90205

91-
## Guardrails
206+
to rank impact and watch duplicate-version pressure.
207+
208+
## Commit Policy
209+
210+
- In `flow`: commit only lock/manifest/patch/docs/script changes.
211+
- In `flow-vendor`: commit source churn.
212+
- Push `flow-vendor` first, then push `flow` pin updates.
213+
- Prefer one crate per commit for auditability.
214+
215+
## Recovery Playbook
216+
217+
Inspect state:
218+
219+
```bash
220+
scripts/vendor/vendor-repo.sh status
221+
```
222+
223+
Re-hydrate local materialization from pinned commit:
224+
225+
```bash
226+
scripts/vendor/vendor-repo.sh hydrate
227+
```
228+
229+
Re-pin to known commit:
230+
231+
```bash
232+
scripts/vendor/vendor-repo.sh pin <commit>
233+
```
234+
235+
## FAQ
236+
237+
### Are we replacing Cargo?
238+
239+
No. Cargo remains central. Vendoring is an ownership layer on top.
240+
241+
### Why separate repo for vendored source?
242+
243+
To keep main repo history focused on product changes while retaining full dependency source control.
244+
245+
### Can we still pull upstream changes quickly?
92246

93-
- Commit only lock/metadata/scripts/docs in `flow`; keep vendor source in `flow-vendor`.
94-
- Keep trim logic deterministic in `scripts/vendor/apply-trims.sh`.
95-
- Keep patch updates default; minor/major only in explicit review windows.
96-
- Always run `cargo check` after hydration/sync.
247+
Yes. `check-upstream` + `sync-*` + locked import flow is designed for repeatable upstream ingestion.

0 commit comments

Comments
 (0)