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

TARGET_EVIDENCE = {
    "bajarr": "Dictionary yaml lines 456-481 give duplicate noun entries bajarr 'leaves', specifically loya-vine fern leaves used for shelter. Rule 324 admits conservative fern-leaf reference only and leaves vine/fern taxonomy, shelter, mia-mia, gathering, carrying, drying, material use, manufacture, and event propositions closed; it keeps double-r bajarr distinct from bajar white gum.",
    "bikarrakul": "Dictionary yaml lines 2381-2391 give bikarrakul as noun 'ti tree' and note that its fruit must be cooked. Rule 324 admits ti-tree reference only and leaves fruit, edibility, cooking, gathering, food, bark, firewood, material use, species comparison, and event propositions closed.",
    "binainyji": "Dictionary yaml lines 2642-2655 give binainyji as noun 'fig-like fruit', sourced from Patz; Patz grammar lines 1145-1151 independently cite bare binainyji in a phonemic minimal-pair set. Rule 324 admits fig-like-fruit reference only and leaves fig identity, edibility, taste, ripeness, gathering, preparation, tree/source, and the distinct forms binanj-ji, jalbanj-ji, and jalbainy-ji closed.",
    "jakalkulu": "Dictionary yaml lines 7197-7205 give jakalkulu as noun 'tree stump'. Rule 324 admits tree-stump reference only and leaves tree species, cutting/felling, age, decay, burning, firewood, sitting, location, material use, cause, and event propositions closed.",
    "jumul-jumul": "Dictionary yaml lines 10812-10825 give the exact full-reduplicated noun jumul-jumul 'grass seeds' and describe seeds that lodge in clothes during the wet season. Rule 324 admits the whole grass-seed head only and leaves productive reduplication, base jumul, clothing contact, sticking, wet-season timing, gathering, food, sowing, and event propositions closed.",
    "jika-birra": "Dictionary yaml lines 8986-8996 give the exact compound noun jika-birra 'tobacco leaf'. Rule 324 admits the whole tobacco-leaf head only and leaves component senses, productive compounding, tobacco use, smoking, chewing, preparation, drying, trade, medicine, possession, and event propositions closed.",
    "kalbawurr": "Dictionary yaml lines 12432-12440 give kalbawurr as noun 'cypress pine pitch' and mark it poisonous. Rule 324 admits cypress-pine-pitch reference only and leaves poison/toxicity, touching, ingestion, medicine, resin processing, spear use, tree/source relation, material use, and event propositions closed; near-form kulbawurr remains separate.",
    "makaji": "Dictionary yaml lines 17152-17161 give makaji as noun 'onion plant, edible herb'. Rule 324 admits onion-plant reference only and leaves edibility, herb classification, food, onion harvesting, digging, cooking, taste, medicine, cultivation, possession, and event propositions closed.",
    "mawu": "Dictionary yaml lines 18764-18774 give mawu as noun 'grass', specifically a coarse grass used in making dilly bags. Rule 324 admits grass reference only and leaves coarseness predication, bag making, weaving, cutting, gathering, drying, material use, possession, and event propositions closed; near-form mawar vine remains separate.",
    "wakumba": "Dictionary yaml lines 25245-25255 give wakumba as noun 'canopy', defined as the spreading branches of a tree. Rule 324 admits tree-canopy reference only and leaves branch decomposition, tree species, size/shape, shade, height, location, growth, climbing, cutting, material use, and event propositions closed.",
}

SUPPORT_EVIDENCE = (
    "Patz grammar line 1476 explicitly includes flora among the corporeal objects denoted by nouns. Patz lines "
    "2577-2584 source bare nominative ngali, ngaliny, yubal, yurra, and ngana; 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 transitive perception. Dictionary lines 23876-23883 and 23968-23976 independently attest "
    "running-form nyajin. Exact Patz target search finds only binainyji at lines 1145-1151; the other nine "
    "targets are absent there, so their lexical evidence remains the dictionary. Rule 324 uses only bare support "
    "and past visual perception."
)

