Add repository baseline signal

ober

8680c9243b732c9dfca727693ec7310fc75dce95

diff --git a/README.md b/README.md
index 1b3c975..b584023 100644
--- a/README.md
+++ b/README.md
@@ -80,6 +80,10 @@ Resource limits default to 500 changed files per commit, 20,000 added lines
 analyzed per commit, and 50,000 bytes per AI note. When a limit is hit, output
 keeps the bounded data and includes a warning.
 
+Baseline signals are reported as contextual evidence with zero default weight.
+The author baseline uses same-author addition history; the repository baseline
+uses median/MAD-style addition-count deviation across the selected scan window.
+
 Warnings also call out root commits with no parent baseline, merge commits where
 the scanner intentionally uses the first-parent diff, missing parent objects in
 shallow history, and binary file changes that are skipped by text-line
diff --git a/main-binary.ss b/main-binary.ss
index 6f8f030..398c71e 100644
--- a/main-binary.ss
+++ b/main-binary.ss
@@ -553,6 +553,30 @@
              [evidence (if (> score 0.0) (list (str "addition-count z-score " z)) '())])
         (sig "author-baseline" "baseline" score 0.00 "low" "commit size differs from author baseline" evidence
              "baseline is contextual in this version and is not directly weighted"))))
+(def (median xs)
+  (if (null? xs)
+      0.0
+      (let* ([sorted (sort xs <)]
+             [n (length sorted)]
+             [mid (floor (/ n 2))])
+        (if (= 0 (modulo n 2))
+            (/ (+ (safe-ref sorted (- mid 1) 0) (safe-ref sorted mid 0)) 2.0)
+            (safe-ref sorted mid 0)))))
+
+(def (mad xs med)
+  (median (map (lambda (x) (abs (- x med))) xs)))
+
+(def (repository-baseline-signal additions repo-additions)
+  (if (< (length repo-additions) 5)
+      (sig "repository-baseline" "baseline" 0.0 0.00 "low" "repository baseline unavailable" '("fewer than five comparison commits")
+           "missing repository baseline is not evidence of human authorship")
+      (let* ([med (median repo-additions)]
+             [spread (mad repo-additions med)]
+             [robust-z (if (= spread 0.0) 0.0 (/ (abs (- additions med)) (* 1.4826 spread)))]
+             [score (cond [(> robust-z 6.0) 0.50] [(> robust-z 3.5) 0.25] [else 0.0])]
+             [evidence (if (> score 0.0) (list (str "repository addition robust-z " robust-z)) '())])
+        (sig "repository-baseline" "baseline" score 0.00 "low" "commit size differs from repository baseline" evidence
+             "repository baseline uses commit-size history only and is not directly weighted"))))
 
 (def (independent-hits signals)
   (length (unique (map signal-category (filter (lambda (s) (>= (signal-score s) 0.30)) signals)))))
@@ -577,6 +601,14 @@
           (if (and (same-public-string? e author-id) (not (same-public-string? rev current)))
               (loop (cdr xs) (cons (numstat-adds (changed-files repo rev file)) out))
               (loop (cdr xs) out))))))
+(def (prior-repository-additions repo revs current file)
+  (let loop ([xs revs] [out '()])
+    (if (null? xs)
+        out
+        (let ([rev (car xs)])
+          (if (not (same-public-string? rev current))
+              (loop (cdr xs) (cons (numstat-adds (changed-files repo rev file)) out))
+              (loop (cdr xs) out))))))
 
 (def (author-times repo revs author-id)
   (let loop ([xs revs] [out '()])
@@ -641,7 +673,8 @@
          [raw-signals (if eligible?
                           (list (message-signal subject body adds) (code-signal lines) (structure-signal paths adds dels lines)
                                 (car sim-pair) (history-signal adds time (parent-time repo parent) (author-times repo revs author-email))
-                                (baseline-signal adds (prior-additions repo revs author-email rev file)))
+                                (baseline-signal adds (prior-additions repo revs author-email rev file))
+                                (repository-baseline-signal adds (prior-repository-additions repo revs rev file)))
                           '())]
          [signals (if metadata-only? '() (map (lambda (s) (with-config-weight current-config s)) raw-signals))]
          [score (if metadata-only? 0.0 (aggregate-score signals))]
diff --git a/tests/fixture-smoke.sh b/tests/fixture-smoke.sh
index 82a9b95..ab02452 100755
--- a/tests/fixture-smoke.sh
+++ b/tests/fixture-smoke.sh
@@ -57,6 +57,7 @@ printf '%s\n' "$json" | grep -q '"category":"structure"'
 printf '%s\n' "$json" | grep -q '"category":"similarity"'
 printf '%s\n' "$json" | grep -q '"category":"history"'
 printf '%s\n' "$json" | grep -q '"category":"baseline"'
+printf '%s\n' "$json" | grep -q '"name":"repository-baseline"'
 printf '%s\n' "$json" | grep -q '"evidence":\[\]'
 printf '%s\n' "$json" | grep -q '"warnings":\[\]'
 if printf '%s\n' "$json" | grep -q 'vendor/library.py'; then