#!/usr/bin/env python3
"""Bank batch-229: Rule 187 clothing/adornment reference lexical expansion after Rule 186."""

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-229"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-229-clothing-adornment-reference-lexical-expansion-after-rule186-process.md"

TARGET_HEADS = {
    "dawarr": "straw hat",
    "kayamuku": "felt hat",
    "malnkurr": "headband",
    "mirrimbal": "cockatoo crest",
    "wayarri": "hair belt",
    "dambal": "shoes",
    "jilngarr": "seashell headband",
    "julkun": "bark belt",
    "bilangkurr": "blanket",
    "wandu": "hat",
}
PRONOUN_A = {"ngayu", "yundu", "jana", "ngana"}
DENY_KUKU = {
    "jurruja", "yangkija", "baki", "biyin", "gilaja", "binjin", "julnji", "nyumbirr",
    "dawarr-bungal", "wandu-bungal", "kayamuku-bungal", "mirrimbal-bungal", "julkun-bungal",
    "binda-dijarr", "duli", "jamar", "kabay", "karrangkal", "kuri", "ngamar", "nganyay", "ngidin",
    "warrmba", "warrmba-bungal", "ngunnga", "nyamun", "nurru", "kurrkal",
}
DENY_ENGLISH = (
    "loan", "english", "trousers", "handkerchief", "wear", "wears", "wore", "worn", "wearing",
    "make", "makes", "made", "making", "sew", "sews", "sewing", "tie", "ties", "tying", "cover",
    "covers", "covering", "sleep", "sleeps", "sleeping", "warm", "warming", "own", "owns", "ownership",
    "possess", "possession", "dog", "back of a dog", "body", "body-part", "bird", "feather", "feathers",
    "beeswax", "wax", "ceremony", "ceremonial", "corroboree", "mourning", "death", "dead", "tree",
    "source", "hair source", "shellfish", "beach", "collect", "collecting", "material", "walk", "walking",
    "foot", "feet", "plural", "many", "productive reduplication", "reduplicate", "event",
)


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, 4, js(words), js([]), evidence, "0.84")


