swarm repositories / source
aboutsummaryrefslogtreecommitdiff
path: root/docs/bootstrap-retrofit.md
diff options
context:
space:
mode:
authormain <main@swarm.moe>2026-03-31 14:21:52 -0400
committermain <main@swarm.moe>2026-03-31 14:21:52 -0400
commitc927ac1c6e041f96326e4a32e76ca13da8f6f5be (patch)
tree9e08adbfce36bfe2b306eb4e833807c2f799cbf3 /docs/bootstrap-retrofit.md
downloadrust_starter-c927ac1c6e041f96326e4a32e76ca13da8f6f5be.zip
Initial import
Diffstat (limited to 'docs/bootstrap-retrofit.md')
-rw-r--r--docs/bootstrap-retrofit.md156
1 files changed, 156 insertions, 0 deletions
diff --git a/docs/bootstrap-retrofit.md b/docs/bootstrap-retrofit.md
new file mode 100644
index 0000000..c07be56
--- /dev/null
+++ b/docs/bootstrap-retrofit.md
@@ -0,0 +1,156 @@
+# Retrofit
+
+Use this surface when the target repo already has Rust linting, but you want to tighten the ratchet without clobbering valid local structure.
+
+## Goal
+
+Migrate the repo toward the `rust-starter` posture while staying diff-aware:
+
+- preserve stricter existing rules
+- preserve justified local carve-outs
+- delete duplicated policy only after it has been re-homed into the manifest
+- never paste the fresh template wholesale over a living repo
+- add a hard source-file line cap without erasing stricter local limits or justified generated-code exemptions
+
+## First Pass: Inventory The Existing Surfaces
+
+Before editing, inspect all of the places the repo may already encode lint policy:
+
+- root and member `Cargo.toml`
+- `check.py`, `xtask`, shell wrappers, `justfile`, or other runners
+- CI workflow files
+- any existing auto-fix or canonicalization commands
+- `clippy.toml`
+- `rust-toolchain.toml`
+- editor settings
+- existing oversized source files, checked-in generated code, and any current file-length checks
+
+You are trying to answer two questions:
+
+1. What policy already exists?
+2. Where is that policy duplicated?
+
+## Comparison Baseline
+
+Use these as the baseline, not as paste targets:
+
+- [template/fresh](/home/main/programming/projects/rust_starter/template/fresh)
+- [docs/rust-linting-proposal.md](/home/main/programming/projects/rust_starter/docs/rust-linting-proposal.md)
+
+The fresh template tells you the shape to converge toward. The proposal doc tells you why.
+
+## Rules Of Engagement
+
+### Preserve stricter local policy
+
+If the repo already does something stricter than the template, keep it unless there is a clear repo-specific reason to relax it.
+
+Examples:
+
+- stricter rustdoc policy
+- additional Clippy bans
+- a more demanding deep gate
+- an intentionally tighter unsafe policy
+- a lower source-file line cap
+
+### Preserve justified local exceptions
+
+If the repo has exceptions with clear local justification, do not erase them just because the template lacks them.
+
+Instead:
+
+- move them into root `Cargo.toml` if they are repo-wide
+- keep them local if they are truly local
+- add or preserve comments / `reason = "..."`
+- use `workspace.metadata.rust-starter.source_files.exclude` for checked-in generated Rust or other deliberate file-cap carve-outs
+
+### Remove duplicate policy, not local intent
+
+When a repo encodes the same allowlist in both `Cargo.toml` and a runner script, the script copy should die.
+
+But only remove the script copy after the equivalent manifest-owned policy exists and the runner still executes the same effective gate.
+
+### Treat `clippy.toml` as configuration-only
+
+If the repo uses `clippy.toml` to hold the main allow/deny architecture, migrate that policy into `[workspace.lints.clippy]`.
+
+Keep `clippy.toml` only for structured knobs such as test allowances.
+
+## Ratchet Order
+
+Apply tightenings in this order:
+
+### 1. Pin or refresh the toolchain
+
+Add `rust-toolchain.toml` if missing. If present but floating, pin it.
+
+### 2. Install workspace lint tables
+
+Move repo-wide policy into root `[workspace.lints.*]`.
+
+### 3. Make member crates inherit explicitly
+
+Add `[lints] workspace = true` to every member crate.
+
+### 4. Re-home script flags into the manifest
+
+Take inline `cargo clippy -- -A/-D ...` tails from scripts and CI, and migrate them into the root manifest in grouped, commented form.
+
+### 5. Tighten local suppression discipline
+
+Prefer:
+
+- `#[expect(..., reason = "...")]` for temporary or evidence-backed suppressions
+- `#[allow(..., reason = "...")]` only for stable local policy
+
+### 6. Simplify the runner
+
+Once the manifest is authoritative, collapse the runner to orchestration-only plus generic manifest-backed checks such as the source-file cap.
+
+If the repo already has an auto-fix pass, re-home it into root `workspace.metadata.rust-starter.canonicalize_commands` and make the default local `check` path invoke it before the verification gate instead of relying on engineers or agents to remember a separate pre-pass.
+
+### 7. Install the source-file cap
+
+Add `[workspace.metadata.rust-starter.source_files]` to the root manifest and set `max_lines` deliberately.
+
+Default to `2500` if the repo has no existing stance. If the repo already enforces a stricter cap, keep the stricter value. If the repo has checked-in generated Rust that would make the rule meaningless, exclude those paths explicitly instead of disabling the whole mechanism.
+
+### 8. Add deep-gate posture if the repo is ready
+
+Add `cargo hack`, docs, and dependency-hygiene checks only when the repo can support them without turning the whole effort into churn theater.
+
+## Special Cases
+
+### Existing `expect_used = "allow"`
+
+Do not keep this globally just because the repo had it historically. Check whether the real need is test-only ergonomics. If so:
+
+- set `expect_used = "deny"` in the root manifest
+- move the relaxation into `clippy.toml` via `allow-expect-in-tests = true`
+
+### Existing repo-specific carve-outs
+
+If the repo carries exceptions for domain-heavy code such as geometry, parsing, or numerics, expect some of them to stay. The goal is not zero exceptions. The goal is explicit, centralized, justified exceptions.
+
+### Checked-in giant files
+
+If the repo already contains Rust files over the default cap, do not blindly raise the limit to fit them. Decide whether each file should be split, exempted, or accepted behind a tighter, evidence-backed local exception pattern.
+
+### Existing CI
+
+Do not rewrite CI into a second policy source. Make it call the canonical commands or the thin runner.
+
+If the repo wants CI to detect canonicalization drift rather than rewriting files in place, keep a non-mutating verification entrypoint such as `check.py verify` and let local `check` remain the mutating convenience path.
+
+## Acceptance Checklist
+
+- repo-wide policy lives in root `[workspace.lints.*]`
+- every member crate inherits that policy explicitly
+- scripts and CI no longer restate Clippy allowlists
+- manifest-owned canonicalization exists where the repo wants auto-fixes, instead of living in shell aliases or tribal memory
+- valid repo-specific exceptions remain intact and justified
+- stricter pre-existing rules remain stricter
+- the root manifest carries an intentional source-file cap and any justified exclusions
+- fast gate commands still match the repo’s effective behavior
+
+Use [docs/rust-linting-proposal.md](/home/main/programming/projects/rust_starter/docs/rust-linting-proposal.md) when you need to justify a ratchet choice, not as a blind replacement spec.