#!/usr/bin/env python3
"""Bank batch-370: Rule 328 low-coverage food non-singular past 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-370"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-370-low-coverage-food-nonsingular-past-perception-after-rule327-process.md"

TARGET_EVIDENCE = {
    "balja": "Dictionary yaml lines 953-962 give balja as a noun for a kind of food or ground food and describe cooking, grinding, and eating. Rule 328 admits the conservative label balja food only and leaves ingredient identity, fire, cooking, grinding, eating, preparation sequence, property, source, and event propositions closed.",
    "birukay": "Dictionary yaml lines 3255-3263 give birukay as the noun 'yolk of the egg'. Rule 328 admits egg-yolk reference only and leaves egg source, shell, white/albumen relation, breaking, separating, cooking, eating, colour, texture, possession, and event propositions closed.",
    "biyangkal": "Dictionary yaml lines 3356-3366 give biyangkal as a toxic yam requiring roasting, grinding, and lengthy leaching before safe eating. Rule 328 admits yam reference only and leaves toxicity, danger, roasting, grinding, leaching, water, preparation, eating, safety, plant/source, digging, and event propositions closed.",
    "jadamu": "Dictionary yaml lines 7006-7014 give jadamu as the noun 'bananas'. Rule 328 admits banana reference only and leaves number inference beyond the lexical translation, plant/source, bunch, ripeness, colour, peeling, gathering, carrying, cooking, eating, possession, and event propositions closed.",
    "jamal": "Dictionary yaml lines 7650-7661 give jamal as the noun 'white of egg; albumen'. Rule 328 admits egg-white reference only and leaves egg source, yolk relation, shell, breaking, separating, cooking, eating, edibility, colour, texture, possession, and event propositions closed.",
    "jandu": "Dictionary yaml lines 7935-7945 give jandu as starch, specifically a thick non-soupy food made from flour cooked in water, and note the post-contact ingredient without identifying the head as an English loan. Rule 328 admits jandu starch reference only and leaves flour, water, thickness, soup comparison, cooking, preparation, post-contact history, eating, ingredient source, and event propositions closed.",
    "jungu-jungu": "Dictionary yaml lines 10950-10963 give exact hyphenated jungu-jungu as the noun 'white ant eggs' and analyze it as a full reduplication based on jungu. Rule 328 admits the whole lexical head and white-ant-egg reference only and leaves base use, productive reduplication, ants, gathering, food use, habitat, nest, cooking, eating, number derivation, and event propositions closed.",
    "kajimarra": "Dictionary yaml lines 12023-12032 give kajimarra as a food or flour made through grinding, wrapping in junjun leaves, soaking for weeks, further grinding, and roasting. Rule 328 admits the conservative label kajimarra food only and leaves flour equivalence, marra or junjun decomposition, leaves, water, duration, grinding, wrapping, soaking, roasting, preparation, eating, and event propositions closed.",
    "milkul": "Dictionary yaml lines 19502-19511 give milkul as the noun 'soup or stew'. Patz lines 5171-5172 independently attest milkul as dative and absolutive soup in clauses about grass and eating. Rule 328 admits soup reference only and leaves stew equivalence as a generated claim, ingredients, grass/wuju, cooking, heat, eating, preparation, possession, and event propositions closed.",
    "wawukuna": "Dictionary yaml lines 27046-27056 give wawukuna as the noun 'long wild yam' and identify it as edible plant food. Rule 328 admits long-wild-yam reference only and leaves edibility, plant/source, length predication, digging, ground/depth, preparation, cooking, eating, gathering, possession, and event propositions closed.",
}

SUPPORT_EVIDENCE = (
    "Patz lines 1474-1476 state that nominals refer to objects and that nouns predominantly refer to corporeal "
    "objects. Lines 2577-2586 source bare nominative ngali, ngaliny, yubal, yurra, and nganjin; lines 2834-2847 "
    "source Yalanji yaluy 'here' and yinyay 'there'. Examples at lines 2021-2024 and 2568-2571 attest nyaji-ny "
    "'see-PAST', lines 3160-3162 define past -ny, and lines 4256-4265 license nominative pronoun A with bare "
    "absolutive O in perception. Dictionary examples at lines 23876-23883 and 23968-23976 independently contain "
    "running-form nyajin. Exact Patz target search finds milkul at lines 5171-5172 with its soup sense and none "
    "of the other nine selected heads. Rule 328 takes every selected food reading from the dictionary and uses "
    "only bare support and past visual perception."
)

TARGET_ORDER = ["balja", "birukay", "biyangkal", "jadamu", "jamal", "jandu", "jungu-jungu", "kajimarra", "milkul", "wawukuna"]
TARGET_LABELS = {
    "balja": "balja food",
    "birukay": "birukay egg yolk",
    "biyangkal": "biyangkal yam",
    "jadamu": "jadamu bananas",
    "jamal": "jamal egg white",
    "jandu": "jandu starch",
    "jungu-jungu": "jungu-jungu white ant eggs",
    "kajimarra": "kajimarra food",
    "milkul": "milkul soup",
    "wawukuna": "wawukuna long wild yam",
}
TARGET_GLOSSES = {
    "balja": "balja.food",
    "birukay": "birukay.egg.yolk",
    "biyangkal": "biyangkal.yam",
    "jadamu": "jadamu.bananas",
    "jamal": "jamal.egg.white",
    "jandu": "jandu.starch",
    "jungu-jungu": "jungu.jungu.white.ant.eggs",
    "kajimarra": "kajimarra.food",
    "milkul": "milkul.soup",
    "wawukuna": "wawukuna.long.wild.yam",
}
TARGET_CONFIDENCE = {
    "balja": "0.84",
    "birukay": "0.94",
    "biyangkal": "0.92",
    "jadamu": "0.94",
    "jamal": "0.94",
    "jandu": "0.86",
    "jungu-jungu": "0.91",
    "kajimarra": "0.84",
    "milkul": "0.95",
    "wawukuna": "0.93",
}
EXPECTED_TARGET_COVERAGE = {
    "balja": 0,
    "birukay": 5,
    "biyangkal": 5,
    "jadamu": 5,
    "jamal": 5,
    "jandu": 0,
    "jungu-jungu": 5,
    "kajimarra": 0,
    "milkul": 5,
    "wawukuna": 6,
}
FRAME_SPECS = [
    ("ngali", "yinyay", "We two, not you, saw", "there", "1du.excl"),
    ("ngaliny", "yaluy", "You and I saw", "here", "1du.incl"),
    ("yubal", "yinyay", "You two saw", "there", "2du"),
    ("yurra", "yaluy", "You all saw", "here", "2pl"),
    ("nganjin", "yinyay", "We, not you, saw", "there", "1pl.excl"),
]

DENY_KUKU = {
    "ngayu", "yundu", "nyulu", "yulu", "bula", "jana", "iana", "ngana",
    "ngalingan", "ngalinyan", "yubalan", "yurrangan", "nganangan",
    "ngalininy", "ngalinyiny", "yubaliny", "yurraniny", "nganjininy",
    "ngalinka", "ngalinyanka", "yubalanka", "yurranka", "nganjinanka",
    "ngalinda", "ngalinyanda", "yubalanda", "yurranda", "nganjinanda",
    "ngalindamuny", "ngalinyandamuny", "yubalandamuny", "yurrandamuny", "nganjinandamuny",
    "ngalinji", "ngalinyanji", "yubalanji", "yurranji", "nganjinanji",
    "ngalinga", "ngalinyanga", "yubalanga", "yurranga", "nganjinanga",
    "banabul", "dunju", "janban", "jarru", "kajinbur", "nganyin", "diyi", "kalbanbina",
    "kamu-kamu", "mirrbi", "mandi-mandi", "bulawu", "balji", "birungubay", "jamalka",
    "jangka", "milman", "wawumal", "jungu", "marra", "junjun",
    "yalay", "yala", "yanyu", "yinya", "yalungku", "yaluyngku", "yinyangka", "yinyayngka",
    "yalamuny", "yinyamuny", "nyajil", "nyaji-l", "nyaji-nka", "nyaji-l-nyaji", "milka",
    "baykal", "jalngkay",
}
DENY_ENGLISH = (
    "ground food", "ingredient", "fire", "cook", "cooked", "grind", "ground", "eat", "eating",
    "egg source", "shell", "albumen relation", "break", "separate", "colour", "texture", "toxic",
    "toxicity", "danger", "roast", "leach", "water", "safe", "safety", "prepare", "preparation",
    "plant source", "dig", "bunch", "ripe", "ripeness", "peel", "gather", "carry", "edible",
    "flour", "thick", "soupy", "post-contact", "history", "ant source", "base", "reduplication",
    "nest", "habitat", "leaf", "weeks", "wrap", "soak", "marra", "junjun", "stew equivalence",
    "grass", "wuju", "heat", "length predication", "depth", "possess", "source", "event", "use",
    "used", "using", "make", "made",
)


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 lower(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]
    return (
        seq,
        english,
        kuku,
        analysis,
        frame,
        3,
        json.dumps(words, ensure_ascii=False),
        json.dumps([], ensure_ascii=False),
        f"{TARGET_EVIDENCE[target]} {SUPPORT_EVIDENCE}",
        TARGET_CONFIDENCE[target],
    )


ROWS = [
    row(1, "We two, not you, saw the balja food there.", "Ngali balja yinyay nyajin.", "ngali balja yinyay nyajin | 1du.excl.NOM balja.food there see.PST", "r328_1du_excl_there_low_food_saw_balja", ["ngali", "balja", "yinyay", "nyajin"]),
    row(2, "We two, not you, saw the birukay egg yolk there.", "Ngali birukay yinyay nyajin.", "ngali birukay yinyay nyajin | 1du.excl.NOM birukay.egg.yolk there see.PST", "r328_1du_excl_there_low_food_saw_birukay", ["ngali", "birukay", "yinyay", "nyajin"]),
    row(3, "We two, not you, saw the biyangkal yam there.", "Ngali biyangkal yinyay nyajin.", "ngali biyangkal yinyay nyajin | 1du.excl.NOM biyangkal.yam there see.PST", "r328_1du_excl_there_low_food_saw_biyangkal", ["ngali", "biyangkal", "yinyay", "nyajin"]),
    row(4, "We two, not you, saw the jadamu bananas there.", "Ngali jadamu yinyay nyajin.", "ngali jadamu yinyay nyajin | 1du.excl.NOM jadamu.bananas there see.PST", "r328_1du_excl_there_low_food_saw_jadamu", ["ngali", "jadamu", "yinyay", "nyajin"]),
    row(5, "We two, not you, saw the jamal egg white there.", "Ngali jamal yinyay nyajin.", "ngali jamal yinyay nyajin | 1du.excl.NOM jamal.egg.white there see.PST", "r328_1du_excl_there_low_food_saw_jamal", ["ngali", "jamal", "yinyay", "nyajin"]),
    row(6, "We two, not you, saw the jandu starch there.", "Ngali jandu yinyay nyajin.", "ngali jandu yinyay nyajin | 1du.excl.NOM jandu.starch there see.PST", "r328_1du_excl_there_low_food_saw_jandu", ["ngali", "jandu", "yinyay", "nyajin"]),
    row(7, "We two, not you, saw the jungu-jungu white ant eggs there.", "Ngali jungu-jungu yinyay nyajin.", "ngali jungu-jungu yinyay nyajin | 1du.excl.NOM jungu.jungu.white.ant.eggs there see.PST", "r328_1du_excl_there_low_food_saw_jungu_jungu", ["ngali", "jungu-jungu", "yinyay", "nyajin"]),
    row(8, "We two, not you, saw the kajimarra food there.", "Ngali kajimarra yinyay nyajin.", "ngali kajimarra yinyay nyajin | 1du.excl.NOM kajimarra.food there see.PST", "r328_1du_excl_there_low_food_saw_kajimarra", ["ngali", "kajimarra", "yinyay", "nyajin"]),
    row(9, "We two, not you, saw the milkul soup there.", "Ngali milkul yinyay nyajin.", "ngali milkul yinyay nyajin | 1du.excl.NOM milkul.soup there see.PST", "r328_1du_excl_there_low_food_saw_milkul", ["ngali", "milkul", "yinyay", "nyajin"]),
    row(10, "We two, not you, saw the wawukuna long wild yam there.", "Ngali wawukuna yinyay nyajin.", "ngali wawukuna yinyay nyajin | 1du.excl.NOM wawukuna.long.wild.yam there see.PST", "r328_1du_excl_there_low_food_saw_wawukuna", ["ngali", "wawukuna", "yinyay", "nyajin"]),
    row(11, "You and I saw the balja food here.", "Ngaliny balja yaluy nyajin.", "ngaliny balja yaluy nyajin | 1du.incl.NOM balja.food here see.PST", "r328_1du_incl_here_low_food_saw_balja", ["ngaliny", "balja", "yaluy", "nyajin"]),
    row(12, "You and I saw the birukay egg yolk here.", "Ngaliny birukay yaluy nyajin.", "ngaliny birukay yaluy nyajin | 1du.incl.NOM birukay.egg.yolk here see.PST", "r328_1du_incl_here_low_food_saw_birukay", ["ngaliny", "birukay", "yaluy", "nyajin"]),
    row(13, "You and I saw the biyangkal yam here.", "Ngaliny biyangkal yaluy nyajin.", "ngaliny biyangkal yaluy nyajin | 1du.incl.NOM biyangkal.yam here see.PST", "r328_1du_incl_here_low_food_saw_biyangkal", ["ngaliny", "biyangkal", "yaluy", "nyajin"]),
    row(14, "You and I saw the jadamu bananas here.", "Ngaliny jadamu yaluy nyajin.", "ngaliny jadamu yaluy nyajin | 1du.incl.NOM jadamu.bananas here see.PST", "r328_1du_incl_here_low_food_saw_jadamu", ["ngaliny", "jadamu", "yaluy", "nyajin"]),
    row(15, "You and I saw the jamal egg white here.", "Ngaliny jamal yaluy nyajin.", "ngaliny jamal yaluy nyajin | 1du.incl.NOM jamal.egg.white here see.PST", "r328_1du_incl_here_low_food_saw_jamal", ["ngaliny", "jamal", "yaluy", "nyajin"]),
    row(16, "You and I saw the jandu starch here.", "Ngaliny jandu yaluy nyajin.", "ngaliny jandu yaluy nyajin | 1du.incl.NOM jandu.starch here see.PST", "r328_1du_incl_here_low_food_saw_jandu", ["ngaliny", "jandu", "yaluy", "nyajin"]),
    row(17, "You and I saw the jungu-jungu white ant eggs here.", "Ngaliny jungu-jungu yaluy nyajin.", "ngaliny jungu-jungu yaluy nyajin | 1du.incl.NOM jungu.jungu.white.ant.eggs here see.PST", "r328_1du_incl_here_low_food_saw_jungu_jungu", ["ngaliny", "jungu-jungu", "yaluy", "nyajin"]),
    row(18, "You and I saw the kajimarra food here.", "Ngaliny kajimarra yaluy nyajin.", "ngaliny kajimarra yaluy nyajin | 1du.incl.NOM kajimarra.food here see.PST", "r328_1du_incl_here_low_food_saw_kajimarra", ["ngaliny", "kajimarra", "yaluy", "nyajin"]),
    row(19, "You and I saw the milkul soup here.", "Ngaliny milkul yaluy nyajin.", "ngaliny milkul yaluy nyajin | 1du.incl.NOM milkul.soup here see.PST", "r328_1du_incl_here_low_food_saw_milkul", ["ngaliny", "milkul", "yaluy", "nyajin"]),
    row(20, "You and I saw the wawukuna long wild yam here.", "Ngaliny wawukuna yaluy nyajin.", "ngaliny wawukuna yaluy nyajin | 1du.incl.NOM wawukuna.long.wild.yam here see.PST", "r328_1du_incl_here_low_food_saw_wawukuna", ["ngaliny", "wawukuna", "yaluy", "nyajin"]),
    row(21, "You two saw the balja food there.", "Yubal balja yinyay nyajin.", "yubal balja yinyay nyajin | 2du.NOM balja.food there see.PST", "r328_2du_there_low_food_saw_balja", ["yubal", "balja", "yinyay", "nyajin"]),
    row(22, "You two saw the birukay egg yolk there.", "Yubal birukay yinyay nyajin.", "yubal birukay yinyay nyajin | 2du.NOM birukay.egg.yolk there see.PST", "r328_2du_there_low_food_saw_birukay", ["yubal", "birukay", "yinyay", "nyajin"]),
    row(23, "You two saw the biyangkal yam there.", "Yubal biyangkal yinyay nyajin.", "yubal biyangkal yinyay nyajin | 2du.NOM biyangkal.yam there see.PST", "r328_2du_there_low_food_saw_biyangkal", ["yubal", "biyangkal", "yinyay", "nyajin"]),
    row(24, "You two saw the jadamu bananas there.", "Yubal jadamu yinyay nyajin.", "yubal jadamu yinyay nyajin | 2du.NOM jadamu.bananas there see.PST", "r328_2du_there_low_food_saw_jadamu", ["yubal", "jadamu", "yinyay", "nyajin"]),
    row(25, "You two saw the jamal egg white there.", "Yubal jamal yinyay nyajin.", "yubal jamal yinyay nyajin | 2du.NOM jamal.egg.white there see.PST", "r328_2du_there_low_food_saw_jamal", ["yubal", "jamal", "yinyay", "nyajin"]),
    row(26, "You two saw the jandu starch there.", "Yubal jandu yinyay nyajin.", "yubal jandu yinyay nyajin | 2du.NOM jandu.starch there see.PST", "r328_2du_there_low_food_saw_jandu", ["yubal", "jandu", "yinyay", "nyajin"]),
    row(27, "You two saw the jungu-jungu white ant eggs there.", "Yubal jungu-jungu yinyay nyajin.", "yubal jungu-jungu yinyay nyajin | 2du.NOM jungu.jungu.white.ant.eggs there see.PST", "r328_2du_there_low_food_saw_jungu_jungu", ["yubal", "jungu-jungu", "yinyay", "nyajin"]),
    row(28, "You two saw the kajimarra food there.", "Yubal kajimarra yinyay nyajin.", "yubal kajimarra yinyay nyajin | 2du.NOM kajimarra.food there see.PST", "r328_2du_there_low_food_saw_kajimarra", ["yubal", "kajimarra", "yinyay", "nyajin"]),
    row(29, "You two saw the milkul soup there.", "Yubal milkul yinyay nyajin.", "yubal milkul yinyay nyajin | 2du.NOM milkul.soup there see.PST", "r328_2du_there_low_food_saw_milkul", ["yubal", "milkul", "yinyay", "nyajin"]),
    row(30, "You two saw the wawukuna long wild yam there.", "Yubal wawukuna yinyay nyajin.", "yubal wawukuna yinyay nyajin | 2du.NOM wawukuna.long.wild.yam there see.PST", "r328_2du_there_low_food_saw_wawukuna", ["yubal", "wawukuna", "yinyay", "nyajin"]),
    row(31, "You all saw the balja food here.", "Yurra balja yaluy nyajin.", "yurra balja yaluy nyajin | 2pl.NOM balja.food here see.PST", "r328_2pl_here_low_food_saw_balja", ["yurra", "balja", "yaluy", "nyajin"]),
    row(32, "You all saw the birukay egg yolk here.", "Yurra birukay yaluy nyajin.", "yurra birukay yaluy nyajin | 2pl.NOM birukay.egg.yolk here see.PST", "r328_2pl_here_low_food_saw_birukay", ["yurra", "birukay", "yaluy", "nyajin"]),
    row(33, "You all saw the biyangkal yam here.", "Yurra biyangkal yaluy nyajin.", "yurra biyangkal yaluy nyajin | 2pl.NOM biyangkal.yam here see.PST", "r328_2pl_here_low_food_saw_biyangkal", ["yurra", "biyangkal", "yaluy", "nyajin"]),
    row(34, "You all saw the jadamu bananas here.", "Yurra jadamu yaluy nyajin.", "yurra jadamu yaluy nyajin | 2pl.NOM jadamu.bananas here see.PST", "r328_2pl_here_low_food_saw_jadamu", ["yurra", "jadamu", "yaluy", "nyajin"]),
    row(35, "You all saw the jamal egg white here.", "Yurra jamal yaluy nyajin.", "yurra jamal yaluy nyajin | 2pl.NOM jamal.egg.white here see.PST", "r328_2pl_here_low_food_saw_jamal", ["yurra", "jamal", "yaluy", "nyajin"]),
    row(36, "You all saw the jandu starch here.", "Yurra jandu yaluy nyajin.", "yurra jandu yaluy nyajin | 2pl.NOM jandu.starch here see.PST", "r328_2pl_here_low_food_saw_jandu", ["yurra", "jandu", "yaluy", "nyajin"]),
    row(37, "You all saw the jungu-jungu white ant eggs here.", "Yurra jungu-jungu yaluy nyajin.", "yurra jungu-jungu yaluy nyajin | 2pl.NOM jungu.jungu.white.ant.eggs here see.PST", "r328_2pl_here_low_food_saw_jungu_jungu", ["yurra", "jungu-jungu", "yaluy", "nyajin"]),
    row(38, "You all saw the kajimarra food here.", "Yurra kajimarra yaluy nyajin.", "yurra kajimarra yaluy nyajin | 2pl.NOM kajimarra.food here see.PST", "r328_2pl_here_low_food_saw_kajimarra", ["yurra", "kajimarra", "yaluy", "nyajin"]),
    row(39, "You all saw the milkul soup here.", "Yurra milkul yaluy nyajin.", "yurra milkul yaluy nyajin | 2pl.NOM milkul.soup here see.PST", "r328_2pl_here_low_food_saw_milkul", ["yurra", "milkul", "yaluy", "nyajin"]),
    row(40, "You all saw the wawukuna long wild yam here.", "Yurra wawukuna yaluy nyajin.", "yurra wawukuna yaluy nyajin | 2pl.NOM wawukuna.long.wild.yam here see.PST", "r328_2pl_here_low_food_saw_wawukuna", ["yurra", "wawukuna", "yaluy", "nyajin"]),
    row(41, "We, not you, saw the balja food there.", "Nganjin balja yinyay nyajin.", "nganjin balja yinyay nyajin | 1pl.excl.NOM balja.food there see.PST", "r328_1pl_excl_there_low_food_saw_balja", ["nganjin", "balja", "yinyay", "nyajin"]),
    row(42, "We, not you, saw the birukay egg yolk there.", "Nganjin birukay yinyay nyajin.", "nganjin birukay yinyay nyajin | 1pl.excl.NOM birukay.egg.yolk there see.PST", "r328_1pl_excl_there_low_food_saw_birukay", ["nganjin", "birukay", "yinyay", "nyajin"]),
    row(43, "We, not you, saw the biyangkal yam there.", "Nganjin biyangkal yinyay nyajin.", "nganjin biyangkal yinyay nyajin | 1pl.excl.NOM biyangkal.yam there see.PST", "r328_1pl_excl_there_low_food_saw_biyangkal", ["nganjin", "biyangkal", "yinyay", "nyajin"]),
    row(44, "We, not you, saw the jadamu bananas there.", "Nganjin jadamu yinyay nyajin.", "nganjin jadamu yinyay nyajin | 1pl.excl.NOM jadamu.bananas there see.PST", "r328_1pl_excl_there_low_food_saw_jadamu", ["nganjin", "jadamu", "yinyay", "nyajin"]),
    row(45, "We, not you, saw the jamal egg white there.", "Nganjin jamal yinyay nyajin.", "nganjin jamal yinyay nyajin | 1pl.excl.NOM jamal.egg.white there see.PST", "r328_1pl_excl_there_low_food_saw_jamal", ["nganjin", "jamal", "yinyay", "nyajin"]),
    row(46, "We, not you, saw the jandu starch there.", "Nganjin jandu yinyay nyajin.", "nganjin jandu yinyay nyajin | 1pl.excl.NOM jandu.starch there see.PST", "r328_1pl_excl_there_low_food_saw_jandu", ["nganjin", "jandu", "yinyay", "nyajin"]),
    row(47, "We, not you, saw the jungu-jungu white ant eggs there.", "Nganjin jungu-jungu yinyay nyajin.", "nganjin jungu-jungu yinyay nyajin | 1pl.excl.NOM jungu.jungu.white.ant.eggs there see.PST", "r328_1pl_excl_there_low_food_saw_jungu_jungu", ["nganjin", "jungu-jungu", "yinyay", "nyajin"]),
    row(48, "We, not you, saw the kajimarra food there.", "Nganjin kajimarra yinyay nyajin.", "nganjin kajimarra yinyay nyajin | 1pl.excl.NOM kajimarra.food there see.PST", "r328_1pl_excl_there_low_food_saw_kajimarra", ["nganjin", "kajimarra", "yinyay", "nyajin"]),
    row(49, "We, not you, saw the milkul soup there.", "Nganjin milkul yinyay nyajin.", "nganjin milkul yinyay nyajin | 1pl.excl.NOM milkul.soup there see.PST", "r328_1pl_excl_there_low_food_saw_milkul", ["nganjin", "milkul", "yinyay", "nyajin"]),
    row(50, "We, not you, saw the wawukuna long wild yam there.", "Nganjin wawukuna yinyay nyajin.", "nganjin wawukuna yinyay nyajin | 1pl.excl.NOM wawukuna.long.wild.yam there see.PST", "r328_1pl_excl_there_low_food_saw_wawukuna", ["nganjin", "wawukuna", "yinyay", "nyajin"]),
]


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")
    if len({r[1] for r in ROWS}) != 50:
        issues.append("duplicate English surface inside batch")
    if len({r[2] for r in ROWS}) != 50:
        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)
        band = (seq - 1) // 10
        target = TARGET_ORDER[(seq - 1) % 10]
        pronoun, demo, prefix, location, person_gloss = FRAME_SPECS[band]
        expected_kuku = f"{pronoun.capitalize()} {target} {demo} nyajin."
        expected_english = f"{prefix} the {TARGET_LABELS[target]} {location}."
        expected_analysis = f"{pronoun} {target} {demo} nyajin | {person_gloss}.NOM {TARGET_GLOSSES[target]} {location} see.PST"
        low_kuku = kuku.lower()
        low_english = english.lower()
        if loans:
            issues.append(f"{seq}: loans used {loans}")
        denied = sorted({word for word in DENY_KUKU if re.search(rf"(^|\s){re.escape(word)}([\s\.]|$)", low_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)}\b", low_english)]
        if denied_english:
            issues.append(f"{seq}: denied English drift {denied_english}")
        if kuku != expected_kuku:
            issues.append(f"{seq}: Kuku mismatch")
        if english != expected_english:
            issues.append(f"{seq}: English mismatch")
        if analysis != expected_analysis:
            issues.append(f"{seq}: analysis mismatch")
        if words != [pronoun, target, demo, "nyajin"]:
            issues.append(f"{seq}: words mismatch {words}")
        if low_kuku.rstrip(".") != " ".join(words):
            issues.append(f"{seq}: Kuku does not match words_used")
        if not frame.startswith("r328_"):
            issues.append(f"{seq}: frame not r328")
        if TARGET_EVIDENCE[target] not in evidence or SUPPORT_EVIDENCE not in evidence:
            issues.append(f"{seq}: evidence mismatch")
        if confidence != TARGET_CONFIDENCE[target]:
            issues.append(f"{seq}: confidence mismatch")
    return issues


def main() -> int:
    issues = scan_static()
    if issues:
        print("\n".join(issues))
        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")
    target_counts = count_words(db, TARGET_ORDER)
    if target_counts != EXPECTED_TARGET_COVERAGE:
        raise SystemExit(f"target coverage changed: {target_counts}")
    support_words = ["ngali", "ngaliny", "yubal", "yurra", "nganjin", "yaluy", "yinyay", "nyajin"]
    support_counts = count_words(db, support_words)
    collisions = []
    for _seq, _english, kuku, *_rest in ROWS:
        hits = 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 hits:
            collisions.append((kuku, hits))
    if collisions:
        raise SystemExit(f"duplicate preflight failed: {collisions}")
    verified_before, words_before = db.execute(
        "SELECT COUNT(*),SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1) FROM sentences WHERE status IN ('accepted','revised')"
    ).fetchone()
    notes = (
        "LOW-COVERAGE FOOD NON-SINGULAR PAST PERCEPTION AFTER RULE 327 (Rule 328). 50 under-review rows over ten "
        "0-6-use noun heads: balja, birukay, biyangkal, jadamu, jamal, jandu, jungu-jungu, kajimarra, milkul, "
        "wawukuna. Exact referential senses only; no explicit loans, preparation, cooking, eating, toxicity, source, "
        "material decomposition, white-ant/reduplication event, food equivalence, property, possession, case, "
        "nonpast/purposive/reduplicated perception, or support drift."
    )
    cur = db.execute(
        "INSERT INTO batches(label,cheatsheet_version,guide_version,notes,created_at) VALUES(?,?,?,?,?)",
        (LABEL, "Rule 328 under review", "operator-guide-2026-07-10", notes, NOW),
    )
    bid = 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(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
        [
            (bid, seq, english, kuku, analysis, frame, tier, words, loans, evidence, "under_review", confidence,
             "project_approved_synthetic_pending_elder_verification", "codex-main", NOW, NOW)
            for seq, english, kuku, analysis, frame, tier, words, loans, evidence, confidence in ROWS
        ],
    )
    record_event(db, batch_label=LABEL, phase="source", event_type="source-readback", actor="codex", detail="Reread all ten dictionary food entries; exact Patz search found milkul only, in its soup sense, with the other nine absent; reread Patz nominal/object status, non-singular pronouns, Yalanji demonstratives, past, perception A/O, and dictionary running nyajin examples.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="candidate-audit", actor="codex", detail="Structured food audit excluded explicit English loans, the undefined bulawu entry, mortuary-context mandi-mandi, culturally or lexically ambiguous candidates, and heads without a stable direct reading. Selected ten non-loan visible food nouns at coverage 0-6; source preparation prose remains closed.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="low-food-nonsingular-past-scope", actor="codex", detail="Locked ten low-coverage food heads to bare reference in five sourced non-singular past-perception frames. Preparation, cooking, eating, toxicity, source, material decomposition, equivalence, property, possession, case, and event fields remain closed.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="coverage-audit", actor="codex", 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="codex", detail="All 50 Rule 328 exact Kuku surfaces are internally unique and returned no corpus collisions.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="static-guard-pass", actor="codex", detail="Static guard passed: 50 explicit rows, exact contracts, one selected food head each, bare non-singular nominatives, Yalanji demonstratives, final nyajin, no loans, excluded candidates, preparation/use, source, case, or support drift.", command="python3 -m py_compile batch_scripts/bank_370.py batch_scripts/close_370.py && AST/static/lint probes", output_excerpt="50 explicit rows; scan_static 0; 50 linter probes 0; collisions 0", artifact_path="batch_scripts/bank_370.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="codex", detail=f"Banked 50 Rule 328 rows as under_review. Verified remains {verified_before}; Kuku words remain {words_before}.", command="python3 batch_scripts/bank_370.py", output_excerpt=f"banked batch-370: 50 under_review; verified_before={verified_before}; words_before={words_before}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit()
    print("banked batch-370: 50 rows under_review")
    return 0


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