ROWS = [
    row(1, "The straw hat is here.", "Dawarr yaluy.", "dawarr yaluy | straw.hat here", "r187_deictic_dawarr_here", ["dawarr", "yaluy"], "Rule 187 admits dawarr as straw hat; no wearing, making, straw-source, or loan row."),
    row(2, "The felt hat is here.", "Kayamuku yaluy.", "kayamuku yaluy | felt.hat here", "r187_deictic_kayamuku_here", ["kayamuku", "yaluy"], "Rule 187 admits kayamuku as felt hat; dog/back literal source closed."),
    row(3, "The headband is here.", "Malnkurr yaluy.", "malnkurr yaluy | headband here", "r187_deictic_malnkurr_here", ["malnkurr", "yaluy"], "Rule 187 admits malnkurr as headband; no wearing/body-part/making row."),
    row(4, "The cockatoo crest is here.", "Mirrimbal yaluy.", "mirrimbal yaluy | cockatoo.crest here", "r187_deictic_mirrimbal_here", ["mirrimbal", "yaluy"], "Rule 187 admits mirrimbal as cockatoo crest; feather/wax/ceremony rows closed."),
    row(5, "The hair belt is here.", "Wayarri yaluy.", "wayarri yaluy | hair.belt here", "r187_deictic_wayarri_here", ["wayarri", "yaluy"], "Rule 187 admits wayarri as hair belt; no body-part hair or wearing row."),
    row(6, "The shoes are here.", "Dambal yaluy.", "dambal yaluy | shoes here", "r187_deictic_dambal_here", ["dambal", "yaluy"], "Rule 187 admits dambal as shoes; no walking or foot/body-part row."),
    row(7, "The seashell headband is here.", "Jilngarr yaluy.", "jilngarr yaluy | seashell.headband here", "r187_deictic_jilngarr_here", ["jilngarr", "yaluy"], "Rule 187 admits jilngarr as seashell headband; shellfish/beach/collecting rows closed."),
    row(8, "The bark belt is here.", "Julkun yaluy.", "julkun yaluy | bark.belt here", "r187_deictic_julkun_here", ["julkun", "yaluy"], "Rule 187 admits julkun as bark belt; mourning/death/tree/material-source rows closed."),
    row(9, "The blanket is here.", "Bilangkurr yaluy.", "bilangkurr yaluy | blanket here", "r187_deictic_bilangkurr_here", ["bilangkurr", "yaluy"], "Rule 187 admits bilangkurr as blanket; no sleeping, covering, warming, or ownership row."),
    row(10, "The hat is here.", "Wandu yaluy.", "wandu yaluy | hat here", "r187_deictic_wandu_here", ["wandu", "yaluy"], "Rule 187 admits wandu as hat; no wearing/making/body-part row."),
    row(11, "I see the straw hat.", "Ngayu dawarr nyajil.", "ngayu dawarr nyaji-l | I straw.hat see-NONPAST", "r187_present_i_dawarr", ["ngayu", "dawarr", "nyaji-l"], "First-person present perception; target clothing head bare."),
    row(12, "I see the felt hat.", "Ngayu kayamuku nyajil.", "ngayu kayamuku nyaji-l | I felt.hat see-NONPAST", "r187_present_i_kayamuku", ["ngayu", "kayamuku", "nyaji-l"], "First-person present perception; dog/back literal source closed."),
    row(13, "I see the headband.", "Ngayu malnkurr nyajil.", "ngayu malnkurr nyaji-l | I headband see-NONPAST", "r187_present_i_malnkurr", ["ngayu", "malnkurr", "nyaji-l"], "First-person present perception; no wearing/body-part row."),
    row(14, "I see the cockatoo crest.", "Ngayu mirrimbal nyajil.", "ngayu mirrimbal nyaji-l | I cockatoo.crest see-NONPAST", "r187_present_i_mirrimbal", ["ngayu", "mirrimbal", "nyaji-l"], "First-person present perception; feather/wax/ceremony rows closed."),
    row(15, "I see the hair belt.", "Ngayu wayarri nyajil.", "ngayu wayarri nyaji-l | I hair.belt see-NONPAST", "r187_present_i_wayarri", ["ngayu", "wayarri", "nyaji-l"], "First-person present perception; no body-part hair row."),
    row(16, "I see the shoes.", "Ngayu dambal nyajil.", "ngayu dambal nyaji-l | I shoes see-NONPAST", "r187_present_i_dambal", ["ngayu", "dambal", "nyaji-l"], "First-person present perception; no walking/foot row."),
    row(17, "I see the seashell headband.", "Ngayu jilngarr nyajil.", "ngayu jilngarr nyaji-l | I seashell.headband see-NONPAST", "r187_present_i_jilngarr", ["ngayu", "jilngarr", "nyaji-l"], "First-person present perception; no shellfish/beach/collecting row."),
    row(18, "I see the bark belt.", "Ngayu julkun nyajil.", "ngayu julkun nyaji-l | I bark.belt see-NONPAST", "r187_present_i_julkun", ["ngayu", "julkun", "nyaji-l"], "First-person present perception; no mourning/death/tree/source row."),
    row(19, "I see the blanket.", "Ngayu bilangkurr nyajil.", "ngayu bilangkurr nyaji-l | I blanket see-NONPAST", "r187_present_i_bilangkurr", ["ngayu", "bilangkurr", "nyaji-l"], "First-person present perception; no sleeping/covering row."),
    row(20, "I see the hat.", "Ngayu wandu nyajil.", "ngayu wandu nyaji-l | I hat see-NONPAST", "r187_present_i_wandu", ["ngayu", "wandu", "nyaji-l"], "First-person present perception; no wearing/making row."),
    row(21, "You see the straw hat there.", "Yundu dawarr yinyay nyajil.", "yundu dawarr yinyay nyaji-l | you straw.hat there see-NONPAST", "r187_present_you_dawarr_there", ["yundu", "dawarr", "yinyay", "nyaji-l"], "Second-person present perception with yinyay support."),
    row(22, "You see the felt hat there.", "Yundu kayamuku yinyay nyajil.", "yundu kayamuku yinyay nyaji-l | you felt.hat there see-NONPAST", "r187_present_you_kayamuku_there", ["yundu", "kayamuku", "yinyay", "nyaji-l"], "Second-person present perception; dog/back literal source closed."),
    row(23, "You see the headband there.", "Yundu malnkurr yinyay nyajil.", "yundu malnkurr yinyay nyaji-l | you headband there see-NONPAST", "r187_present_you_malnkurr_there", ["yundu", "malnkurr", "yinyay", "nyaji-l"], "Second-person present perception; no wearing/body-part row."),
    row(24, "You see the cockatoo crest there.", "Yundu mirrimbal yinyay nyajil.", "yundu mirrimbal yinyay nyaji-l | you cockatoo.crest there see-NONPAST", "r187_present_you_mirrimbal_there", ["yundu", "mirrimbal", "yinyay", "nyaji-l"], "Second-person present perception; feather/wax/ceremony rows closed."),
    row(25, "You see the hair belt there.", "Yundu wayarri yinyay nyajil.", "yundu wayarri yinyay nyaji-l | you hair.belt there see-NONPAST", "r187_present_you_wayarri_there", ["yundu", "wayarri", "yinyay", "nyaji-l"], "Second-person present perception; no body-part hair row."),
    row(26, "You see the shoes there.", "Yundu dambal yinyay nyajil.", "yundu dambal yinyay nyaji-l | you shoes there see-NONPAST", "r187_present_you_dambal_there", ["yundu", "dambal", "yinyay", "nyaji-l"], "Second-person present perception; no walking/foot row."),
    row(27, "You see the seashell headband there.", "Yundu jilngarr yinyay nyajil.", "yundu jilngarr yinyay nyaji-l | you seashell.headband there see-NONPAST", "r187_present_you_jilngarr_there", ["yundu", "jilngarr", "yinyay", "nyaji-l"], "Second-person present perception; no shellfish/beach/collecting row."),
    row(28, "You see the bark belt there.", "Yundu julkun yinyay nyajil.", "yundu julkun yinyay nyaji-l | you bark.belt there see-NONPAST", "r187_present_you_julkun_there", ["yundu", "julkun", "yinyay", "nyaji-l"], "Second-person present perception; no mourning/death/tree/source row."),
    row(29, "You see the blanket there.", "Yundu bilangkurr yinyay nyajil.", "yundu bilangkurr yinyay nyaji-l | you blanket there see-NONPAST", "r187_present_you_bilangkurr_there", ["yundu", "bilangkurr", "yinyay", "nyaji-l"], "Second-person present perception; no sleeping/covering row."),
    row(30, "You see the hat there.", "Yundu wandu yinyay nyajil.", "yundu wandu yinyay nyaji-l | you hat there see-NONPAST", "r187_present_you_wandu_there", ["yundu", "wandu", "yinyay", "nyaji-l"], "Second-person present perception; no wearing/making row."),
    row(31, "They saw the straw hat there.", "Jana dawarr yinyay nyajin.", "jana dawarr yinyay nyaji-ny | they straw.hat there see-PAST", "r187_past_they_dawarr_there", ["jana", "dawarr", "yinyay", "nyaji-l"], "Third-person plural past perception with yinyay support."),
    row(32, "They saw the felt hat there.", "Jana kayamuku yinyay nyajin.", "jana kayamuku yinyay nyaji-ny | they felt.hat there see-PAST", "r187_past_they_kayamuku_there", ["jana", "kayamuku", "yinyay", "nyaji-l"], "Third-person plural past perception; dog/back literal source closed."),
    row(33, "They saw the headband there.", "Jana malnkurr yinyay nyajin.", "jana malnkurr yinyay nyaji-ny | they headband there see-PAST", "r187_past_they_malnkurr_there", ["jana", "malnkurr", "yinyay", "nyaji-l"], "Third-person plural past perception; no wearing/body-part row."),
    row(34, "They saw the cockatoo crest there.", "Jana mirrimbal yinyay nyajin.", "jana mirrimbal yinyay nyaji-ny | they cockatoo.crest there see-PAST", "r187_past_they_mirrimbal_there", ["jana", "mirrimbal", "yinyay", "nyaji-l"], "Third-person plural past perception; feather/wax/ceremony rows closed."),
    row(35, "They saw the hair belt there.", "Jana wayarri yinyay nyajin.", "jana wayarri yinyay nyaji-ny | they hair.belt there see-PAST", "r187_past_they_wayarri_there", ["jana", "wayarri", "yinyay", "nyaji-l"], "Third-person plural past perception; no body-part hair row."),
    row(36, "They saw the shoes there.", "Jana dambal yinyay nyajin.", "jana dambal yinyay nyaji-ny | they shoes there see-PAST", "r187_past_they_dambal_there", ["jana", "dambal", "yinyay", "nyaji-l"], "Third-person plural past perception; no walking/foot row."),
    row(37, "They saw the seashell headband there.", "Jana jilngarr yinyay nyajin.", "jana jilngarr yinyay nyaji-ny | they seashell.headband there see-PAST", "r187_past_they_jilngarr_there", ["jana", "jilngarr", "yinyay", "nyaji-l"], "Third-person plural past perception; no shellfish/beach/collecting row."),
    row(38, "They saw the bark belt there.", "Jana julkun yinyay nyajin.", "jana julkun yinyay nyaji-ny | they bark.belt there see-PAST", "r187_past_they_julkun_there", ["jana", "julkun", "yinyay", "nyaji-l"], "Third-person plural past perception; no mourning/death/tree/source row."),
    row(39, "They saw the blanket there.", "Jana bilangkurr yinyay nyajin.", "jana bilangkurr yinyay nyaji-ny | they blanket there see-PAST", "r187_past_they_bilangkurr_there", ["jana", "bilangkurr", "yinyay", "nyaji-l"], "Third-person plural past perception; no sleeping/covering row."),
    row(40, "They saw the hat there.", "Jana wandu yinyay nyajin.", "jana wandu yinyay nyaji-ny | they hat there see-PAST", "r187_past_they_wandu_there", ["jana", "wandu", "yinyay", "nyaji-l"], "Third-person plural past perception; no wearing/making row."),
    row(41, "We see the straw hat here.", "Ngana dawarr yaluy nyajil.", "ngana dawarr yaluy nyaji-l | we straw.hat here see-NONPAST", "r187_present_we_dawarr_here", ["ngana", "dawarr", "yaluy", "nyaji-l"], "Inclusive present perception with yaluy support."),
    row(42, "We see the felt hat here.", "Ngana kayamuku yaluy nyajil.", "ngana kayamuku yaluy nyaji-l | we felt.hat here see-NONPAST", "r187_present_we_kayamuku_here", ["ngana", "kayamuku", "yaluy", "nyaji-l"], "Inclusive present perception; dog/back literal source closed."),
    row(43, "We see the headband here.", "Ngana malnkurr yaluy nyajil.", "ngana malnkurr yaluy nyaji-l | we headband here see-NONPAST", "r187_present_we_malnkurr_here", ["ngana", "malnkurr", "yaluy", "nyaji-l"], "Inclusive present perception; no wearing/body-part row."),
    row(44, "We see the cockatoo crest here.", "Ngana mirrimbal yaluy nyajil.", "ngana mirrimbal yaluy nyaji-l | we cockatoo.crest here see-NONPAST", "r187_present_we_mirrimbal_here", ["ngana", "mirrimbal", "yaluy", "nyaji-l"], "Inclusive present perception; feather/wax/ceremony rows closed."),
    row(45, "We see the hair belt here.", "Ngana wayarri yaluy nyajil.", "ngana wayarri yaluy nyaji-l | we hair.belt here see-NONPAST", "r187_present_we_wayarri_here", ["ngana", "wayarri", "yaluy", "nyaji-l"], "Inclusive present perception; no body-part hair row."),
    row(46, "We see the shoes here.", "Ngana dambal yaluy nyajil.", "ngana dambal yaluy nyaji-l | we shoes here see-NONPAST", "r187_present_we_dambal_here", ["ngana", "dambal", "yaluy", "nyaji-l"], "Inclusive present perception; no walking/foot row."),
    row(47, "We see the seashell headband here.", "Ngana jilngarr yaluy nyajil.", "ngana jilngarr yaluy nyaji-l | we seashell.headband here see-NONPAST", "r187_present_we_jilngarr_here", ["ngana", "jilngarr", "yaluy", "nyaji-l"], "Inclusive present perception; no shellfish/beach/collecting row."),
    row(48, "We see the bark belt here.", "Ngana julkun yaluy nyajil.", "ngana julkun yaluy nyaji-l | we bark.belt here see-NONPAST", "r187_present_we_julkun_here", ["ngana", "julkun", "yaluy", "nyaji-l"], "Inclusive present perception; no mourning/death/tree/source row."),
    row(49, "We see the blanket here.", "Ngana bilangkurr yaluy nyajil.", "ngana bilangkurr yaluy nyaji-l | we blanket here see-NONPAST", "r187_present_we_bilangkurr_here", ["ngana", "bilangkurr", "yaluy", "nyaji-l"], "Inclusive present perception; no sleeping/covering row."),
    row(50, "We see the hat here.", "Ngana wandu yaluy nyajil.", "ngana wandu yaluy nyaji-l | we hat here see-NONPAST", "r187_present_we_wandu_here", ["ngana", "wandu", "yaluy", "nyaji-l"], "Inclusive present perception; no wearing/making row."),
]


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


