All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Danilo Krummrich" <dakr@kernel.org>
To: "Miguel Ojeda" <miguel.ojeda.sandonis@gmail.com>
Cc: "Roman Gushchin" <roman.gushchin@linux.dev>,
	"Alexandre Courbot" <acourbot@nvidia.com>,
	<sashiko@lists.linux.dev>
Subject: Re: Sashiko email policy precedence
Date: Mon, 01 Jun 2026 11:46:54 +0200	[thread overview]
Message-ID: <DIXM8JL1CM5A.315I0YBSDJT5O@kernel.org> (raw)
In-Reply-To: <CANiq72mSpur28Fz8YL7_-FJk_h008kt=sw6mLeSsRNmiy+ko1Q@mail.gmail.com>

On Mon Jun 1, 2026 at 8:16 AM CEST, Miguel Ojeda wrote:
> On Mon, Jun 1, 2026 at 1:17 AM Danilo Krummrich <dakr@kernel.org> wrote:
> IIUC, from what Danilo says, the current algorithm's conservative approach
> would remove that setting as soon as the patch is sent to any list where that
> isn't the case, right?

Only if the other list has a sashiko email policy entry in the first place,
otherwise it is not part of the matching loop and no further logic is applied.

I'd assume that this is intentional, and can be read as "no entry, no expressed
preference".

> if it is too complex to implement other logic, I guess it is an option.

Flagging something as wide list seems rather simple [1], the tristate [2] would
work as well, but seems a bit more complicated and potentially requires
adjusting the existing policies.

(Test adjustments stripped from [2]; code is LLM generated.)

[1]

