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

TARGET_HEADS = {
    "mabil": "swamp",
    "karrirrangkal": "coral",
    "jalngarr": "flat rock",
    "jinali": "smooth rock",
    "kangku": "valley",
    "yalmba": "seashore",
    "kambal-kambal": "mud",
    "jalkar": "high bank",
    "janku": "hole",
    "jamba": "hillside",
}
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 = {
    # Earlier landform targets/rejected candidates and source-prose traps.
    "jalkaraburr", "yikin", "binda-dijarr", "duli", "jamar", "kabay", "karrangkal",
    "kuri", "ngamar", "nganyay", "ngidin", "warrmba", "damu", "naka", "kurrkal",
    "ngunnga", "nurru", "nyamun", "walba-murru", "bana", "yilki", "walngka",
    "yalmbar", "jalkar-jalkar", "kambal", "kangkul", "karrngka",
    # Non-selected supports and older Rule 232/233 frames.
    "yinya", "ngayu", "yundu", "nyulu", "ngana", "jana", "bula", "yulu", "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 fields remain closed.
    "baya", "jimal", "jirramar", "kubu", "kunjin", "miyilkura", "ngalku",
    "ngaluri", "ngunjil", "wula", "bakarr", "bayan", "bira", "jiji", "kilili",
    "wurun", "jakway", "yulal", "kararr", "bilangkurr", "kubija", "mujarrka",
    "barrbal", "wuyumbu", "bayil", "dalmbal", "balarri", "bilmbin", "jalkay",
    "jijirr", "birmba", "jamarbina", "nili-nili", "mabal", "wungku", "kuludu",
    "kururrungka", "karrambil", "yinjul", "kadanji",
}
DENY_ENGLISH = (
    "route", "travel", "traveled", "travelled", "go", "went", "come", "came",
    "cross", "crossing", "path", "track", "road", "river", "creek", "water",
    "waterhole", "reef", "sea", "tide", "beach", "collect", "collecting", "gather",
    "lime", "material", "source", "use", "using", "burn", "burning", "clear",
    "clearing", "live ant", "insect", "habitat", "ecology", "climb", "climbing",
    "fall", "falling", "danger", "dangerous", "own", "owner", "ownership",
    "dispute", "legal", "law", "social", "find", "finding", "peep", "causative",
    "rubbish", "debris", "leaf mould", "grow", "growing", "smooth out", "smooths",
    "steep", "mountain pass", "cheek", "body", "turtle", "food", "warning",
    "burrow", "nest", "dig", "digging", "ground oven", "root", "under tree",
    "case", "compound", "loan", "place name",
)


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.85")


EVIDENCE = {
    "mabil": "Dictionary mabil noun lines 17032-17038: gloss/definition/translation 'swamp'. Rule 244 keeps swamp reference/perception only. 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'.",
    "karrirrangkal": "Dictionary karrirrangkal noun lines 13616-13624: gloss 'coral', definition 'coral crushed for lime', translations coral/lime. Rule 244 selects coral only; lime/source-material, reef/sea, collecting, and use prose stay closed.",
    "jalngarr": "Dictionary jalngarr noun lines 7500-7506: gloss/definition/translation 'flat rock'. Rule 244 selects flat-rock reference/perception only; no sitting, creek, water, route, or event row.",
    "jinali": "Dictionary jinali noun lines 9391-9399: gloss/definition/translation 'smooth rock'. Rule 244 selects smooth-rock reference/perception only; no smooth-property predicate or smoothing-use row.",
    "kangku": "Dictionary kangku noun lines 13266-13275: gloss 'valley', definition 'low gap in mountain, mountain pass', translations valley/mountain pass. Rule 244 selects valley only and does not open route/travel or cheek/body-part drift.",
    "yalmba": "Dictionary yalmba noun lines 29078-29087: gloss 'seashore', definition 'seashore, beach', translations seashore/beach. Rule 244 selects seashore only; beach-collecting, sea/tide, turtle, food, and warning rows stay closed.",
    "kambal-kambal": "Dictionary kambal-kambal noun lines 12962-12975: gloss/definition/translation 'mud', lexical reduplicated form. Rule 244 keeps it as a whole headword and does not license productive reduplication from kambal.",
    "jalkar": "Dictionary jalkar noun lines 7429-7439: gloss/definition/translation 'high bank', with commentary cf. jalkar-jalkar 'steep'. Rule 244 selects high-bank reference only and leaves steep-property, route, river, and danger rows closed.",
    "janku": "Dictionary janku noun lines 8119-8127: gloss 'hole', definition 'hole in the ground', translation hole. Rule 244 selects hole only and leaves waterhole, burrow, nest, digging, ground-oven, and event rows closed.",
    "jamba": "Dictionary jamba noun lines 7690-7703: gloss/definition/translation 'hillside', with locative usage examples. Rule 244 selects the bare hillside head only and does not import locative case, root/under-tree, burning, social-metaphor, or event readings.",
}


