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

TARGET_EVIDENCE = {
    "jimu": "Dictionary yaml lines 9295-9303 give jimu as the fauna-insect noun 'grasshopper'. Rule 331 admits grasshopper reference only and leaves number, body, colour, movement, jumping, flying, swarming, feeding, habitat, season, catching, source, possession, and event propositions closed.",
    "kira-kira": "Dictionary yaml lines 14450-14463 give exact hyphenated kira-kira as a full-reduplicated fauna-insect noun 'black ant', based on kira, and warn that it is homophonous with a reduplication of kira 'baby girl' but semantically distinct. Rule 331 admits the whole black-ant head only and leaves free-base use, productive reduplication, child reference, homonym identity, colour predication, colony, nest, behavior, food, sting/bite, source, possession, and events closed.",
    "kuran": "Dictionary yaml lines 16065-16076 give kuran as the fauna-insect noun 'larva of case moth', with prose saying it is edible and found in green wood. Rule 331 admits case-moth-larva reference only and leaves edibility, food, collection, green wood, habitat, life cycle, moth transformation, source, possession, and event propositions closed.",
    "kurrmaja": "Dictionary yaml lines 16507-16515 give kurrmaja as the fauna-insect noun 'larvae of green ants'. Rule 331 admits kurrmaja-larvae reference only and leaves green-ant identity/behavior, eggs or pupae, colony, nest, food, medicine, collection, preparation, source, possession, and event propositions closed.",
    "murma": "Dictionary yaml lines 20936-20944 give murma as the fauna-insect noun 'wasp', with prose specifying a small yellow paper wasp with a bad sting and a nest hanging in trees. Rule 331 admits wasp reference only and leaves size, paper-wasp taxonomy, colour, sting, pain/danger, nest, tree habitat, behavior, source, possession, and event propositions closed.",
    "durra": "Dictionary yaml lines 6696-6707 give durra as the fauna-insect noun 'caterpillar, worm', with caterpillar as the primary gloss. Rule 331 selects caterpillar reference only and leaves worm equivalence, feeding, growth, wrapping, transformation, moth identity, life cycle, habitat, source, possession, and event propositions closed.",
    "jiljay": "Dictionary yaml lines 9160-9168 give jiljay as the fauna-insect noun 'grub found in antbed'. Rule 331 admits jiljay-grub reference only and leaves antbed location/habitat, gathering, fishing bait, strength, weight, catching, source, possession, and prior-row event propositions closed.",
    "kandal": "Dictionary yaml lines 13147-13157 give kandal as the fauna-insect noun 'maggot' and comment that a maggot is a fly larva. Rule 331 admits maggot reference only and leaves fly identity, egg/larval relation, life cycle, carrion or food spoilage, habitat, source, possession, and event propositions closed.",
    "kinga": "Dictionary yaml lines 14352-14360 give kinga as the fauna-insect noun 'caterpillar'; the adjacent derived verb kinga-dungay at lines 14361-14372 means a shocked feeling or goose pimples. Rule 331 admits caterpillar reference only and leaves the derived body-state form, derivational decomposition, feeding, movement, transformation, habitat, source, possession, and event propositions closed.",
    "birinjil": "Dictionary yaml lines 3118-3126 give birinjil as the fauna-insect noun 'centipede'. Rule 331 admits centipede reference only and leaves body/leg count, crawling, bark/stone habitat, bite/danger, blanket/bedding, source, possession, and prior-row event propositions closed.",
}

SUPPORT_EVIDENCE = (
    "Patz line 1476 includes fauna among noun referents. Lines 2577-2586 source bare nominative ngayu, yundu, "
    "nyulu, and bula; running examples at lines 1947 and 2686 establish third-plural jana despite OCR iana in "
    "the paradigm table; 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 search for all ten selected insect heads returned no occurrences, so every target sense "
    "remains dictionary-bounded. Rule 331 uses only bare insect reference and past visual perception."
)

