#!/usr/bin/env python3
"""Bank batch-322: Rule 280 complementary visible water/landform nonpast pronoun 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-322"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-322-visible-water-landform-complementary-nonpast-pronoun-perception-after-rule279-process.md"

TARGET_HEADS = {
    "dajali": "deep water",
    "jalun": "sea",
    "jirka": "spring",
    "bubu": "ground",
    "manjal": "mountain",
    "daburri": "swamp",
    "dulngku": "reef",
    "yilki": "creek",
    "yiri": "waterfall",
    "yirri": "running water",
}
TARGET_ORDER = ["dajali", "jalun", "jirka", "bubu", "manjal", "daburri", "dulngku", "yilki", "yiri", "yirri"]
PRONOUN_SUPPORT = {
    "ngayu": "1sg.NOM",
    "yundu": "2sg.NOM",
    "nyulu": "3sg.NOM",
    "bula": "3du.NOM",
    "ngana": "1pl.INCL.NOM",
}
SUPPORT = set(PRONOUN_SUPPORT) | {"yaluy", "yinyay", "nyajil"}
DENY_KUKU = {
    "bana", "wawubaja", "jukar", "banabila", "jalungkarr", "jirimandi", "marrka", "mukurr-mukurr",
    "yalkan", "yikin", "yirri-damal", "yiril", "yiman", "kalki", "kubirri", "bujung", "wawu-balangaji",
    "nganya", "yununy", "nyunguny", "bulangan", "nganangan", "nganiny", "ngaykunku", "yununku",
    "nyungunku", "bulanka", "ngananka", "ngaykundu", "yunundu", "nyungundu", "bulanda", "ngananda",
    "ngaykundumuny", "yunundumuny", "nyungundumuny", "bulandamuny", "nganandamuny", "ngaykunji",
    "yununji", "nyungunji", "bulanji", "ngananji", "ngayku", "yunu", "nyunju", "bulanga", "ngananga",
    "nyajin", "nyaji-ny", "nyaji-nka", "nyaji-l-nyaji", "bubujida", "bubungu", "bubumuny", "bububa",
    "yinyangka", "yinyayngka", "yinyamba", "yinyamuny", "yalungku", "yaluyngku", "yaluymbu",
    "yaluyundu", "yalamuny", "yalanji",
}
DENY_ENGLISH = (
    "saw", "look", "looked", "watch", "watched", "watching", "listen", "listening", "hearing", "heard",
    "drink", "drank", "drinking", "get ", "got ", "getting", "fill", "filled", "wash", "washed",
    "washing", "swim", "swam", "swimming", "cross", "crossed", "crossing", "travel", "route",
    "road", "flood", "tide", "salt pan", "whale oil", "season", "place", "country", "belong",
    "dirty", "dirt", "story", "spirit", "fish", "fishing", "shell", "snake", "crocodile", "plant",
    "tree", "ecology", "danger", "navigation", "own", "owner", "source", "use", "uses", "used",
    "case", "compound", "event",
)


def js(values: list[str]) -> str:
    return json.dumps(values, ensure_ascii=False)


def row(seq: int, english: str, kuku: str, analysis: str, frame: str, words: list[str], evidence: str) -> tuple:
    return (seq, english, kuku, analysis, frame, 3, js(words), js([]), evidence, "0.86")


EVIDENCE = {
    "dajali": "Dictionary lines 4510-4518 give dajali as noun 'deep water'. Rule 280 selects visible deep-water reference only. Patz lines 2577-2586 and 2592-2603 source bare nominative pronouns; lines 2678-2686 source bula/ngana distinctions; lines 2838-2845 source yaluy/yinyay; and lines 3043-3049 source nyaji-l 'see' nonpast.",
    "jalun": "Dictionary lines 7612-7620 give jalun as noun 'sea, large body of water'. Rule 280 selects sea reference only and leaves flood rows closed.",
    "jirka": "Dictionary lines 9803-9813 give jirka as noun 'spring' and commentary reads it as a water source rather than season. Rule 280 selects visible water-source spring only, not season.",
    "bubu": "Dictionary lines 3452-3470 give bubu as noun 'ground/earth' with a country/place extension. Rule 280 selects visible ground/earth only and leaves country/place/dirtiness extensions closed.",
    "manjal": "Dictionary lines 17832-17840 give manjal as noun 'mountain'. Rule 280 selects visible mountain reference only.",
    "daburri": "Dictionary lines 4428-4442 give daburri as noun 'swamp' and specifically brackish swamp water. Rule 280 selects visible swamp reference only.",
    "dulngku": "Dictionary lines 6520-6530 give dulngku as noun 'reef'. Rule 280 selects visible reef reference only.",
    "yilki": "Dictionary lines 30031-30039 give yilki as noun 'creek'. Rule 280 selects visible creek reference only.",
    "yiri": "Dictionary lines 30410-30418 give yiri as noun 'waterfall'. Rule 280 selects visible waterfall reference only.",
    "yirri": "Dictionary lines 30507-30515 give yirri as noun 'running water'. Rule 280 selects visible running-water reference only and leaves yirri-damal 'leak' closed.",
}

ROWS = [
    row(1, "I see the deep water there.", "Ngayu dajali yinyay nyajil.", "ngayu dajali yinyay nyajil | 1sg.NOM deep.water there see.NPST", "r280_1sg_water_landform_there_see_dajali", ["ngayu", "dajali", "yinyay", "nyajil"], EVIDENCE["dajali"]),
    row(2, "I see the sea there.", "Ngayu jalun yinyay nyajil.", "ngayu jalun yinyay nyajil | 1sg.NOM sea there see.NPST", "r280_1sg_water_landform_there_see_jalun", ["ngayu", "jalun", "yinyay", "nyajil"], EVIDENCE["jalun"]),
    row(3, "I see the spring there.", "Ngayu jirka yinyay nyajil.", "ngayu jirka yinyay nyajil | 1sg.NOM spring there see.NPST", "r280_1sg_water_landform_there_see_jirka", ["ngayu", "jirka", "yinyay", "nyajil"], EVIDENCE["jirka"]),
    row(4, "I see the ground there.", "Ngayu bubu yinyay nyajil.", "ngayu bubu yinyay nyajil | 1sg.NOM ground there see.NPST", "r280_1sg_water_landform_there_see_bubu", ["ngayu", "bubu", "yinyay", "nyajil"], EVIDENCE["bubu"]),
    row(5, "I see the mountain there.", "Ngayu manjal yinyay nyajil.", "ngayu manjal yinyay nyajil | 1sg.NOM mountain there see.NPST", "r280_1sg_water_landform_there_see_manjal", ["ngayu", "manjal", "yinyay", "nyajil"], EVIDENCE["manjal"]),
    row(6, "I see the swamp there.", "Ngayu daburri yinyay nyajil.", "ngayu daburri yinyay nyajil | 1sg.NOM swamp there see.NPST", "r280_1sg_water_landform_there_see_daburri", ["ngayu", "daburri", "yinyay", "nyajil"], EVIDENCE["daburri"]),
    row(7, "I see the reef there.", "Ngayu dulngku yinyay nyajil.", "ngayu dulngku yinyay nyajil | 1sg.NOM reef there see.NPST", "r280_1sg_water_landform_there_see_dulngku", ["ngayu", "dulngku", "yinyay", "nyajil"], EVIDENCE["dulngku"]),
    row(8, "I see the creek there.", "Ngayu yilki yinyay nyajil.", "ngayu yilki yinyay nyajil | 1sg.NOM creek there see.NPST", "r280_1sg_water_landform_there_see_yilki", ["ngayu", "yilki", "yinyay", "nyajil"], EVIDENCE["yilki"]),
    row(9, "I see the waterfall there.", "Ngayu yiri yinyay nyajil.", "ngayu yiri yinyay nyajil | 1sg.NOM waterfall there see.NPST", "r280_1sg_water_landform_there_see_yiri", ["ngayu", "yiri", "yinyay", "nyajil"], EVIDENCE["yiri"]),
    row(10, "I see the running water there.", "Ngayu yirri yinyay nyajil.", "ngayu yirri yinyay nyajil | 1sg.NOM running.water there see.NPST", "r280_1sg_water_landform_there_see_yirri", ["ngayu", "yirri", "yinyay", "nyajil"], EVIDENCE["yirri"]),
    row(11, "You see the deep water here.", "Yundu dajali yaluy nyajil.", "yundu dajali yaluy nyajil | 2sg.NOM deep.water here see.NPST", "r280_2sg_water_landform_here_see_dajali", ["yundu", "dajali", "yaluy", "nyajil"], EVIDENCE["dajali"]),
    row(12, "You see the sea here.", "Yundu jalun yaluy nyajil.", "yundu jalun yaluy nyajil | 2sg.NOM sea here see.NPST", "r280_2sg_water_landform_here_see_jalun", ["yundu", "jalun", "yaluy", "nyajil"], EVIDENCE["jalun"]),
    row(13, "You see the spring here.", "Yundu jirka yaluy nyajil.", "yundu jirka yaluy nyajil | 2sg.NOM spring here see.NPST", "r280_2sg_water_landform_here_see_jirka", ["yundu", "jirka", "yaluy", "nyajil"], EVIDENCE["jirka"]),
    row(14, "You see the ground here.", "Yundu bubu yaluy nyajil.", "yundu bubu yaluy nyajil | 2sg.NOM ground here see.NPST", "r280_2sg_water_landform_here_see_bubu", ["yundu", "bubu", "yaluy", "nyajil"], EVIDENCE["bubu"]),
    row(15, "You see the mountain here.", "Yundu manjal yaluy nyajil.", "yundu manjal yaluy nyajil | 2sg.NOM mountain here see.NPST", "r280_2sg_water_landform_here_see_manjal", ["yundu", "manjal", "yaluy", "nyajil"], EVIDENCE["manjal"]),
    row(16, "You see the swamp here.", "Yundu daburri yaluy nyajil.", "yundu daburri yaluy nyajil | 2sg.NOM swamp here see.NPST", "r280_2sg_water_landform_here_see_daburri", ["yundu", "daburri", "yaluy", "nyajil"], EVIDENCE["daburri"]),
    row(17, "You see the reef here.", "Yundu dulngku yaluy nyajil.", "yundu dulngku yaluy nyajil | 2sg.NOM reef here see.NPST", "r280_2sg_water_landform_here_see_dulngku", ["yundu", "dulngku", "yaluy", "nyajil"], EVIDENCE["dulngku"]),
    row(18, "You see the creek here.", "Yundu yilki yaluy nyajil.", "yundu yilki yaluy nyajil | 2sg.NOM creek here see.NPST", "r280_2sg_water_landform_here_see_yilki", ["yundu", "yilki", "yaluy", "nyajil"], EVIDENCE["yilki"]),
    row(19, "You see the waterfall here.", "Yundu yiri yaluy nyajil.", "yundu yiri yaluy nyajil | 2sg.NOM waterfall here see.NPST", "r280_2sg_water_landform_here_see_yiri", ["yundu", "yiri", "yaluy", "nyajil"], EVIDENCE["yiri"]),
    row(20, "You see the running water here.", "Yundu yirri yaluy nyajil.", "yundu yirri yaluy nyajil | 2sg.NOM running.water here see.NPST", "r280_2sg_water_landform_here_see_yirri", ["yundu", "yirri", "yaluy", "nyajil"], EVIDENCE["yirri"]),
    row(21, "He sees the deep water there.", "Nyulu dajali yinyay nyajil.", "nyulu dajali yinyay nyajil | 3sg.NOM deep.water there see.NPST", "r280_3sg_water_landform_there_see_dajali", ["nyulu", "dajali", "yinyay", "nyajil"], EVIDENCE["dajali"]),
    row(22, "He sees the sea there.", "Nyulu jalun yinyay nyajil.", "nyulu jalun yinyay nyajil | 3sg.NOM sea there see.NPST", "r280_3sg_water_landform_there_see_jalun", ["nyulu", "jalun", "yinyay", "nyajil"], EVIDENCE["jalun"]),
    row(23, "He sees the spring there.", "Nyulu jirka yinyay nyajil.", "nyulu jirka yinyay nyajil | 3sg.NOM spring there see.NPST", "r280_3sg_water_landform_there_see_jirka", ["nyulu", "jirka", "yinyay", "nyajil"], EVIDENCE["jirka"]),
    row(24, "He sees the ground there.", "Nyulu bubu yinyay nyajil.", "nyulu bubu yinyay nyajil | 3sg.NOM ground there see.NPST", "r280_3sg_water_landform_there_see_bubu", ["nyulu", "bubu", "yinyay", "nyajil"], EVIDENCE["bubu"]),
    row(25, "He sees the mountain there.", "Nyulu manjal yinyay nyajil.", "nyulu manjal yinyay nyajil | 3sg.NOM mountain there see.NPST", "r280_3sg_water_landform_there_see_manjal", ["nyulu", "manjal", "yinyay", "nyajil"], EVIDENCE["manjal"]),
    row(26, "He sees the swamp there.", "Nyulu daburri yinyay nyajil.", "nyulu daburri yinyay nyajil | 3sg.NOM swamp there see.NPST", "r280_3sg_water_landform_there_see_daburri", ["nyulu", "daburri", "yinyay", "nyajil"], EVIDENCE["daburri"]),
    row(27, "He sees the reef there.", "Nyulu dulngku yinyay nyajil.", "nyulu dulngku yinyay nyajil | 3sg.NOM reef there see.NPST", "r280_3sg_water_landform_there_see_dulngku", ["nyulu", "dulngku", "yinyay", "nyajil"], EVIDENCE["dulngku"]),
    row(28, "He sees the creek there.", "Nyulu yilki yinyay nyajil.", "nyulu yilki yinyay nyajil | 3sg.NOM creek there see.NPST", "r280_3sg_water_landform_there_see_yilki", ["nyulu", "yilki", "yinyay", "nyajil"], EVIDENCE["yilki"]),
    row(29, "He sees the waterfall there.", "Nyulu yiri yinyay nyajil.", "nyulu yiri yinyay nyajil | 3sg.NOM waterfall there see.NPST", "r280_3sg_water_landform_there_see_yiri", ["nyulu", "yiri", "yinyay", "nyajil"], EVIDENCE["yiri"]),
    row(30, "He sees the running water there.", "Nyulu yirri yinyay nyajil.", "nyulu yirri yinyay nyajil | 3sg.NOM running.water there see.NPST", "r280_3sg_water_landform_there_see_yirri", ["nyulu", "yirri", "yinyay", "nyajil"], EVIDENCE["yirri"]),
    row(31, "The two of them see the deep water here.", "Bula dajali yaluy nyajil.", "bula dajali yaluy nyajil | 3du.NOM deep.water here see.NPST", "r280_3du_water_landform_here_see_dajali", ["bula", "dajali", "yaluy", "nyajil"], EVIDENCE["dajali"]),
    row(32, "The two of them see the sea here.", "Bula jalun yaluy nyajil.", "bula jalun yaluy nyajil | 3du.NOM sea here see.NPST", "r280_3du_water_landform_here_see_jalun", ["bula", "jalun", "yaluy", "nyajil"], EVIDENCE["jalun"]),
    row(33, "The two of them see the spring here.", "Bula jirka yaluy nyajil.", "bula jirka yaluy nyajil | 3du.NOM spring here see.NPST", "r280_3du_water_landform_here_see_jirka", ["bula", "jirka", "yaluy", "nyajil"], EVIDENCE["jirka"]),
    row(34, "The two of them see the ground here.", "Bula bubu yaluy nyajil.", "bula bubu yaluy nyajil | 3du.NOM ground here see.NPST", "r280_3du_water_landform_here_see_bubu", ["bula", "bubu", "yaluy", "nyajil"], EVIDENCE["bubu"]),
    row(35, "The two of them see the mountain here.", "Bula manjal yaluy nyajil.", "bula manjal yaluy nyajil | 3du.NOM mountain here see.NPST", "r280_3du_water_landform_here_see_manjal", ["bula", "manjal", "yaluy", "nyajil"], EVIDENCE["manjal"]),
    row(36, "The two of them see the swamp here.", "Bula daburri yaluy nyajil.", "bula daburri yaluy nyajil | 3du.NOM swamp here see.NPST", "r280_3du_water_landform_here_see_daburri", ["bula", "daburri", "yaluy", "nyajil"], EVIDENCE["daburri"]),
    row(37, "The two of them see the reef here.", "Bula dulngku yaluy nyajil.", "bula dulngku yaluy nyajil | 3du.NOM reef here see.NPST", "r280_3du_water_landform_here_see_dulngku", ["bula", "dulngku", "yaluy", "nyajil"], EVIDENCE["dulngku"]),
    row(38, "The two of them see the creek here.", "Bula yilki yaluy nyajil.", "bula yilki yaluy nyajil | 3du.NOM creek here see.NPST", "r280_3du_water_landform_here_see_yilki", ["bula", "yilki", "yaluy", "nyajil"], EVIDENCE["yilki"]),
    row(39, "The two of them see the waterfall here.", "Bula yiri yaluy nyajil.", "bula yiri yaluy nyajil | 3du.NOM waterfall here see.NPST", "r280_3du_water_landform_here_see_yiri", ["bula", "yiri", "yaluy", "nyajil"], EVIDENCE["yiri"]),
    row(40, "The two of them see the running water here.", "Bula yirri yaluy nyajil.", "bula yirri yaluy nyajil | 3du.NOM running.water here see.NPST", "r280_3du_water_landform_here_see_yirri", ["bula", "yirri", "yaluy", "nyajil"], EVIDENCE["yirri"]),
    row(41, "We see the deep water here.", "Ngana dajali yaluy nyajil.", "ngana dajali yaluy nyajil | 1pl.INCL.NOM deep.water here see.NPST", "r280_1pl_incl_water_landform_here_see_dajali", ["ngana", "dajali", "yaluy", "nyajil"], EVIDENCE["dajali"]),
    row(42, "We see the sea here.", "Ngana jalun yaluy nyajil.", "ngana jalun yaluy nyajil | 1pl.INCL.NOM sea here see.NPST", "r280_1pl_incl_water_landform_here_see_jalun", ["ngana", "jalun", "yaluy", "nyajil"], EVIDENCE["jalun"]),
    row(43, "We see the spring here.", "Ngana jirka yaluy nyajil.", "ngana jirka yaluy nyajil | 1pl.INCL.NOM spring here see.NPST", "r280_1pl_incl_water_landform_here_see_jirka", ["ngana", "jirka", "yaluy", "nyajil"], EVIDENCE["jirka"]),
    row(44, "We see the ground here.", "Ngana bubu yaluy nyajil.", "ngana bubu yaluy nyajil | 1pl.INCL.NOM ground here see.NPST", "r280_1pl_incl_water_landform_here_see_bubu", ["ngana", "bubu", "yaluy", "nyajil"], EVIDENCE["bubu"]),
    row(45, "We see the mountain here.", "Ngana manjal yaluy nyajil.", "ngana manjal yaluy nyajil | 1pl.INCL.NOM mountain here see.NPST", "r280_1pl_incl_water_landform_here_see_manjal", ["ngana", "manjal", "yaluy", "nyajil"], EVIDENCE["manjal"]),
    row(46, "We see the swamp here.", "Ngana daburri yaluy nyajil.", "ngana daburri yaluy nyajil | 1pl.INCL.NOM swamp here see.NPST", "r280_1pl_incl_water_landform_here_see_daburri", ["ngana", "daburri", "yaluy", "nyajil"], EVIDENCE["daburri"]),
    row(47, "We see the reef here.", "Ngana dulngku yaluy nyajil.", "ngana dulngku yaluy nyajil | 1pl.INCL.NOM reef here see.NPST", "r280_1pl_incl_water_landform_here_see_dulngku", ["ngana", "dulngku", "yaluy", "nyajil"], EVIDENCE["dulngku"]),
    row(48, "We see the creek here.", "Ngana yilki yaluy nyajil.", "ngana yilki yaluy nyajil | 1pl.INCL.NOM creek here see.NPST", "r280_1pl_incl_water_landform_here_see_yilki", ["ngana", "yilki", "yaluy", "nyajil"], EVIDENCE["yilki"]),
    row(49, "We see the waterfall here.", "Ngana yiri yaluy nyajil.", "ngana yiri yaluy nyajil | 1pl.INCL.NOM waterfall here see.NPST", "r280_1pl_incl_water_landform_here_see_yiri", ["ngana", "yiri", "yaluy", "nyajil"], EVIDENCE["yiri"]),
    row(50, "We see the running water here.", "Ngana yirri yaluy nyajil.", "ngana yirri yaluy nyajil | 1pl.INCL.NOM running.water here see.NPST", "r280_1pl_incl_water_landform_here_see_yirri", ["ngana", "yirri", "yaluy", "nyajil"], EVIDENCE["yirri"]),
]


def has_token(low: str, token: str) -> bool:
    return re.search(rf"(?<![a-z-]){re.escape(token)}(?![a-z-])", 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: set[str] = set()
    for expected, data in enumerate(ROWS, 1):
        seq, english, kuku, analysis, frame, _tier, words_used, loans_used, evidence, confidence = 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")
        if low in seen:
            issues.append(f"{label}: duplicate surface inside batch")
        seen.add(low)
        if not frame.startswith("r280_"):
            issues.append(f"{label}: frame must start with r280_")
        if " | " not in analysis or "see.NPST" not in analysis:
            issues.append(f"{label}: analysis missing gloss separator or see.NPST")
        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 one 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 re.search(rf"(?<![a-z-]){re.escape(head)}-[a-z]+", low):
                issues.append(f"{label}: target head {head} has forbidden suffix/compound")
        pronouns = [pronoun for pronoun in PRONOUN_SUPPORT if has_token(low, pronoun)]
        if len(pronouns) != 1:
            issues.append(f"{label}: expected one selected bare nominative pronoun, found {pronouns}")
        for support in SUPPORT:
            if has_token(low, support) and support not in words:
                issues.append(f"{label}: support {support} missing from words_used")
        if " see " not in f" {english_low} " and " sees " not in f" {english_low} ":
            issues.append(f"{label}: English must use nonpast 'see/sees'")
        if "nyajil" not in words or not low.endswith(" nyajil."):
            issues.append(f"{label}: row must end with nyajil")
        if 1 <= seq <= 10 and (not low.startswith("ngayu ") or not low.endswith(" yinyay nyajil.")):
            issues.append(f"{label}: rows 1-10 require Ngayu TARGET yinyay nyajil")
        if 11 <= seq <= 20 and (not low.startswith("yundu ") or not low.endswith(" yaluy nyajil.")):
            issues.append(f"{label}: rows 11-20 require Yundu TARGET yaluy nyajil")
        if 21 <= seq <= 30 and (not low.startswith("nyulu ") or not low.endswith(" yinyay nyajil.")):
            issues.append(f"{label}: rows 21-30 require Nyulu TARGET yinyay nyajil")
        if 31 <= seq <= 40 and (not low.startswith("bula ") or not low.endswith(" yaluy nyajil.")):
            issues.append(f"{label}: rows 31-40 require Bula TARGET yaluy nyajil")
        if 41 <= seq <= 50 and (not low.startswith("ngana ") or not low.endswith(" yaluy nyajil.")):
            issues.append(f"{label}: rows 41-50 require Ngana TARGET yaluy nyajil")
        if len(low.split()) != 4:
            issues.append(f"{label}: expected four Kuku tokens")
        if any(english_has_denied(english_low, bad) for bad in DENY_ENGLISH):
            issues.append(f"{label}: denied water/landform source-prose or tense field in English")
        if not evidence or not confidence:
            issues.append(f"{label}: missing evidence/confidence")
    return issues


def count_token(db: sqlite3.Connection, token: str) -> int:
    rows = db.execute("SELECT kuku FROM sentences WHERE status IN ('accepted','revised')").fetchall()
    return sum(1 for (kuku,) in rows if has_token(kuku.lower(), token))


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)
    if db.execute("SELECT 1 FROM batches WHERE label=?", (LABEL,)).fetchone():
        raise SystemExit(f"{LABEL} already exists")
    duplicates = []
    for _seq, _english, kuku, *_rest in ROWS:
        hit = 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,),
        ).fetchone()
        if hit:
            duplicates.append((kuku, hit))
    if duplicates:
        for kuku, hit in duplicates:
            print(f"duplicate: {kuku} -> {hit}")
        raise SystemExit(f"{LABEL}: duplicate preflight failed")

    target_counts = {head: count_token(db, head) for head in TARGET_ORDER}
    support_counts = {head: count_token(db, head) for head in ["ngayu", "yundu", "nyulu", "bula", "ngana", "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 WATER/LANDFORM COMPLEMENTARY NONPAST PRONOUN PERCEPTION SWEEP (Rule 280). 50 under-review rows "
        "over dajali deep water, jalun sea, jirka spring, bubu ground/earth, manjal mountain, daburri swamp, dulngku "
        "reef, yilki creek, yiri waterfall, and yirri running water with bare nominative ngayu, yundu, nyulu, bula, "
        "and ngana. Bana and wawubaja were excluded after exact duplicate pressure. Only bare visual reference/"
        "perception rows are opened; pronoun case, water use, travel, route, flood, tide, place names, source-use, "
        "bubu country/place extension, daburri ecology/use, dulngku fishing/navigation, target case, demonstrative "
        "case, compounds, productive reduplication, perception compounds, 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 280 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 water/landform targets including replacement daburri and dulngku, and Patz pronoun, 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="debt-sweep-scope", actor="claude-main", detail="Selected complementary-deictic nonpast counterpart to Rule 279. Rejected first bana/wawubaja candidate after Batch 194 duplicates and replaced them with sourced daburri swamp and dulngku reef.", 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: targets={target_counts}; support={support_counts}.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="duplicate-preflight", actor="claude-main", detail="Initial candidate found duplicates Ngayu bana yinyay nyajil. and Ngayu wawubaja yinyay nyajil. from Batch 194; final 50 Rule 280 surfaces returned no accepted, revised, or under-review collisions.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="static-guard-pass", actor="claude-main", detail="Static guard passed: 50 rows, one target each, bare nominative pronouns, bare yaluy/yinyay, final nyajil, no loans, no denied Kuku forms, no water-use/travel/place-name/bubu-country/daburri-ecology/dulngku-fishing drift.", command="python3 -m py_compile batch_scripts/bank_322.py && python3 - <<'PY' import bank_322; print(bank_322.scan_static()) PY", output_excerpt="issues 0", artifact_path="batch_scripts/bank_322.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="claude-main", detail=f"Banked 50 Rule 280 rows as under_review. Verified total remains {verified_before}; Kuku word count remains {words_before}.", command="python3 batch_scripts/bank_322.py", output_excerpt=f"banked batch-322: 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-322: 50 rows under_review")
    return 0


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