#!/usr/bin/env python3
"""Bank batch-294: Rule 252 reptile/amphibian 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-294"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-294-reptile-amphibian-perception-debt-sweep-after-rule251-process.md"

TARGET_HEADS = {
    "bajuy": "lizard",
    "bilngkumu": "crocodile",
    "binanjal": "frill necked lizard",
    "bindimu": "black snake",
    "bubal": "tree snake",
    "jijirrbay": "whip snake",
    "kabul": "rock python",
    "kalajarr": "scrub goanna",
    "kundurr": "death adder",
    "yuday": "frog",
}
SUPPORT = {"ngayu", "nyulu", "yurra", "bula", "jana", "yaluy", "yinyay", "nyajil"}
PRONOUN_SUPPORT = {"ngayu", "nyulu", "yurra", "bula", "jana"}
DENY_KUKU = {
    # Rule 175-176 and Rule 220 hard reptile/amphibian exclusions.
    "banamu", "binju", "dukul-mukul", "jirabay", "junbirr", "kabuljaka",
    "kulmba-kulmba", "kurriyala", "ngawurr-ngawun", "ngumbul", "biwul",
    "bajabaja", "bajalji", "barka", "bilbil-bilbil", "jadi", "jalbil",
    "jarba", "jimalili", "jinkalmu", "kalkamuku", "karrkurr", "kungkun",
    "kundurr-kundurr", "kurmba-kurmba", "ngawiya", "ngujay", "walkarr",
    "yalnga", "yirku-yirku", "yuray",
    # Behavior/use/habitat/story/body-part drift.
    "badur", "bana", "bubu", "jalun", "juku", "kalka", "karrba", "kanya",
    "makarr", "mandurr", "munyun", "wawubaja", "yinba",
    # 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: fish, bird, dwelling, fire, body, landform/geography.
    "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 = (
    "hunt", "hunting", "hunter", "catch", "caught", "catching", "trap", "trapped",
    "kill", "killed", "bite", "biting", "poison", "poisonous", "venom", "danger",
    "dangerous", "fear", "frighten", "frightened", "harmless", "food", "edible",
    "eat", "eating", "ate", "meat", "cook", "cooked", "egg", "eggs", "skin",
    "scale", "body", "part", "habitat", "ecology", "water", "river", "sea", "swamp",
    "story", "story-site", "myth", "legend", "mythological", "place", "place-name",
    "firestick", "fighter", "bald", "hat", "chase", "chased", "split", "island",
    "tree-climbing", "climb", "domestic", "loan", "introduced", "mother-in-law",
    "avoidance", "red-bellied", "saltwater", "large frog", "colour", "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 = {
    "bajuy": "Dictionary lines 559-567 give bajuy as noun 'lizard', definition 'slippery lizard', semantic domain fauna-reptile; Rule 252 selects lizard only. Patz grammar lines 2553-2603 source bare nominative pronouns, lines 2838-2845 source yaluy/yinyay, and lines 3043-3049 source nyaji-l 'see'.",
    "bilngkumu": "Dictionary lines 2575-2585 give bilngkumu as noun 'crocodile' with salt-water source prose; Rule 252 selects crocodile only and leaves saltwater/habitat/danger rows closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source the support forms.",
    "binanjal": "Dictionary lines 2726-2734 give binanjal as noun 'frill necked lizard', semantic domain fauna-reptile. Rule 252 selects the animal label only. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source the frame.",
    "bindimu": "Dictionary lines 2884-2892 give bindimu as black snake and lines 2893-2901 give a red-bellied black-snake alternate; Rule 252 selects black snake only and leaves alternate/colour-predicate expansion closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "bubal": "Dictionary lines 3397-3408 give bubal as species of tree snake and lines 3409-3417 give tree snake; Rule 252 selects tree snake only and leaves tree/habitat/biting prose closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "jijirrbay": "Dictionary lines 8955-8963 and 8964-8972 give jijirrbay as noun 'whip snake', semantic domain fauna-reptile. Rule 252 selects whip snake only. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "kabul": "Dictionary lines 11816-11824 and 11825-11833 give kabul as noun 'rock python', semantic domain fauna-reptile. Rule 252 selects rock python only and leaves rock/place/action prose closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "kalajarr": "Dictionary lines 12243-12251 give kalajarr as noun 'scrub goanna', semantic domain fauna-reptile. Rule 252 selects scrub goanna only and leaves scrub/habitat/food/action prose closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "kundurr": "Dictionary lines 15704-15712 and 15713-15720 give kundurr as noun 'death adder', semantic domain fauna-reptile. Rule 252 selects death adder as a lexical label only and leaves danger/poison/biting prose closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
    "yuday": "Dictionary lines 30662-30670 give yuday as noun 'frog' with large/edible source prose; Rule 252 selects frog only and leaves edible/rain/swamp/event rows closed. Patz grammar lines 2553-2603, 2838-2845, and 3043-3049 source support.",
}


ROWS = [
    row(1, "I see the lizard there.", "Ngayu bajuy yinyay nyajil.", "ngayu bajuy yinyay nyajil | 1sg.NOM lizard there see.NPST", "r252_1sg_target_there_see_bajuy", ["ngayu", "bajuy", "yinyay", "nyajil"], EVIDENCE["bajuy"]),
    row(2, "I see the crocodile there.", "Ngayu bilngkumu yinyay nyajil.", "ngayu bilngkumu yinyay nyajil | 1sg.NOM crocodile there see.NPST", "r252_1sg_target_there_see_bilngkumu", ["ngayu", "bilngkumu", "yinyay", "nyajil"], EVIDENCE["bilngkumu"]),
    row(3, "I see the frill necked lizard there.", "Ngayu binanjal yinyay nyajil.", "ngayu binanjal yinyay nyajil | 1sg.NOM frill.necked.lizard there see.NPST", "r252_1sg_target_there_see_binanjal", ["ngayu", "binanjal", "yinyay", "nyajil"], EVIDENCE["binanjal"]),
    row(4, "I see the black snake there.", "Ngayu bindimu yinyay nyajil.", "ngayu bindimu yinyay nyajil | 1sg.NOM black.snake there see.NPST", "r252_1sg_target_there_see_bindimu", ["ngayu", "bindimu", "yinyay", "nyajil"], EVIDENCE["bindimu"]),
    row(5, "I see the tree snake there.", "Ngayu bubal yinyay nyajil.", "ngayu bubal yinyay nyajil | 1sg.NOM tree.snake there see.NPST", "r252_1sg_target_there_see_bubal", ["ngayu", "bubal", "yinyay", "nyajil"], EVIDENCE["bubal"]),
    row(6, "I see the whip snake there.", "Ngayu jijirrbay yinyay nyajil.", "ngayu jijirrbay yinyay nyajil | 1sg.NOM whip.snake there see.NPST", "r252_1sg_target_there_see_jijirrbay", ["ngayu", "jijirrbay", "yinyay", "nyajil"], EVIDENCE["jijirrbay"]),
    row(7, "I see the rock python there.", "Ngayu kabul yinyay nyajil.", "ngayu kabul yinyay nyajil | 1sg.NOM rock.python there see.NPST", "r252_1sg_target_there_see_kabul", ["ngayu", "kabul", "yinyay", "nyajil"], EVIDENCE["kabul"]),
    row(8, "I see the scrub goanna there.", "Ngayu kalajarr yinyay nyajil.", "ngayu kalajarr yinyay nyajil | 1sg.NOM scrub.goanna there see.NPST", "r252_1sg_target_there_see_kalajarr", ["ngayu", "kalajarr", "yinyay", "nyajil"], EVIDENCE["kalajarr"]),
    row(9, "I see the death adder there.", "Ngayu kundurr yinyay nyajil.", "ngayu kundurr yinyay nyajil | 1sg.NOM death.adder there see.NPST", "r252_1sg_target_there_see_kundurr", ["ngayu", "kundurr", "yinyay", "nyajil"], EVIDENCE["kundurr"]),
    row(10, "I see the frog there.", "Ngayu yuday yinyay nyajil.", "ngayu yuday yinyay nyajil | 1sg.NOM frog there see.NPST", "r252_1sg_target_there_see_yuday", ["ngayu", "yuday", "yinyay", "nyajil"], EVIDENCE["yuday"]),
    row(11, "He sees the lizard here.", "Nyulu bajuy yaluy nyajil.", "nyulu bajuy yaluy nyajil | 3sg.NOM lizard here see.NPST", "r252_3sg_target_here_see_bajuy", ["nyulu", "bajuy", "yaluy", "nyajil"], EVIDENCE["bajuy"]),
    row(12, "He sees the crocodile here.", "Nyulu bilngkumu yaluy nyajil.", "nyulu bilngkumu yaluy nyajil | 3sg.NOM crocodile here see.NPST", "r252_3sg_target_here_see_bilngkumu", ["nyulu", "bilngkumu", "yaluy", "nyajil"], EVIDENCE["bilngkumu"]),
    row(13, "He sees the frill necked lizard here.", "Nyulu binanjal yaluy nyajil.", "nyulu binanjal yaluy nyajil | 3sg.NOM frill.necked.lizard here see.NPST", "r252_3sg_target_here_see_binanjal", ["nyulu", "binanjal", "yaluy", "nyajil"], EVIDENCE["binanjal"]),
    row(14, "He sees the black snake here.", "Nyulu bindimu yaluy nyajil.", "nyulu bindimu yaluy nyajil | 3sg.NOM black.snake here see.NPST", "r252_3sg_target_here_see_bindimu", ["nyulu", "bindimu", "yaluy", "nyajil"], EVIDENCE["bindimu"]),
    row(15, "He sees the tree snake here.", "Nyulu bubal yaluy nyajil.", "nyulu bubal yaluy nyajil | 3sg.NOM tree.snake here see.NPST", "r252_3sg_target_here_see_bubal", ["nyulu", "bubal", "yaluy", "nyajil"], EVIDENCE["bubal"]),
    row(16, "He sees the whip snake here.", "Nyulu jijirrbay yaluy nyajil.", "nyulu jijirrbay yaluy nyajil | 3sg.NOM whip.snake here see.NPST", "r252_3sg_target_here_see_jijirrbay", ["nyulu", "jijirrbay", "yaluy", "nyajil"], EVIDENCE["jijirrbay"]),
    row(17, "He sees the rock python here.", "Nyulu kabul yaluy nyajil.", "nyulu kabul yaluy nyajil | 3sg.NOM rock.python here see.NPST", "r252_3sg_target_here_see_kabul", ["nyulu", "kabul", "yaluy", "nyajil"], EVIDENCE["kabul"]),
    row(18, "He sees the scrub goanna here.", "Nyulu kalajarr yaluy nyajil.", "nyulu kalajarr yaluy nyajil | 3sg.NOM scrub.goanna here see.NPST", "r252_3sg_target_here_see_kalajarr", ["nyulu", "kalajarr", "yaluy", "nyajil"], EVIDENCE["kalajarr"]),
    row(19, "He sees the death adder here.", "Nyulu kundurr yaluy nyajil.", "nyulu kundurr yaluy nyajil | 3sg.NOM death.adder here see.NPST", "r252_3sg_target_here_see_kundurr", ["nyulu", "kundurr", "yaluy", "nyajil"], EVIDENCE["kundurr"]),
    row(20, "He sees the frog here.", "Nyulu yuday yaluy nyajil.", "nyulu yuday yaluy nyajil | 3sg.NOM frog here see.NPST", "r252_3sg_target_here_see_yuday", ["nyulu", "yuday", "yaluy", "nyajil"], EVIDENCE["yuday"]),
    row(21, "You all see the lizard there.", "Yurra bajuy yinyay nyajil.", "yurra bajuy yinyay nyajil | 2pl.NOM lizard there see.NPST", "r252_2pl_target_there_see_bajuy", ["yurra", "bajuy", "yinyay", "nyajil"], EVIDENCE["bajuy"]),
    row(22, "You all see the crocodile there.", "Yurra bilngkumu yinyay nyajil.", "yurra bilngkumu yinyay nyajil | 2pl.NOM crocodile there see.NPST", "r252_2pl_target_there_see_bilngkumu", ["yurra", "bilngkumu", "yinyay", "nyajil"], EVIDENCE["bilngkumu"]),
    row(23, "You all see the frill necked lizard there.", "Yurra binanjal yinyay nyajil.", "yurra binanjal yinyay nyajil | 2pl.NOM frill.necked.lizard there see.NPST", "r252_2pl_target_there_see_binanjal", ["yurra", "binanjal", "yinyay", "nyajil"], EVIDENCE["binanjal"]),
    row(24, "You all see the black snake there.", "Yurra bindimu yinyay nyajil.", "yurra bindimu yinyay nyajil | 2pl.NOM black.snake there see.NPST", "r252_2pl_target_there_see_bindimu", ["yurra", "bindimu", "yinyay", "nyajil"], EVIDENCE["bindimu"]),
    row(25, "You all see the tree snake there.", "Yurra bubal yinyay nyajil.", "yurra bubal yinyay nyajil | 2pl.NOM tree.snake there see.NPST", "r252_2pl_target_there_see_bubal", ["yurra", "bubal", "yinyay", "nyajil"], EVIDENCE["bubal"]),
    row(26, "You all see the whip snake there.", "Yurra jijirrbay yinyay nyajil.", "yurra jijirrbay yinyay nyajil | 2pl.NOM whip.snake there see.NPST", "r252_2pl_target_there_see_jijirrbay", ["yurra", "jijirrbay", "yinyay", "nyajil"], EVIDENCE["jijirrbay"]),
    row(27, "You all see the rock python there.", "Yurra kabul yinyay nyajil.", "yurra kabul yinyay nyajil | 2pl.NOM rock.python there see.NPST", "r252_2pl_target_there_see_kabul", ["yurra", "kabul", "yinyay", "nyajil"], EVIDENCE["kabul"]),
    row(28, "You all see the scrub goanna there.", "Yurra kalajarr yinyay nyajil.", "yurra kalajarr yinyay nyajil | 2pl.NOM scrub.goanna there see.NPST", "r252_2pl_target_there_see_kalajarr", ["yurra", "kalajarr", "yinyay", "nyajil"], EVIDENCE["kalajarr"]),
    row(29, "You all see the death adder there.", "Yurra kundurr yinyay nyajil.", "yurra kundurr yinyay nyajil | 2pl.NOM death.adder there see.NPST", "r252_2pl_target_there_see_kundurr", ["yurra", "kundurr", "yinyay", "nyajil"], EVIDENCE["kundurr"]),
    row(30, "You all see the frog there.", "Yurra yuday yinyay nyajil.", "yurra yuday yinyay nyajil | 2pl.NOM frog there see.NPST", "r252_2pl_target_there_see_yuday", ["yurra", "yuday", "yinyay", "nyajil"], EVIDENCE["yuday"]),
    row(31, "The two of them see the lizard here.", "Bula bajuy yaluy nyajil.", "bula bajuy yaluy nyajil | 3du.NOM lizard here see.NPST", "r252_3du_target_here_see_bajuy", ["bula", "bajuy", "yaluy", "nyajil"], EVIDENCE["bajuy"]),
    row(32, "The two of them see the crocodile here.", "Bula bilngkumu yaluy nyajil.", "bula bilngkumu yaluy nyajil | 3du.NOM crocodile here see.NPST", "r252_3du_target_here_see_bilngkumu", ["bula", "bilngkumu", "yaluy", "nyajil"], EVIDENCE["bilngkumu"]),
    row(33, "The two of them see the frill necked lizard here.", "Bula binanjal yaluy nyajil.", "bula binanjal yaluy nyajil | 3du.NOM frill.necked.lizard here see.NPST", "r252_3du_target_here_see_binanjal", ["bula", "binanjal", "yaluy", "nyajil"], EVIDENCE["binanjal"]),
    row(34, "The two of them see the black snake here.", "Bula bindimu yaluy nyajil.", "bula bindimu yaluy nyajil | 3du.NOM black.snake here see.NPST", "r252_3du_target_here_see_bindimu", ["bula", "bindimu", "yaluy", "nyajil"], EVIDENCE["bindimu"]),
    row(35, "The two of them see the tree snake here.", "Bula bubal yaluy nyajil.", "bula bubal yaluy nyajil | 3du.NOM tree.snake here see.NPST", "r252_3du_target_here_see_bubal", ["bula", "bubal", "yaluy", "nyajil"], EVIDENCE["bubal"]),
    row(36, "The two of them see the whip snake here.", "Bula jijirrbay yaluy nyajil.", "bula jijirrbay yaluy nyajil | 3du.NOM whip.snake here see.NPST", "r252_3du_target_here_see_jijirrbay", ["bula", "jijirrbay", "yaluy", "nyajil"], EVIDENCE["jijirrbay"]),
    row(37, "The two of them see the rock python here.", "Bula kabul yaluy nyajil.", "bula kabul yaluy nyajil | 3du.NOM rock.python here see.NPST", "r252_3du_target_here_see_kabul", ["bula", "kabul", "yaluy", "nyajil"], EVIDENCE["kabul"]),
    row(38, "The two of them see the scrub goanna here.", "Bula kalajarr yaluy nyajil.", "bula kalajarr yaluy nyajil | 3du.NOM scrub.goanna here see.NPST", "r252_3du_target_here_see_kalajarr", ["bula", "kalajarr", "yaluy", "nyajil"], EVIDENCE["kalajarr"]),
    row(39, "The two of them see the death adder here.", "Bula kundurr yaluy nyajil.", "bula kundurr yaluy nyajil | 3du.NOM death.adder here see.NPST", "r252_3du_target_here_see_kundurr", ["bula", "kundurr", "yaluy", "nyajil"], EVIDENCE["kundurr"]),
    row(40, "The two of them see the frog here.", "Bula yuday yaluy nyajil.", "bula yuday yaluy nyajil | 3du.NOM frog here see.NPST", "r252_3du_target_here_see_yuday", ["bula", "yuday", "yaluy", "nyajil"], EVIDENCE["yuday"]),
    row(41, "They see the lizard there.", "Jana bajuy yinyay nyajil.", "jana bajuy yinyay nyajil | 3pl.NOM lizard there see.NPST", "r252_3pl_target_there_see_bajuy", ["jana", "bajuy", "yinyay", "nyajil"], EVIDENCE["bajuy"]),
    row(42, "They see the crocodile there.", "Jana bilngkumu yinyay nyajil.", "jana bilngkumu yinyay nyajil | 3pl.NOM crocodile there see.NPST", "r252_3pl_target_there_see_bilngkumu", ["jana", "bilngkumu", "yinyay", "nyajil"], EVIDENCE["bilngkumu"]),
    row(43, "They see the frill necked lizard there.", "Jana binanjal yinyay nyajil.", "jana binanjal yinyay nyajil | 3pl.NOM frill.necked.lizard there see.NPST", "r252_3pl_target_there_see_binanjal", ["jana", "binanjal", "yinyay", "nyajil"], EVIDENCE["binanjal"]),
    row(44, "They see the black snake there.", "Jana bindimu yinyay nyajil.", "jana bindimu yinyay nyajil | 3pl.NOM black.snake there see.NPST", "r252_3pl_target_there_see_bindimu", ["jana", "bindimu", "yinyay", "nyajil"], EVIDENCE["bindimu"]),
    row(45, "They see the tree snake there.", "Jana bubal yinyay nyajil.", "jana bubal yinyay nyajil | 3pl.NOM tree.snake there see.NPST", "r252_3pl_target_there_see_bubal", ["jana", "bubal", "yinyay", "nyajil"], EVIDENCE["bubal"]),
    row(46, "They see the whip snake there.", "Jana jijirrbay yinyay nyajil.", "jana jijirrbay yinyay nyajil | 3pl.NOM whip.snake there see.NPST", "r252_3pl_target_there_see_jijirrbay", ["jana", "jijirrbay", "yinyay", "nyajil"], EVIDENCE["jijirrbay"]),
    row(47, "They see the rock python there.", "Jana kabul yinyay nyajil.", "jana kabul yinyay nyajil | 3pl.NOM rock.python there see.NPST", "r252_3pl_target_there_see_kabul", ["jana", "kabul", "yinyay", "nyajil"], EVIDENCE["kabul"]),
    row(48, "They see the scrub goanna there.", "Jana kalajarr yinyay nyajil.", "jana kalajarr yinyay nyajil | 3pl.NOM scrub.goanna there see.NPST", "r252_3pl_target_there_see_kalajarr", ["jana", "kalajarr", "yinyay", "nyajil"], EVIDENCE["kalajarr"]),
    row(49, "They see the death adder there.", "Jana kundurr yinyay nyajil.", "jana kundurr yinyay nyajil | 3pl.NOM death.adder there see.NPST", "r252_3pl_target_there_see_kundurr", ["jana", "kundurr", "yinyay", "nyajil"], EVIDENCE["kundurr"]),
    row(50, "They see the frog there.", "Jana yuday yinyay nyajil.", "jana yuday yinyay nyajil | 3pl.NOM frog there see.NPST", "r252_3pl_target_there_see_yuday", ["jana", "yuday", "yinyay", "nyajil"], EVIDENCE["yuday"]),
]


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("r252_"):
            issues.append(f"{label}: Rule 252 frame must start with r252_")
        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 252")
        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 252 target reptile/amphibian 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(" yinyay nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 1-10 require Ngayu TARGET yinyay nyajil")
        if 11 <= seq <= 20 and (not low.startswith("nyulu ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 11-20 require Nyulu TARGET yaluy nyajil")
        if 21 <= seq <= 30 and (not low.startswith("yurra ") or not low.endswith(" yinyay nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 21-30 require Yurra TARGET yinyay nyajil")
        if 31 <= seq <= 40 and (not low.startswith("bula ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 31-40 require Bula TARGET yaluy nyajil")
        if 41 <= seq <= 50 and (not low.startswith("jana ") or not low.endswith(" yinyay nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 41-50 require Jana TARGET yinyay nyajil")
        if any(english_has_denied(english_low, bad) for bad in DENY_ENGLISH):
            issues.append(f"{label}: denied reptile/amphibian behavior/use/habitat/story/body-part/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,))
    else:
        db.execute(
            "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
            (LABEL, "Rule 252 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 252 source pass checked exact dictionary lines for bajuy lizard, bilngkumu crocodile, binanjal frill necked lizard, bindimu black snake, bubal tree snake, jijirrbay whip snake, kabul rock python, kalajarr scrub goanna, kundurr death adder, and yuday frog; 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 252 reptile/amphibian perception debt sweep after Rule 251: ten Rule 220 reptile/amphibian labels in five zero-collision nominative-pronoun perception bands. All behavior, danger, food, habitat, body-part, story, myth, colour-predicate, secondary-sense, 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 251: bajuy 13, bilngkumu 73, binanjal 9, bindimu 11, bubal 7, jijirrbay 7, kabul 23, kalajarr 9, kundurr 9, and yuday 17. Support coverage: ngayu 1246, nyulu 1767, yurra 180, bula 184, jana 2089, yaluy 2167, yinyay 2430, nyajil 2470.",
        command="python3 dictionary/corpus 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 252 Kuku surfaces returned zero accepted, revised, or under-review collisions.",
        command="python3 batch_scripts/bank_294.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 252 target reptile/amphibian noun per row, exactly one bare nominative pronoun per row, no loans, no target suffixes, no excluded reptile/amphibian candidate, no behavior/use/habitat/story/body-part/source-prose drift, no pronoun case, no demonstrative case, no perception compound, and five planned frame bands only.",
        command="python3 batch_scripts/bank_294.py",
        artifact_path="batch_scripts/bank_294.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 252 reptile/amphibian perception rows as under_review.",
        command="python3 batch_scripts/bank_294.py",
        artifact_path="batch_scripts/bank_294.py",
        created_at=NOW,
    )
    db.commit()
    print(f"banked {LABEL}: 50 under_review rows")
    return 0


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