#!/usr/bin/env python3
"""Bank batch-258: Rule 216 low-frequency food-reference lexical expansion."""

from __future__ import annotations

import datetime as dt
import json
import re
import sqlite3

from process_ledger import ensure_schema, record_event

DB = "/mnt/donto-data/donto-resources/research/translation-training/kuku-yalanji-runpod-2026-06-30/synthetic/claude-synthetic-v1-2026-07-02/synthetic.db"
LABEL = "batch-258"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-258-low-frequency-food-reference-lexical-expansion-after-rule215-process.md"

TARGET_HEADS = {
    "birukay": "yolk",
    "biyangkal": "yam",
    "darka": "nut",
    "dukal": "fig",
    "jadamu": "bananas",
    "jamal": "egg white",
    "jungu-jungu": "white ant eggs",
    "mujurr": "witchetty grub",
    "wawukuna": "long wild yam",
    "wuynkurr": "meat juice",
}
SUPPORT = {"yinya", "yaluy", "yinyay"}
DENY_KUKU = {
    "nuka", "nukal", "nukan", "nukaji", "dajin", "daji", "daji-l",
    "mani", "manil", "manin", "muja", "mujal", "mujan", "baja", "bajaku",
    "wurrmba", "kaba", "bana", "jaban", "kurrma", "kurrmaja", "kalbal",
    "kamu-kamu", "mayngku", "banabul", "jarru", "damba", "balja", "kawu",
    "diyi", "kalbanbina", "nganyin", "marrkabina", "ngarrakaja", "kaduy",
    "karruku", "kulil", "kuyalin", "mujurr-bu", "mujurr-nga", "bayan",
    "bubu", "juku", "mayi", "minya", "yala", "yanyu", "ngayu", "nyulu",
    "yundu", "jana", "ngana", "nganya", "yununy", "nyunguny",
}
DENY_ENGLISH = (
    "cook", "cooked", "cooking", "roast", "roasted", "ground up", "grind", "leach", "leached",
    "safe to eat", "eat", "eating", "edible", "food here for", "medicine", "remedy", "treatment",
    "sickness", "cold", "beer", "strong drink", "alcohol", "mango", "pineapple", "loan", "flour",
    "damper", "taro", "found in", "rotting wood", "gather", "gathered", "white ant nest", "egg collecting",
    "fat", "meat source", "water", "fire", "fireplace",
)


def js(values: list[str]) -> str:
    return json.dumps(values, ensure_ascii=False)


def row(
    seq: int,
    english: str,
    kuku: str,
    analysis: str,
    frame: str,
    words: list[str],
    evidence: str,
) -> tuple:
    return (seq, english, kuku, analysis, frame, 2, js(words), js([]), evidence, "0.86")


