#!/usr/bin/env python3
"""Bank batch-328: Rule 286 visible artefact/tool non-singular nonpast 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-328"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-328-visible-artefact-tool-nonsingular-nonpast-pronoun-perception-after-rule285-process.md"

TARGET_HEADS = {
    "badur": "hook",
    "balji": "dilly bag",
    "balur": "spear thrower",
    "kaljan": "outrigger canoe",
    "dajal": "fighting spear",
    "dakilji": "cup",
    "jidi": "torch",
    "jindal": "three-pronged spear",
    "jundi": "pumice stone",
    "karra": "rope",
}
TARGET_ORDER = [
    "badur", "balji", "balur", "kaljan", "dajal", "dakilji", "jidi", "jindal", "jundi", "karra",
]
DENY_KUKU = {
    "birungubay", "biruwybay", "birubay", "badurriji", "baluriji", "dama-l", "dama-ny",
    "damal", "damany", "daman", "damba", "jindal-ny", "jindalny", "jindal-ji", "jarrjal",
    "jarrkal", "milbayarr", "mingu", "marrakan", "knife", "pipe", "blanket", "hat",
    "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", "nyajin", "nyaji-ny", "nyaji-nka", "nyaji-l-nyaji", "yinyangka",
    "yinyayngka", "yinyamba", "yinyamuny", "yalungku", "yaluyngku", "yaluymbu", "yaluyundu",
    "yalamuny",
}
DENY_ENGLISH = (
    "fishing", "fish with", "row", "paddle with", "oar", "made", "make", "used", "use",
    "throwing", "threw", "thrown", "fighting with", "fight with", "kill", "killed", "bite",
    "bit", "bad news", "message", "euphemism", "penis", "fire", "burn", "burned", "cooking",
    "travel", "route", "went in", "place", "story", "ceremony", "mortuary", "coffin",
)


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 = {
    "badur": "Dictionary lines 256-268 give badur as noun 'hook', with definition 'hook and line'. Rule 286 selects the visible object only and leaves fishing action closed. Patz lines 2577-2603 source bare non-singular nominative pronouns; lines 2674-2686 source non-singular contrasts; lines 2838-2845 source yaluy/yinyay; and lines 3043-3049 source nyaji-l 'see'.",
    "balji": "Dictionary lines 963-974 give balji as noun 'bag/dilly bag', specifically a woman's dilly bag made from grass or black palm. Rule 286 selects the visible bag only and leaves making/material-use rows closed.",
    "balur": "Dictionary lines 1154-1170 give balur as noun 'spear thrower' and mark a duplicate empty entry as the same noun. Rule 286 selects the visible woomera/spear-thrower object only.",
    "kaljan": "Dictionary lines 12560-12568 give kaljan as noun 'outrigger canoe'. Rule 286 selects visible canoe reference only and leaves travel/rowing/use rows closed.",
    "dajal": "Dictionary lines 4499-4509 give dajal as noun 'spear', specifically fighting spear. Rule 286 selects visible spear reference only and leaves fighting/spearing actions closed.",
    "dakilji": "Dictionary lines 4665-4676 give dakilji as noun 'cup', also pannikin only rarely used now. Rule 286 selects visible cup reference only.",
    "jidi": "Dictionary lines 8842-8851 give jidi as noun 'torch', a paperbark-tree-bark torch. Rule 286 selects visible torch reference only and leaves fire/burning/making rows closed.",
    "jindal": "Dictionary lines 9423-9433 give jindal as noun 'spear with three prongs' and warn it is homophonous with jindal 'bite'. Rule 286 selects the noun only and leaves the biting verb closed.",
    "jundi": "Dictionary lines 10846-10857 give jundi as noun 'pumice stone/carborundum stone'. Rule 286 selects visible stone/tool reference only and leaves sharpening/rubbing use closed.",
    "karra": "Dictionary lines 13534-13544 give karra as noun 'rope, cord, string', with synonym ngarra. Rule 286 selects visible rope reference only and leaves tying/use rows closed.",
}

ROWS = [
    row(1, "We two (not you) see the hook there.", "Ngali badur yinyay nyajil.", "ngali badur yinyay nyajil | 1du.EXCL.NOM hook there see.NPST", "r286_1du_excl_artefact_tool_there_see_badur", ["ngali", "badur", "yinyay", "nyajil"], EVIDENCE["badur"]),
    row(2, "We two (not you) see the dilly bag there.", "Ngali balji yinyay nyajil.", "ngali balji yinyay nyajil | 1du.EXCL.NOM dilly.bag there see.NPST", "r286_1du_excl_artefact_tool_there_see_balji", ["ngali", "balji", "yinyay", "nyajil"], EVIDENCE["balji"]),
    row(3, "We two (not you) see the spear thrower there.", "Ngali balur yinyay nyajil.", "ngali balur yinyay nyajil | 1du.EXCL.NOM spear.thrower there see.NPST", "r286_1du_excl_artefact_tool_there_see_balur", ["ngali", "balur", "yinyay", "nyajil"], EVIDENCE["balur"]),
    row(4, "We two (not you) see the outrigger canoe there.", "Ngali kaljan yinyay nyajil.", "ngali kaljan yinyay nyajil | 1du.EXCL.NOM outrigger.canoe there see.NPST", "r286_1du_excl_artefact_tool_there_see_kaljan", ["ngali", "kaljan", "yinyay", "nyajil"], EVIDENCE["kaljan"]),
    row(5, "We two (not you) see the fighting spear there.", "Ngali dajal yinyay nyajil.", "ngali dajal yinyay nyajil | 1du.EXCL.NOM fighting.spear there see.NPST", "r286_1du_excl_artefact_tool_there_see_dajal", ["ngali", "dajal", "yinyay", "nyajil"], EVIDENCE["dajal"]),
    row(6, "We two (not you) see the cup there.", "Ngali dakilji yinyay nyajil.", "ngali dakilji yinyay nyajil | 1du.EXCL.NOM cup there see.NPST", "r286_1du_excl_artefact_tool_there_see_dakilji", ["ngali", "dakilji", "yinyay", "nyajil"], EVIDENCE["dakilji"]),
    row(7, "We two (not you) see the torch there.", "Ngali jidi yinyay nyajil.", "ngali jidi yinyay nyajil | 1du.EXCL.NOM torch there see.NPST", "r286_1du_excl_artefact_tool_there_see_jidi", ["ngali", "jidi", "yinyay", "nyajil"], EVIDENCE["jidi"]),
    row(8, "We two (not you) see the three-pronged spear there.", "Ngali jindal yinyay nyajil.", "ngali jindal yinyay nyajil | 1du.EXCL.NOM three.pronged.spear there see.NPST", "r286_1du_excl_artefact_tool_there_see_jindal", ["ngali", "jindal", "yinyay", "nyajil"], EVIDENCE["jindal"]),
    row(9, "We two (not you) see the pumice stone there.", "Ngali jundi yinyay nyajil.", "ngali jundi yinyay nyajil | 1du.EXCL.NOM pumice.stone there see.NPST", "r286_1du_excl_artefact_tool_there_see_jundi", ["ngali", "jundi", "yinyay", "nyajil"], EVIDENCE["jundi"]),
    row(10, "We two (not you) see the rope there.", "Ngali karra yinyay nyajil.", "ngali karra yinyay nyajil | 1du.EXCL.NOM rope there see.NPST", "r286_1du_excl_artefact_tool_there_see_karra", ["ngali", "karra", "yinyay", "nyajil"], EVIDENCE["karra"]),
    row(11, "You and I see the hook here.", "Ngaliny badur yaluy nyajil.", "ngaliny badur yaluy nyajil | 1du.INCL.NOM hook here see.NPST", "r286_1du_incl_artefact_tool_here_see_badur", ["ngaliny", "badur", "yaluy", "nyajil"], EVIDENCE["badur"]),
    row(12, "You and I see the dilly bag here.", "Ngaliny balji yaluy nyajil.", "ngaliny balji yaluy nyajil | 1du.INCL.NOM dilly.bag here see.NPST", "r286_1du_incl_artefact_tool_here_see_balji", ["ngaliny", "balji", "yaluy", "nyajil"], EVIDENCE["balji"]),
    row(13, "You and I see the spear thrower here.", "Ngaliny balur yaluy nyajil.", "ngaliny balur yaluy nyajil | 1du.INCL.NOM spear.thrower here see.NPST", "r286_1du_incl_artefact_tool_here_see_balur", ["ngaliny", "balur", "yaluy", "nyajil"], EVIDENCE["balur"]),
    row(14, "You and I see the outrigger canoe here.", "Ngaliny kaljan yaluy nyajil.", "ngaliny kaljan yaluy nyajil | 1du.INCL.NOM outrigger.canoe here see.NPST", "r286_1du_incl_artefact_tool_here_see_kaljan", ["ngaliny", "kaljan", "yaluy", "nyajil"], EVIDENCE["kaljan"]),
    row(15, "You and I see the fighting spear here.", "Ngaliny dajal yaluy nyajil.", "ngaliny dajal yaluy nyajil | 1du.INCL.NOM fighting.spear here see.NPST", "r286_1du_incl_artefact_tool_here_see_dajal", ["ngaliny", "dajal", "yaluy", "nyajil"], EVIDENCE["dajal"]),
    row(16, "You and I see the cup here.", "Ngaliny dakilji yaluy nyajil.", "ngaliny dakilji yaluy nyajil | 1du.INCL.NOM cup here see.NPST", "r286_1du_incl_artefact_tool_here_see_dakilji", ["ngaliny", "dakilji", "yaluy", "nyajil"], EVIDENCE["dakilji"]),
    row(17, "You and I see the torch here.", "Ngaliny jidi yaluy nyajil.", "ngaliny jidi yaluy nyajil | 1du.INCL.NOM torch here see.NPST", "r286_1du_incl_artefact_tool_here_see_jidi", ["ngaliny", "jidi", "yaluy", "nyajil"], EVIDENCE["jidi"]),
    row(18, "You and I see the three-pronged spear here.", "Ngaliny jindal yaluy nyajil.", "ngaliny jindal yaluy nyajil | 1du.INCL.NOM three.pronged.spear here see.NPST", "r286_1du_incl_artefact_tool_here_see_jindal", ["ngaliny", "jindal", "yaluy", "nyajil"], EVIDENCE["jindal"]),
    row(19, "You and I see the pumice stone here.", "Ngaliny jundi yaluy nyajil.", "ngaliny jundi yaluy nyajil | 1du.INCL.NOM pumice.stone here see.NPST", "r286_1du_incl_artefact_tool_here_see_jundi", ["ngaliny", "jundi", "yaluy", "nyajil"], EVIDENCE["jundi"]),
    row(20, "You and I see the rope here.", "Ngaliny karra yaluy nyajil.", "ngaliny karra yaluy nyajil | 1du.INCL.NOM rope here see.NPST", "r286_1du_incl_artefact_tool_here_see_karra", ["ngaliny", "karra", "yaluy", "nyajil"], EVIDENCE["karra"]),
    row(21, "You two see the hook there.", "Yubal badur yinyay nyajil.", "yubal badur yinyay nyajil | 2du.NOM hook there see.NPST", "r286_2du_artefact_tool_there_see_badur", ["yubal", "badur", "yinyay", "nyajil"], EVIDENCE["badur"]),
    row(22, "You two see the dilly bag there.", "Yubal balji yinyay nyajil.", "yubal balji yinyay nyajil | 2du.NOM dilly.bag there see.NPST", "r286_2du_artefact_tool_there_see_balji", ["yubal", "balji", "yinyay", "nyajil"], EVIDENCE["balji"]),
    row(23, "You two see the spear thrower there.", "Yubal balur yinyay nyajil.", "yubal balur yinyay nyajil | 2du.NOM spear.thrower there see.NPST", "r286_2du_artefact_tool_there_see_balur", ["yubal", "balur", "yinyay", "nyajil"], EVIDENCE["balur"]),
    row(24, "You two see the outrigger canoe there.", "Yubal kaljan yinyay nyajil.", "yubal kaljan yinyay nyajil | 2du.NOM outrigger.canoe there see.NPST", "r286_2du_artefact_tool_there_see_kaljan", ["yubal", "kaljan", "yinyay", "nyajil"], EVIDENCE["kaljan"]),
    row(25, "You two see the fighting spear there.", "Yubal dajal yinyay nyajil.", "yubal dajal yinyay nyajil | 2du.NOM fighting.spear there see.NPST", "r286_2du_artefact_tool_there_see_dajal", ["yubal", "dajal", "yinyay", "nyajil"], EVIDENCE["dajal"]),
    row(26, "You two see the cup there.", "Yubal dakilji yinyay nyajil.", "yubal dakilji yinyay nyajil | 2du.NOM cup there see.NPST", "r286_2du_artefact_tool_there_see_dakilji", ["yubal", "dakilji", "yinyay", "nyajil"], EVIDENCE["dakilji"]),
    row(27, "You two see the torch there.", "Yubal jidi yinyay nyajil.", "yubal jidi yinyay nyajil | 2du.NOM torch there see.NPST", "r286_2du_artefact_tool_there_see_jidi", ["yubal", "jidi", "yinyay", "nyajil"], EVIDENCE["jidi"]),
    row(28, "You two see the three-pronged spear there.", "Yubal jindal yinyay nyajil.", "yubal jindal yinyay nyajil | 2du.NOM three.pronged.spear there see.NPST", "r286_2du_artefact_tool_there_see_jindal", ["yubal", "jindal", "yinyay", "nyajil"], EVIDENCE["jindal"]),
    row(29, "You two see the pumice stone there.", "Yubal jundi yinyay nyajil.", "yubal jundi yinyay nyajil | 2du.NOM pumice.stone there see.NPST", "r286_2du_artefact_tool_there_see_jundi", ["yubal", "jundi", "yinyay", "nyajil"], EVIDENCE["jundi"]),
    row(30, "You two see the rope there.", "Yubal karra yinyay nyajil.", "yubal karra yinyay nyajil | 2du.NOM rope there see.NPST", "r286_2du_artefact_tool_there_see_karra", ["yubal", "karra", "yinyay", "nyajil"], EVIDENCE["karra"]),
    row(31, "You all see the hook here.", "Yurra badur yaluy nyajil.", "yurra badur yaluy nyajil | 2pl.NOM hook here see.NPST", "r286_2pl_artefact_tool_here_see_badur", ["yurra", "badur", "yaluy", "nyajil"], EVIDENCE["badur"]),
    row(32, "You all see the dilly bag here.", "Yurra balji yaluy nyajil.", "yurra balji yaluy nyajil | 2pl.NOM dilly.bag here see.NPST", "r286_2pl_artefact_tool_here_see_balji", ["yurra", "balji", "yaluy", "nyajil"], EVIDENCE["balji"]),
    row(33, "You all see the spear thrower here.", "Yurra balur yaluy nyajil.", "yurra balur yaluy nyajil | 2pl.NOM spear.thrower here see.NPST", "r286_2pl_artefact_tool_here_see_balur", ["yurra", "balur", "yaluy", "nyajil"], EVIDENCE["balur"]),
    row(34, "You all see the outrigger canoe here.", "Yurra kaljan yaluy nyajil.", "yurra kaljan yaluy nyajil | 2pl.NOM outrigger.canoe here see.NPST", "r286_2pl_artefact_tool_here_see_kaljan", ["yurra", "kaljan", "yaluy", "nyajil"], EVIDENCE["kaljan"]),
    row(35, "You all see the fighting spear here.", "Yurra dajal yaluy nyajil.", "yurra dajal yaluy nyajil | 2pl.NOM fighting.spear here see.NPST", "r286_2pl_artefact_tool_here_see_dajal", ["yurra", "dajal", "yaluy", "nyajil"], EVIDENCE["dajal"]),
    row(36, "You all see the cup here.", "Yurra dakilji yaluy nyajil.", "yurra dakilji yaluy nyajil | 2pl.NOM cup here see.NPST", "r286_2pl_artefact_tool_here_see_dakilji", ["yurra", "dakilji", "yaluy", "nyajil"], EVIDENCE["dakilji"]),
    row(37, "You all see the torch here.", "Yurra jidi yaluy nyajil.", "yurra jidi yaluy nyajil | 2pl.NOM torch here see.NPST", "r286_2pl_artefact_tool_here_see_jidi", ["yurra", "jidi", "yaluy", "nyajil"], EVIDENCE["jidi"]),
    row(38, "You all see the three-pronged spear here.", "Yurra jindal yaluy nyajil.", "yurra jindal yaluy nyajil | 2pl.NOM three.pronged.spear here see.NPST", "r286_2pl_artefact_tool_here_see_jindal", ["yurra", "jindal", "yaluy", "nyajil"], EVIDENCE["jindal"]),
    row(39, "You all see the pumice stone here.", "Yurra jundi yaluy nyajil.", "yurra jundi yaluy nyajil | 2pl.NOM pumice.stone here see.NPST", "r286_2pl_artefact_tool_here_see_jundi", ["yurra", "jundi", "yaluy", "nyajil"], EVIDENCE["jundi"]),
    row(40, "You all see the rope here.", "Yurra karra yaluy nyajil.", "yurra karra yaluy nyajil | 2pl.NOM rope here see.NPST", "r286_2pl_artefact_tool_here_see_karra", ["yurra", "karra", "yaluy", "nyajil"], EVIDENCE["karra"]),
    row(41, "They see the hook there.", "Jana badur yinyay nyajil.", "jana badur yinyay nyajil | 3pl.NOM hook there see.NPST", "r286_3pl_artefact_tool_there_see_badur", ["jana", "badur", "yinyay", "nyajil"], EVIDENCE["badur"]),
    row(42, "They see the dilly bag there.", "Jana balji yinyay nyajil.", "jana balji yinyay nyajil | 3pl.NOM dilly.bag there see.NPST", "r286_3pl_artefact_tool_there_see_balji", ["jana", "balji", "yinyay", "nyajil"], EVIDENCE["balji"]),
    row(43, "They see the spear thrower there.", "Jana balur yinyay nyajil.", "jana balur yinyay nyajil | 3pl.NOM spear.thrower there see.NPST", "r286_3pl_artefact_tool_there_see_balur", ["jana", "balur", "yinyay", "nyajil"], EVIDENCE["balur"]),
    row(44, "They see the outrigger canoe there.", "Jana kaljan yinyay nyajil.", "jana kaljan yinyay nyajil | 3pl.NOM outrigger.canoe there see.NPST", "r286_3pl_artefact_tool_there_see_kaljan", ["jana", "kaljan", "yinyay", "nyajil"], EVIDENCE["kaljan"]),
    row(45, "They see the fighting spear there.", "Jana dajal yinyay nyajil.", "jana dajal yinyay nyajil | 3pl.NOM fighting.spear there see.NPST", "r286_3pl_artefact_tool_there_see_dajal", ["jana", "dajal", "yinyay", "nyajil"], EVIDENCE["dajal"]),
    row(46, "They see the cup there.", "Jana dakilji yinyay nyajil.", "jana dakilji yinyay nyajil | 3pl.NOM cup there see.NPST", "r286_3pl_artefact_tool_there_see_dakilji", ["jana", "dakilji", "yinyay", "nyajil"], EVIDENCE["dakilji"]),
    row(47, "They see the torch there.", "Jana jidi yinyay nyajil.", "jana jidi yinyay nyajil | 3pl.NOM torch there see.NPST", "r286_3pl_artefact_tool_there_see_jidi", ["jana", "jidi", "yinyay", "nyajil"], EVIDENCE["jidi"]),
    row(48, "They see the three-pronged spear there.", "Jana jindal yinyay nyajil.", "jana jindal yinyay nyajil | 3pl.NOM three.pronged.spear there see.NPST", "r286_3pl_artefact_tool_there_see_jindal", ["jana", "jindal", "yinyay", "nyajil"], EVIDENCE["jindal"]),
    row(49, "They see the pumice stone there.", "Jana jundi yinyay nyajil.", "jana jundi yinyay nyajil | 3pl.NOM pumice.stone there see.NPST", "r286_3pl_artefact_tool_there_see_jundi", ["jana", "jundi", "yinyay", "nyajil"], EVIDENCE["jundi"]),
    row(50, "They see the rope there.", "Jana karra yinyay nyajil.", "jana karra yinyay nyajil | 3pl.NOM rope there see.NPST", "r286_3pl_artefact_tool_there_see_karra", ["jana", "karra", "yinyay", "nyajil"], EVIDENCE["karra"]),
]

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 "nyajil" not in words or not lower_kuku.endswith(" nyajil."):
            issues.append(f"{seq}: missing final nyajil")
        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] != "nyajil":
            issues.append(f"{seq}: word 4 is not nyajil {words[3]}")
        if not frame.startswith("r286_"):
            issues.append(f"{seq}: frame not r286 {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", "nyajil"])
    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 ARTEFACT/TOOL NON-SINGULAR NONPAST PRONOUN PERCEPTION SWEEP AFTER RULE 285 "
        "(Rule 286). 50 under-review rows over badur hook, balji dilly bag, balur spear thrower, "
        "kaljan outrigger canoe, dajal fighting spear, dakilji cup, jidi torch, jindal three-pronged spear, "
        "jundi pumice stone, and karra rope. SUPPORT: bare nominative ngali, ngaliny, yubal, yurra, and jana, "
        "plus yaluy/yinyay and nyajil. Rule 286 inherits the final Rule 285 target set and does not reopen "
        "birungubay after Batch 231 duplicate pressure. Only bare visible object nonpast perception/reference rows "
        "are opened; fishing, making, material-source, canoe travel, rowing/paddling, spear throwing, fighting, "
        "biting, sharpening/rubbing, tying, fire/burning, post-contact loan objects, target case, pronoun case, "
        "demonstrative case, compounds, productive reduplication, past/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 286 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 visible artefact/tool targets: badur 256-268, balji 963-974, balur 1154-1170, kaljan 12560-12568, dajal 4499-4509, dakilji 4665-4676, jidi 8842-8851, jindal 9423-9433, jundi 10846-10857, karra 13534-13544. Reread Patz pronoun, non-singular, demonstrative, and nyaji-l nonpast support before authoring.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="construction-consolidation-scope", actor="claude-main", detail="Selected a justified nonpast consolidation of the Rule 285 visible artefact/tool field. Rule 286 inherits the final kaljan replacement target set and does not reopen birungubay after Batch 231 duplicate pressure.", 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="Final 50 Rule 286 nonpast surfaces over the Rule 285 artefact/tool target set returned no accepted, revised, or under-review collisions. Birungubay remains excluded by prior duplicate pressure.", 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 nyajil, no loans, no denied Kuku forms, no fishing/making/canoe-travel/spear-action/fire/use/case/compound drift.", command="python3 -m py_compile batch_scripts/bank_328.py && python3 -c \"import sys; sys.path.insert(0,'batch_scripts'); import bank_328; print(bank_328.scan_static())\"", output_excerpt="issues 0", artifact_path="batch_scripts/bank_328.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="claude-main", detail=f"Banked 50 Rule 286 rows as under_review. Verified total remains {verified_before}; Kuku word count remains {words_before}.", command="python3 batch_scripts/bank_328.py", output_excerpt=f"banked batch-328: 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-328: 50 rows under_review")
    return 0


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