Skip to content

fix(features): gate 6 items on streamable-http/async + add lint-ci-no-default regression guard (Phase 8e, closes #295)#296

Merged
githubrobbi merged 1 commit into
mainfrom
chore/feature-additivity-phase-8e
May 19, 2026
Merged

fix(features): gate 6 items on streamable-http/async + add lint-ci-no-default regression guard (Phase 8e, closes #295)#296
githubrobbi merged 1 commit into
mainfrom
chore/feature-additivity-phase-8e

Conversation

@githubrobbi
Copy link
Copy Markdown
Collaborator

Summary

Closes #295. Companion to the closed Phase-8 issue #195.

Post-Phase-8 audit found that cargo check --workspace --no-default-features (playbook §996, the second of the four required Phase 8 validations) was never run during Phase 8. Doing so reveals 6 items reachable only when feature X is on but not themselves #[cfg(feature = "X")]-gated. Under strict CI (-D warnings) all 6 hard-fail. CI today runs only --all-features configurations which mask the dead-code + unfulfilled-expect warnings these gaps emit.

Fixes

Source (3 surgical cfg/cfg_attr annotations, zero behavior change)

Site Before After Why
uffs-mcp::McpStats::avg_tool_latency_us always defined #[cfg(feature = "streamable-http")] only called by http.rs::/status
uffs-mcp::McpStats::to_json always defined #[cfg(feature = "streamable-http")] only called by http.rs::/status
uffs-client::daemon_ctl::keepalive_send_blocking always defined #[cfg(feature = "async")] only called by connect_keepalive (itself async-gated)
uffs-mcp::lib.rs::run_mcp_server_with_config #[expect(cognitive_complexity)] always present #[cfg_attr(feature = "streamable-http", expect(…))] score only crosses threshold when feature on
uffs-mcp::handler/mod.rs::on_roots_list_changed same same same same
uffs-mcp::handler/mod.rs::call_tool same same same same

Regression guard (new lint-ci-no-default gate)

  • scripts/ci/gates.toml: new [[gate]] block; mirrors lint-ci in flag stack + -D warnings strictness; differs only in --no-default-features vs --all-features. Tiers: pre-push + pr-fast.
  • just/test.just: new lint-ci-no-default recipe.
  • scripts/hooks/_lint_pre_push.sh: regenerated via just gen-hooks (auto from manifest).
  • .github/workflows/pr-fast.yml: new clippy-no-default job, registered in required.needs: + aggregator table.
  • All 4 drift detectors green: gates-drift (27 gates), hooks-drift, workflow-drift, fast-drift.

Together lint-ci (--all-features) + lint-ci-no-default (--no-default-features) establish the additivity invariant: every pub/pub(crate) item reachable only with feature X must compile cleanly both with feature X off AND with all features on.

Documentation

  • docs/architecture/code-quality/dependency_policy.md §2: 5-tool table → 6-tool table; new paragraph explaining the additivity invariant.
  • docs/architecture/code-quality/dependency_policy.md §10: 8e decisions-log row.
  • docs/architecture/code-quality/trait_policy.md:193: Phase 7f TBD#291 (closes Phase 8 follow-up Bump the cargo group across 1 directory with 2 updates #1).

Verification

Config Before After
cargo clippy --workspace --all-features -D warnings 0 0
cargo clippy --workspace --no-default-features -D warnings 6 warnings 0
cargo clippy -p uffs-client --no-default-features -D warnings 1 warning 0
cargo clippy -p uffs-mcp --no-default-features -D warnings 5 warnings 0
cargo clippy -p uffs-cli --features mcp-http-probe -D warnings 1 warning 0

Pre-push gate: full 24-gate run green in 106 s (lint-ci-no-default fires in ~1 s warm).

5-rule contract adherence

  • Rule 1 (no suppression hacks): zero #[allow] added. All 6 fixes are minimum-correct #[cfg] annotations expressing actual reachability. The 3 expects become conditional rather than blanket — they preserve the strict check when triggered, no unfulfilled-expect when not.
  • Rule 2 (surgical, correct fixes): 3 source files, 9 attribute lines added, zero logic change.
  • Rule 3 (preserve behavior + contracts): default + --all-features binary surface byte-identical. All API contracts preserved.
  • Rule 4 (improve tests, don't dodge them): new CI gate gives the whole workspace the structural feature-additivity verification it lacked.
  • Rule 5 (document & commit well): comprehensive commit message + 2 policy-doc updates + decisions-log entries.

Follow-ups

This closes Phase 8 follow-up #1 (trait_policy.md TBD) and addresses the audit-finding gap (cargo tree --workspace -e features snapshot is local-only baseline; not in scope for this PR).

…-default regression guard (Phase 8e, refs #295)

Post-Phase-8 audit found that `cargo check --workspace --no-default-features`
(playbook §996, the second of the four required Phase 8 validations) was
never run during Phase 8.  Doing so reveals 6 items reachable only when
feature X is on but not themselves `#[cfg(feature = "X")]`-gated.
Under strict CI (`-D warnings`) all 6 would have hard-failed.

Source fixes (3 surgical cfg/cfg_attr annotations, zero behavior change
in default + --all-features configs):

* `uffs-mcp::McpStats::{avg_tool_latency_us,to_json}` → `#[cfg(feature = "streamable-http")]`
  (both only called by `http.rs`'s `/status` endpoint).
* `uffs-client::daemon_ctl::keepalive_send_blocking` → `#[cfg(feature = "async")]`
  (only called by `connect_keepalive`, itself `async`-gated in `lib.rs`).
* 3 `#[expect(clippy::cognitive_complexity, …)]` in `uffs-mcp::lib.rs`
  + `handler/mod.rs` → `#[cfg_attr(feature = "streamable-http", expect(…))]`
  (the lint score only crosses threshold when streamable-http is on;
  the conditional expect preserves the strict check when it actually
  triggers without leaving an unfulfilled expect when it doesn't).

Regression guard:

* New `lint-ci-no-default` gate added to `scripts/ci/gates.toml`:
  `cargo clippy --workspace --all-targets --no-default-features
   --no-deps -- -D warnings`.  Mirrors `lint-ci` in flag stack + strictness;
  differs only in `--no-default-features` vs `--all-features`.  Together
  the pair enforces the additivity invariant.
* `just lint-ci-no-default` recipe added to `just/test.just`.
* `pr-fast.yml::clippy-no-default` job added (mirrors `clippy` job).
* Registered in `required.needs:` + aggregator table.
* Pre-push hook regenerated via `just gen-hooks` (auto from manifest).
* All 4 drift detectors green: gates-drift, hooks-drift, workflow-drift, fast-drift.

Documentation:

* `dependency_policy.md` §2: 5-tool table → 6-tool table; new
  paragraph explaining the additivity invariant the pair establishes.
* `dependency_policy.md` §10: 8e decisions-log row.
* `trait_policy.md:193`: Phase 7f TBD → #291 (Phase 8 follow-up #1).

Adherence to the 5-rule contract:

* **Rule 1** (no suppression hacks): zero `#[allow]` added.  All 6 fixes
  are minimum-correct `#[cfg]` annotations that express the actual
  reachability; the 3 `expect`s become conditional rather than absolute.
* **Rule 2** (surgical, correct fixes): 3 source files touched with 9
  attribute lines added; no logic change.
* **Rule 3** (preserve behavior + contracts): default + --all-features
  binary surface unchanged.  All API contracts preserved.
* **Rule 4** (improve tests, don't dodge them): new CI gate gives the
  whole workspace structural feature-additivity verification it lacked.
* **Rule 5** (document & commit well): this commit message + 2 policy-doc
  updates + 4-line decisions-log entries explain the why, the what, and
  the guard against regression.
@githubrobbi githubrobbi enabled auto-merge (squash) May 19, 2026 20:18
@githubrobbi githubrobbi merged commit 0d87d9d into main May 19, 2026
21 checks passed
@githubrobbi githubrobbi deleted the chore/feature-additivity-phase-8e branch May 19, 2026 20:27
githubrobbi added a commit that referenced this pull request May 19, 2026
The Phase 7g decisions-log row in `trait_policy.md:194` read 'this PR'
at the time of authoring (when PR #290 was open).  After PR #290 merged
the placeholder needed backfilling to '#290' to match the surrounding
rows (#288/#289/#291).

Companion to Phase 8e (PR #296), which already backfilled the sibling
'TBD' placeholder on row 193 (Phase 7f -> #291).  This 1-line edit
completes the decisions-log hygiene pass for Phase 7.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[playbook-phase-8e] Feature additivity regression guard + 6 cfg-gating fixes

1 participant