ROWS = [
    row(1, "The yolk is here.", "Birukay yaluy.", "birukay yaluy | yolk here", "r216_food_ref_here_birukay", ["birukay", "yaluy"], "Dictionary birukay noun 'yolk of the egg'; Patz section 3.7 yaluy 'here'."),
    row(2, "The yam is here.", "Biyangkal yaluy.", "biyangkal yaluy | yam here", "r216_food_ref_here_biyangkal", ["biyangkal", "yaluy"], "Dictionary biyangkal noun 'yam'; roasting/grinding/leaching/eating prose closed; Patz section 3.7 yaluy."),
    row(3, "The nut is here.", "Darka yaluy.", "darka yaluy | nut here", "r216_food_ref_here_darka", ["darka", "yaluy"], "Dictionary darka noun 'kind of nut'; Patz section 3.7 yaluy 'here'."),
    row(4, "The fig is here.", "Dukal yaluy.", "dukal yaluy | fig here", "r216_food_ref_here_dukal", ["dukal", "yaluy"], "Dictionary dukal noun 'kind of fruit (fig)'; edible/roasting prose closed; Patz section 3.7 yaluy."),
    row(5, "The bananas are here.", "Jadamu yaluy.", "jadamu yaluy | bananas here", "r216_food_ref_here_jadamu", ["jadamu", "yaluy"], "Dictionary jadamu noun 'bananas'; Patz section 3.7 yaluy 'here'."),
    row(6, "The egg white is here.", "Jamal yaluy.", "jamal yaluy | egg.white here", "r216_food_ref_here_jamal", ["jamal", "yaluy"], "Dictionary jamal noun 'white of egg, albumen'; selected egg white; Patz section 3.7 yaluy."),
    row(7, "The white ant eggs are here.", "Jungu-jungu yaluy.", "jungu-jungu yaluy | white.ant.eggs here", "r216_food_ref_here_jungu_jungu", ["jungu-jungu", "yaluy"], "Dictionary jungu-jungu noun 'white ant eggs'; gathering/insect-event prose closed; Patz section 3.7 yaluy."),
    row(8, "The witchetty grub is here.", "Mujurr yaluy.", "mujurr yaluy | witchetty.grub here", "r216_food_ref_here_mujurr", ["mujurr", "yaluy"], "Dictionary mujurr noun 'witchetty grub'; rotting-wood habitat and collecting prose closed; Patz section 3.7 yaluy."),
    row(9, "The long wild yam is here.", "Wawukuna yaluy.", "wawukuna yaluy | long.wild.yam here", "r216_food_ref_here_wawukuna", ["wawukuna", "yaluy"], "Dictionary wawukuna noun 'long wild yam'; Patz section 3.7 yaluy 'here'."),
    row(10, "The meat juice is here.", "Wuynkurr yaluy.", "wuynkurr yaluy | meat.juice here", "r216_food_ref_here_wuynkurr", ["wuynkurr", "yaluy"], "Dictionary wuynkurr noun 'juice of meat'; fat/source prose closed; Patz section 3.7 yaluy."),
    row(11, "The yolk is there.", "Birukay yinyay.", "birukay yinyay | yolk there", "r216_food_ref_there_birukay", ["birukay", "yinyay"], "Dictionary birukay noun 'yolk'; Patz section 3.7 yinyay 'there'."),
    row(12, "The yam is there.", "Biyangkal yinyay.", "biyangkal yinyay | yam there", "r216_food_ref_there_biyangkal", ["biyangkal", "yinyay"], "Dictionary biyangkal noun 'yam'; preparation/eating prose closed; Patz section 3.7 yinyay."),
    row(13, "The nut is there.", "Darka yinyay.", "darka yinyay | nut there", "r216_food_ref_there_darka", ["darka", "yinyay"], "Dictionary darka noun 'nut'; Patz section 3.7 yinyay 'there'."),
    row(14, "The fig is there.", "Dukal yinyay.", "dukal yinyay | fig there", "r216_food_ref_there_dukal", ["dukal", "yinyay"], "Dictionary dukal noun 'fig'; edible/roasting prose closed; Patz section 3.7 yinyay."),
    row(15, "The bananas are there.", "Jadamu yinyay.", "jadamu yinyay | bananas there", "r216_food_ref_there_jadamu", ["jadamu", "yinyay"], "Dictionary jadamu noun 'bananas'; Patz section 3.7 yinyay 'there'."),
    row(16, "The egg white is there.", "Jamal yinyay.", "jamal yinyay | egg.white there", "r216_food_ref_there_jamal", ["jamal", "yinyay"], "Dictionary jamal noun 'white of egg'; Patz section 3.7 yinyay."),
    row(17, "The white ant eggs are there.", "Jungu-jungu yinyay.", "jungu-jungu yinyay | white.ant.eggs there", "r216_food_ref_there_jungu_jungu", ["jungu-jungu", "yinyay"], "Dictionary jungu-jungu noun 'white ant eggs'; collecting/event prose closed; Patz section 3.7 yinyay."),
    row(18, "The witchetty grub is there.", "Mujurr yinyay.", "mujurr yinyay | witchetty.grub there", "r216_food_ref_there_mujurr", ["mujurr", "yinyay"], "Dictionary mujurr noun 'witchetty grub'; habitat/use prose closed; Patz section 3.7 yinyay."),
    row(19, "The long wild yam is there.", "Wawukuna yinyay.", "wawukuna yinyay | long.wild.yam there", "r216_food_ref_there_wawukuna", ["wawukuna", "yinyay"], "Dictionary wawukuna noun 'long wild yam'; Patz section 3.7 yinyay."),
    row(20, "The meat juice is there.", "Wuynkurr yinyay.", "wuynkurr yinyay | meat.juice there", "r216_food_ref_there_wuynkurr", ["wuynkurr", "yinyay"], "Dictionary wuynkurr noun 'meat juice'; fat/source prose closed; Patz section 3.7 yinyay."),
    row(21, "That yolk is there.", "Yinya birukay yinyay.", "yinya birukay yinyay | that yolk there", "r216_that_food_ref_there_birukay", ["yinya", "birukay", "yinyay"], "Patz section 3.7 yinya can co-occur with a noun; dictionary birukay noun 'yolk'; yinyay 'there'."),
    row(22, "That yam is there.", "Yinya biyangkal yinyay.", "yinya biyangkal yinyay | that yam there", "r216_that_food_ref_there_biyangkal", ["yinya", "biyangkal", "yinyay"], "Patz section 3.7 yinya with noun; dictionary biyangkal noun 'yam'; preparation/eating prose closed."),
    row(23, "That nut is there.", "Yinya darka yinyay.", "yinya darka yinyay | that nut there", "r216_that_food_ref_there_darka", ["yinya", "darka", "yinyay"], "Patz section 3.7 yinya with noun; dictionary darka noun 'nut'; yinyay 'there'."),
    row(24, "That fig is there.", "Yinya dukal yinyay.", "yinya dukal yinyay | that fig there", "r216_that_food_ref_there_dukal", ["yinya", "dukal", "yinyay"], "Patz section 3.7 yinya with noun; dictionary dukal noun 'fig'; edible/roasting prose closed."),
    row(25, "Those bananas are there.", "Yinya jadamu yinyay.", "yinya jadamu yinyay | those bananas there", "r216_that_food_ref_there_jadamu", ["yinya", "jadamu", "yinyay"], "Patz section 3.7 yinya can imply singular or plural by context; dictionary jadamu noun 'bananas'."),
    row(26, "That egg white is there.", "Yinya jamal yinyay.", "yinya jamal yinyay | that egg.white there", "r216_that_food_ref_there_jamal", ["yinya", "jamal", "yinyay"], "Patz section 3.7 yinya with noun; dictionary jamal noun 'egg white'; yinyay 'there'."),
    row(27, "Those white ant eggs are there.", "Yinya jungu-jungu yinyay.", "yinya jungu-jungu yinyay | those white.ant.eggs there", "r216_that_food_ref_there_jungu_jungu", ["yinya", "jungu-jungu", "yinyay"], "Patz section 3.7 yinya can imply plural by context; dictionary jungu-jungu noun 'white ant eggs'."),
    row(28, "That witchetty grub is there.", "Yinya mujurr yinyay.", "yinya mujurr yinyay | that witchetty.grub there", "r216_that_food_ref_there_mujurr", ["yinya", "mujurr", "yinyay"], "Patz section 3.7 yinya with noun; dictionary mujurr noun 'witchetty grub'; habitat closed."),
    row(29, "That long wild yam is there.", "Yinya wawukuna yinyay.", "yinya wawukuna yinyay | that long.wild.yam there", "r216_that_food_ref_there_wawukuna", ["yinya", "wawukuna", "yinyay"], "Patz section 3.7 yinya with noun; dictionary wawukuna noun 'long wild yam'."),
    row(30, "That meat juice is there.", "Yinya wuynkurr yinyay.", "yinya wuynkurr yinyay | that meat.juice there", "r216_that_food_ref_there_wuynkurr", ["yinya", "wuynkurr", "yinyay"], "Patz section 3.7 yinya with noun; dictionary wuynkurr noun 'meat juice'; fat/source prose closed."),
    row(31, "That yolk is there.", "Birukay yinya yinyay.", "birukay yinya yinyay | that yolk there", "r216_food_that_there_birukay", ["birukay", "yinya", "yinyay"], "Patz section 3.7 yinya can follow a noun; dictionary birukay noun 'yolk'; yinyay 'there'."),
    row(32, "That yam is there.", "Biyangkal yinya yinyay.", "biyangkal yinya yinyay | that yam there", "r216_food_that_there_biyangkal", ["biyangkal", "yinya", "yinyay"], "Patz section 3.7 yinya can follow a noun; dictionary biyangkal noun 'yam'."),
    row(33, "That nut is there.", "Darka yinya yinyay.", "darka yinya yinyay | that nut there", "r216_food_that_there_darka", ["darka", "yinya", "yinyay"], "Patz section 3.7 yinya can follow a noun; dictionary darka noun 'nut'."),
    row(34, "That fig is there.", "Dukal yinya yinyay.", "dukal yinya yinyay | that fig there", "r216_food_that_there_dukal", ["dukal", "yinya", "yinyay"], "Patz section 3.7 yinya can follow a noun; dictionary dukal noun 'fig'."),
    row(35, "Those bananas are there.", "Jadamu yinya yinyay.", "jadamu yinya yinyay | those bananas there", "r216_food_that_there_jadamu", ["jadamu", "yinya", "yinyay"], "Patz section 3.7 yinya can follow a noun and imply plural by context; dictionary jadamu noun 'bananas'."),
    row(36, "That egg white is there.", "Jamal yinya yinyay.", "jamal yinya yinyay | that egg.white there", "r216_food_that_there_jamal", ["jamal", "yinya", "yinyay"], "Patz section 3.7 yinya can follow a noun; dictionary jamal noun 'egg white'."),
    row(37, "Those white ant eggs are there.", "Jungu-jungu yinya yinyay.", "jungu-jungu yinya yinyay | those white.ant.eggs there", "r216_food_that_there_jungu_jungu", ["jungu-jungu", "yinya", "yinyay"], "Patz section 3.7 yinya can follow a noun; dictionary jungu-jungu noun 'white ant eggs'."),
    row(38, "That witchetty grub is there.", "Mujurr yinya yinyay.", "mujurr yinya yinyay | that witchetty.grub there", "r216_food_that_there_mujurr", ["mujurr", "yinya", "yinyay"], "Patz section 3.7 yinya can follow a noun; dictionary mujurr noun 'witchetty grub'."),
    row(39, "That long wild yam is there.", "Wawukuna yinya yinyay.", "wawukuna yinya yinyay | that long.wild.yam there", "r216_food_that_there_wawukuna", ["wawukuna", "yinya", "yinyay"], "Patz section 3.7 yinya can follow a noun; dictionary wawukuna noun 'long wild yam'."),
    row(40, "That meat juice is there.", "Wuynkurr yinya yinyay.", "wuynkurr yinya yinyay | that meat.juice there", "r216_food_that_there_wuynkurr", ["wuynkurr", "yinya", "yinyay"], "Patz section 3.7 yinya can follow a noun; dictionary wuynkurr noun 'meat juice'."),
    row(41, "That yolk is here.", "Yinya birukay yaluy.", "yinya birukay yaluy | that yolk here", "r216_that_food_ref_here_birukay", ["yinya", "birukay", "yaluy"], "Patz section 3.7 yinya with noun; dictionary birukay noun 'yolk'; yaluy 'here'."),
    row(42, "That yam is here.", "Yinya biyangkal yaluy.", "yinya biyangkal yaluy | that yam here", "r216_that_food_ref_here_biyangkal", ["yinya", "biyangkal", "yaluy"], "Patz section 3.7 yinya with noun; dictionary biyangkal noun 'yam'; preparation/eating closed."),
    row(43, "That nut is here.", "Yinya darka yaluy.", "yinya darka yaluy | that nut here", "r216_that_food_ref_here_darka", ["yinya", "darka", "yaluy"], "Patz section 3.7 yinya with noun; dictionary darka noun 'nut'; yaluy 'here'."),
    row(44, "That fig is here.", "Yinya dukal yaluy.", "yinya dukal yaluy | that fig here", "r216_that_food_ref_here_dukal", ["yinya", "dukal", "yaluy"], "Patz section 3.7 yinya with noun; dictionary dukal noun 'fig'; edible/roasting closed."),
    row(45, "Those bananas are here.", "Yinya jadamu yaluy.", "yinya jadamu yaluy | those bananas here", "r216_that_food_ref_here_jadamu", ["yinya", "jadamu", "yaluy"], "Patz section 3.7 yinya can imply plural by context; dictionary jadamu noun 'bananas'."),
    row(46, "That egg white is here.", "Yinya jamal yaluy.", "yinya jamal yaluy | that egg.white here", "r216_that_food_ref_here_jamal", ["yinya", "jamal", "yaluy"], "Patz section 3.7 yinya with noun; dictionary jamal noun 'egg white'."),
    row(47, "Those white ant eggs are here.", "Yinya jungu-jungu yaluy.", "yinya jungu-jungu yaluy | those white.ant.eggs here", "r216_that_food_ref_here_jungu_jungu", ["yinya", "jungu-jungu", "yaluy"], "Patz section 3.7 yinya can imply plural by context; dictionary jungu-jungu noun 'white ant eggs'."),
    row(48, "That witchetty grub is here.", "Yinya mujurr yaluy.", "yinya mujurr yaluy | that witchetty.grub here", "r216_that_food_ref_here_mujurr", ["yinya", "mujurr", "yaluy"], "Patz section 3.7 yinya with noun; dictionary mujurr noun 'witchetty grub'."),
    row(49, "That long wild yam is here.", "Yinya wawukuna yaluy.", "yinya wawukuna yaluy | that long.wild.yam here", "r216_that_food_ref_here_wawukuna", ["yinya", "wawukuna", "yaluy"], "Patz section 3.7 yinya with noun; dictionary wawukuna noun 'long wild yam'."),
    row(50, "That meat juice is here.", "Yinya wuynkurr yaluy.", "yinya wuynkurr yaluy | that meat.juice here", "r216_that_food_ref_here_wuynkurr", ["yinya", "wuynkurr", "yaluy"], "Patz section 3.7 yinya with noun; dictionary wuynkurr noun 'meat juice'."),
]


