#!/usr/bin/env python3
"""Bank batch-377: Rule 335 mammal singular/third-person past-perception completion."""

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-377"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-377-mammal-singular-third-past-perception-after-rule334-process.md"

TARGET_EVIDENCE = {
    "kaya-kaya": "Dictionary yaml lines 13966-13979 give exact hyphenated kaya-kaya as a fauna-mammal noun 'dogs', explicitly analyzed as full reduplication of kaya marking plurality. Rule 335 admits the whole plural dog head as bare O only and leaves free-base substitution, new productive-reduplication generalization, ownership, hunting, feeding, barking, camp, source, and event propositions closed.",
    "murral": "Dictionary yaml lines 20999-21009 give murral as the fauna-mammal noun 'tree kangaroo', explicitly the Yalanji form, with Nyungkul jarrabina supplied in prose. Rule 335 admits exact Yalanji murral tree-kangaroo reference only and leaves dialect substitution, equivalence generation, tree/canopy habitat, climbing, sleeping, visibility, hunting, spearing, catching, food, source, and events closed.",
    "jungarr": "Dictionary yaml lines 10882-10892 give jungarr as the fauna-mammal noun 'marsupial native cat', with commentary identifying a quoll. Rule 335 retains the conservative source label and leaves modern taxonomic equivalence, size, fierceness, hunting, killing rats or birds, branches, nests, night behavior, source, possession, and events closed.",
    "jayju": "Dictionary yaml lines 8602-8610 give jayju as the fauna-mammal noun 'kangaroo rat'. Rule 335 admits bare kangaroo-rat reference only and leaves size, burrow, sand/grass country, hiding, day/night activity, seed/root feeding, source, possession, and events closed.",
    "ngumbi": "Dictionary yaml lines 23562-23572 give ngumbi as a fauna-mammal noun for the little spotted bandicoot. Rule 335 uses the conservative corpus label 'ngumbi bandicoot' and leaves size/spot predication, burrowing, grass habitat, night activity, hunting, catching, cooking, food, source, possession, and events closed.",
    "mali": "Dictionary yaml lines 17566-17577 give mali as a fauna-mammal noun for a species of small bat. Patz lines 5946-5956 separately use homophonous mali as a former-possession particle/suffix/clitic. Rule 335 admits only the dictionary bat noun and leaves homonym merger, former-possession function, size predication, flight, hanging, tree hollow, night, insect catching, source, possession, and events closed.",
    "kukur": "Dictionary yaml lines 15002-15010 give kukur as the fauna-mammal noun 'rat'. Patz lines 1657-1659 and 1728-1730 attest the same rat root in potent case examples kukur-uku and kukur-undu. Rule 335 uses bare kukur only and leaves case, camp/food, night, predation, source, possession, and events closed.",
    "murramu": "Dictionary yaml lines 21010-21020 give murramu as the fauna-mammal noun 'dingo' and explicitly list ngamu-murramu as a synonym. Rule 335 admits exact bare murramu dingo reference only and leaves synonym/equivalence generation, inflected murramungku, decomposition, wild-dog relation, hunting, tracking, call/howl, family, food, ownership, source, and events closed.",
    "darrba": "Dictionary yaml lines 5306-5315 give darrba as the fauna-mammal noun 'wallaby', specifically grass wallaby. Nearby darra is an adjective 'narrow, too small' and remains distinct. Rule 335 admits the exact grass-wallaby noun only and leaves homophone confusion, size, grass habitat, feeding, tracks, hunting, spearing, food, ceremony, source, possession, and events closed.",
    "yawa": "Dictionary yaml lines 29634-29642 give yawa as the fauna-mammal noun 'possum'; nearby yawarr at 29643-29650 is a palm noun. Rule 335 admits exact possum reference only and leaves palm identity, tree/hollow habitat, climbing, sleeping, night activity, eye-shine, hunting, catching, biting, food, fur/cloak, source, possession, and events closed.",
}