def first_word(low: str) -> str:
    return low.split()[0].strip(".,!?;:\"")


def has_target_case(low: str, head: str) -> bool:
    return re.search(rf"(?<![a-z-]){re.escape(head)}-(?: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)\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)}\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("r187_"):
            issues.append(f"{label}: Rule 187 frame must start with r187_")
        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 187")
        for denied in DENY_KUKU:
            if has_token(low, denied):
                issues.append(f"{label}: denied clothing/loan/old-field 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 187 target head, found {targets}")
        for head in targets:
            selected = TARGET_HEADS[head]
            if head not in words:
                issues.append(f"{label}: target head {head} missing from words_used")
            if selected.replace(" ", ".") not in analysis:
                issues.append(f"{label}: target head {head} must be glossed as {selected}")
            if selected not in english_low:
                issues.append(f"{label}: {head} must be translated with selected sense {selected!r}")
            if has_target_case(low, head):
                issues.append(f"{label}: target head {head} has forbidden case/compound morphology")
        if seq <= 10:
            if "nyajil" in low or "nyajin" in low or "nyaji-l" in words:
                issues.append(f"{label}: deictic rows must not use nyaji-l")
            if not has_token(low, "yaluy") or "yaluy" not in words or "here" not in english_low:
                issues.append(f"{label}: Rule 187 deictic rows require yaluy/here")
        else:
            if ("nyajin" not in low and "nyajil" not in low) or "nyaji-l" not in words:
                issues.append(f"{label}: Rule 187 perception rows must use nyaji-l")
            first = first_word(low)
            if first not in PRONOUN_A:
                issues.append(f"{label}: perception A should be an approved bare pronoun")
            if 11 <= seq <= 20 and first != "ngayu":
                issues.append(f"{label}: rows 11-20 require ngayu")
            if 21 <= seq <= 30 and (first != "yundu" or not has_token(low, "yinyay") or "there" not in english_low):
                issues.append(f"{label}: rows 21-30 require yundu + yinyay/there")
            if 31 <= seq <= 40 and (first != "jana" or not has_token(low, "yinyay") or "saw" not in english_low):
                issues.append(f"{label}: rows 31-40 require jana + yinyay + past saw")
            if 41 <= seq <= 50 and (first != "ngana" or not has_token(low, "yaluy") or "here" not in english_low):
                issues.append(f"{label}: rows 41-50 require ngana + yaluy/here")
            if "nyajin" in low and "see-PAST" not in analysis:
                issues.append(f"{label}: nyajin must be glossed as see-PAST")
            if "nyajil" in low and "see-NONPAST" not in analysis:
                issues.append(f"{label}: nyajil must be glossed as see-NONPAST")
        if any(english_has_denied(english_low, bad) for bad in DENY_ENGLISH):
            issues.append(f"{label}: denied clothing use/material/event/polysemy 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 187 draft: clothing/adornment reference lexical expansion after Rule 186", "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

    record_event(db, batch_label=LABEL, phase="source", event_type="source-pass", actor="claude-main",
                 detail="Rule 187 source pass selected ten low-hit clothing/adornment reference heads: dawarr straw hat, kayamuku felt hat, malnkurr headband, mirrimbal cockatoo crest, wayarri hair belt, dambal shoes, jilngarr seashell headband, julkun bark belt, bilangkurr blanket, and wandu hat. Fresh dictionary readback confirmed selected senses and traps: kayamuku literal dog-back source closed; mirrimbal feather/wax/ceremony prose closed; jilngarr seashell material/collecting closed; julkun bark/hair/mourning prose closed; dambal walking/foot body-part import closed. Rejected jurruja and yangkija because both entries mark English loan words. Patz readback reconfirmed yaluy/yinyay, nyaji-l/nyaji-ny, absolutive bare objects, and bare pronoun A forms.",
                 command="structured dictionary YAML readback; rg grammar readback; sqlite exact token corpus readback",
                 artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="scope", event_type="lexical-scope", actor="claude-main",
                 detail="Rule 187 is a clothing/adornment reference lexical pass for ten bare target heads. It excludes loans, rejected clothing candidates, wearing, making, sewing, tying, covering, sleeping, warming, ownership, possession, dog/back compound, body-part, bird, feather, wax, ceremony, corroboree, mourning, death, tree/bark-source, hair-source, shellfish, beach, collecting, material-source, walking, foot/body-part, target case, target compounds, plural derivation, productive reduplication, and event claims.",
                 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 found 50 planned Kuku surfaces, 50 unique within-batch surfaces, and no exact accepted/revised/under_review cross-corpus duplicates.",
                 command="sqlite exact lower(trim(kuku)) duplicate scan before banking", artifact_path="batch_scripts/bank_229.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="static-guard-pass", actor="claude-main",
                 detail="Static guards passed: all 50 rows have exactly one Rule 187 target, no loans, no denied Kuku tokens, no denied English import fields, no target case/compound morphology, required deictic/perception support, bare pronoun A where applicable, and correct nyajil/nyajin glosses.",
                 command="python3 batch_scripts/bank_229.py internal scan_static()", artifact_path="batch_scripts/bank_229.py", created_at=NOW)

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

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


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