#!/usr/bin/env python3
"""Bank batch-232: Rule 190 construction consolidation after Rule 189."""

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-232"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-232-weapon-implement-reference-construction-consolidation-after-rule189-process.md"

TARGET_HEADS = {
    "birungubay": "paddle",
    "durray": "fighting stick",
    "jinil": "spear barb",
    "kukuni": "big spear",
    "kulbanmuku": "axe",
    "kurajan": "turtle spear point",
    "kuyan": "war spear",
    "mirru": "club",
    "nala-nala": "waddy club",
    "ngurmu": "woomera butt",
}
PRONOUN_A = {"ngayu", "yundu", "jana", "ngana"}
DENY_KUKU = {
    "dikarra", "jindal", "mirrba", "naybu", "balur", "wangal", "kunjuri", "kalka",
    "dama", "daman", "dama-ny", "mumal", "muman", "yaka", "yakal", "yakan",
    "warrbi", "waymbil", "makarr", "yinba", "jarrngkurr", "biyul", "kurrajan",
    "jurruja", "yangkija", "karrkany", "juwal", "marrkin",
}
DENY_ENGLISH = (
    "loan", "english", "place name", "homograph", "rifle", "knife", "boomerang", "shield",
    "throw", "throws", "threw", "thrown", "throwing", "spear with", "speared", "spearing",
    "cut", "cuts", "cutting", "chop", "chops", "chopping", "hit", "hits", "hitting",
    "kill", "kills", "killed", "killing", "hunt", "hunts", "hunting", "catch", "caught",
    "catching", "fish with", "fight with", "fought", "defend", "defence", "defense", "ward",
    "wound", "wounds", "injure", "injury", "blood", "barbed", "barb from", "quartz",
    "stone source", "wood", "wooden", "timber", "wattle", "bamboo source", "material",
    "make", "makes", "made", "making", "ownership", "own", "owns", "possess", "possession",
    "instrumental", "with the", "case", "plural", "many", "productive reduplication", "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 paddle is there.", "Birungubay yinyay.", "birungubay yinyay | paddle there", "r190_deictic_birungubay_there", ["birungubay", "yinyay"], "Rule 190 retains birungubay as paddle/oar and rotates to yinyay deictic support."),
    row(2, "The fighting stick is there.", "Durray yinyay.", "durray yinyay | fighting.stick there", "r190_deictic_durray_there", ["durray", "yinyay"], "Rule 190 retains durray as fighting stick; no fighting/hitting event row."),
    row(3, "The spear barb is there.", "Jinil yinyay.", "jinil yinyay | spear.barb there", "r190_deictic_jinil_there", ["jinil", "yinyay"], "Rule 190 retains jinil as spear barb; no spear-use/material row."),
    row(4, "The big spear is there.", "Kukuni yinyay.", "kukuni yinyay | big.spear there", "r190_deictic_kukuni_there", ["kukuni", "yinyay"], "Rule 190 retains kukuni as big spear; no harpoon-use row."),
    row(5, "The axe is there.", "Kulbanmuku yinyay.", "kulbanmuku yinyay | axe there", "r190_deictic_kulbanmuku_there", ["kulbanmuku", "yinyay"], "Rule 190 retains kulbanmuku as axe; no cutting/chopping row."),
    row(6, "The turtle spear point is there.", "Kurajan yinyay.", "kurajan yinyay | turtle.spear.point there", "r190_deictic_kurajan_there", ["kurajan", "yinyay"], "Rule 190 retains kurajan as turtle spear point; no turtle event row."),
    row(7, "The war spear is there.", "Kuyan yinyay.", "kuyan yinyay | war.spear there", "r190_deictic_kuyan_there", ["kuyan", "yinyay"], "Rule 190 retains kuyan as war spear; no quartz/fighting row."),
    row(8, "The club is there.", "Mirru yinyay.", "mirru yinyay | club there", "r190_deictic_mirru_there", ["mirru", "yinyay"], "Rule 190 retains mirru as club; no striking row."),
    row(9, "The waddy club is there.", "Nala-nala yinyay.", "nala-nala yinyay | waddy.club there", "r190_deictic_nala_nala_there", ["nala-nala", "yinyay"], "Rule 190 retains nala-nala as lexical waddy club; no productive reduplication row."),
    row(10, "The woomera butt is there.", "Ngurmu yinyay.", "ngurmu yinyay | woomera.butt there", "r190_deictic_ngurmu_there", ["ngurmu", "yinyay"], "Rule 190 retains ngurmu as woomera butt; no throwing/defence row."),
    row(11, "I see the paddle here.", "Ngayu birungubay yaluy nyajil.", "ngayu birungubay yaluy nyaji-l | I paddle here see-NONPAST", "r190_present_i_birungubay_here", ["ngayu", "birungubay", "yaluy", "nyaji-l"], "First-person present perception with yaluy support; target remains bare."),
    row(12, "I see the fighting stick here.", "Ngayu durray yaluy nyajil.", "ngayu durray yaluy nyaji-l | I fighting.stick here see-NONPAST", "r190_present_i_durray_here", ["ngayu", "durray", "yaluy", "nyaji-l"], "First-person present perception; no fighting event opened."),
    row(13, "I see the spear barb here.", "Ngayu jinil yaluy nyajil.", "ngayu jinil yaluy nyaji-l | I spear.barb here see-NONPAST", "r190_present_i_jinil_here", ["ngayu", "jinil", "yaluy", "nyaji-l"], "First-person present perception; component remains bare."),
    row(14, "I see the big spear here.", "Ngayu kukuni yaluy nyajil.", "ngayu kukuni yaluy nyaji-l | I big.spear here see-NONPAST", "r190_present_i_kukuni_here", ["ngayu", "kukuni", "yaluy", "nyaji-l"], "First-person present perception; no turtle-spearing row."),
    row(15, "I see the axe here.", "Ngayu kulbanmuku yaluy nyajil.", "ngayu kulbanmuku yaluy nyaji-l | I axe here see-NONPAST", "r190_present_i_kulbanmuku_here", ["ngayu", "kulbanmuku", "yaluy", "nyaji-l"], "First-person present perception; no cutting/material-source row."),
    row(16, "I see the turtle spear point here.", "Ngayu kurajan yaluy nyajil.", "ngayu kurajan yaluy nyaji-l | I turtle.spear.point here see-NONPAST", "r190_present_i_kurajan_here", ["ngayu", "kurajan", "yaluy", "nyaji-l"], "First-person present perception; no turtle event row."),
    row(17, "I see the war spear here.", "Ngayu kuyan yaluy nyajil.", "ngayu kuyan yaluy nyaji-l | I war.spear here see-NONPAST", "r190_present_i_kuyan_here", ["ngayu", "kuyan", "yaluy", "nyaji-l"], "First-person present perception; no throwing/fighting row."),
    row(18, "I see the club here.", "Ngayu mirru yaluy nyajil.", "ngayu mirru yaluy nyaji-l | I club here see-NONPAST", "r190_present_i_mirru_here", ["ngayu", "mirru", "yaluy", "nyaji-l"], "First-person present perception; no striking row."),
    row(19, "I see the waddy club here.", "Ngayu nala-nala yaluy nyajil.", "ngayu nala-nala yaluy nyaji-l | I waddy.club here see-NONPAST", "r190_present_i_nala_nala_here", ["ngayu", "nala-nala", "yaluy", "nyaji-l"], "First-person present perception; lexical reduplication only."),
    row(20, "I see the woomera butt here.", "Ngayu ngurmu yaluy nyajil.", "ngayu ngurmu yaluy nyaji-l | I woomera.butt here see-NONPAST", "r190_present_i_ngurmu_here", ["ngayu", "ngurmu", "yaluy", "nyaji-l"], "First-person present perception; no throwing/defence row."),
    row(21, "You see the paddle here.", "Yundu birungubay yaluy nyajil.", "yundu birungubay yaluy nyaji-l | you paddle here see-NONPAST", "r190_present_you_birungubay_here", ["yundu", "birungubay", "yaluy", "nyaji-l"], "Second-person present perception with yaluy support."),
    row(22, "You see the fighting stick here.", "Yundu durray yaluy nyajil.", "yundu durray yaluy nyaji-l | you fighting.stick here see-NONPAST", "r190_present_you_durray_here", ["yundu", "durray", "yaluy", "nyaji-l"], "Second-person present perception; no fighting event opened."),
    row(23, "You see the spear barb here.", "Yundu jinil yaluy nyajil.", "yundu jinil yaluy nyaji-l | you spear.barb here see-NONPAST", "r190_present_you_jinil_here", ["yundu", "jinil", "yaluy", "nyaji-l"], "Second-person present perception; no spear-use row."),
    row(24, "You see the big spear here.", "Yundu kukuni yaluy nyajil.", "yundu kukuni yaluy nyaji-l | you big.spear here see-NONPAST", "r190_present_you_kukuni_here", ["yundu", "kukuni", "yaluy", "nyaji-l"], "Second-person present perception; no harpoon-use row."),
    row(25, "You see the axe here.", "Yundu kulbanmuku yaluy nyajil.", "yundu kulbanmuku yaluy nyaji-l | you axe here see-NONPAST", "r190_present_you_kulbanmuku_here", ["yundu", "kulbanmuku", "yaluy", "nyaji-l"], "Second-person present perception; no cutting/tool-use row."),
    row(26, "You see the turtle spear point here.", "Yundu kurajan yaluy nyajil.", "yundu kurajan yaluy nyaji-l | you turtle.spear.point here see-NONPAST", "r190_present_you_kurajan_here", ["yundu", "kurajan", "yaluy", "nyaji-l"], "Second-person present perception; no turtle row."),
    row(27, "You see the war spear here.", "Yundu kuyan yaluy nyajil.", "yundu kuyan yaluy nyaji-l | you war.spear here see-NONPAST", "r190_present_you_kuyan_here", ["yundu", "kuyan", "yaluy", "nyaji-l"], "Second-person present perception; quartz/source prose closed."),
    row(28, "You see the club here.", "Yundu mirru yaluy nyajil.", "yundu mirru yaluy nyaji-l | you club here see-NONPAST", "r190_present_you_mirru_here", ["yundu", "mirru", "yaluy", "nyaji-l"], "Second-person present perception; no striking row."),
    row(29, "You see the waddy club here.", "Yundu nala-nala yaluy nyajil.", "yundu nala-nala yaluy nyaji-l | you waddy.club here see-NONPAST", "r190_present_you_nala_nala_here", ["yundu", "nala-nala", "yaluy", "nyaji-l"], "Second-person present perception; lexical reduplication only."),
    row(30, "You see the woomera butt here.", "Yundu ngurmu yaluy nyajil.", "yundu ngurmu yaluy nyaji-l | you woomera.butt here see-NONPAST", "r190_present_you_ngurmu_here", ["yundu", "ngurmu", "yaluy", "nyaji-l"], "Second-person present perception; no throwing/defence row."),
    row(31, "They saw the paddle here.", "Jana birungubay yaluy nyajin.", "jana birungubay yaluy nyaji-ny | they paddle here see-PAST", "r190_past_they_birungubay_here", ["jana", "birungubay", "yaluy", "nyaji-l"], "Third-person plural past perception with yaluy support."),
    row(32, "They saw the fighting stick here.", "Jana durray yaluy nyajin.", "jana durray yaluy nyaji-ny | they fighting.stick here see-PAST", "r190_past_they_durray_here", ["jana", "durray", "yaluy", "nyaji-l"], "Third-person plural past perception; no fighting event opened."),
    row(33, "They saw the spear barb here.", "Jana jinil yaluy nyajin.", "jana jinil yaluy nyaji-ny | they spear.barb here see-PAST", "r190_past_they_jinil_here", ["jana", "jinil", "yaluy", "nyaji-l"], "Third-person plural past perception; component remains bare."),
    row(34, "They saw the big spear here.", "Jana kukuni yaluy nyajin.", "jana kukuni yaluy nyaji-ny | they big.spear here see-PAST", "r190_past_they_kukuni_here", ["jana", "kukuni", "yaluy", "nyaji-l"], "Third-person plural past perception; no spearing event opened."),
    row(35, "They saw the axe here.", "Jana kulbanmuku yaluy nyajin.", "jana kulbanmuku yaluy nyaji-ny | they axe here see-PAST", "r190_past_they_kulbanmuku_here", ["jana", "kulbanmuku", "yaluy", "nyaji-l"], "Third-person plural past perception; no chopping/cutting row."),
    row(36, "They saw the turtle spear point here.", "Jana kurajan yaluy nyajin.", "jana kurajan yaluy nyaji-ny | they turtle.spear.point here see-PAST", "r190_past_they_kurajan_here", ["jana", "kurajan", "yaluy", "nyaji-l"], "Third-person plural past perception; no turtle event row."),
    row(37, "They saw the war spear here.", "Jana kuyan yaluy nyajin.", "jana kuyan yaluy nyaji-ny | they war.spear here see-PAST", "r190_past_they_kuyan_here", ["jana", "kuyan", "yaluy", "nyaji-l"], "Third-person plural past perception; no quartz/source row."),
    row(38, "They saw the club here.", "Jana mirru yaluy nyajin.", "jana mirru yaluy nyaji-ny | they club here see-PAST", "r190_past_they_mirru_here", ["jana", "mirru", "yaluy", "nyaji-l"], "Third-person plural past perception; no striking row."),
    row(39, "They saw the waddy club here.", "Jana nala-nala yaluy nyajin.", "jana nala-nala yaluy nyaji-ny | they waddy.club here see-PAST", "r190_past_they_nala_nala_here", ["jana", "nala-nala", "yaluy", "nyaji-l"], "Third-person plural past perception; no weapon-use row."),
    row(40, "They saw the woomera butt here.", "Jana ngurmu yaluy nyajin.", "jana ngurmu yaluy nyaji-ny | they woomera.butt here see-PAST", "r190_past_they_ngurmu_here", ["jana", "ngurmu", "yaluy", "nyaji-l"], "Third-person plural past perception; no throwing/defence row."),
    row(41, "We see the paddle there.", "Ngana birungubay yinyay nyajil.", "ngana birungubay yinyay nyaji-l | we paddle there see-NONPAST", "r190_present_we_birungubay_there", ["ngana", "birungubay", "yinyay", "nyaji-l"], "Inclusive present perception with yinyay support."),
    row(42, "We see the fighting stick there.", "Ngana durray yinyay nyajil.", "ngana durray yinyay nyaji-l | we fighting.stick there see-NONPAST", "r190_present_we_durray_there", ["ngana", "durray", "yinyay", "nyaji-l"], "Inclusive present perception; no fighting event opened."),
    row(43, "We see the spear barb there.", "Ngana jinil yinyay nyajil.", "ngana jinil yinyay nyaji-l | we spear.barb there see-NONPAST", "r190_present_we_jinil_there", ["ngana", "jinil", "yinyay", "nyaji-l"], "Inclusive present perception; component remains bare."),
    row(44, "We see the big spear there.", "Ngana kukuni yinyay nyajil.", "ngana kukuni yinyay nyaji-l | we big.spear there see-NONPAST", "r190_present_we_kukuni_there", ["ngana", "kukuni", "yinyay", "nyaji-l"], "Inclusive present perception; no harpoon-use row."),
    row(45, "We see the axe there.", "Ngana kulbanmuku yinyay nyajil.", "ngana kulbanmuku yinyay nyaji-l | we axe there see-NONPAST", "r190_present_we_kulbanmuku_there", ["ngana", "kulbanmuku", "yinyay", "nyaji-l"], "Inclusive present perception; no cutting/tool-use row."),
    row(46, "We see the turtle spear point there.", "Ngana kurajan yinyay nyajil.", "ngana kurajan yinyay nyaji-l | we turtle.spear.point there see-NONPAST", "r190_present_we_kurajan_there", ["ngana", "kurajan", "yinyay", "nyaji-l"], "Inclusive present perception; no turtle event opened."),
    row(47, "We see the war spear there.", "Ngana kuyan yinyay nyajil.", "ngana kuyan yinyay nyaji-l | we war.spear there see-NONPAST", "r190_present_we_kuyan_there", ["ngana", "kuyan", "yinyay", "nyaji-l"], "Inclusive present perception; no fighting/throwing row."),
    row(48, "We see the club there.", "Ngana mirru yinyay nyajil.", "ngana mirru yinyay nyaji-l | we club there see-NONPAST", "r190_present_we_mirru_there", ["ngana", "mirru", "yinyay", "nyaji-l"], "Inclusive present perception; club remains bare."),
    row(49, "We see the waddy club there.", "Ngana nala-nala yinyay nyajil.", "ngana nala-nala yinyay nyaji-l | we waddy.club there see-NONPAST", "r190_present_we_nala_nala_there", ["ngana", "nala-nala", "yinyay", "nyaji-l"], "Inclusive present perception; lexical reduplication only."),
    row(50, "We see the woomera butt there.", "Ngana ngurmu yinyay nyajil.", "ngana ngurmu yinyay nyaji-l | we woomera.butt there see-NONPAST", "r190_present_we_ngurmu_there", ["ngana", "ngurmu", "yinyay", "nyaji-l"], "Inclusive present perception; no throwing/defence 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("r190_"):
            issues.append(f"{label}: Rule 190 frame must start with r190_")
        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 190")
        for denied in DENY_KUKU:
            if has_token(low, denied):
                issues.append(f"{label}: denied weapon/use/loan/homograph 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 retained Rule 189 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, "yinyay") or "yinyay" not in words or "there" not in english_low:
                issues.append(f"{label}: Rule 190 deictic rows require yinyay/there")
        else:
            if ("nyajin" not in low and "nyajil" not in low) or "nyaji-l" not in words:
                issues.append(f"{label}: Rule 190 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" or not has_token(low, "yaluy") or "here" not in english_low):
                issues.append(f"{label}: rows 11-20 require ngayu + yaluy/here")
            if 21 <= seq <= 30 and (first != "yundu" or not has_token(low, "yaluy") or "here" not in english_low):
                issues.append(f"{label}: rows 21-30 require yundu + yaluy/here")
            if 31 <= seq <= 40 and (first != "jana" or not has_token(low, "yaluy") or "saw" not in english_low):
                issues.append(f"{label}: rows 31-40 require jana + yaluy + past saw")
            if 41 <= seq <= 50 and (first != "ngana" or not has_token(low, "yinyay") or "there" not in english_low):
                issues.append(f"{label}: rows 41-50 require ngana + yinyay/there")
            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 weapon-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 190 draft: construction consolidation after Rule 189", "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 190 source pass retained exactly the ten Rule 189 weapon/implement reference heads: birungubay paddle/oar, durray fighting stick, jinil spear barb, kukuni big spear, kulbanmuku axe, kurajan turtle spear point, kuyan war spear, mirru club, nala-nala waddy club, and ngurmu decorated butt of woomera. Fresh dictionary readback reconfirmed selected senses and traps. Grammar grep found no target-specific construction license beyond established yaluy/yinyay, nyaji-l/nyaji-ny, bare absolutive objects, and bare pronoun A forms. Rejected candidates dikarra, jindal, mirrba, naybu, kalka, balur, wangal, kunjuri, makarr, biyul, and kurrajan stay closed.",
                 command="dictionary YAML readback; Patz grammar readback; sqlite corpus readback",
                 artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="scope", event_type="construction-scope", actor="claude-main",
                 detail="Rule 190 is a weapon/implement construction consolidation pass for the Rule 189 field. It admits no new target heads and excludes throwing, spearing, cutting, chopping, hitting, killing, hunting, catching, fighting, defending, wounding, injury, use, making, stone-source, quartz-source, wattle-source, bamboo-source, timber-source, material-source, instrumental/comitative/possessive/case morphology, loan import, place-name homograph, body-part/euphemism drift, 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_232.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 retained Rule 189 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_232.py internal scan_static()", artifact_path="batch_scripts/bank_232.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())