diff --git a/src/email_policy.rs b/src/email_policy.rs
index 9fe1179330f3..1ae892e67535 100644
--- a/src/email_policy.rs
+++ b/src/email_policy.rs
@@ -43,6 +43,10 @@ pub struct SubsystemPolicy {
     pub embargo_hours: Option<u32>,
     #[serde(default)]
     pub send_positive_review: bool,
+    /// When true and co-matched with a non-wide list, only `cc` is
+    /// contributed. All boolean flags are deferred to the non-wide lists.
+    #[serde(default)]
+    pub wide_list: bool,
 }

 impl EmailPolicyConfig {
diff --git a/src/email_router.rs b/src/email_router.rs
index c17273aad8ff..216a85d7738d 100644
--- a/src/email_router.rs
+++ b/src/email_router.rs
@@ -93,7 +93,18 @@ impl EmailRouter {
         let mut send_positive_review = false;
         let mut cc = Vec::new();

-        for p in active_policies {
+        let has_non_wide = active_policies.iter().any(|p| !p.wide_list);
+
+        for p in &active_policies {
+            let deferred = p.wide_list && has_non_wide;
+
+            if deferred {
+                for cr in &p.cc {
+                    cc.push(cr.clone());
+                }
+                continue;
+            }
+
             if p.mute_all {
                 mute_all = true;
             }

[2]

diff --git a/src/email_policy.rs b/src/email_policy.rs
index 9fe1179330f3..5c9d94a4d416 100644
--- a/src/email_policy.rs
+++ b/src/email_policy.rs
@@ -23,14 +23,15 @@ pub struct EmailPolicyConfig {
 pub struct SubsystemPolicy {
     #[serde(default)]
     pub lists: Vec<String>,
+    /// None = no preference, Some(false) = private, Some(true) = public.
     #[serde(default)]
-    pub reply_all: bool,
+    pub reply_all: Option<bool>,
     #[serde(default)]
-    pub reply_to_author: bool,
+    pub reply_to_author: Option<bool>,
     #[serde(default)]
-    pub cc_individuals: bool,
+    pub cc_individuals: Option<bool>,
     #[serde(default)]
-    pub mute_all: bool,
+    pub mute_all: Option<bool>,
     #[serde(default)]
     pub cc: Vec<String>,
     #[serde(default)]
@@ -42,7 +43,7 @@ pub struct SubsystemPolicy {
     #[serde(default)]
     pub embargo_hours: Option<u32>,
     #[serde(default)]
-    pub send_positive_review: bool,
+    pub send_positive_review: Option<bool>,
 }
 
 impl EmailPolicyConfig {
diff --git a/src/email_router.rs b/src/email_router.rs
index c17273aad8ff..452c09411552 100644
--- a/src/email_router.rs
+++ b/src/email_router.rs
@@ -12,6 +12,19 @@ pub enum Action {
 
 pub struct EmailRouter {}
 
+/// Merges two Option<bool> policy votes. `dominant` is the value that wins on
+/// conflict: `true` for mute_all, reply_to_author, cc_individuals, and
+/// send_positive_review (any-true wins); `false` for reply_all (any-false wins).
+fn merge_flag(acc: Option<bool>, vote: Option<bool>, dominant: bool) -> Option<bool> {
+    match (acc, vote) {
+        (_, None) => acc,
+        (None, _) => vote,
+        (Some(v), _) if v == dominant => acc,
+        (_, Some(v)) if v == dominant => vote,
+        _ => acc,
+    }
+}
+
 impl EmailRouter {
     pub fn resolve_patchwork(
         policy: &EmailPolicyConfig,
@@ -86,34 +99,30 @@ impl EmailRouter {
             active_policies.push(&policy.defaults);
         }
 
-        let mut mute_all = false;
-        let mut is_private = false;
-        let mut reply_to_author = false;
-        let mut cc_individuals = false;
-        let mut send_positive_review = false;
+        let mut mute_all = None;
+        let mut reply_all = None;
+        let mut reply_to_author = None;
+        let mut cc_individuals = None;
+        let mut send_positive_review = None;
         let mut cc = Vec::new();
 
         for p in active_policies {
-            if p.mute_all {
-                mute_all = true;
-            }
-            if !p.reply_all {
-                is_private = true;
-            }
-            if p.reply_to_author {
-                reply_to_author = true;
-            }
-            if p.cc_individuals {
-                cc_individuals = true;
-            }
-            if p.send_positive_review {
-                send_positive_review = true;
-            }
+            mute_all = merge_flag(mute_all, p.mute_all, true);
+            reply_all = merge_flag(reply_all, p.reply_all, false);
+            reply_to_author = merge_flag(reply_to_author, p.reply_to_author, true);
+            cc_individuals = merge_flag(cc_individuals, p.cc_individuals, true);
+            send_positive_review = merge_flag(send_positive_review, p.send_positive_review, true);
             for cr in &p.cc {
                 cc.push(cr.clone());
             }
         }
 
+        let mute_all = mute_all.unwrap_or(false);
+        let is_private = !reply_all.unwrap_or(false);
+        let reply_to_author = reply_to_author.unwrap_or(false);
+        let cc_individuals = cc_individuals.unwrap_or(false);
+        let send_positive_review = send_positive_review.unwrap_or(false);
+
         // Always append defaults.cc so users can define a global CC
         for cr in &policy.defaults.cc {
             cc.push(cr.clone());

  reply	other threads:[~2026-06-01  9:46 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-31 23:17 Sashiko email policy precedence Danilo Krummrich
2026-06-01  6:16 ` Miguel Ojeda
2026-06-01  9:46   ` Danilo Krummrich [this message]
2026-06-08 13:44     ` Danilo Krummrich
2026-06-09 16:26       ` Roman Gushchin
2026-06-09 16:38         ` Miguel Ojeda
2026-06-09 17:21           ` Roman Gushchin
2026-06-10  5:57             ` Miguel Ojeda
2026-06-09 16:58         ` Danilo Krummrich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DIXM8JL1CM5A.315I0YBSDJT5O@kernel.org \
    --to=dakr@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=miguel.ojeda.sandonis@gmail.com \
    --cc=roman.gushchin@linux.dev \
    --cc=sashiko@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.