TARGET_ORDER = ["jimu", "kira-kira", "kuran", "kurrmaja", "murma", "durra", "jiljay", "kandal", "kinga", "birinjil"]
TARGET_LABELS = {
    "jimu": "jimu grasshopper",
    "kira-kira": "kira-kira black ant",
    "kuran": "kuran case-moth larva",
    "kurrmaja": "kurrmaja larvae",
    "murma": "murma wasp",
    "durra": "durra caterpillar",
    "jiljay": "jiljay grub",
    "kandal": "kandal maggot",
    "kinga": "kinga caterpillar",
    "birinjil": "birinjil centipede",
}
TARGET_GLOSSES = {
    "jimu": "jimu.grasshopper",
    "kira-kira": "kira.kira.black.ant",
    "kuran": "kuran.case.moth.larva",
    "kurrmaja": "kurrmaja.larvae",
    "murma": "murma.wasp",
    "durra": "durra.caterpillar",
    "jiljay": "jiljay.grub",
    "kandal": "kandal.maggot",
    "kinga": "kinga.caterpillar",
    "birinjil": "birinjil.centipede",
}
TARGET_CONFIDENCE = {
    "jimu": "0.94", "kira-kira": "0.92", "kuran": "0.91", "kurrmaja": "0.91", "murma": "0.92",
    "durra": "0.90", "jiljay": "0.90", "kandal": "0.93", "kinga": "0.94", "birinjil": "0.94",
}
EXPECTED_TARGET_COVERAGE = {"jimu": 5, "kira-kira": 5, "kuran": 5, "kurrmaja": 5, "murma": 5, "durra": 6, "jiljay": 6, "kandal": 6, "kinga": 6, "birinjil": 7}
FRAME_SPECS = [
    ("ngayu", "yaluy", "I saw", "here", "1sg"),
    ("yundu", "yinyay", "You saw", "there", "2sg"),
    ("nyulu", "yaluy", "He saw", "here", "3sg"),
    ("bula", "yinyay", "The two of them saw", "there", "3du"),
    ("jana", "yaluy", "They saw", "here", "3pl"),
]

