#!/usr/bin/env python3
"""Bank batch-288: Rule 246 fire-reference pronoun 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-288"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-288-fire-reference-pronoun-expansion-after-rule245-process.md"

TARGET_HEADS = {
    "baya": "fire",
    "jimal": "fire stick",
    "jirramar": "small sticks",
    "kubu": "smoke",
    "kunjin": "fire",
    "miyilkura": "smouldering log",
    "ngalku": "bush fire",
    "ngaluri": "flames",
    "ngunjil": "charcoal",
    "wula": "flames",
}
PRONOUN_SUPPORT = {
    "ngali": "1du.EXCL.NOM",
    "ngaliny": "1du.INCL.NOM",
    "yubal": "2du.NOM",
    "nganjin": "1pl.EXCL.NOM",
    "yurra": "2pl.NOM",
}
SUPPORT = set(PRONOUN_SUPPORT) | {"yaluy", "yinyay", "nyajil"}
DENY_KUKU = {
    # Fire-use/action/homograph traps.
    "baya-wayu", "wayu", "waju", "dalngarri", "dama-murnil", "jakalambal", "jimal damal",
    "jimal-damal", "jimalili", "maji", "minjiji", "nulung", "nyunil", "wulay", "kubu-kubu",
    "kunjirr", "ngalkun", "ngalkunbu", "ngamar", "ngamba",
    # Non-selected supports and older fire-reference frames.
    "yinya", "yundu", "nyulu", "ngana", "jana", "nyajin",
    # Pronoun/demonstrative case, perception compounds, and support inflection.
    "ngalingan", "ngalinyan", "yubalan", "nganjinan", "yurrangan", "ngalininy",
    "ngalinyiny", "yubaliny", "nganjininy", "yurraniny", "ngalinka", "ngalinyanka",
    "yubalanka", "nganjinanka", "yurranka", "ngalinda", "ngalinyanda", "yubalanda",
    "nganjinanda", "yurranda", "ngalinji", "ngalinyanji", "yubalanji", "nganjinanji",
    "yurranji", "ngalinga", "ngalinyanga", "yubalanga", "nganjinanga", "yurranga",
    "yinyangka", "yinyayngka", "yinyayanka", "yinyamba", "yinyayanda", "yinyamuny",
    "yinyamundu", "yinyanji", "yinyarriny", "nyaji-nka", "nyaji-nyaku",
    "nyaji-l-nyaji", "nyajiny",
    # Recent non-fire fields remain closed.
    "bandin", "bari", "bibar", "birri", "jiba", "jandal", "jibar", "kangkul",
    "kuwinyu", "waba", "jibarr", "mabil", "karrirrangkal", "jalngarr", "jinali",
    "kangku", "yalmba", "kambal-kambal", "jalkar", "janku", "jamba", "bakarr",
    "bayan", "bira", "jiji", "kilili", "wurun", "jakway", "yulal", "kararr",
    "bilangkurr",
}
DENY_ENGLISH = (
    "firewood", "light ", "lit ", "lighting", "start", "started", "starting", "make", "made",
    "making", "twirl", "drill", "collect", "collected", "gather", "gathered", "cook", "cooked",
    "cooking", "food", "damper", "leap", "leapt", "leaping", "shoot", "shooting", "spread",
    "spreading", "burn", "burned", "burning", "clear", "clearing", "grassfire", "danger", "warning",
    "smoke out", "smoking out", "source", "motion", "move", "moving", "warm", "warmed", "warming",
    "urine", "pus", "body fluid", "ashes", "hot ashes", "hot coals", "coals", "matches", "motor",
    "loan", "story", "ritual", "ceremony", "purify", "purified", "mullet", "place", "tadpole",
    "my ", "your ", "his ", "her ", "their ", "possess", "owner", "case", "compound", "watch",
    "look", "listening", "hearing", "event", "use",
)


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


EVIDENCE = {
    "baya": "Dictionary baya noun lines 1948-1962: gloss 'fire', definitions flame/fire plus firewood and baya wayu 'light a fire'. Rule 246 selects fire reference/perception only; no firewood, lighting, collecting, cooking, or use row. Patz 3.5 Table 3.6 sources ngali/ngaliny/yubal/nganjin/yurra; Patz 3.7 sources yaluy/yinyay; Patz 3.8.3.2 sources nyaji-l 'see'.",
    "jimal": "Dictionary jimal noun lines 9258-9268: gloss and definition 'fire stick'. Nearby jimal damal 'make fire with a fire stick' stays closed. Rule 246 selects fire-stick perception/reference only.",
    "jirramar": "Dictionary jirramar noun lines 9863-9874: gloss 'chips', definition 'chips, small sticks to start a fire'. Rule 246 selects small-sticks perception/reference only and leaves starting-fire/kindling-use prose closed.",
    "kubu": "Dictionary kubu noun lines 14707-14715: gloss/definition/translation 'smoke'. Nearby kubu-kubu tadpole stays closed. Rule 246 selects smoke perception/reference only.",
    "kunjin": "Dictionary kunjin noun lines 15880-15888: gloss/definition/translation 'fire'. Nearby kunjirr ritual smoke/purification prose stays closed. Rule 246 asserts no contrast with baya.",
    "miyilkura": "Dictionary miyilkura noun lines 19985-19994: gloss/definition/translation 'smouldering log'. Rule 246 selects object perception/reference only; no burning, cooking, warming, ash, or eye/miyil drift.",
    "ngalku": "Dictionary ngalku noun lines 21918-21926: gloss/definition/translation 'bush fire'. Nearby ngalkun mullet and ngalkunbu place stay closed. Rule 246 selects bush-fire reference only.",
    "ngaluri": "Dictionary ngaluri noun lines 22014-22025: gloss/definition/translation 'flames', with usage 'The flames leap up from the fire'. Rule 246 selects flames perception/reference only and leaves leap-up event prose closed.",
    "ngunjil": "Dictionary ngunjil noun lines 23679-23687: gloss 'charcoal', definition 'charcoal; hot coals or hot ashes'. Rule 246 selects charcoal only and leaves hot-coals/hot-ashes extension closed.",
    "wula": "Dictionary wula noun lines 27719-27727: gloss/definition/translation 'flames', synonym dalngarri. Rule 246 selects flames perception/reference only; dalngarri urine/flame homograph remains closed.",
}


ROWS = [
    row(1, "We two, not you, see the fire here.", "Ngali baya yaluy nyajil.", "ngali baya yaluy nyajil | 1du.EXCL.NOM fire here see.NPST", "r246_1du_excl_fire_here_see_baya", ["ngali", "baya", "yaluy", "nyajil"], EVIDENCE["baya"]),
    row(2, "We two, not you, see the fire stick here.", "Ngali jimal yaluy nyajil.", "ngali jimal yaluy nyajil | 1du.EXCL.NOM fire.stick here see.NPST", "r246_1du_excl_fire_here_see_jimal", ["ngali", "jimal", "yaluy", "nyajil"], EVIDENCE["jimal"]),
    row(3, "We two, not you, see the small sticks here.", "Ngali jirramar yaluy nyajil.", "ngali jirramar yaluy nyajil | 1du.EXCL.NOM small.sticks here see.NPST", "r246_1du_excl_fire_here_see_jirramar", ["ngali", "jirramar", "yaluy", "nyajil"], EVIDENCE["jirramar"]),
    row(4, "We two, not you, see the smoke here.", "Ngali kubu yaluy nyajil.", "ngali kubu yaluy nyajil | 1du.EXCL.NOM smoke here see.NPST", "r246_1du_excl_fire_here_see_kubu", ["ngali", "kubu", "yaluy", "nyajil"], EVIDENCE["kubu"]),
    row(5, "We two, not you, see the fire here.", "Ngali kunjin yaluy nyajil.", "ngali kunjin yaluy nyajil | 1du.EXCL.NOM fire here see.NPST", "r246_1du_excl_fire_here_see_kunjin", ["ngali", "kunjin", "yaluy", "nyajil"], EVIDENCE["kunjin"]),
    row(6, "We two, not you, see the smouldering log here.", "Ngali miyilkura yaluy nyajil.", "ngali miyilkura yaluy nyajil | 1du.EXCL.NOM smouldering.log here see.NPST", "r246_1du_excl_fire_here_see_miyilkura", ["ngali", "miyilkura", "yaluy", "nyajil"], EVIDENCE["miyilkura"]),
    row(7, "We two, not you, see the bush fire here.", "Ngali ngalku yaluy nyajil.", "ngali ngalku yaluy nyajil | 1du.EXCL.NOM bush.fire here see.NPST", "r246_1du_excl_fire_here_see_ngalku", ["ngali", "ngalku", "yaluy", "nyajil"], EVIDENCE["ngalku"]),
    row(8, "We two, not you, see the flames here.", "Ngali ngaluri yaluy nyajil.", "ngali ngaluri yaluy nyajil | 1du.EXCL.NOM flames here see.NPST", "r246_1du_excl_fire_here_see_ngaluri", ["ngali", "ngaluri", "yaluy", "nyajil"], EVIDENCE["ngaluri"]),
    row(9, "We two, not you, see the charcoal here.", "Ngali ngunjil yaluy nyajil.", "ngali ngunjil yaluy nyajil | 1du.EXCL.NOM charcoal here see.NPST", "r246_1du_excl_fire_here_see_ngunjil", ["ngali", "ngunjil", "yaluy", "nyajil"], EVIDENCE["ngunjil"]),
    row(10, "We two, not you, see the flames here.", "Ngali wula yaluy nyajil.", "ngali wula yaluy nyajil | 1du.EXCL.NOM flames here see.NPST", "r246_1du_excl_fire_here_see_wula", ["ngali", "wula", "yaluy", "nyajil"], EVIDENCE["wula"]),
    row(11, "You and I see the fire there.", "Ngaliny baya yinyay nyajil.", "ngaliny baya yinyay nyajil | 1du.INCL.NOM fire there see.NPST", "r246_1du_incl_fire_there_see_baya", ["ngaliny", "baya", "yinyay", "nyajil"], EVIDENCE["baya"]),
    row(12, "You and I see the fire stick there.", "Ngaliny jimal yinyay nyajil.", "ngaliny jimal yinyay nyajil | 1du.INCL.NOM fire.stick there see.NPST", "r246_1du_incl_fire_there_see_jimal", ["ngaliny", "jimal", "yinyay", "nyajil"], EVIDENCE["jimal"]),
    row(13, "You and I see the small sticks there.", "Ngaliny jirramar yinyay nyajil.", "ngaliny jirramar yinyay nyajil | 1du.INCL.NOM small.sticks there see.NPST", "r246_1du_incl_fire_there_see_jirramar", ["ngaliny", "jirramar", "yinyay", "nyajil"], EVIDENCE["jirramar"]),
    row(14, "You and I see the smoke there.", "Ngaliny kubu yinyay nyajil.", "ngaliny kubu yinyay nyajil | 1du.INCL.NOM smoke there see.NPST", "r246_1du_incl_fire_there_see_kubu", ["ngaliny", "kubu", "yinyay", "nyajil"], EVIDENCE["kubu"]),
    row(15, "You and I see the fire there.", "Ngaliny kunjin yinyay nyajil.", "ngaliny kunjin yinyay nyajil | 1du.INCL.NOM fire there see.NPST", "r246_1du_incl_fire_there_see_kunjin", ["ngaliny", "kunjin", "yinyay", "nyajil"], EVIDENCE["kunjin"]),
    row(16, "You and I see the smouldering log there.", "Ngaliny miyilkura yinyay nyajil.", "ngaliny miyilkura yinyay nyajil | 1du.INCL.NOM smouldering.log there see.NPST", "r246_1du_incl_fire_there_see_miyilkura", ["ngaliny", "miyilkura", "yinyay", "nyajil"], EVIDENCE["miyilkura"]),
    row(17, "You and I see the bush fire there.", "Ngaliny ngalku yinyay nyajil.", "ngaliny ngalku yinyay nyajil | 1du.INCL.NOM bush.fire there see.NPST", "r246_1du_incl_fire_there_see_ngalku", ["ngaliny", "ngalku", "yinyay", "nyajil"], EVIDENCE["ngalku"]),
    row(18, "You and I see the flames there.", "Ngaliny ngaluri yinyay nyajil.", "ngaliny ngaluri yinyay nyajil | 1du.INCL.NOM flames there see.NPST", "r246_1du_incl_fire_there_see_ngaluri", ["ngaliny", "ngaluri", "yinyay", "nyajil"], EVIDENCE["ngaluri"]),
    row(19, "You and I see the charcoal there.", "Ngaliny ngunjil yinyay nyajil.", "ngaliny ngunjil yinyay nyajil | 1du.INCL.NOM charcoal there see.NPST", "r246_1du_incl_fire_there_see_ngunjil", ["ngaliny", "ngunjil", "yinyay", "nyajil"], EVIDENCE["ngunjil"]),
    row(20, "You and I see the flames there.", "Ngaliny wula yinyay nyajil.", "ngaliny wula yinyay nyajil | 1du.INCL.NOM flames there see.NPST", "r246_1du_incl_fire_there_see_wula", ["ngaliny", "wula", "yinyay", "nyajil"], EVIDENCE["wula"]),
    row(21, "You two see the fire here.", "Yubal baya yaluy nyajil.", "yubal baya yaluy nyajil | 2du.NOM fire here see.NPST", "r246_2du_fire_here_see_baya", ["yubal", "baya", "yaluy", "nyajil"], EVIDENCE["baya"]),
    row(22, "You two see the fire stick here.", "Yubal jimal yaluy nyajil.", "yubal jimal yaluy nyajil | 2du.NOM fire.stick here see.NPST", "r246_2du_fire_here_see_jimal", ["yubal", "jimal", "yaluy", "nyajil"], EVIDENCE["jimal"]),
    row(23, "You two see the small sticks here.", "Yubal jirramar yaluy nyajil.", "yubal jirramar yaluy nyajil | 2du.NOM small.sticks here see.NPST", "r246_2du_fire_here_see_jirramar", ["yubal", "jirramar", "yaluy", "nyajil"], EVIDENCE["jirramar"]),
    row(24, "You two see the smoke here.", "Yubal kubu yaluy nyajil.", "yubal kubu yaluy nyajil | 2du.NOM smoke here see.NPST", "r246_2du_fire_here_see_kubu", ["yubal", "kubu", "yaluy", "nyajil"], EVIDENCE["kubu"]),
    row(25, "You two see the fire here.", "Yubal kunjin yaluy nyajil.", "yubal kunjin yaluy nyajil | 2du.NOM fire here see.NPST", "r246_2du_fire_here_see_kunjin", ["yubal", "kunjin", "yaluy", "nyajil"], EVIDENCE["kunjin"]),
    row(26, "You two see the smouldering log here.", "Yubal miyilkura yaluy nyajil.", "yubal miyilkura yaluy nyajil | 2du.NOM smouldering.log here see.NPST", "r246_2du_fire_here_see_miyilkura", ["yubal", "miyilkura", "yaluy", "nyajil"], EVIDENCE["miyilkura"]),
    row(27, "You two see the bush fire here.", "Yubal ngalku yaluy nyajil.", "yubal ngalku yaluy nyajil | 2du.NOM bush.fire here see.NPST", "r246_2du_fire_here_see_ngalku", ["yubal", "ngalku", "yaluy", "nyajil"], EVIDENCE["ngalku"]),
    row(28, "You two see the flames here.", "Yubal ngaluri yaluy nyajil.", "yubal ngaluri yaluy nyajil | 2du.NOM flames here see.NPST", "r246_2du_fire_here_see_ngaluri", ["yubal", "ngaluri", "yaluy", "nyajil"], EVIDENCE["ngaluri"]),
    row(29, "You two see the charcoal here.", "Yubal ngunjil yaluy nyajil.", "yubal ngunjil yaluy nyajil | 2du.NOM charcoal here see.NPST", "r246_2du_fire_here_see_ngunjil", ["yubal", "ngunjil", "yaluy", "nyajil"], EVIDENCE["ngunjil"]),
    row(30, "You two see the flames here.", "Yubal wula yaluy nyajil.", "yubal wula yaluy nyajil | 2du.NOM flames here see.NPST", "r246_2du_fire_here_see_wula", ["yubal", "wula", "yaluy", "nyajil"], EVIDENCE["wula"]),
    row(31, "We all, not you, see the fire there.", "Nganjin baya yinyay nyajil.", "nganjin baya yinyay nyajil | 1pl.EXCL.NOM fire there see.NPST", "r246_1pl_excl_fire_there_see_baya", ["nganjin", "baya", "yinyay", "nyajil"], EVIDENCE["baya"]),
    row(32, "We all, not you, see the fire stick there.", "Nganjin jimal yinyay nyajil.", "nganjin jimal yinyay nyajil | 1pl.EXCL.NOM fire.stick there see.NPST", "r246_1pl_excl_fire_there_see_jimal", ["nganjin", "jimal", "yinyay", "nyajil"], EVIDENCE["jimal"]),
    row(33, "We all, not you, see the small sticks there.", "Nganjin jirramar yinyay nyajil.", "nganjin jirramar yinyay nyajil | 1pl.EXCL.NOM small.sticks there see.NPST", "r246_1pl_excl_fire_there_see_jirramar", ["nganjin", "jirramar", "yinyay", "nyajil"], EVIDENCE["jirramar"]),
    row(34, "We all, not you, see the smoke there.", "Nganjin kubu yinyay nyajil.", "nganjin kubu yinyay nyajil | 1pl.EXCL.NOM smoke there see.NPST", "r246_1pl_excl_fire_there_see_kubu", ["nganjin", "kubu", "yinyay", "nyajil"], EVIDENCE["kubu"]),
    row(35, "We all, not you, see the fire there.", "Nganjin kunjin yinyay nyajil.", "nganjin kunjin yinyay nyajil | 1pl.EXCL.NOM fire there see.NPST", "r246_1pl_excl_fire_there_see_kunjin", ["nganjin", "kunjin", "yinyay", "nyajil"], EVIDENCE["kunjin"]),
    row(36, "We all, not you, see the smouldering log there.", "Nganjin miyilkura yinyay nyajil.", "nganjin miyilkura yinyay nyajil | 1pl.EXCL.NOM smouldering.log there see.NPST", "r246_1pl_excl_fire_there_see_miyilkura", ["nganjin", "miyilkura", "yinyay", "nyajil"], EVIDENCE["miyilkura"]),
    row(37, "We all, not you, see the bush fire there.", "Nganjin ngalku yinyay nyajil.", "nganjin ngalku yinyay nyajil | 1pl.EXCL.NOM bush.fire there see.NPST", "r246_1pl_excl_fire_there_see_ngalku", ["nganjin", "ngalku", "yinyay", "nyajil"], EVIDENCE["ngalku"]),
    row(38, "We all, not you, see the flames there.", "Nganjin ngaluri yinyay nyajil.", "nganjin ngaluri yinyay nyajil | 1pl.EXCL.NOM flames there see.NPST", "r246_1pl_excl_fire_there_see_ngaluri", ["nganjin", "ngaluri", "yinyay", "nyajil"], EVIDENCE["ngaluri"]),
    row(39, "We all, not you, see the charcoal there.", "Nganjin ngunjil yinyay nyajil.", "nganjin ngunjil yinyay nyajil | 1pl.EXCL.NOM charcoal there see.NPST", "r246_1pl_excl_fire_there_see_ngunjil", ["nganjin", "ngunjil", "yinyay", "nyajil"], EVIDENCE["ngunjil"]),
    row(40, "We all, not you, see the flames there.", "Nganjin wula yinyay nyajil.", "nganjin wula yinyay nyajil | 1pl.EXCL.NOM flames there see.NPST", "r246_1pl_excl_fire_there_see_wula", ["nganjin", "wula", "yinyay", "nyajil"], EVIDENCE["wula"]),
    row(41, "You all see the fire here.", "Yurra baya yaluy nyajil.", "yurra baya yaluy nyajil | 2pl.NOM fire here see.NPST", "r246_2pl_fire_here_see_baya", ["yurra", "baya", "yaluy", "nyajil"], EVIDENCE["baya"]),
    row(42, "You all see the fire stick here.", "Yurra jimal yaluy nyajil.", "yurra jimal yaluy nyajil | 2pl.NOM fire.stick here see.NPST", "r246_2pl_fire_here_see_jimal", ["yurra", "jimal", "yaluy", "nyajil"], EVIDENCE["jimal"]),
    row(43, "You all see the small sticks here.", "Yurra jirramar yaluy nyajil.", "yurra jirramar yaluy nyajil | 2pl.NOM small.sticks here see.NPST", "r246_2pl_fire_here_see_jirramar", ["yurra", "jirramar", "yaluy", "nyajil"], EVIDENCE["jirramar"]),
    row(44, "You all see the smoke here.", "Yurra kubu yaluy nyajil.", "yurra kubu yaluy nyajil | 2pl.NOM smoke here see.NPST", "r246_2pl_fire_here_see_kubu", ["yurra", "kubu", "yaluy", "nyajil"], EVIDENCE["kubu"]),
    row(45, "You all see the fire here.", "Yurra kunjin yaluy nyajil.", "yurra kunjin yaluy nyajil | 2pl.NOM fire here see.NPST", "r246_2pl_fire_here_see_kunjin", ["yurra", "kunjin", "yaluy", "nyajil"], EVIDENCE["kunjin"]),
    row(46, "You all see the smouldering log here.", "Yurra miyilkura yaluy nyajil.", "yurra miyilkura yaluy nyajil | 2pl.NOM smouldering.log here see.NPST", "r246_2pl_fire_here_see_miyilkura", ["yurra", "miyilkura", "yaluy", "nyajil"], EVIDENCE["miyilkura"]),
    row(47, "You all see the bush fire here.", "Yurra ngalku yaluy nyajil.", "yurra ngalku yaluy nyajil | 2pl.NOM bush.fire here see.NPST", "r246_2pl_fire_here_see_ngalku", ["yurra", "ngalku", "yaluy", "nyajil"], EVIDENCE["ngalku"]),
    row(48, "You all see the flames here.", "Yurra ngaluri yaluy nyajil.", "yurra ngaluri yaluy nyajil | 2pl.NOM flames here see.NPST", "r246_2pl_fire_here_see_ngaluri", ["yurra", "ngaluri", "yaluy", "nyajil"], EVIDENCE["ngaluri"]),
    row(49, "You all see the charcoal here.", "Yurra ngunjil yaluy nyajil.", "yurra ngunjil yaluy nyajil | 2pl.NOM charcoal here see.NPST", "r246_2pl_fire_here_see_ngunjil", ["yurra", "ngunjil", "yaluy", "nyajil"], EVIDENCE["ngunjil"]),
    row(50, "You all see the flames here.", "Yurra wula yaluy nyajil.", "yurra wula yaluy nyajil | 2pl.NOM flames here see.NPST", "r246_2pl_fire_here_see_wula", ["yurra", "wula", "yaluy", "nyajil"], EVIDENCE["wula"]),
]


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("r246_"):
            issues.append(f"{label}: Rule 246 frame must start with r246_")
        if low in seen_ku:
            issues.append(f"{label}: duplicate Kuku surface inside batch")
        seen_ku.add(low)
        if json.loads(loans_used):
            issues.append(f"{label}: loans_used must be empty")
        denied = [bad for bad in DENY_KUKU if has_token(low, bad)]
        if denied:
            issues.append(f"{label}: denied Kuku token(s) present: {denied}")
        targets = [head for head in TARGET_HEADS if has_token(low, head)]
        if len(targets) != 1:
            issues.append(f"{label}: expected exactly one Rule 246 target noun, found {targets}")
        for head in targets:
            selected = TARGET_HEADS[head]
            dotted = selected.replace("-", ".").replace(" ", ".")
            if head not in words:
                issues.append(f"{label}: target head {head} missing from words_used")
            if selected not in english_low:
                issues.append(f"{label}: English must include selected sense {selected!r}")
            if selected not in analysis and dotted not in analysis:
                issues.append(f"{label}: analysis must gloss {head} as {selected}")
            if has_target_morphology(low, head):
                issues.append(f"{label}: target head {head} has forbidden morphology")
        for support in SUPPORT:
            if has_token(low, support) and support not in words:
                issues.append(f"{label}: support {support} missing from words_used")
        pronouns = [pronoun for pronoun in PRONOUN_SUPPORT if has_token(low, pronoun)]
        if len(pronouns) != 1:
            issues.append(f"{label}: rows require exactly one selected bare nominative pronoun, found {pronouns}")
        if 1 <= seq <= 10 and (not low.startswith("ngali ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 1-10 require Ngali TARGET yaluy nyajil")
        if 11 <= seq <= 20 and (not low.startswith("ngaliny ") or not low.endswith(" yinyay nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 11-20 require Ngaliny TARGET yinyay nyajil")
        if 21 <= seq <= 30 and (not low.startswith("yubal ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 21-30 require Yubal TARGET yaluy nyajil")
        if 31 <= seq <= 40 and (not low.startswith("nganjin ") or not low.endswith(" yinyay nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 31-40 require Nganjin TARGET yinyay nyajil")
        if 41 <= seq <= 50 and (not low.startswith("yurra ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 41-50 require Yurra TARGET yaluy nyajil")
        if any(english_has_denied(english_low, bad) for bad in DENY_ENGLISH):
            issues.append(f"{label}: denied fire action/use/homograph/pronoun-case 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 lessons 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 246 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}: {kuku} -> {found}")
    if collisions:
        raise SystemExit("collision scan failed:\n" + "\n".join(collisions))

    db.executemany(
        """
        INSERT INTO sentences(
          batch_id, seq, english, kuku, analysis, frame, tier, words_used,
          loans_used, evidence, status, confidence, created_at
        )
        VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)
        """,
        [
            (
                batch_id,
                seq,
                english,
                kuku,
                analysis,
                frame,
                tier,
                words_used,
                loans_used,
                evidence,
                "under_review",
                confidence,
                NOW,
            )
            for seq, english, kuku, analysis, frame, tier, words_used, loans_used, evidence, confidence in ROWS
        ],
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="source",
        event_type="source-readback",
        actor="claude-main",
        detail="Rule 246 source pass retained the ten Rule 236 fire-reference target nouns; checked dictionary entries and line evidence for baya, jimal, jirramar, kubu, kunjin, miyilkura, ngalku, ngaluri, ngunjil, and wula; checked Patz 3.5 Table 3.6 for ngali, ngaliny, yubal, nganjin, and yurra; Patz 3.7 for yaluy/yinyay; and Patz 3.8.3.2 for nyaji-l.",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="planning",
        event_type="construction-scope",
        actor="claude-main",
        detail="Selected Rule 246 fire-reference pronoun expansion after Rule 245: same ten Rule 236 target nouns in five zero-collision nominative-pronoun perception bands. No new fire lexemes, fire-making, firewood, lighting, collecting, cooking, burning, clearing, spreading, smoke-source, hot-coal/ash, body-fluid homograph, loan, event, target case, pronoun case, or perception-compound semantics opened.",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="preflight",
        event_type="coverage-audit",
        actor="claude-main",
        detail="Token-aware pre-batch coverage after Rule 245: baya 460, jimal 38, jirramar 10, kubu 66, kunjin 16, miyilkura 10, ngalku 10, ngaluri 10, ngunjil 73, wula 64; pronouns ngali 109, ngaliny 44, yubal 55, nganjin 61, yurra 103.",
        command="token-aware coverage audit over accepted/revised rows",
        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 246 fire-reference pronoun-expansion perception surfaces returned zero accepted, revised, or under-review collisions.",
        command="python3 batch_scripts/bank_288.py internal collision scan",
        output_excerpt="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="Static guards passed: 50 rows, exactly one Rule 246 target noun per row, exactly one selected bare nominative pronoun per row, no loans, no target suffixes, no excluded fire-making/firewood/lighting/collecting/cooking/burning/clearing/spreading/smoke-source/smoke-out/leaping/hot-coal/body-fluid/loan/homograph/source-prose drift, no pronoun case, no perception compound, and five planned frame bands only.",
        command="python3 batch_scripts/bank_288.py",
        artifact_path="batch_scripts/bank_288.py",
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="bank",
        event_type="bank-success",
        actor="claude-main",
        detail="Banked 50 hand-authored Rule 246 fire-reference pronoun-expansion perception rows as under_review.",
        command="python3 batch_scripts/bank_288.py",
        artifact_path="batch_scripts/bank_288.py",
        created_at=NOW,
    )
    db.commit()
    print(f"banked {LABEL}: {len(ROWS)} under_review rows")
    return 0


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