#!/usr/bin/env python3
"""Bank batch-226: Rule 184 object reference construction consolidation after Rule 183."""

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

TARGET_HEADS = {
    "dibarr": "teapot",
    "jakway": "door",
    "juljal": "grave",
    "jurungurr": "spoon",
    "kadirangkal": "clay pipe",
    "mararr": "cloth",
    "mayal": "bottle",
    "wararra": "empty box",
    "yulal": "board",
    "yiki-yiki": "didgeridoo",
}
PRONOUN_A = {"ngayu", "yundu", "jana", "ngana"}
DENY_KUKU = {
    "biyin", "gilaja", "binjin", "julnji", "nyumbirr", "baki", "baybu", "bijikan", "budmandu", "bulin",
    "dakilji", "dingkil-dingkil", "dubal", "duburan", "jamu", "jungkalu", "kaban", "kaljan", "kararr",
    "karra", "kilaja", "kulu", "kurmun", "makarra", "makirr", "marrakan", "mudaka", "murbuy",
    "ngunyin", "ngurran", "warkal", "wuba", "yamba-yamba", "yanday", "yinkar",
    "nuka", "nukan", "waju", "wajun", "mani", "manin", "daji", "dajin", "balkan", "balka",
    "dungan", "dunga", "wandi", "wandin", "yirrka", "burri", "yirrbay", "yirrbal", "wawu-juljal",
}
DENY_ENGLISH = (
    "front", "tea", "drink", "drinks", "drinking", "eat", "eats", "eating", "food", "use", "uses", "used",
    "using", "make", "makes", "made", "making", "old time", "old-time", "smoke", "smokes", "smoking",
    "tobacco", "fill", "fills", "filled", "filling", "carry", "carries", "carried", "carrying", "store",
    "stores", "stored", "storage", "open", "opens", "opened", "close", "closes", "closed", "sail",
    "plaited", "palm", "leaf", "leaves", "plank", "round stick", "stick", "play", "plays", "played",
    "playing", "music", "song", "sound", "corroboree", "instrument", "burial", "bury", "buried",
    "mourning", "death", "dead", "story", "material", "source", "manufacture", "origin", "possess",
    "possession", "plural", "many", "productive reduplication", "reduplicate", "loan", "petrol", "fuel",
    "pin", "glass", "mirror", "tar", "wax", "bee", "bees",
)


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 teapot is there.", "Dibarr yinyay.", "dibarr yinyay | teapot there", "r184_deictic_dibarr_there", ["dibarr", "yinyay"], "Rule 184 retains dibarr as teapot and rotates to yinyay deictic support."),
    row(2, "The door is there.", "Jakway yinyay.", "jakway yinyay | door there", "r184_deictic_jakway_there", ["jakway", "yinyay"], "Rule 184 retains jakway as door; front sense closed."),
    row(3, "The grave is there.", "Juljal yinyay.", "juljal yinyay | grave there", "r184_deictic_juljal_there", ["juljal", "yinyay"], "Rule 184 retains juljal as grave; no burial/death-event row."),
    row(4, "The spoon is there.", "Jurungurr yinyay.", "jurungurr yinyay | spoon there", "r184_deictic_jurungurr_there", ["jurungurr", "yinyay"], "Rule 184 retains jurungurr as spoon; old-time/making/eating prose closed."),
    row(5, "The clay pipe is there.", "Kadirangkal yinyay.", "kadirangkal yinyay | clay.pipe there", "r184_deictic_kadirangkal_there", ["kadirangkal", "yinyay"], "Rule 184 retains kadirangkal as clay pipe; no smoking/use row."),
    row(6, "The cloth is there.", "Mararr yinyay.", "mararr yinyay | cloth there", "r184_deictic_mararr_there", ["mararr", "yinyay"], "Rule 184 retains mararr as cloth; sail/plaited-palm origin closed."),
    row(7, "The bottle is there.", "Mayal yinyay.", "mayal yinyay | bottle there", "r184_deictic_mayal_there", ["mayal", "yinyay"], "Rule 184 retains mayal as bottle; no filling/drinking/carrying row."),
    row(8, "The empty box is there.", "Wararra yinyay.", "wararra yinyay | empty.box there", "r184_deictic_wararra_there", ["wararra", "yinyay"], "Rule 184 retains wararra as empty box; no possession/storage/use row."),
    row(9, "The board is there.", "Yulal yinyay.", "yulal yinyay | board there", "r184_deictic_yulal_there", ["yulal", "yinyay"], "Rule 184 retains yulal as board; plank and stick contrast closed."),
    row(10, "The didgeridoo is there.", "Yiki-yiki yinyay.", "yiki-yiki yinyay | didgeridoo there", "r184_deictic_yiki_yiki_there", ["yiki-yiki", "yinyay"], "Rule 184 retains yiki-yiki as didgeridoo; no music/play/event row."),
    row(11, "I see the teapot here.", "Ngayu dibarr yaluy nyajil.", "ngayu dibarr yaluy nyaji-l | I teapot here see-NONPAST", "r184_present_i_dibarr_here", ["ngayu", "dibarr", "yaluy", "nyaji-l"], "First-person present perception with yaluy support; target object bare."),
    row(12, "I see the door here.", "Ngayu jakway yaluy nyajil.", "ngayu jakway yaluy nyaji-l | I door here see-NONPAST", "r184_present_i_jakway_here", ["ngayu", "jakway", "yaluy", "nyaji-l"], "First-person present perception; front sense closed."),
    row(13, "I see the grave here.", "Ngayu juljal yaluy nyajil.", "ngayu juljal yaluy nyaji-l | I grave here see-NONPAST", "r184_present_i_juljal_here", ["ngayu", "juljal", "yaluy", "nyaji-l"], "First-person present perception; no burial/death-event row."),
    row(14, "I see the spoon here.", "Ngayu jurungurr yaluy nyajil.", "ngayu jurungurr yaluy nyaji-l | I spoon here see-NONPAST", "r184_present_i_jurungurr_here", ["ngayu", "jurungurr", "yaluy", "nyaji-l"], "First-person present perception; no eating/use row."),
    row(15, "I see the clay pipe here.", "Ngayu kadirangkal yaluy nyajil.", "ngayu kadirangkal yaluy nyaji-l | I clay.pipe here see-NONPAST", "r184_present_i_kadirangkal_here", ["ngayu", "kadirangkal", "yaluy", "nyaji-l"], "First-person present perception; no smoking/use row."),
    row(16, "I see the cloth here.", "Ngayu mararr yaluy nyajil.", "ngayu mararr yaluy nyaji-l | I cloth here see-NONPAST", "r184_present_i_mararr_here", ["ngayu", "mararr", "yaluy", "nyaji-l"], "First-person present perception; sail origin closed."),
    row(17, "I see the bottle here.", "Ngayu mayal yaluy nyajil.", "ngayu mayal yaluy nyaji-l | I bottle here see-NONPAST", "r184_present_i_mayal_here", ["ngayu", "mayal", "yaluy", "nyaji-l"], "First-person present perception; no filling/drinking row."),
    row(18, "I see the empty box here.", "Ngayu wararra yaluy nyajil.", "ngayu wararra yaluy nyaji-l | I empty.box here see-NONPAST", "r184_present_i_wararra_here", ["ngayu", "wararra", "yaluy", "nyaji-l"], "First-person present perception; no storage/use row."),
    row(19, "I see the board here.", "Ngayu yulal yaluy nyajil.", "ngayu yulal yaluy nyaji-l | I board here see-NONPAST", "r184_present_i_yulal_here", ["ngayu", "yulal", "yaluy", "nyaji-l"], "First-person present perception; plank/stick contrast closed."),
    row(20, "I see the didgeridoo here.", "Ngayu yiki-yiki yaluy nyajil.", "ngayu yiki-yiki yaluy nyaji-l | I didgeridoo here see-NONPAST", "r184_present_i_yiki_yiki_here", ["ngayu", "yiki-yiki", "yaluy", "nyaji-l"], "First-person present perception; no music/play row."),
    row(21, "You see the teapot here.", "Yundu dibarr yaluy nyajil.", "yundu dibarr yaluy nyaji-l | you teapot here see-NONPAST", "r184_present_you_dibarr_here", ["yundu", "dibarr", "yaluy", "nyaji-l"], "Second-person present perception with yaluy support."),
    row(22, "You see the door here.", "Yundu jakway yaluy nyajil.", "yundu jakway yaluy nyaji-l | you door here see-NONPAST", "r184_present_you_jakway_here", ["yundu", "jakway", "yaluy", "nyaji-l"], "Second-person present perception; front sense closed."),
    row(23, "You see the grave here.", "Yundu juljal yaluy nyajil.", "yundu juljal yaluy nyaji-l | you grave here see-NONPAST", "r184_present_you_juljal_here", ["yundu", "juljal", "yaluy", "nyaji-l"], "Second-person present perception; no burial/death-event row."),
    row(24, "You see the spoon here.", "Yundu jurungurr yaluy nyajil.", "yundu jurungurr yaluy nyaji-l | you spoon here see-NONPAST", "r184_present_you_jurungurr_here", ["yundu", "jurungurr", "yaluy", "nyaji-l"], "Second-person present perception; no eating/use row."),
    row(25, "You see the clay pipe here.", "Yundu kadirangkal yaluy nyajil.", "yundu kadirangkal yaluy nyaji-l | you clay.pipe here see-NONPAST", "r184_present_you_kadirangkal_here", ["yundu", "kadirangkal", "yaluy", "nyaji-l"], "Second-person present perception; no smoking/use row."),
    row(26, "You see the cloth here.", "Yundu mararr yaluy nyajil.", "yundu mararr yaluy nyaji-l | you cloth here see-NONPAST", "r184_present_you_mararr_here", ["yundu", "mararr", "yaluy", "nyaji-l"], "Second-person present perception; target object bare."),
    row(27, "You see the bottle here.", "Yundu mayal yaluy nyajil.", "yundu mayal yaluy nyaji-l | you bottle here see-NONPAST", "r184_present_you_mayal_here", ["yundu", "mayal", "yaluy", "nyaji-l"], "Second-person present perception; no filling/drinking row."),
    row(28, "You see the empty box here.", "Yundu wararra yaluy nyajil.", "yundu wararra yaluy nyaji-l | you empty.box here see-NONPAST", "r184_present_you_wararra_here", ["yundu", "wararra", "yaluy", "nyaji-l"], "Second-person present perception; no storage/use row."),
    row(29, "You see the board here.", "Yundu yulal yaluy nyajil.", "yundu yulal yaluy nyaji-l | you board here see-NONPAST", "r184_present_you_yulal_here", ["yundu", "yulal", "yaluy", "nyaji-l"], "Second-person present perception; board only."),
    row(30, "You see the didgeridoo here.", "Yundu yiki-yiki yaluy nyajil.", "yundu yiki-yiki yaluy nyaji-l | you didgeridoo here see-NONPAST", "r184_present_you_yiki_yiki_here", ["yundu", "yiki-yiki", "yaluy", "nyaji-l"], "Second-person present perception; no play/music row."),
    row(31, "They saw the teapot here.", "Jana dibarr yaluy nyajin.", "jana dibarr yaluy nyaji-ny | they teapot here see-PAST", "r184_past_they_dibarr_here", ["jana", "dibarr", "yaluy", "nyaji-l"], "Third-person plural past perception with yaluy support."),
    row(32, "They saw the door here.", "Jana jakway yaluy nyajin.", "jana jakway yaluy nyaji-ny | they door here see-PAST", "r184_past_they_jakway_here", ["jana", "jakway", "yaluy", "nyaji-l"], "Third-person plural past perception; front sense closed."),
    row(33, "They saw the grave here.", "Jana juljal yaluy nyajin.", "jana juljal yaluy nyaji-ny | they grave here see-PAST", "r184_past_they_juljal_here", ["jana", "juljal", "yaluy", "nyaji-l"], "Third-person plural past perception; no burial/death-event row."),
    row(34, "They saw the spoon here.", "Jana jurungurr yaluy nyajin.", "jana jurungurr yaluy nyaji-ny | they spoon here see-PAST", "r184_past_they_jurungurr_here", ["jana", "jurungurr", "yaluy", "nyaji-l"], "Third-person plural past perception; no eating/use row."),
    row(35, "They saw the clay pipe here.", "Jana kadirangkal yaluy nyajin.", "jana kadirangkal yaluy nyaji-ny | they clay.pipe here see-PAST", "r184_past_they_kadirangkal_here", ["jana", "kadirangkal", "yaluy", "nyaji-l"], "Third-person plural past perception; no smoking/use row."),
    row(36, "They saw the cloth here.", "Jana mararr yaluy nyajin.", "jana mararr yaluy nyaji-ny | they cloth here see-PAST", "r184_past_they_mararr_here", ["jana", "mararr", "yaluy", "nyaji-l"], "Third-person plural past perception; sail origin closed."),
    row(37, "They saw the bottle here.", "Jana mayal yaluy nyajin.", "jana mayal yaluy nyaji-ny | they bottle here see-PAST", "r184_past_they_mayal_here", ["jana", "mayal", "yaluy", "nyaji-l"], "Third-person plural past perception; no filling/drinking row."),
    row(38, "They saw the empty box here.", "Jana wararra yaluy nyajin.", "jana wararra yaluy nyaji-ny | they empty.box here see-PAST", "r184_past_they_wararra_here", ["jana", "wararra", "yaluy", "nyaji-l"], "Third-person plural past perception; no storage/use row."),
    row(39, "They saw the board here.", "Jana yulal yaluy nyajin.", "jana yulal yaluy nyaji-ny | they board here see-PAST", "r184_past_they_yulal_here", ["jana", "yulal", "yaluy", "nyaji-l"], "Third-person plural past perception; board only."),
    row(40, "They saw the didgeridoo here.", "Jana yiki-yiki yaluy nyajin.", "jana yiki-yiki yaluy nyaji-ny | they didgeridoo here see-PAST", "r184_past_they_yiki_yiki_here", ["jana", "yiki-yiki", "yaluy", "nyaji-l"], "Third-person plural past perception; no play/music row."),
    row(41, "We see the teapot there.", "Ngana dibarr yinyay nyajil.", "ngana dibarr yinyay nyaji-l | we teapot there see-NONPAST", "r184_present_we_dibarr_there", ["ngana", "dibarr", "yinyay", "nyaji-l"], "Inclusive present perception with yinyay support."),
    row(42, "We see the door there.", "Ngana jakway yinyay nyajil.", "ngana jakway yinyay nyaji-l | we door there see-NONPAST", "r184_present_we_jakway_there", ["ngana", "jakway", "yinyay", "nyaji-l"], "Inclusive present perception; front sense closed."),
    row(43, "We see the grave there.", "Ngana juljal yinyay nyajil.", "ngana juljal yinyay nyaji-l | we grave there see-NONPAST", "r184_present_we_juljal_there", ["ngana", "juljal", "yinyay", "nyaji-l"], "Inclusive present perception; no burial/death-event row."),
    row(44, "We see the spoon there.", "Ngana jurungurr yinyay nyajil.", "ngana jurungurr yinyay nyaji-l | we spoon there see-NONPAST", "r184_present_we_jurungurr_there", ["ngana", "jurungurr", "yinyay", "nyaji-l"], "Inclusive present perception; no eating/use row."),
    row(45, "We see the clay pipe there.", "Ngana kadirangkal yinyay nyajil.", "ngana kadirangkal yinyay nyaji-l | we clay.pipe there see-NONPAST", "r184_present_we_kadirangkal_there", ["ngana", "kadirangkal", "yinyay", "nyaji-l"], "Inclusive present perception; no smoking/use row."),
    row(46, "We see the cloth there.", "Ngana mararr yinyay nyajil.", "ngana mararr yinyay nyaji-l | we cloth there see-NONPAST", "r184_present_we_mararr_there", ["ngana", "mararr", "yinyay", "nyaji-l"], "Inclusive present perception; target object bare."),
    row(47, "We see the bottle there.", "Ngana mayal yinyay nyajil.", "ngana mayal yinyay nyaji-l | we bottle there see-NONPAST", "r184_present_we_mayal_there", ["ngana", "mayal", "yinyay", "nyaji-l"], "Inclusive present perception; no filling/drinking row."),
    row(48, "We see the empty box there.", "Ngana wararra yinyay nyajil.", "ngana wararra yinyay nyaji-l | we empty.box there see-NONPAST", "r184_present_we_wararra_there", ["ngana", "wararra", "yinyay", "nyaji-l"], "Inclusive present perception; no storage/use row."),
    row(49, "We see the board there.", "Ngana yulal yinyay nyajil.", "ngana yulal yinyay nyaji-l | we board there see-NONPAST", "r184_present_we_yulal_there", ["ngana", "yulal", "yinyay", "nyaji-l"], "Inclusive present perception; board only."),
    row(50, "We see the didgeridoo there.", "Ngana yiki-yiki yinyay nyajil.", "ngana yiki-yiki yinyay nyaji-l | we didgeridoo there see-NONPAST", "r184_present_we_yiki_yiki_there", ["ngana", "yiki-yiki", "yinyay", "nyaji-l"], "Inclusive present perception; no play/music 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("r184_"):
            issues.append(f"{label}: Rule 184 frame must start with r184_")
        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 184")
        for denied in DENY_KUKU:
            if has_token(low, denied):
                issues.append(f"{label}: denied object/use/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 retained Rule 183 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 184 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 184 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 object 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 184 draft: construction consolidation after Rule 183", "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 184 source pass retained exactly the ten Rule 183 object-reference heads: dibarr, jakway, juljal, jurungurr, kadirangkal, mararr, mayal, wararra, yulal, and yiki-yiki. Fresh dictionary readback reconfirmed selected senses and traps: jakway front sense, juljal grave only not death/mourning/story, jurungurr old-time spoon prose, kadirangkal smoking-use risk, mararr sail/plaited-palm origin, mayal bottle only, wararra empty box only, yulal plank/stick contrast, and yiki-yiki lexical reduplication only. Patz readback reconfirmed yaluy/yinyay, nyaji-l/nyaji-ny, absolutive bare objects, and bare pronoun A forms.",
                 command="rg/sed dictionary YAML readback; rg 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 184 is a construction consolidation pass for the Rule 183 object-reference field. It admits no new target heads and excludes loans, unselected artefact heads, making, using, drinking, eating, smoking, carrying, storing, filling, opening, closing, playing, music, sound, corroboree, death-event, burial, mourning, story, material-source, manufacture, origin, possession, 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_226.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="static-guard-pass", actor="claude-main",
                 detail="Static guards passed: exactly one retained Rule 183 object target per row; all targets bare; no loans; no unselected object/use/event/polysemy tokens; no target case/compound forms; pronoun A bare; yinyay/yaluy support only.",
                 command="python3 batch_scripts/bank_226.py static scan", artifact_path="batch_scripts/bank_226.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())
