Idiomatic axum cleanups: named Auth field, cfg guard, drop local Either
- Auth extractor: replace bare bool tuple field with named `authenticated`
  field and `is_authenticated()` method so call sites read clearly
- main.rs: guard the `inject_dev_user` branch with `#[cfg(feature = "dev")]`
  so non-dev builds don't reference the cfg-gated symbol and fail to compile
- tree.rs: remove local `Either<L, R>` enum; use `Result<TreeData, FileData>`
  (Ok = directory, Err = file) as the two-variant discriminant instead

https://claude.ai/code/session_013nzzxsm19t84xnUDroLyt3
change
commit 18a99e4077bfa5184cc725e39be7521f531c6201
author Claude <noreply@anthropic.com>
date
parent ukovxsxr
diff --git a/quire-server/src/bin/quire/main.rs b/quire-server/src/bin/quire/main.rs
index 18ac4ad..8b05070 100644
--- a/quire-server/src/bin/quire/main.rs
+++ b/quire-server/src/bin/quire/main.rs
@@ -151,13 +151,15 @@ async fn main() -> Result<()> {
                     quire::quire::web::auth::require_auth,
                 ));
                 let merged = public.merge(ci);
-                if dev {
+                #[cfg(feature = "dev")]
+                let merged = if dev {
                     merged.layer(axum::middleware::from_fn(
                         quire::quire::web::auth::inject_dev_user,
                     ))
                 } else {
                     merged
-                }
+                };
+                merged
             };
             let api_routes = quire::quire::web::api::router(quire.clone());
             commands::serve::run(&quire, web_routes, api_routes).await?
diff --git a/quire-server/src/quire/web/auth.rs b/quire-server/src/quire/web/auth.rs
index a6c08ab..e9c68f3 100644
--- a/quire-server/src/quire/web/auth.rs
+++ b/quire-server/src/quire/web/auth.rs
@@ -8,14 +8,24 @@ use axum::http::request::Parts;
 use axum::middleware::Next;
 use axum::response::{IntoResponse, Response};
 
-/// Extractor that resolves to `true` when the `Remote-User` header is present.
-pub struct Auth(pub bool);
+/// Extractor that resolves to whether the request carries a `Remote-User` header.
+pub struct Auth {
+    pub authenticated: bool,
+}
+
+impl Auth {
+    pub fn is_authenticated(&self) -> bool {
+        self.authenticated
+    }
+}
 
 impl<S: Send + Sync> FromRequestParts<S> for Auth {
     type Rejection = Infallible;
 
     async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
-        Ok(Auth(parts.headers.contains_key("Remote-User")))
+        Ok(Auth {
+            authenticated: parts.headers.contains_key("Remote-User"),
+        })
     }
 }
 
diff --git a/quire-server/src/quire/web/handlers/repo.rs b/quire-server/src/quire/web/handlers/repo.rs
index 175273c..7a25707 100644
--- a/quire-server/src/quire/web/handlers/repo.rs
+++ b/quire-server/src/quire/web/handlers/repo.rs
@@ -57,7 +57,7 @@ pub async fn repo_home(
             .unwrap_or_default();
 
     let tmpl = RepoHomeTemplate {
-        sections: nav_sections(&repo_display, "overview", auth.0),
+        sections: nav_sections(&repo_display, "overview", auth.is_authenticated()),
         repo: repo_display,
         crumbs: vec![],
         head,
diff --git a/quire-server/src/quire/web/handlers/tree.rs b/quire-server/src/quire/web/handlers/tree.rs
index 50fe98a..5c7d146 100644
--- a/quire-server/src/quire/web/handlers/tree.rs
+++ b/quire-server/src/quire/web/handlers/tree.rs
@@ -18,7 +18,7 @@ pub async fn tree_view(
     auth: Auth,
     AxumPath(repo): AxumPath<String>,
 ) -> Response {
-    tree_or_file_at_path(quire, repo, String::new(), auth.0).await
+    tree_or_file_at_path(quire, repo, String::new(), auth.is_authenticated()).await
 }
 
 pub async fn tree_view_path(
@@ -26,7 +26,7 @@ pub async fn tree_view_path(
     auth: Auth,
     AxumPath((repo, path)): AxumPath<(String, String)>,
 ) -> Response {
-    tree_or_file_at_path(quire, repo, path, auth.0).await
+    tree_or_file_at_path(quire, repo, path, auth.is_authenticated()).await
 }
 
 async fn tree_or_file_at_path(quire: Quire, repo: String, path: String, authed: bool) -> Response {
@@ -46,17 +46,17 @@ async fn tree_or_file_at_path(quire: Quire, repo: String, path: String, authed:
             let bookmarks = reader.bookmarks();
             let tags = reader.tags();
             let recent_changes = reader.recent_changes_for(Some(&path_clone));
-            Some(Either::Left((tree_data, bookmarks, tags, recent_changes)))
+            Some(Ok((tree_data, bookmarks, tags, recent_changes)))
         } else {
             // ls-tree failed — try reading as a file blob.
-            read_file_data(&reader, &path_clone).map(Either::Right)
+            read_file_data(&reader, &path_clone).map(Err)
         }
     })
     .await
     .unwrap_or(None);
 
     match result {
-        Some(Either::Left((tree_data, bookmarks, tags, recent_changes))) => {
+        Some(Ok((tree_data, bookmarks, tags, recent_changes))) => {
             let crumbs = build_tree_crumbs(&repo_display, &path);
             let tmpl = TreeTemplate {
                 sections: nav_sections(&repo_display, "tree", authed),
@@ -72,7 +72,7 @@ async fn tree_or_file_at_path(quire: Quire, repo: String, path: String, authed:
             };
             render(&tmpl)
         }
-        Some(Either::Right(file_data)) => {
+        Some(Err(file_data)) => {
             let crumbs = build_file_crumbs(&repo_display, &path);
             let line_nums: Vec<usize> = (1..=file_data.line_count).collect();
             let tmpl = FileViewTemplate {
@@ -105,11 +105,6 @@ async fn tree_or_file_at_path(quire: Quire, repo: String, path: String, authed:
     }
 }
 
-enum Either<L, R> {
-    Left(L),
-    Right(R),
-}
-
 // ── Tree (directory) view ──────────────────────────────────────
 
 struct TreeData {