#!/usr/bin/env python3
"""Bank batch-324: Rule 282 complementary non-singular visible water/landform past perception."""

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-324"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-324-visible-water-landform-nonsingular-complementary-past-pronoun-perception-after-rule281-process.md"

TARGET_HEADS = {
    "bubu": "ground",
    "dajali": "deep water",
    "jalun": "sea",
    "jirka": "spring",
    "jukar": "sand",
    "manjal": "mountain",
    "wawubaja": "river",
    "yilki": "creek",
    "yiri": "waterfall",
    "yirri": "running water",
}
TARGET_ORDER = ["bubu", "dajali", "jalun", "jirka", "jukar", "manjal", "wawubaja", "yilki", "yiri", "yirri"]
SUPPORT = {"ngali", "ngaliny", "yubal", "yurra", "jana", "yaluy", "yinyay", "nyajin"}
DENY_KUKU = {
    "bana", "daburri", "dulngku", "banabila", "jalungkarr", "jirimandi", "marrka", "mukurr-mukurr",
    "yalkan", "yikin", "yirri-damal", "yiril", "yiman", "kalki", "kubirri", "bujung", "wawu-balangaji",
    "ngalingan", "ngalinyan", "yubalan", "yurrangan", "janangan", "ngalininy", "ngalinyiny",
    "yubaliny", "yurraniny", "jananiny", "ngalinka", "ngalinyanka", "yubalanka", "yurranka", "jananka",
    "ngalinda", "ngalinyanda", "yubalanda", "yurranda", "jananda", "ngalinji", "ngalinyanji",
    "yubalanji", "yurranji", "jananji", "ngalinga", "ngalinyanga", "yubalanga", "yurranga", "jananga",
    "nyajil", "nyaji-l", "nyaji-nka", "nyaji-l-nyaji", "bubujida", "bubungu", "bubumuny", "bububa",
    "yinyangka", "yinyayngka", "yinyamba", "yinyamuny", "yalungku", "yaluyngku", "yaluymbu",
    "yaluyundu", "yalamuny", "yalanji",
}
DENY_ENGLISH = (
    "look", "looked", "watch", "watched", "watching", "listen", "listening", "hearing", "heard",
    "drink", "drank", "drinking", "get ", "got ", "getting", "fill", "filled", "wash", "washed",
    "washing", "swim", "swam", "swimming", "cross", "crossed", "crossing", "travel", "route",
    "road", "flood", "tide", "salt pan", "whale oil", "season", "place", "country", "belong",
    "dirty", "dirt", "story", "spirit", "fish", "fishing", "shell", "snake", "crocodile", "plant",
    "tree", "ecology", "danger", "navigation", "own", "owner", "source", "use", "uses", "used",
    "case", "compound", "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, 3, js(words), js([]), evidence, "0.86")


EVIDENCE = {
    "bubu": "Dictionary lines 3452-3470 give bubu as noun 'ground/earth' with a country/place extension. Rule 282 selects visible ground/earth only and leaves country/place/dirtiness extensions closed. Patz lines 2577-2586 and 2592-2603 source bare non-singular nominative pronouns; lines 2674-2686 source non-singular contrasts; lines 2838-2845 source yaluy/yinyay; and lines 2568-2571 source nyaji-ny 'see-PAST'.",
    "dajali": "Dictionary lines 4510-4518 give dajali as noun 'deep water'. Rule 282 selects visible deep-water reference only.",
    "jalun": "Dictionary lines 7612-7620 give jalun as noun 'sea, large body of water'. Rule 282 selects visible sea reference only.",
    "jirka": "Dictionary lines 9803-9813 give jirka as noun 'spring' and commentary reads it as a water source rather than season. Rule 282 selects visible water-source spring only, not season.",
    "jukar": "Dictionary lines 10254-10262 give jukar as noun 'sand'. Rule 282 selects visible sand reference only.",
    "manjal": "Dictionary lines 17832-17840 give manjal as noun 'mountain'. Rule 282 selects visible mountain reference only.",
    "wawubaja": "Dictionary lines 26813-26821 give wawubaja as noun 'river'. Rule 282 selects visible river reference only and leaves travel, route, crossing, bank, place-name, and water-use rows closed.",
    "yilki": "Dictionary lines 30031-30039 give yilki as noun 'creek'. Rule 282 selects visible creek reference only.",
    "yiri": "Dictionary lines 30410-30418 give yiri as noun 'waterfall'. Rule 282 selects visible waterfall reference only.",
    "yirri": "Dictionary lines 30507-30515 give yirri as noun 'running water'. Rule 282 selects visible running-water reference only and leaves yirri-damal 'leak' closed.",
}

ROWS = [
    row(1, "We two (not you) saw the ground there.", "Ngali bubu yinyay nyajin.", "ngali bubu yinyay nyajin | 1du.EXCL.NOM ground there see.PAST", "r282_1du_excl_water_landform_there_saw_bubu", ["ngali", "bubu", "yinyay", "nyajin"], EVIDENCE["bubu"]),
    row(2, "We two (not you) saw the deep water there.", "Ngali dajali yinyay nyajin.", "ngali dajali yinyay nyajin | 1du.EXCL.NOM deep.water there see.PAST", "r282_1du_excl_water_landform_there_saw_dajali", ["ngali", "dajali", "yinyay", "nyajin"], EVIDENCE["dajali"]),
    row(3, "We two (not you) saw the sea there.", "Ngali jalun yinyay nyajin.", "ngali jalun yinyay nyajin | 1du.EXCL.NOM sea there see.PAST", "r282_1du_excl_water_landform_there_saw_jalun", ["ngali", "jalun", "yinyay", "nyajin"], EVIDENCE["jalun"]),
    row(4, "We two (not you) saw the spring there.", "Ngali jirka yinyay nyajin.", "ngali jirka yinyay nyajin | 1du.EXCL.NOM spring there see.PAST", "r282_1du_excl_water_landform_there_saw_jirka", ["ngali", "jirka", "yinyay", "nyajin"], EVIDENCE["jirka"]),
    row(5, "We two (not you) saw the sand there.", "Ngali jukar yinyay nyajin.", "ngali jukar yinyay nyajin | 1du.EXCL.NOM sand there see.PAST", "r282_1du_excl_water_landform_there_saw_jukar", ["ngali", "jukar", "yinyay", "nyajin"], EVIDENCE["jukar"]),
    row(6, "We two (not you) saw the mountain there.", "Ngali manjal yinyay nyajin.", "ngali manjal yinyay nyajin | 1du.EXCL.NOM mountain there see.PAST", "r282_1du_excl_water_landform_there_saw_manjal", ["ngali", "manjal", "yinyay", "nyajin"], EVIDENCE["manjal"]),
    row(7, "We two (not you) saw the river there.", "Ngali wawubaja yinyay nyajin.", "ngali wawubaja yinyay nyajin | 1du.EXCL.NOM river there see.PAST", "r282_1du_excl_water_landform_there_saw_wawubaja", ["ngali", "wawubaja", "yinyay", "nyajin"], EVIDENCE["wawubaja"]),
    row(8, "We two (not you) saw the creek there.", "Ngali yilki yinyay nyajin.", "ngali yilki yinyay nyajin | 1du.EXCL.NOM creek there see.PAST", "r282_1du_excl_water_landform_there_saw_yilki", ["ngali", "yilki", "yinyay", "nyajin"], EVIDENCE["yilki"]),
    row(9, "We two (not you) saw the waterfall there.", "Ngali yiri yinyay nyajin.", "ngali yiri yinyay nyajin | 1du.EXCL.NOM waterfall there see.PAST", "r282_1du_excl_water_landform_there_saw_yiri", ["ngali", "yiri", "yinyay", "nyajin"], EVIDENCE["yiri"]),
    row(10, "We two (not you) saw the running water there.", "Ngali yirri yinyay nyajin.", "ngali yirri yinyay nyajin | 1du.EXCL.NOM running.water there see.PAST", "r282_1du_excl_water_landform_there_saw_yirri", ["ngali", "yirri", "yinyay", "nyajin"], EVIDENCE["yirri"]),
    row(11, "You and I saw the ground here.", "Ngaliny bubu yaluy nyajin.", "ngaliny bubu yaluy nyajin | 1du.INCL.NOM ground here see.PAST", "r282_1du_incl_water_landform_here_saw_bubu", ["ngaliny", "bubu", "yaluy", "nyajin"], EVIDENCE["bubu"]),
    row(12, "You and I saw the deep water here.", "Ngaliny dajali yaluy nyajin.", "ngaliny dajali yaluy nyajin | 1du.INCL.NOM deep.water here see.PAST", "r282_1du_incl_water_landform_here_saw_dajali", ["ngaliny", "dajali", "yaluy", "nyajin"], EVIDENCE["dajali"]),
    row(13, "You and I saw the sea here.", "Ngaliny jalun yaluy nyajin.", "ngaliny jalun yaluy nyajin | 1du.INCL.NOM sea here see.PAST", "r282_1du_incl_water_landform_here_saw_jalun", ["ngaliny", "jalun", "yaluy", "nyajin"], EVIDENCE["jalun"]),
    row(14, "You and I saw the spring here.", "Ngaliny jirka yaluy nyajin.", "ngaliny jirka yaluy nyajin | 1du.INCL.NOM spring here see.PAST", "r282_1du_incl_water_landform_here_saw_jirka", ["ngaliny", "jirka", "yaluy", "nyajin"], EVIDENCE["jirka"]),
    row(15, "You and I saw the sand here.", "Ngaliny jukar yaluy nyajin.", "ngaliny jukar yaluy nyajin | 1du.INCL.NOM sand here see.PAST", "r282_1du_incl_water_landform_here_saw_jukar", ["ngaliny", "jukar", "yaluy", "nyajin"], EVIDENCE["jukar"]),
    row(16, "You and I saw the mountain here.", "Ngaliny manjal yaluy nyajin.", "ngaliny manjal yaluy nyajin | 1du.INCL.NOM mountain here see.PAST", "r282_1du_incl_water_landform_here_saw_manjal", ["ngaliny", "manjal", "yaluy", "nyajin"], EVIDENCE["manjal"]),
    row(17, "You and I saw the river here.", "Ngaliny wawubaja yaluy nyajin.", "ngaliny wawubaja yaluy nyajin | 1du.INCL.NOM river here see.PAST", "r282_1du_incl_water_landform_here_saw_wawubaja", ["ngaliny", "wawubaja", "yaluy", "nyajin"], EVIDENCE["wawubaja"]),
    row(18, "You and I saw the creek here.", "Ngaliny yilki yaluy nyajin.", "ngaliny yilki yaluy nyajin | 1du.INCL.NOM creek here see.PAST", "r282_1du_incl_water_landform_here_saw_yilki", ["ngaliny", "yilki", "yaluy", "nyajin"], EVIDENCE["yilki"]),
    row(19, "You and I saw the waterfall here.", "Ngaliny yiri yaluy nyajin.", "ngaliny yiri yaluy nyajin | 1du.INCL.NOM waterfall here see.PAST", "r282_1du_incl_water_landform_here_saw_yiri", ["ngaliny", "yiri", "yaluy", "nyajin"], EVIDENCE["yiri"]),
    row(20, "You and I saw the running water here.", "Ngaliny yirri yaluy nyajin.", "ngaliny yirri yaluy nyajin | 1du.INCL.NOM running.water here see.PAST", "r282_1du_incl_water_landform_here_saw_yirri", ["ngaliny", "yirri", "yaluy", "nyajin"], EVIDENCE["yirri"]),
    row(21, "You two saw the ground there.", "Yubal bubu yinyay nyajin.", "yubal bubu yinyay nyajin | 2du.NOM ground there see.PAST", "r282_2du_water_landform_there_saw_bubu", ["yubal", "bubu", "yinyay", "nyajin"], EVIDENCE["bubu"]),
    row(22, "You two saw the deep water there.", "Yubal dajali yinyay nyajin.", "yubal dajali yinyay nyajin | 2du.NOM deep.water there see.PAST", "r282_2du_water_landform_there_saw_dajali", ["yubal", "dajali", "yinyay", "nyajin"], EVIDENCE["dajali"]),
    row(23, "You two saw the sea there.", "Yubal jalun yinyay nyajin.", "yubal jalun yinyay nyajin | 2du.NOM sea there see.PAST", "r282_2du_water_landform_there_saw_jalun", ["yubal", "jalun", "yinyay", "nyajin"], EVIDENCE["jalun"]),
    row(24, "You two saw the spring there.", "Yubal jirka yinyay nyajin.", "yubal jirka yinyay nyajin | 2du.NOM spring there see.PAST", "r282_2du_water_landform_there_saw_jirka", ["yubal", "jirka", "yinyay", "nyajin"], EVIDENCE["jirka"]),
    row(25, "You two saw the sand there.", "Yubal jukar yinyay nyajin.", "yubal jukar yinyay nyajin | 2du.NOM sand there see.PAST", "r282_2du_water_landform_there_saw_jukar", ["yubal", "jukar", "yinyay", "nyajin"], EVIDENCE["jukar"]),
    row(26, "You two saw the mountain there.", "Yubal manjal yinyay nyajin.", "yubal manjal yinyay nyajin | 2du.NOM mountain there see.PAST", "r282_2du_water_landform_there_saw_manjal", ["yubal", "manjal", "yinyay", "nyajin"], EVIDENCE["manjal"]),
    row(27, "You two saw the river there.", "Yubal wawubaja yinyay nyajin.", "yubal wawubaja yinyay nyajin | 2du.NOM river there see.PAST", "r282_2du_water_landform_there_saw_wawubaja", ["yubal", "wawubaja", "yinyay", "nyajin"], EVIDENCE["wawubaja"]),
    row(28, "You two saw the creek there.", "Yubal yilki yinyay nyajin.", "yubal yilki yinyay nyajin | 2du.NOM creek there see.PAST", "r282_2du_water_landform_there_saw_yilki", ["yubal", "yilki", "yinyay", "nyajin"], EVIDENCE["yilki"]),
    row(29, "You two saw the waterfall there.", "Yubal yiri yinyay nyajin.", "yubal yiri yinyay nyajin | 2du.NOM waterfall there see.PAST", "r282_2du_water_landform_there_saw_yiri", ["yubal", "yiri", "yinyay", "nyajin"], EVIDENCE["yiri"]),
    row(30, "You two saw the running water there.", "Yubal yirri yinyay nyajin.", "yubal yirri yinyay nyajin | 2du.NOM running.water there see.PAST", "r282_2du_water_landform_there_saw_yirri", ["yubal", "yirri", "yinyay", "nyajin"], EVIDENCE["yirri"]),
    row(31, "You all saw the ground here.", "Yurra bubu yaluy nyajin.", "yurra bubu yaluy nyajin | 2pl.NOM ground here see.PAST", "r282_2pl_water_landform_here_saw_bubu", ["yurra", "bubu", "yaluy", "nyajin"], EVIDENCE["bubu"]),
    row(32, "You all saw the deep water here.", "Yurra dajali yaluy nyajin.", "yurra dajali yaluy nyajin | 2pl.NOM deep.water here see.PAST", "r282_2pl_water_landform_here_saw_dajali", ["yurra", "dajali", "yaluy", "nyajin"], EVIDENCE["dajali"]),
    row(33, "You all saw the sea here.", "Yurra jalun yaluy nyajin.", "yurra jalun yaluy nyajin | 2pl.NOM sea here see.PAST", "r282_2pl_water_landform_here_saw_jalun", ["yurra", "jalun", "yaluy", "nyajin"], EVIDENCE["jalun"]),
    row(34, "You all saw the spring here.", "Yurra jirka yaluy nyajin.", "yurra jirka yaluy nyajin | 2pl.NOM spring here see.PAST", "r282_2pl_water_landform_here_saw_jirka", ["yurra", "jirka", "yaluy", "nyajin"], EVIDENCE["jirka"]),
    row(35, "You all saw the sand here.", "Yurra jukar yaluy nyajin.", "yurra jukar yaluy nyajin | 2pl.NOM sand here see.PAST", "r282_2pl_water_landform_here_saw_jukar", ["yurra", "jukar", "yaluy", "nyajin"], EVIDENCE["jukar"]),
    row(36, "You all saw the mountain here.", "Yurra manjal yaluy nyajin.", "yurra manjal yaluy nyajin | 2pl.NOM mountain here see.PAST", "r282_2pl_water_landform_here_saw_manjal", ["yurra", "manjal", "yaluy", "nyajin"], EVIDENCE["manjal"]),
    row(37, "You all saw the river here.", "Yurra wawubaja yaluy nyajin.", "yurra wawubaja yaluy nyajin | 2pl.NOM river here see.PAST", "r282_2pl_water_landform_here_saw_wawubaja", ["yurra", "wawubaja", "yaluy", "nyajin"], EVIDENCE["wawubaja"]),
    row(38, "You all saw the creek here.", "Yurra yilki yaluy nyajin.", "yurra yilki yaluy nyajin | 2pl.NOM creek here see.PAST", "r282_2pl_water_landform_here_saw_yilki", ["yurra", "yilki", "yaluy", "nyajin"], EVIDENCE["yilki"]),
    row(39, "You all saw the waterfall here.", "Yurra yiri yaluy nyajin.", "yurra yiri yaluy nyajin | 2pl.NOM waterfall here see.PAST", "r282_2pl_water_landform_here_saw_yiri", ["yurra", "yiri", "yaluy", "nyajin"], EVIDENCE["yiri"]),
    row(40, "You all saw the running water here.", "Yurra yirri yaluy nyajin.", "yurra yirri yaluy nyajin | 2pl.NOM running.water here see.PAST", "r282_2pl_water_landform_here_saw_yirri", ["yurra", "yirri", "yaluy", "nyajin"], EVIDENCE["yirri"]),
    row(41, "They saw the ground there.", "Jana bubu yinyay nyajin.", "jana bubu yinyay nyajin | 3pl.NOM ground there see.PAST", "r282_3pl_water_landform_there_saw_bubu", ["jana", "bubu", "yinyay", "nyajin"], EVIDENCE["bubu"]),
    row(42, "They saw the deep water there.", "Jana dajali yinyay nyajin.", "jana dajali yinyay nyajin | 3pl.NOM deep.water there see.PAST", "r282_3pl_water_landform_there_saw_dajali", ["jana", "dajali", "yinyay", "nyajin"], EVIDENCE["dajali"]),
    row(43, "They saw the sea there.", "Jana jalun yinyay nyajin.", "jana jalun yinyay nyajin | 3pl.NOM sea there see.PAST", "r282_3pl_water_landform_there_saw_jalun", ["jana", "jalun", "yinyay", "nyajin"], EVIDENCE["jalun"]),
    row(44, "They saw the spring there.", "Jana jirka yinyay nyajin.", "jana jirka yinyay nyajin | 3pl.NOM spring there see.PAST", "r282_3pl_water_landform_there_saw_jirka", ["jana", "jirka", "yinyay", "nyajin"], EVIDENCE["jirka"]),
    row(45, "They saw the sand there.", "Jana jukar yinyay nyajin.", "jana jukar yinyay nyajin | 3pl.NOM sand there see.PAST", "r282_3pl_water_landform_there_saw_jukar", ["jana", "jukar", "yinyay", "nyajin"], EVIDENCE["jukar"]),
    row(46, "They saw the mountain there.", "Jana manjal yinyay nyajin.", "jana manjal yinyay nyajin | 3pl.NOM mountain there see.PAST", "r282_3pl_water_landform_there_saw_manjal", ["jana", "manjal", "yinyay", "nyajin"], EVIDENCE["manjal"]),
    row(47, "They saw the river there.", "Jana wawubaja yinyay nyajin.", "jana wawubaja yinyay nyajin | 3pl.NOM river there see.PAST", "r282_3pl_water_landform_there_saw_wawubaja", ["jana", "wawubaja", "yinyay", "nyajin"], EVIDENCE["wawubaja"]),
    row(48, "They saw the creek there.", "Jana yilki yinyay nyajin.", "jana yilki yinyay nyajin | 3pl.NOM creek there see.PAST", "r282_3pl_water_landform_there_saw_yilki", ["jana", "yilki", "yinyay", "nyajin"], EVIDENCE["yilki"]),
    row(49, "They saw the waterfall there.", "Jana yiri yinyay nyajin.", "jana yiri yinyay nyajin | 3pl.NOM waterfall there see.PAST", "r282_3pl_water_landform_there_saw_yiri", ["jana", "yiri", "yinyay", "nyajin"], EVIDENCE["yiri"]),
    row(50, "They saw the running water there.", "Jana yirri yinyay nyajin.", "jana yirri yinyay nyajin | 3pl.NOM running.water there see.PAST", "r282_3pl_water_landform_there_saw_yirri", ["jana", "yirri", "yinyay", "nyajin"], EVIDENCE["yirri"]),
]

EXPECTED_BANDS = [
    ("ngali", "yinyay"),
    ("ngaliny", "yaluy"),
    ("yubal", "yinyay"),
    ("yurra", "yaluy"),
    ("jana", "yinyay"),
]


def scan_static() -> list[str]:
    issues: list[str] = []
    if len(ROWS) != 50:
        issues.append(f"row count {len(ROWS)} != 50")
    if [r[0] for r in ROWS] != list(range(1, 51)):
        issues.append("sequence is not 1..50")
    kukus = [r[2] for r in ROWS]
    if len(set(kukus)) != len(kukus):
        issues.append("duplicate Kuku surface inside batch")
    for seq, english, kuku, analysis, frame, _tier, words_json, loans_json, _evidence, _confidence in ROWS:
        words = json.loads(words_json)
        loans = json.loads(loans_json)
        lower_kuku = kuku.lower()
        lower_english = english.lower()
        if loans:
            issues.append(f"{seq}: loans used {loans}")
        denied = sorted({w for w in DENY_KUKU if re.search(rf"(^|\\s){re.escape(w)}([\\s\\.]|$)", lower_kuku)})
        if denied:
            issues.append(f"{seq}: denied Kuku forms {denied}")
        denied_english = [
            term for term in DENY_ENGLISH
            if re.search(rf"\b{re.escape(term.strip())}\b", lower_english)
        ]
        if denied_english:
            issues.append(f"{seq}: denied English drift {denied_english}")
        target_hits = [w for w in TARGET_ORDER if w in words]
        if len(target_hits) != 1:
            issues.append(f"{seq}: target hits {target_hits}")
        if len(words) != 4:
            issues.append(f"{seq}: expected 4 words, got {words}")
        if "nyajin" not in words or not lower_kuku.endswith(" nyajin."):
            issues.append(f"{seq}: missing final nyajin")
        if len([w for w in ("yaluy", "yinyay") if w in words]) != 1:
            issues.append(f"{seq}: demonstrative problem {words}")
        expected_pronoun, expected_demo = EXPECTED_BANDS[(seq - 1) // 10]
        if words[0] != expected_pronoun:
            issues.append(f"{seq}: expected pronoun {expected_pronoun}, got {words[0]}")
        if words[2] != expected_demo:
            issues.append(f"{seq}: expected demonstrative {expected_demo}, got {words[2]}")
        if words[1] not in TARGET_HEADS:
            issues.append(f"{seq}: word 2 is not a target {words[1]}")
        if words[3] != "nyajin":
            issues.append(f"{seq}: word 4 is not nyajin {words[3]}")
        if not frame.startswith("r282_"):
            issues.append(f"{seq}: frame not r282 {frame}")
    return issues


def count_words(db: sqlite3.Connection, words: list[str]) -> dict[str, int]:
    return {
        word: db.execute(
            """
            SELECT COUNT(*)
            FROM sentences s
            WHERE s.status IN ('accepted','revised')
              AND EXISTS (SELECT 1 FROM json_each(s.words_used) WHERE value=?)
            """,
            (word,),
        ).fetchone()[0]
        for word in words
    }


def main() -> int:
    issues = scan_static()
    if issues:
        for issue in issues:
            print(issue)
        raise SystemExit(1)

    db = sqlite3.connect(DB)
    db.execute("PRAGMA foreign_keys = ON")
    db.execute("BEGIN")
    ensure_schema(db)
    if db.execute("SELECT 1 FROM batches WHERE label=?", (LABEL,)).fetchone():
        raise SystemExit(f"{LABEL} already exists")
    collisions = []
    for _seq, _english, kuku, *_rest in ROWS:
        existing = 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!='rejected'
            """,
            (kuku,),
        ).fetchall()
        if existing:
            collisions.append((kuku, existing))
    if collisions:
        raise SystemExit(f"duplicate preflight failed: {collisions}")

    target_counts = count_words(db, TARGET_ORDER)
    support_counts = count_words(db, ["ngali", "ngaliny", "yubal", "yurra", "jana", "yaluy", "yinyay", "nyajin"])
    verified_before, words_before = db.execute(
        """
        SELECT COUNT(*), SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1)
        FROM sentences
        WHERE status IN ('accepted','revised')
        """
    ).fetchone()

    notes = (
        "VISIBLE WATER/LANDFORM NON-SINGULAR COMPLEMENTARY PAST PRONOUN PERCEPTION SWEEP (Rule 282). "
        "50 under-review rows over bubu ground/earth, dajali deep water, jalun sea, jirka spring, jukar sand, "
        "manjal mountain, wawubaja river, yilki creek, yiri waterfall, and yirri running water with bare nominative "
        "ngali, ngaliny, yubal, yurra, and jana. Bana was excluded after exact duplicate pressure and bubu replaced "
        "it; daburri was also rejected in this frame set after duplicate pressure. Only bare visual past reference/"
        "perception rows are opened; pronoun case, water use, travel, route, flood, tide, place names, source-use, "
        "bubu country/place extension, jukar sand-compound/source-prose, wawubaja route/crossing/place use, target "
        "case, demonstrative case, compounds, productive reduplication, perception compounds, nonpast/purposive/"
        "reduplicated perception drift, and support inflection remain closed."
    )
    cur = db.execute(
        "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
        (LABEL, "Rule 282 under review", "operator-guide-2026-07-09", notes, NOW),
    )
    batch_id = cur.lastrowid
    db.executemany(
        """
        INSERT INTO sentences(
          batch_id, seq, english, kuku, analysis, frame, tier, words_used, loans_used,
          evidence, status, confidence, rights_status, author, created_at, updated_at
        )
        VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
        """,
        [
            (
                batch_id, seq, english, kuku, analysis, frame, tier, words_used, loans_used,
                evidence, "under_review", confidence,
                "project_approved_synthetic_pending_elder_verification", "claude", NOW, 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="Reread dictionary source lines for final water/landform targets including replacement bubu and Patz non-singular pronoun, demonstrative, and nyaji-ny past support before authoring.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="debt-sweep-scope", actor="claude-main", detail="Selected complementary-deictic non-singular past counterpart to Rule 277 after Rule 281. Initial target set with bana was rejected after a Batch 193 duplicate; sourced bubu ground/earth replaced it. Daburri was also rejected after a Batch 194 duplicate in the same frame set.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="coverage-audit", actor="claude-main", detail=f"Token-aware accepted/revised coverage before banking from words_used JSON: targets={target_counts}; support={support_counts}.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="duplicate-preflight", actor="claude-main", detail="Initial candidate found duplicate Jana bana yinyay nyajin. from Batch 193; daburri replacement candidate found duplicate Jana daburri yinyay nyajin. from Batch 194; final 50 Rule 282 surfaces with bubu returned no accepted, revised, or under-review collisions.", 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 guard passed: 50 rows, one target each, bare non-singular nominative pronouns, bare yaluy/yinyay, final nyajin, no loans, no denied Kuku forms, no water-use/travel/place-name/bubu-country/jukar-compound/wawubaja-route drift.", command="python3 -m py_compile batch_scripts/bank_324.py && python3 -c \"import sys; sys.path.insert(0,'batch_scripts'); import bank_324; print(bank_324.scan_static())\"", output_excerpt="issues 0", artifact_path="batch_scripts/bank_324.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="claude-main", detail=f"Banked 50 Rule 282 rows as under_review. Verified total remains {verified_before}; Kuku word count remains {words_before}.", command="python3 batch_scripts/bank_324.py", output_excerpt=f"banked batch-324: 50 rows under_review; verified_before={verified_before}; kuku_words_before={words_before}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit()
    print("banked batch-324: 50 rows under_review")
    return 0


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