ROWS = [
    row(1, "We two, not you, see the swamp here.", "Ngali mabil yaluy nyajil.", "ngali mabil yaluy nyajil | 1du.EXCL.NOM swamp here see.NPST", "r244_1du_excl_landform_here_see_mabil", ["ngali", "mabil", "yaluy", "nyajil"], EVIDENCE["mabil"]),
    row(2, "We two, not you, see the coral here.", "Ngali karrirrangkal yaluy nyajil.", "ngali karrirrangkal yaluy nyajil | 1du.EXCL.NOM coral here see.NPST", "r244_1du_excl_landform_here_see_karrirrangkal", ["ngali", "karrirrangkal", "yaluy", "nyajil"], EVIDENCE["karrirrangkal"]),
    row(3, "We two, not you, see the flat rock here.", "Ngali jalngarr yaluy nyajil.", "ngali jalngarr yaluy nyajil | 1du.EXCL.NOM flat.rock here see.NPST", "r244_1du_excl_landform_here_see_jalngarr", ["ngali", "jalngarr", "yaluy", "nyajil"], EVIDENCE["jalngarr"]),
    row(4, "We two, not you, see the smooth rock here.", "Ngali jinali yaluy nyajil.", "ngali jinali yaluy nyajil | 1du.EXCL.NOM smooth.rock here see.NPST", "r244_1du_excl_landform_here_see_jinali", ["ngali", "jinali", "yaluy", "nyajil"], EVIDENCE["jinali"]),
    row(5, "We two, not you, see the valley here.", "Ngali kangku yaluy nyajil.", "ngali kangku yaluy nyajil | 1du.EXCL.NOM valley here see.NPST", "r244_1du_excl_landform_here_see_kangku", ["ngali", "kangku", "yaluy", "nyajil"], EVIDENCE["kangku"]),
    row(6, "We two, not you, see the seashore here.", "Ngali yalmba yaluy nyajil.", "ngali yalmba yaluy nyajil | 1du.EXCL.NOM seashore here see.NPST", "r244_1du_excl_landform_here_see_yalmba", ["ngali", "yalmba", "yaluy", "nyajil"], EVIDENCE["yalmba"]),
    row(7, "We two, not you, see the mud here.", "Ngali kambal-kambal yaluy nyajil.", "ngali kambal-kambal yaluy nyajil | 1du.EXCL.NOM mud here see.NPST", "r244_1du_excl_landform_here_see_kambal_kambal", ["ngali", "kambal-kambal", "yaluy", "nyajil"], EVIDENCE["kambal-kambal"]),
    row(8, "We two, not you, see the high bank here.", "Ngali jalkar yaluy nyajil.", "ngali jalkar yaluy nyajil | 1du.EXCL.NOM high.bank here see.NPST", "r244_1du_excl_landform_here_see_jalkar", ["ngali", "jalkar", "yaluy", "nyajil"], EVIDENCE["jalkar"]),
    row(9, "We two, not you, see the hole here.", "Ngali janku yaluy nyajil.", "ngali janku yaluy nyajil | 1du.EXCL.NOM hole here see.NPST", "r244_1du_excl_landform_here_see_janku", ["ngali", "janku", "yaluy", "nyajil"], EVIDENCE["janku"]),
    row(10, "We two, not you, see the hillside here.", "Ngali jamba yaluy nyajil.", "ngali jamba yaluy nyajil | 1du.EXCL.NOM hillside here see.NPST", "r244_1du_excl_landform_here_see_jamba", ["ngali", "jamba", "yaluy", "nyajil"], EVIDENCE["jamba"]),
    row(11, "You and I see the swamp there.", "Ngaliny mabil yinyay nyajil.", "ngaliny mabil yinyay nyajil | 1du.INCL.NOM swamp there see.NPST", "r244_1du_incl_landform_there_see_mabil", ["ngaliny", "mabil", "yinyay", "nyajil"], EVIDENCE["mabil"]),
    row(12, "You and I see the coral there.", "Ngaliny karrirrangkal yinyay nyajil.", "ngaliny karrirrangkal yinyay nyajil | 1du.INCL.NOM coral there see.NPST", "r244_1du_incl_landform_there_see_karrirrangkal", ["ngaliny", "karrirrangkal", "yinyay", "nyajil"], EVIDENCE["karrirrangkal"]),
    row(13, "You and I see the flat rock there.", "Ngaliny jalngarr yinyay nyajil.", "ngaliny jalngarr yinyay nyajil | 1du.INCL.NOM flat.rock there see.NPST", "r244_1du_incl_landform_there_see_jalngarr", ["ngaliny", "jalngarr", "yinyay", "nyajil"], EVIDENCE["jalngarr"]),
    row(14, "You and I see the smooth rock there.", "Ngaliny jinali yinyay nyajil.", "ngaliny jinali yinyay nyajil | 1du.INCL.NOM smooth.rock there see.NPST", "r244_1du_incl_landform_there_see_jinali", ["ngaliny", "jinali", "yinyay", "nyajil"], EVIDENCE["jinali"]),
    row(15, "You and I see the valley there.", "Ngaliny kangku yinyay nyajil.", "ngaliny kangku yinyay nyajil | 1du.INCL.NOM valley there see.NPST", "r244_1du_incl_landform_there_see_kangku", ["ngaliny", "kangku", "yinyay", "nyajil"], EVIDENCE["kangku"]),
    row(16, "You and I see the seashore there.", "Ngaliny yalmba yinyay nyajil.", "ngaliny yalmba yinyay nyajil | 1du.INCL.NOM seashore there see.NPST", "r244_1du_incl_landform_there_see_yalmba", ["ngaliny", "yalmba", "yinyay", "nyajil"], EVIDENCE["yalmba"]),
    row(17, "You and I see the mud there.", "Ngaliny kambal-kambal yinyay nyajil.", "ngaliny kambal-kambal yinyay nyajil | 1du.INCL.NOM mud there see.NPST", "r244_1du_incl_landform_there_see_kambal_kambal", ["ngaliny", "kambal-kambal", "yinyay", "nyajil"], EVIDENCE["kambal-kambal"]),
    row(18, "You and I see the high bank there.", "Ngaliny jalkar yinyay nyajil.", "ngaliny jalkar yinyay nyajil | 1du.INCL.NOM high.bank there see.NPST", "r244_1du_incl_landform_there_see_jalkar", ["ngaliny", "jalkar", "yinyay", "nyajil"], EVIDENCE["jalkar"]),
    row(19, "You and I see the hole there.", "Ngaliny janku yinyay nyajil.", "ngaliny janku yinyay nyajil | 1du.INCL.NOM hole there see.NPST", "r244_1du_incl_landform_there_see_janku", ["ngaliny", "janku", "yinyay", "nyajil"], EVIDENCE["janku"]),
    row(20, "You and I see the hillside there.", "Ngaliny jamba yinyay nyajil.", "ngaliny jamba yinyay nyajil | 1du.INCL.NOM hillside there see.NPST", "r244_1du_incl_landform_there_see_jamba", ["ngaliny", "jamba", "yinyay", "nyajil"], EVIDENCE["jamba"]),
    row(21, "You two see the swamp here.", "Yubal mabil yaluy nyajil.", "yubal mabil yaluy nyajil | 2du.NOM swamp here see.NPST", "r244_2du_landform_here_see_mabil", ["yubal", "mabil", "yaluy", "nyajil"], EVIDENCE["mabil"]),
    row(22, "You two see the coral here.", "Yubal karrirrangkal yaluy nyajil.", "yubal karrirrangkal yaluy nyajil | 2du.NOM coral here see.NPST", "r244_2du_landform_here_see_karrirrangkal", ["yubal", "karrirrangkal", "yaluy", "nyajil"], EVIDENCE["karrirrangkal"]),
    row(23, "You two see the flat rock here.", "Yubal jalngarr yaluy nyajil.", "yubal jalngarr yaluy nyajil | 2du.NOM flat.rock here see.NPST", "r244_2du_landform_here_see_jalngarr", ["yubal", "jalngarr", "yaluy", "nyajil"], EVIDENCE["jalngarr"]),
    row(24, "You two see the smooth rock here.", "Yubal jinali yaluy nyajil.", "yubal jinali yaluy nyajil | 2du.NOM smooth.rock here see.NPST", "r244_2du_landform_here_see_jinali", ["yubal", "jinali", "yaluy", "nyajil"], EVIDENCE["jinali"]),
    row(25, "You two see the valley here.", "Yubal kangku yaluy nyajil.", "yubal kangku yaluy nyajil | 2du.NOM valley here see.NPST", "r244_2du_landform_here_see_kangku", ["yubal", "kangku", "yaluy", "nyajil"], EVIDENCE["kangku"]),
    row(26, "You two see the seashore here.", "Yubal yalmba yaluy nyajil.", "yubal yalmba yaluy nyajil | 2du.NOM seashore here see.NPST", "r244_2du_landform_here_see_yalmba", ["yubal", "yalmba", "yaluy", "nyajil"], EVIDENCE["yalmba"]),
    row(27, "You two see the mud here.", "Yubal kambal-kambal yaluy nyajil.", "yubal kambal-kambal yaluy nyajil | 2du.NOM mud here see.NPST", "r244_2du_landform_here_see_kambal_kambal", ["yubal", "kambal-kambal", "yaluy", "nyajil"], EVIDENCE["kambal-kambal"]),
    row(28, "You two see the high bank here.", "Yubal jalkar yaluy nyajil.", "yubal jalkar yaluy nyajil | 2du.NOM high.bank here see.NPST", "r244_2du_landform_here_see_jalkar", ["yubal", "jalkar", "yaluy", "nyajil"], EVIDENCE["jalkar"]),
    row(29, "You two see the hole here.", "Yubal janku yaluy nyajil.", "yubal janku yaluy nyajil | 2du.NOM hole here see.NPST", "r244_2du_landform_here_see_janku", ["yubal", "janku", "yaluy", "nyajil"], EVIDENCE["janku"]),
    row(30, "You two see the hillside here.", "Yubal jamba yaluy nyajil.", "yubal jamba yaluy nyajil | 2du.NOM hillside here see.NPST", "r244_2du_landform_here_see_jamba", ["yubal", "jamba", "yaluy", "nyajil"], EVIDENCE["jamba"]),
    row(31, "We all, not you, see the swamp there.", "Nganjin mabil yinyay nyajil.", "nganjin mabil yinyay nyajil | 1pl.EXCL.NOM swamp there see.NPST", "r244_1pl_excl_landform_there_see_mabil", ["nganjin", "mabil", "yinyay", "nyajil"], EVIDENCE["mabil"]),
    row(32, "We all, not you, see the coral there.", "Nganjin karrirrangkal yinyay nyajil.", "nganjin karrirrangkal yinyay nyajil | 1pl.EXCL.NOM coral there see.NPST", "r244_1pl_excl_landform_there_see_karrirrangkal", ["nganjin", "karrirrangkal", "yinyay", "nyajil"], EVIDENCE["karrirrangkal"]),
    row(33, "We all, not you, see the flat rock there.", "Nganjin jalngarr yinyay nyajil.", "nganjin jalngarr yinyay nyajil | 1pl.EXCL.NOM flat.rock there see.NPST", "r244_1pl_excl_landform_there_see_jalngarr", ["nganjin", "jalngarr", "yinyay", "nyajil"], EVIDENCE["jalngarr"]),
    row(34, "We all, not you, see the smooth rock there.", "Nganjin jinali yinyay nyajil.", "nganjin jinali yinyay nyajil | 1pl.EXCL.NOM smooth.rock there see.NPST", "r244_1pl_excl_landform_there_see_jinali", ["nganjin", "jinali", "yinyay", "nyajil"], EVIDENCE["jinali"]),
    row(35, "We all, not you, see the valley there.", "Nganjin kangku yinyay nyajil.", "nganjin kangku yinyay nyajil | 1pl.EXCL.NOM valley there see.NPST", "r244_1pl_excl_landform_there_see_kangku", ["nganjin", "kangku", "yinyay", "nyajil"], EVIDENCE["kangku"]),
    row(36, "We all, not you, see the seashore there.", "Nganjin yalmba yinyay nyajil.", "nganjin yalmba yinyay nyajil | 1pl.EXCL.NOM seashore there see.NPST", "r244_1pl_excl_landform_there_see_yalmba", ["nganjin", "yalmba", "yinyay", "nyajil"], EVIDENCE["yalmba"]),
    row(37, "We all, not you, see the mud there.", "Nganjin kambal-kambal yinyay nyajil.", "nganjin kambal-kambal yinyay nyajil | 1pl.EXCL.NOM mud there see.NPST", "r244_1pl_excl_landform_there_see_kambal_kambal", ["nganjin", "kambal-kambal", "yinyay", "nyajil"], EVIDENCE["kambal-kambal"]),
    row(38, "We all, not you, see the high bank there.", "Nganjin jalkar yinyay nyajil.", "nganjin jalkar yinyay nyajil | 1pl.EXCL.NOM high.bank there see.NPST", "r244_1pl_excl_landform_there_see_jalkar", ["nganjin", "jalkar", "yinyay", "nyajil"], EVIDENCE["jalkar"]),
    row(39, "We all, not you, see the hole there.", "Nganjin janku yinyay nyajil.", "nganjin janku yinyay nyajil | 1pl.EXCL.NOM hole there see.NPST", "r244_1pl_excl_landform_there_see_janku", ["nganjin", "janku", "yinyay", "nyajil"], EVIDENCE["janku"]),
    row(40, "We all, not you, see the hillside there.", "Nganjin jamba yinyay nyajil.", "nganjin jamba yinyay nyajil | 1pl.EXCL.NOM hillside there see.NPST", "r244_1pl_excl_landform_there_see_jamba", ["nganjin", "jamba", "yinyay", "nyajil"], EVIDENCE["jamba"]),
    row(41, "You all see the swamp here.", "Yurra mabil yaluy nyajil.", "yurra mabil yaluy nyajil | 2pl.NOM swamp here see.NPST", "r244_2pl_landform_here_see_mabil", ["yurra", "mabil", "yaluy", "nyajil"], EVIDENCE["mabil"]),
    row(42, "You all see the coral here.", "Yurra karrirrangkal yaluy nyajil.", "yurra karrirrangkal yaluy nyajil | 2pl.NOM coral here see.NPST", "r244_2pl_landform_here_see_karrirrangkal", ["yurra", "karrirrangkal", "yaluy", "nyajil"], EVIDENCE["karrirrangkal"]),
    row(43, "You all see the flat rock here.", "Yurra jalngarr yaluy nyajil.", "yurra jalngarr yaluy nyajil | 2pl.NOM flat.rock here see.NPST", "r244_2pl_landform_here_see_jalngarr", ["yurra", "jalngarr", "yaluy", "nyajil"], EVIDENCE["jalngarr"]),
    row(44, "You all see the smooth rock here.", "Yurra jinali yaluy nyajil.", "yurra jinali yaluy nyajil | 2pl.NOM smooth.rock here see.NPST", "r244_2pl_landform_here_see_jinali", ["yurra", "jinali", "yaluy", "nyajil"], EVIDENCE["jinali"]),
    row(45, "You all see the valley here.", "Yurra kangku yaluy nyajil.", "yurra kangku yaluy nyajil | 2pl.NOM valley here see.NPST", "r244_2pl_landform_here_see_kangku", ["yurra", "kangku", "yaluy", "nyajil"], EVIDENCE["kangku"]),
    row(46, "You all see the seashore here.", "Yurra yalmba yaluy nyajil.", "yurra yalmba yaluy nyajil | 2pl.NOM seashore here see.NPST", "r244_2pl_landform_here_see_yalmba", ["yurra", "yalmba", "yaluy", "nyajil"], EVIDENCE["yalmba"]),
    row(47, "You all see the mud here.", "Yurra kambal-kambal yaluy nyajil.", "yurra kambal-kambal yaluy nyajil | 2pl.NOM mud here see.NPST", "r244_2pl_landform_here_see_kambal_kambal", ["yurra", "kambal-kambal", "yaluy", "nyajil"], EVIDENCE["kambal-kambal"]),
    row(48, "You all see the high bank here.", "Yurra jalkar yaluy nyajil.", "yurra jalkar yaluy nyajil | 2pl.NOM high.bank here see.NPST", "r244_2pl_landform_here_see_jalkar", ["yurra", "jalkar", "yaluy", "nyajil"], EVIDENCE["jalkar"]),
    row(49, "You all see the hole here.", "Yurra janku yaluy nyajil.", "yurra janku yaluy nyajil | 2pl.NOM hole here see.NPST", "r244_2pl_landform_here_see_janku", ["yurra", "janku", "yaluy", "nyajil"], EVIDENCE["janku"]),
    row(50, "You all see the hillside here.", "Yurra jamba yaluy nyajil.", "yurra jamba yaluy nyajil | 2pl.NOM hillside here see.NPST", "r244_2pl_landform_here_see_jamba", ["yurra", "jamba", "yaluy", "nyajil"], EVIDENCE["jamba"]),
]


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("r244_"):
            issues.append(f"{label}: Rule 244 frame must start with r244_")
        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 244 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 landform source-prose/action/use 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 244 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 244 source pass retained the ten Rule 232 landform/geography target nouns; checked dictionary entries and line evidence for mabil, karrirrangkal, jalngarr, jinali, kangku, yalmba, kambal-kambal, jalkar, janku, and jamba; 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 244 landform/geography pronoun expansion after Rule 243: same ten Rule 232 target nouns in five zero-collision nominative-pronoun perception bands. No new landform lexemes, target case, place-name, route, water-use, ecology, source-material, or event 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 243: mabil 11, karrirrangkal 11, jalngarr 13, jinali 13, kangku 12, yalmba 11, kambal-kambal 16, jalkar 23, janku 45, jamba 32; pronouns ngaliny 25, yubal 39, nganjin 41, yurra 84, ngali 91.",
        command="python3 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 244 landform/geography pronoun-expansion perception surfaces returned zero accepted, revised, or under-review collisions.",
        command="python3 batch_scripts/bank_286.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 244 target noun per row, exactly one selected bare nominative pronoun per row, no loans, no target suffixes, no excluded route/water-use/ecology/place-name/source-prose drift, no pronoun case, no perception compound, and five planned frame bands only.",
        command="python3 batch_scripts/bank_286.py",
        artifact_path="batch_scripts/bank_286.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 244 landform/geography pronoun-expansion perception rows as under_review.",
        command="python3 batch_scripts/bank_286.py",
        artifact_path="batch_scripts/bank_286.py",
        created_at=NOW,
    )
    db.commit()
    print(f"banked {LABEL}: 50 under_review rows")
    return 0


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