#!/usr/bin/env python3
"""Bank batch-298: Rule 256 insect complementary perception debt sweep."""

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-298"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-298-insect-complementary-perception-debt-sweep-after-rule255-process.md"

TARGET_HEADS = {
    "balarr": "flea",
    "dijaraban": "mayfly",
    "kalburiji": "kalburiji bee",
    "mawal": "mawal bee",
    "munudumbun": "scorpion",
    "munyurri": "sandfly",
    "nakawarra": "nakawarra bee",
    "ngalmnbu": "jumper ant",
    "yarrka": "yarrka bee",
    "yiljun": "grasshopper",
}
SUPPORT = {"ngayu", "nyulu", "yurra", "bula", "jana", "yaluy", "yinyay", "nyajil"}
PRONOUN_SUPPORT = {"ngayu", "nyulu", "yurra", "bula", "jana"}
DENY_KUKU = {
    # Rule 169-170 and Rule 222 insect/arthropod exclusions and alternate target sets.
    "biray", "kamay", "manukurru", "mindil", "murrmun", "murrumun",
    "muyu-muyu", "wurrarr-wurrarr", "yijil-yijin", "yinja-yinja",
    "kira-kira", "kandal", "kinga", "mulma", "biringal", "birinjil",
    "kurrmbal", "nganjamu", "kurran", "ngirran", "dabadaba", "daba-daba",
    "dujandujan", "dujan-dujan", "kalkamal", "karrkil", "kuran",
    "kurrmaja", "murma", "wurrbu", "nyumbil", "jawurraji", "jiljay",
    "jingka-jingka", "wurarr-wurarr", "munukurru", "diri-diri",
    # Behavior/use/ecology/body/source-prose drift.
    "bayka-l", "baykal", "jindal", "wunba", "bayan", "mayi", "bama",
    "juku", "bubu", "bana", "wukay", "badida", "kalbal", "dukunjaka",
    # Pronoun/demonstrative case, perception compounds, and support inflection.
    "nganya", "nyunguny", "yurrangan", "yurraniny", "yurranka", "yurranda",
    "yurranji", "yurranga", "bulangan", "bulaniny", "bulanka", "bulanda",
    "bulanji", "bulanga", "ianangan", "iananiny", "iananka", "iananda",
    "iananji", "iananga", "yinyangka", "yinyayngka", "yinyayanka",
    "yinyamba", "yinyayanda", "yinyamuny", "yinyamundu", "yinyanji",
    "yinyarriny", "yalungku", "yaluyngku", "yaluyunku", "yaluymbu",
    "yaluyundu", "yalamuny", "yalamundu", "yalanji", "nyaji-nka",
    "nyaji-nyaku", "nyaji-l-nyaji",
    # Recent closed domains.
    "bala", "darrba", "jarrabina", "jayju", "jungarr", "kukur", "mali",
    "murramu", "ngumbi", "yawa", "bajuy", "bilngkumu", "binanjal",
    "bindimu", "bubal", "jijirrbay", "kabul", "kalajarr", "kundurr",
    "yuday", "kubija", "mujarrka", "barrbal", "wuyumbu", "bayil",
    "dalmbal", "balarri", "bilmbin", "jalkay", "jijirr", "birmba",
    "jamarbina", "nili-nili", "mabal", "wungku", "kuludu", "kururrungka",
    "karrambil", "yinjul", "kadanji", "bakarr", "bayan", "bira", "jiji",
    "kilili", "wurun", "jakway", "yulal", "kararr", "bilangkurr", "baya",
    "jimal", "jirramar", "kubu", "kunjin", "miyilkura", "ngalku",
    "ngaluri", "ngunjil", "wula", "bandin", "bari", "bibar", "birri",
    "jiba", "jina", "maka", "milka", "nguman", "mabil", "karrirrangkal",
    "jalngarr", "jinali", "kangku", "yalmba", "kambal-kambal", "jalkar",
    "janku", "jamba",
}
DENY_ENGLISH = (
    "body", "human", "bite", "biting", "bitten", "sting", "stinging",
    "sick", "sickness", "vomit", "vomiting", "larva", "larvae", "egg",
    "eggs", "honey", "nest", "nests", "edible", "food", "eat", "eating",
    "medicine", "season", "seasonal", "collect", "collecting", "antbed",
    "ant bed", "anthill", "ant hill", "grub", "tree", "wood", "green wood",
    "mountain", "habitat", "pest", "control", "totem", "life-force",
    "dragonfly", "smallest", "bush", "ecology", "movement", "danger",
    "dangerous", "event", "yam", "singing", "song", "case", "compound",
    "reduplication", "support inflection", "plural", "many",
)


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 = {
    "balarr": "Dictionary lines 833-841 give balarr as noun 'flea', semantic domain fauna-insect; the human-body wording is source prose only. Patz grammar lines 2553-2603 source bare nominative pronouns, lines 2838-2845 source yaluy/yinyay, and lines 3043-3049 source nyaji-l 'see'.",
    "dijaraban": "Dictionary lines 5542-5551 give dijaraban as noun 'mayfly', definition/translations mayfly/dragonfly, semantic domain fauna-insect; Rule 256 selects mayfly only. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "kalburiji": "Dictionary lines 12474-12484 give kalburiji as noun 'bee', definition 'species of bee', semantic domain fauna-insect; Rule 256 selects kalburiji bee only and leaves honey/nest/egg/larvae readings closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "mawal": "Dictionary lines 18743-18753 give mawal as noun 'bee', definition 'species of bee', semantic domain fauna-insect; Rule 256 selects mawal bee only and leaves honey/nest/egg/larvae readings closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "munudumbun": "Dictionary lines 20816-20826 give munudumbun as noun 'scorpion', semantic domain fauna-insect, synonym munukurru; Rule 256 selects munudumbun only and leaves synonym/sting/sickness/fear/danger rows closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "munyurri": "Dictionary lines 20868-20889 give duplicate munyurri noun entries as 'sandfly', semantic domain fauna-insect, synonym diri-diri; Rule 256 selects munyurri only and leaves synonym/biting/sickness rows closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "nakawarra": "Dictionary lines 21461-21470 give nakawarra as noun 'species of bee', translations species of bee/bee, semantic domain fauna-insect; Rule 256 selects nakawarra bee only and leaves honey/nest/egg/larvae readings closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "ngalmnbu": "Dictionary lines 21972-21980 give ngalmnbu as noun 'jumper ant', semantic domain fauna-insect; Rule 256 selects jumper ant only and leaves jumping, biting, sting, antbed, and event readings closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "yarrka": "Dictionary lines 29551-29559 give yarrka as noun 'bee', definition 'bee, the smallest bee in the bush', semantic domain fauna-insect; Rule 256 selects yarrka bee only and leaves smallest/bush/ecology readings closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "yiljun": "Dictionary lines 30019-30029 give yiljun as noun 'grasshopper', definition 'type of grasshopper', with a singing/yam-readiness source usage; Rule 256 selects grasshopper only. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
}


