Developer Reference

Lint Policy Census

Workspace Clippy policy for jackin: measured allow census, restriction-family decisions, blocked-surface inventory, and #[allow] carve-out rules. Counts were measured 2026-07-14 with:

cargo clippy --workspace --all-targets --all-features --locked -- \
  -W clippy::<lint> 2>&1 | rg -c 'index\.html#<lint>'

Revisit triggers are concrete; re-measure when a trigger fires and update this table in the same PR as any level change.

Workspace policy

ControlLevelNotes
allow_attributes_without_reasondenyevery suppression needs reason = "..."
allow_attributesdenyprefer #[expect] so suppressions self-retire when the lint stops firing
Bare #[allow]0 (2026-07-14)all production/test suppressions use #[expect] (or cfg_attr(…, expect(…)) when target-dependent)

Legitimate #[allow] carve-outs (roadmap): cfg/target-dependent firing, test-only instability, generated code. Prefer #[cfg_attr(not(test), expect(…))] over #[allow] when the lint fires on one target and not another. If a true #[allow] is required under allow_attributes = deny, pair it with a fulfilled #[expect(clippy::allow_attributes, reason = "…")] on the same item and name the removal trigger in the reason.

Workspace allow census (clippy)

Every [workspace.lints.clippy] entry at allow as of this census. Level-decision is the workspace table value; counts are primary Clippy hits under -W.

LintLevelCountDateRationaleRevisit trigger
needless_pass_by_valueallow792026-07-14Dominant by-value state/view handoffs across TUI/runtimere-measure when count changes >20% or after TUI state-pass refactor
large_futuresallow1132026-07-14Residual large futures in attach/runtime/capsulere-measure after plan 016/017 pipeline splits
redundant_feature_namesallow12026-07-14Single test-support feature namingrevisit at next feature rename pass
implicit_hasherallow112026-07-14HashMap defaults without explicit hasher noiserevisit at next toolchain major
similar_namesallow72026-07-14Adjacent domain names (rows/cols, before/after)re-measure when count >20
assigning_clonesallow172026-07-14usage/capsule/runtime clone assignmentsre-measure when count changes >20%
match_same_armsallow452026-07-14capsule/console/lookbook match arms intentionally parallelre-measure after dialog/action enum splits
drop_non_dropallow362026-07-14console-heavy drop patternsre-measure when count changes >20%
format_push_stringallow362026-07-14progressive string building in diagnostics/xtaskre-measure when count changes >20%
no_effect_underscore_bindingallow72026-07-14intentional discard bindingsrevisit at next toolchain major
items_after_statementsallow472026-07-14local helpers after early returns in handlersre-measure after handler extractions
unnecessary_wrapsallow92026-07-14API symmetry returning Result/Optionre-measure when count changes >20%
option_optionallow22026-07-14rare tri-state encodingrevisit when introducing a third site
verbose_bit_maskallow32026-07-14terminal attribute bit masksrevisit at next term attribute redesign
unreadable_literalallow172026-07-14large integer literals in tests/benchesrevisit at next toolchain major
unnecessary_debug_formattingallow22026-07-14debug formatting in operator-facing pathsrevisit when count >5
struct_field_namesallow32026-07-14domain field prefixes matching type namesrevisit at next public API pass
missing_errors_docallow3562026-07-14docs backlog; not a safety gatere-measure after docs campaign; promote when below 50
missing_panics_docallow92026-07-14small panics-doc backlogre-measure when count changes >20%
must_use_candidateallow6622026-07-14noise-dominant on pure gettersre-measure at next toolchain major only
module_name_repetitionsallow3762026-07-14intentional foo::FooBar domain namingre-measure at next toolchain major only
future_not_sendallow1532026-07-14runner/trait object futures intentionally !Send in placesre-measure after async boundary ports (plan 017)
cast_possible_truncationallow1722026-07-14terminal geometry and byte-width castsre-measure after typed geometry newtypes (plan 020)
cast_possible_wrapallow162026-07-14signed/unsigned edge castsre-measure with cast_possible_truncation
cast_precision_lossallow612026-07-14animation/layout float pathsre-measure after animation cleanup
cargo_common_metadataallow02026-07-14workspace metadata completepromote to warn if any hit appears
multiple_crate_versionsallow442026-07-14transitive duplicates (syn, thiserror, …); tracked via deny/cargore-measure after major dep upgrades

cast_sign_loss remains deny (precedent for the lossy-cast tier). unused_self / unused_async already warn at 0 hits.

Restriction family

Denied today at crate roots: jackin-core, jackin-config, jackin-manifest, jackin-protocol (string_slice, indexing_slicing, get_unwrap, unwrap_in_result, panic_in_result_fn, unchecked_time_subtraction).

Per-crate indexing/slicing census (lib, 2026-07-14)

Crateindexing_slicingstring_sliceDecision
jackin-core00adopted (deny at root)
jackin-config00adopted
jackin-manifest00adopted
jackin-protocol00adopted
jackin-term530defer — >50 sites (plan STOP bar); hot parser loops; adopt after targeted extraction
jackin-env6445defer — >50 indexing + large string_slice surface
jackin-tui4316defer — near bar; revisit after component splits
jackin-runtime13063defer — largest surface; couple with plan 015/016
jackin-capsule22537defer — largest absolute; couple with plan 017
jackin-usage6133defer
jackin-host5833defer

Adoption bar: production signal is actionable with <50 site fixes per crate. Test escape valves stay in clippy.toml (allow-indexing-slicing-in-tests).

map_err_ignore

CountDateDecision
352026-07-14defer — non-zero; promote only with a named sweep PR

Lossy-cast tier

LintCountDecision
cast_possible_truncation172defer (newtype work in plan 020)
cast_possible_wrap16defer with truncation tier
cast_precision_loss61defer
cast_sign_lossdenyalready enforced

Whole-category clippy::restriction pilot

Piloted #![warn(clippy::restriction)] on jackin-protocol (smallest pure crate already on the slice/index family). Verdict: reject whole-category posture. Restriction is a mixed bag of style/perf/pedantic rules that flood actionable signal; continue allowlist-style adoption of named restriction lints (as today) rather than category-wide warn/deny. Experimental attribute not retained.

Blocked-surface inventory (clippy.toml)

Disallowed methods (enforced)

PathReplacement
std::process::Command::outputasync process helpers / spawn_blocking
std::thread::sleepasync sleep, polling hooks, or owned OS thread
std::fs::File::openasync file work or spawn_blocking
std::fs::OpenOptions::openasync file work or spawn_blocking

Disallowed types / macros

No additional disallowed-types or disallowed-macros entries in this plan. Bans land only when a canonical replacement exists; evaluated and not banned:

SurfaceVerdict
std::sync::Mutex / RwLock on async pathsCovered by await_holding_lock deny — no blanket type ban
Rc<RefCell<_>> in asyncCovered by await_holding_refcell_ref + Dylint render_thread_purity pilot (plan 012)
Ring buffers / custom queuesNo indiscriminate ban; prefer typed wrappers at domain boundaries (plan 020)
Bare primitive payloads (u16 rows/cols, raw path Strings)Evaluate via domain newtypes (plan 020); ban types only after newtypes land

Maintenance

  • New workspace allow entries require a row in this table in the same PR.
  • Plan 027 may later generate the count column mechanically; keep this machine-friendly Markdown table.
  • Cargo.toml comments point here; do not duplicate full rationales in-tree.

On this page