DENY_KUKU = {
    "ngali", "ngaliny", "yubal", "yurra", "ngana", "nganjin", "yulu", "iana",
    "nganya", "yununy", "nyunguny", "bulangan", "ianangan", "ngaykunku", "yununku", "nyungunku",
    "bulanka", "iananka", "ngaykundumuny", "yunundumuny", "nyungundumuny", "bulandamuny", "ianandamuny",
    "ngaykunji", "yununji", "nyungunji", "bulanji", "iananji", "ngayku", "yunu", "nyunju", "bulanga", "iananga",
    "dabadaba", "dujandujan", "jingka-jingka", "kuja", "walbul-walbul", "malal", "kira", "kinga-dungay",
    "yalay", "yala", "yanyu", "yinya", "yalungku", "yaluyngku", "yinyangka", "yinyayngka", "yalamuny", "yinyamuny",
    "nyajil", "nyaji-l", "nyaji-nka", "nyaji-l-nyaji", "milka", "baykal", "jalngkay",
}
DENY_ENGLISH = (
    "worm", "fly larva", "baby girl", "homophon", "free base", "productive reduplication", "child",
    "colony", "nest", "behavior", "food", "edible", "collect", "green wood", "habitat", "life cycle",
    "transform", "egg", "pupa", "medicine", "prepare", "small", "paper wasp", "yellow", "sting", "pain",
    "danger", "tree", "antbed", "bait", "strength", "weight", "spoil", "carrion", "goose pimples",
    "body state", "leg count", "crawl", "bark", "stone", "blanket", "bedding", "source", "possess", "event",
)


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, "I saw the jimu grasshopper here.", "Ngayu jimu yaluy nyajin.", "ngayu jimu yaluy nyajin | 1sg.NOM jimu.grasshopper here see.PST", "r331_1sg_here_low_insect_saw_jimu", ["ngayu", "jimu", "yaluy", "nyajin"]),
    row(2, "I saw the kira-kira black ant here.", "Ngayu kira-kira yaluy nyajin.", "ngayu kira-kira yaluy nyajin | 1sg.NOM kira.kira.black.ant here see.PST", "r331_1sg_here_low_insect_saw_kira_kira", ["ngayu", "kira-kira", "yaluy", "nyajin"]),
    row(3, "I saw the kuran case-moth larva here.", "Ngayu kuran yaluy nyajin.", "ngayu kuran yaluy nyajin | 1sg.NOM kuran.case.moth.larva here see.PST", "r331_1sg_here_low_insect_saw_kuran", ["ngayu", "kuran", "yaluy", "nyajin"]),
    row(4, "I saw the kurrmaja larvae here.", "Ngayu kurrmaja yaluy nyajin.", "ngayu kurrmaja yaluy nyajin | 1sg.NOM kurrmaja.larvae here see.PST", "r331_1sg_here_low_insect_saw_kurrmaja", ["ngayu", "kurrmaja", "yaluy", "nyajin"]),
    row(5, "I saw the murma wasp here.", "Ngayu murma yaluy nyajin.", "ngayu murma yaluy nyajin | 1sg.NOM murma.wasp here see.PST", "r331_1sg_here_low_insect_saw_murma", ["ngayu", "murma", "yaluy", "nyajin"]),
    row(6, "I saw the durra caterpillar here.", "Ngayu durra yaluy nyajin.", "ngayu durra yaluy nyajin | 1sg.NOM durra.caterpillar here see.PST", "r331_1sg_here_low_insect_saw_durra", ["ngayu", "durra", "yaluy", "nyajin"]),
    row(7, "I saw the jiljay grub here.", "Ngayu jiljay yaluy nyajin.", "ngayu jiljay yaluy nyajin | 1sg.NOM jiljay.grub here see.PST", "r331_1sg_here_low_insect_saw_jiljay", ["ngayu", "jiljay", "yaluy", "nyajin"]),
    row(8, "I saw the kandal maggot here.", "Ngayu kandal yaluy nyajin.", "ngayu kandal yaluy nyajin | 1sg.NOM kandal.maggot here see.PST", "r331_1sg_here_low_insect_saw_kandal", ["ngayu", "kandal", "yaluy", "nyajin"]),
    row(9, "I saw the kinga caterpillar here.", "Ngayu kinga yaluy nyajin.", "ngayu kinga yaluy nyajin | 1sg.NOM kinga.caterpillar here see.PST", "r331_1sg_here_low_insect_saw_kinga", ["ngayu", "kinga", "yaluy", "nyajin"]),
    row(10, "I saw the birinjil centipede here.", "Ngayu birinjil yaluy nyajin.", "ngayu birinjil yaluy nyajin | 1sg.NOM birinjil.centipede here see.PST", "r331_1sg_here_low_insect_saw_birinjil", ["ngayu", "birinjil", "yaluy", "nyajin"]),
    row(11, "You saw the jimu grasshopper there.", "Yundu jimu yinyay nyajin.", "yundu jimu yinyay nyajin | 2sg.NOM jimu.grasshopper there see.PST", "r331_2sg_there_low_insect_saw_jimu", ["yundu", "jimu", "yinyay", "nyajin"]),
    row(12, "You saw the kira-kira black ant there.", "Yundu kira-kira yinyay nyajin.", "yundu kira-kira yinyay nyajin | 2sg.NOM kira.kira.black.ant there see.PST", "r331_2sg_there_low_insect_saw_kira_kira", ["yundu", "kira-kira", "yinyay", "nyajin"]),
    row(13, "You saw the kuran case-moth larva there.", "Yundu kuran yinyay nyajin.", "yundu kuran yinyay nyajin | 2sg.NOM kuran.case.moth.larva there see.PST", "r331_2sg_there_low_insect_saw_kuran", ["yundu", "kuran", "yinyay", "nyajin"]),
    row(14, "You saw the kurrmaja larvae there.", "Yundu kurrmaja yinyay nyajin.", "yundu kurrmaja yinyay nyajin | 2sg.NOM kurrmaja.larvae there see.PST", "r331_2sg_there_low_insect_saw_kurrmaja", ["yundu", "kurrmaja", "yinyay", "nyajin"]),
    row(15, "You saw the murma wasp there.", "Yundu murma yinyay nyajin.", "yundu murma yinyay nyajin | 2sg.NOM murma.wasp there see.PST", "r331_2sg_there_low_insect_saw_murma", ["yundu", "murma", "yinyay", "nyajin"]),
    row(16, "You saw the durra caterpillar there.", "Yundu durra yinyay nyajin.", "yundu durra yinyay nyajin | 2sg.NOM durra.caterpillar there see.PST", "r331_2sg_there_low_insect_saw_durra", ["yundu", "durra", "yinyay", "nyajin"]),
    row(17, "You saw the jiljay grub there.", "Yundu jiljay yinyay nyajin.", "yundu jiljay yinyay nyajin | 2sg.NOM jiljay.grub there see.PST", "r331_2sg_there_low_insect_saw_jiljay", ["yundu", "jiljay", "yinyay", "nyajin"]),
    row(18, "You saw the kandal maggot there.", "Yundu kandal yinyay nyajin.", "yundu kandal yinyay nyajin | 2sg.NOM kandal.maggot there see.PST", "r331_2sg_there_low_insect_saw_kandal", ["yundu", "kandal", "yinyay", "nyajin"]),
    row(19, "You saw the kinga caterpillar there.", "Yundu kinga yinyay nyajin.", "yundu kinga yinyay nyajin | 2sg.NOM kinga.caterpillar there see.PST", "r331_2sg_there_low_insect_saw_kinga", ["yundu", "kinga", "yinyay", "nyajin"]),
    row(20, "You saw the birinjil centipede there.", "Yundu birinjil yinyay nyajin.", "yundu birinjil yinyay nyajin | 2sg.NOM birinjil.centipede there see.PST", "r331_2sg_there_low_insect_saw_birinjil", ["yundu", "birinjil", "yinyay", "nyajin"]),
    row(21, "He saw the jimu grasshopper here.", "Nyulu jimu yaluy nyajin.", "nyulu jimu yaluy nyajin | 3sg.NOM jimu.grasshopper here see.PST", "r331_3sg_here_low_insect_saw_jimu", ["nyulu", "jimu", "yaluy", "nyajin"]),
    row(22, "He saw the kira-kira black ant here.", "Nyulu kira-kira yaluy nyajin.", "nyulu kira-kira yaluy nyajin | 3sg.NOM kira.kira.black.ant here see.PST", "r331_3sg_here_low_insect_saw_kira_kira", ["nyulu", "kira-kira", "yaluy", "nyajin"]),
    row(23, "He saw the kuran case-moth larva here.", "Nyulu kuran yaluy nyajin.", "nyulu kuran yaluy nyajin | 3sg.NOM kuran.case.moth.larva here see.PST", "r331_3sg_here_low_insect_saw_kuran", ["nyulu", "kuran", "yaluy", "nyajin"]),
    row(24, "He saw the kurrmaja larvae here.", "Nyulu kurrmaja yaluy nyajin.", "nyulu kurrmaja yaluy nyajin | 3sg.NOM kurrmaja.larvae here see.PST", "r331_3sg_here_low_insect_saw_kurrmaja", ["nyulu", "kurrmaja", "yaluy", "nyajin"]),
    row(25, "He saw the murma wasp here.", "Nyulu murma yaluy nyajin.", "nyulu murma yaluy nyajin | 3sg.NOM murma.wasp here see.PST", "r331_3sg_here_low_insect_saw_murma", ["nyulu", "murma", "yaluy", "nyajin"]),
    row(26, "He saw the durra caterpillar here.", "Nyulu durra yaluy nyajin.", "nyulu durra yaluy nyajin | 3sg.NOM durra.caterpillar here see.PST", "r331_3sg_here_low_insect_saw_durra", ["nyulu", "durra", "yaluy", "nyajin"]),
    row(27, "He saw the jiljay grub here.", "Nyulu jiljay yaluy nyajin.", "nyulu jiljay yaluy nyajin | 3sg.NOM jiljay.grub here see.PST", "r331_3sg_here_low_insect_saw_jiljay", ["nyulu", "jiljay", "yaluy", "nyajin"]),
    row(28, "He saw the kandal maggot here.", "Nyulu kandal yaluy nyajin.", "nyulu kandal yaluy nyajin | 3sg.NOM kandal.maggot here see.PST", "r331_3sg_here_low_insect_saw_kandal", ["nyulu", "kandal", "yaluy", "nyajin"]),
    row(29, "He saw the kinga caterpillar here.", "Nyulu kinga yaluy nyajin.", "nyulu kinga yaluy nyajin | 3sg.NOM kinga.caterpillar here see.PST", "r331_3sg_here_low_insect_saw_kinga", ["nyulu", "kinga", "yaluy", "nyajin"]),
    row(30, "He saw the birinjil centipede here.", "Nyulu birinjil yaluy nyajin.", "nyulu birinjil yaluy nyajin | 3sg.NOM birinjil.centipede here see.PST", "r331_3sg_here_low_insect_saw_birinjil", ["nyulu", "birinjil", "yaluy", "nyajin"]),
    row(31, "The two of them saw the jimu grasshopper there.", "Bula jimu yinyay nyajin.", "bula jimu yinyay nyajin | 3du.NOM jimu.grasshopper there see.PST", "r331_3du_there_low_insect_saw_jimu", ["bula", "jimu", "yinyay", "nyajin"]),
    row(32, "The two of them saw the kira-kira black ant there.", "Bula kira-kira yinyay nyajin.", "bula kira-kira yinyay nyajin | 3du.NOM kira.kira.black.ant there see.PST", "r331_3du_there_low_insect_saw_kira_kira", ["bula", "kira-kira", "yinyay", "nyajin"]),
    row(33, "The two of them saw the kuran case-moth larva there.", "Bula kuran yinyay nyajin.", "bula kuran yinyay nyajin | 3du.NOM kuran.case.moth.larva there see.PST", "r331_3du_there_low_insect_saw_kuran", ["bula", "kuran", "yinyay", "nyajin"]),
    row(34, "The two of them saw the kurrmaja larvae there.", "Bula kurrmaja yinyay nyajin.", "bula kurrmaja yinyay nyajin | 3du.NOM kurrmaja.larvae there see.PST", "r331_3du_there_low_insect_saw_kurrmaja", ["bula", "kurrmaja", "yinyay", "nyajin"]),
    row(35, "The two of them saw the murma wasp there.", "Bula murma yinyay nyajin.", "bula murma yinyay nyajin | 3du.NOM murma.wasp there see.PST", "r331_3du_there_low_insect_saw_murma", ["bula", "murma", "yinyay", "nyajin"]),
    row(36, "The two of them saw the durra caterpillar there.", "Bula durra yinyay nyajin.", "bula durra yinyay nyajin | 3du.NOM durra.caterpillar there see.PST", "r331_3du_there_low_insect_saw_durra", ["bula", "durra", "yinyay", "nyajin"]),
    row(37, "The two of them saw the jiljay grub there.", "Bula jiljay yinyay nyajin.", "bula jiljay yinyay nyajin | 3du.NOM jiljay.grub there see.PST", "r331_3du_there_low_insect_saw_jiljay", ["bula", "jiljay", "yinyay", "nyajin"]),
    row(38, "The two of them saw the kandal maggot there.", "Bula kandal yinyay nyajin.", "bula kandal yinyay nyajin | 3du.NOM kandal.maggot there see.PST", "r331_3du_there_low_insect_saw_kandal", ["bula", "kandal", "yinyay", "nyajin"]),
    row(39, "The two of them saw the kinga caterpillar there.", "Bula kinga yinyay nyajin.", "bula kinga yinyay nyajin | 3du.NOM kinga.caterpillar there see.PST", "r331_3du_there_low_insect_saw_kinga", ["bula", "kinga", "yinyay", "nyajin"]),
    row(40, "The two of them saw the birinjil centipede there.", "Bula birinjil yinyay nyajin.", "bula birinjil yinyay nyajin | 3du.NOM birinjil.centipede there see.PST", "r331_3du_there_low_insect_saw_birinjil", ["bula", "birinjil", "yinyay", "nyajin"]),
    row(41, "They saw the jimu grasshopper here.", "Jana jimu yaluy nyajin.", "jana jimu yaluy nyajin | 3pl.NOM jimu.grasshopper here see.PST", "r331_3pl_here_low_insect_saw_jimu", ["jana", "jimu", "yaluy", "nyajin"]),
    row(42, "They saw the kira-kira black ant here.", "Jana kira-kira yaluy nyajin.", "jana kira-kira yaluy nyajin | 3pl.NOM kira.kira.black.ant here see.PST", "r331_3pl_here_low_insect_saw_kira_kira", ["jana", "kira-kira", "yaluy", "nyajin"]),
    row(43, "They saw the kuran case-moth larva here.", "Jana kuran yaluy nyajin.", "jana kuran yaluy nyajin | 3pl.NOM kuran.case.moth.larva here see.PST", "r331_3pl_here_low_insect_saw_kuran", ["jana", "kuran", "yaluy", "nyajin"]),
    row(44, "They saw the kurrmaja larvae here.", "Jana kurrmaja yaluy nyajin.", "jana kurrmaja yaluy nyajin | 3pl.NOM kurrmaja.larvae here see.PST", "r331_3pl_here_low_insect_saw_kurrmaja", ["jana", "kurrmaja", "yaluy", "nyajin"]),
    row(45, "They saw the murma wasp here.", "Jana murma yaluy nyajin.", "jana murma yaluy nyajin | 3pl.NOM murma.wasp here see.PST", "r331_3pl_here_low_insect_saw_murma", ["jana", "murma", "yaluy", "nyajin"]),
    row(46, "They saw the durra caterpillar here.", "Jana durra yaluy nyajin.", "jana durra yaluy nyajin | 3pl.NOM durra.caterpillar here see.PST", "r331_3pl_here_low_insect_saw_durra", ["jana", "durra", "yaluy", "nyajin"]),
    row(47, "They saw the jiljay grub here.", "Jana jiljay yaluy nyajin.", "jana jiljay yaluy nyajin | 3pl.NOM jiljay.grub here see.PST", "r331_3pl_here_low_insect_saw_jiljay", ["jana", "jiljay", "yaluy", "nyajin"]),
    row(48, "They saw the kandal maggot here.", "Jana kandal yaluy nyajin.", "jana kandal yaluy nyajin | 3pl.NOM kandal.maggot here see.PST", "r331_3pl_here_low_insect_saw_kandal", ["jana", "kandal", "yaluy", "nyajin"]),
    row(49, "They saw the kinga caterpillar here.", "Jana kinga yaluy nyajin.", "jana kinga yaluy nyajin | 3pl.NOM kinga.caterpillar here see.PST", "r331_3pl_here_low_insect_saw_kinga", ["jana", "kinga", "yaluy", "nyajin"]),
    row(50, "They saw the birinjil centipede here.", "Jana birinjil yaluy nyajin.", "jana birinjil yaluy nyajin | 3pl.NOM birinjil.centipede here see.PST", "r331_3pl_here_low_insect_saw_birinjil", ["jana", "birinjil", "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")
        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("r331_"): issues.append(f"{seq}: frame not r331")
        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_counts = count_words(db, ["ngayu", "yundu", "nyulu", "bula", "jana", "yaluy", "yinyay", "nyajin"])
    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 INSECTS COMPLEMENTARY SINGULAR/THIRD-PERSON PAST PERCEPTION AFTER RULE 330 (Rule 331). 50 under-review rows over ten 5-7-use direct fauna-insect noun heads: jimu, kira-kira, kuran, kurrmaja, murma, durra, jiljay, kandal, kinga, and birinjil. Initial Rule-317-orientation frames collided with Batch 359 for five heads; every deictic band was inverted and all 50 complementary surfaces collision-probed. Exact referential senses only; no alternate sense, reduplicative/derivational analysis, habitat, food/use, life cycle, danger, body, source, 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 331 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, 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 insect records and their adjacent polysemy/derivation notes; exact Patz target search returned no occurrences; reread Patz fauna noun status, singular/third-person pronouns, Yalanji demonstratives, past, perception A/O, and dictionary running nyajin.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="candidate-audit", actor="codex", detail="Structured fauna-insect audit selected ten unique direct noun records, all non-loan and coverage 5-7. Excluded unhyphenated repeated-looking dabadaba/dujandujan, polysemous jingka-jingka/kuja/walbul-walbul/malal, free base kira, adjacent derived kinga-dungay, and every non-selected sense or source-commentary proposition.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="collision-resolution", actor="codex", detail="Initial Rule-317-orientation frames collided with Batch 359 for kuran, kurrmaja, murma, durra, and jiljay. Inverting each here/there band yielded a complementary paradigm with zero collisions for all ten targets; no existing row was overwritten or weakened.", 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 331 complementary 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 insect head each, bare nominative A and absolutive O, Yalanji demonstratives, final nyajin, no loans, alternate senses, morphology, habitat/use, source, case, or support drift.", command="python3 -m py_compile batch_scripts/bank_373.py batch_scripts/close_373.py && AST/static/lint probes", output_excerpt="50 explicit rows; scan_static 0; 50 linter probes 0; collisions 0", artifact_path="batch_scripts/bank_373.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="codex", detail=f"Banked 50 Rule 331 rows as under_review. Verified remains {verified_before}; Kuku words remain {words_before}.", command="python3 batch_scripts/bank_373.py", output_excerpt=f"banked batch-373: 50 under_review; verified_before={verified_before}; words_before={words_before}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit(); print("banked batch-373: 50 rows under_review"); return 0


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