SUPPORT_EVIDENCE = (
    "Patz line 1476 includes fauna among noun referents. Lines 2577-2586 source bare nominative ngayu, yundu, "
    "nyulu, bula, and third-plural jana through the running paradigm evidence already established; 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 contain "
    "running nyajin. Fresh Patz target search found only inflected kukur rat examples at lines 1659 and 1730 "
    "and five mali former-possession homonym mentions at lines 5946-5956; no grammar occurrence licenses a new "
    "mammal event. Rule 335 fills an exact four-token bare-target singular/third-person past grid while preserving "
    "all lexical, dialect, homonym, case, cultural, ecological, and event boundaries."
)

TARGET_ORDER = ["kaya-kaya", "murral", "jungarr", "jayju", "ngumbi", "mali", "kukur", "murramu", "darrba", "yawa"]
TARGET_LABELS = {
    "kaya-kaya": "kaya-kaya dogs",
    "murral": "murral tree kangaroo",
    "jungarr": "jungarr marsupial native cat",
    "jayju": "jayju kangaroo rat",
    "ngumbi": "ngumbi bandicoot",
    "mali": "mali small bat",
    "kukur": "kukur rat",
    "murramu": "murramu dingo",
    "darrba": "darrba grass wallaby",
    "yawa": "yawa possum",
}
TARGET_GLOSSES = {
    "kaya-kaya": "kaya.kaya.dogs",
    "murral": "murral.tree.kangaroo",
    "jungarr": "marsupial.native.cat",
    "jayju": "kangaroo.rat",
    "ngumbi": "bandicoot",
    "mali": "small.bat",
    "kukur": "rat",
    "murramu": "dingo",
    "darrba": "grass.wallaby",
    "yawa": "possum",
}
TARGET_CONFIDENCE = {
    "kaya-kaya": "0.93", "murral": "0.94", "jungarr": "0.93", "jayju": "0.94", "ngumbi": "0.93",
    "mali": "0.90", "kukur": "0.94", "murramu": "0.93", "darrba": "0.94", "yawa": "0.94",
}
EXPECTED_TARGET_COVERAGE = {"kaya-kaya": 5, "murral": 9, "jungarr": 27, "jayju": 28, "ngumbi": 28, "mali": 30, "kukur": 31, "murramu": 54, "darrba": 56, "yawa": 59}
EXPECTED_SUPPORT_COVERAGE = {"ngayu": 1441, "yundu": 1037, "nyulu": 712, "bula": 508, "jana": 1213, "yaluy": 4242, "yinyay": 4444, "nyajin": 1800}
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", "iana", "yulu",
    "kaya", "jarrabina", "ngamu-murramu", "murramungku", "kukuruku", "kukur-uku", "kukurundu",
    "kukur-undu", "darra", "yawarr", "yalay", "yala", "yanyu", "yinya", "yalungku", "yaluyngku",
    "yinyangka", "yinyayngka", "yalamuny", "yinyamuny", "nyajil", "nyaji-l", "nyaji-nka",
    "nyaji-l-nyaji", "milka", "baykal", "jalngkay",
}
DENY_ENGLISH = (
    "nyungkul", "synonym", "equivalent", "former possession", "particle", "suffix", "clitic", "plural process",
    "free base", "productive reduplication", "wild dog", "quoll identity", "palm", "narrow", "too small",
    "tree canopy", "climb", "sleep", "burrow", "hide", "seed", "root feeding", "spotted property", "fly",
    "hang", "tree hollow", "night", "insect", "camp food", "predation", "hunt", "track", "call", "howl",
    "family", "spear", "catch", "cook", "fur", "cloak", "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 kaya-kaya dogs here.", "Ngayu kaya-kaya yaluy nyajin.", "ngayu kaya-kaya yaluy nyajin | 1sg.NOM kaya.kaya.dogs here see.PST", "r335_1sg_here_mammal_saw_kaya_kaya", ["ngayu", "kaya-kaya", "yaluy", "nyajin"]),
    row(2, "I saw the murral tree kangaroo here.", "Ngayu murral yaluy nyajin.", "ngayu murral yaluy nyajin | 1sg.NOM murral.tree.kangaroo here see.PST", "r335_1sg_here_mammal_saw_murral", ["ngayu", "murral", "yaluy", "nyajin"]),
    row(3, "I saw the jungarr marsupial native cat here.", "Ngayu jungarr yaluy nyajin.", "ngayu jungarr yaluy nyajin | 1sg.NOM marsupial.native.cat here see.PST", "r335_1sg_here_mammal_saw_jungarr", ["ngayu", "jungarr", "yaluy", "nyajin"]),
    row(4, "I saw the jayju kangaroo rat here.", "Ngayu jayju yaluy nyajin.", "ngayu jayju yaluy nyajin | 1sg.NOM kangaroo.rat here see.PST", "r335_1sg_here_mammal_saw_jayju", ["ngayu", "jayju", "yaluy", "nyajin"]),
    row(5, "I saw the ngumbi bandicoot here.", "Ngayu ngumbi yaluy nyajin.", "ngayu ngumbi yaluy nyajin | 1sg.NOM bandicoot here see.PST", "r335_1sg_here_mammal_saw_ngumbi", ["ngayu", "ngumbi", "yaluy", "nyajin"]),
    row(6, "I saw the mali small bat here.", "Ngayu mali yaluy nyajin.", "ngayu mali yaluy nyajin | 1sg.NOM small.bat here see.PST", "r335_1sg_here_mammal_saw_mali", ["ngayu", "mali", "yaluy", "nyajin"]),
    row(7, "I saw the kukur rat here.", "Ngayu kukur yaluy nyajin.", "ngayu kukur yaluy nyajin | 1sg.NOM rat here see.PST", "r335_1sg_here_mammal_saw_kukur", ["ngayu", "kukur", "yaluy", "nyajin"]),
    row(8, "I saw the murramu dingo here.", "Ngayu murramu yaluy nyajin.", "ngayu murramu yaluy nyajin | 1sg.NOM dingo here see.PST", "r335_1sg_here_mammal_saw_murramu", ["ngayu", "murramu", "yaluy", "nyajin"]),
    row(9, "I saw the darrba grass wallaby here.", "Ngayu darrba yaluy nyajin.", "ngayu darrba yaluy nyajin | 1sg.NOM grass.wallaby here see.PST", "r335_1sg_here_mammal_saw_darrba", ["ngayu", "darrba", "yaluy", "nyajin"]),
    row(10, "I saw the yawa possum here.", "Ngayu yawa yaluy nyajin.", "ngayu yawa yaluy nyajin | 1sg.NOM possum here see.PST", "r335_1sg_here_mammal_saw_yawa", ["ngayu", "yawa", "yaluy", "nyajin"]),
    row(11, "You saw the kaya-kaya dogs there.", "Yundu kaya-kaya yinyay nyajin.", "yundu kaya-kaya yinyay nyajin | 2sg.NOM kaya.kaya.dogs there see.PST", "r335_2sg_there_mammal_saw_kaya_kaya", ["yundu", "kaya-kaya", "yinyay", "nyajin"]),
    row(12, "You saw the murral tree kangaroo there.", "Yundu murral yinyay nyajin.", "yundu murral yinyay nyajin | 2sg.NOM murral.tree.kangaroo there see.PST", "r335_2sg_there_mammal_saw_murral", ["yundu", "murral", "yinyay", "nyajin"]),
    row(13, "You saw the jungarr marsupial native cat there.", "Yundu jungarr yinyay nyajin.", "yundu jungarr yinyay nyajin | 2sg.NOM marsupial.native.cat there see.PST", "r335_2sg_there_mammal_saw_jungarr", ["yundu", "jungarr", "yinyay", "nyajin"]),
    row(14, "You saw the jayju kangaroo rat there.", "Yundu jayju yinyay nyajin.", "yundu jayju yinyay nyajin | 2sg.NOM kangaroo.rat there see.PST", "r335_2sg_there_mammal_saw_jayju", ["yundu", "jayju", "yinyay", "nyajin"]),
    row(15, "You saw the ngumbi bandicoot there.", "Yundu ngumbi yinyay nyajin.", "yundu ngumbi yinyay nyajin | 2sg.NOM bandicoot there see.PST", "r335_2sg_there_mammal_saw_ngumbi", ["yundu", "ngumbi", "yinyay", "nyajin"]),
    row(16, "You saw the mali small bat there.", "Yundu mali yinyay nyajin.", "yundu mali yinyay nyajin | 2sg.NOM small.bat there see.PST", "r335_2sg_there_mammal_saw_mali", ["yundu", "mali", "yinyay", "nyajin"]),
    row(17, "You saw the kukur rat there.", "Yundu kukur yinyay nyajin.", "yundu kukur yinyay nyajin | 2sg.NOM rat there see.PST", "r335_2sg_there_mammal_saw_kukur", ["yundu", "kukur", "yinyay", "nyajin"]),
    row(18, "You saw the murramu dingo there.", "Yundu murramu yinyay nyajin.", "yundu murramu yinyay nyajin | 2sg.NOM dingo there see.PST", "r335_2sg_there_mammal_saw_murramu", ["yundu", "murramu", "yinyay", "nyajin"]),
    row(19, "You saw the darrba grass wallaby there.", "Yundu darrba yinyay nyajin.", "yundu darrba yinyay nyajin | 2sg.NOM grass.wallaby there see.PST", "r335_2sg_there_mammal_saw_darrba", ["yundu", "darrba", "yinyay", "nyajin"]),
    row(20, "You saw the yawa possum there.", "Yundu yawa yinyay nyajin.", "yundu yawa yinyay nyajin | 2sg.NOM possum there see.PST", "r335_2sg_there_mammal_saw_yawa", ["yundu", "yawa", "yinyay", "nyajin"]),
    row(21, "He saw the kaya-kaya dogs here.", "Nyulu kaya-kaya yaluy nyajin.", "nyulu kaya-kaya yaluy nyajin | 3sg.NOM kaya.kaya.dogs here see.PST", "r335_3sg_here_mammal_saw_kaya_kaya", ["nyulu", "kaya-kaya", "yaluy", "nyajin"]),
    row(22, "He saw the murral tree kangaroo here.", "Nyulu murral yaluy nyajin.", "nyulu murral yaluy nyajin | 3sg.NOM murral.tree.kangaroo here see.PST", "r335_3sg_here_mammal_saw_murral", ["nyulu", "murral", "yaluy", "nyajin"]),
    row(23, "He saw the jungarr marsupial native cat here.", "Nyulu jungarr yaluy nyajin.", "nyulu jungarr yaluy nyajin | 3sg.NOM marsupial.native.cat here see.PST", "r335_3sg_here_mammal_saw_jungarr", ["nyulu", "jungarr", "yaluy", "nyajin"]),
    row(24, "He saw the jayju kangaroo rat here.", "Nyulu jayju yaluy nyajin.", "nyulu jayju yaluy nyajin | 3sg.NOM kangaroo.rat here see.PST", "r335_3sg_here_mammal_saw_jayju", ["nyulu", "jayju", "yaluy", "nyajin"]),
    row(25, "He saw the ngumbi bandicoot here.", "Nyulu ngumbi yaluy nyajin.", "nyulu ngumbi yaluy nyajin | 3sg.NOM bandicoot here see.PST", "r335_3sg_here_mammal_saw_ngumbi", ["nyulu", "ngumbi", "yaluy", "nyajin"]),
    row(26, "He saw the mali small bat here.", "Nyulu mali yaluy nyajin.", "nyulu mali yaluy nyajin | 3sg.NOM small.bat here see.PST", "r335_3sg_here_mammal_saw_mali", ["nyulu", "mali", "yaluy", "nyajin"]),
    row(27, "He saw the kukur rat here.", "Nyulu kukur yaluy nyajin.", "nyulu kukur yaluy nyajin | 3sg.NOM rat here see.PST", "r335_3sg_here_mammal_saw_kukur", ["nyulu", "kukur", "yaluy", "nyajin"]),
    row(28, "He saw the murramu dingo here.", "Nyulu murramu yaluy nyajin.", "nyulu murramu yaluy nyajin | 3sg.NOM dingo here see.PST", "r335_3sg_here_mammal_saw_murramu", ["nyulu", "murramu", "yaluy", "nyajin"]),
    row(29, "He saw the darrba grass wallaby here.", "Nyulu darrba yaluy nyajin.", "nyulu darrba yaluy nyajin | 3sg.NOM grass.wallaby here see.PST", "r335_3sg_here_mammal_saw_darrba", ["nyulu", "darrba", "yaluy", "nyajin"]),
    row(30, "He saw the yawa possum here.", "Nyulu yawa yaluy nyajin.", "nyulu yawa yaluy nyajin | 3sg.NOM possum here see.PST", "r335_3sg_here_mammal_saw_yawa", ["nyulu", "yawa", "yaluy", "nyajin"]),
    row(31, "The two of them saw the kaya-kaya dogs there.", "Bula kaya-kaya yinyay nyajin.", "bula kaya-kaya yinyay nyajin | 3du.NOM kaya.kaya.dogs there see.PST", "r335_3du_there_mammal_saw_kaya_kaya", ["bula", "kaya-kaya", "yinyay", "nyajin"]),
    row(32, "The two of them saw the murral tree kangaroo there.", "Bula murral yinyay nyajin.", "bula murral yinyay nyajin | 3du.NOM murral.tree.kangaroo there see.PST", "r335_3du_there_mammal_saw_murral", ["bula", "murral", "yinyay", "nyajin"]),
    row(33, "The two of them saw the jungarr marsupial native cat there.", "Bula jungarr yinyay nyajin.", "bula jungarr yinyay nyajin | 3du.NOM marsupial.native.cat there see.PST", "r335_3du_there_mammal_saw_jungarr", ["bula", "jungarr", "yinyay", "nyajin"]),
    row(34, "The two of them saw the jayju kangaroo rat there.", "Bula jayju yinyay nyajin.", "bula jayju yinyay nyajin | 3du.NOM kangaroo.rat there see.PST", "r335_3du_there_mammal_saw_jayju", ["bula", "jayju", "yinyay", "nyajin"]),
    row(35, "The two of them saw the ngumbi bandicoot there.", "Bula ngumbi yinyay nyajin.", "bula ngumbi yinyay nyajin | 3du.NOM bandicoot there see.PST", "r335_3du_there_mammal_saw_ngumbi", ["bula", "ngumbi", "yinyay", "nyajin"]),
    row(36, "The two of them saw the mali small bat there.", "Bula mali yinyay nyajin.", "bula mali yinyay nyajin | 3du.NOM small.bat there see.PST", "r335_3du_there_mammal_saw_mali", ["bula", "mali", "yinyay", "nyajin"]),
    row(37, "The two of them saw the kukur rat there.", "Bula kukur yinyay nyajin.", "bula kukur yinyay nyajin | 3du.NOM rat there see.PST", "r335_3du_there_mammal_saw_kukur", ["bula", "kukur", "yinyay", "nyajin"]),
    row(38, "The two of them saw the murramu dingo there.", "Bula murramu yinyay nyajin.", "bula murramu yinyay nyajin | 3du.NOM dingo there see.PST", "r335_3du_there_mammal_saw_murramu", ["bula", "murramu", "yinyay", "nyajin"]),
    row(39, "The two of them saw the darrba grass wallaby there.", "Bula darrba yinyay nyajin.", "bula darrba yinyay nyajin | 3du.NOM grass.wallaby there see.PST", "r335_3du_there_mammal_saw_darrba", ["bula", "darrba", "yinyay", "nyajin"]),
    row(40, "The two of them saw the yawa possum there.", "Bula yawa yinyay nyajin.", "bula yawa yinyay nyajin | 3du.NOM possum there see.PST", "r335_3du_there_mammal_saw_yawa", ["bula", "yawa", "yinyay", "nyajin"]),
    row(41, "They saw the kaya-kaya dogs here.", "Jana kaya-kaya yaluy nyajin.", "jana kaya-kaya yaluy nyajin | 3pl.NOM kaya.kaya.dogs here see.PST", "r335_3pl_here_mammal_saw_kaya_kaya", ["jana", "kaya-kaya", "yaluy", "nyajin"]),
    row(42, "They saw the murral tree kangaroo here.", "Jana murral yaluy nyajin.", "jana murral yaluy nyajin | 3pl.NOM murral.tree.kangaroo here see.PST", "r335_3pl_here_mammal_saw_murral", ["jana", "murral", "yaluy", "nyajin"]),
    row(43, "They saw the jungarr marsupial native cat here.", "Jana jungarr yaluy nyajin.", "jana jungarr yaluy nyajin | 3pl.NOM marsupial.native.cat here see.PST", "r335_3pl_here_mammal_saw_jungarr", ["jana", "jungarr", "yaluy", "nyajin"]),
    row(44, "They saw the jayju kangaroo rat here.", "Jana jayju yaluy nyajin.", "jana jayju yaluy nyajin | 3pl.NOM kangaroo.rat here see.PST", "r335_3pl_here_mammal_saw_jayju", ["jana", "jayju", "yaluy", "nyajin"]),
    row(45, "They saw the ngumbi bandicoot here.", "Jana ngumbi yaluy nyajin.", "jana ngumbi yaluy nyajin | 3pl.NOM bandicoot here see.PST", "r335_3pl_here_mammal_saw_ngumbi", ["jana", "ngumbi", "yaluy", "nyajin"]),
    row(46, "They saw the mali small bat here.", "Jana mali yaluy nyajin.", "jana mali yaluy nyajin | 3pl.NOM small.bat here see.PST", "r335_3pl_here_mammal_saw_mali", ["jana", "mali", "yaluy", "nyajin"]),
    row(47, "They saw the kukur rat here.", "Jana kukur yaluy nyajin.", "jana kukur yaluy nyajin | 3pl.NOM rat here see.PST", "r335_3pl_here_mammal_saw_kukur", ["jana", "kukur", "yaluy", "nyajin"]),
    row(48, "They saw the murramu dingo here.", "Jana murramu yaluy nyajin.", "jana murramu yaluy nyajin | 3pl.NOM dingo here see.PST", "r335_3pl_here_mammal_saw_murramu", ["jana", "murramu", "yaluy", "nyajin"]),
    row(49, "They saw the darrba grass wallaby here.", "Jana darrba yaluy nyajin.", "jana darrba yaluy nyajin | 3pl.NOM grass.wallaby here see.PST", "r335_3pl_here_mammal_saw_darrba", ["jana", "darrba", "yaluy", "nyajin"]),
    row(50, "They saw the yawa possum here.", "Jana yawa yaluy nyajin.", "jana yawa yaluy nyajin | 3pl.NOM possum here see.PST", "r335_3pl_here_mammal_saw_yawa", ["jana", "yawa", "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("r335_"): issues.append(f"{seq}: frame not r335")
        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}")
    grid_hits = []
    for pronoun in ["ngayu", "yundu", "nyulu", "bula", "jana"]:
        for demo in ["yaluy", "yinyay"]:
            for target in TARGET_ORDER:
                surface = f"{pronoun.capitalize()} {target} {demo} nyajin."
                hits = db.execute("SELECT b.label,s.seq FROM sentences s JOIN batches b ON b.id=s.batch_id WHERE lower(s.kuku)=lower(?) AND s.status!='rejected'", (surface,)).fetchall()
                if hits: grid_hits.append((surface, hits))
    if grid_hits: raise SystemExit(f"four-token construction grid changed: {grid_hits}")
    selected_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: selected_collisions.append((kuku, hits))
    if selected_collisions: raise SystemExit(f"duplicate preflight failed: {selected_collisions}")
    alternate = []
    for pronoun, demo in [("ngayu", "yinyay"), ("yundu", "yaluy"), ("nyulu", "yinyay"), ("bula", "yaluy"), ("jana", "yinyay")]:
        for target in TARGET_ORDER:
            surface = f"{pronoun.capitalize()} {target} {demo} nyajin."
            hits = db.execute("SELECT b.label,s.seq FROM sentences s JOIN batches b ON b.id=s.batch_id WHERE lower(s.kuku)=lower(?) AND s.status!='rejected'", (surface,)).fetchall()
            if hits: alternate.append((surface, hits))
    if alternate: raise SystemExit(f"alternate orientation unexpectedly collided: {alternate}")
    verified_before, words_before = db.execute("SELECT COUNT(*),SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1) FROM sentences WHERE status IN ('accepted','revised')").fetchone()
    if (verified_before, words_before) != (18897, 130947): raise SystemExit(f"baseline changed: verified={verified_before} words={words_before}")
    notes = ("MAMMAL SINGULAR/THIRD-PERSON PAST-PERCEPTION COMPLETION AFTER RULE 334 (Rule 335). 50 under-review rows over ten exact non-loan fauna-mammal heads: kaya-kaya, murral, jungarr, jayju, ngumbi, mali, kukur, murramu, darrba, and yawa. The exact bare-target four-token past grid was empty for both deictic orientations. The three-yaluy/two-yinyay layout was selected because it reduces the support gap from 202 to 192. Exact noun senses only; no free-base/productive reduplication, Nyungkul substitution, synonym generation, mali former-possession homonym, kukur case, inflected murramungku, nearby darra/yawarr identity, body/property, habitat, behavior, hunting, food/use, source, possession, cultural-event, target 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 335 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 exact mammal dictionary records plus nearby or linked kaya, jarrabina, ngamu-murramu, darra, and yawarr records; reread Patz fauna, selected pronouns, Yalanji demonstratives, past, perception A/O, running nyajin, kukur case examples, and mali former-possession section.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="lexical-boundary-audit", actor="codex", detail="Confirmed ten exact unique noun-typed fauna-mammal non-loan records. Kept kaya-kaya plural head, Yalanji murral, bat-noun mali, bare kukur, murramu, darrba, and yawa distinct from free base, dialect alternate, homonym, case forms, synonym, inflected form, nearby adjective, and nearby palm.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="construction-gap-audit", actor="codex", detail="Exact SQLite matrix over five selected pronouns x ten targets x yaluy/yinyay found zero bare-target four-token surfaces ending nyajin. One older murramungku sentence contains an inflected dingo A plus a separate ngayu clause and was explicitly excluded from the narrower gap claim, not erased.", 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 singular/third-person past orientations were internally unique and collision-free. Before banking yaluy=4242 and yinyay=4444 (gap 202); selected three-yaluy/two-yinyay orientation projects gap 192, whereas inversion projects 212.", 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 selected Rule 335 exact Kuku surfaces are internally unique and returned no corpus collisions; the inverse orientation was also collision-free but less balanced.", 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 mammal head each, bare singular/third nominative A and absolutive O, Yalanji demonstratives, final nyajin, no loans, dialect/homonym/synonym/case/secondary-sense/event or support drift.", command="python3 -m py_compile batch_scripts/bank_377.py batch_scripts/close_377.py && AST/static/lint probes", output_excerpt="50 explicit rows; scan_static 0; 50 linter probes 0; selected/inverse collisions 0", artifact_path="batch_scripts/bank_377.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="codex", detail=f"Banked 50 Rule 335 rows as under_review. Verified remains {verified_before}; Kuku words remain {words_before}.", command="python3 batch_scripts/bank_377.py", output_excerpt=f"banked batch-377: 50 under_review; verified_before={verified_before}; words_before={words_before}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit(); print("banked batch-377: 50 rows under_review"); return 0


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