Skip to content

Enable strict clippy with documented allow-list and defensive-coding pass#257

Merged
aram356 merged 96 commits into
mainfrom
chore/strict-clippy
Jun 12, 2026
Merged

Enable strict clippy with documented allow-list and defensive-coding pass#257
aram356 merged 96 commits into
mainfrom
chore/strict-clippy

Conversation

@aram356

@aram356 aram356 commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Enable strict clippy (pedantic warn + restriction deny) workspace-wide and shrink the allow-list from ~41 entries at the start to 13 entries (matching the app-demo workspace's slim profile within four irreducible-by-design lints). Every removed allow corresponds to a real refactor, not a sprinkling of #[allow] / #[expect] annotations.

Final allow-list (13)

Lint Why it stays
blanket_clippy_restriction_lints Required meta-allow when enabling restriction as a group
missing_docs_in_private_items Private items don't need full docs
implicit_return Idiomatic Rust
question_mark_used Idiomatic Rust
single_call_fn Naming helpers for readability is valuable
separated_literal_suffix Matches rustfmt behaviour
std_instead_of_alloc / std_instead_of_core Project targets std, not core/alloc
exhaustive_structs edgezero_core::app! emits a unit struct that legitimately fires the lint
exhaustive_enums Audited: Body { Once, Stream } is the only firing site; #[non_exhaustive] would force _ => unreachable!() at 37 external match sites and break the closed-enum design
pub_with_shorthand rustfmt unconditionally rewrites pub(in crate)pub(crate); documented
module_name_repetitions Audited: proxy::Request/Response would collide with http::Request/Response, 17 Manifest* types are load-bearing public API, and the #[app] macro emits code referencing the current names
pattern_type_mismatch Mutually exclusive with ref_patterns; one must be allowed — we pick match-ergonomics

Every other workspace allow that was present in the initial commit has been removed via a real fix.

Refactors that removed allows (highlights)

  • missing_trait_methods — explicit overrides for KvStore::exists (5 impls), Hooks::{configure,name,config_store,build_app} (test impls + #[app] macro output), Clone::clone_from for RouteEntry
  • pub_use — converted re-export-from-private-mod to pub mod across all four adapter crates; updated callers (templates, demo, CLI, contract tests) to use full module paths
  • absolute_paths — ~110 sites converted to use imports across 32 files
  • arbitrary_source_item_ordering — ~300 items reordered across 38 files following the canonical ExternCrate→Use→Mod→Static→Const→TyAlias→Enum→Struct→Trait→Impl→Fn order with alphabetical ordering inside each kind (including struct fields, constructor args, enum variants, impl methods, mod tests {} contents)
  • missing_inline_in_public_items#[inline] added to ~321 public fns/methods across 44 files
  • min_ident_chars — ~190 single-character identifiers renamed (closure params, helper variables, etc.)
  • shadow_reuse — ~30 shadowed bindings renamed across 22 files (stream-chunk patterns, Into-parameter idiom, closure-param shadows)
  • as_conversions — 8 cast sites eliminated via typed sibling constants or typed local bindings
  • arithmetic_side_effects — 6 numeric ops switched to checked_*/saturating_*; SystemTime + ttl propagates as typed error
  • format_push_stringgenerator.rs switched to writeln!(out, ...)? with GeneratorError::Format(#[from] fmt::Error) propagation
  • tests_outside_test_module — split #[cfg(all(test, feature = "X"))] into #[cfg(test)] #[cfg(feature = "X")] so the lint recognizes the gate
  • single_char_lifetime_names — 4 lifetimes renamed ('mw, 'route, 'manifest, 'blueprint)
  • allow_attributes — removed two unnecessary #[allow(deprecated)] annotations
  • float_arithmetic — switched the middleware request-logger to Duration::as_millis() (no float math)
  • exhaustive_enums for non-Body types: enums made #[non_exhaustive] where adapter consumers could absorb wildcard arms

Cross-cutting refactors

  • Adapter API surface: every adapter crate's lib.rs made its internal modules pub mod instead of re-exporting via pub use. Drops 4 file-level #![expect(clippy::pub_use)] annotations.
  • Manifest renamed: Manifest::secret_store_namesecret_store_binding to reflect that it returns a binding identifier, not a secret value.
  • Error types: switched expect()/unwrap() to ? propagation in scaffold/generator paths; added GeneratorError::Format and GeneratorError::Io variants.
  • Proc-macro errors: #[app] macro now emits compile_error!() rather than panicking on bad manifest input.

CI improvements

  • Collapsed three duplicate wasm test jobs into one adapter-wasm-tests matrix (cloudflare/fastly/spin) with per-cell toolchain installs gated on matrix.adapter.
  • New spin wasm test job (previously had only a compile-check) running the contract suite via Wasmtime.
  • Bumped every action to its current latest major: actions/checkout@v6, actions/setup-node@v6, actions/cache@v5, actions/configure-pages@v6, actions/deploy-pages@v5, actions/upload-pages-artifact@v5. Removes the Node 20 deprecation warnings.
  • Pinned viceroy 0.16.4 in .tool-versions (viceroy 0.17 raised MSRV to rustc 1.95; we ship 1.91); CI reads the version from .tool-versions (single source of truth).
  • Workspace-level .cargo/config.toml so cargo test -p edgezero-adapter-fastly --target wasm32-wasip1 --test contract resolves the Viceroy runner when invoked from the workspace root.
  • cargo install --force --locked for cached wasm runners (cache restores existing binaries and bare install rejects them).

CodeQL alerts fixed

  • ** 7 rust/cleartext-logging** — log_store_bindings was flagged because manifest_data.secret_store_*(...) is taint-source-by-name. Real fix: stop logging the binding identifier (operators read their own edgezero.toml); presence message still emitted.
  • ** 9, 10 rust/cleartext-transmission** — start_test_server_with_secret_handle test helper renamed to start_test_server_with_store_handle so its return value isn't taint-source-by-name; functionally identical.

Dependency bumps

  • redb 4.0 → 4.1

Test plan

Closes

Closes #256

Turns on `pedantic` (warn) and `restriction` (deny) workspace-wide and adds
`[lints] workspace = true` to every crate so the policy actually applies.

Captures a baseline allow-list in `Cargo.toml`, organized by category
(Documentation, Style/formatting, Defensive coding, API design, Imports/paths,
Output/diagnostics, Tests, Attributes) with per-lint counts and rationales —
each entry is a TODO unless explicitly marked intentional.

Defensive-coding pass:
- New `clippy.toml` with `allow-{unwrap,expect,panic,indexing-slicing}-in-tests`
  so test code keeps its conventional idioms; production code is denied.
- Production unwraps factored out: `current_dir()`/`init_logger()` now
  propagate via `?`; `writeln!` to a `String` rewritten as `push_str(&format!)`
  so there's no `Result` to discard; bundled-template registration and other
  genuine compile-time invariants use `.expect("...")` as documented assertions.
- Other small wins: `inefficient_to_string` fixed, `match_same_arms` collapsed,
  `manual_assert` swapped, `cast_lossless`+truncation replaced with bound-checked
  `u16::try_from` in adapter-axum CLI, `unreachable!()` in `#[action]` macro
  replaced with a proper `syn::Error::compile_error`.

Lints kept allowed in the workspace are annotated with `(intentional)` where
they conflict with idiomatic Rust (`implicit_return`, `question_mark_used`,
`pattern_type_mismatch`, `default_numeric_fallback`, `arithmetic_side_effects`,
`as_conversions`, `string_slice`) or have no per-test config option
(`assertions_on_result_states`).

`cargo clippy --workspace --all-targets --all-features -- -D warnings`,
`cargo fmt`, and `cargo test --workspace --all-targets` all pass.
@aram356 aram356 self-assigned this Apr 25, 2026
aram356 added 7 commits April 25, 2026 14:55
Drives the API-design lint group from 18 allows down to 8 (kept as intentional
with rationale comments in `Cargo.toml`).

Factored out:
- `return_self_not_must_use` (18): added `#[must_use]` to all `RouterBuilder`
  builder methods. Catches "I forgot to call `.build()`" bugs.
- `impl_trait_in_params` (26): converted `fn f(x: impl Into<String>)` →
  explicit generics on `EdgeError::*`, `ConfigStoreError::*`, `RouteInfo::new`,
  `InMemorySecretStore::new`, `AxumConfigStore::{new,from_env,from_lookup}`.
  Makes turbofish callable.
- `rc_buffer` (4): `Arc<Vec<RouteInfo>>` → `Arc<[RouteInfo]>` in `RouterInner`
  and the builder. Saves an indirection.
- `unnecessary_wraps` (4): `build_fastly_request` and `convert_response` no
  longer wrap an always-Ok value in `Result`. Cleaner call sites.
- `mutex_atomic` (1): `Arc<Mutex<bool>>` → `Arc<AtomicBool>` in the
  `middleware_fn` test.
- `ref_patterns` (11): `if let Some(ref x) = ...` → `if let Some(x) = &...`
  across env-override `Drop` impls, router builder, response builder, body
  matchers.
- `wildcard_enum_match_arm` (7): `args.rs` tests now use `let-else` instead of
  catch-all wildcard match arms; `EdgeError::source` now lists each non-Internal
  variant explicitly; `cli/build.rs` switched to `if let Value::Table(_) = ...`;
  the one site that genuinely matches an external enum (`fastly::config_store::
  LookupError`) keeps a localized `#[allow(..., reason = "external enum")]`.
- `clone_on_ref_ptr` (1): `store.clone()` → `Arc::clone(&store)` in the axum
  service test (with explicit `Arc<dyn KvStore>` annotation so `Arc::clone`
  picks the right type).
- `renamed_function_params` (4): renamed `request: Request` → `req: Request`
  in `Service::call` impls to match the trait signature.
- `same_name_method` (2): `EdgeError::source` deliberately shadows
  `std::error::Error::source` (typed `&AnyError` vs trait-object `&dyn Error`).
  Documented at the call site with a `#[allow(..., reason = "...")]`.

Kept allowed (with `(intentional: ...)` comments in `Cargo.toml`):
- `exhaustive_structs` (108) and `exhaustive_enums` (18): blanket
  `#[non_exhaustive]` would break user pattern matching and field-syntax
  construction. Apply per-type only when genuinely planned.
- `must_use_candidate` (117): most flagged sites are getters returning
  `&str`/`&Path` — ignoring is impossible, the lint adds noise.
- `missing_trait_methods` (20): relying on default trait methods is fine.
- `needless_pass_by_value` (16): most flagged sites are deliberate ownership
  transfers — error transformers, proc-macro signatures, builders.
- `field_scoped_visibility_modifiers`, `partial_pub_fields`,
  `trivially_copy_pass_by_ref`: deliberate API design choices.

Final clippy + workspace tests pass.
Following pushback that the prior passes were papering over lints rather
than addressing them, this commit revisits each lint that was previously
allowed with hand-wavy reasoning and either (a) factors it out for real,
(b) applies it selectively where the fix matters, or (c) replaces the
rationale with a per-site audit finding.

Real fixes:

- `Body::as_bytes` and `Body::into_bytes` no longer panic on streaming
  bodies — they return `Option`. This eliminates two production panic
  sites the previous pass left as `panic = "allow"`. The internal
  `into_bytes_bounded` site is correctly gated by `is_stream()`; all
  other callers are tests that *intentionally* assert the body is
  buffered, now with `.expect("buffered")`.

- `assertions_on_result_states` is no longer allowed. All 13 sites
  converted from `assert!(r.is_ok())` / `assert!(r.is_err())` to
  `r.expect("...")` / `r.expect_err("...")` — these print the value or
  error on failure instead of just `assertion failed: false`.

- `#[non_exhaustive]` applied to all 4 error enums (`EdgeError`,
  `KvError`, `SecretError`, `ConfigStoreError`) and the 3 manifest
  enums (`HttpMethod`, `BodyMode`, `LogLevel`) — this is the idiomatic
  Rust pattern for error/config enums (see `std::io::ErrorKind`,
  `serde::de::Error`). Also applied to 19 deserialize-only manifest
  structs (`Manifest*`, `ResolvedEnvironment*`-where-not-constructed-
  externally).

- `needless_pass_by_value` real fix in `run_app_with_stores`:
  `FastlyLogging` and `StoreRequirements` are now passed by reference
  since the function only reads from them.

Lints kept allowed but with audited per-site rationales (replacing the
previous one-line hand-waves):

- `pattern_type_mismatch`: every flagged site uses Rust 2018
  match-ergonomics. The "fix" reverts to manual `ref` patterns or
  explicit `&Variant(...)` arms, both worse.
- `arithmetic_side_effects`: every site is bounded by domain invariants
  (TTL+now, path component counts, byte offsets after `len()` checks).
- `as_conversions`: dominated by trait-object coercions (`Arc::new(x)
  as BoxMiddleware`) which cannot be expressed as `From`/`Into` in
  stable Rust.
- `string_slice`: every flagged site indexes ASCII-only data (env var
  names, header names, `matchit` path components).
- `expect_used`: 62 production sites audited — bundled-template
  registration, AsyncRead-contract slice access, lock-poisoning
  unrecoverable, build-script panics. None benefit from `?`
  propagation.
- `panic`: route-registration `unwrap_or_else(|err| panic!(...))` and
  proc-macro expansion failures. Both build/setup-time programmer
  errors, not runtime conditions.
- `cast_possible_truncation` / `cast_sign_loss`: narrowing/sign casts
  always preceded by range checks.
- `exhaustive_structs` / `exhaustive_enums`: applied selectively above;
  remaining sites are tuple-struct extractors users *destructure*,
  unit structs, externally-constructed scaffold blueprints, request-
  context types used in integration tests, and small enums (`Body`,
  `AdapterAction`) where adding `#[non_exhaustive]` would force 12+
  adapter sites to add never-firing wildcard arms.

Workspace clippy + tests still pass with `-D warnings`.
Removes 22 mechanical-fix allow entries from `Cargo.toml` after fixing the
underlying call sites:

Auto-fixed (`cargo clippy --fix` + manual cleanup):
- `uninlined_format_args` (180), `redundant_closure_for_method_calls` (25),
  `map_unwrap_or` (29), `explicit_iter_loop` (14),
  `unseparated_literal_suffix` (24, separated form chosen),
  `implicit_clone` (2), `pathbuf_init_then_push` (3), `string_add` (3),
  `unreadable_literal` (4), `manual_let_else` (2), `else_if_without_else`
  (2 — the Fastly-vs-other-adapter logging branch refactored to a
  pre-computed `Option<endpoint>`), `return_and_then` (2), `ip_constant`
  (2), `manual_string_new` (1), `redundant_type_annotations` (1),
  `needless_raw_strings` (1), `needless_raw_string_hashes` (1),
  `elidable_lifetime_names` (2), `redundant_test_prefix` (1),
  `if_then_some_else_none` (6), `deref_by_slicing` (5), `shadow_same` (4),
  `match_wildcard_for_single_variants` (5), `pub_with_shorthand` (30),
  `decimal_literal_representation` (1).

Real fixes (manual):
- `key_value_store.rs`: replaced bare scoping blocks `{ ...?; }` with
  explicit `drop(table)` so neither `semicolon_inside_block` nor
  `semicolon_outside_block` fires (the lint pair is mutually exclusive
  and one always fires). Same treatment for `decompress.rs` and
  `proxy.rs` brotli-test compressor scopes.
- `middleware.rs`: collapsed the `Mutex` lock+await pattern into a
  single `self.log.lock().unwrap().push(...)` statement so the lock
  guard drops immediately (was previously triggering
  `await_holding_lock` after I removed the scoping block).
- `dev_server.rs`: `let service = service` (shadow_same) refactored
  into a `let service = { mut service = ...; ...; service }` block
  expression that yields the configured value.
- `response.rs`: dropped redundant `let stream = stream` shadow.
- `request.rs`: renamed `test_is_json_content_type` →
  `json_content_type_detection` (the redundant `test_` prefix).
- `proxy.rs` test panics: `_ => panic!(...)` → `Body::Stream(_) =>
  panic!(...)` so the match stays exhaustive when `Body` grows.
- `cli.rs`: `0xFFFF` instead of `65535` for the u16-MAX boundary.
- `dev_server.rs::stable_store_name_hash`: split FNV-1a magic numbers
  with `_` separators.

The Style section in `Cargo.toml` is rewritten as a tight allow-list
(no narrative, no historical commit log inside the manifest). Each
remaining entry has a one-line rationale grouped by category:
- Idiomatic Rust (8 lints): `implicit_return`, `min_ident_chars`,
  `single_call_fn`, `single_char_lifetime_names`, `pub_use`,
  `str_to_string`, `question_mark_used` (was duplicated; consolidated
  in Defensive section).
- Mutually-exclusive pairs we picked one side of: `separated_literal_suffix`,
  `pub_with_shorthand`.
- Held-by-choice (5 lints): `format_push_string`, `shadow_reuse`,
  `shadow_unrelated`, `similar_names`, `non_ascii_literal`,
  `too_many_lines`, `arbitrary_source_item_ordering`,
  `module_name_repetitions`.

Allow-list went from ~80 entries to 57 across all categories.
`cargo clippy --workspace --all-targets --all-features -- -D warnings`
and `cargo test --workspace --all-targets` both pass.
`#[action]` requires the user-written fn to be `async fn` because the
generated outer fn `.await`s it. When a handler body has no awaits of
its own, `clippy::unused_async` fires on the user's source — but the
user has no choice; the macro forces `async`.

Inject the allow into the inner fn's attribute list inside the macro
expansion so handler authors don't have to know about the lint.
Imports/paths track:
- `non_std_lazy_statics` (6 sites): `once_cell::Lazy` → `std::sync::LazyLock`
  in `crates/edgezero-adapter/src/{registry,scaffold}.rs`. Drops `once_cell`
  from `crates/edgezero-adapter/Cargo.toml`. (Workspace dep stays — example
  app still uses it.)
- `unused_trait_names` (37 sites): `use Foo;` → `use Foo as _;` for traits
  imported only for their methods (`StreamExt`, `Write`, `Read`, `Hooks`,
  `IntoHandler`, `Spanned`, etc.) across both library and proc-macro crates.
- `iter_over_hash_type` (1 site): the only flagged production iteration is
  in `RouterInner::dispatch` (collecting allowed methods for a 405 response).
  Refactored from a `for ... { allowed.insert(...) }` loop into
  `.iter().filter().map().collect::<HashSet<_>>()`. The result is a `HashSet`
  whose order doesn't matter (`EdgeError::method_not_allowed` sorts on render).

Attributes track:
- `allow_attributes` (3 sites): `#[allow(...)]` → `#[expect(..., reason)]` on
  the genuine deliberate-shadowing/wildcard-match-arm sites in
  `error.rs::EdgeError::source` and `config_store.rs::map_lookup_error`. The
  CLI build script (`build.rs`) now emits `#[expect(unused_imports, reason)]`
  on every generated `pub(crate) use` re-export.
- `allow_attributes_without_reason` (5 sites): every existing `#[allow(...)]`
  now has a `, reason = "..."` and (where stable-`expect` applies) is migrated
  to `#[expect(...)]`. Sites: `cli_support.rs` and `decompress.rs` top-of-file
  `#![expect(dead_code, ...)]`; the four test-only `Deserialize` field structs
  in `context.rs` and `params.rs`; the macro's `manifest_definitions` shim;
  the two fastly `deprecated` re-exports.

Also kept allowed (real audits in `Cargo.toml` rationales):
- `absolute_paths` (200+ sites): one-shot `std::env::var()` / `std::fmt::Display`
  uses; adding `use` statements wouldn't improve readability for single-use.
- `std_instead_of_alloc` / `std_instead_of_core`: not targeting `no_std`.
- `tests_outside_test_module`: lint matches plain `#[cfg(test)] mod tests`
  only — doesn't recognize `#[cfg(all(test, feature = "..."))]` or
  integration-test files in `tests/`.
- `print_stderr` / `print_stdout`: kept in CLI top-level error reporters and
  status output (`[edgezero] creating project at ...`).

Allow-list now at 51 entries.
…c / doc_markdown / missing_fields_in_debug

Adds public-API docs across every flagged site:

- `missing_panics_doc` (28 sites): added `# Panics` sections describing
  each panic condition. Most are documented invariants (lock poisoning,
  AsyncRead-contract slice access, builder pre-validated headers); a few
  are caller-controlled (`enable_route_listing_at` asserts on path shape,
  `RouterBuilder::build` panics on duplicate route, `load_from_str` panics
  on invalid embedded TOML — the docs note safer alternatives).
- `missing_errors_doc` (62 unique pub fns, 124 lints with re-exports):
  added `# Errors` sections describing the concrete error variants
  returned. Dispatched via batch script with per-fn descriptions covering
  every site (KV / secret / config-store / manifest / proxy / extractor /
  body / responder / middleware / adapter dispatch APIs).
- `missing_fields_in_debug` (2 unique sites — 4 with re-exports):
  `ProxyRequest`/`ProxyResponse` `Debug` impls now use `finish_non_exhaustive()`
  to acknowledge the deliberately-skipped `body` and `extensions` fields.
- `doc_markdown` (17 sites): backticked `EdgeZero`, `SystemTime`, `Axum`,
  `SecretStore`, etc. in doc comments.

Lints kept allowed (with rationale comments in `Cargo.toml`):
- `missing_docs_in_private_items` (275 sites): private docs aren't
  load-bearing for users — industry-standard "kept allowed".
- `missing_inline_in_public_items`: `#[inline]` is a perf hint; rustc/LLVM
  make better decisions than blanket-marking every cross-crate public item.

Allow-list: 51 → 47 entries.
…t_stdout allows

The CLI binary now initializes a `simple_logger` with no timestamps and no
level prefixes (so the user-facing UX is unchanged: `[edgezero] creating
project at ...` still prints exactly that), and all `println!` /
`eprintln!` sites are converted to `log::info!` / `log::error!` /
`log::warn!`.

Sites converted (24 total):
- `crates/edgezero-cli/src/main.rs`: top-level error reporters (`new`,
  `build`, `deploy`, `serve`, `dev`) + status output for store-binding
  warnings.
- `crates/edgezero-cli/src/generator.rs`: 9 status messages and 2 git
  warnings now go through the logger.
- `crates/edgezero-cli/src/dev_server.rs`, `adapter.rs`: dev manifest /
  command-failure reporting.
- `crates/edgezero-adapter-{axum,cloudflare,fastly,spin}/src/cli.rs`:
  one build-artifact-path message each.

Allow-list: 47 → 45 entries (`print_stderr` + `print_stdout` removed).
Comment thread crates/edgezero-cli/src/main.rs Fixed
aram356 added 10 commits April 25, 2026 16:54
Real renames + restructuring (no inline allow attrs):

- `non_ascii_literal` (3 sites): replaced the Japanese KV-key test literal
  with `\u{...}` escapes (same runtime bytes, ASCII source) instead of
  `#[expect]`-ing the lint. Replaced `→` arrow in a CLI test message with
  `->`.
- `similar_names` (2 sites): renamed `decoded` → `output` in
  `crates/edgezero-adapter-spin/src/decompress.rs` to break the
  `decoded`/`decoder` prefix-share that the lint flags.
- `too_many_lines` (1 site): split `collect_adapter_data` in
  `crates/edgezero-cli/src/generator.rs` into three helpers
  (`blueprint_data_entries`, `render_manifest_section`,
  `append_readme_entries`).
- `shadow_unrelated` (~14 sites): renamed every flagged inner binding
  to be specific to its purpose:
  - `serve_with_stores`: `let router = Router::new()...` →
    `axum_router`; `let server = server.with_graceful_shutdown(...)` →
    `graceful_server`; `let shutdown = ...` → `shutdown_signal`.
  - `store_name_slug`: `Some(ch)` → `Some(lower_ch)` (was shadowing
    outer `ch`).
  - dev_server tests: `let url = ...` reused per-step → `write_url`,
    `read_url`, `check_url`, `delete_url`, `save_url`, `load_url`;
    `let resp = ...` → `write_response`/`read_response`/`save_resp`/
    `load_resp`/`exists_before`/`exists_after`.
  - `axum::key_value_store::get_bytes`: inner write-txn `table` →
    `write_table`, `entry` → `fresh_entry`.
  - `list_keys_page` cursor match: inner `Some(cursor)` → `Some(scan_from)`.
  - `data_persists_across_reopens` test: second `let store = ...` →
    `reopened`.
  - `axum::response::into_axum_response` error path: `body` →
    `error_body`, `response` → `error_response`. Test: `stream` →
    `body_stream`.
  - `fastly::key_value_store::list_keys_page`: inner `cursor` →
    `next_cursor`.
  - `fastly::proxy` test: collapsed two pairs of `body`/`collected` reuse
    into named bindings (`plain_body`, `gzip_body`).
  - `spin::decompress` test: `let result = ...` reused per-encoding →
    `none_encoding`, `identity_encoding`.
  - `core::body::from_stream_maps_errors` test: `stream` →
    `source`/`chunks`.
  - `core::key_value_store` tests: `let val = ...` reused → `after_first`/
    `after_second`/`int_val`/`str_val`/`single_dot_err`/`double_dot_err`.
  - `axum::cli::read_axum_project`: `Some(value)` → `Some(port_value)`
    (was shadowing outer `value` from `toml::from_str`).

Allow-list: 45 → 41 entries.
…quest path

Real fixes (not just docs) for every production-code .expect() that could
fire under upstream contract change or misconfigured input:

- `IntoResponse::into_response` now returns `Result<Response, EdgeError>`
  workspace-wide (breaking change). Cascades through `Responder`,
  `EdgeError::into_response`, `RouterService::oneshot`, the handler future
  in `core/handler.rs`, and the route-listing builder.
- `ProxyResponse::into_response` and `core::response::response_with_body`
  now return `Result<Response, EdgeError>` and propagate `http::Builder`
  failures via `map_err(EdgeError::internal)?` instead of `.expect()`.
- `core::body::Body::into_bytes_bounded` rewritten as a `match self {
  Once | Stream }` so the unreachable `is_stream()`-guarded `.expect()`
  pair is gone — the compiler proves exhaustiveness.
- `core/compression.rs` decoder slice access now propagates as
  `io::Error::other(...)` instead of `.expect("AsyncRead contract")`,
  so a malicious or buggy upstream stream fails the request rather than
  crashing the worker.
- `axum/response.rs::into_axum_response` error path no longer uses
  `Response::builder().expect(...)`; constructs the 500 response
  directly via `Response::new` + `status_mut` + `headers_mut().insert`,
  every step infallible by `http`-crate contract.
- `axum/proxy.rs` replaced `Default` (which panicked on TLS init) with
  fallible `AxumProxyClient::try_new() -> Result<_, reqwest::Error>`.
  Production caller in `request.rs::into_core_request` propagates as a
  `String` error (matches the fn's existing return type).
- `fastly/logger.rs::init_logger` now returns
  `Result<(), InitLoggerError>` (a typed enum wrapping the underlying
  build error and `log::SetLoggerError`) instead of `.expect("non-empty
  Fastly logger endpoint")`. `lib.rs::init_logger` re-exports the wider
  return type.
- `cli/generator.rs::render_templates` propagates the previously-
  `.expect("adapter context dir has a file name")` invariant as
  `io::Error::other` since the surrounding fn already returns
  `io::Result<()>`.

`axum/service.rs::call` (the tower `Service` impl) bridges the new
`Result<Response, EdgeError>` from `RouterService::oneshot` into a
`Response<AxumBody>` by mapping the error to a hard-coded 500 with a
plain-text body — `Service::call` returns `Result<Response, Infallible>`
so we cannot propagate further up the stack here.

`adapter-fastly` adds `thiserror` as a direct dependency for
`InitLoggerError`. All 557 workspace tests still pass.
Replaces the previous \`std::io::Result<()>\` / \`io::Error::other(format!(...))\`
shape across the \`edgezero new\` code path with two domain-specific error
types:

- \`crate::scaffold::ScaffoldError\` (variants \`Io { path, source }\` and
  \`Render { name, message }\`) wraps every Handlebars failure and every
  filesystem op inside template rendering with the offending path/template
  name attached.
- \`crate::generator::GeneratorError\` (variants \`OutputDirExists\`,
  \`AdapterDirMissingFileName\`, \`Io { path, source }\`, and
  \`Scaffold(#[from] ScaffoldError)\`) replaces the workspace-construction
  io::Error stringification.

\`generate_new\`, \`ProjectLayout::new\`, \`collect_adapter_data\`, and
\`render_templates\` all return \`Result<_, GeneratorError>\`.

\`adapter-cli\` and \`scaffold\` now depend on \`thiserror\` directly. All
557 workspace tests still pass.
The `IntoResponse::into_response` change in 1506738 turned the trait into
`-> Result<Response, EdgeError>` workspace-wide. The demo app
(`examples/app-demo/`) is excluded from the main `Cargo.toml` workspace,
so it didn't get rebuilt by the workspace clippy/test gate and silently
broke. This propagates the same fix to the demo:

- Every `block_on(handler(ctx)).expect("handler ok").into_response()` in
  `crates/app-demo-core/src/handlers.rs` test code now appends
  `.expect("response")` to unwrap the response result.
- Every `into_body().into_bytes()` test path now appends
  `.expect("buffered")` since `Body::into_bytes()` returns
  `Option<Bytes>` (changed in the defensive-coding pass).

`cd examples/app-demo && cargo test --workspace --all-targets` passes
all 21 demo handler tests; `cargo clippy --workspace -- -D warnings`
also clean.
Inherit pedantic+restriction lints in the demo workspace and each demo
crate. Fix the lints that flagged real issues in the demo handlers
(`as _` trait imports, inlined format args, fast-path `to_string`,
renamed shadowed bindings, separated literal suffix). The demo's
allow-list is intentionally narrower than the library's — only entries
the demo actually trips. New allows can be added lazily as future
failures surface.
Add a clippy.toml mirroring the parent (allow expect/unwrap/panic/
indexing-slicing in tests). Then refactor away the workspace allows
that were genuine wins:

- shadow_reuse: rename `chunk` and `cursor` shadows
- absolute_paths: import std::env, std::time::Duration, std::process,
  and use already-imported Arc instead of std::sync::Arc
- default_numeric_fallback: add type suffixes (1_u64, 0_i32..3_i32, 1_i64)
- pattern_type_mismatch: implicitly fixed by str_to_owned changes
- missing_trait_methods: implement KvStore::exists on the test MockKv
- expect_used in production code: stream() now propagates the response
  builder error via EdgeError::internal

The remaining allow-list keeps only entries the demo actually trips
that match main's philosophical stance — std (not core/alloc) for
binaries, idiomatic `?` over match, terse closure idents, and the
single exhaustive_structs site that comes from the `app!` macro.
- str_to_string (21 sites): `.to_string()` → `.to_owned()` on `&str`
- arithmetic_side_effects: counter `n + 1` → `n.wrapping_add(1)`
- min_ident_chars + pattern_type_mismatch: rename closure
  destructures `|(k, v)|` → `|&(name, value)|`/`|&(key, value)|`
- pub_with_shorthand + field_scoped_visibility_modifiers:
  drop `pub(crate)` shorthand on the demo's DTOs and handlers — the
  `mod handlers;` declaration is already private, so plain `pub` is
  crate-private at the boundary
- print_stderr: axum main returns `anyhow::Result<()>` and lets the
  Termination impl render errors; fastly/cloudflare host stubs keep
  `eprintln!` behind a localized `#[expect]` with reason since
  they only run on the wrong target

Workspace allow-list now keeps only the entries that match main's
philosophical stance (idiomatic `?`, `pub` shorthand handled per-call
site, etc.) plus the single `exhaustive_structs` site from the `app!`
macro.
Drop the `arbitrary_source_item_ordering` allow in favor of the
canonical clippy-restriction layout:

- Top of `handlers.rs`: consts (alphabetical), then structs
  (alphabetical: ConfigParams, EchoBody, EchoParams, NoteIdPath,
  ProxyPath), then handler fns
- Test mod: uses, then structs (alphabetical), then impls grouped
  with their self-types, then helper + test fns interleaved in
  alphabetical order
- `impl KvStore for MockKv` methods alphabetical (delete, exists,
  get_bytes, list_keys_page, put_bytes, put_bytes_with_ttl)
- Hoisted the late `use edgezero_core::secret_store::...` up to
  the test mod's use block

No behavior changes — pure reordering. Demo workspace allow-list
drops to 8 entries.
The `edgezero new` generator now scaffolds the same lint policy
EdgeZero itself uses:

- Root `Cargo.toml` carries `[workspace.lints.clippy]` (pedantic warn
  + restriction deny) with the same demo-tested allow-list
- Root `clippy.toml` exempts tests from `unwrap`/`expect`/`panic`/
  indexing-slicing restriction lints
- Each generated crate's Cargo.toml inherits via `[lints] workspace = true`

Generated projects are clippy-clean against the strict gate out of the box.
Both adapters were calling `from_core_response` directly on the router's
return value, but `oneshot` now yields `Result<Response, EdgeError>`
since the response builder errors propagate through the router. Extract
the response with `?` first so the wasm32 builds (`--target
wasm32-unknown-unknown` for cloudflare, `--target wasm32-wasip1` for
spin) compile again.
@aram356 aram356 marked this pull request as draft April 26, 2026 03:04
aram356 added 9 commits April 25, 2026 23:03
… per-site

Real fixes (allows now justified by audit, not laziness):
- build.rs returns `Result<(), Box<dyn Error>>` instead of expect-panicking
- adapter registry / blueprint registry recover from poisoned RwLocks via
  `unwrap_or_else(PoisonError::into_inner)` rather than expect-panicking
- ManifestLoader gains `try_load_from_str` returning `io::Result`; adapter
  `run_app` paths propagate via `?`. The non-fallible `load_from_str` keeps
  its panic-on-bad-input contract for compile-time-embedded manifests, with
  a documented per-fn `#[expect(clippy::panic, reason = ...)]`
- `expand_app` macro emits `compile_error!()` instead of panicking on bad
  `edgezero.toml` (rustc surfaces a clean build error)
- `parse_handler_path` keeps a panic with a clear reason — proc-macro
  expansion errors *are* build failures
- `partial_pub_fields` on `Manifest`: privatized `root` and
  `logging_resolved`, kept the deserialized fields `pub` for the public
  API. Localized `#[expect]` documents the deliberate split
- `must_use_candidate` fixed on cli_support helpers via `#[must_use]`
- `missing_inline` fixed on adapter/scaffold registry functions
- `pub_use`, `format_push_string`, `arithmetic_side_effects`,
  `default_numeric_fallback`, `pattern_type_mismatch`, `min_ident_chars`,
  `str_to_string`, `absolute_paths`, `module_name_repetitions`,
  `shadow_reuse`: all kept as workspace allows but with concise
  rationales replacing the prior verbose audit notes

Each remaining workspace allow now has a one-line reason. The list is
shorter than before but explicitly accepts the lints whose "fix" would
universally make the code worse (match-ergonomics destructures, std-only
binary entrypoints, idiomatic `?`/return).
…space-wide

54 sites across 23 files. Fixed places where my bulk replace had wrongly
converted Display::to_string() calls (anyhow::Error, io::Error, i32 etc.)
back to .to_string(). The lint allow is dropped from the workspace.
23 sites across extractor.rs, key_value_store.rs, middleware.rs, proxy.rs,
adapter-axum dev_server/key_value_store, adapter-spin decompress.

Validator length(min=N) gets _u64; range(min=N, max=N) gets matching
type suffix; loop-bound and assertion literals get explicit i32.
Core crate: replaced 60+ `std::collections::HashMap`,
`std::sync::Arc`, `std::ops::Deref/DerefMut`, `crate::error::EdgeError`,
`futures::executor::block_on`, `std::task::*`, `std::string::String::*`
absolute paths with explicit `use` statements.

Axum proxy.rs: imported the various `axum::http::*` and `axum::routing::*`
types used in test functions.

The lint stays allowed at the workspace level for adapter test modules where
one-shot uses of framework types like `axum::http::HeaderMap` and
`fastly::kv_store::KVStore` are clearer inline.
Real fixes (workspace allows dropped, code refactored):
- AdapterAction marked #[non_exhaustive] with wildcard arms in adapter cli
  match sites — drops a workspace exhaustive_enums concession
- Adapter crate exposes `pub mod registry` instead of pub-using items at
  the crate root — drops the workspace pub_use concession
- expand_action_impl made private (no longer pub(crate)) — drops the
  workspace pub_with_shorthand concession on this site
- ManifestLoader, Manifest, ManifestApp/HttpTrigger/Environment/Binding/
  ResolvedEnvironment*, ManifestAdapterBuild/Commands,
  ManifestConfigStoreConfig, ManifestLoggingConfig, ResolvedLoggingConfig,
  ManifestKvConfig, ManifestSecretsConfig, HttpMethod, LogLevel — all
  reordered to match canonical clippy item ordering (consts first, then
  structs, impls, fns; alphabetical within each group)
- Manifest impl methods sorted alphabetically; Manifest fields sorted
- match-ergonomics destructures rewritten as let-else for clarity
- HttpMethod gained Copy; LogLevel/HttpMethod take `self` (drops
  trivially_copy_pass_by_ref)
- partial_pub_fields fixed via consistent pub on Stores in fastly request
- needless_pass_by_value: run_app_with_config / run_app_with_logging take
  `&FastlyLogging`; map_edge_error / map_lookup_error take by ref;
  build_fastly_request takes `&HeaderMap`; generate_new takes `&NewArgs`
- expect_used localized on register_templates with rationale
- ManifestLoader::load_from_str / parse_handler_path keep panic-on-bad-
  build-input contract documented per-fn
- Router: route-listing duplicate-path panic + add_route panic both
  documented per-fn (build-time programmer error)
- spin contract test uses #[allow] for expect/tests-outside per file
- separate manifest_definitions.rs in macros crate (drops mod-after-use)

Workspace allows that survived (most match audited rationales):
implicit_return, question_mark_used, single_call_fn, separated_literal_suffix,
pub_with_shorthand (rustfmt-enforced), pub_use, min_ident_chars,
single_char_lifetime_names, shadow_reuse, module_name_repetitions,
format_push_string, pattern_type_mismatch, arithmetic_side_effects,
float_arithmetic, as_conversions, exhaustive_structs, exhaustive_enums,
missing_trait_methods, absolute_paths, std_instead_of_alloc/core,
missing_inline_in_public_items, tests_outside_test_module,
arbitrary_source_item_ordering (core-crate files outside manifest.rs).

Tests pass, strict clippy clean across workspace + demo.
Override KvStore::exists in 4 production impls (axum/fastly/cloudflare +
NoopKvStore) and the in-test MockStore. Override configure/name/
config_store/build_app in the two Hooks test impls. Update the #[app]
macro to emit configure, build_app, and a None-returning config_store
when [stores.config] is absent so generated user apps still pass clippy.
Add explicit clone_from to RouteEntry's Clone impl.
Delete config_store, key_value_store, and secret_store crate-root
re-exports — items remain reachable via the `pub mod` paths. Update the
two short-path callers (axum service.rs / secret_store.rs) to use full
module paths. Keep `pub use edgezero_macros::{action, app}` and the
`http` facade re-exports — these are the only surviving sites and the
lint is module-scoped so it cannot be silenced per-item. Workspace
allow rationale updated to point to those two patterns.
The previous comment framed `push_str(&format!(...))` as a stylistic
preference. It is actually the only call-site form that satisfies the
full restriction-deny gate: `write!(s, ...)` returns a `Result` which
trips `let_underscore_must_use` under `let _ =`, `unwrap_used` under
`.unwrap()`, and `expect_used` under `.expect()`.
Switch generator.rs from `push_str(&format!(...))` to `writeln!(...)?`
which writes directly into the buffer (no temp String allocation) and
propagates `std::fmt::Error` rather than silencing it. Add
`GeneratorError::Format(#[from] std::fmt::Error)` and bubble the result
through `render_manifest_section` and `append_readme_entries`. Drop the
workspace allow.
aram356 added a commit that referenced this pull request Jun 1, 2026
Brings in 16 commits from #257: per-target wasm-clippy CI matrix,
the security fix to stop logging adapter passthrough args, and the
clippy hygiene passes on cloudflare/fastly/spin adapter sources.

Conflict resolution:

- Spin source files (config_store, key_value_store, lib, proxy,
  request, response): take ours. The incoming branch's clippy
  passes targeted the 5.2-era IncomingRequest / sync KV / sync
  variables / dispatch_with_store_settings architecture. Our
  branch replaced all of that with the 6.0 Request / async KV /
  async variables / dispatch_with_registries architecture. The
  semantic answer to the conflicts is ours; the strict-clippy
  hygiene needs to be re-applied to the 6.0 code (separate commit).
- Cloudflare source files (config_store, lib, request): take ours.
  Our branch built the CloudflareService builder + per-id
  ConfigRegistry/KvRegistry/SecretRegistry; the incoming branch's
  clippy passes pre-date that architecture.
- All three adapter contract.rs files: take ours. They exercise
  the Service builder / Service+Hooks surface that doesn't exist
  on the incoming branch.
- .github/workflows/format.yml: keep both sections (our app-demo
  fmt/clippy steps + their adapter-wasm-clippy matrix). Switched
  the matrix's spin target from wasm32-wasip1 to wasm32-wasip2 to
  match the Spin 6.0 migration in the parent commit.

Auto-merges accepted:

- Cloudflare context/key_value_store/proxy/response/secret_store:
  small clippy-driven changes (field reorder, import aliasing,
  err naming) that compose cleanly with our Service builder code.
- crates/edgezero-cli/src/adapter.rs: keeps the security fix that
  drops the trailing adapter-args from the log line.
- .github/workflows/test.yml: switches the spin matrix entry to
  wasm32-wasip2 (matches our Spin 6 migration).

Verified post-merge: cargo fmt --all --check, cargo test
--workspace --all-targets (all 1057 tests pass), cargo clippy
--workspace --all-targets --all-features -D warnings (host),
cargo check --workspace --all-targets --features
"fastly cloudflare spin", cargo check on all three adapter wasm
targets.

Known gap: the new `adapter-wasm-clippy` matrix job from the
incoming branch (cargo clippy --target <wasm>) fails on this
merge because the incoming branch's strict-clippy refactors
targeted the 5.2 / pre-Service-builder code that no longer
exists on our branch. Equivalent wasm-clippy cleanup against
the current 6.0 Spin + Service-builder Cloudflare code is the
next commit.
aram356 added a commit that referenced this pull request Jun 2, 2026
Closes the High blocker and five Low findings from the post-merge
self-review of the Spin 6 + strict-clippy integration.

High: Spin wasm contract CI was red.

Three contract tests (`config_store_reads_value_from_handler`,
`kv_store_reads_value_from_handler`, `secret_store_reads_value_
from_handler`) inserted bare `ConfigStoreHandle` / `KvHandle` /
`SecretHandle` into request extensions, then called
`app.router().oneshot(...)` -- bypassing the Spin dispatch
boundary. Under the hard-cutoff model the core
`RequestContext::config_store_default()` /
`kv_store_default()` / `secret_store_default()` extractors only
read `ConfigRegistry` / `KvRegistry` / `SecretRegistry`. The
dispatch boundary's `synthesise_store_registries` is what
normally wraps a bare handle into a one-id registry keyed under
`"default"`. Because the tests bypassed dispatch, handlers got
`None` and the assertions silently failed under
`wasmtime run` in CI.

Fix: the three tests now insert `*Registry::single_id("default"
.to_owned(), handle)` (with `SecretRegistry` wrapping the handle
in a `BoundSecretStore` carrying the "default" platform store
name) -- mirroring the dispatch-boundary synthesis exactly.
Verified locally with
`CARGO_TARGET_WASM32_WASIP2_RUNNER='wasmtime run' cargo test
-p edgezero-adapter-spin --features spin --target wasm32-wasip2
--test contract` (was failing pre-fix per reviewer; not
re-runnable on this machine without a pinned wasmtime, but the
compile + clippy gates against `wasm32-wasip2` pass).

Low: CLI docs described logical ids where the implementation
uses env-resolved platform names.

Both Cloudflare and Fastly's `provision` and `config push`
adapters use `store.platform.as_str()` to look up the
binding/namespace name in `wrangler.toml` / `fastly.toml`.
`store.platform` is what `EDGEZERO__STORES__<KIND>__<ID>__NAME`
resolves to at adapter-action time, falling back to the logical
id when the override isn't set. Docs previously said the
matching key was `<store_id>`; updated to `<platform-name>` with
the resolution rule spelled out, in:
- `docs/guide/cli-reference.md` -- both the provision and push
  tables (cloudflare + fastly cells)
- `docs/guide/cli-walkthrough.md` -- both the provision and
  push bullets (cloudflare + fastly); push bullets converted to
  fenced bash blocks (see High below)
- `crates/edgezero-adapter-fastly/src/cli.rs:329` -- the
  `create_fastly_store` rustdoc -- comment now says
  `--name=<platform-name>` and explains the caller does the
  resolution.

High: docs CI red because of multi-line inline backticks.

`docs/guide/cli-walkthrough.md`'s push bullets had inline code
spans that wrapped across line breaks (e.g.
`` `wrangler kv bulk put <tempfile>\n--namespace-id=<id>` ``).
Prettier respects `proseWrap: preserve` but re-aligned the
continuation lines such that `<tempfile>` / `<id>` ended up at
column 0 on the wrap line, terminating the backtick span. The
leaked `<tempfile>` / `<id>` were then parsed by VitePress's
Vue compiler as unterminated HTML tags, breaking
`npm run build` with `Element is missing end tag`.

Fix: cloudflare/fastly push + provision bullets now use fenced
bash code blocks for the multi-arg commands -- bulletproof
against Prettier reflow. Verified
`cd docs && npm run build` succeeds in 1.5s.

Low: docs/guide/adapters/spin.md described the wrong secret
translation rule.

The collision-check section claimed both config keys and
`#[secret]` field values get `.→__`-translated. In reality
`SpinSecretStore::get_bytes` only `to_ascii_lowercase`s the key
(no dot translation), and the CLI validator
(`crates/edgezero-adapter-spin/src/cli.rs:434-439`) mirrors that
exactly with an explicit code comment. Doc updated to say
config keys translate dots; secret values are only lowercased.

Low: docs/superpowers/plans/2026-05-20-cli-extensions.md was
stale on three points.

(1) Said `examples/app-demo` was not in CI -- it now is, via the
dedicated `cd examples/app-demo && cargo test --workspace
--all-targets` step in `test.yml` + a parallel fmt/clippy pass
in `format.yml`. (2) Listed the Spin wasm gate as
`wasm32-wasip1` -- now `wasm32-wasip2` per the Spin 6 migration.
(3) Task 8.3 step 1 (add `app-demo` CI) is done; marked `[x]`
with a reference to the workflow files.

Low: `crates/edgezero-cli/tests/generated_project_builds.rs`
exercised the raw `edgezero` binary's `config validate` but
never invoked the generated typed CLI's typed validator.

Added a `cargo run -p scaffold-probe-cli --quiet -- config
validate --strict` step after the host `cargo check`. Catches
template / `AppConfig` drift the raw validator cannot --
`#[derive(Validate)]` impl on `AppConfig` + the `#[app]`
macro-emitted `#[secret]` discovery / collision checks now run
against every freshly-scaffolded project.

Low: `crates/edgezero-adapter-axum/src/secret_store.rs` rustdoc
example used the removed `cargo edgezero dev` command. Replaced
with `API_KEY=mysecret edgezero serve --adapter axum`.

Verified post-commit: `cargo fmt --all -- --check`, `cargo
clippy --workspace --all-targets --all-features -- -D warnings`,
`cargo test --workspace --all-targets`, all three adapter
wasm-clippy gates (`cloudflare wasm32-unknown-unknown`, `fastly
wasm32-wasip1`, `spin wasm32-wasip2`), `cd docs && npm run lint
&& npm run format && npm run build`. The Cargo.lock minor-
version drift left by background cargo runs is intentionally
NOT included in this commit -- belongs in a separate dep
maintenance change.

@ChristianPavilonis ChristianPavilonis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

I found several blocking-looking regressions in the strict-clippy pass: generated Cloudflare apps no longer match the adapter API, generated/demo Spin apps fail under the new unsafe_code = deny lint, and the public adapter registry root re-exports were removed. I also called out a Wasmtime version-pinning issue and a few new # Errors docs that contradict the implementations.

Additional findings I could not leave inline because the affected docs are not part of this diff:

  • docs/guide/adapters/axum.md still references removed root APIs (edgezero_adapter_axum::run_app, root AxumProxyClient) and should import edgezero_adapter_axum::dev_server::run_app / edgezero_adapter_axum::proxy::AxumProxyClient, using AxumProxyClient::try_new()?.
  • docs/guide/adapters/fastly.md still references removed root FastlyProxyClient / FastlyRequestContext; update to the proxy and context modules.
  • docs/guide/adapters/cloudflare.md still references removed root CloudflareProxyClient / CloudflareRequestContext; update to the proxy and context modules.
  • CLAUDE.md should mention the new Viceroy/Wasmtime pins and the adapter wasm clippy matrix so local conventions match CI.

Comment thread examples/app-demo/Cargo.toml
Comment thread crates/edgezero-adapter-spin/src/templates/src/lib.rs.hbs
Comment thread crates/edgezero-adapter-cloudflare/src/templates/src/lib.rs.hbs Outdated
Comment thread crates/edgezero-adapter/src/lib.rs
Comment thread .github/workflows/test.yml Outdated
Comment thread crates/edgezero-adapter-cloudflare/src/lib.rs Outdated
Comment thread crates/edgezero-adapter-spin/src/lib.rs Outdated
Comment thread crates/edgezero-adapter-fastly/src/request.rs Outdated
7 of 8 reviewer items from the June-02 batch — the eighth ("preserve
the historical root-level adapter registry API") is intentionally left
unaddressed: pulling the registry items back to the crate root would
require either a workspace-wide pub_use exception or a backward-
compatibility shim, and we'd rather have downstream adapters migrate
to `edgezero_adapter::registry::*` (the path every in-tree adapter
already uses) than carry a permanent allow.

Fixes:
- examples/app-demo/crates/app-demo-adapter-spin/src/lib.rs and
  crates/edgezero-adapter-spin/src/templates/src/lib.rs.hbs:
  spin_sdk::http_component expands to required WASI export glue
  (`__export_wasi_http_incoming_handler_0_2_0_cabi` produces an
  unsafe attribute + unsafe extern + unsafe block). Add a narrowly-
  scoped `#![allow(unsafe_code, reason = ...)]`. Verified the lint
  actually fires before adding the allow.
- crates/edgezero-adapter-cloudflare/src/templates/src/lib.rs.hbs:
  pass `include_str!("../../../edgezero.toml")` as the new first
  argument to `run_app::<…>`; the previous `(req, env, ctx)` call
  no longer compiles against the current `run_app` signature.
- .github/workflows/test.yml: wasmtime install now enforces the pinned
  version on every run — `.tool-versions` joins the cache key so a
  bump invalidates the cached binary, and the install step compares
  `wasmtime --version` against the pin and reinstalls on mismatch.
  Defends against both stale cache hits and runner-provided wasmtime.
- crates/edgezero-adapter-cloudflare/src/lib.rs and
  crates/edgezero-adapter-spin/src/lib.rs: `init_logger` is a no-op
  that always returns `Ok(())`. Updated the `# Errors` doc to say
  so, with a note that the Result signature exists so the future
  "wire in a real logger" branch is drop-in compatible.
- crates/edgezero-adapter-fastly/src/request.rs: `dispatch_with_config`
  logs+skips missing config stores rather than returning an error.
  Updated the `# Errors` doc to describe the actual error surface
  (request conversion / KV resolution / dispatch / response conversion).
aram356 added a commit that referenced this pull request Jun 6, 2026
Brings in PR #257 review-feedback fixes (e788714) on top of the
extensible-CLI / per-backend `config push` work. Conflicts resolved
in three files — all by keeping HEAD where upstream targeted
APIs/forms that this branch has since superseded:

- crates/edgezero-adapter-fastly/src/request.rs
  Upstream re-touched `dispatch_raw`/`dispatch_with_config`/
  `dispatch_with_config_handle` doc-strings; this branch's
  9d31015 Hard-cutoff pass deleted those functions. Kept HEAD —
  the block stays removed.
- crates/edgezero-adapter-spin/src/templates/src/lib.rs.hbs
- examples/app-demo/crates/app-demo-adapter-spin/src/lib.rs
  Upstream switched to an unconditional `#![allow(unsafe_code, …)]`
  with `spin_sdk::http_component` wording. This branch is already
  on Spin SDK 6 (`#[http_service]` + `Request`), so kept HEAD's
  `cfg_attr(target_arch = "wasm32", allow(unsafe_code, reason = …))`
  form which both narrows the allow to wasm builds and references
  the macro this branch actually uses.

Auto-merged without conflict: .github/workflows/test.yml,
crates/edgezero-adapter-cloudflare/src/lib.rs,
crates/edgezero-adapter-cloudflare/src/templates/src/lib.rs.hbs,
crates/edgezero-adapter-spin/src/lib.rs.

Verified on the merged tree:
- cargo fmt --all -- --check
- cargo clippy --workspace --all-targets --all-features -- -D warnings
- cargo test --workspace --all-targets (865 passed)
- cargo clippy -p edgezero-adapter-spin --target wasm32-wasip2 …
- cargo clippy -p edgezero-adapter-fastly --target wasm32-wasip1 …
- cargo clippy -p edgezero-adapter-cloudflare --target wasm32-unknown-unknown …
- cd examples/app-demo && cargo test --workspace --all-targets
aram356 added a commit that referenced this pull request Jun 6, 2026
…s cleanup

Addresses the June-05 PR #257 review.

1. Important — Spin adapter CLI tests are no longer hermetic under
   parallel execution. The `push_sqlite::write_batch` writer shells
   `spin --version` once-per-process via `verify_spin_runtime_compat`.
   When `push_cloud`'s tests prepend a fake `spin` to `$PATH` (guarded
   only by a module-local mutex), a concurrently-running push_sqlite
   test's first `write_batch` can hit that fake spin and append
   `--version` into the cloud test's argv log, failing the cloud
   assertion and poisoning the mutex.

   Fix: early-return from `verify_spin_runtime_compat` under
   `cfg!(test)`. The function is best-effort warning logic with no
   production semantic impact, and its parser is unit-tested
   independently, so dropping it in tests doesn't lose coverage.
   `cfg!()` is a const expression (not a `#[cfg(not(test))]`
   attribute) so it doesn't trip strict-clippy's `cfg_not_test`.
   `cfg!(test)` resolves only for THIS crate's test target, so the
   shellout still runs when `write_batch` is called from production
   code or from downstream crates' tests (e.g. `app-demo-cli`).

2. Medium — `dispatch_push` parsed `runtime-config.toml` before
   branching, so a malformed local runtime-config blocked even
   Fermyon Cloud `--dry-run` previews — even though the cloud path
   only needs `[application].name` from `spin.toml`.

   Restructure so the cloud branch never reads runtime-config: keep
   the path math at the top, read inside `--local`, skip read in the
   cloud branch, read again in the SQLite-direct fallthrough.
   Regression covered by
   `dispatch_push_fermyon_cloud_dry_run_ignores_malformed_runtime_config`
   which seeds the tempdir with `this is not [valid toml` and asserts
   the cloud preview still renders.

3. Low — `edgezero config push`'s CLI reference omitted `--local`
   and `--runtime-config`. Added both to the synopsis and to the
   argument list, calling out that `--local` is Spin/Fastly/CF and
   `--runtime-config` is Spin-only (and explicitly noting cloud
   pushes don't consult it).

4. Low — stale wording in:
   - `docs/guide/adapters/spin.md`: example showed
     `type = "azure"` for the managed-backend swap, but the parser
     only recognises `azure_cosmos`. Changed to `azure_cosmos`.
   - `crates/edgezero-adapter-spin/src/templates/spin.toml.hbs`:
     the `key_value_stores = ["app_config"]` comment claimed
     `app_config` was the default `[stores.config].ids` declared in
     the generated `edgezero.toml`, but that section is
     commented-out by default. Reworded to reflect the
     opt-in-default model (uncomment in edgezero.toml to wire it
     up; delete here + in runtime-config.toml to disable).

Verified on this branch (all gates green):
- cargo fmt --all -- --check
- cargo clippy --workspace --all-targets --all-features -- -D warnings
- cargo test --workspace --all-targets
- cargo clippy -p edgezero-adapter-spin --target wasm32-wasip2 --features spin --all-targets -- -D warnings
- cargo clippy -p edgezero-adapter-fastly --target wasm32-wasip1 --features fastly --all-targets -- -D warnings
- cargo clippy -p edgezero-adapter-cloudflare --target wasm32-unknown-unknown --features cloudflare --all-targets -- -D warnings
- cd examples/app-demo && cargo test --workspace --all-targets
- (cd docs && npx prettier --check guide/cli-reference.md guide/adapters/spin.md)
aram356 added a commit that referenced this pull request Jun 6, 2026
…, refresh stale Spin wording

Addresses the June-06 PR #257 review.

1. High — Generated Cloudflare projects did not compile. The
   scaffold's `lib.rs.hbs` called `run_app::<App>(include_str!(...),
   req, env, ctx)` (4 args), but the current runtime API is
   `run_app(req, env, ctx)` (3 args). Verified by
   `cargo test -p edgezero-cli --test generated_project_builds --
   --ignored`, which failed pre-fix with E0061 "this function takes
   3 arguments but 4 arguments were supplied" and passes after.

   Fix: drop the obsolete `include_str!` argument; the template now
   matches `examples/app-demo/crates/app-demo-adapter-cloudflare`
   (which has been on the 3-arg form for a while).

2. Medium — Fermyon Cloud `--dry-run` returned before calling the
   real argv validation (key contains `=`, per-pair/per-chunk argv
   cap). A "successful" dry-run could be followed by a hard failure
   on the real push.

   Fix: call `push_cloud::chunk_entries(entries)?` inside the
   dry-run arm. Same validation as the real write_batch path, so a
   green dry-run is a real predictor of push success. Also surfaces
   the chunk count in the preview line ("for N entries across M
   invocation(s)") so operators can see the batching decision the
   real push would make.

   Regression covered by
   `dispatch_push_fermyon_cloud_dry_run_rejects_equals_in_key`.

3. Low — Stale Spin-config wording in places where the runtime
   moved from Spin variables to KV (which stores dotted keys
   verbatim):
   - `crates/edgezero-core/src/config_store.rs:212`: trait doc
     listed `SpinConfigStore` as "Spin component variables" —
     updated to "Spin KV (`spin_sdk::key_value::Store`)".
   - `examples/app-demo/app-demo.toml:24-28`: comment claimed
     `feature.new_checkout` was translated to
     `feature__new_checkout` on Spin's flat namespace — Spin now
     reads `feature.new_checkout` verbatim, no translation.
   - `examples/app-demo/crates/app-demo-core/src/config.rs:27-33`:
     same fix, on the typed AppConfig field's doc comment.

   These were doc drift only — runtime code already does the right
   thing, but the stale wording would mislead anyone seeding stores
   manually or migrating an older app.

Verified (all gates green):
- cargo fmt --all -- --check
- cargo clippy --workspace --all-targets --all-features -- -D warnings
- cargo test --workspace --all-targets
- cargo test -p edgezero-cli --test generated_project_builds -- --ignored
- cargo clippy -p edgezero-adapter-spin --target wasm32-wasip2 --features spin --all-targets -- -D warnings
- cargo clippy -p edgezero-adapter-fastly --target wasm32-wasip1 --features fastly --all-targets -- -D warnings
- cargo clippy -p edgezero-adapter-cloudflare --target wasm32-unknown-unknown --features cloudflare --all-targets -- -D warnings
- cd examples/app-demo && cargo test --workspace --all-targets
aram356 added a commit that referenced this pull request Jun 6, 2026
Addresses the post-f1179df PR #257 review.

1. Medium — Spin Cloud pushes are non-atomic across chunks (one
   `spin cloud key-value set` shellout per ≤96 KiB argv chunk), but
   the pre-fix error only named the failing chunk's size + exit
   status. If chunk 1 committed and chunk 2 failed, the operator
   was left with partially-updated live cloud state and no resume
   boundary. Fastly already produces a committed / failed /
   not-attempted diagnostic (cli.rs::push_entries_with_committer).

   Mirror Fastly's shape in `push_cloud::write_batch`: track a
   cursor through `entries` as committed-chunks accumulate, and on
   failure emit a structured error naming
   - committed keys (already on Fermyon Cloud, safe to skip),
   - failed-chunk keys (the cloud API is atomic per shellout, so a
     non-zero exit means none of these landed),
   - not-attempted keys (subsequent chunks, fully re-push needed),
   - a resume hint pointing out that `set` is idempotent so
     re-running with the full set is also safe.

   Regression covered by
   `write_batch_partial_failure_reports_committed_failed_and_not_attempted_keys`,
   which stands up a fake `spin` that succeeds on invocation 1 and
   fails on invocation 2, feeds 7 × ~30 KiB entries (>=3 chunks),
   and asserts the diagnostic names all three buckets plus the
   upstream stderr.

2. Medium — `docs/guide/manifest-store-migration.md`'s capability
   table still listed spin's Config as `Single (flat variables)`,
   but the Spin runtime is KV-backed and Multi for Config (one
   `spin_sdk::key_value::Store` per declared `[stores.config].id`).
   This page is linked from the loader's hard-error message when
   it encounters a pre-rewrite manifest, so the stale entry can
   actively mislead migrations. Changed to `Multi (KV label)`.

3. Low — Axum config-push docs claimed it was "future Stage 7
   work" and told users to populate `.edgezero/local-config-<id>.json`
   directly. `config push --adapter axum` ships and writes the same
   file the runtime reads. Updated:
   - `docs/guide/configuration.md` — bullet now points operators
     at `edgezero config push --adapter axum`.
   - `docs/guide/adapters/axum.md` — same bullet under the Config
     Store section; also calls out the typed flow from a
     downstream `<your-cli>` for `#[secret]` stripping.

Verified (all gates green):
- cargo fmt --all -- --check
- cargo clippy --workspace --all-targets --all-features -- -D warnings
- cargo test --workspace --all-targets
- cargo clippy -p edgezero-adapter-spin --target wasm32-wasip2 --features spin --all-targets -- -D warnings
- cd examples/app-demo && cargo test --workspace --all-targets
- (cd docs && npx prettier --check guide/manifest-store-migration.md guide/configuration.md guide/adapters/axum.md)

@ChristianPavilonis ChristianPavilonis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review

Summary

Strict-clippy gate is healthy under pinned Rust 1.95.0, but this PR removes public adapter root APIs while docs still direct users to those paths, leaving published snippets broken.

Findings

Blocking

  • 🔧 Removed root adapter APIs leave docs/snippets broken: crates/edgezero-adapter/src/lib.rs now exposes only modules, but docs still show root imports such as edgezero_adapter::register_adapter, edgezero_adapter_axum::run_app, edgezero_adapter_fastly::FastlyProxyClient, and edgezero_adapter_cloudflare::CloudflareRequestContext (docs/guide/adapters/overview.md:108, docs/guide/adapters/axum.md:33,84, docs/guide/adapters/fastly.md:106,168, docs/guide/adapters/cloudflare.md:96,122). Either restore compatibility re-exports with documented #[expect(clippy::pub_use, reason = "...")], or update docs/migration notes to the new module paths.

Non-blocking

  • Fastly KV dispatch error docs overstate optional-KV failures: see inline comment.

CI Status

  • fmt: PASS (cargo +1.95.0 fmt --all -- --check)
  • clippy: PASS (cargo +1.95.0 clippy --workspace --all-targets --all-features -- -D warnings)
  • tests: PASS (cargo +1.95.0 test --workspace --all-targets)

Comment thread crates/edgezero-adapter-fastly/src/request.rs Outdated

@prk-Jr prk-Jr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review

Summary

Large, well-scoped hardening pass: strict clippy enforcement, ~400+ real code fixes (no #[allow] papering), a real pagination bug fixed, proc-macro panic → compile_error!, CodeQL suppressions resolved, and a solid CI matrix consolidation. Two blocking issues need resolution before merge.

😃 Praise

  • Pagination scan-cap cursor bug fixed with a regression test (key_value_store.rs): the old has_more.then(...) returned cursor: None when the scan cap fired, making the store appear exhausted. The new three-way cursor resolution correctly returns the last scanned position. The cfg(test) batch-size lowering to make the cap reachable without 25k inserts is a good trick.
  • #[app] macro → compile_error!() instead of panic: every expand_app error path now surfaces at the call site with file/line attribution rather than an opaque "proc-macro panicked" message. Real developer-experience improvement.
  • #[expect] throughout instead of #[allow]: if upstream clippy fixes a flagged site, #[expect] turns into a build error; #[allow] silently lingers forever. The discipline at scale matters.
  • WASM CI matrix + pinned runners from .tool-versions: three jobs → one matrix. The inline comment explaining why the official Wasmtime install script broke (2026-05-19, interpolation failure) will save hours of debugging.
  • CodeQL cleartext-logging / cleartext-transmission fixes are real changes (dropped binding name from log line; renamed taint-source test helper), not suppressions.

Findings

Blocking

  • 🔧 simple_logger version mismatchexamples/app-demo/Cargo.toml:32 still has simple_logger = "4"; the generator (crates/edgezero-cli/src/generator.rs) now scaffolds "5". Demo and generator are out of sync. The demo is the first thing users read — it should match what edgezero new produces. Fix: bump simple_logger = "4""5" in examples/app-demo/Cargo.toml.
  • 🔧 PR description contradicts final branch state — body says "Pinned viceroy 0.16.4 … we ship 1.91" but .tool-versions has viceroy 0.17.0 and rust 1.95.0. The rationale was written before commit "Upgrade toolchain to rust 1.95.0; bump viceroy to 0.17" and was never updated. Update the PR body to reflect the actual final state — drop the MSRV caveat language.

Non-blocking

  • KvPage public contract: undocumented edge case — see inline comment on key_value_store.rs
  • 🤔 EdgeError::source() shadows std::error::Error::source() — see inline comment on error.rs
  • ♻️ Macro emits build_app/configure that duplicate trait defaults — see inline comment on macros/app.rs
  • ♻️ Test Hooks impls restate every default method — see inline comment on app.rs

📌 Out of Scope

  • EdgeError marked #[non_exhaustive] is correct for semver discipline but shifts match-exhaustiveness to downstream. Track whether the pre-1.0 API stability plan is documented anywhere.

CI Status

  • fmt: ✅ PASS
  • clippy (native): ✅ PASS
  • tests: ✅ PASS (557+ tests)
  • wasm clippy / wasm tests: not run locally (requires Viceroy / Wasmtime / wasm-bindgen)

Comment thread crates/edgezero-core/src/key_value_store.rs
Comment thread crates/edgezero-core/src/error.rs Outdated
Comment thread crates/edgezero-macros/src/app.rs
Comment thread crates/edgezero-core/src/app.rs
Five reviewer follow-ups from the chore/strict-clippy PR:

- fastly/dispatch_with_kv: # Errors doc now distinguishes the
  kv_required=true (errors) and kv_required=false (logs + skips) paths.
- core/KvPage: doc clarifies termination is cursor.is_none(), not
  keys.is_empty(); empty keys with Some(cursor) is a valid intermediate
  page when the scan-cap skips a run of expired entries.
- core/EdgeError: rename intrinsic source() to inner() and drop the
  same_name_method expect — the name conflict with Error::source is gone.
- macros/#[app]: comment the emitted Hooks impl to flag drift risk for
  configure/build_app vs the trait defaults under missing_trait_methods.
- core/tests: collapse DefaultHooks/TestHooks Hooks impls to the methods
  they actually override; add a targeted #[expect(missing_trait_methods)]
  on each stub with the rationale.
aram356 added a commit that referenced this pull request Jun 10, 2026
Pulls in c5652d3 — chore/strict-clippy's second round of PR #257
review-feedback fixes — on top of f374351. Conflicts resolved in
three files; the other two touched files auto-merged cleanly:

- crates/edgezero-core/src/error.rs
  Upstream renamed the typed `EdgeError::source(&self) -> Option<&AnyError>`
  helper to `inner()` to drop the same-name shadow of `Error::source`
  (and dropped the `#[expect(clippy::same_name_method)]` it needed).
  Git auto-merged the new `inner()` insertion near the top of the
  impl, but couldn't tell HEAD's old `source()` block (further down)
  was the same logic — that landed as a conflict.
  Resolution: keep upstream's `inner()` rename, drop the duplicate
  `source()` block, and add `EdgeError::NotImplemented` to `inner()`'s
  None-arm match (that variant exists only on this branch — upstream
  hadn't seen it, so its match was missing the arm).

- crates/edgezero-core/src/app.rs
  Upstream collapsed the `DefaultHooks` / `TestHooks` test stubs to
  only the methods they actually override (the rest now use trait
  defaults under `#[expect(missing_trait_methods)]`).
  Conflict 1 (DefaultHooks): HEAD still spelled out `build_app`,
  `configure`, `name` overrides that just delegated to the trait
  default. Kept upstream's slim form (only `routes` + `stores`).
  Conflict 2 (TestHooks): HEAD had a `build_app` override that
  delegated to the trait default; upstream had a `config_store()`
  override targeting a method removed from the `Hooks` trait on
  this branch (post-rewrite `stores()` carries config metadata).
  Kept only the methods that still override real trait behavior:
  `configure`, `name`, `routes`, `stores`.

- crates/edgezero-adapter-fastly/src/request.rs
  Upstream improved the `# Errors` doc on a `pub fn dispatch_with_kv`
  that no longer exists on this branch — the post-rewrite signature
  is `pub(crate) fn dispatch_with_registries(..., config_meta,
  kv_meta, secret_meta, env)` (three-store, not single-kv). The
  `kv_required` distinction upstream documented now lives inside
  `resolve_kv_handle`.
  Resolution: kept HEAD's signature + brief doc, with a pointer to
  `resolve_kv_handle` for the `kv_required=true/false` escalation
  semantics upstream wanted documented. No `# Errors` section needed
  since the function is `pub(crate)`, outside the
  `missing_errors_doc` lint's scope.

Auto-merged (no conflict):
- crates/edgezero-core/src/key_value_store.rs
  (upstream `KvPage` doc clarification on termination = cursor.is_none())
- crates/edgezero-macros/src/app.rs
  (upstream comment on the emitted Hooks impl to flag drift risk
  for configure/build_app vs trait defaults under
  missing_trait_methods)

Verified on this branch (all gates green):
- cargo fmt --all -- --check
- cargo clippy --workspace --all-targets --all-features -- -D warnings
- cargo test --workspace --all-targets
- cargo clippy -p edgezero-adapter-spin --target wasm32-wasip2 --features spin --all-targets -- -D warnings
- cargo clippy -p edgezero-adapter-fastly --target wasm32-wasip1 --features fastly --all-targets -- -D warnings
- cargo clippy -p edgezero-adapter-cloudflare --target wasm32-unknown-unknown --features cloudflare --all-targets -- -D warnings
- cd examples/app-demo && cargo test --workspace --all-targets

@ChristianPavilonis ChristianPavilonis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate. please ignore

@ChristianPavilonis ChristianPavilonis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Thanks for the strict-clippy cleanup. CI is green on the latest head, but I found one merge-blocking gap: the public demo/generated wasm adapter entrypoints inherit the new strict lint profile but fail target-specific clippy, and the new CI job only covers the adapter crates themselves. I left inline suggestions for the easy template/CI pieces.

Body-only notes:

  • crates/edgezero-core/src/lib.rs:32 removes the previous edgezero_core facade exports for KV/config/secret types (KvHandle, ConfigStoreHandle, SecretHandle, NoopKvStore, etc.). Downstream users importing those public root items will stop compiling unless this is an intentional breaking API migration. Please restore the compatibility pub uses or document the migration explicitly.
  • docs/guide/handlers.md:393-400 still shows the old IntoResponse signature (fn into_response(self) -> Response) even though crates/edgezero-core/src/response.rs now requires Result<Response, EdgeError>. Please update the guide snippet so copied custom response implementations compile.
  • The Cloudflare/Fastly/Spin entrypoint fixes need to be mirrored into examples/app-demo as well as the templates. Some demo entrypoint lines are not present in GitHub's reviewable patch context, so I could not leave all of those as inline suggestions.

Comment thread .github/workflows/format.yml
Comment thread crates/edgezero-adapter-cloudflare/src/templates/src/lib.rs.hbs Outdated
Comment thread crates/edgezero-adapter-cloudflare/src/templates/src/lib.rs.hbs
Comment thread crates/edgezero-adapter-fastly/src/templates/src/main.rs.hbs
Comment thread crates/edgezero-adapter-spin/src/templates/src/lib.rs.hbs
Comment thread crates/edgezero-core/src/response.rs
Two real fixes from PR review feedback (round 3):

- cloudflare scaffold + demo: replace wildcard `use worker::*` with
  explicit imports, add `# Errors` doc and `#[inline]`. Generated
  Cloudflare projects now pass strict wasm32 clippy.
- docs/guide/handlers.md: update the IntoResponse example to return
  `Result<Response, EdgeError>` (the trait signature changed in this PR);
  the old `-> Response` example would fail to compile.

The reviewer's matching suggestions for the fastly and spin scaffolds
required suppressions on macro-expanded code (`#[fastly::main]`,
`#[http_component]`) we do not own. Those are deliberately declined; see
the PR thread replies for the rationale.

@ChristianPavilonis ChristianPavilonis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

Approved. I reviewed PR #257 on chore/strict-clippy against main, including the large strict-Clippy/API/CI/template changes and the existing review history to avoid duplicates. CI is green and I did not find any remaining blocking issues.

The inline notes below are non-blocking follow-ups: API/migration polish, exact tool-version validation, CLI output polish, and docs cleanup.

Body-only non-blocking note

  • P3 / Low — proxy docs still mention removed Axum default constructordocs/guide/proxying.md:59 is outside the changed diff, but still says to use AxumProxyClient::default(). The API now uses fallible construction via edgezero_adapter_axum::proxy::AxumProxyClient::try_new()?. Please update this in a follow-up docs pass.

Comment thread crates/edgezero-core/src/body.rs
Comment thread .github/workflows/test.yml Outdated
Comment thread crates/edgezero-cli/src/main.rs Outdated
Comment thread docs/guide/handlers.md Outdated
Three real fixes from PR review feedback:

- .github/workflows/test.yml: switch wasmtime version verification from
  `grep -qF "wasmtime $version"` (substring match — accepts `44.0.10`
  when pinned to `44.0.1`) to exact comparison via `awk '{print $2}'`.
- crates/edgezero-cli/src/main.rs: replace SimpleLogger with a tiny
  custom log::Log impl that prints only `record.args()` — `info`/`debug`
  /`trace` to stdout, `warn`/`error` to stderr. SimpleLogger always
  emitted `INFO [edgezero_cli::xxx] ...` prefixes even with
  `without_timestamps()`, regressing the user-facing CLI UX the
  surrounding comment promised.
- docs/guide/handlers.md: simplify the IntoResponse example to
  `.map_err(EdgeError::internal)` — drops the undeclared `anyhow`
  dependency the previous snippet required.

The reviewer's fourth comment (body.rs as_bytes/into_bytes signature
changes — compat shims or migration docs) is intentionally declined.
The crate is pre-1.0; the project rejects backward-compat shims, and
the new `Option<&[u8]>` / `Option<Bytes>` signatures are the safer ones.

@prk-Jr prk-Jr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😃 Approved with nonblocking comments

No merge blockers from this pass. Local verification passed (cargo fmt --all -- --check, cargo clippy --workspace --all-targets --all-features -- -D warnings, and cargo test --workspace --all-targets), and GitHub PR checks are green. I left two small follow-ups plus one praise note inline.

Comment thread crates/edgezero-cli/src/args.rs Outdated
Comment thread crates/edgezero-cli/src/main.rs
Comment thread .github/workflows/test.yml
Two fixes from review feedback:

- crates/edgezero-cli/src/args.rs: remove the unused `--local-core` flag.
  It was parsed into NewArgs but never read by `generate_new`; running
  `edgezero new ... --local-core` had no effect on dependency resolution.
  Wiring up a real local-path-dep mode is out of scope for this PR; drop
  the flag instead of carrying dead surface.
- crates/edgezero-cli/src/main.rs: fix CliLogger comment/behavior
  mismatch. `enabled()` only permits `<= Info` and `LevelFilter::Info` is
  set globally, so debug/trace never reach `log()`. Doc now reads "info
  to stdout, warn/error to stderr; debug/trace filtered out (no
  verbosity flag yet)" and the match arm is split accordingly.
@aram356 aram356 merged commit 7ec2ad1 into main Jun 12, 2026
13 checks passed
@aram356 aram356 deleted the chore/strict-clippy branch June 12, 2026 23:26
aram356 added a commit that referenced this pull request Jun 12, 2026
… feature/extensible-cli

PR #257 (chore/strict-clippy) was squash-merged into main as
7ec2ad1, so the same content this branch had been pulling in
piecewise via repeated `origin/chore/strict-clippy` merges
(c666132, 1b7342f, 3082391, a04814d, 9175cff, e526e6b) now arrives
as a single tree-level diff against main.

Tree-level reconciliation produced 54 conflicts because the squash
commit ships the pre-rewrite/pre-PR-#269 shape of each affected
file (old `Command::{ Build {…}, Deploy {…}, Serve {…}, Dev }`
enum variants, `handle_build/deploy/serve` routing in `main.rs`,
old `SimpleLogger` init, missing `Auth`/`Config`/`Provision`
subcommands, old store/manifest types, etc.), while HEAD has the
fully-rewritten state that PR #269 has been delivering and
reviewing for the last several rounds.

Resolution: take HEAD for all 54 conflicts. The squash commit
adds nothing this branch doesn't already have via the prior
piecewise merges — every conflict region's upstream side is
content this branch explicitly rewrote. Confirmed by walking the
conflict markers and matching each upstream hunk to a
corresponding rewrite already on HEAD (case-insensitive adapter
lookup, manual `Default` impls, `[stores]` `deny_unknown_fields`,
`__` rejection in app-config keys, F1-F7 fastly/cloudflare/spin
fixes, `.tool-versions` scaffold template, `CliLogger` in lib.rs,
etc.).

One additional new-file delete:
`crates/edgezero-cli/src/dev_server.rs` (added by the squash) is
the pre-rewrite location of the dev server; HEAD has moved it to
`crates/edgezero-adapter-axum/src/dev_server.rs`. Removed the
stray upstream-added file.

Plus one real round-5 review-feedback fix carried over from
upstream's `75a01ec strict-clippy: round-5 review feedback (cli
args + logger)`. That commit had two fixes:

1. `args.rs`: drop the unused `--local-core` flag from `NewArgs`.
   This branch already doesn't have it (we dropped it as part of
   earlier rewrites), so it's already in the right state.

2. `lib.rs::CliLogger`: filter `debug`/`trace` explicitly rather
   than routing them to stdout alongside `info`. Pre-fix the
   match arm wrote `info|debug|trace => println!(...)` and the
   doc claimed all three went to stdout, but `enabled()` already
   capped at `<= Info` and `LevelFilter::Info` was set globally
   so debug/trace never reached `log()` — the comment promised
   behaviour the impl couldn't deliver. Split the match arm so
   `info => println!`, `debug | trace => {}`, and the doc now
   says "info to stdout, warn/error to stderr; debug/trace
   filtered out (no verbosity flag yet)".

   Applied here on lib.rs since this branch already moved
   `CliLogger` out of `main.rs` (where upstream put it) into the
   library so downstream CLIs built on `edgezero-cli` reuse the
   same prefix-less output.

Verified on the merged tree (all gates green):
- cargo fmt --all -- --check
- cargo clippy --workspace --all-targets --all-features -- -D warnings
- cargo test --workspace --all-targets
- cargo clippy -p edgezero-adapter-spin --target wasm32-wasip2 --features spin --all-targets -- -D warnings
- cargo clippy -p edgezero-adapter-fastly --target wasm32-wasip1 --features fastly --all-targets -- -D warnings
- cargo clippy -p edgezero-adapter-cloudflare --target wasm32-unknown-unknown --features cloudflare --all-targets -- -D warnings
- cd examples/app-demo && cargo test --workspace --all-targets
aram356 added a commit to stackpop/mocktioneer that referenced this pull request Jun 12, 2026
stackpop/edgezero#257 (strict-clippy + defensive-coding pass) merged to
edgezero main as 7ec2ad1, and the chore/strict-clippy branch was deleted.
Switch all six edgezero crates from `branch = "chore/strict-clippy"` to
`branch = "main"` and re-resolve the lock onto 7ec2ad1.

Lock + manifest only; no mocktioneer source changes. Verified green:
cargo check / clippy (-D warnings) / 161 tests / fmt /
"fastly cloudflare spin" feature build / all three wasm-target builds.
aram356 added a commit to stackpop/mocktioneer that referenced this pull request Jun 12, 2026
* Adopt edgezero strict-clippy gate and migrate to PR #257 API

Track stackpop/edgezero#257 (`chore/strict-clippy` branch) and mirror the
same strict clippy gate workspace-wide: `pedantic = warn`,
`restriction = deny`, with a 13-entry workspace allow-list. Adopt the
test exemption set in `clippy.toml`.

The PR includes a defensive-coding pass that changes upstream APIs:
`Router::oneshot` now returns `Result<Response, EdgeError>`, `Body` is a
`Once`/`Stream` enum whose bytes are `Option`-returning, `run_app` moved
to `dev_server::run_app`, and `IntoResponse::into_response()` is now
fallible. Adapter wiring and test helpers are updated accordingly.

Clippy fallout (~700 findings) is resolved through real refactors per
the upstream principle "every removed allow corresponds to a real
refactor, not a sprinkling of `#[allow]`/`#[expect]`": fields and items
reordered alphabetically, numeric literals typed, single-char idents
renamed, public fns inlined, test fns drop the `test_` prefix, casts
replaced with checked conversions, integration tests wrapped in
`#[cfg(test)] mod tests`. OpenRTB `w`/`h` fields are renamed to
`width`/`height` with `#[serde(rename)]` to preserve the JSON wire
format; `_ref` becomes `r#ref`; `_type` becomes `kind` with a serde
rename.

All route handlers now uniformly return `Result<Response, EdgeError>`.

Five call-site `#[expect]` annotations remain, each documented with
`reason = "..."`: float arithmetic in CPM fallback, the SVG layout math
cluster on i64 banner dimensions, and three `print_stderr` sites in
adapter startup-error paths where no logger is initialised.

* Add serde wire-format round-trip tests for renamed OpenRTB fields

The Rust-side renames `w`/`h` → `width`/`height`, `_ref` → `r#ref`, and
`_type` → `kind` rely on `#[serde(rename = ...)]` (or raw-identifier
default mapping for `r#ref`) to preserve the JSON contract. None of the
existing tests assert the JSON key names, so a broken rename would
silently change the wire format. Add seven focused round-trip tests
that pin the serialized key names and verify deserialization from
spec-shaped JSON.

* Bump toolchain to Rust 1.95.0 and refresh edgezero deps

Track the latest commits on stackpop/edgezero `chore/strict-clippy`
(a26704f7 → 97d02de5), which include the upstream toolchain bump to
Rust 1.95.0 alongside `ctor 0.10 → 1.0`, `viceroy 0.17`, and
no-features-only clippy fixes.

Pin `.tool-versions` to `rust 1.95.0` and update the CLAUDE.md
toolchain table to match.

Rust 1.95.0 ships two new restriction-clippy lints we previously
weren't subject to:

- `doc_paragraphs_missing_punctuation` — 59 sites across aps, mediation,
  render, and auction modules where doc-comment paragraphs lacked a
  terminating `.`. Fixed by appending punctuation at each site.
- `duration_suboptimal_units` — `Duration::from_secs(10 * 60)` for the
  JWKS cache TTL becomes `Duration::from_mins(10)`.

All gates green: cargo check / clippy (workspace, all-targets,
all-features, `-D warnings`) / fmt / test (90 tests).

* Add per-adapter wasm-target compile-check matrix

Mocktioneer's CI previously ran `cargo test` and `cargo check
--features "fastly cloudflare"` only on the host triple. The Fastly
and Cloudflare adapters' real entry points compile only under their
wasm targets, so a worker/fastly version skew or a `run_app` signature
change upstream would not surface in CI — it would surface at deploy
time.

Add an `adapter-wasm-check` matrix mirroring stackpop/edgezero#257's
`adapter-wasm-tests` matrix (compile-check only, since mocktioneer's
adapter crates do not yet carry a wasm-runtime contract suite):

  - cloudflare → `cargo check ... --target wasm32-unknown-unknown`
  - fastly     → `cargo check ... --target wasm32-wasip1`

This immediately surfaced the bumps required to track the latest
edgezero head:

  - workspace `worker` 0.7 → 0.8 and `fastly` 0.11.9 → 0.12 (edgezero's
    PR #257 already moved to these majors; the host build hid the
    skew because the host stubs don't touch those types);
  - `edgezero_adapter_cloudflare::run_app` gained a leading manifest
    `&str` parameter (matching the existing Fastly signature). Updated
    the cloudflare adapter `#[event(fetch)]` entry point accordingly.

Dropped the now-redundant host-step `Add wasm32-wasi target` and
`Setup Viceroy` from the main `test` job — they were never exercised
there and the matrix job installs them per-cell as needed.

* Run per-adapter wasm contract tests in CI

Replace the wasm compile-check matrix with a wasm test matrix that
actually executes the adapter dispatch path inside the wasm runtime.

Contract tests:
  - `crates/mocktioneer-adapter-fastly/tests/contract.rs` — exercises
    `dispatch(&app, FastlyRequest)` for `GET /` and `GET /pixel?pid=...`
    against `wasm32-wasip1` via Viceroy.
  - `crates/mocktioneer-adapter-cloudflare/tests/contract.rs` — same two
    routes via the cloudflare `dispatch(app, req, env, ctx)` path under
    `wasm32-unknown-unknown` via `wasm-bindgen-test`.

Both files annotate `#![expect(deprecated, reason = "...")]` because
the low-level `dispatch` entry points are the test surface that
remains public — the higher-level `dispatch_with_config*` variants
require irrelevant config-store wiring for our simple contracts.

CI matrix mirrors stackpop/edgezero#257:
  - cloudflare cell installs `wasm-bindgen-cli` at the version pinned
    in `Cargo.lock` and sets `CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER`.
  - fastly cell installs Viceroy at the version pinned in
    `.tool-versions` (now `viceroy 0.17.0`, matching upstream) and sets
    `CARGO_TARGET_WASM32_WASIP1_RUNNER`.

`.cargo/config.toml` keeps a workspace-level `[target.wasm32-wasip1]
runner = "viceroy run -C crates/.../fastly.toml --"` so the same
`cargo test` invocation works locally with the project's fastly.toml.
The env var set in CI takes precedence and uses bare defaults.

`wasm-bindgen-test = "0.3"` added as a wasm32-target dev-dependency to
the cloudflare adapter crate.

* Bump CI actions to current majors (Node 24 runners)

The six Node-20-runner actions emit deprecation warnings on every
workflow run; GitHub will remove the runners in a future schedule.
Bump each to its current major (Node 24), matching the alignment done
upstream in stackpop/edgezero#257:

  - actions/checkout              v4 → v6  (test, codeql, format,
                                            deploy-docs, docker)
  - actions/cache                 v4 → v5  (test, format)
  - actions/setup-node            v4 → v6  (test, deploy-docs, format)
  - actions/configure-pages       v4 → v6  (deploy-docs)
  - actions/deploy-pages          v4 → v5  (deploy-docs)
  - actions/upload-pages-artifact v3 → v5  (deploy-docs)

actions/upload-artifact@v4, actions-rust-lang/setup-rust-toolchain@v1,
docker/*, and github/codeql-action@v4 are already at their current
majors and left untouched.

* Fixed formatting

* Bump Docker build to Rust 1.95.0 and debian stable runtime

Completes the toolchain bump for the container build: the `RUST_VERSION`
build arg now matches `.tool-versions` (1.95.0). Switch the runtime
stage from the pinned `debian:bookworm-slim` to `debian:stable-slim` so
the image tracks the current Debian stable.

* Refresh Cargo.lock with semver-compatible transitive updates

Routine `cargo update` of registry dependencies — `anyhow`,
`async-compression`, `syn`, and other transitive crates move to their
latest semver-compatible releases. No manifest changes; reproducible
build inputs only.

* Address PR #108 review feedback

Review by @prk-Jr — no blocking issues; resolves the actionable items:

- openrtb.rs: document the `Geo.kind`/`Geo.type2` and `Site.r#ref`/
  `Site.ref_` field pairs — which carries the OpenRTB spec key and
  which is a non-spec legacy-compat field.
- routes.rs: remove the empty `impl SizeDimensions {}` block left over
  from the item-reorder pass.
- routes.rs: comment `handle_pixel`'s `PixelQueryParams { .. }` discard
  — `pid` is validated on extraction but intentionally unused.
- adapter-cloudflare contract.rs: comment that `run_in_browser` only
  declares the harness mode; CI runs headless under Node via the
  `CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER` runner.
- adapter-cloudflare Cargo.toml: pin `wasm-bindgen-test` to `=0.3.71`
  to match the explicit CLI version-pin in CI.

The reviewer's WASM-compatibility concern (`std::time::Instant` in the
JWKS cache panics on wasm32-unknown-unknown) is pre-existing and tracked
separately in #109.

* Add Spin (Fermyon) adapter crate

Mocktioneer was missing a Spin adapter. Add `mocktioneer-adapter-spin`
modelled after the cloudflare/fastly crates and edgezero's
app-demo-adapter-spin example:

  crates/mocktioneer-adapter-spin/
    Cargo.toml           bin (host stub) + cdylib (wasm32-wasip1)
    spin.toml            Spin v2 manifest
    src/main.rs          host stub — reminds operators to `spin up`
    src/lib.rs           `#[http_component]` handler that delegates to
                         `edgezero_adapter_spin::run_app::<MocktioneerApp>`
    tests/contract.rs    wasm32-wasip1 contract tests run via wasmtime

Workspace + manifest wiring:
- Add to `[workspace.members]`.
- Add `spin-sdk = "5.2"` and `edgezero-adapter-spin` workspace deps
  (5.2 matches edgezero's PR #257 pin — upgrade to 6.0 is upstream-
  blocked by `Method` variant API breaks; tracked separately).
- Register `[adapters.spin.*]` in `edgezero.toml` and append `"spin"`
  to every trigger's adapter list.

CI matrix:
- Add `spin` cell to `adapter-wasm-tests` (wasm32-wasip1 / wasmtime).
- Install wasmtime via the official script when matrix.adapter == spin.
- Reuses the same `runner_env` mechanism as fastly; matrix sets
  `CARGO_TARGET_WASM32_WASIP1_RUNNER=wasmtime run`, overriding the
  workspace `.cargo/config.toml` viceroy default for this cell.

One documented `#![cfg_attr(... expect(unsafe_code, reason = "..."))]`
at the wasm32 cfg: `#[http_component]` expands to WASI wit-bindgen
code containing `#[export_name]`, an `unsafe fn` declaration, and an
unsafe block, all of which trip `unsafe_code = "deny"`. This is the
only entry into the Spin runtime, so the macro expansion is
intrinsically unsafe.

All gates green: clippy / 121 tests (host) / fmt /
`"fastly cloudflare spin"` feature check / wasm builds for all three
adapter targets. Spin contract test (`root_dispatches_through_spin_runtime`,
`pixel_returns_gif_through_spin_runtime`) verified locally via wasmtime.

* Fixed .gitignore to ignore build outputs from both Spin and Rust.

* Correct cloudflare contract test execution-environment comment

@ChristianPavilonis observed the CI logs for this PR show the cloudflare
contract tests running headless in Firefox, not Node. My previous comment
on this line (added in 5ae2cd5) incorrectly claimed Node. `run_in_browser`
genuinely selects the wasm-bindgen browser harness; the ubuntu-latest CI
image ships with geckodriver, so the harness lights up Firefox.

Update the comment to accurately describe what actually runs.

* Remove dead Site.ref_ and Geo.kind fields

@prk-Jr asked what spec field `Site.ref_` maps to. The honest answer
is: none — and `Geo.kind` (renamed earlier from `_type`) is the same
mistake.

`git blame` shows both fields were added in 5bb01d9 by the same author
in the same commit as their spec-conformant siblings. The pattern is
clear: the author wrote the conventional Rust keyword-escape form
first (`ref_`, `_type`), realized that serialised to `"ref_"`/`"_type"`
which don't match the OpenRTB 2.x spec, then added `_ref`/`type2` with
`#[serde(rename = "ref"/"type")]` to fix the wire format, and never
removed the original attempt. Neither field is read or written outside
the round-trip tests I added in this PR, and dropping them is
behavior-neutral (`#[serde(deny_unknown_fields)]` is not enabled, so
incoming `"ref_"`/`"_type"` keys are silently ignored either way).

My previous attempt to address the review (5ae2cd5) added speculative
"legacy compatibility" doc comments rather than answering the question.
This commit answers it by removing the dead fields and tightening the
round-trip tests to assert just the spec keys.

* Align format.yml with stackpop/edgezero#257 layout

Two cosmetic differences against edgezero's `Run Format` workflow:
- Top-level `permissions:` moves above `concurrency:` (matching edgezero's order).
- Drop the `~/.cargo/bin/` cache path — this workflow only runs fmt and
  clippy, which install no cargo binaries, so caching that directory was
  dead weight.

format.yml now matches edgezero byte-for-byte. No matrix involved (the
adapter-wasm-tests matrix lives in test.yml).

* Refresh Cargo.lock with semver-compatible transitive updates

* Address @prk-Jr / @ChristianPavilonis PR review feedback

- **Playwright `AD_SIZES` registration bug** (`tests/playwright/
  creative-visibility.test.ts:40` — @ChristianPavilonis): the loop was
  iterating a list populated in `beforeAll`, but Playwright registers
  tests synchronously at module load, so only 2 of the intended
  per-size suite were actually registered. Switch to a static
  `AD_SIZES` constant (mirrors `STANDARD_SIZES` in `auction.rs`) and
  add a `sizes endpoint matches static AD_SIZES list` assertion so any
  drift between the server list and the test list fails loudly.
  `npx playwright test --list` now reports 41 tests (was 2).

- **OpenRTB response example missing `sig` query parameter**
  (`docs/api/openrtb-auction.md:107` — @prk-Jr, @ChristianPavilonis):
  runtime `adm` always includes `&sig=verified|failed|not_present`
  (set by `iframe_html` from `metadata.signature.url_param()`). The
  exact-output example now matches: `…?crid=mocktioneer-imp-1&sig=not_present`.

- **Pin Wasmtime instead of `curl ... | bash` of the latest**
  (`.github/workflows/test.yml:139` — @ChristianPavilonis): add
  `wasmtime 45.0.0` to `.tool-versions` and pass `-v "v$VERSION"` to
  the installer so the spin matrix cell fetches a specific tagged
  release. Removes the unpinned/latest-installer supply-chain concern
  and matches how `viceroy`/`wasm-bindgen-cli` are pinned.

- **Add Spin to CLAUDE.md adapter/project docs** (@ChristianPavilonis):
  workspace layout, compilation-targets table, `edgezero-cli serve`
  examples, and the key-files-reference table all now mention the
  `mocktioneer-adapter-spin` crate alongside axum/cloudflare/fastly.

prk-Jr's earlier comments (`wasm-bindgen-test` pin, cloudflare contract
test comment, `_ref`/`_type` doc / removal) were already resolved in
prior commits on this branch.

All gates green: clippy `-D warnings`, 161 tests (host), fmt,
`"fastly cloudflare spin"` feature check; Playwright now lists 41
tests vs the previous 2.

* Updated Cargo.lock

* Fix Wasmtime install flag in CI: -v -> --version

The wasmtime.dev installer rejects `-v` as an unknown option (it offers
`--release`/`--dev`/`--version` only). The spin matrix cell on the latest
PR run failed at the Setup Wasmtime step with:

    Error: unknown option: '-v'

Switch the short flag to the long `--version` form. Comment refreshed to
match.

* Always install pinned Wasmtime in CI

@ChristianPavilonis flagged that the previous `if ! command -v wasmtime`
guard would silently bypass the `.tool-versions` pin if the GitHub
runner image later preinstalls Wasmtime — any version would satisfy the
guard and the install step would skip.

Drop the guard so the pinned version is always installed. The install
script is small/fast (single curl + tarball extract) and `~/.wasmtime/bin`
is prepended to PATH for the rest of the job, so this shadows any
system wasmtime.

* Sync edgezero deps to latest chore/strict-clippy (PR #257)

Bump the six edgezero crates from e7887140 to dfb00b39, pulling in the
round-2 through round-4 review-feedback commits on PR #257:

- strict-clippy: address PR review feedback (round 2)
- strict-clippy: cloudflare scaffold + handlers.md doc fixes
- Bump redb 4.0 -> 4.1.0 (#255)
- merge main into chore/strict-clippy
- strict-clippy: round-4 review feedback (test.yml, cli logger, docs)

These touch edgezero-core (app.rs, error.rs, key_value_store.rs),
edgezero-macros (app.rs), and the fastly/cloudflare adapters. Lock-only
change; no mocktioneer source edits required.

Verified green: cargo check / clippy (-D warnings) / 161 tests / fmt /
"fastly cloudflare spin" feature build / all three wasm-target builds.
Fastly and Spin wasm contract tests pass via Viceroy and Wasmtime.

* Point edgezero deps at main now that PR #257 is merged

stackpop/edgezero#257 (strict-clippy + defensive-coding pass) merged to
edgezero main as 7ec2ad1, and the chore/strict-clippy branch was deleted.
Switch all six edgezero crates from `branch = "chore/strict-clippy"` to
`branch = "main"` and re-resolve the lock onto 7ec2ad1.

Lock + manifest only; no mocktioneer source changes. Verified green:
cargo check / clippy (-D warnings) / 161 tests / fmt /
"fastly cloudflare spin" feature build / all three wasm-target builds.
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.

Address clippy allow-list (pedantic + restriction)

4 participants