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

TARGET_HEADS = {
    "bana": "water",
    "dajali": "deep water",
    "jalun": "sea",
    "jirka": "spring",
    "jukar": "sand",
    "manjal": "mountain",
    "wawubaja": "river",
    "yilki": "creek",
    "yiri": "waterfall",
    "yirri": "running water",
}
TARGET_ORDER = ["bana", "dajali", "jalun", "jirka", "jukar", "manjal", "wawubaja", "yilki", "yiri", "yirri"]
PRONOUN_SUPPORT = {
    "ngayu": "1sg.NOM",
    "yundu": "2sg.NOM",
    "nyulu": "3sg.NOM",
    "bula": "3du.NOM",
    "ngana": "1pl.INC.NOM",
}
SUPPORT = set(PRONOUN_SUPPORT) | {"yaluy", "yinyay", "nyajin"}
DENY_KUKU = {
    "banabila", "jalungkarr", "jirimandi", "marrka", "mukurr-mukurr", "yalkan", "yikin",
    "yirri-damal", "yiril", "yiman", "kalki", "kubirri", "bujung", "wawu", "wawu-balangaji",
    "bana-mani", "bana-daji", "nyajil", "nyaji-nka", "nyaji-nyaku", "nyaji-l-nyaji", "nyajiny",
    "nganya", "yununy", "yununiny", "nyunguny", "nyunguniny", "bulangan", "nganangan",
    "ngananiny", "ngananka", "ngananda", "nganandamuny", "ngananji", "ngananga", "ngaykunku",
    "yununku", "nyungunku", "ngaykundu", "yunundu", "nyungundu", "ngaykundumuny",
    "yunundumuny", "nyungundumuny", "ngaykunji", "yununji", "nyungunji", "ngayku", "yunu",
    "nyunju", "yinyangka", "yinyayngka", "yinyamba", "yinyamuny", "yalungku", "yaluyngku",
    "yaluymbu", "yaluyundu", "yalamuny", "yalanji",
}
DENY_ENGLISH = (
    "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", "story", "spirit",
    "fish", "shell", "snake", "crocodile", "plant", "tree", "ecology", "danger", "own", "owner",
    "source", "use", "uses", "used", "case", "compound", "watch", "look", "listening", "hearing",
    "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 = {
    "bana": "Dictionary lines 1264-1272 give bana as noun 'water'. Rule 276 selects visible water reference/perception only. Patz lines 2577-2586 and 2592-2603 source bare nominative pronouns; lines 2838-2845 source yaluy/yinyay; lines 2568-2571 give nyaji-ny see-PAST; and lines 3043-3049 source nyaji-l 'see'.",
    "dajali": "Dictionary lines 4510-4518 give dajali as noun 'deep water'. Rule 276 selects visible deep-water reference only.",
    "jalun": "Dictionary lines 7612-7620 give jalun as noun 'sea, large body of water'. Rule 276 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 276 selects visible water-source spring only, not season.",
    "jukar": "Dictionary lines 10254-10262 give jukar as noun 'sand'. Rule 276 selects visible sand reference only.",
    "manjal": "Dictionary lines 17832-17840 give manjal as noun 'mountain'. Rule 276 selects visible mountain reference only.",
    "wawubaja": "Dictionary lines 26813-26821 give wawubaja as noun 'river'. Rule 276 selects visible river reference only.",
    "yilki": "Dictionary lines 30031-30039 give yilki as noun 'creek'. Rule 276 selects visible creek reference only.",
    "yiri": "Dictionary lines 30410-30418 give yiri as noun 'waterfall'. Rule 276 selects visible waterfall reference only.",
    "yirri": "Dictionary lines 30507-30515 give yirri as noun 'running water'. Rule 276 selects visible running-water reference only and leaves yirri-damal 'leak' closed.",
}

