#!/usr/bin/env python3
"""Bank batch-352: Rule 310 zero-count visible tree/palm singular/third-person nonpast 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-352"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-352-zero-count-tree-palm-singular-third-nonpast-perception-after-rule309-process.md"

TARGET_EVIDENCE = {
    "dulmbi": "Dictionary yaml lines 6478-6490 give dulmbi as noun 'umbrella palm' and also a place name at Stucky's Gap. Rule 310 selects visible umbrella-palm reference only and leaves place-name use closed.",
    "kakaji": "Dictionary yaml lines 12087-12098 give kakaji as noun 'mangrove tree'. Rule 310 selects visible kakaji mangrove-tree reference only and leaves shore, tide, sea-nursery, fruit, use, and ecology rows closed.",
    "mukukanka": "Dictionary yaml lines 20286-20300 give mukukanka as noun 'tree' with source prose about edible fruit. Rule 310 selects visible mukukanka-tree reference only and leaves fruit, edible, food, season, and use rows closed.",
    "murrkul": "Dictionary yaml lines 21058-21070 give murrkul as noun 'tree' with source prose about edible fruit. Rule 310 selects visible murrkul-tree reference only and leaves fruit, edible, food, seed, season, and use rows closed.",
    "milbarkal": "Dictionary yaml lines 18981-18990 give milbarkal as noun 'tree', English name unknown. Rule 310 selects visible milbarkal-tree reference only.",
    "mirrbangku": "Dictionary yaml lines 19739-19760 give mirrbangku as noun 'tree' / 'pencil cedar' with source prose about date-shaped sweet fruit. Rule 310 selects visible pencil-cedar-tree reference only and leaves fruit, date-shape, sweetness, and food rows closed.",
    "mura": "Dictionary yaml lines 20890-20910 give mura as noun 'tree', including source prose that blooming marks the time for minya jalan. Rule 310 selects visible mura-tree reference only and leaves bloom, seasonal timing, minya jalan, and event rows closed.",
    "ngadil": "Dictionary yaml lines 21677-21697 give ngadil as noun 'tree' / 'hickory' with source prose about good timber for woomeras. Rule 310 selects visible hickory-tree reference only and leaves timber, woomera, and material-use rows closed.",
    "nyumbil": "Dictionary yaml lines 24727-24748 give nyumbil as noun 'tree' / 'coolibah tree', with a separate homographic leech entry. Rule 310 selects visible coolibah-tree reference only and leaves leech/fauna homograph rows closed.",
    "wankar": "Dictionary yaml lines 26184-26206 give wankar as noun 'tree' with source prose about water-side growth, red flowers, and a necklace made from seeds. Rule 310 selects visible wankar-tree reference only and leaves water-side ecology, flowers, seed, necklace, and artefact rows closed.",
}

SUPPORT_EVIDENCE = (
    "Living grammar pronoun table lines 2577-2582 source bare nominatives ngayu, yundu, nyulu, bula, and jana with "
    "non-nominative case forms separated in the same table; lines 2684-2686 discuss second/third-person historical "
    "forms and third-person jana/bula; demonstrative lines 2834-2845 source yaluy 'here' and yinyay 'there'; "
    "grammar lines 3043-3049 give nyaji-l as the non-past form of 'see'. Rule 310 uses only bare support forms and "
    "corpus-conventional nyajil as the surface of nyaji-l."
)

TARGET_ORDER = ["dulmbi", "kakaji", "mukukanka", "murrkul", "milbarkal", "mirrbangku", "mura", "ngadil", "nyumbil", "wankar"]
FRAME_SPECS = [
    ("ngayu", "yaluy"),
    ("yundu", "yinyay"),
    ("nyulu", "yaluy"),
    ("bula", "yinyay"),
    ("jana", "yaluy"),
]

DENY_KUKU = {
    "nganya", "yununy", "nyunguny", "yununiny", "nyunguniny", "ngaykunku", "yununku",
    "nyungunku", "ngaykundu", "yunundu", "nyungundu", "ngaykundumuny", "yunundumuny",
    "nyungundumuny", "ngaykunji", "yununji", "nyungunji", "ngayku", "yunu", "nyunju",
    "bulangan", "bulaniny", "bulanka", "bulanda", "bulandamuny", "bulanji", "bulanga",
    "ianangan", "iananiny", "iananka", "iananda", "ianandamuny", "iananji", "iananga",
    "yulu", "iana", "ngali", "ngaliny", "yubal", "yurra", "ngana", "nganjin",
    "bujabay", "jingajalka", "jirimandi", "julbal", "jungka", "karranda", "karrandal",
    "kawarr", "marril", "ngurrkul",
    "yalungku", "yaluyngku", "yinyangka", "yinyayngka", "yalamuny", "yinyamuny",
    "nyajin", "nyaji-ny", "nyaji-nka", "nyaji-l-nyaji", "milka", "baykal", "jalngkay",
}
DENY_ENGLISH = (
    "place", "stucky", "gap", "timber", "woomera", "woomeras", "dialect", "use", "used", "using",
    "fruit", "date", "sweet", "sweetness", "food", "edible", "bloom", "blooming", "season", "time",
    "minya", "jalan", "pair", "dual", "leech", "fauna", "water-side", "waterside", "water side",
    "ecology", "flower", "flowers", "seed", "seeds", "necklace", "string", "threaded", "artefact",
    "material", "source", "story", "red", "black",
)


def count_words(db: sqlite3.Connection, words: list[str]) -> dict[str, int]:
    return {
        word: db.execute(
            """
            SELECT COUNT(*)
            FROM sentences s
            WHERE s.status IN ('accepted','revised')
              AND EXISTS (SELECT 1 FROM json_each(s.words_used) WHERE value=?)
            """,
            (word,),
        ).fetchone()[0]
        for word in words
    }


def row(seq: int, english: str, kuku: str, analysis: str, frame: str, words: list[str]) -> tuple:
    target = words[1]
    evidence = f"{TARGET_EVIDENCE[target]} {SUPPORT_EVIDENCE}"
    return (seq, english, kuku, analysis, frame, 3, json.dumps(words, ensure_ascii=False), json.dumps([], ensure_ascii=False), evidence, "0.86")


ROWS = [
    row(1, "I see the dulmbi umbrella palm here.", "Ngayu dulmbi yaluy nyajil.", "ngayu dulmbi yaluy nyajil | 1sg.NOM dulmbi.umbrella.palm here see.NPST", "r310_1sg_here_zero_tree_see_dulmbi", ["ngayu", "dulmbi", "yaluy", "nyajil"]),
    row(2, "I see the kakaji mangrove tree here.", "Ngayu kakaji yaluy nyajil.", "ngayu kakaji yaluy nyajil | 1sg.NOM kakaji.mangrove.tree here see.NPST", "r310_1sg_here_zero_tree_see_kakaji", ["ngayu", "kakaji", "yaluy", "nyajil"]),
    row(3, "I see the mukukanka tree here.", "Ngayu mukukanka yaluy nyajil.", "ngayu mukukanka yaluy nyajil | 1sg.NOM mukukanka.tree here see.NPST", "r310_1sg_here_zero_tree_see_mukukanka", ["ngayu", "mukukanka", "yaluy", "nyajil"]),
    row(4, "I see the murrkul tree here.", "Ngayu murrkul yaluy nyajil.", "ngayu murrkul yaluy nyajil | 1sg.NOM murrkul.tree here see.NPST", "r310_1sg_here_zero_tree_see_murrkul", ["ngayu", "murrkul", "yaluy", "nyajil"]),
    row(5, "I see the milbarkal tree here.", "Ngayu milbarkal yaluy nyajil.", "ngayu milbarkal yaluy nyajil | 1sg.NOM milbarkal.tree here see.NPST", "r310_1sg_here_zero_tree_see_milbarkal", ["ngayu", "milbarkal", "yaluy", "nyajil"]),
    row(6, "I see the mirrbangku pencil cedar tree here.", "Ngayu mirrbangku yaluy nyajil.", "ngayu mirrbangku yaluy nyajil | 1sg.NOM mirrbangku.pencil.cedar.tree here see.NPST", "r310_1sg_here_zero_tree_see_mirrbangku", ["ngayu", "mirrbangku", "yaluy", "nyajil"]),
    row(7, "I see the mura tree here.", "Ngayu mura yaluy nyajil.", "ngayu mura yaluy nyajil | 1sg.NOM mura.tree here see.NPST", "r310_1sg_here_zero_tree_see_mura", ["ngayu", "mura", "yaluy", "nyajil"]),
    row(8, "I see the ngadil hickory tree here.", "Ngayu ngadil yaluy nyajil.", "ngayu ngadil yaluy nyajil | 1sg.NOM ngadil.hickory.tree here see.NPST", "r310_1sg_here_zero_tree_see_ngadil", ["ngayu", "ngadil", "yaluy", "nyajil"]),
    row(9, "I see the nyumbil coolibah tree here.", "Ngayu nyumbil yaluy nyajil.", "ngayu nyumbil yaluy nyajil | 1sg.NOM nyumbil.coolibah.tree here see.NPST", "r310_1sg_here_zero_tree_see_nyumbil", ["ngayu", "nyumbil", "yaluy", "nyajil"]),
    row(10, "I see the wankar tree here.", "Ngayu wankar yaluy nyajil.", "ngayu wankar yaluy nyajil | 1sg.NOM wankar.tree here see.NPST", "r310_1sg_here_zero_tree_see_wankar", ["ngayu", "wankar", "yaluy", "nyajil"]),
    row(11, "You see the dulmbi umbrella palm there.", "Yundu dulmbi yinyay nyajil.", "yundu dulmbi yinyay nyajil | 2sg.NOM dulmbi.umbrella.palm there see.NPST", "r310_2sg_there_zero_tree_see_dulmbi", ["yundu", "dulmbi", "yinyay", "nyajil"]),
    row(12, "You see the kakaji mangrove tree there.", "Yundu kakaji yinyay nyajil.", "yundu kakaji yinyay nyajil | 2sg.NOM kakaji.mangrove.tree there see.NPST", "r310_2sg_there_zero_tree_see_kakaji", ["yundu", "kakaji", "yinyay", "nyajil"]),
    row(13, "You see the mukukanka tree there.", "Yundu mukukanka yinyay nyajil.", "yundu mukukanka yinyay nyajil | 2sg.NOM mukukanka.tree there see.NPST", "r310_2sg_there_zero_tree_see_mukukanka", ["yundu", "mukukanka", "yinyay", "nyajil"]),
    row(14, "You see the murrkul tree there.", "Yundu murrkul yinyay nyajil.", "yundu murrkul yinyay nyajil | 2sg.NOM murrkul.tree there see.NPST", "r310_2sg_there_zero_tree_see_murrkul", ["yundu", "murrkul", "yinyay", "nyajil"]),
    row(15, "You see the milbarkal tree there.", "Yundu milbarkal yinyay nyajil.", "yundu milbarkal yinyay nyajil | 2sg.NOM milbarkal.tree there see.NPST", "r310_2sg_there_zero_tree_see_milbarkal", ["yundu", "milbarkal", "yinyay", "nyajil"]),
    row(16, "You see the mirrbangku pencil cedar tree there.", "Yundu mirrbangku yinyay nyajil.", "yundu mirrbangku yinyay nyajil | 2sg.NOM mirrbangku.pencil.cedar.tree there see.NPST", "r310_2sg_there_zero_tree_see_mirrbangku", ["yundu", "mirrbangku", "yinyay", "nyajil"]),
    row(17, "You see the mura tree there.", "Yundu mura yinyay nyajil.", "yundu mura yinyay nyajil | 2sg.NOM mura.tree there see.NPST", "r310_2sg_there_zero_tree_see_mura", ["yundu", "mura", "yinyay", "nyajil"]),
    row(18, "You see the ngadil hickory tree there.", "Yundu ngadil yinyay nyajil.", "yundu ngadil yinyay nyajil | 2sg.NOM ngadil.hickory.tree there see.NPST", "r310_2sg_there_zero_tree_see_ngadil", ["yundu", "ngadil", "yinyay", "nyajil"]),
    row(19, "You see the nyumbil coolibah tree there.", "Yundu nyumbil yinyay nyajil.", "yundu nyumbil yinyay nyajil | 2sg.NOM nyumbil.coolibah.tree there see.NPST", "r310_2sg_there_zero_tree_see_nyumbil", ["yundu", "nyumbil", "yinyay", "nyajil"]),
    row(20, "You see the wankar tree there.", "Yundu wankar yinyay nyajil.", "yundu wankar yinyay nyajil | 2sg.NOM wankar.tree there see.NPST", "r310_2sg_there_zero_tree_see_wankar", ["yundu", "wankar", "yinyay", "nyajil"]),
    row(21, "He sees the dulmbi umbrella palm here.", "Nyulu dulmbi yaluy nyajil.", "nyulu dulmbi yaluy nyajil | 3sg.NOM dulmbi.umbrella.palm here see.NPST", "r310_3sg_here_zero_tree_see_dulmbi", ["nyulu", "dulmbi", "yaluy", "nyajil"]),
    row(22, "He sees the kakaji mangrove tree here.", "Nyulu kakaji yaluy nyajil.", "nyulu kakaji yaluy nyajil | 3sg.NOM kakaji.mangrove.tree here see.NPST", "r310_3sg_here_zero_tree_see_kakaji", ["nyulu", "kakaji", "yaluy", "nyajil"]),
    row(23, "He sees the mukukanka tree here.", "Nyulu mukukanka yaluy nyajil.", "nyulu mukukanka yaluy nyajil | 3sg.NOM mukukanka.tree here see.NPST", "r310_3sg_here_zero_tree_see_mukukanka", ["nyulu", "mukukanka", "yaluy", "nyajil"]),
    row(24, "He sees the murrkul tree here.", "Nyulu murrkul yaluy nyajil.", "nyulu murrkul yaluy nyajil | 3sg.NOM murrkul.tree here see.NPST", "r310_3sg_here_zero_tree_see_murrkul", ["nyulu", "murrkul", "yaluy", "nyajil"]),
    row(25, "He sees the milbarkal tree here.", "Nyulu milbarkal yaluy nyajil.", "nyulu milbarkal yaluy nyajil | 3sg.NOM milbarkal.tree here see.NPST", "r310_3sg_here_zero_tree_see_milbarkal", ["nyulu", "milbarkal", "yaluy", "nyajil"]),
    row(26, "He sees the mirrbangku pencil cedar tree here.", "Nyulu mirrbangku yaluy nyajil.", "nyulu mirrbangku yaluy nyajil | 3sg.NOM mirrbangku.pencil.cedar.tree here see.NPST", "r310_3sg_here_zero_tree_see_mirrbangku", ["nyulu", "mirrbangku", "yaluy", "nyajil"]),
    row(27, "He sees the mura tree here.", "Nyulu mura yaluy nyajil.", "nyulu mura yaluy nyajil | 3sg.NOM mura.tree here see.NPST", "r310_3sg_here_zero_tree_see_mura", ["nyulu", "mura", "yaluy", "nyajil"]),
    row(28, "He sees the ngadil hickory tree here.", "Nyulu ngadil yaluy nyajil.", "nyulu ngadil yaluy nyajil | 3sg.NOM ngadil.hickory.tree here see.NPST", "r310_3sg_here_zero_tree_see_ngadil", ["nyulu", "ngadil", "yaluy", "nyajil"]),
    row(29, "He sees the nyumbil coolibah tree here.", "Nyulu nyumbil yaluy nyajil.", "nyulu nyumbil yaluy nyajil | 3sg.NOM nyumbil.coolibah.tree here see.NPST", "r310_3sg_here_zero_tree_see_nyumbil", ["nyulu", "nyumbil", "yaluy", "nyajil"]),
    row(30, "He sees the wankar tree here.", "Nyulu wankar yaluy nyajil.", "nyulu wankar yaluy nyajil | 3sg.NOM wankar.tree here see.NPST", "r310_3sg_here_zero_tree_see_wankar", ["nyulu", "wankar", "yaluy", "nyajil"]),
    row(31, "The two of them see the dulmbi umbrella palm there.", "Bula dulmbi yinyay nyajil.", "bula dulmbi yinyay nyajil | 3du.NOM dulmbi.umbrella.palm there see.NPST", "r310_3du_there_zero_tree_see_dulmbi", ["bula", "dulmbi", "yinyay", "nyajil"]),
    row(32, "The two of them see the kakaji mangrove tree there.", "Bula kakaji yinyay nyajil.", "bula kakaji yinyay nyajil | 3du.NOM kakaji.mangrove.tree there see.NPST", "r310_3du_there_zero_tree_see_kakaji", ["bula", "kakaji", "yinyay", "nyajil"]),
    row(33, "The two of them see the mukukanka tree there.", "Bula mukukanka yinyay nyajil.", "bula mukukanka yinyay nyajil | 3du.NOM mukukanka.tree there see.NPST", "r310_3du_there_zero_tree_see_mukukanka", ["bula", "mukukanka", "yinyay", "nyajil"]),
    row(34, "The two of them see the murrkul tree there.", "Bula murrkul yinyay nyajil.", "bula murrkul yinyay nyajil | 3du.NOM murrkul.tree there see.NPST", "r310_3du_there_zero_tree_see_murrkul", ["bula", "murrkul", "yinyay", "nyajil"]),
    row(35, "The two of them see the milbarkal tree there.", "Bula milbarkal yinyay nyajil.", "bula milbarkal yinyay nyajil | 3du.NOM milbarkal.tree there see.NPST", "r310_3du_there_zero_tree_see_milbarkal", ["bula", "milbarkal", "yinyay", "nyajil"]),
    row(36, "The two of them see the mirrbangku pencil cedar tree there.", "Bula mirrbangku yinyay nyajil.", "bula mirrbangku yinyay nyajil | 3du.NOM mirrbangku.pencil.cedar.tree there see.NPST", "r310_3du_there_zero_tree_see_mirrbangku", ["bula", "mirrbangku", "yinyay", "nyajil"]),
    row(37, "The two of them see the mura tree there.", "Bula mura yinyay nyajil.", "bula mura yinyay nyajil | 3du.NOM mura.tree there see.NPST", "r310_3du_there_zero_tree_see_mura", ["bula", "mura", "yinyay", "nyajil"]),
    row(38, "The two of them see the ngadil hickory tree there.", "Bula ngadil yinyay nyajil.", "bula ngadil yinyay nyajil | 3du.NOM ngadil.hickory.tree there see.NPST", "r310_3du_there_zero_tree_see_ngadil", ["bula", "ngadil", "yinyay", "nyajil"]),
    row(39, "The two of them see the nyumbil coolibah tree there.", "Bula nyumbil yinyay nyajil.", "bula nyumbil yinyay nyajil | 3du.NOM nyumbil.coolibah.tree there see.NPST", "r310_3du_there_zero_tree_see_nyumbil", ["bula", "nyumbil", "yinyay", "nyajil"]),
    row(40, "The two of them see the wankar tree there.", "Bula wankar yinyay nyajil.", "bula wankar yinyay nyajil | 3du.NOM wankar.tree there see.NPST", "r310_3du_there_zero_tree_see_wankar", ["bula", "wankar", "yinyay", "nyajil"]),
    row(41, "They see the dulmbi umbrella palm here.", "Jana dulmbi yaluy nyajil.", "jana dulmbi yaluy nyajil | 3pl.NOM dulmbi.umbrella.palm here see.NPST", "r310_3pl_here_zero_tree_see_dulmbi", ["jana", "dulmbi", "yaluy", "nyajil"]),
    row(42, "They see the kakaji mangrove tree here.", "Jana kakaji yaluy nyajil.", "jana kakaji yaluy nyajil | 3pl.NOM kakaji.mangrove.tree here see.NPST", "r310_3pl_here_zero_tree_see_kakaji", ["jana", "kakaji", "yaluy", "nyajil"]),
    row(43, "They see the mukukanka tree here.", "Jana mukukanka yaluy nyajil.", "jana mukukanka yaluy nyajil | 3pl.NOM mukukanka.tree here see.NPST", "r310_3pl_here_zero_tree_see_mukukanka", ["jana", "mukukanka", "yaluy", "nyajil"]),
    row(44, "They see the murrkul tree here.", "Jana murrkul yaluy nyajil.", "jana murrkul yaluy nyajil | 3pl.NOM murrkul.tree here see.NPST", "r310_3pl_here_zero_tree_see_murrkul", ["jana", "murrkul", "yaluy", "nyajil"]),
    row(45, "They see the milbarkal tree here.", "Jana milbarkal yaluy nyajil.", "jana milbarkal yaluy nyajil | 3pl.NOM milbarkal.tree here see.NPST", "r310_3pl_here_zero_tree_see_milbarkal", ["jana", "milbarkal", "yaluy", "nyajil"]),
    row(46, "They see the mirrbangku pencil cedar tree here.", "Jana mirrbangku yaluy nyajil.", "jana mirrbangku yaluy nyajil | 3pl.NOM mirrbangku.pencil.cedar.tree here see.NPST", "r310_3pl_here_zero_tree_see_mirrbangku", ["jana", "mirrbangku", "yaluy", "nyajil"]),
    row(47, "They see the mura tree here.", "Jana mura yaluy nyajil.", "jana mura yaluy nyajil | 3pl.NOM mura.tree here see.NPST", "r310_3pl_here_zero_tree_see_mura", ["jana", "mura", "yaluy", "nyajil"]),
    row(48, "They see the ngadil hickory tree here.", "Jana ngadil yaluy nyajil.", "jana ngadil yaluy nyajil | 3pl.NOM ngadil.hickory.tree here see.NPST", "r310_3pl_here_zero_tree_see_ngadil", ["jana", "ngadil", "yaluy", "nyajil"]),
    row(49, "They see the nyumbil coolibah tree here.", "Jana nyumbil yaluy nyajil.", "jana nyumbil yaluy nyajil | 3pl.NOM nyumbil.coolibah.tree here see.NPST", "r310_3pl_here_zero_tree_see_nyumbil", ["jana", "nyumbil", "yaluy", "nyajil"]),
    row(50, "They see the wankar tree here.", "Jana wankar yaluy nyajil.", "jana wankar yaluy nyajil | 3pl.NOM wankar.tree here see.NPST", "r310_3pl_here_zero_tree_see_wankar", ["jana", "wankar", "yaluy", "nyajil"]),
]


def scan_static() -> list[str]:
    issues: list[str] = []
    if len(ROWS) != 50:
        issues.append(f"row count {len(ROWS)} != 50")
    if [r[0] for r in ROWS] != list(range(1, 51)):
        issues.append("sequence is not 1..50")
    kukus = [r[2] for r in ROWS]
    if len(set(kukus)) != len(kukus):
        issues.append("duplicate Kuku surface inside batch")
    for seq, english, kuku, _analysis, frame, _tier, words_json, loans_json, _evidence, _confidence in ROWS:
        words = json.loads(words_json)
        loans = json.loads(loans_json)
        lower_kuku = kuku.lower()
        lower_english = english.lower()
        if loans:
            issues.append(f"{seq}: loans used {loans}")
        denied = sorted({w for w in DENY_KUKU if re.search(rf"(^|\s){re.escape(w)}([\s\.]|$)", lower_kuku)})
        if denied:
            issues.append(f"{seq}: denied Kuku forms {denied}")
        denied_english = [term for term in DENY_ENGLISH if re.search(rf"\b{re.escape(term.strip())}\b", lower_english)]
        if denied_english:
            issues.append(f"{seq}: denied English drift {denied_english}")
        if " see " not in f" {lower_english} " and " sees " not in f" {lower_english} ":
            issues.append(f"{seq}: English is not nonpast see/sees")
        target_hits = [w for w in TARGET_ORDER if w in words]
        if len(target_hits) != 1:
            issues.append(f"{seq}: target hits {target_hits}")
        if len(words) != 4:
            issues.append(f"{seq}: expected 4 words, got {words}")
        if "nyajil" not in words or not lower_kuku.endswith(" nyajil."):
            issues.append(f"{seq}: missing final nyajil")
        if "nyajin" in lower_kuku:
            issues.append(f"{seq}: past nyajin leakage")
        if len([w for w in ("yaluy", "yinyay") if w in words]) != 1:
            issues.append(f"{seq}: demonstrative problem {words}")
        expected_pronoun, expected_demo = FRAME_SPECS[(seq - 1) // 10]
        if words[0] != expected_pronoun:
            issues.append(f"{seq}: expected pronoun {expected_pronoun}, got {words[0]}")
        if words[2] != expected_demo:
            issues.append(f"{seq}: expected demonstrative {expected_demo}, got {words[2]}")
        if words[1] != TARGET_ORDER[(seq - 1) % 10]:
            issues.append(f"{seq}: target order mismatch {words[1]}")
        if words[3] != "nyajil":
            issues.append(f"{seq}: word 4 is not nyajil {words[3]}")
        if lower_kuku.rstrip(".") != " ".join(words):
            issues.append(f"{seq}: Kuku does not match words_used {words}")
        if not frame.startswith("r310_"):
            issues.append(f"{seq}: frame not r310 {frame}")
    return issues


def main() -> int:
    issues = scan_static()
    if issues:
        for issue in issues:
            print(issue)
        raise SystemExit(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")
    collisions = []
    for _seq, _english, kuku, *_rest in ROWS:
        existing = 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!='rejected'
            """,
            (kuku,),
        ).fetchall()
        if existing:
            collisions.append((kuku, existing))
    if collisions:
        raise SystemExit(f"duplicate preflight failed: {collisions}")

    target_counts = count_words(db, TARGET_ORDER)
    support_counts = count_words(db, ["ngayu", "yundu", "nyulu", "bula", "jana", "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 = (
        "ZERO-COUNT VISIBLE TREE/PALM SINGULAR/THIRD-PERSON NONPAST PERCEPTION SWEEP AFTER RULE 309 (Rule 310). "
        "50 under-review rows over ten newly checked zero-count flora/tree target heads: dulmbi umbrella palm, "
        "kakaji mangrove tree, mukukanka tree, murrkul tree, milbarkal tree, mirrbangku pencil cedar tree, mura tree, "
        "ngadil hickory tree, nyumbil coolibah tree, and wankar tree. SUPPORT: bare nominative ngayu, yundu, nyulu, "
        "bula, and jana, plus yaluy/yinyay and nyajil. Only bare visible object nonpast perception/reference rows are "
        "opened; place names, timber, woomeras, dialect commentary, productive reduplication, pair/dual morphology, "
        "shore/tide ecology, fruit, date-shape, sweetness, bloom timing, minya jalan, leech/fauna homographs, water-side ecology, flowers, "
        "seeds, necklaces, artefacts, target case, pronoun case, demonstrative case, 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 310 under review", "operator-guide-2026-07-10", 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 direct dictionary yaml entries for ten Rule 310 zero-count visible tree/palm targets and living grammar singular/third-person pronoun, demonstrative, and nyaji-l/nyajil nonpast support before authoring Rule 310.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="zero-count-tree-palm-singular-third-nonpast-scope", actor="claude-main", detail="Selected zero-count visible tree/palm singular/third-person nonpast perception after Rule 309. The batch uses newly checked targets dulmbi, kakaji, mukukanka, murrkul, milbarkal, mirrbangku, mura, ngadil, nyumbil, and wankar with nyajil and opens no plant use, place-name, timber, woomera, shore/tide ecology, fruit, bloom, leech, necklace, artefact, case, compound, past, purposive, reduplicated perception, or support-inflection semantics.", 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 from words_used JSON: 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="Final 50 Rule 310 zero-count visible tree/palm singular/third-person nonpast 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 explicit hand-authored rows, one target each, bare singular/third-person nominative pronoun bands, bare yaluy/yinyay, final nyajil, no loans, no denied Kuku forms, no past nyajin leakage, and no place/timber/woomera/fruit/bloom/leech/necklace/source-prose drift.", command="python3 -m py_compile batch_scripts/bank_352.py && python3 -c \"import sys; sys.path.insert(0,'batch_scripts'); import bank_352; print(bank_352.scan_static())\"", output_excerpt="issues 0", artifact_path="batch_scripts/bank_352.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="claude-main", detail=f"Banked 50 Rule 310 rows as under_review. Verified total remains {verified_before}; Kuku word count remains {words_before}.", command="python3 batch_scripts/bank_352.py", output_excerpt=f"banked batch-352: 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-352: 50 rows under_review")
    return 0


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