TARGET_ORDER = [
    "bajarr", "bikarrakul", "binainyji", "jakalkulu", "jumul-jumul",
    "jika-birra", "kalbawurr", "makaji", "mawu", "wakumba",
]
TARGET_LABELS = {
    "bajarr": "bajarr fern leaves",
    "bikarrakul": "bikarrakul ti tree",
    "binainyji": "binainyji fig-like fruit",
    "jakalkulu": "jakalkulu tree stump",
    "jumul-jumul": "jumul-jumul grass seeds",
    "jika-birra": "jika-birra tobacco leaf",
    "kalbawurr": "kalbawurr cypress-pine pitch",
    "makaji": "makaji onion plant",
    "mawu": "mawu grass",
    "wakumba": "wakumba tree canopy",
}
TARGET_GLOSSES = {
    "bajarr": "bajarr.fern.leaves",
    "bikarrakul": "bikarrakul.ti.tree",
    "binainyji": "binainyji.fig.like.fruit",
    "jakalkulu": "jakalkulu.tree.stump",
    "jumul-jumul": "jumul.jumul.grass.seeds",
    "jika-birra": "jika.birra.tobacco.leaf",
    "kalbawurr": "kalbawurr.cypress.pine.pitch",
    "makaji": "makaji.onion.plant",
    "mawu": "mawu.grass",
    "wakumba": "wakumba.tree.canopy",
}
TARGET_CONFIDENCE = {
    "bajarr": "0.88",
    "bikarrakul": "0.88",
    "binainyji": "0.94",
    "jakalkulu": "0.90",
    "jumul-jumul": "0.89",
    "jika-birra": "0.87",
    "kalbawurr": "0.87",
    "makaji": "0.88",
    "mawu": "0.88",
    "wakumba": "0.90",
}
EXPECTED_TARGET_COVERAGE = {
    "bajarr": 2,
    "bikarrakul": 2,
    "binainyji": 1,
    "jakalkulu": 2,
    "jumul-jumul": 1,
    "jika-birra": 0,
    "kalbawurr": 0,
    "makaji": 0,
    "mawu": 2,
    "wakumba": 2,
}
FRAME_SPECS = [
    ("ngali", "yaluy", "We two, not you, saw", "here", "1du.excl"),
    ("ngaliny", "yinyay", "You and I saw", "there", "1du.incl"),
    ("yubal", "yaluy", "You two saw", "here", "2du"),
    ("yurra", "yinyay", "You all saw", "there", "2pl"),
    ("ngana", "yaluy", "We saw", "here", "1pl.incl"),
]