def has_token(low: str, token: str) -> bool:
    return re.search(rf"(?<![a-z-]){re.escape(token)}(?![a-z-])", low) is not None


def has_target_morphology(low: str, head: str) -> bool:
    suffixes = "ngka|ngku|angka|nga|ngu|ba|mba|mbu|muny|darr|burr|bu|ka|nka|nku|ji|jirr|ku|mundu|amu|mu|iji|nda|ndu|anda|undu|unji|nji|kari|baka|baja|bungal|bungan|mal|man|rriny"
    return re.search(rf"(?<![a-z-]){re.escape(head)}-(?:{suffixes})\b", low) is not None


def english_has_denied(english_low: str, denied: str) -> bool:
    return denied in english_low if " " in denied else re.search(rf"\b{re.escape(denied.strip())}\b", english_low) is not None


def scan_static() -> list[str]:
    issues: list[str] = []
    if len(ROWS) != 50:
        issues.append(f"{LABEL}: expected 50 rows, found {len(ROWS)}")
    seen_ku: set[str] = set()
    for expected, row_data in enumerate(ROWS, start=1):
        seq, english, kuku, analysis, frame, _tier, words_used, loans_used, evidence, confidence = row_data
        label = f"{LABEL}.{seq:02d}"
        low = kuku.lower()
        english_low = english.lower()
        words = json.loads(words_used)
        if seq != expected:
            issues.append(f"{label}: sequence mismatch; expected {expected}")
        if not english[:1].isupper() or english[-1:] not in ".!?":
            issues.append(f"{label}: English punctuation/capitalization failure")
        if " | " not in analysis:
            issues.append(f"{label}: analysis missing gloss separator")
        if not frame.startswith("r216_"):
            issues.append(f"{label}: Rule 216 frame must start with r216_")
        if low in seen_ku:
            issues.append(f"{label}: duplicate Kuku surface within batch")
        seen_ku.add(low)
        if json.loads(loans_used):
            issues.append(f"{label}: no loans are admitted in Rule 216")
        for denied in DENY_KUKU:
            if has_token(low, denied):
                issues.append(f"{label}: denied carry-forward token {denied!r}")
        targets = [head for head in TARGET_HEADS if has_token(low, head)]
        if len(targets) != 1:
            issues.append(f"{label}: expected exactly one Rule 216 target noun, found {targets}")
        for head in targets:
            selected = TARGET_HEADS[head]
            dotted = selected.replace("-", ".").replace(" ", ".")
            if head not in words:
                issues.append(f"{label}: target head {head} missing from words_used")
            if selected not in english_low:
                issues.append(f"{label}: English must include selected sense {selected!r}")
            if selected not in analysis and dotted not in analysis:
                issues.append(f"{label}: analysis must gloss {head} as {selected}")
            if has_target_morphology(low, head):
                issues.append(f"{label}: target head {head} has forbidden morphology")
        for support in SUPPORT:
            if has_token(low, support) and support not in words:
                issues.append(f"{label}: support {support} missing from words_used")
        if 1 <= seq <= 10 and (has_token(low, "yinya") or has_token(low, "yinyay") or not low.endswith(" yaluy.") or len(low.split()) != 2):
            issues.append(f"{label}: rows 1-10 require TARGET yaluy")
        if 11 <= seq <= 20 and (has_token(low, "yinya") or has_token(low, "yaluy") or not low.endswith(" yinyay.") or len(low.split()) != 2):
            issues.append(f"{label}: rows 11-20 require TARGET yinyay")
        if 21 <= seq <= 30 and (not low.startswith("yinya ") or has_token(low, "yaluy") or not low.endswith(" yinyay.") or len(low.split()) != 3):
            issues.append(f"{label}: rows 21-30 require Yinya TARGET yinyay")
        if 31 <= seq <= 40 and (not has_token(low, "yinya") or has_token(low, "yaluy") or not low.endswith(" yinyay.") or len(low.split()) != 3 or low.startswith("yinya ")):
            issues.append(f"{label}: rows 31-40 require TARGET yinya yinyay")
        if 41 <= seq <= 50 and (not low.startswith("yinya ") or has_token(low, "yinyay") or not low.endswith(" yaluy.") or len(low.split()) != 3):
            issues.append(f"{label}: rows 41-50 require Yinya TARGET yaluy")
        if any(english_has_denied(english_low, bad) for bad in DENY_ENGLISH):
            issues.append(f"{label}: denied food-use/preparation/loan field in English")
        if not evidence or not confidence:
            issues.append(f"{label}: missing evidence/confidence")
    return issues


