Plan P: Nursery Promotion Sweep
On this page
Status
| Step | Description | Status |
|---|---|---|
1 |
Plan filing — body lands as a docs-only MR alongside epic + per-lint-step issues. |
Not started |
2 |
|
Done (2026-06-05) — #505 closed via this MR. Actual surface (~50 sites across 11 files in 8 crates) larger than Plan M Step 12 estimate of 21 because cascade-stop on first error masked downstream emissions. Workspace |
3 |
|
Done (2026-06-05) — 506 closed via this MR. ~90 sites swept across 2 cascade rounds (44 first round in craig-auth + craig-cli/clients; 46 second round revealed once craig-auth compiled clean in craig-api, craig-authz, craig-test-lib). Python auto-sweep script splits first paragraph at first sentence boundary. Workspace |
4 |
|
Done (2026-06-05) — #507 closed via this MR. Audit outcome: workspace allow retained permanently with comprehensive architectural rationale per ADR-031 § 1. Real surface: 140+ emissions across 4 site classes, ALL intentionally |
5 |
|
Done (2026-06-05) — #508 closed via this MR. Audit: workspace grep confirmed ZERO |
6 |
|
Done (2026-06-05) — #509 closed via this MR. Audit outcome: workspace allow retained permanently with documented rationale per ADR-031 § 2. Actual surface (38 sites across craig-common/settings + craig-db + craig-mq + craig-partner-* adapters) is larger than the Plan M Step 12 estimate of 23, but the conclusion holds: ZERO callers in the workspace use these fns in |
7 |
|
Done (2026-06-05) — #510 closed via this MR. 6 sites swept: craig-exchange/{adapters/standard.rs, api/transactions.rs}, craig-rules/tests/api/evil_corpus.rs, craig-web/{routes/intake/referrals.rs (×2), routes/report.rs}, xtask/cmd/api_docs.rs. All |
8 |
|
Done (2026-06-05) — #511 closed via this MR. Audit outcome: no benchmarks needed. All 5 craig-auth sites are legitimate redundant clones on error-return paths (audience-mismatch error variants in introspection.rs + jwks.rs; file-empty error variants in keypair_env.rs) — the cloned values were already owned locals not used after return; clippy correctly flagged them. Cascade revealed 10 more sites across craig-authz tests, craig-test-lib tests, craig-exchange/adapters, craig-intake/{main,sink/upstream_error}, craig-web/{auth,routes/report}, xtask/cmd/{coverage_matrix,identity/verify,migrate}. 15 sites total swept (all moves where ownership analysis allows; 1 needed |
9 |
Long-tail single-emission cleanup — |
Done (2026-06-05) — #512 closed via this MR. 6 long-tail lints flipped from workspace allow to deny ( |
10 |
Plan completion audit + archive. Per |
Done (2026-06-06) — this MR closes #513. Audit subagent verified all 9 prior steps |
Epic: TBD (file alongside Step 1)
Issues: TBD (one per step, #N0X–#N0Y)
Branch prefix: refactor/plan-p-
*Milestone: TBD
Context
Plan M Step 12 (#503, !581) promoted clippy::nursery = deny workspace-wide and triaged 130+ emissions across 16 unique nursery lints. Per the plan’s <10-same-MR-threshold rule (codified as ADR-031 § 1), small-surface + clear-value lints were swept in the Step 12 MR (24 sites across 6 lints). 17 lints with either >10 emissions or case-by-case judgment were allow-listed at workspace priority 1 with documented rationale.
ADR-031 § 4 (Successor plan handoff) requires that deferred sweeps go to a named successor plan with explicit sweep scope — NOT a "potential improvements" section or a vague follow-up issue without owner. This plan IS that successor: each deferred lint becomes one bounded sweep MR (Steps 2–9), and the plan completes when each workspace allow entry has been re-evaluated and either flipped to deny after sweep, or replaced with per-site #[allow] blocks documenting why each surviving emission is correct.
Threat Model
Plan P’s threat model is the same as Plan M’s: workspace lint configs that allow-list a lint silently can hide real new emissions added by clippy updates, by codebase growth, or by lint behavior changes. The Plan M Step 12 allow-lists are time-bound (each allow entry’s comment cites Plan P as the home for the sweep); if Plan P never lands, the allow-lists become permanent and the regression-gate value of nursery = deny is partially defeated.
Cross-cutting Invariants
-
Each Step 2–9 MR flips its corresponding workspace
allowentry todeny(or removes it entirely if defeating the lint workspace-wide). Leaving an entry atallowafter its sweep step closes means the sweep didn’t actually take. -
Per-site
#[allow(clippy::X, reason = "…")]blocks survive only if the reason describes an idiomatic correctness invariant (e.g. "JDM eval thread is!Sendby design"), NOT just "this lint is annoying." -
ADR-031 patterns apply to Plan P MRs too. New
[workspace.lints.clippy]allow entries (if any) carry the same comment-block requirement: surface measurement + rationale + successor-plan pointer. -
Per-step sweeps do not introduce new lint emissions in unrelated lints. Pre-push battery covers this; an MR that touches
craig-cases/error.rsto flip 21use_selfarms must not introduce, say, newwildcard_enum_match_armviolations.
Step DAG
1 (plan filing)
↓
── per-lint sweeps run in any order; each independent ──
↓
2 (use_self) → 3 (too_long_first_doc_paragraph) → 7 (or_fun_call) → 9 (long-tail batch)
↓
── investigation-heavy steps run in parallel with mechanical sweeps ──
↓
4 (future_not_send !Send-audit) || 5 (derive_partial_eq_without_eq triage) || 6 (missing_const_for_fn) || 8 (redundant_clone benchmarks)
↓
── all sweeps converge ──
↓
10 (audit + archive)
Risks
-
Step 4
future_not_sendaudit may surface real concurrency bugs.!Sendfutures held acrosstokio::spawnboundaries silently deadlock or single-task-serialize work that callers expected to parallelize. If the audit finds these, the fix may be larger than expected (refactor toArc<RwLock<T>>). Mitigation: each finding files its own issue + fixes in a separate MR; Plan P Step 4 closes with audit findings + linked fix MRs. -
Step 8
redundant_clonebenchmarks may inconclusive. Keypair clone is rare (once-per-rotation). Ifcriterionshows <1μs impact, the entry stays at workspaceallow. Documented as "benchmark confirms negligible" and the step closes — Plan P Step 10 audit accepts the outcome. -
Step 6
missing_const_for_fnmay close as "no value". If no caller in the codebase needsconstcontext, the lint adds maintenance friction without benefit. Documented at Step 6 close.
Successor plans
After Plan P closes, future work that builds on the workspace lint discipline:
-
Plan Q — clippy::restriction probe. The
restrictiongroup fires on patterns that are sometimes correct, sometimes wrong (e.g.clippy::indexing_slicing,clippy::shadow_reuse,clippy::float_arithmetic). Probe with the same <10-same-MR-threshold rule from ADR-031. Most lints will allow-list; a few will sweep. -
Plan R — cargo-mutants integration. Once Plans M + P land, the lint config is tight enough that mutation testing won’t surface trivially-broken code (no
panic!()slipping past tests, no.unwrap()masking errors). Runcargo mutantson the workspace and triage the surviving mutants.
References
-
Plan M archived body:
plans/archive/quality-lint-followthrough.adoc -
ADR-031 — Nursery Lint Triage and Promotion Pattern:
adrs/adr-031-nursery-lint-triage.adoc -
Cargo.toml [workspace.lints.clippy]— current 17 escape-hatch entries from Plan M Step 12 -
delivery-protocol.md § Plan completion audit— audit protocol Plan P Step 10 follows