#!/usr/bin/env python3
"""Bank batch-374: Rule 332 insect non-singular past-perception consolidation."""

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-374"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-374-insect-nonsingular-past-perception-consolidation-after-rule331-process.md"

TARGET_EVIDENCE = {
    "jimu": "Dictionary yaml lines 9295-9303 give jimu as the fauna-insect noun 'grasshopper'. Rule 332 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 332 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 332 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 332 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 332 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 332 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 332 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 332 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 332 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 332 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-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 perception. Dictionary examples at lines "
    "23876-23883 and 23968-23976 independently contain running-form nyajin. Fresh exact Patz search for all ten "
    "selected insect heads returned no occurrences, so every target sense remains dictionary-bounded. Rule 332 "
    "adds five non-singular participant-number contrasts absent for every target and 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": 10, "kira-kira": 10, "kuran": 10, "kurrmaja": 10, "murma": 10, "durra": 11, "jiljay": 11, "kandal": 11, "kinga": 11, "birinjil": 12}
EXPECTED_SUPPORT_COVERAGE = {"ngali": 583, "ngaliny": 525, "yubal": 535, "yurra": 520, "ngana": 1095, "yaluy": 4152, "yinyay": 4384, "nyajin": 1650}
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", "nganangan", "ngalininy", "ngalinyiny", "yubaliny",
    "yurraniny", "ngananiny", "ngalinka", "ngalinyanka", "yubalanka", "yurranka", "ngananka",
    "ngalinda", "ngalinyanda", "yubalanda", "yurranda", "ngananda", "ngalindamuny",
    "ngalinyandamuny", "yubalandamuny", "yurrandamuny", "nganandamuny", "ngalinji", "ngalinyanji",
    "yubalanji", "yurranji", "ngananji", "ngalinga", "ngalinyanga", "yubalanga", "yurranga", "ngananga",
    "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, "We two, not you, saw the jimu grasshopper here.", "Ngali jimu yaluy nyajin.", "ngali jimu yaluy nyajin | 1du.excl.NOM jimu.grasshopper here see.PST", "r332_1du_excl_here_insect_saw_jimu", ["ngali", "jimu", "yaluy", "nyajin"]),
    row(2, "We two, not you, saw the kira-kira black ant here.", "Ngali kira-kira yaluy nyajin.", "ngali kira-kira yaluy nyajin | 1du.excl.NOM kira.kira.black.ant here see.PST", "r332_1du_excl_here_insect_saw_kira_kira", ["ngali", "kira-kira", "yaluy", "nyajin"]),
    row(3, "We two, not you, saw the kuran case-moth larva here.", "Ngali kuran yaluy nyajin.", "ngali kuran yaluy nyajin | 1du.excl.NOM kuran.case.moth.larva here see.PST", "r332_1du_excl_here_insect_saw_kuran", ["ngali", "kuran", "yaluy", "nyajin"]),
    row(4, "We two, not you, saw the kurrmaja larvae here.", "Ngali kurrmaja yaluy nyajin.", "ngali kurrmaja yaluy nyajin | 1du.excl.NOM kurrmaja.larvae here see.PST", "r332_1du_excl_here_insect_saw_kurrmaja", ["ngali", "kurrmaja", "yaluy", "nyajin"]),
    row(5, "We two, not you, saw the murma wasp here.", "Ngali murma yaluy nyajin.", "ngali murma yaluy nyajin | 1du.excl.NOM murma.wasp here see.PST", "r332_1du_excl_here_insect_saw_murma", ["ngali", "murma", "yaluy", "nyajin"]),
    row(6, "We two, not you, saw the durra caterpillar here.", "Ngali durra yaluy nyajin.", "ngali durra yaluy nyajin | 1du.excl.NOM durra.caterpillar here see.PST", "r332_1du_excl_here_insect_saw_durra", ["ngali", "durra", "yaluy", "nyajin"]),
    row(7, "We two, not you, saw the jiljay grub here.", "Ngali jiljay yaluy nyajin.", "ngali jiljay yaluy nyajin | 1du.excl.NOM jiljay.grub here see.PST", "r332_1du_excl_here_insect_saw_jiljay", ["ngali", "jiljay", "yaluy", "nyajin"]),
    row(8, "We two, not you, saw the kandal maggot here.", "Ngali kandal yaluy nyajin.", "ngali kandal yaluy nyajin | 1du.excl.NOM kandal.maggot here see.PST", "r332_1du_excl_here_insect_saw_kandal", ["ngali", "kandal", "yaluy", "nyajin"]),
    row(9, "We two, not you, saw the kinga caterpillar here.", "Ngali kinga yaluy nyajin.", "ngali kinga yaluy nyajin | 1du.excl.NOM kinga.caterpillar here see.PST", "r332_1du_excl_here_insect_saw_kinga", ["ngali", "kinga", "yaluy", "nyajin"]),
    row(10, "We two, not you, saw the birinjil centipede here.", "Ngali birinjil yaluy nyajin.", "ngali birinjil yaluy nyajin | 1du.excl.NOM birinjil.centipede here see.PST", "r332_1du_excl_here_insect_saw_birinjil", ["ngali", "birinjil", "yaluy", "nyajin"]),
    row(11, "You and I saw the jimu grasshopper there.", "Ngaliny jimu yinyay nyajin.", "ngaliny jimu yinyay nyajin | 1du.incl.NOM jimu.grasshopper there see.PST", "r332_1du_incl_there_insect_saw_jimu", ["ngaliny", "jimu", "yinyay", "nyajin"]),
    row(12, "You and I saw the kira-kira black ant there.", "Ngaliny kira-kira yinyay nyajin.", "ngaliny kira-kira yinyay nyajin | 1du.incl.NOM kira.kira.black.ant there see.PST", "r332_1du_incl_there_insect_saw_kira_kira", ["ngaliny", "kira-kira", "yinyay", "nyajin"]),
    row(13, "You and I saw the kuran case-moth larva there.", "Ngaliny kuran yinyay nyajin.", "ngaliny kuran yinyay nyajin | 1du.incl.NOM kuran.case.moth.larva there see.PST", "r332_1du_incl_there_insect_saw_kuran", ["ngaliny", "kuran", "yinyay", "nyajin"]),
    row(14, "You and I saw the kurrmaja larvae there.", "Ngaliny kurrmaja yinyay nyajin.", "ngaliny kurrmaja yinyay nyajin | 1du.incl.NOM kurrmaja.larvae there see.PST", "r332_1du_incl_there_insect_saw_kurrmaja", ["ngaliny", "kurrmaja", "yinyay", "nyajin"]),
    row(15, "You and I saw the murma wasp there.", "Ngaliny murma yinyay nyajin.", "ngaliny murma yinyay nyajin | 1du.incl.NOM murma.wasp there see.PST", "r332_1du_incl_there_insect_saw_murma", ["ngaliny", "murma", "yinyay", "nyajin"]),
    row(16, "You and I saw the durra caterpillar there.", "Ngaliny durra yinyay nyajin.", "ngaliny durra yinyay nyajin | 1du.incl.NOM durra.caterpillar there see.PST", "r332_1du_incl_there_insect_saw_durra", ["ngaliny", "durra", "yinyay", "nyajin"]),
    row(17, "You and I saw the jiljay grub there.", "Ngaliny jiljay yinyay nyajin.", "ngaliny jiljay yinyay nyajin | 1du.incl.NOM jiljay.grub there see.PST", "r332_1du_incl_there_insect_saw_jiljay", ["ngaliny", "jiljay", "yinyay", "nyajin"]),
    row(18, "You and I saw the kandal maggot there.", "Ngaliny kandal yinyay nyajin.", "ngaliny kandal yinyay nyajin | 1du.incl.NOM kandal.maggot there see.PST", "r332_1du_incl_there_insect_saw_kandal", ["ngaliny", "kandal", "yinyay", "nyajin"]),
    row(19, "You and I saw the kinga caterpillar there.", "Ngaliny kinga yinyay nyajin.", "ngaliny kinga yinyay nyajin | 1du.incl.NOM kinga.caterpillar there see.PST", "r332_1du_incl_there_insect_saw_kinga", ["ngaliny", "kinga", "yinyay", "nyajin"]),
    row(20, "You and I saw the birinjil centipede there.", "Ngaliny birinjil yinyay nyajin.", "ngaliny birinjil yinyay nyajin | 1du.incl.NOM birinjil.centipede there see.PST", "r332_1du_incl_there_insect_saw_birinjil", ["ngaliny", "birinjil", "yinyay", "nyajin"]),
    row(21, "You two saw the jimu grasshopper here.", "Yubal jimu yaluy nyajin.", "yubal jimu yaluy nyajin | 2du.NOM jimu.grasshopper here see.PST", "r332_2du_here_insect_saw_jimu", ["yubal", "jimu", "yaluy", "nyajin"]),
    row(22, "You two saw the kira-kira black ant here.", "Yubal kira-kira yaluy nyajin.", "yubal kira-kira yaluy nyajin | 2du.NOM kira.kira.black.ant here see.PST", "r332_2du_here_insect_saw_kira_kira", ["yubal", "kira-kira", "yaluy", "nyajin"]),
    row(23, "You two saw the kuran case-moth larva here.", "Yubal kuran yaluy nyajin.", "yubal kuran yaluy nyajin | 2du.NOM kuran.case.moth.larva here see.PST", "r332_2du_here_insect_saw_kuran", ["yubal", "kuran", "yaluy", "nyajin"]),
    row(24, "You two saw the kurrmaja larvae here.", "Yubal kurrmaja yaluy nyajin.", "yubal kurrmaja yaluy nyajin | 2du.NOM kurrmaja.larvae here see.PST", "r332_2du_here_insect_saw_kurrmaja", ["yubal", "kurrmaja", "yaluy", "nyajin"]),
    row(25, "You two saw the murma wasp here.", "Yubal murma yaluy nyajin.", "yubal murma yaluy nyajin | 2du.NOM murma.wasp here see.PST", "r332_2du_here_insect_saw_murma", ["yubal", "murma", "yaluy", "nyajin"]),
    row(26, "You two saw the durra caterpillar here.", "Yubal durra yaluy nyajin.", "yubal durra yaluy nyajin | 2du.NOM durra.caterpillar here see.PST", "r332_2du_here_insect_saw_durra", ["yubal", "durra", "yaluy", "nyajin"]),
    row(27, "You two saw the jiljay grub here.", "Yubal jiljay yaluy nyajin.", "yubal jiljay yaluy nyajin | 2du.NOM jiljay.grub here see.PST", "r332_2du_here_insect_saw_jiljay", ["yubal", "jiljay", "yaluy", "nyajin"]),
    row(28, "You two saw the kandal maggot here.", "Yubal kandal yaluy nyajin.", "yubal kandal yaluy nyajin | 2du.NOM kandal.maggot here see.PST", "r332_2du_here_insect_saw_kandal", ["yubal", "kandal", "yaluy", "nyajin"]),
    row(29, "You two saw the kinga caterpillar here.", "Yubal kinga yaluy nyajin.", "yubal kinga yaluy nyajin | 2du.NOM kinga.caterpillar here see.PST", "r332_2du_here_insect_saw_kinga", ["yubal", "kinga", "yaluy", "nyajin"]),
    row(30, "You two saw the birinjil centipede here.", "Yubal birinjil yaluy nyajin.", "yubal birinjil yaluy nyajin | 2du.NOM birinjil.centipede here see.PST", "r332_2du_here_insect_saw_birinjil", ["yubal", "birinjil", "yaluy", "nyajin"]),
    row(31, "You all saw the jimu grasshopper there.", "Yurra jimu yinyay nyajin.", "yurra jimu yinyay nyajin | 2pl.NOM jimu.grasshopper there see.PST", "r332_2pl_there_insect_saw_jimu", ["yurra", "jimu", "yinyay", "nyajin"]),
    row(32, "You all saw the kira-kira black ant there.", "Yurra kira-kira yinyay nyajin.", "yurra kira-kira yinyay nyajin | 2pl.NOM kira.kira.black.ant there see.PST", "r332_2pl_there_insect_saw_kira_kira", ["yurra", "kira-kira", "yinyay", "nyajin"]),
    row(33, "You all saw the kuran case-moth larva there.", "Yurra kuran yinyay nyajin.", "yurra kuran yinyay nyajin | 2pl.NOM kuran.case.moth.larva there see.PST", "r332_2pl_there_insect_saw_kuran", ["yurra", "kuran", "yinyay", "nyajin"]),
    row(34, "You all saw the kurrmaja larvae there.", "Yurra kurrmaja yinyay nyajin.", "yurra kurrmaja yinyay nyajin | 2pl.NOM kurrmaja.larvae there see.PST", "r332_2pl_there_insect_saw_kurrmaja", ["yurra", "kurrmaja", "yinyay", "nyajin"]),
    row(35, "You all saw the murma wasp there.", "Yurra murma yinyay nyajin.", "yurra murma yinyay nyajin | 2pl.NOM murma.wasp there see.PST", "r332_2pl_there_insect_saw_murma", ["yurra", "murma", "yinyay", "nyajin"]),
    row(36, "You all saw the durra caterpillar there.", "Yurra durra yinyay nyajin.", "yurra durra yinyay nyajin | 2pl.NOM durra.caterpillar there see.PST", "r332_2pl_there_insect_saw_durra", ["yurra", "durra", "yinyay", "nyajin"]),
    row(37, "You all saw the jiljay grub there.", "Yurra jiljay yinyay nyajin.", "yurra jiljay yinyay nyajin | 2pl.NOM jiljay.grub there see.PST", "r332_2pl_there_insect_saw_jiljay", ["yurra", "jiljay", "yinyay", "nyajin"]),
    row(38, "You all saw the kandal maggot there.", "Yurra kandal yinyay nyajin.", "yurra kandal yinyay nyajin | 2pl.NOM kandal.maggot there see.PST", "r332_2pl_there_insect_saw_kandal", ["yurra", "kandal", "yinyay", "nyajin"]),
    row(39, "You all saw the kinga caterpillar there.", "Yurra kinga yinyay nyajin.", "yurra kinga yinyay nyajin | 2pl.NOM kinga.caterpillar there see.PST", "r332_2pl_there_insect_saw_kinga", ["yurra", "kinga", "yinyay", "nyajin"]),
    row(40, "You all saw the birinjil centipede there.", "Yurra birinjil yinyay nyajin.", "yurra birinjil yinyay nyajin | 2pl.NOM birinjil.centipede there see.PST", "r332_2pl_there_insect_saw_birinjil", ["yurra", "birinjil", "yinyay", "nyajin"]),
    row(41, "We saw the jimu grasshopper here.", "Ngana jimu yaluy nyajin.", "ngana jimu yaluy nyajin | 1pl.incl.NOM jimu.grasshopper here see.PST", "r332_1pl_incl_here_insect_saw_jimu", ["ngana", "jimu", "yaluy", "nyajin"]),
    row(42, "We saw the kira-kira black ant here.", "Ngana kira-kira yaluy nyajin.", "ngana kira-kira yaluy nyajin | 1pl.incl.NOM kira.kira.black.ant here see.PST", "r332_1pl_incl_here_insect_saw_kira_kira", ["ngana", "kira-kira", "yaluy", "nyajin"]),
    row(43, "We saw the kuran case-moth larva here.", "Ngana kuran yaluy nyajin.", "ngana kuran yaluy nyajin | 1pl.incl.NOM kuran.case.moth.larva here see.PST", "r332_1pl_incl_here_insect_saw_kuran", ["ngana", "kuran", "yaluy", "nyajin"]),
    row(44, "We saw the kurrmaja larvae here.", "Ngana kurrmaja yaluy nyajin.", "ngana kurrmaja yaluy nyajin | 1pl.incl.NOM kurrmaja.larvae here see.PST", "r332_1pl_incl_here_insect_saw_kurrmaja", ["ngana", "kurrmaja", "yaluy", "nyajin"]),
    row(45, "We saw the murma wasp here.", "Ngana murma yaluy nyajin.", "ngana murma yaluy nyajin | 1pl.incl.NOM murma.wasp here see.PST", "r332_1pl_incl_here_insect_saw_murma", ["ngana", "murma", "yaluy", "nyajin"]),
    row(46, "We saw the durra caterpillar here.", "Ngana durra yaluy nyajin.", "ngana durra yaluy nyajin | 1pl.incl.NOM durra.caterpillar here see.PST", "r332_1pl_incl_here_insect_saw_durra", ["ngana", "durra", "yaluy", "nyajin"]),
    row(47, "We saw the jiljay grub here.", "Ngana jiljay yaluy nyajin.", "ngana jiljay yaluy nyajin | 1pl.incl.NOM jiljay.grub here see.PST", "r332_1pl_incl_here_insect_saw_jiljay", ["ngana", "jiljay", "yaluy", "nyajin"]),
    row(48, "We saw the kandal maggot here.", "Ngana kandal yaluy nyajin.", "ngana kandal yaluy nyajin | 1pl.incl.NOM kandal.maggot here see.PST", "r332_1pl_incl_here_insect_saw_kandal", ["ngana", "kandal", "yaluy", "nyajin"]),
    row(49, "We saw the kinga caterpillar here.", "Ngana kinga yaluy nyajin.", "ngana kinga yaluy nyajin | 1pl.incl.NOM kinga.caterpillar here see.PST", "r332_1pl_incl_here_insect_saw_kinga", ["ngana", "kinga", "yaluy", "nyajin"]),
    row(50, "We saw the birinjil centipede here.", "Ngana birinjil yaluy nyajin.", "ngana birinjil yaluy nyajin | 1pl.incl.NOM birinjil.centipede here see.PST", "r332_1pl_incl_here_insect_saw_birinjil", ["ngana", "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("r332_"): issues.append(f"{seq}: frame not r332")
        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, list(EXPECTED_SUPPORT_COVERAGE))
    if support_counts != EXPECTED_SUPPORT_COVERAGE: raise SystemExit(f"support coverage changed: {support_counts}")
    existing_nonsingular = db.execute("""SELECT COUNT(*) FROM sentences s WHERE s.status!='rejected' AND EXISTS (SELECT 1 FROM json_each(s.words_used) WHERE value IN ('jimu','kira-kira','kuran','kurrmaja','murma','durra','jiljay','kandal','kinga','birinjil')) AND EXISTS (SELECT 1 FROM json_each(s.words_used) WHERE value IN ('ngali','ngaliny','yubal','yurra','ngana'))""").fetchone()[0]
    if existing_nonsingular: raise SystemExit(f"construction gap changed: {existing_nonsingular} existing target/non-singular rows")
    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 = ("INSECT NON-SINGULAR PAST-PERCEPTION CONSOLIDATION AFTER RULE 331 (Rule 332). 50 under-review rows over the ten freshly revalidated Rule 331 fauna-insect heads: jimu, kira-kira, kuran, kurrmaja, murma, durra, jiljay, kandal, kinga, and birinjil. No target had an accepted non-singular-pronoun row. Both deictic orientations were collision-free; the three-yaluy/two-yinyay layout was selected because it reduces the current deictic-support gap from 232 to 222. Exact referential senses only; no alternate sense, reduplicative/derivational analysis, habitat, behavior, food/use, life cycle, danger, body, source, possession, case, singular/third-person subject, nonpast/purposive/reduplicated perception, or support drift.")
    cur = db.execute("INSERT INTO batches(label,cheatsheet_version,guide_version,notes,created_at) VALUES(?,?,?,?,?)", (LABEL, "Rule 332 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="Freshly reread all ten dictionary insect records and their adjacent polysemy/derivation notes; exact Patz target search again returned no occurrences; reread Patz fauna noun status, non-singular 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="construction-gap-audit", actor="codex", detail="SQLite token audit found zero accepted, revised, or under-review rows combining any selected insect target with ngali, ngaliny, yubal, yurra, or ngana. Rule 332 therefore adds five absent participant-number contrasts per target rather than duplicating Rule 331's singular/third-person bands.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="deictic-balance-audit", actor="codex", detail="Both 50-surface deictic orientations were internally unique and collision-free. Before banking yaluy=4152 and yinyay=4384 (gap 232); selected three-yaluy/two-yinyay orientation projects gap 222, whereas inversion projects 242.", 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 332 exact Kuku surfaces are internally unique and returned no corpus collisions; alternate orientation was also collision-free but not selected.", 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 non-singular nominative A and absolutive O, Yalanji demonstratives, final nyajin, no loans, alternate senses, morphology, habitat/use, source, case, singular/third-person subject, or support drift.", command="python3 -m py_compile batch_scripts/bank_374.py batch_scripts/close_374.py && AST/static/lint probes", output_excerpt="50 explicit rows; scan_static 0; 50 linter probes 0; collisions 0", artifact_path="batch_scripts/bank_374.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="codex", detail=f"Banked 50 Rule 332 rows as under_review. Verified remains {verified_before}; Kuku words remain {words_before}.", command="python3 batch_scripts/bank_374.py", output_excerpt=f"banked batch-374: 50 under_review; verified_before={verified_before}; words_before={words_before}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit(); print("banked batch-374: 50 rows under_review"); return 0


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