master
John Lauer v2.0.634 (insiders): background windows proven: default ext lane gets --no-startup-window + --keep-alive-for-test (was… 3fcc8b8 1mo ago
//! Z-order doctrine from Node (v1.9.181 userIsUsingWindow, v2.0.26/2.0.27 osBottomUnlessForeground,
//! v2.0.261 birth grace). pup must NEVER pull a window out from under the user: every re-park after a
//! navigation, reload, view switch or recording asks first whether the user is using the window.
//! A newborn window (8 s, no granted raise) cannot be "in use": Chrome self-activates a new window and
//! the user's typing is not a click on a taskbar button that did not exist yet, so it is bottomed.
//! Missing from the Rust port until 2.0.426 (John, 2026-09-06: "you seem to be acting odd").

use crate::Ctx;

pub const BIRTH_GRACE_MS: u64 = 8_000;
const USER_MEMORY_MS: u64 = 10 * 60_000;

pub fn in_birth_grace(s: &pup_session::Session) -> bool { !s.raise_granted && pup_core::now_ms().saturating_sub(s.born_at_ms) < BIRTH_GRACE_MS }
pub fn user_is_using(s: &pup_session::Session) -> bool {
    if in_birth_grace(s) { return false; }
    s.foreground || (s.user_active_at_ms > 0 && pup_core::now_ms().saturating_sub(s.user_active_at_ms) < USER_MEMORY_MS)
}

/// Node osBottomUnlessForeground. Returns "bottomed" | "foreground" | "user-foreground" | "no-hwnd".
pub fn bottom_unless_foreground(ctx: &Ctx, sid: &str, force: bool) -> &'static str {
    let Some(s) = ctx.sessions.get(sid) else { return "no-hwnd" };
    let Some(h) = s.hwnd else { return "no-hwnd" };
    let fg = ctx.host.foreground();
    if fg == h && fg != 0 {
        if !force { return "foreground"; }
        // 2.0.584 (John: "within like 200ms a human might click the windows taskbar icon"): the birth grace may
        // override the session FLAGS (they lag), never INPUT. A programmatic self-raise happens with idle hands
        // (the 2.0.26 insight); keyboard or mouse activity in the last 5 s is a person, grace or not. Before
        // this, a taskbar click inside the first 8 s was undone by the +2.5 s re-assert.
        // 2.0.588 (John: "you cannot fuck over the user if they bring it to the foreground to look at it"): a pup
        // window that IS the foreground belongs to the user, full stop, and READING it involves no input, so the
        // 5 s idle rule must never expire that. The only self-raise pup may undo is a NEWBORN's (Chrome's first
        // paint or a PDF viewer) with idle hands inside the birth grace. Everything else: hands off, and remember
        // it for 10 minutes so the re-asserts that follow stay off too.
        // 2.0.589 (John: "a user could click the windows taskbar icon within 200ms"): no magic idle number.
        // Inside the birth grace pup may demote ONLY when nobody has touched the machine since the window
        // was born (so the raise was Chrome's), and only on the CDP lane, where Chrome self-activates a
        // newborn at all (an extension-lane window is created unfocused and never does). Any input since
        // birth, a click at 200 ms included, means a person: hands off, remembered for 10 minutes, and a
        // remembered person stays a person for the rest of the grace even while they read without input.
        let idle = ctx.host.idle_ms().unwrap_or(u64::MAX);
        let since_birth = pup_core::now_ms().saturating_sub(s.born_at_ms);
        let remembered = s.user_active_at_ms > 0 && pup_core::now_ms().saturating_sub(s.user_active_at_ms) < USER_MEMORY_MS;
        // 2.0.628: the extension lane is no longer excluded. The exclusion rested on "Chrome never self-activates
        // an unfocused-created window on this lane", which is true for a warm birth and FALSE for the first
        // window of a freshly started browser: measured 2026-09-18, the cold-birth re-assert answered
        // "foreground" with no input since birth, while a Notepad window held the keyboard a second earlier.
        // The idle-hands rule is lane-independent: no input since birth means Chrome raised it, not a person.
        let chrome_self_raise = in_birth_grace(&s) && !remembered && idle >= since_birth;
        if chrome_self_raise {
            pup_core::log(format!("[park] \"{sid}\" is foreground {since_birth} ms after birth with no input since birth: Chrome's self-raise, bottoming"));
        } else {
            ctx.sessions.with_mut(sid, |x| x.user_active_at_ms = pup_core::now_ms());
            if in_birth_grace(&s) { pup_core::log(format!("[park] \"{sid}\" is foreground inside the birth grace with input {idle} ms ago: a person raised it, hands off")); }
            return "user-foreground";
        }
    }
    ctx.host.send_to_bottom_no_activate(h);
    "bottomed"
}