ROWS = [
    row(1, "I see the flea here.", "Ngayu balarr yaluy nyajil.", "ngayu balarr yaluy nyajil | 1sg.NOM flea here see.NPST", "r256_1sg_target_here_see_balarr", ["ngayu", "balarr", "yaluy", "nyajil"], EVIDENCE["balarr"]),
    row(2, "I see the mayfly here.", "Ngayu dijaraban yaluy nyajil.", "ngayu dijaraban yaluy nyajil | 1sg.NOM mayfly here see.NPST", "r256_1sg_target_here_see_dijaraban", ["ngayu", "dijaraban", "yaluy", "nyajil"], EVIDENCE["dijaraban"]),
    row(3, "I see the kalburiji bee here.", "Ngayu kalburiji yaluy nyajil.", "ngayu kalburiji yaluy nyajil | 1sg.NOM kalburiji.bee here see.NPST", "r256_1sg_target_here_see_kalburiji", ["ngayu", "kalburiji", "yaluy", "nyajil"], EVIDENCE["kalburiji"]),
    row(4, "I see the mawal bee here.", "Ngayu mawal yaluy nyajil.", "ngayu mawal yaluy nyajil | 1sg.NOM mawal.bee here see.NPST", "r256_1sg_target_here_see_mawal", ["ngayu", "mawal", "yaluy", "nyajil"], EVIDENCE["mawal"]),
    row(5, "I see the scorpion here.", "Ngayu munudumbun yaluy nyajil.", "ngayu munudumbun yaluy nyajil | 1sg.NOM scorpion here see.NPST", "r256_1sg_target_here_see_munudumbun", ["ngayu", "munudumbun", "yaluy", "nyajil"], EVIDENCE["munudumbun"]),
    row(6, "I see the sandfly here.", "Ngayu munyurri yaluy nyajil.", "ngayu munyurri yaluy nyajil | 1sg.NOM sandfly here see.NPST", "r256_1sg_target_here_see_munyurri", ["ngayu", "munyurri", "yaluy", "nyajil"], EVIDENCE["munyurri"]),
    row(7, "I see the nakawarra bee here.", "Ngayu nakawarra yaluy nyajil.", "ngayu nakawarra yaluy nyajil | 1sg.NOM nakawarra.bee here see.NPST", "r256_1sg_target_here_see_nakawarra", ["ngayu", "nakawarra", "yaluy", "nyajil"], EVIDENCE["nakawarra"]),
    row(8, "I see the jumper ant here.", "Ngayu ngalmnbu yaluy nyajil.", "ngayu ngalmnbu yaluy nyajil | 1sg.NOM jumper.ant here see.NPST", "r256_1sg_target_here_see_ngalmnbu", ["ngayu", "ngalmnbu", "yaluy", "nyajil"], EVIDENCE["ngalmnbu"]),
    row(9, "I see the yarrka bee here.", "Ngayu yarrka yaluy nyajil.", "ngayu yarrka yaluy nyajil | 1sg.NOM yarrka.bee here see.NPST", "r256_1sg_target_here_see_yarrka", ["ngayu", "yarrka", "yaluy", "nyajil"], EVIDENCE["yarrka"]),
    row(10, "I see the grasshopper here.", "Ngayu yiljun yaluy nyajil.", "ngayu yiljun yaluy nyajil | 1sg.NOM grasshopper here see.NPST", "r256_1sg_target_here_see_yiljun", ["ngayu", "yiljun", "yaluy", "nyajil"], EVIDENCE["yiljun"]),
    row(11, "He sees the flea there.", "Nyulu balarr yinyay nyajil.", "nyulu balarr yinyay nyajil | 3sg.NOM flea there see.NPST", "r256_3sg_target_there_see_balarr", ["nyulu", "balarr", "yinyay", "nyajil"], EVIDENCE["balarr"]),
    row(12, "He sees the mayfly there.", "Nyulu dijaraban yinyay nyajil.", "nyulu dijaraban yinyay nyajil | 3sg.NOM mayfly there see.NPST", "r256_3sg_target_there_see_dijaraban", ["nyulu", "dijaraban", "yinyay", "nyajil"], EVIDENCE["dijaraban"]),
    row(13, "He sees the kalburiji bee there.", "Nyulu kalburiji yinyay nyajil.", "nyulu kalburiji yinyay nyajil | 3sg.NOM kalburiji.bee there see.NPST", "r256_3sg_target_there_see_kalburiji", ["nyulu", "kalburiji", "yinyay", "nyajil"], EVIDENCE["kalburiji"]),
    row(14, "He sees the mawal bee there.", "Nyulu mawal yinyay nyajil.", "nyulu mawal yinyay nyajil | 3sg.NOM mawal.bee there see.NPST", "r256_3sg_target_there_see_mawal", ["nyulu", "mawal", "yinyay", "nyajil"], EVIDENCE["mawal"]),
    row(15, "He sees the scorpion there.", "Nyulu munudumbun yinyay nyajil.", "nyulu munudumbun yinyay nyajil | 3sg.NOM scorpion there see.NPST", "r256_3sg_target_there_see_munudumbun", ["nyulu", "munudumbun", "yinyay", "nyajil"], EVIDENCE["munudumbun"]),
    row(16, "He sees the sandfly there.", "Nyulu munyurri yinyay nyajil.", "nyulu munyurri yinyay nyajil | 3sg.NOM sandfly there see.NPST", "r256_3sg_target_there_see_munyurri", ["nyulu", "munyurri", "yinyay", "nyajil"], EVIDENCE["munyurri"]),
    row(17, "He sees the nakawarra bee there.", "Nyulu nakawarra yinyay nyajil.", "nyulu nakawarra yinyay nyajil | 3sg.NOM nakawarra.bee there see.NPST", "r256_3sg_target_there_see_nakawarra", ["nyulu", "nakawarra", "yinyay", "nyajil"], EVIDENCE["nakawarra"]),
    row(18, "He sees the jumper ant there.", "Nyulu ngalmnbu yinyay nyajil.", "nyulu ngalmnbu yinyay nyajil | 3sg.NOM jumper.ant there see.NPST", "r256_3sg_target_there_see_ngalmnbu", ["nyulu", "ngalmnbu", "yinyay", "nyajil"], EVIDENCE["ngalmnbu"]),
    row(19, "He sees the yarrka bee there.", "Nyulu yarrka yinyay nyajil.", "nyulu yarrka yinyay nyajil | 3sg.NOM yarrka.bee there see.NPST", "r256_3sg_target_there_see_yarrka", ["nyulu", "yarrka", "yinyay", "nyajil"], EVIDENCE["yarrka"]),
    row(20, "He sees the grasshopper there.", "Nyulu yiljun yinyay nyajil.", "nyulu yiljun yinyay nyajil | 3sg.NOM grasshopper there see.NPST", "r256_3sg_target_there_see_yiljun", ["nyulu", "yiljun", "yinyay", "nyajil"], EVIDENCE["yiljun"]),
    row(21, "You all see the flea here.", "Yurra balarr yaluy nyajil.", "yurra balarr yaluy nyajil | 2pl.NOM flea here see.NPST", "r256_2pl_target_here_see_balarr", ["yurra", "balarr", "yaluy", "nyajil"], EVIDENCE["balarr"]),
    row(22, "You all see the mayfly here.", "Yurra dijaraban yaluy nyajil.", "yurra dijaraban yaluy nyajil | 2pl.NOM mayfly here see.NPST", "r256_2pl_target_here_see_dijaraban", ["yurra", "dijaraban", "yaluy", "nyajil"], EVIDENCE["dijaraban"]),
    row(23, "You all see the kalburiji bee here.", "Yurra kalburiji yaluy nyajil.", "yurra kalburiji yaluy nyajil | 2pl.NOM kalburiji.bee here see.NPST", "r256_2pl_target_here_see_kalburiji", ["yurra", "kalburiji", "yaluy", "nyajil"], EVIDENCE["kalburiji"]),
    row(24, "You all see the mawal bee here.", "Yurra mawal yaluy nyajil.", "yurra mawal yaluy nyajil | 2pl.NOM mawal.bee here see.NPST", "r256_2pl_target_here_see_mawal", ["yurra", "mawal", "yaluy", "nyajil"], EVIDENCE["mawal"]),
    row(25, "You all see the scorpion here.", "Yurra munudumbun yaluy nyajil.", "yurra munudumbun yaluy nyajil | 2pl.NOM scorpion here see.NPST", "r256_2pl_target_here_see_munudumbun", ["yurra", "munudumbun", "yaluy", "nyajil"], EVIDENCE["munudumbun"]),
    row(26, "You all see the sandfly here.", "Yurra munyurri yaluy nyajil.", "yurra munyurri yaluy nyajil | 2pl.NOM sandfly here see.NPST", "r256_2pl_target_here_see_munyurri", ["yurra", "munyurri", "yaluy", "nyajil"], EVIDENCE["munyurri"]),
    row(27, "You all see the nakawarra bee here.", "Yurra nakawarra yaluy nyajil.", "yurra nakawarra yaluy nyajil | 2pl.NOM nakawarra.bee here see.NPST", "r256_2pl_target_here_see_nakawarra", ["yurra", "nakawarra", "yaluy", "nyajil"], EVIDENCE["nakawarra"]),
    row(28, "You all see the jumper ant here.", "Yurra ngalmnbu yaluy nyajil.", "yurra ngalmnbu yaluy nyajil | 2pl.NOM jumper.ant here see.NPST", "r256_2pl_target_here_see_ngalmnbu", ["yurra", "ngalmnbu", "yaluy", "nyajil"], EVIDENCE["ngalmnbu"]),
    row(29, "You all see the yarrka bee here.", "Yurra yarrka yaluy nyajil.", "yurra yarrka yaluy nyajil | 2pl.NOM yarrka.bee here see.NPST", "r256_2pl_target_here_see_yarrka", ["yurra", "yarrka", "yaluy", "nyajil"], EVIDENCE["yarrka"]),
    row(30, "You all see the grasshopper here.", "Yurra yiljun yaluy nyajil.", "yurra yiljun yaluy nyajil | 2pl.NOM grasshopper here see.NPST", "r256_2pl_target_here_see_yiljun", ["yurra", "yiljun", "yaluy", "nyajil"], EVIDENCE["yiljun"]),
    row(31, "The two of them see the flea there.", "Bula balarr yinyay nyajil.", "bula balarr yinyay nyajil | 3du.NOM flea there see.NPST", "r256_3du_target_there_see_balarr", ["bula", "balarr", "yinyay", "nyajil"], EVIDENCE["balarr"]),
    row(32, "The two of them see the mayfly there.", "Bula dijaraban yinyay nyajil.", "bula dijaraban yinyay nyajil | 3du.NOM mayfly there see.NPST", "r256_3du_target_there_see_dijaraban", ["bula", "dijaraban", "yinyay", "nyajil"], EVIDENCE["dijaraban"]),
    row(33, "The two of them see the kalburiji bee there.", "Bula kalburiji yinyay nyajil.", "bula kalburiji yinyay nyajil | 3du.NOM kalburiji.bee there see.NPST", "r256_3du_target_there_see_kalburiji", ["bula", "kalburiji", "yinyay", "nyajil"], EVIDENCE["kalburiji"]),
    row(34, "The two of them see the mawal bee there.", "Bula mawal yinyay nyajil.", "bula mawal yinyay nyajil | 3du.NOM mawal.bee there see.NPST", "r256_3du_target_there_see_mawal", ["bula", "mawal", "yinyay", "nyajil"], EVIDENCE["mawal"]),
    row(35, "The two of them see the scorpion there.", "Bula munudumbun yinyay nyajil.", "bula munudumbun yinyay nyajil | 3du.NOM scorpion there see.NPST", "r256_3du_target_there_see_munudumbun", ["bula", "munudumbun", "yinyay", "nyajil"], EVIDENCE["munudumbun"]),
    row(36, "The two of them see the sandfly there.", "Bula munyurri yinyay nyajil.", "bula munyurri yinyay nyajil | 3du.NOM sandfly there see.NPST", "r256_3du_target_there_see_munyurri", ["bula", "munyurri", "yinyay", "nyajil"], EVIDENCE["munyurri"]),
    row(37, "The two of them see the nakawarra bee there.", "Bula nakawarra yinyay nyajil.", "bula nakawarra yinyay nyajil | 3du.NOM nakawarra.bee there see.NPST", "r256_3du_target_there_see_nakawarra", ["bula", "nakawarra", "yinyay", "nyajil"], EVIDENCE["nakawarra"]),
    row(38, "The two of them see the jumper ant there.", "Bula ngalmnbu yinyay nyajil.", "bula ngalmnbu yinyay nyajil | 3du.NOM jumper.ant there see.NPST", "r256_3du_target_there_see_ngalmnbu", ["bula", "ngalmnbu", "yinyay", "nyajil"], EVIDENCE["ngalmnbu"]),
    row(39, "The two of them see the yarrka bee there.", "Bula yarrka yinyay nyajil.", "bula yarrka yinyay nyajil | 3du.NOM yarrka.bee there see.NPST", "r256_3du_target_there_see_yarrka", ["bula", "yarrka", "yinyay", "nyajil"], EVIDENCE["yarrka"]),
    row(40, "The two of them see the grasshopper there.", "Bula yiljun yinyay nyajil.", "bula yiljun yinyay nyajil | 3du.NOM grasshopper there see.NPST", "r256_3du_target_there_see_yiljun", ["bula", "yiljun", "yinyay", "nyajil"], EVIDENCE["yiljun"]),
    row(41, "They see the flea here.", "Jana balarr yaluy nyajil.", "jana balarr yaluy nyajil | 3pl.NOM flea here see.NPST", "r256_3pl_target_here_see_balarr", ["jana", "balarr", "yaluy", "nyajil"], EVIDENCE["balarr"]),
    row(42, "They see the mayfly here.", "Jana dijaraban yaluy nyajil.", "jana dijaraban yaluy nyajil | 3pl.NOM mayfly here see.NPST", "r256_3pl_target_here_see_dijaraban", ["jana", "dijaraban", "yaluy", "nyajil"], EVIDENCE["dijaraban"]),
    row(43, "They see the kalburiji bee here.", "Jana kalburiji yaluy nyajil.", "jana kalburiji yaluy nyajil | 3pl.NOM kalburiji.bee here see.NPST", "r256_3pl_target_here_see_kalburiji", ["jana", "kalburiji", "yaluy", "nyajil"], EVIDENCE["kalburiji"]),
    row(44, "They see the mawal bee here.", "Jana mawal yaluy nyajil.", "jana mawal yaluy nyajil | 3pl.NOM mawal.bee here see.NPST", "r256_3pl_target_here_see_mawal", ["jana", "mawal", "yaluy", "nyajil"], EVIDENCE["mawal"]),
    row(45, "They see the scorpion here.", "Jana munudumbun yaluy nyajil.", "jana munudumbun yaluy nyajil | 3pl.NOM scorpion here see.NPST", "r256_3pl_target_here_see_munudumbun", ["jana", "munudumbun", "yaluy", "nyajil"], EVIDENCE["munudumbun"]),
    row(46, "They see the sandfly here.", "Jana munyurri yaluy nyajil.", "jana munyurri yaluy nyajil | 3pl.NOM sandfly here see.NPST", "r256_3pl_target_here_see_munyurri", ["jana", "munyurri", "yaluy", "nyajil"], EVIDENCE["munyurri"]),
    row(47, "They see the nakawarra bee here.", "Jana nakawarra yaluy nyajil.", "jana nakawarra yaluy nyajil | 3pl.NOM nakawarra.bee here see.NPST", "r256_3pl_target_here_see_nakawarra", ["jana", "nakawarra", "yaluy", "nyajil"], EVIDENCE["nakawarra"]),
    row(48, "They see the jumper ant here.", "Jana ngalmnbu yaluy nyajil.", "jana ngalmnbu yaluy nyajil | 3pl.NOM jumper.ant here see.NPST", "r256_3pl_target_here_see_ngalmnbu", ["jana", "ngalmnbu", "yaluy", "nyajil"], EVIDENCE["ngalmnbu"]),
    row(49, "They see the yarrka bee here.", "Jana yarrka yaluy nyajil.", "jana yarrka yaluy nyajil | 3pl.NOM yarrka.bee here see.NPST", "r256_3pl_target_here_see_yarrka", ["jana", "yarrka", "yaluy", "nyajil"], EVIDENCE["yarrka"]),
    row(50, "They see the grasshopper here.", "Jana yiljun yaluy nyajil.", "jana yiljun yaluy nyajil | 3pl.NOM grasshopper here see.NPST", "r256_3pl_target_here_see_yiljun", ["jana", "yiljun", "yaluy", "nyajil"], EVIDENCE["yiljun"]),
]


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("r256_"):
            issues.append(f"{label}: Rule 256 frame must start with r256_")
        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 256")
        for denied in DENY_KUKU:
            if has_token(low, denied):
                issues.append(f"{label}: denied carry-forward 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 Rule 256 target insect 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 bare nominative pronoun, found {pronouns}")
        if 1 <= seq <= 10 and (not low.startswith("ngayu ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 1-10 require Ngayu TARGET yaluy nyajil")
        if 11 <= seq <= 20 and (not low.startswith("nyulu ") or not low.endswith(" yinyay nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 11-20 require Nyulu TARGET yinyay nyajil")
        if 21 <= seq <= 30 and (not low.startswith("yurra ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 21-30 require Yurra TARGET yaluy nyajil")
        if 31 <= seq <= 40 and (not low.startswith("bula ") or not low.endswith(" yinyay nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 31-40 require Bula TARGET yinyay nyajil")
        if 41 <= seq <= 50 and (not low.startswith("jana ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 41-50 require Jana TARGET yaluy nyajil")
        if any(english_has_denied(english_low, bad) for bad in DENY_ENGLISH):
            issues.append(f"{label}: denied insect behavior/use/body/ecology/source-prose 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,))
        db.execute("UPDATE batches SET notes=?, created_at=? WHERE id=?", ("rebanked under_review", NOW, batch_id))
    else:
        db.execute(
            "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
            (LABEL, "Rule 256 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 256 source pass checked exact dictionary lines for balarr flea, dijaraban mayfly, kalburiji bee, mawal bee, munudumbun scorpion, munyurri sandfly, nakawarra bee, ngalmnbu jumper ant, yarrka bee, and yiljun grasshopper; Patz grammar lines 2553-2603 for bare nominative pronouns; lines 2838-2845 for yaluy/yinyay; and lines 3043-3049 for nyaji-l.",
        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 Rule 256 insect-reference complementary perception debt sweep after Rule 255: ten Rule 212 insect labels in the opposite zero-collision nominative-pronoun perception bands from Rule 255. All biting, stinging, sickness, honey, nest, egg, larvae, edible, food, medicine, seasonal-signal, ecology, body-part, source-prose, target-case, pronoun-case, demonstrative-case, and perception-compound semantics remain closed.",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="preflight",
        event_type="coverage-audit",
        actor="claude-main",
        detail="Pre-batch token-aware target coverage among accepted/revised rows after Rule 255: balarr 10, dijaraban 10, kalburiji 10, mawal 10, munudumbun 10, munyurri 10, nakawarra 10, ngalmnbu 10, yarrka 10, and yiljun 10. Support coverage: ngayu 1273, nyulu 1754, yurra 203, bula 183, jana 1476, yaluy 2243, yinyay 2506, nyajil 2617.",
        command="sqlite3 synthetic.db token-aware coverage audit",
        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 256 Kuku surfaces returned zero accepted, revised, or under-review collisions.",
        command="python3 batch_scripts/bank_298.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 256 target insect noun per row, exactly one bare nominative pronoun per row, no loans, no target suffixes, no excluded insect candidate, no behavior/use/ecology/body/source-prose drift, no pronoun case, no demonstrative case, no perception compound, and five planned complementary frame bands only.",
        command="python3 batch_scripts/bank_298.py",
        artifact_path="batch_scripts/bank_298.py",
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="bank",
        event_type="bank-success",
        actor="claude-main",
        detail="Banked 50 explicit hand-authored Rule 256 insect-reference complementary perception rows as under_review.",
        command="python3 batch_scripts/bank_298.py",
        artifact_path="batch_scripts/bank_298.py",
        created_at=NOW,
    )
    db.commit()
    print(f"banked {LABEL}: 50 under_review rows")
    return 0


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