DENY_KUKU = {
    "ngayu", "yundu", "nyulu", "yulu", "bula", "jana", "iana", "nganjin",
    "ngalingan", "ngalinyan", "yubalan", "ngalininy", "ngalinyiny", "yubaliny",
    "ngalinka", "ngalinyanka", "yubalanka", "ngalinda", "ngalinyanda", "yubalanda",
    "ngalindamuny", "ngalinyandamuny", "yubalandamuny", "ngalinji", "ngalinyanji", "yubalanji",
    "ngalinga", "ngalinyanga", "yubalanga", "yurrangan", "yurraniny", "yurranka", "yurranda",
    "yurrandamuny", "yurranji", "yurranga", "nganangan", "ngananiny", "ngananka", "ngananda",
    "nganandamuny", "ngananji", "ngananga",
    "bajar", "bikarrakal", "binanj-ji", "jalbanj-ji", "jalbainy-ji", "jakal", "jumul",
    "jika", "birra", "kulbawurr", "mawar", "juku",
    "yalay", "yala", "yanyu", "yinya", "yalungku", "yaluyngku", "yinyangka", "yinyayngka",
    "yalamuny", "yinyamuny", "nyajil", "nyaji-l", "nyaji-nka", "nyaji-l-nyaji", "milka",
    "baykal", "jalngkay",
}
DENY_ENGLISH = (
    "mia-mia", "shelter", "gather", "carry", "dry", "material", "manufacture", "cook", "edible",
    "food", "bark", "firewood", "taste", "ripe", "tree source", "fell", "decay", "burn", "sit",
    "stuck", "clothes", "wet season", "sow", "smoke", "chew", "prepare", "trade", "medicine",
    "poison", "toxic", "touch", "ingest", "spear", "dig", "cultivate", "weave", "cut", "bag",
    "shade", "height", "grow", "climb", "possess", "event", "use", "used", "using",
)


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 bajarr fern leaves here.", "Ngali bajarr yaluy nyajin.", "ngali bajarr yaluy nyajin | 1du.excl.NOM bajarr.fern.leaves here see.PST", "r324_1du_excl_here_low_flora_saw_bajarr", ["ngali", "bajarr", "yaluy", "nyajin"]),
    row(2, "We two, not you, saw the bikarrakul ti tree here.", "Ngali bikarrakul yaluy nyajin.", "ngali bikarrakul yaluy nyajin | 1du.excl.NOM bikarrakul.ti.tree here see.PST", "r324_1du_excl_here_low_flora_saw_bikarrakul", ["ngali", "bikarrakul", "yaluy", "nyajin"]),
    row(3, "We two, not you, saw the binainyji fig-like fruit here.", "Ngali binainyji yaluy nyajin.", "ngali binainyji yaluy nyajin | 1du.excl.NOM binainyji.fig.like.fruit here see.PST", "r324_1du_excl_here_low_flora_saw_binainyji", ["ngali", "binainyji", "yaluy", "nyajin"]),
    row(4, "We two, not you, saw the jakalkulu tree stump here.", "Ngali jakalkulu yaluy nyajin.", "ngali jakalkulu yaluy nyajin | 1du.excl.NOM jakalkulu.tree.stump here see.PST", "r324_1du_excl_here_low_flora_saw_jakalkulu", ["ngali", "jakalkulu", "yaluy", "nyajin"]),
    row(5, "We two, not you, saw the jumul-jumul grass seeds here.", "Ngali jumul-jumul yaluy nyajin.", "ngali jumul-jumul yaluy nyajin | 1du.excl.NOM jumul.jumul.grass.seeds here see.PST", "r324_1du_excl_here_low_flora_saw_jumul_jumul", ["ngali", "jumul-jumul", "yaluy", "nyajin"]),
    row(6, "We two, not you, saw the jika-birra tobacco leaf here.", "Ngali jika-birra yaluy nyajin.", "ngali jika-birra yaluy nyajin | 1du.excl.NOM jika.birra.tobacco.leaf here see.PST", "r324_1du_excl_here_low_flora_saw_jika_birra", ["ngali", "jika-birra", "yaluy", "nyajin"]),
    row(7, "We two, not you, saw the kalbawurr cypress-pine pitch here.", "Ngali kalbawurr yaluy nyajin.", "ngali kalbawurr yaluy nyajin | 1du.excl.NOM kalbawurr.cypress.pine.pitch here see.PST", "r324_1du_excl_here_low_flora_saw_kalbawurr", ["ngali", "kalbawurr", "yaluy", "nyajin"]),
    row(8, "We two, not you, saw the makaji onion plant here.", "Ngali makaji yaluy nyajin.", "ngali makaji yaluy nyajin | 1du.excl.NOM makaji.onion.plant here see.PST", "r324_1du_excl_here_low_flora_saw_makaji", ["ngali", "makaji", "yaluy", "nyajin"]),
    row(9, "We two, not you, saw the mawu grass here.", "Ngali mawu yaluy nyajin.", "ngali mawu yaluy nyajin | 1du.excl.NOM mawu.grass here see.PST", "r324_1du_excl_here_low_flora_saw_mawu", ["ngali", "mawu", "yaluy", "nyajin"]),
    row(10, "We two, not you, saw the wakumba tree canopy here.", "Ngali wakumba yaluy nyajin.", "ngali wakumba yaluy nyajin | 1du.excl.NOM wakumba.tree.canopy here see.PST", "r324_1du_excl_here_low_flora_saw_wakumba", ["ngali", "wakumba", "yaluy", "nyajin"]),
    row(11, "You and I saw the bajarr fern leaves there.", "Ngaliny bajarr yinyay nyajin.", "ngaliny bajarr yinyay nyajin | 1du.incl.NOM bajarr.fern.leaves there see.PST", "r324_1du_incl_there_low_flora_saw_bajarr", ["ngaliny", "bajarr", "yinyay", "nyajin"]),
    row(12, "You and I saw the bikarrakul ti tree there.", "Ngaliny bikarrakul yinyay nyajin.", "ngaliny bikarrakul yinyay nyajin | 1du.incl.NOM bikarrakul.ti.tree there see.PST", "r324_1du_incl_there_low_flora_saw_bikarrakul", ["ngaliny", "bikarrakul", "yinyay", "nyajin"]),
    row(13, "You and I saw the binainyji fig-like fruit there.", "Ngaliny binainyji yinyay nyajin.", "ngaliny binainyji yinyay nyajin | 1du.incl.NOM binainyji.fig.like.fruit there see.PST", "r324_1du_incl_there_low_flora_saw_binainyji", ["ngaliny", "binainyji", "yinyay", "nyajin"]),
    row(14, "You and I saw the jakalkulu tree stump there.", "Ngaliny jakalkulu yinyay nyajin.", "ngaliny jakalkulu yinyay nyajin | 1du.incl.NOM jakalkulu.tree.stump there see.PST", "r324_1du_incl_there_low_flora_saw_jakalkulu", ["ngaliny", "jakalkulu", "yinyay", "nyajin"]),
    row(15, "You and I saw the jumul-jumul grass seeds there.", "Ngaliny jumul-jumul yinyay nyajin.", "ngaliny jumul-jumul yinyay nyajin | 1du.incl.NOM jumul.jumul.grass.seeds there see.PST", "r324_1du_incl_there_low_flora_saw_jumul_jumul", ["ngaliny", "jumul-jumul", "yinyay", "nyajin"]),
    row(16, "You and I saw the jika-birra tobacco leaf there.", "Ngaliny jika-birra yinyay nyajin.", "ngaliny jika-birra yinyay nyajin | 1du.incl.NOM jika.birra.tobacco.leaf there see.PST", "r324_1du_incl_there_low_flora_saw_jika_birra", ["ngaliny", "jika-birra", "yinyay", "nyajin"]),
    row(17, "You and I saw the kalbawurr cypress-pine pitch there.", "Ngaliny kalbawurr yinyay nyajin.", "ngaliny kalbawurr yinyay nyajin | 1du.incl.NOM kalbawurr.cypress.pine.pitch there see.PST", "r324_1du_incl_there_low_flora_saw_kalbawurr", ["ngaliny", "kalbawurr", "yinyay", "nyajin"]),
    row(18, "You and I saw the makaji onion plant there.", "Ngaliny makaji yinyay nyajin.", "ngaliny makaji yinyay nyajin | 1du.incl.NOM makaji.onion.plant there see.PST", "r324_1du_incl_there_low_flora_saw_makaji", ["ngaliny", "makaji", "yinyay", "nyajin"]),
    row(19, "You and I saw the mawu grass there.", "Ngaliny mawu yinyay nyajin.", "ngaliny mawu yinyay nyajin | 1du.incl.NOM mawu.grass there see.PST", "r324_1du_incl_there_low_flora_saw_mawu", ["ngaliny", "mawu", "yinyay", "nyajin"]),
    row(20, "You and I saw the wakumba tree canopy there.", "Ngaliny wakumba yinyay nyajin.", "ngaliny wakumba yinyay nyajin | 1du.incl.NOM wakumba.tree.canopy there see.PST", "r324_1du_incl_there_low_flora_saw_wakumba", ["ngaliny", "wakumba", "yinyay", "nyajin"]),
    row(21, "You two saw the bajarr fern leaves here.", "Yubal bajarr yaluy nyajin.", "yubal bajarr yaluy nyajin | 2du.NOM bajarr.fern.leaves here see.PST", "r324_2du_here_low_flora_saw_bajarr", ["yubal", "bajarr", "yaluy", "nyajin"]),
    row(22, "You two saw the bikarrakul ti tree here.", "Yubal bikarrakul yaluy nyajin.", "yubal bikarrakul yaluy nyajin | 2du.NOM bikarrakul.ti.tree here see.PST", "r324_2du_here_low_flora_saw_bikarrakul", ["yubal", "bikarrakul", "yaluy", "nyajin"]),
    row(23, "You two saw the binainyji fig-like fruit here.", "Yubal binainyji yaluy nyajin.", "yubal binainyji yaluy nyajin | 2du.NOM binainyji.fig.like.fruit here see.PST", "r324_2du_here_low_flora_saw_binainyji", ["yubal", "binainyji", "yaluy", "nyajin"]),
    row(24, "You two saw the jakalkulu tree stump here.", "Yubal jakalkulu yaluy nyajin.", "yubal jakalkulu yaluy nyajin | 2du.NOM jakalkulu.tree.stump here see.PST", "r324_2du_here_low_flora_saw_jakalkulu", ["yubal", "jakalkulu", "yaluy", "nyajin"]),
    row(25, "You two saw the jumul-jumul grass seeds here.", "Yubal jumul-jumul yaluy nyajin.", "yubal jumul-jumul yaluy nyajin | 2du.NOM jumul.jumul.grass.seeds here see.PST", "r324_2du_here_low_flora_saw_jumul_jumul", ["yubal", "jumul-jumul", "yaluy", "nyajin"]),
    row(26, "You two saw the jika-birra tobacco leaf here.", "Yubal jika-birra yaluy nyajin.", "yubal jika-birra yaluy nyajin | 2du.NOM jika.birra.tobacco.leaf here see.PST", "r324_2du_here_low_flora_saw_jika_birra", ["yubal", "jika-birra", "yaluy", "nyajin"]),
    row(27, "You two saw the kalbawurr cypress-pine pitch here.", "Yubal kalbawurr yaluy nyajin.", "yubal kalbawurr yaluy nyajin | 2du.NOM kalbawurr.cypress.pine.pitch here see.PST", "r324_2du_here_low_flora_saw_kalbawurr", ["yubal", "kalbawurr", "yaluy", "nyajin"]),
    row(28, "You two saw the makaji onion plant here.", "Yubal makaji yaluy nyajin.", "yubal makaji yaluy nyajin | 2du.NOM makaji.onion.plant here see.PST", "r324_2du_here_low_flora_saw_makaji", ["yubal", "makaji", "yaluy", "nyajin"]),
    row(29, "You two saw the mawu grass here.", "Yubal mawu yaluy nyajin.", "yubal mawu yaluy nyajin | 2du.NOM mawu.grass here see.PST", "r324_2du_here_low_flora_saw_mawu", ["yubal", "mawu", "yaluy", "nyajin"]),
    row(30, "You two saw the wakumba tree canopy here.", "Yubal wakumba yaluy nyajin.", "yubal wakumba yaluy nyajin | 2du.NOM wakumba.tree.canopy here see.PST", "r324_2du_here_low_flora_saw_wakumba", ["yubal", "wakumba", "yaluy", "nyajin"]),
    row(31, "You all saw the bajarr fern leaves there.", "Yurra bajarr yinyay nyajin.", "yurra bajarr yinyay nyajin | 2pl.NOM bajarr.fern.leaves there see.PST", "r324_2pl_there_low_flora_saw_bajarr", ["yurra", "bajarr", "yinyay", "nyajin"]),
    row(32, "You all saw the bikarrakul ti tree there.", "Yurra bikarrakul yinyay nyajin.", "yurra bikarrakul yinyay nyajin | 2pl.NOM bikarrakul.ti.tree there see.PST", "r324_2pl_there_low_flora_saw_bikarrakul", ["yurra", "bikarrakul", "yinyay", "nyajin"]),
    row(33, "You all saw the binainyji fig-like fruit there.", "Yurra binainyji yinyay nyajin.", "yurra binainyji yinyay nyajin | 2pl.NOM binainyji.fig.like.fruit there see.PST", "r324_2pl_there_low_flora_saw_binainyji", ["yurra", "binainyji", "yinyay", "nyajin"]),
    row(34, "You all saw the jakalkulu tree stump there.", "Yurra jakalkulu yinyay nyajin.", "yurra jakalkulu yinyay nyajin | 2pl.NOM jakalkulu.tree.stump there see.PST", "r324_2pl_there_low_flora_saw_jakalkulu", ["yurra", "jakalkulu", "yinyay", "nyajin"]),
    row(35, "You all saw the jumul-jumul grass seeds there.", "Yurra jumul-jumul yinyay nyajin.", "yurra jumul-jumul yinyay nyajin | 2pl.NOM jumul.jumul.grass.seeds there see.PST", "r324_2pl_there_low_flora_saw_jumul_jumul", ["yurra", "jumul-jumul", "yinyay", "nyajin"]),
    row(36, "You all saw the jika-birra tobacco leaf there.", "Yurra jika-birra yinyay nyajin.", "yurra jika-birra yinyay nyajin | 2pl.NOM jika.birra.tobacco.leaf there see.PST", "r324_2pl_there_low_flora_saw_jika_birra", ["yurra", "jika-birra", "yinyay", "nyajin"]),
    row(37, "You all saw the kalbawurr cypress-pine pitch there.", "Yurra kalbawurr yinyay nyajin.", "yurra kalbawurr yinyay nyajin | 2pl.NOM kalbawurr.cypress.pine.pitch there see.PST", "r324_2pl_there_low_flora_saw_kalbawurr", ["yurra", "kalbawurr", "yinyay", "nyajin"]),
    row(38, "You all saw the makaji onion plant there.", "Yurra makaji yinyay nyajin.", "yurra makaji yinyay nyajin | 2pl.NOM makaji.onion.plant there see.PST", "r324_2pl_there_low_flora_saw_makaji", ["yurra", "makaji", "yinyay", "nyajin"]),
    row(39, "You all saw the mawu grass there.", "Yurra mawu yinyay nyajin.", "yurra mawu yinyay nyajin | 2pl.NOM mawu.grass there see.PST", "r324_2pl_there_low_flora_saw_mawu", ["yurra", "mawu", "yinyay", "nyajin"]),
    row(40, "You all saw the wakumba tree canopy there.", "Yurra wakumba yinyay nyajin.", "yurra wakumba yinyay nyajin | 2pl.NOM wakumba.tree.canopy there see.PST", "r324_2pl_there_low_flora_saw_wakumba", ["yurra", "wakumba", "yinyay", "nyajin"]),
    row(41, "We saw the bajarr fern leaves here.", "Ngana bajarr yaluy nyajin.", "ngana bajarr yaluy nyajin | 1pl.incl.NOM bajarr.fern.leaves here see.PST", "r324_1pl_incl_here_low_flora_saw_bajarr", ["ngana", "bajarr", "yaluy", "nyajin"]),
    row(42, "We saw the bikarrakul ti tree here.", "Ngana bikarrakul yaluy nyajin.", "ngana bikarrakul yaluy nyajin | 1pl.incl.NOM bikarrakul.ti.tree here see.PST", "r324_1pl_incl_here_low_flora_saw_bikarrakul", ["ngana", "bikarrakul", "yaluy", "nyajin"]),
    row(43, "We saw the binainyji fig-like fruit here.", "Ngana binainyji yaluy nyajin.", "ngana binainyji yaluy nyajin | 1pl.incl.NOM binainyji.fig.like.fruit here see.PST", "r324_1pl_incl_here_low_flora_saw_binainyji", ["ngana", "binainyji", "yaluy", "nyajin"]),
    row(44, "We saw the jakalkulu tree stump here.", "Ngana jakalkulu yaluy nyajin.", "ngana jakalkulu yaluy nyajin | 1pl.incl.NOM jakalkulu.tree.stump here see.PST", "r324_1pl_incl_here_low_flora_saw_jakalkulu", ["ngana", "jakalkulu", "yaluy", "nyajin"]),
    row(45, "We saw the jumul-jumul grass seeds here.", "Ngana jumul-jumul yaluy nyajin.", "ngana jumul-jumul yaluy nyajin | 1pl.incl.NOM jumul.jumul.grass.seeds here see.PST", "r324_1pl_incl_here_low_flora_saw_jumul_jumul", ["ngana", "jumul-jumul", "yaluy", "nyajin"]),
    row(46, "We saw the jika-birra tobacco leaf here.", "Ngana jika-birra yaluy nyajin.", "ngana jika-birra yaluy nyajin | 1pl.incl.NOM jika.birra.tobacco.leaf here see.PST", "r324_1pl_incl_here_low_flora_saw_jika_birra", ["ngana", "jika-birra", "yaluy", "nyajin"]),
    row(47, "We saw the kalbawurr cypress-pine pitch here.", "Ngana kalbawurr yaluy nyajin.", "ngana kalbawurr yaluy nyajin | 1pl.incl.NOM kalbawurr.cypress.pine.pitch here see.PST", "r324_1pl_incl_here_low_flora_saw_kalbawurr", ["ngana", "kalbawurr", "yaluy", "nyajin"]),
    row(48, "We saw the makaji onion plant here.", "Ngana makaji yaluy nyajin.", "ngana makaji yaluy nyajin | 1pl.incl.NOM makaji.onion.plant here see.PST", "r324_1pl_incl_here_low_flora_saw_makaji", ["ngana", "makaji", "yaluy", "nyajin"]),
    row(49, "We saw the mawu grass here.", "Ngana mawu yaluy nyajin.", "ngana mawu yaluy nyajin | 1pl.incl.NOM mawu.grass here see.PST", "r324_1pl_incl_here_low_flora_saw_mawu", ["ngana", "mawu", "yaluy", "nyajin"]),
    row(50, "We saw the wakumba tree canopy here.", "Ngana wakumba yaluy nyajin.", "ngana wakumba yaluy nyajin | 1pl.incl.NOM wakumba.tree.canopy here see.PST", "r324_1pl_incl_here_low_flora_saw_wakumba", ["ngana", "wakumba", "yaluy", "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({w for w in DENY_KUKU if re.search(rf"(^|\s){re.escape(w)}([\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 expected {expected_kuku!r}, got {kuku!r}")
        if english != expected_english:
            issues.append(f"{seq}: English mismatch expected {expected_english!r}, got {english!r}")
        if analysis != expected_analysis:
            issues.append(f"{seq}: analysis mismatch expected {expected_analysis!r}, got {analysis!r}")
        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("r324_"):
            issues.append(f"{seq}: frame not r324 {frame}")
        if TARGET_EVIDENCE[target] not in evidence or SUPPORT_EVIDENCE not in evidence:
            issues.append(f"{seq}: evidence contract mismatch")
        if confidence != TARGET_CONFIDENCE[target]:
            issues.append(f"{seq}: confidence mismatch {confidence}")
    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; rerun source/scope audit: {target_counts}")
    support_counts = count_words(db, ["ngali", "ngaliny", "yubal", "yurra", "ngana", "yaluy", "yinyay", "nyajin"])
    collisions = []
    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!='rejected'",
            (kuku,),
        ).fetchall()
        if hit:
            collisions.append((kuku, hit))
    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 FLORA NON-SINGULAR PAST PERCEPTION AFTER RULE 323 (Rule 324). 50 under-review rows over "
        "three zero-use, two one-use, and five two-use noun heads: bajarr, bikarrakul, binainyji, jakalkulu, "
        "jumul-jumul, jika-birra, kalbawurr, makaji, mawu, wakumba. SUPPORT: bare nominative ngali, ngaliny, "
        "yubal, yurra, ngana; Yalanji yaluy/yinyay; dictionary-attested past nyajin. Exact conservative flora "
        "labels only. No alternate sense, source-prose use/event, edibility/food, poison, shelter, clothing, "
        "material manufacture, productive compound/reduplication, target case, nonpast/purposive/reduplicated "
        "perception, support inflection, or carried trap."
    )
    cur = db.execute(
        "INSERT INTO batches(label,cheatsheet_version,guide_version,notes,created_at) VALUES(?,?,?,?,?)",
        (LABEL, "Rule 324 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, en, ku, an, fr, ti, wo, lo, ev, "under_review", co,
             "project_approved_synthetic_pending_elder_verification", "codex-main", NOW, NOW)
            for seq, en, ku, an, fr, ti, wo, lo, ev, co in ROWS
        ],
    )
    record_event(db, batch_label=LABEL, phase="source", event_type="source-readback", actor="codex", detail="Reread all ten selected dictionary flora entries; exact-searched every target in Patz (binainyji occurs independently, the other nine do not); reread Patz flora noun status, non-singular nominative pronouns, Yalanji local demonstratives, past -ny, perception A/O syntax, and dictionary running-form nyajin before authoring Rule 324.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="candidate-audit", actor="codex", detail="Structured dictionary-to-corpus audit compared zero/low-use noun pools across semantic domains. Rejected contradictory/undefined entries, Nyungkul-only forms, place names, post-contact and hazardous food/drink heads, culturally sensitive or stigmatizing human/spirit labels, weapon/euphemism ambiguity, coercive implements, and flora entries with unresolved sense/dialect drift. Selected ten direct, lint-safe flora nouns with stable visible readings and coverage 0-2.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="low-flora-nonsingular-past-scope", actor="codex", detail="Locked three zero-use, two one-use, and five two-use dictionary flora heads to bare reference in five sourced non-singular past-perception frames. Bajarr remains double-r fern leaves; binainyji remains the Patz fig-like fruit; jumul-jumul and jika-birra remain exact whole heads; kalbawurr remains separate from kulbawurr; no source use, event, property, case, or productive morphology is opened.", 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 324 exact Kuku surfaces are internally unique and returned no accepted, revised, or under-review 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 Kuku/English/analysis/evidence/confidence contracts, one selected flora head each, bare non-singular nominative pronouns and Yalanji demonstratives, final nyajin, no loans, no denied forms, and no alternate-sense, source-use, food, poison, shelter, clothing, material, productive-morphology, case, or support drift.", command="python3 -m py_compile batch_scripts/bank_366.py batch_scripts/close_366.py && explicit-row/lesson/lexeme AST inventory && scan_static/lint probes", output_excerpt="50 explicit rows; scan_static issues 0; 50 linter probes issues 0; collisions 0", artifact_path="batch_scripts/bank_366.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="codex", detail=f"Banked 50 Rule 324 rows as under_review. Verified remains {verified_before}; Kuku words remain {words_before}.", command="python3 batch_scripts/bank_366.py", output_excerpt=f"banked batch-366: 50 under_review; verified_before={verified_before}; kuku_words_before={words_before}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit()
    print("banked batch-366: 50 rows under_review")
    return 0


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