ROWS = [
    row(1, "I saw the water here.", "Ngayu bana yaluy nyajin.", "ngayu bana yaluy nyajin | 1sg.NOM water here see.PAST", "r276_1sg_water_landform_here_saw_bana", ["ngayu", "bana", "yaluy", "nyajin"], EVIDENCE["bana"]),
    row(2, "I saw the deep water here.", "Ngayu dajali yaluy nyajin.", "ngayu dajali yaluy nyajin | 1sg.NOM deep.water here see.PAST", "r276_1sg_water_landform_here_saw_dajali", ["ngayu", "dajali", "yaluy", "nyajin"], EVIDENCE["dajali"]),
    row(3, "I saw the sea here.", "Ngayu jalun yaluy nyajin.", "ngayu jalun yaluy nyajin | 1sg.NOM sea here see.PAST", "r276_1sg_water_landform_here_saw_jalun", ["ngayu", "jalun", "yaluy", "nyajin"], EVIDENCE["jalun"]),
    row(4, "I saw the spring here.", "Ngayu jirka yaluy nyajin.", "ngayu jirka yaluy nyajin | 1sg.NOM spring here see.PAST", "r276_1sg_water_landform_here_saw_jirka", ["ngayu", "jirka", "yaluy", "nyajin"], EVIDENCE["jirka"]),
    row(5, "I saw the sand here.", "Ngayu jukar yaluy nyajin.", "ngayu jukar yaluy nyajin | 1sg.NOM sand here see.PAST", "r276_1sg_water_landform_here_saw_jukar", ["ngayu", "jukar", "yaluy", "nyajin"], EVIDENCE["jukar"]),
    row(6, "I saw the mountain here.", "Ngayu manjal yaluy nyajin.", "ngayu manjal yaluy nyajin | 1sg.NOM mountain here see.PAST", "r276_1sg_water_landform_here_saw_manjal", ["ngayu", "manjal", "yaluy", "nyajin"], EVIDENCE["manjal"]),
    row(7, "I saw the river here.", "Ngayu wawubaja yaluy nyajin.", "ngayu wawubaja yaluy nyajin | 1sg.NOM river here see.PAST", "r276_1sg_water_landform_here_saw_wawubaja", ["ngayu", "wawubaja", "yaluy", "nyajin"], EVIDENCE["wawubaja"]),
    row(8, "I saw the creek here.", "Ngayu yilki yaluy nyajin.", "ngayu yilki yaluy nyajin | 1sg.NOM creek here see.PAST", "r276_1sg_water_landform_here_saw_yilki", ["ngayu", "yilki", "yaluy", "nyajin"], EVIDENCE["yilki"]),
    row(9, "I saw the waterfall here.", "Ngayu yiri yaluy nyajin.", "ngayu yiri yaluy nyajin | 1sg.NOM waterfall here see.PAST", "r276_1sg_water_landform_here_saw_yiri", ["ngayu", "yiri", "yaluy", "nyajin"], EVIDENCE["yiri"]),
    row(10, "I saw the running water here.", "Ngayu yirri yaluy nyajin.", "ngayu yirri yaluy nyajin | 1sg.NOM running.water here see.PAST", "r276_1sg_water_landform_here_saw_yirri", ["ngayu", "yirri", "yaluy", "nyajin"], EVIDENCE["yirri"]),
    row(11, "You saw the water there.", "Yundu bana yinyay nyajin.", "yundu bana yinyay nyajin | 2sg.NOM water there see.PAST", "r276_2sg_water_landform_there_saw_bana", ["yundu", "bana", "yinyay", "nyajin"], EVIDENCE["bana"]),
    row(12, "You saw the deep water there.", "Yundu dajali yinyay nyajin.", "yundu dajali yinyay nyajin | 2sg.NOM deep.water there see.PAST", "r276_2sg_water_landform_there_saw_dajali", ["yundu", "dajali", "yinyay", "nyajin"], EVIDENCE["dajali"]),
    row(13, "You saw the sea there.", "Yundu jalun yinyay nyajin.", "yundu jalun yinyay nyajin | 2sg.NOM sea there see.PAST", "r276_2sg_water_landform_there_saw_jalun", ["yundu", "jalun", "yinyay", "nyajin"], EVIDENCE["jalun"]),
    row(14, "You saw the spring there.", "Yundu jirka yinyay nyajin.", "yundu jirka yinyay nyajin | 2sg.NOM spring there see.PAST", "r276_2sg_water_landform_there_saw_jirka", ["yundu", "jirka", "yinyay", "nyajin"], EVIDENCE["jirka"]),
    row(15, "You saw the sand there.", "Yundu jukar yinyay nyajin.", "yundu jukar yinyay nyajin | 2sg.NOM sand there see.PAST", "r276_2sg_water_landform_there_saw_jukar", ["yundu", "jukar", "yinyay", "nyajin"], EVIDENCE["jukar"]),
    row(16, "You saw the mountain there.", "Yundu manjal yinyay nyajin.", "yundu manjal yinyay nyajin | 2sg.NOM mountain there see.PAST", "r276_2sg_water_landform_there_saw_manjal", ["yundu", "manjal", "yinyay", "nyajin"], EVIDENCE["manjal"]),
    row(17, "You saw the river there.", "Yundu wawubaja yinyay nyajin.", "yundu wawubaja yinyay nyajin | 2sg.NOM river there see.PAST", "r276_2sg_water_landform_there_saw_wawubaja", ["yundu", "wawubaja", "yinyay", "nyajin"], EVIDENCE["wawubaja"]),
    row(18, "You saw the creek there.", "Yundu yilki yinyay nyajin.", "yundu yilki yinyay nyajin | 2sg.NOM creek there see.PAST", "r276_2sg_water_landform_there_saw_yilki", ["yundu", "yilki", "yinyay", "nyajin"], EVIDENCE["yilki"]),
    row(19, "You saw the waterfall there.", "Yundu yiri yinyay nyajin.", "yundu yiri yinyay nyajin | 2sg.NOM waterfall there see.PAST", "r276_2sg_water_landform_there_saw_yiri", ["yundu", "yiri", "yinyay", "nyajin"], EVIDENCE["yiri"]),
    row(20, "You saw the running water there.", "Yundu yirri yinyay nyajin.", "yundu yirri yinyay nyajin | 2sg.NOM running.water there see.PAST", "r276_2sg_water_landform_there_saw_yirri", ["yundu", "yirri", "yinyay", "nyajin"], EVIDENCE["yirri"]),
    row(21, "He saw the water here.", "Nyulu bana yaluy nyajin.", "nyulu bana yaluy nyajin | 3sg.NOM water here see.PAST", "r276_3sg_water_landform_here_saw_bana", ["nyulu", "bana", "yaluy", "nyajin"], EVIDENCE["bana"]),
    row(22, "He saw the deep water here.", "Nyulu dajali yaluy nyajin.", "nyulu dajali yaluy nyajin | 3sg.NOM deep.water here see.PAST", "r276_3sg_water_landform_here_saw_dajali", ["nyulu", "dajali", "yaluy", "nyajin"], EVIDENCE["dajali"]),
    row(23, "He saw the sea here.", "Nyulu jalun yaluy nyajin.", "nyulu jalun yaluy nyajin | 3sg.NOM sea here see.PAST", "r276_3sg_water_landform_here_saw_jalun", ["nyulu", "jalun", "yaluy", "nyajin"], EVIDENCE["jalun"]),
    row(24, "He saw the spring here.", "Nyulu jirka yaluy nyajin.", "nyulu jirka yaluy nyajin | 3sg.NOM spring here see.PAST", "r276_3sg_water_landform_here_saw_jirka", ["nyulu", "jirka", "yaluy", "nyajin"], EVIDENCE["jirka"]),
    row(25, "He saw the sand here.", "Nyulu jukar yaluy nyajin.", "nyulu jukar yaluy nyajin | 3sg.NOM sand here see.PAST", "r276_3sg_water_landform_here_saw_jukar", ["nyulu", "jukar", "yaluy", "nyajin"], EVIDENCE["jukar"]),
    row(26, "He saw the mountain here.", "Nyulu manjal yaluy nyajin.", "nyulu manjal yaluy nyajin | 3sg.NOM mountain here see.PAST", "r276_3sg_water_landform_here_saw_manjal", ["nyulu", "manjal", "yaluy", "nyajin"], EVIDENCE["manjal"]),
    row(27, "He saw the river here.", "Nyulu wawubaja yaluy nyajin.", "nyulu wawubaja yaluy nyajin | 3sg.NOM river here see.PAST", "r276_3sg_water_landform_here_saw_wawubaja", ["nyulu", "wawubaja", "yaluy", "nyajin"], EVIDENCE["wawubaja"]),
    row(28, "He saw the creek here.", "Nyulu yilki yaluy nyajin.", "nyulu yilki yaluy nyajin | 3sg.NOM creek here see.PAST", "r276_3sg_water_landform_here_saw_yilki", ["nyulu", "yilki", "yaluy", "nyajin"], EVIDENCE["yilki"]),
    row(29, "He saw the waterfall here.", "Nyulu yiri yaluy nyajin.", "nyulu yiri yaluy nyajin | 3sg.NOM waterfall here see.PAST", "r276_3sg_water_landform_here_saw_yiri", ["nyulu", "yiri", "yaluy", "nyajin"], EVIDENCE["yiri"]),
    row(30, "He saw the running water here.", "Nyulu yirri yaluy nyajin.", "nyulu yirri yaluy nyajin | 3sg.NOM running.water here see.PAST", "r276_3sg_water_landform_here_saw_yirri", ["nyulu", "yirri", "yaluy", "nyajin"], EVIDENCE["yirri"]),
    row(31, "The two of them saw the water there.", "Bula bana yinyay nyajin.", "bula bana yinyay nyajin | 3du.NOM water there see.PAST", "r276_3du_water_landform_there_saw_bana", ["bula", "bana", "yinyay", "nyajin"], EVIDENCE["bana"]),
    row(32, "The two of them saw the deep water there.", "Bula dajali yinyay nyajin.", "bula dajali yinyay nyajin | 3du.NOM deep.water there see.PAST", "r276_3du_water_landform_there_saw_dajali", ["bula", "dajali", "yinyay", "nyajin"], EVIDENCE["dajali"]),
    row(33, "The two of them saw the sea there.", "Bula jalun yinyay nyajin.", "bula jalun yinyay nyajin | 3du.NOM sea there see.PAST", "r276_3du_water_landform_there_saw_jalun", ["bula", "jalun", "yinyay", "nyajin"], EVIDENCE["jalun"]),
    row(34, "The two of them saw the spring there.", "Bula jirka yinyay nyajin.", "bula jirka yinyay nyajin | 3du.NOM spring there see.PAST", "r276_3du_water_landform_there_saw_jirka", ["bula", "jirka", "yinyay", "nyajin"], EVIDENCE["jirka"]),
    row(35, "The two of them saw the sand there.", "Bula jukar yinyay nyajin.", "bula jukar yinyay nyajin | 3du.NOM sand there see.PAST", "r276_3du_water_landform_there_saw_jukar", ["bula", "jukar", "yinyay", "nyajin"], EVIDENCE["jukar"]),
    row(36, "The two of them saw the mountain there.", "Bula manjal yinyay nyajin.", "bula manjal yinyay nyajin | 3du.NOM mountain there see.PAST", "r276_3du_water_landform_there_saw_manjal", ["bula", "manjal", "yinyay", "nyajin"], EVIDENCE["manjal"]),
    row(37, "The two of them saw the river there.", "Bula wawubaja yinyay nyajin.", "bula wawubaja yinyay nyajin | 3du.NOM river there see.PAST", "r276_3du_water_landform_there_saw_wawubaja", ["bula", "wawubaja", "yinyay", "nyajin"], EVIDENCE["wawubaja"]),
    row(38, "The two of them saw the creek there.", "Bula yilki yinyay nyajin.", "bula yilki yinyay nyajin | 3du.NOM creek there see.PAST", "r276_3du_water_landform_there_saw_yilki", ["bula", "yilki", "yinyay", "nyajin"], EVIDENCE["yilki"]),
    row(39, "The two of them saw the waterfall there.", "Bula yiri yinyay nyajin.", "bula yiri yinyay nyajin | 3du.NOM waterfall there see.PAST", "r276_3du_water_landform_there_saw_yiri", ["bula", "yiri", "yinyay", "nyajin"], EVIDENCE["yiri"]),
    row(40, "The two of them saw the running water there.", "Bula yirri yinyay nyajin.", "bula yirri yinyay nyajin | 3du.NOM running.water there see.PAST", "r276_3du_water_landform_there_saw_yirri", ["bula", "yirri", "yinyay", "nyajin"], EVIDENCE["yirri"]),
    row(41, "We saw the water there.", "Ngana bana yinyay nyajin.", "ngana bana yinyay nyajin | 1pl.INC.NOM water there see.PAST", "r276_1pl_incl_water_landform_there_saw_bana", ["ngana", "bana", "yinyay", "nyajin"], EVIDENCE["bana"]),
    row(42, "We saw the deep water there.", "Ngana dajali yinyay nyajin.", "ngana dajali yinyay nyajin | 1pl.INC.NOM deep.water there see.PAST", "r276_1pl_incl_water_landform_there_saw_dajali", ["ngana", "dajali", "yinyay", "nyajin"], EVIDENCE["dajali"]),
    row(43, "We saw the sea there.", "Ngana jalun yinyay nyajin.", "ngana jalun yinyay nyajin | 1pl.INC.NOM sea there see.PAST", "r276_1pl_incl_water_landform_there_saw_jalun", ["ngana", "jalun", "yinyay", "nyajin"], EVIDENCE["jalun"]),
    row(44, "We saw the spring there.", "Ngana jirka yinyay nyajin.", "ngana jirka yinyay nyajin | 1pl.INC.NOM spring there see.PAST", "r276_1pl_incl_water_landform_there_saw_jirka", ["ngana", "jirka", "yinyay", "nyajin"], EVIDENCE["jirka"]),
    row(45, "We saw the sand there.", "Ngana jukar yinyay nyajin.", "ngana jukar yinyay nyajin | 1pl.INC.NOM sand there see.PAST", "r276_1pl_incl_water_landform_there_saw_jukar", ["ngana", "jukar", "yinyay", "nyajin"], EVIDENCE["jukar"]),
    row(46, "We saw the mountain there.", "Ngana manjal yinyay nyajin.", "ngana manjal yinyay nyajin | 1pl.INC.NOM mountain there see.PAST", "r276_1pl_incl_water_landform_there_saw_manjal", ["ngana", "manjal", "yinyay", "nyajin"], EVIDENCE["manjal"]),
    row(47, "We saw the river there.", "Ngana wawubaja yinyay nyajin.", "ngana wawubaja yinyay nyajin | 1pl.INC.NOM river there see.PAST", "r276_1pl_incl_water_landform_there_saw_wawubaja", ["ngana", "wawubaja", "yinyay", "nyajin"], EVIDENCE["wawubaja"]),
    row(48, "We saw the creek there.", "Ngana yilki yinyay nyajin.", "ngana yilki yinyay nyajin | 1pl.INC.NOM creek there see.PAST", "r276_1pl_incl_water_landform_there_saw_yilki", ["ngana", "yilki", "yinyay", "nyajin"], EVIDENCE["yilki"]),
    row(49, "We saw the waterfall there.", "Ngana yiri yinyay nyajin.", "ngana yiri yinyay nyajin | 1pl.INC.NOM waterfall there see.PAST", "r276_1pl_incl_water_landform_there_saw_yiri", ["ngana", "yiri", "yinyay", "nyajin"], EVIDENCE["yiri"]),
    row(50, "We saw the running water there.", "Ngana yirri yinyay nyajin.", "ngana yirri yinyay nyajin | 1pl.INC.NOM running.water there see.PAST", "r276_1pl_incl_water_landform_there_saw_yirri", ["ngana", "yirri", "yinyay", "nyajin"], 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("r276_"):
            issues.append(f"{label}: frame must start with r276_")
        if " | " not in analysis or "see.PAST" not in analysis:
            issues.append(f"{label}: analysis missing gloss separator or see.PAST")
        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 " saw " not in f" {english_low} ":
            issues.append(f"{label}: English must use past 'saw'")
        if "nyajin" not in words or not low.endswith(" nyajin."):
            issues.append(f"{label}: row must end with nyajin")
        if 1 <= seq <= 10 and (not low.startswith("ngayu ") or not low.endswith(" yaluy nyajin.")):
            issues.append(f"{label}: rows 1-10 require Ngayu TARGET yaluy nyajin")
        if 11 <= seq <= 20 and (not low.startswith("yundu ") or not low.endswith(" yinyay nyajin.")):
            issues.append(f"{label}: rows 11-20 require Yundu TARGET yinyay nyajin")
        if 21 <= seq <= 30 and (not low.startswith("nyulu ") or not low.endswith(" yaluy nyajin.")):
            issues.append(f"{label}: rows 21-30 require Nyulu TARGET yaluy nyajin")
        if 31 <= seq <= 40 and (not low.startswith("bula ") or not low.endswith(" yinyay nyajin.")):
            issues.append(f"{label}: rows 31-40 require Bula TARGET yinyay nyajin")
        if 41 <= seq <= 50 and (not low.startswith("ngana ") or not low.endswith(" yinyay nyajin.")):
            issues.append(f"{label}: rows 41-50 require Ngana TARGET yinyay nyajin")
        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 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", "nyajin"]}
    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 PAST PRONOUN PERCEPTION SWEEP (Rule 276). 50 under-review rows over bana water, "
        "dajali deep water, jalun sea, jirka spring, jukar sand, manjal mountain, wawubaja river, yilki creek, "
        "yiri waterfall, and yirri running water. Only bare visual reference/perception rows are opened; drinking, "
        "getting, filling, washing, swimming, crossing, travel, route, flood, tide, salt-pan, whale-oil, spring-season, "
        "place names, mountain story, water source use, water spirits, fauna/flora/ecology, danger, ownership, target "
        "case, pronoun case, demonstrative case, target compounds, productive reduplication, perception compounds, and "
        "support inflection remain closed."
    )
    cur = db.execute(
        "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
        (LABEL, "Rule 276 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="Read dictionary entries for bana, dajali, jalun, jirka, jukar, manjal, wawubaja, yilki, yiri, and yirri plus Patz pronoun, demonstrative, and nyaji-l/nyaji-ny 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 visible water/landform targets only because they fit a visual nyajin frame; excluded water use, travel, route, place-name, flood/tide, ecology, source-use, and event prose.",
        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="Exact duplicate preflight over the final 50 Rule 276 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 nyajin, no loans, no denied Kuku forms, no water-use/travel/place-name/event/source-prose drift.",
        command="python3 -m py_compile batch_scripts/bank_318.py && python3 - <<'PY' import bank_318; print(bank_318.scan_static()) PY",
        output_excerpt="issues 0",
        artifact_path="batch_scripts/bank_318.py",
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="bank",
        event_type="bank-success",
        actor="claude-main",
        detail=f"Banked 50 Rule 276 rows as under_review. Verified total remains {verified_before}; Kuku word count remains {words_before}.",
        command="python3 batch_scripts/bank_318.py",
        output_excerpt=f"banked batch-318: 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-318: 50 rows under_review")
    return 0


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