#!/usr/bin/env python3
"""Bank batch-371: Rule 329 low-coverage shellfish singular/third nonpast 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-371"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-371-low-coverage-shellfish-singular-third-nonpast-perception-after-rule328-process.md"

TARGET_EVIDENCE = {
    "wurru-bulan": "Dictionary yaml lines 28490-28498 give exact hyphenated wurru-bulan as a noun for a small crab found on a reef. Rule 329 admits small-crab reference only and leaves component decomposition, productive compounding, size comparison, reef/sea habitat, movement, gathering, catching, food, cooking, eating, possession, source, and event propositions closed.",
    "dakaldakal": "Dictionary yaml lines 4590-4603 give solid dakaldakal as a full-reduplicated noun for trochus shell, based on dakal. Patz line 944 independently attests dakaldakal 'trochus shell' among reduplicated forms. Rule 329 admits the exact whole head only and leaves free-base use, productive reduplication, shell source, animal identity, gathering, carrying, tool/ornament use, and events closed.",
    "kajarrbi": "Dictionary yaml lines 12013-12022 give kajarrbi as a noun for clam shell or giant clam. Rule 329 admits the conservative clam-shell reading only and leaves giant-size predication, animal/shell identity claims, sea habitat, opening, gathering, carrying, food, tool/ornament use, source, and event propositions closed.",
    "kunkun": "Dictionary yaml lines 15937-15951 give solid kunkun as a full-reduplicated noun for periwinkle, a flat shellfish with a smooth shell, based on kun. Rule 329 admits periwinkle reference only and leaves base use, productive reduplication, flatness/smoothness, shell parts, habitat, gathering, food, source, and event propositions closed.",
    "kurrija": "Dictionary yaml lines 16364-16372 give kurrija as the noun 'octopus'. Rule 329 admits octopus reference only and leaves body parts, number, movement, water/reef habitat, catching, spearing, cooking, eating, danger, possession, source, and event propositions closed.",
    "ngajay": "Dictionary yaml lines 21731-21741 give ngajay as a species of small crayfish and explicitly note that it is not eaten. Rule 329 admits small-crayfish reference only and leaves edibility/avoidance, eating, size comparison, water habitat, catching, gathering, cooking, possession, source, and event propositions closed.",
    "nikar": "Dictionary yaml lines 24079-24087 give nikar as a shallow-water oyster found on rock. Rule 329 admits oyster reference only and leaves shallow-water/rock habitat, attachment, shell parts, gathering, opening, cooking, eating, possession, source, and event propositions closed.",
    "wuli-wuli": "Dictionary yaml lines 27786-27799 give exact hyphenated wuli-wuli as a full-reduplicated noun for soldier crab, based on wuli. Rule 329 admits the whole lexical head only and leaves base use, productive reduplication, group/number claims, sand/beach habitat, movement, gathering, food, possession, source, and events closed.",
    "jalan": "Dictionary yaml lines 7340-7350 give jalan as an edible spiny sea urchin living on coastal rocks and note that its meat is fried. Rule 329 admits sea-urchin reference only and leaves shell/spines, porcupine comparison, injury, rock/sea habitat, edibility, meat, frying, gathering, carrying, source, and event propositions closed.",
    "wurrul": "Dictionary yaml lines 28499-28510 give wurrul as a noun for a species of shellfish. Rule 329 admits shellfish reference only and leaves species identity, shell parts, habitat, gathering, opening, cooking, eating, possession, source, equivalence to another head, and event propositions closed.",
}

SUPPORT_EVIDENCE = (
    "Patz line 1476 includes fauna among noun referents. Lines 2577-2586 source bare nominative ngayu, yundu, "
    "nyulu, bula, and jana/iana; lines 2834-2847 source Yalanji yaluy 'here' and yinyay 'there'. Lines "
    "3043-3049 give nonpast nyaji-l, lines 3149-3151 define its present/future function, and lines 4256-4265 "
    "license nominative pronoun A with bare absolutive O in perception. Dictionary lines 24282-24296 independently "
    "attest running-form nyajil and its visual sense. Exact Patz target search finds dakaldakal at line 944 in "
    "the trochus-shell sense and none of the other nine selected heads. Rule 329 takes every selected marine-fauna "
    "reading from the dictionary and uses only bare support and nonpast visual perception."
)

TARGET_ORDER = ["wurru-bulan", "dakaldakal", "kajarrbi", "kunkun", "kurrija", "ngajay", "nikar", "wuli-wuli", "jalan", "wurrul"]
TARGET_LABELS = {
    "wurru-bulan": "wurru-bulan small crab",
    "dakaldakal": "dakaldakal trochus shell",
    "kajarrbi": "kajarrbi clam shell",
    "kunkun": "kunkun periwinkle",
    "kurrija": "kurrija octopus",
    "ngajay": "ngajay small crayfish",
    "nikar": "nikar oyster",
    "wuli-wuli": "wuli-wuli soldier crab",
    "jalan": "jalan sea urchin",
    "wurrul": "wurrul shellfish",
}
TARGET_GLOSSES = {
    "wurru-bulan": "wurru.bulan.small.crab",
    "dakaldakal": "dakaldakal.trochus.shell",
    "kajarrbi": "kajarrbi.clam.shell",
    "kunkun": "kunkun.periwinkle",
    "kurrija": "kurrija.octopus",
    "ngajay": "ngajay.small.crayfish",
    "nikar": "nikar.oyster",
    "wuli-wuli": "wuli.wuli.soldier.crab",
    "jalan": "jalan.sea.urchin",
    "wurrul": "wurrul.shellfish",
}
TARGET_CONFIDENCE = {"wurru-bulan": "0.90", "dakaldakal": "0.96", "kajarrbi": "0.90", "kunkun": "0.92", "kurrija": "0.95", "ngajay": "0.91", "nikar": "0.93", "wuli-wuli": "0.92", "jalan": "0.94", "wurrul": "0.88"}
EXPECTED_TARGET_COVERAGE = {"wurru-bulan": 10, "dakaldakal": 7, "kajarrbi": 8, "kunkun": 8, "kurrija": 8, "ngajay": 8, "nikar": 8, "wuli-wuli": 8, "jalan": 9, "wurrul": 9}
FRAME_SPECS = [
    ("ngayu", "yaluy", "I see", "here", "1sg"),
    ("yundu", "yinyay", "You see", "there", "2sg"),
    ("nyulu", "yaluy", "He sees", "here", "3sg"),
    ("bula", "yinyay", "The two of them see", "there", "3du"),
    ("jana", "yaluy", "They see", "here", "3pl"),
]

DENY_KUKU = {
    "ngali", "ngaliny", "yubal", "yurra", "nganjin", "ngana", "yulu", "iana",
    "nganya", "yununy", "nyunguny", "yununiny", "nyunguniny",
    "ngaykunku", "yununku", "nyungunku", "ngaykundu", "yunundu", "nyungundu",
    "ngaykundumuny", "yunundumuny", "nyungundumuny", "ngaykunji", "yununji", "nyungunji",
    "ngayku", "yunu", "nyunju", "dakal", "kun", "wuli", "Kunkunbuku", "ngaji", "nili-nili",
    "wurun", "jirrum", "juwarru", "yalay", "yala", "yanyu", "yinya", "yalungku", "yaluyngku", "yinyangka",
    "yinyayngka", "yalamuny", "yinyamuny", "nyajin", "nyaji-ny", "nyaji-nka", "nyaji-l-nyaji",
    "milka", "baykal", "jalngkay",
}
DENY_ENGLISH = (
    "shell part", "size comparison", "water habitat", "rock habitat", "gather", "open", "cook", "eat",
    "possess", "source", "base use", "productive reduplication", "animal identity", "carry", "tool",
    "ornament", "giant", "sea habitat", "flatness", "smoothness", "body part", "number", "move",
    "reef", "catch", "spear", "danger", "edible", "avoid", "not eaten", "shallow water", "attach",
    "group", "sand", "beach", "spine", "porcupine", "injury", "meat", "fry", "fried", "species identity",
    "equivalent", "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, "I see the wurru-bulan small crab here.", "Ngayu wurru-bulan yaluy nyajil.", "ngayu wurru-bulan yaluy nyajil | 1sg.NOM wurru.bulan.small.crab here see.NPST", "r329_1sg_here_low_shellfish_see_wurru_bulan", ["ngayu", "wurru-bulan", "yaluy", "nyajil"]),
    row(2, "I see the dakaldakal trochus shell here.", "Ngayu dakaldakal yaluy nyajil.", "ngayu dakaldakal yaluy nyajil | 1sg.NOM dakaldakal.trochus.shell here see.NPST", "r329_1sg_here_low_shellfish_see_dakaldakal", ["ngayu", "dakaldakal", "yaluy", "nyajil"]),
    row(3, "I see the kajarrbi clam shell here.", "Ngayu kajarrbi yaluy nyajil.", "ngayu kajarrbi yaluy nyajil | 1sg.NOM kajarrbi.clam.shell here see.NPST", "r329_1sg_here_low_shellfish_see_kajarrbi", ["ngayu", "kajarrbi", "yaluy", "nyajil"]),
    row(4, "I see the kunkun periwinkle here.", "Ngayu kunkun yaluy nyajil.", "ngayu kunkun yaluy nyajil | 1sg.NOM kunkun.periwinkle here see.NPST", "r329_1sg_here_low_shellfish_see_kunkun", ["ngayu", "kunkun", "yaluy", "nyajil"]),
    row(5, "I see the kurrija octopus here.", "Ngayu kurrija yaluy nyajil.", "ngayu kurrija yaluy nyajil | 1sg.NOM kurrija.octopus here see.NPST", "r329_1sg_here_low_shellfish_see_kurrija", ["ngayu", "kurrija", "yaluy", "nyajil"]),
    row(6, "I see the ngajay small crayfish here.", "Ngayu ngajay yaluy nyajil.", "ngayu ngajay yaluy nyajil | 1sg.NOM ngajay.small.crayfish here see.NPST", "r329_1sg_here_low_shellfish_see_ngajay", ["ngayu", "ngajay", "yaluy", "nyajil"]),
    row(7, "I see the nikar oyster here.", "Ngayu nikar yaluy nyajil.", "ngayu nikar yaluy nyajil | 1sg.NOM nikar.oyster here see.NPST", "r329_1sg_here_low_shellfish_see_nikar", ["ngayu", "nikar", "yaluy", "nyajil"]),
    row(8, "I see the wuli-wuli soldier crab here.", "Ngayu wuli-wuli yaluy nyajil.", "ngayu wuli-wuli yaluy nyajil | 1sg.NOM wuli.wuli.soldier.crab here see.NPST", "r329_1sg_here_low_shellfish_see_wuli_wuli", ["ngayu", "wuli-wuli", "yaluy", "nyajil"]),
    row(9, "I see the jalan sea urchin here.", "Ngayu jalan yaluy nyajil.", "ngayu jalan yaluy nyajil | 1sg.NOM jalan.sea.urchin here see.NPST", "r329_1sg_here_low_shellfish_see_jalan", ["ngayu", "jalan", "yaluy", "nyajil"]),
    row(10, "I see the wurrul shellfish here.", "Ngayu wurrul yaluy nyajil.", "ngayu wurrul yaluy nyajil | 1sg.NOM wurrul.shellfish here see.NPST", "r329_1sg_here_low_shellfish_see_wurrul", ["ngayu", "wurrul", "yaluy", "nyajil"]),
    row(11, "You see the wurru-bulan small crab there.", "Yundu wurru-bulan yinyay nyajil.", "yundu wurru-bulan yinyay nyajil | 2sg.NOM wurru.bulan.small.crab there see.NPST", "r329_2sg_there_low_shellfish_see_wurru_bulan", ["yundu", "wurru-bulan", "yinyay", "nyajil"]),
    row(12, "You see the dakaldakal trochus shell there.", "Yundu dakaldakal yinyay nyajil.", "yundu dakaldakal yinyay nyajil | 2sg.NOM dakaldakal.trochus.shell there see.NPST", "r329_2sg_there_low_shellfish_see_dakaldakal", ["yundu", "dakaldakal", "yinyay", "nyajil"]),
    row(13, "You see the kajarrbi clam shell there.", "Yundu kajarrbi yinyay nyajil.", "yundu kajarrbi yinyay nyajil | 2sg.NOM kajarrbi.clam.shell there see.NPST", "r329_2sg_there_low_shellfish_see_kajarrbi", ["yundu", "kajarrbi", "yinyay", "nyajil"]),
    row(14, "You see the kunkun periwinkle there.", "Yundu kunkun yinyay nyajil.", "yundu kunkun yinyay nyajil | 2sg.NOM kunkun.periwinkle there see.NPST", "r329_2sg_there_low_shellfish_see_kunkun", ["yundu", "kunkun", "yinyay", "nyajil"]),
    row(15, "You see the kurrija octopus there.", "Yundu kurrija yinyay nyajil.", "yundu kurrija yinyay nyajil | 2sg.NOM kurrija.octopus there see.NPST", "r329_2sg_there_low_shellfish_see_kurrija", ["yundu", "kurrija", "yinyay", "nyajil"]),
    row(16, "You see the ngajay small crayfish there.", "Yundu ngajay yinyay nyajil.", "yundu ngajay yinyay nyajil | 2sg.NOM ngajay.small.crayfish there see.NPST", "r329_2sg_there_low_shellfish_see_ngajay", ["yundu", "ngajay", "yinyay", "nyajil"]),
    row(17, "You see the nikar oyster there.", "Yundu nikar yinyay nyajil.", "yundu nikar yinyay nyajil | 2sg.NOM nikar.oyster there see.NPST", "r329_2sg_there_low_shellfish_see_nikar", ["yundu", "nikar", "yinyay", "nyajil"]),
    row(18, "You see the wuli-wuli soldier crab there.", "Yundu wuli-wuli yinyay nyajil.", "yundu wuli-wuli yinyay nyajil | 2sg.NOM wuli.wuli.soldier.crab there see.NPST", "r329_2sg_there_low_shellfish_see_wuli_wuli", ["yundu", "wuli-wuli", "yinyay", "nyajil"]),
    row(19, "You see the jalan sea urchin there.", "Yundu jalan yinyay nyajil.", "yundu jalan yinyay nyajil | 2sg.NOM jalan.sea.urchin there see.NPST", "r329_2sg_there_low_shellfish_see_jalan", ["yundu", "jalan", "yinyay", "nyajil"]),
    row(20, "You see the wurrul shellfish there.", "Yundu wurrul yinyay nyajil.", "yundu wurrul yinyay nyajil | 2sg.NOM wurrul.shellfish there see.NPST", "r329_2sg_there_low_shellfish_see_wurrul", ["yundu", "wurrul", "yinyay", "nyajil"]),
    row(21, "He sees the wurru-bulan small crab here.", "Nyulu wurru-bulan yaluy nyajil.", "nyulu wurru-bulan yaluy nyajil | 3sg.NOM wurru.bulan.small.crab here see.NPST", "r329_3sg_here_low_shellfish_see_wurru_bulan", ["nyulu", "wurru-bulan", "yaluy", "nyajil"]),
    row(22, "He sees the dakaldakal trochus shell here.", "Nyulu dakaldakal yaluy nyajil.", "nyulu dakaldakal yaluy nyajil | 3sg.NOM dakaldakal.trochus.shell here see.NPST", "r329_3sg_here_low_shellfish_see_dakaldakal", ["nyulu", "dakaldakal", "yaluy", "nyajil"]),
    row(23, "He sees the kajarrbi clam shell here.", "Nyulu kajarrbi yaluy nyajil.", "nyulu kajarrbi yaluy nyajil | 3sg.NOM kajarrbi.clam.shell here see.NPST", "r329_3sg_here_low_shellfish_see_kajarrbi", ["nyulu", "kajarrbi", "yaluy", "nyajil"]),
    row(24, "He sees the kunkun periwinkle here.", "Nyulu kunkun yaluy nyajil.", "nyulu kunkun yaluy nyajil | 3sg.NOM kunkun.periwinkle here see.NPST", "r329_3sg_here_low_shellfish_see_kunkun", ["nyulu", "kunkun", "yaluy", "nyajil"]),
    row(25, "He sees the kurrija octopus here.", "Nyulu kurrija yaluy nyajil.", "nyulu kurrija yaluy nyajil | 3sg.NOM kurrija.octopus here see.NPST", "r329_3sg_here_low_shellfish_see_kurrija", ["nyulu", "kurrija", "yaluy", "nyajil"]),
    row(26, "He sees the ngajay small crayfish here.", "Nyulu ngajay yaluy nyajil.", "nyulu ngajay yaluy nyajil | 3sg.NOM ngajay.small.crayfish here see.NPST", "r329_3sg_here_low_shellfish_see_ngajay", ["nyulu", "ngajay", "yaluy", "nyajil"]),
    row(27, "He sees the nikar oyster here.", "Nyulu nikar yaluy nyajil.", "nyulu nikar yaluy nyajil | 3sg.NOM nikar.oyster here see.NPST", "r329_3sg_here_low_shellfish_see_nikar", ["nyulu", "nikar", "yaluy", "nyajil"]),
    row(28, "He sees the wuli-wuli soldier crab here.", "Nyulu wuli-wuli yaluy nyajil.", "nyulu wuli-wuli yaluy nyajil | 3sg.NOM wuli.wuli.soldier.crab here see.NPST", "r329_3sg_here_low_shellfish_see_wuli_wuli", ["nyulu", "wuli-wuli", "yaluy", "nyajil"]),
    row(29, "He sees the jalan sea urchin here.", "Nyulu jalan yaluy nyajil.", "nyulu jalan yaluy nyajil | 3sg.NOM jalan.sea.urchin here see.NPST", "r329_3sg_here_low_shellfish_see_jalan", ["nyulu", "jalan", "yaluy", "nyajil"]),
    row(30, "He sees the wurrul shellfish here.", "Nyulu wurrul yaluy nyajil.", "nyulu wurrul yaluy nyajil | 3sg.NOM wurrul.shellfish here see.NPST", "r329_3sg_here_low_shellfish_see_wurrul", ["nyulu", "wurrul", "yaluy", "nyajil"]),
    row(31, "The two of them see the wurru-bulan small crab there.", "Bula wurru-bulan yinyay nyajil.", "bula wurru-bulan yinyay nyajil | 3du.NOM wurru.bulan.small.crab there see.NPST", "r329_3du_there_low_shellfish_see_wurru_bulan", ["bula", "wurru-bulan", "yinyay", "nyajil"]),
    row(32, "The two of them see the dakaldakal trochus shell there.", "Bula dakaldakal yinyay nyajil.", "bula dakaldakal yinyay nyajil | 3du.NOM dakaldakal.trochus.shell there see.NPST", "r329_3du_there_low_shellfish_see_dakaldakal", ["bula", "dakaldakal", "yinyay", "nyajil"]),
    row(33, "The two of them see the kajarrbi clam shell there.", "Bula kajarrbi yinyay nyajil.", "bula kajarrbi yinyay nyajil | 3du.NOM kajarrbi.clam.shell there see.NPST", "r329_3du_there_low_shellfish_see_kajarrbi", ["bula", "kajarrbi", "yinyay", "nyajil"]),
    row(34, "The two of them see the kunkun periwinkle there.", "Bula kunkun yinyay nyajil.", "bula kunkun yinyay nyajil | 3du.NOM kunkun.periwinkle there see.NPST", "r329_3du_there_low_shellfish_see_kunkun", ["bula", "kunkun", "yinyay", "nyajil"]),
    row(35, "The two of them see the kurrija octopus there.", "Bula kurrija yinyay nyajil.", "bula kurrija yinyay nyajil | 3du.NOM kurrija.octopus there see.NPST", "r329_3du_there_low_shellfish_see_kurrija", ["bula", "kurrija", "yinyay", "nyajil"]),
    row(36, "The two of them see the ngajay small crayfish there.", "Bula ngajay yinyay nyajil.", "bula ngajay yinyay nyajil | 3du.NOM ngajay.small.crayfish there see.NPST", "r329_3du_there_low_shellfish_see_ngajay", ["bula", "ngajay", "yinyay", "nyajil"]),
    row(37, "The two of them see the nikar oyster there.", "Bula nikar yinyay nyajil.", "bula nikar yinyay nyajil | 3du.NOM nikar.oyster there see.NPST", "r329_3du_there_low_shellfish_see_nikar", ["bula", "nikar", "yinyay", "nyajil"]),
    row(38, "The two of them see the wuli-wuli soldier crab there.", "Bula wuli-wuli yinyay nyajil.", "bula wuli-wuli yinyay nyajil | 3du.NOM wuli.wuli.soldier.crab there see.NPST", "r329_3du_there_low_shellfish_see_wuli_wuli", ["bula", "wuli-wuli", "yinyay", "nyajil"]),
    row(39, "The two of them see the jalan sea urchin there.", "Bula jalan yinyay nyajil.", "bula jalan yinyay nyajil | 3du.NOM jalan.sea.urchin there see.NPST", "r329_3du_there_low_shellfish_see_jalan", ["bula", "jalan", "yinyay", "nyajil"]),
    row(40, "The two of them see the wurrul shellfish there.", "Bula wurrul yinyay nyajil.", "bula wurrul yinyay nyajil | 3du.NOM wurrul.shellfish there see.NPST", "r329_3du_there_low_shellfish_see_wurrul", ["bula", "wurrul", "yinyay", "nyajil"]),
    row(41, "They see the wurru-bulan small crab here.", "Jana wurru-bulan yaluy nyajil.", "jana wurru-bulan yaluy nyajil | 3pl.NOM wurru.bulan.small.crab here see.NPST", "r329_3pl_here_low_shellfish_see_wurru_bulan", ["jana", "wurru-bulan", "yaluy", "nyajil"]),
    row(42, "They see the dakaldakal trochus shell here.", "Jana dakaldakal yaluy nyajil.", "jana dakaldakal yaluy nyajil | 3pl.NOM dakaldakal.trochus.shell here see.NPST", "r329_3pl_here_low_shellfish_see_dakaldakal", ["jana", "dakaldakal", "yaluy", "nyajil"]),
    row(43, "They see the kajarrbi clam shell here.", "Jana kajarrbi yaluy nyajil.", "jana kajarrbi yaluy nyajil | 3pl.NOM kajarrbi.clam.shell here see.NPST", "r329_3pl_here_low_shellfish_see_kajarrbi", ["jana", "kajarrbi", "yaluy", "nyajil"]),
    row(44, "They see the kunkun periwinkle here.", "Jana kunkun yaluy nyajil.", "jana kunkun yaluy nyajil | 3pl.NOM kunkun.periwinkle here see.NPST", "r329_3pl_here_low_shellfish_see_kunkun", ["jana", "kunkun", "yaluy", "nyajil"]),
    row(45, "They see the kurrija octopus here.", "Jana kurrija yaluy nyajil.", "jana kurrija yaluy nyajil | 3pl.NOM kurrija.octopus here see.NPST", "r329_3pl_here_low_shellfish_see_kurrija", ["jana", "kurrija", "yaluy", "nyajil"]),
    row(46, "They see the ngajay small crayfish here.", "Jana ngajay yaluy nyajil.", "jana ngajay yaluy nyajil | 3pl.NOM ngajay.small.crayfish here see.NPST", "r329_3pl_here_low_shellfish_see_ngajay", ["jana", "ngajay", "yaluy", "nyajil"]),
    row(47, "They see the nikar oyster here.", "Jana nikar yaluy nyajil.", "jana nikar yaluy nyajil | 3pl.NOM nikar.oyster here see.NPST", "r329_3pl_here_low_shellfish_see_nikar", ["jana", "nikar", "yaluy", "nyajil"]),
    row(48, "They see the wuli-wuli soldier crab here.", "Jana wuli-wuli yaluy nyajil.", "jana wuli-wuli yaluy nyajil | 3pl.NOM wuli.wuli.soldier.crab here see.NPST", "r329_3pl_here_low_shellfish_see_wuli_wuli", ["jana", "wuli-wuli", "yaluy", "nyajil"]),
    row(49, "They see the jalan sea urchin here.", "Jana jalan yaluy nyajil.", "jana jalan yaluy nyajil | 3pl.NOM jalan.sea.urchin here see.NPST", "r329_3pl_here_low_shellfish_see_jalan", ["jana", "jalan", "yaluy", "nyajil"]),
    row(50, "They see the wurrul shellfish here.", "Jana wurrul yaluy nyajil.", "jana wurrul yaluy nyajil | 3pl.NOM wurrul.shellfish here see.NPST", "r329_3pl_here_low_shellfish_see_wurrul", ["jana", "wurrul", "yaluy", "nyajil"]),
]


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} nyajil."; expected_english=f"{prefix} the {TARGET_LABELS[target]} {location}."; expected_analysis=f"{pronoun} {target} {demo} nyajil | {person_gloss}.NOM {TARGET_GLOSSES[target]} {location} see.NPST"
        low_kuku=kuku.lower(); low_english=english.lower()
        if loans: issues.append(f"{seq}: loans used {loans}")
        denied=sorted({word for word in DENY_KUKU if re.search(rf"(^|\s){re.escape(word.lower())}([\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,"nyajil"]: 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("r329_"): issues.append(f"{seq}: frame not r329")
        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","nyajil"])
    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 SHELLFISH/CRUSTACEAN SINGULAR/THIRD-PERSON NONPAST PERCEPTION AFTER RULE 328 (Rule 329). 50 under-review rows over nine 7-9-use domain heads plus one 10-use control: wurru-bulan, dakaldakal, kajarrbi, kunkun, kurrija, ngajay, nikar, wuli-wuli, jalan, wurrul. Jirrum was excluded because its dictionary-final -m violates the corpus orthotactic contract. Exact referential senses only; no loans, base/productive reduplication, shell/animal collapse, habitat, edibility, gathering, catching, cooking, eating, source, possession, case, past/purposive/reduplicated perception, or support drift.")
    cur=db.execute("INSERT INTO batches(label,cheatsheet_version,guide_version,notes,created_at) VALUES(?,?,?,?,?)",(LABEL,"Rule 329 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 dictionary shellfish/crustacean entries; exact Patz search found dakaldakal only, in the trochus-shell sense, with the other nine absent; reread Patz fauna noun status, singular/third pronouns, Yalanji demonstratives, nonpast, perception A/O, and dictionary nyajil.",artifact_path=PROCESS_LOG,created_at=NOW)
    record_event(db,batch_label=LABEL,phase="planning",event_type="candidate-audit",actor="codex",detail="Structured domain audit found ten noun-typed shellfish/crustacean heads at coverage 0-9. Direct dictionary jirrum was excluded because final -m fails the established corpus orthotactic contract; no one-off linter exception was added. The next-lowest direct unflagged head, 10-use wurru-bulan, serves as control. Shell/animal readings and three lexicalized reduplicated forms remain exact.",artifact_path=PROCESS_LOG,created_at=NOW)
    record_event(db,batch_label=LABEL,phase="planning",event_type="low-shellfish-singular-third-nonpast-scope",actor="codex",detail="Locked all ten low-coverage shellfish/crustacean heads to bare reference in five sourced singular/third-person nonpast-perception frames. Reduplication, shell/animal identity, habitat, edibility, gathering, catching, use, source, property, case, and event fields remain closed.",artifact_path=PROCESS_LOG,created_at=NOW)
    record_event(db,batch_label=LABEL,phase="preflight",event_type="coverage-audit",actor="codex",detail=f"Token-aware accepted/revised coverage before banking: targets={target_counts}; support={support_counts}.",artifact_path=PROCESS_LOG,created_at=NOW)
    record_event(db,batch_label=LABEL,phase="preflight",event_type="duplicate-preflight",actor="codex",detail="All 50 Rule 329 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 marine-fauna head each, bare singular/third nominatives, Yalanji demonstratives, final nyajil, no loans, reduplication/base, habitat/use, source, case, or support drift.",command="python3 -m py_compile batch_scripts/bank_371.py batch_scripts/close_371.py && AST/static/lint probes",output_excerpt="50 explicit rows; scan_static 0; 50 linter probes 0; collisions 0",artifact_path="batch_scripts/bank_371.py",created_at=NOW)
    record_event(db,batch_label=LABEL,phase="bank",event_type="bank-success",actor="codex",detail=f"Banked 50 Rule 329 rows as under_review. Verified remains {verified_before}; Kuku words remain {words_before}.",command="python3 batch_scripts/bank_371.py",output_excerpt=f"banked batch-371: 50 under_review; verified_before={verified_before}; words_before={words_before}",artifact_path=PROCESS_LOG,created_at=NOW)
    db.commit(); print("banked batch-371: 50 rows under_review"); return 0


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