"""The sealed rule for "don't program on Fridays", on the Linux kernel.

Sealed before any commit of the kernel reached this server. Before the seal I read only
the sha of master (git ls-remote, 3 November 2026) and search snippets of two papers:
Sliwerski, Zimmermann and Zeller 2005, on Mozilla and Eclipse, and Eyolfson, Tan and Lam
2011, whose Linux weekday result I did not read.

Claim tested. Code written on a Friday is buggier: a commit authored on a Friday is more
likely to need a later fix than the same author's commit on another working day.

Frame. Non-merge commits reachable from HEAD_SHA in torvalds/linux whose author date, in
the author's own recorded UTC offset, falls in 2014 to 2023. Dropped: offsets beyond
14 hours; author and committer times more than 365 days apart.

1. A commit is FIXED if a different non-merge commit reachable from HEAD_SHA has a line
   matching FIXES_RE whose hex resolves uniquely, as a prefix, to it, and that commit's
   committer time is 0 to 730 days after this one's. Every frame commit has the full 730
   days of follow-up.
2. Author = lowercased author email, no mailmap. Stratum = author and local year.
3. Estimate: the Mantel-Haenszel risk ratio RR of FIXED, Friday against Monday to Thursday
   pooled, over the strata. Only strata holding both sides count. Saturday and Sunday are
   outside this comparison.
4. Placebos: each of Monday, Tuesday, Wednesday and Thursday against the other three of
   those days, by the same estimator.
5. SE on log RR = the larger of the bootstrap SE (DRAWS resamples of authors, whole, seed
   SEED) and the sample SD of the four placebos' log RR. Interval exp(log RR +/- Z SE).
6. Verdict, bar 1.10 (ten percent more later fixes is the smallest difference that could
   change when anybody works): killed if the upper bound is below 1.10; survived if the
   lower bound is above 1.00 and RR is at least 1.10; inconclusive otherwise.

Void if any of:
V1 2.8 x SE >= log(1.10).
V2 Fewer than 300,000 commits in the comparison or fewer than 10,000 of them FIXED.
V3 Fewer than 80 % of the Fixes lines resolve uniquely.
V4 The clock reading fails: Saturday and Sunday together must be under 20 % of the frame,
   and local hours 09 to 16 must hold at least three times the commits of hours 01 to 04.
V5 A planted effect: for each of PLANTS seeds, unfixed Friday commits turned FIXED so
   that Friday's overall rate rises by 25 %. At least 8 of 10 must survive, each judged
   with its own bootstrap of PLANT_DRAWS draws and the placebos' SD from step 4.
V6 HEAD_SHA's committer date is before 1 January 2026, which would break the follow-up.

Printed only, cannot move the verdict: the crude rate of every weekday and the crude RR;
Saturday and Sunday against Monday to Thursday; hours 00 to 04 against 09 to 16 by the same
estimator; offset +0000 left out; follow-up of 365 days; strata split further by the
subject's first word before a colon; 2014-2018 and 2019-2023 alone; only commits that
carry no Fixes line themselves; the share of commits carrying a Fixes line by weekday;
only fixes by a different author.
"""

import bisect
import re

import numpy as np

HEAD_SHA = "05441d697f7f9a927264f4058cbbc6a03dfcac9d"
REPO = "https://github.com/torvalds/linux"
Y0, Y1 = 2014, 2023
FOLLOW_S = 730 * 86400
MAX_OFFSET_MIN = 14 * 60
MAX_SKEW_S = 365 * 86400
FIXES_RE = re.compile(r"^\s*fixes:\s*(?:commit\s+)?([0-9a-f]{8,40})\b", re.I | re.M)
BAR = 1.10
DRAWS = 2000
PLANTS = 10
PLANT_DRAWS = 200
PLANT_RISE = 1.25
SEED = 20261103
Z = 1.959964
FRIDAY = 4  # Monday is 0
WORKDAYS = (0, 1, 2, 3)


def resolver(shas):
    """A function from hex prefix to the one full sha it names, or None."""
    ordered = sorted(shas)

    def resolve(prefix):
        prefix = prefix.lower()
        i = bisect.bisect_left(ordered, prefix)
        if i >= len(ordered) or not ordered[i].startswith(prefix):
            return None
        if i + 1 < len(ordered) and ordered[i + 1].startswith(prefix):
            return None
        return ordered[i]

    return resolve


def mh_terms(stratum, author, fixed, exposed, control):
    """One (author index, A, B) per stratum holding both sides.

    RR_MH = sum A / sum B, A = a n0 / N, B = c n1 / N, where a of n1 exposed commits and
    c of n0 control commits are fixed. Rows that are neither exposed nor control are out.
    """
    keep = exposed | control
    s = stratum[keep]
    x = exposed[keep]
    f = fixed[keep].astype(float)
    n_s = int(stratum.max()) + 1 if len(stratum) else 0
    n1 = np.bincount(s, x, n_s)
    n0 = np.bincount(s, ~x, n_s)
    a = np.bincount(s, f * x, n_s)
    c = np.bincount(s, f * ~x, n_s)
    both = (n1 > 0) & (n0 > 0)
    big = n1 + n0
    A = (a * n0 / np.where(big > 0, big, 1))[both]
    B = (c * n1 / np.where(big > 0, big, 1))[both]
    first = np.full(n_s, -1)
    first[stratum[::-1]] = author[::-1]
    return first[both], A, B


def rr_of(A, B):
    return float(A.sum() / B.sum())


def bootstrap_se(auth, A, B, draws, seed):
    """SE of log RR under resampling whole authors."""
    ids, inv = np.unique(auth, return_inverse=True)
    a = np.bincount(inv, A, len(ids))
    b = np.bincount(inv, B, len(ids))
    rng = np.random.default_rng(seed)
    out = np.empty(draws)
    n = len(ids)
    for k in range(draws):
        w = rng.multinomial(n, np.full(n, 1 / n)).astype(float)
        out[k] = np.log((w * a).sum() / (w * b).sum())
    return float(out.std(ddof=1))


def verdict(rr, se):
    lo = float(np.exp(np.log(rr) - Z * se))
    hi = float(np.exp(np.log(rr) + Z * se))
    if hi < BAR:
        v = "killed"
    elif lo > 1.0 and rr >= BAR:
        v = "survived"
    else:
        v = "inconclusive"
    return v, lo, hi


def plant(fixed, friday, seed):
    """Turn unfixed Friday commits FIXED so Friday's overall rate rises by PLANT_RISE."""
    rng = np.random.default_rng(seed)
    out = fixed.copy()
    idx = np.flatnonzero(friday & ~fixed)
    want = int(round((PLANT_RISE - 1.0) * (friday & fixed).sum()))
    out[rng.choice(idx, size=want, replace=False)] = True
    return out