def main() -> int:
    issues = scan_static()
    if issues:
        print("pre-bank scan failed:")
        for issue in issues:
            print(f"  - {issue}")
        return 1

    db = sqlite3.connect(DB)
    db.execute("PRAGMA foreign_keys = ON")
    db.execute("BEGIN")
    ensure_schema(db)
    existing = db.execute("SELECT id FROM batches WHERE label=?", (LABEL,)).fetchone()
    if existing:
        batch_id = existing[0]
        accepted = db.execute(
            "SELECT COUNT(*) FROM sentences WHERE batch_id=? AND status IN ('accepted','revised')",
            (batch_id,),
        ).fetchone()[0]
        if accepted:
            raise SystemExit(f"{LABEL} already has accepted/revised rows; refusing to overwrite")
        db.execute("DELETE FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)", (batch_id,))
        db.execute("DELETE FROM sentences WHERE batch_id=?", (batch_id,))
        db.execute("UPDATE batches SET notes=?, created_at=? WHERE id=?", ("rebanked under_review", NOW, batch_id))
    else:
        cur = db.execute(
            "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
            (
                LABEL,
                "Rule 216 draft: low-frequency food-reference lexical expansion after Rule 215",
                "operator-guide-2026-07-08",
                "under_review",
                NOW,
            ),
        )
        batch_id = cur.lastrowid

    dupes: list[str] = []
    for seq, _english, kuku, *_rest in ROWS:
        hit = db.execute(
            """
            SELECT b.label, s.seq
            FROM sentences s JOIN batches b ON b.id=s.batch_id
            WHERE lower(trim(s.kuku))=lower(trim(?))
              AND s.status!='rejected'
              AND s.batch_id!=?
            """,
            (kuku, batch_id),
        ).fetchone()
        if hit:
            dupes.append(f"{LABEL}.{seq:02d} duplicates {hit[0]}.{hit[1]:02d}: {kuku}")
    if dupes:
        db.rollback()
        print("cross-corpus duplicate check failed:")
        for dupe in dupes:
            print(f"  - {dupe}")
        return 1

    db.executemany(
        """
        INSERT INTO sentences(
          batch_id, seq, english, kuku, analysis, frame, tier, words_used,
          loans_used, evidence, status, confidence, author, created_at
        ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)
        """,
        [
            (batch_id, seq, english, kuku, analysis, frame, tier, words_used, loans_used, evidence, "under_review", confidence, "claude", NOW)
            for seq, english, kuku, analysis, frame, tier, words_used, loans_used, evidence, confidence in ROWS
        ],
    )

    verified_before, words_before = db.execute(
        """
        SELECT
          COUNT(*),
          SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1)
        FROM sentences
        WHERE status IN ('accepted','revised')
        """
    ).fetchone()
    under_review = db.execute(
        "SELECT COUNT(*) FROM sentences WHERE batch_id=? AND status='under_review'",
        (batch_id,),
    ).fetchone()[0]

    record_event(
        db,
        batch_label=LABEL,
        phase="source",
        event_type="source-pass",
        actor="claude-main",
        detail=(
            "Checked Patz section 3.1 noun/reference basis, Patz section 3.7 yinya/yaluy/yinyay support, and dictionary entries "
            "for birukay, biyangkal, darka, dukal, jadamu, jamal, jungu-jungu, mujurr, wawukuna, and wuynkurr. "
            "Admitted only selected bare food-reference senses."
        ),
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="scope",
        event_type="candidate-rejection",
        actor="claude-main",
        detail=(
            "Selected food-reference only after excluding loan/post-contact or unsafe heads: banabul, mayngku, and jarru as loans; "
            "kalbal for medicine/sickness; kamu-kamu for alcohol; damba/balja/jandu for heavier preparation/post-contact pressure; "
            "kawu held because generic yam duplication was avoidable."
        ),
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="preflight",
        event_type="duplicate-preflight",
        actor="claude-main",
        detail="Exact duplicate preflight over all 50 planned Rule 216 Kuku surfaces returned no accepted, revised, or under-review collisions.",
        command="python3 batch_scripts/bank_258.py cross-corpus duplicate scan",
        artifact_path="batch_scripts/bank_258.py",
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="preflight",
        event_type="static-guard-pass",
        actor="claude-main",
        detail=(
            "bank_258.py static guards passed: 50 explicit hand-authored rows, exactly one food-reference target noun per row, "
            "no loans, no target morphology, no cooking/eating/preparation/medicine/alcohol/loan English, and only the five sourced deictic frame bands."
        ),
        artifact_path="batch_scripts/bank_258.py",
        created_at=NOW,
    )
    db.commit()
    print(
        f"banked {LABEL}: rows={len(ROWS)}, under_review={under_review}, "
        f"verified_before_close={verified_before}, words_before={words_before or 0}"
    )
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
