From b093d181cfb11abe40c14d0646704ced955016fd Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 20 Aug 2026 06:48:07 +0000 Subject: [PATCH] render-askama: depend on askama_axum, or feature unification breaks consumers `ogar-render-askama` cannot be consumed by any crate that also uses `askama_axum`. Measured 2026-08-20 wiring it into `AdaWorldAPI/MedCare-rs`'s `medcare-server`, which has used `askama_axum = "0.4"` for its own handlers all along: error[E0433]: cannot find `askama_axum` in the crate root --> crates/ogar-render-askama/src/artifact_kinds/cells.rs:21:10 | 21 | #[derive(Template)] | ^^^^^^^^ could not find `askama_axum` in the list of | imported crates The mechanism is cargo feature unification, not a version conflict -- both sides are on askama 0.12: askama_axum 0.4 enables askama/with-axum | (features unify across the WHOLE graph) v askama's #[derive(Template)] emits an `IntoResponse` impl naming `::askama_axum`, in EVERY crate that derives Template -- including this one, which does not have it. Confirmed with `cargo tree -e features -i askama`: `askama feature "with-axum"` resolves to `askama_axum v0.4.0`, enabled by the consumer, applied to us. Two properties make this worth a dependency rather than a note: * It is INVISIBLE here. Nothing in this repository combines the two, so every test passes with the dependency absent -- which is exactly how it went missing. * It is UNFIXABLE from the consumer side. The failure is inside this crate's own derives, so the only escapes are forking or pinning this crate, and the workspace doctrine forbids both. `askama_axum` is a thin adapter over the same askama, and where nobody enables the feature the derive never references it -- so the dependency is cheap and inert rather than a new capability. Added `tests/axum_feature_unification.rs` to keep it reachable from source. It states plainly what it cannot do: it does NOT reproduce the failure, because the trigger is a feature a sibling package enables and a test here cannot enable it on a consumer's behalf. What it does is make a dependency-hygiene pass (`cargo machete`, a "remove unused deps" cleanup) fail HERE instead of in a downstream repository weeks later. Verified: `cargo test -p ogar-render-askama` 61+1+2 passed / 0 failed; `cargo clippy -p ogar-render-askama --all-targets -- -D warnings` clean; `cargo fmt` clean. Generated by [Claude Code](https://claude.com/claude-code) Claude-Session: https://claude.ai/code/session_017Pud4qpxFHwqyqDjSabQbs --- crates/ogar-render-askama/Cargo.toml | 21 ++++++++ .../tests/axum_feature_unification.rs | 48 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 crates/ogar-render-askama/tests/axum_feature_unification.rs diff --git a/crates/ogar-render-askama/Cargo.toml b/crates/ogar-render-askama/Cargo.toml index 262e467e..90bf3556 100644 --- a/crates/ogar-render-askama/Cargo.toml +++ b/crates/ogar-render-askama/Cargo.toml @@ -9,6 +9,27 @@ description = "Build-time askama codegen harness over the canonical layer — on ogar-vocab = { path = "../ogar-vocab" } lance-graph-contract = { git = "https://github.com/AdaWorldAPI/lance-graph", branch = "main" } askama = "0.12" +# `askama_axum` is NOT used by this crate — it is required to COMPILE it in any +# graph where some other crate uses it, and that is a cargo feature-unification +# fact, not a choice here. +# +# `askama_axum 0.4` enables `askama/with-axum`. Features unify across the whole +# dependency graph, so once any consumer pulls `askama_axum`, askama's +# `#[derive(Template)]` starts emitting an `IntoResponse` impl that names +# `::askama_axum` — in EVERY crate that derives Template, including this one. +# Without the dependency the expansion cannot resolve and the build dies with +# `E0433: cannot find `askama_axum` in the crate root`, pointing at our own +# `#[derive(Template)]` lines (measured on `artifact_kinds/cells.rs`). +# +# The defect is therefore invisible until a consumer combines the two, and then +# it is unfixable from the consumer side without forking or pinning this crate. +# Measured 2026-08-20 wiring `ogar-render-askama` into `medcare-server`, which +# has used `askama_axum = "0.4"` for its own handlers all along. +# +# Cheap and inert where nobody enables the feature: `askama_axum` is a thin +# adapter over the same askama, and with the feature off the derive never +# references it. +askama_axum = "0.4" [dev-dependencies] # harvest driver for examples/render_osm.rs (Rails app/models → Class → Rust) diff --git a/crates/ogar-render-askama/tests/axum_feature_unification.rs b/crates/ogar-render-askama/tests/axum_feature_unification.rs new file mode 100644 index 00000000..22f28b26 --- /dev/null +++ b/crates/ogar-render-askama/tests/axum_feature_unification.rs @@ -0,0 +1,48 @@ +//! **The `askama_axum` dependency is load-bearing and must not be tidied away.** +//! +//! This crate never calls `askama_axum`. A dependency-hygiene pass (`cargo +//! machete`, a "remove unused deps" cleanup, a reviewer asking "why is this +//! here?") will therefore read it as dead weight and delete it — and the +//! deletion is invisible, because every test in this repository still passes. +//! +//! It breaks CONSUMERS instead, and only those that combine two innocuous +//! choices: +//! +//! ```text +//! consumer ──> askama_axum 0.4 (its own axum handlers) +//! └─> ogar-render-askama (this crate) +//! +//! askama_axum 0.4 enables askama/with-axum +//! ↓ (cargo unifies features across the WHOLE graph) +//! askama's #[derive(Template)] now emits `impl IntoResponse` naming +//! `::askama_axum` — in every crate that derives Template, including this one +//! ↓ +//! error[E0433]: cannot find `askama_axum` in the crate root +//! --> crates/ogar-render-askama/src/artifact_kinds/cells.rs:21 +//! ``` +//! +//! Measured 2026-08-20 wiring this crate into `AdaWorldAPI/MedCare-rs`'s +//! `medcare-server`, which has used `askama_axum = "0.4"` for its own handlers +//! all along. The consumer cannot fix it: the failure is inside THIS crate's +//! derives, so the only consumer-side escapes are forking or pinning, and the +//! workspace doctrine forbids both. +//! +//! # What this test can and cannot prove +//! +//! It CANNOT reproduce the failure: the trigger is a feature enabled by a +//! sibling package, and a test in this crate cannot enable it on the consumer's +//! behalf. Honest limitation, stated rather than dressed up. +//! +//! What it DOES do is make the dependency reachable from source, so removing it +//! fails to compile here instead of failing in a downstream repository weeks +//! later. That is the whole job. + +/// Referenced so the dependency is used from source. Deleting the +/// `askama_axum` dependency breaks this line — which is the point. +#[test] +fn the_askama_axum_dependency_is_referenced_so_it_cannot_be_tidied_away() { + use askama_axum as _; + // The version that carries the `with-axum` feature this crate's derives + // start depending on the moment any consumer enables it. + assert!(!env!("CARGO_PKG_NAME").is_empty()); +}