|
1 | | -# Dependency Vendoring |
| 1 | +# Dependency Vendoring (Cargo-First) |
2 | 2 |
|
3 | | -Flow now uses a split model: |
| 3 | +This project uses a Cargo-first vendoring model: |
4 | 4 |
|
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/*`. |
8 | 9 |
|
9 | | -## Goals |
| 10 | +This gives direct dependency control without giving up Cargo behavior. |
10 | 11 |
|
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 |
14 | 13 |
|
15 | | -## Core Files |
| 14 | +### Problem |
16 | 15 |
|
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. |
20 | 19 |
|
21 | | -## Vendor Repo Layout (`flow-vendor`) |
| 20 | +### Requirements |
22 | 21 |
|
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. |
26 | 26 |
|
27 | | -## Flow Workflow |
| 27 | +### Result |
28 | 28 |
|
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. |
30 | 33 |
|
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 |
34 | 65 |
|
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: |
36 | 82 |
|
37 | 83 | ```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] |
39 | 85 | ``` |
40 | 86 |
|
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: |
42 | 101 |
|
43 | 102 | ```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 |
47 | 106 | ``` |
48 | 107 |
|
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: |
50 | 130 |
|
51 | 131 | ```bash |
52 | | -scripts/vendor/vendor-repo.sh status |
| 132 | +/Users/nikiv/code/rise/scripts/vendor-control.sh provenance --project /Users/nikiv/code/flow |
53 | 133 | ``` |
54 | 134 |
|
55 | | -5. Push vendor repo updates: |
| 135 | +Use stricter mode when migrating fully: |
56 | 136 |
|
57 | 137 | ```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 |
59 | 139 | ``` |
60 | 140 |
|
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): |
62 | 151 |
|
63 | 152 | ```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 |
65 | 154 | ``` |
66 | 155 |
|
67 | 156 | ## Upstream Sync Loop |
68 | 157 |
|
69 | | -Keep existing update policy scripts: |
| 158 | +Track updates: |
70 | 159 |
|
71 | 160 | ```bash |
72 | 161 | scripts/vendor/check-upstream.sh --important |
73 | 162 | scripts/vendor/sync-all.sh --important --dry-run |
74 | | -scripts/vendor/sync-all.sh --important |
75 | 163 | ``` |
76 | 164 |
|
77 | | -After syncing local vendored crates, import + pin to vendor repo: |
| 165 | +Apply updates intentionally: |
78 | 166 |
|
79 | 167 | ```bash |
| 168 | +scripts/vendor/sync-all.sh --important |
80 | 169 | scripts/vendor/vendor-repo.sh import-local |
| 170 | +git -C .vendor/flow-vendor push origin main |
81 | 171 | ``` |
82 | 172 |
|
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 |
84 | 179 |
|
85 | | -If you intentionally want the old local-cache materialization path: |
| 180 | +CI must hydrate vendored source from `vendor.lock.toml` before Cargo build: |
86 | 181 |
|
87 | 182 | ```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 |
89 | 204 | ``` |
90 | 205 |
|
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? |
92 | 246 |
|
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