#!/usr/bin/env python3
"""Bank batch-276: Rule 234 third body-part 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-276"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-276-third-body-part-reference-lexical-expansion-after-rule233-process.md"

TARGET_HEADS = {
    "bandin": "love handles",
    "bari": "chin",
    "bibar": "shin",
    "birri": "fingernail",
    "jiba": "liver",
    "jandal": "leg",
    "jibar": "stomach",
    "kangkul": "cheek",
    "kuwinyu": "posterior",
    "waba": "thigh",
}
PLURAL_TARGETS = {"bandin"}
SUPPORT = {"yinya", "yaluy", "yinyay"}
DENY_KUKU = {
    # Rule 217 and Rule 226 exact body-part targets.
    "barrkar", "baru", "jaljan", "jamalka", "jinbar", "kabari", "kuburrubun", "makal",
    "mirrimar", "mudu", "bilirr", "durru", "jakuji", "jurrubiji", "murun", "ngungumurr",
    "nyidu", "nyumbul", "wulurringkal", "yimbi",
    # Earlier common body-part exact targets and rejected/deferred body-part candidates.
    "bajibay", "bangkarr", "bibi", "binda", "biyal", "dabul", "dabulkurra", "dakil",
    "dalkari", "diburr-miyil", "dirra", "dukul", "jadalangka", "jirril", "juju",
    "juka", "junkan", "jurru", "juwul", "kadan", "kali", "kanya", "kiru",
    "kunja", "kurrburrbun", "kurrul", "kuyi", "malbin", "manji", "manu", "mara",
    "mijan", "milka", "miyil", "muku", "muku-duku", "mula", "mungka", "mungka-dirka",
    "munju", "munyun", "murrka", "muyu", "nangki", "ngandal", "ngarran", "ngarri",
    "ngumanji", "nyabil", "nyinki", "nyirribulu", "nyumba", "waba-", "wakuy",
    "walarr", "walu", "waral", "wubul", "wubun", "wulbar", "wulu", "wurmbu",
    "wurra", "yijirr", "yiman", "yiman-bunjal", "yimarr-yiman", "yinkan", "yulban",
}
DENY_ENGLISH = (
    "my ", "your ", "his ", "her ", "their ", "person's", "owner", "possession", "possessor",
    "pain", "painful", "sore", "hurt", "injury", "injured", "illness", "sick", "medicine", "medical",
    "healing", "heal", "body fluid", "fluid", "blood", "mucus", "saliva", "urine", "pus", "milk",
    "taboo", "scar", "scab", "initiation", "ritual", "witchcraft", "magic", "place", "story", "site",
    "animal", "beast", "turtle", "snake", "pig", "fish", "egg", "fur", "pelt", "dialect", "nyungkul",
    "cut", "pierced", "pierce", "stubbed", "touch", "touching", "hold", "holding", "carry", "carrying",
    "move", "moving", "walk", "walking", "tiptoe", "eat", "eating", "swallow", "speaking", "speech",
    "jaw", "ankle", "toenail", "insides", "guts", "organs", "emotion", "sad", "glad", "hip", "only",
)


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")


EVIDENCE = {
    "bandin": "Dictionary bandin noun gloss 'love handles', definition 'waist on the side above the hips; love handles'. Rule 234 uses the body-part reference label only. Patz 3.1 nominal body-part source and Patz 3.7 yinya/yaluy/yinyay deictic support.",
    "bari": "Dictionary bari noun gloss 'chin', definitions 'chin; jaw'. Rule 234 narrows to chin reference only. Patz 3.1 and 3.7.",
    "bibar": "Dictionary bibar noun gloss 'shin', definitions 'shin, ankle'. Rule 234 narrows to shin reference only. Patz 3.1 and 3.7.",
    "birri": "Dictionary birri noun gloss 'fingernail', definitions 'fingernail, toenail'. Rule 234 narrows to fingernail reference only. Patz 3.1 and 3.7.",
    "jiba": "Dictionary jiba noun gloss 'liver', definitions 'liver; insides, guts'. Rule 234 narrows to liver reference only and does not open emotion/inside-guts prose. Patz 3.1 and 3.7.",
    "jandal": "Dictionary jandal noun gloss 'leg', definition 'lower limb, leg'. Rule 234 uses leg reference only. Patz 3.1 and 3.7.",
    "jibar": "Dictionary jibar noun gloss 'stomach'. Rule 234 keeps jibar distinct from locational jibarr 'hinterland'. Patz 3.1 and 3.7.",
    "kangkul": "Dictionary kangkul noun gloss 'cheek'. Rule 234 keeps it distinct from kangku 'valley'. Patz 3.1 and 3.7.",
    "kuwinyu": "Dictionary kuwinyu noun gloss 'posterior', definition 'posterior (not a rude term)'. Rule 234 uses posterior reference only. Patz 3.1 and 3.7.",
    "waba": "Dictionary/grammar-added waba noun gloss 'thigh', definition 'thigh, hip'. Rule 234 narrows to thigh reference only. Patz 3.1 and 3.7.",
}


ROWS = [
    row(1, "The love handles are here.", "Bandin yaluy.", "bandin yaluy | love.handles here", "r234_body_part_ref_here_bandin", ["bandin", "yaluy"], EVIDENCE["bandin"]),
    row(2, "The chin is here.", "Bari yaluy.", "bari yaluy | chin here", "r234_body_part_ref_here_bari", ["bari", "yaluy"], EVIDENCE["bari"]),
    row(3, "The shin is here.", "Bibar yaluy.", "bibar yaluy | shin here", "r234_body_part_ref_here_bibar", ["bibar", "yaluy"], EVIDENCE["bibar"]),
    row(4, "The fingernail is here.", "Birri yaluy.", "birri yaluy | fingernail here", "r234_body_part_ref_here_birri", ["birri", "yaluy"], EVIDENCE["birri"]),
    row(5, "The liver is here.", "Jiba yaluy.", "jiba yaluy | liver here", "r234_body_part_ref_here_jiba", ["jiba", "yaluy"], EVIDENCE["jiba"]),
    row(6, "The leg is here.", "Jandal yaluy.", "jandal yaluy | leg here", "r234_body_part_ref_here_jandal", ["jandal", "yaluy"], EVIDENCE["jandal"]),
    row(7, "The stomach is here.", "Jibar yaluy.", "jibar yaluy | stomach here", "r234_body_part_ref_here_jibar", ["jibar", "yaluy"], EVIDENCE["jibar"]),
    row(8, "The cheek is here.", "Kangkul yaluy.", "kangkul yaluy | cheek here", "r234_body_part_ref_here_kangkul", ["kangkul", "yaluy"], EVIDENCE["kangkul"]),
    row(9, "The posterior is here.", "Kuwinyu yaluy.", "kuwinyu yaluy | posterior here", "r234_body_part_ref_here_kuwinyu", ["kuwinyu", "yaluy"], EVIDENCE["kuwinyu"]),
    row(10, "The thigh is here.", "Waba yaluy.", "waba yaluy | thigh here", "r234_body_part_ref_here_waba", ["waba", "yaluy"], EVIDENCE["waba"]),
    row(11, "The love handles are there.", "Bandin yinyay.", "bandin yinyay | love.handles there", "r234_body_part_ref_there_bandin", ["bandin", "yinyay"], EVIDENCE["bandin"]),
    row(12, "The chin is there.", "Bari yinyay.", "bari yinyay | chin there", "r234_body_part_ref_there_bari", ["bari", "yinyay"], EVIDENCE["bari"]),
    row(13, "The shin is there.", "Bibar yinyay.", "bibar yinyay | shin there", "r234_body_part_ref_there_bibar", ["bibar", "yinyay"], EVIDENCE["bibar"]),
    row(14, "The fingernail is there.", "Birri yinyay.", "birri yinyay | fingernail there", "r234_body_part_ref_there_birri", ["birri", "yinyay"], EVIDENCE["birri"]),
    row(15, "The liver is there.", "Jiba yinyay.", "jiba yinyay | liver there", "r234_body_part_ref_there_jiba", ["jiba", "yinyay"], EVIDENCE["jiba"]),
    row(16, "The leg is there.", "Jandal yinyay.", "jandal yinyay | leg there", "r234_body_part_ref_there_jandal", ["jandal", "yinyay"], EVIDENCE["jandal"]),
    row(17, "The stomach is there.", "Jibar yinyay.", "jibar yinyay | stomach there", "r234_body_part_ref_there_jibar", ["jibar", "yinyay"], EVIDENCE["jibar"]),
    row(18, "The cheek is there.", "Kangkul yinyay.", "kangkul yinyay | cheek there", "r234_body_part_ref_there_kangkul", ["kangkul", "yinyay"], EVIDENCE["kangkul"]),
    row(19, "The posterior is there.", "Kuwinyu yinyay.", "kuwinyu yinyay | posterior there", "r234_body_part_ref_there_kuwinyu", ["kuwinyu", "yinyay"], EVIDENCE["kuwinyu"]),
    row(20, "The thigh is there.", "Waba yinyay.", "waba yinyay | thigh there", "r234_body_part_ref_there_waba", ["waba", "yinyay"], EVIDENCE["waba"]),
    row(21, "Those love handles are there.", "Yinya bandin yinyay.", "yinya bandin yinyay | those love.handles there", "r234_that_body_part_ref_there_bandin", ["yinya", "bandin", "yinyay"], EVIDENCE["bandin"]),
    row(22, "That chin is there.", "Yinya bari yinyay.", "yinya bari yinyay | that chin there", "r234_that_body_part_ref_there_bari", ["yinya", "bari", "yinyay"], EVIDENCE["bari"]),
    row(23, "That shin is there.", "Yinya bibar yinyay.", "yinya bibar yinyay | that shin there", "r234_that_body_part_ref_there_bibar", ["yinya", "bibar", "yinyay"], EVIDENCE["bibar"]),
    row(24, "That fingernail is there.", "Yinya birri yinyay.", "yinya birri yinyay | that fingernail there", "r234_that_body_part_ref_there_birri", ["yinya", "birri", "yinyay"], EVIDENCE["birri"]),
    row(25, "That liver is there.", "Yinya jiba yinyay.", "yinya jiba yinyay | that liver there", "r234_that_body_part_ref_there_jiba", ["yinya", "jiba", "yinyay"], EVIDENCE["jiba"]),
    row(26, "That leg is there.", "Yinya jandal yinyay.", "yinya jandal yinyay | that leg there", "r234_that_body_part_ref_there_jandal", ["yinya", "jandal", "yinyay"], EVIDENCE["jandal"]),
    row(27, "That stomach is there.", "Yinya jibar yinyay.", "yinya jibar yinyay | that stomach there", "r234_that_body_part_ref_there_jibar", ["yinya", "jibar", "yinyay"], EVIDENCE["jibar"]),
    row(28, "That cheek is there.", "Yinya kangkul yinyay.", "yinya kangkul yinyay | that cheek there", "r234_that_body_part_ref_there_kangkul", ["yinya", "kangkul", "yinyay"], EVIDENCE["kangkul"]),
    row(29, "That posterior is there.", "Yinya kuwinyu yinyay.", "yinya kuwinyu yinyay | that posterior there", "r234_that_body_part_ref_there_kuwinyu", ["yinya", "kuwinyu", "yinyay"], EVIDENCE["kuwinyu"]),
    row(30, "That thigh is there.", "Yinya waba yinyay.", "yinya waba yinyay | that thigh there", "r234_that_body_part_ref_there_waba", ["yinya", "waba", "yinyay"], EVIDENCE["waba"]),
    row(31, "Those love handles are there.", "Bandin yinya yinyay.", "bandin yinya yinyay | love.handles that there", "r234_body_part_that_there_bandin", ["bandin", "yinya", "yinyay"], EVIDENCE["bandin"]),
    row(32, "That chin is there.", "Bari yinya yinyay.", "bari yinya yinyay | chin that there", "r234_body_part_that_there_bari", ["bari", "yinya", "yinyay"], EVIDENCE["bari"]),
    row(33, "That shin is there.", "Bibar yinya yinyay.", "bibar yinya yinyay | shin that there", "r234_body_part_that_there_bibar", ["bibar", "yinya", "yinyay"], EVIDENCE["bibar"]),
    row(34, "That fingernail is there.", "Birri yinya yinyay.", "birri yinya yinyay | fingernail that there", "r234_body_part_that_there_birri", ["birri", "yinya", "yinyay"], EVIDENCE["birri"]),
    row(35, "That liver is there.", "Jiba yinya yinyay.", "jiba yinya yinyay | liver that there", "r234_body_part_that_there_jiba", ["jiba", "yinya", "yinyay"], EVIDENCE["jiba"]),
    row(36, "That leg is there.", "Jandal yinya yinyay.", "jandal yinya yinyay | leg that there", "r234_body_part_that_there_jandal", ["jandal", "yinya", "yinyay"], EVIDENCE["jandal"]),
    row(37, "That stomach is there.", "Jibar yinya yinyay.", "jibar yinya yinyay | stomach that there", "r234_body_part_that_there_jibar", ["jibar", "yinya", "yinyay"], EVIDENCE["jibar"]),
    row(38, "That cheek is there.", "Kangkul yinya yinyay.", "kangkul yinya yinyay | cheek that there", "r234_body_part_that_there_kangkul", ["kangkul", "yinya", "yinyay"], EVIDENCE["kangkul"]),
    row(39, "That posterior is there.", "Kuwinyu yinya yinyay.", "kuwinyu yinya yinyay | posterior that there", "r234_body_part_that_there_kuwinyu", ["kuwinyu", "yinya", "yinyay"], EVIDENCE["kuwinyu"]),
    row(40, "That thigh is there.", "Waba yinya yinyay.", "waba yinya yinyay | thigh that there", "r234_body_part_that_there_waba", ["waba", "yinya", "yinyay"], EVIDENCE["waba"]),
    row(41, "Those love handles are here.", "Yinya bandin yaluy.", "yinya bandin yaluy | those love.handles here", "r234_that_body_part_ref_here_bandin", ["yinya", "bandin", "yaluy"], EVIDENCE["bandin"]),
    row(42, "That chin is here.", "Yinya bari yaluy.", "yinya bari yaluy | that chin here", "r234_that_body_part_ref_here_bari", ["yinya", "bari", "yaluy"], EVIDENCE["bari"]),
    row(43, "That shin is here.", "Yinya bibar yaluy.", "yinya bibar yaluy | that shin here", "r234_that_body_part_ref_here_bibar", ["yinya", "bibar", "yaluy"], EVIDENCE["bibar"]),
    row(44, "That fingernail is here.", "Yinya birri yaluy.", "yinya birri yaluy | that fingernail here", "r234_that_body_part_ref_here_birri", ["yinya", "birri", "yaluy"], EVIDENCE["birri"]),
    row(45, "That liver is here.", "Yinya jiba yaluy.", "yinya jiba yaluy | that liver here", "r234_that_body_part_ref_here_jiba", ["yinya", "jiba", "yaluy"], EVIDENCE["jiba"]),
    row(46, "That leg is here.", "Yinya jandal yaluy.", "yinya jandal yaluy | that leg here", "r234_that_body_part_ref_here_jandal", ["yinya", "jandal", "yaluy"], EVIDENCE["jandal"]),
    row(47, "That stomach is here.", "Yinya jibar yaluy.", "yinya jibar yaluy | that stomach here", "r234_that_body_part_ref_here_jibar", ["yinya", "jibar", "yaluy"], EVIDENCE["jibar"]),
    row(48, "That cheek is here.", "Yinya kangkul yaluy.", "yinya kangkul yaluy | that cheek here", "r234_that_body_part_ref_here_kangkul", ["yinya", "kangkul", "yaluy"], EVIDENCE["kangkul"]),
    row(49, "That posterior is here.", "Yinya kuwinyu yaluy.", "yinya kuwinyu yaluy | that posterior here", "r234_that_body_part_ref_here_kuwinyu", ["yinya", "kuwinyu", "yaluy"], EVIDENCE["kuwinyu"]),
    row(50, "That thigh is here.", "Yinya waba yaluy.", "yinya waba yaluy | that thigh here", "r234_that_body_part_ref_here_waba", ["yinya", "waba", "yaluy"], EVIDENCE["waba"]),
]


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|karra|manda|bulal"
    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("r234_"):
            issues.append(f"{label}: Rule 234 frame must start with r234_")
        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 234")
        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 234 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")
            if head in PLURAL_TARGETS and not ("love handles" in english_low and "love.handles" in analysis):
                issues.append(f"{label}: plural lexical target {head} must stay lexical/contextual, not morphological")
        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 possession/body-state/medical/ritual/animal/event 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,))
    else:
        db.execute(
            "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
            (LABEL, "Rule 234 draft", "operator-guide-2026-07-09", "draft under review", NOW),
        )
        batch_id = db.execute("SELECT id FROM batches WHERE label=?", (LABEL,)).fetchone()[0]

    collisions: list[str] = []
    for seq, _english, kuku, *_rest in ROWS:
        found = db.execute(
            """
            SELECT b.label, s.seq, s.status
            FROM sentences s JOIN batches b ON b.id=s.batch_id
            WHERE lower(s.kuku)=lower(?) AND s.status IN ('accepted','revised','under_review')
            """,
            (kuku,),
        ).fetchall()
        if found:
            collisions.append(f"{seq:02d} {kuku}: {found}")
    if collisions:
        raise SystemExit("duplicate preflight failed:\n" + "\n".join(collisions))

    record_event(
        db,
        batch_label=LABEL,
        phase="source",
        event_type="source-pass",
        actor="claude-main",
        detail="Checked Patz section 3.1 nominal semantic content for body-part nouns, Patz section 3.7 yinya/yaluy/yinyay demonstrative support, and dictionary entries for the ten Rule 234 body-part heads: bandin, bari, bibar, birri, jiba, jandal, jibar, kangkul, kuwinyu, and waba.",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="scope",
        event_type="lexical-scope",
        actor="claude-main",
        detail="Rule 234 admits a third body-part lexical field in bare deictic reference frames only. It excludes Rule 217/226 exact target repeats, earlier common body-part exact-target repeats, ritual/witchcraft/initiation, body-fluid/medical/sickness, animal-only, dialect-only, homograph-heavy, possession, body-state, movement/use/event, target case, target compounds, productive reduplication, support inflection, and all Rule 233 landform drift.",
        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 234 Kuku surfaces returned no accepted, revised, or under-review collisions.",
        command="bank_276.py lower(kuku) collision scan for 50 planned surfaces",
        output_excerpt="collisions=0",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="preflight",
        event_type="static-guard-pass",
        actor="claude-main",
        detail="bank_276.py static guards passed: 50 explicit hand-authored rows, exactly one Rule 234 body-part target noun per row, no loans, no target morphology, no denied earlier body-part or rejected candidate token, no possession/body-state/medical/ritual/animal/event English, three bare support heads, and five deictic frame bands.",
        artifact_path="batch_scripts/bank_276.py",
        created_at=NOW,
    )

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

    n = db.execute("SELECT COUNT(*) FROM sentences WHERE batch_id=? AND status='under_review'", (batch_id,)).fetchone()[0]
    print(f"banked {LABEL}: {n} under_review rows")
    return 0


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