#!/usr/bin/env python3
"""Bank batch-372: Rule 330 low-coverage fish non-singular past perception."""

from __future__ import annotations

import datetime as dt
import json
import re
import sqlite3

from process_ledger import ensure_schema, record_event

DB = "/mnt/donto-data/donto-resources/research/translation-training/kuku-yalanji-runpod-2026-06-30/synthetic/claude-synthetic-v1-2026-07-02/synthetic.db"
LABEL = "batch-372"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-372-low-coverage-fish-nonsingular-past-perception-after-rule329-process.md"

TARGET_EVIDENCE = {
    "bububay": "Dictionary yaml lines 3470-3482 contain an empty source placeholder marked needs_review and a separate complete fauna-fish noun record for bububay 'black tip shark'. Rule 330 relies only on the complete record and admits blacktip-shark reference; it leaves placeholder reconciliation, spelling normalization, body/fin parts, colour/pattern, water/reef habitat, movement, catching, danger, food, possession, source, and event propositions closed.",
    "baban": "Dictionary yaml lines 91-108 contain two agreeing noun records for baban, with source spelling 'anglefish' corrected by the duplicate record to 'angelfish'. Rule 330 admits angelfish reference only and leaves spelling-variant propositions, body parts, colour/pattern, water/reef habitat, catching, food, possession, source, and event propositions closed.",
    "kundurr-kundurr": "Dictionary yaml lines 15722-15735 give exact hyphenated kundurr-kundurr as a full-reduplicated noun for crescent perch, based on kundurr. Rule 330 admits the whole lexical head only and leaves free-base use, productive reduplication, crescent-shape property, water habitat, catching, food, possession, source, and events closed.",
    "kurruba": "Dictionary yaml lines 16537-16545 give kurruba as a species of freshwater fish. Rule 330 admits the conservative freshwater-fish label only and leaves species identity, freshwater habitat proposition, size/appearance, movement, catching, food, possession, source, equivalence to another fish head, and event propositions closed.",
    "murrabal": "Dictionary yaml lines 20970-20980 give murrabal as the Yalanji noun for barramundi and note Nyungkul kudi. Rule 330 admits the Yalanji barramundi reading only and leaves dialect equivalence/substitution, water habitat, size, catching, spearing, cooking, eating, possession, source, and event propositions closed.",
    "dukul-barangkal": "Dictionary yaml lines 6312-6322 give exact hyphenated dukul-barangkal as a noun for flathead fish and list dalmbal as a synonym. Rule 330 admits the whole flathead-fish head only and leaves component decomposition, productive compounding, synonym substitution/equivalence, head/body shape, water habitat, catching, food, possession, source, and events closed.",
    "jalil-jalil": "Dictionary yaml lines 7406-7419 give exact hyphenated jalil-jalil as a full-reduplicated noun for mudskipper, based on jalil. Rule 330 admits the whole lexical head only and leaves free-base use, productive reduplication, mud/water habitat, skipping/movement, amphibious property, catching, food, possession, source, and events closed.",
    "kurrubal": "Dictionary yaml lines 16546-16556 give kurrubal as the noun for freshwater cod. Rule 330 admits freshwater-cod reference only and leaves species identity beyond the label, freshwater habitat proposition, size/appearance, movement, catching, food, possession, source, and event propositions closed.",
    "murraja": "Dictionary yaml lines 20981-20998 contain two agreeing noun records for murraja 'stonefish'. Patz lines 4279, 4340, 6505, and 6507 attest inflected murraja in clauses about poking. Rule 330 admits bare stonefish reference only and leaves potent/ergative/instrumental/locative morphology, poking, injury, foot/body contact, danger, story context, habitat, catching, food, possession, source, and events closed.",
    "kubu-kubu": "Dictionary yaml lines 14716-14729 give exact hyphenated kubu-kubu as a full-reduplicated noun for tadpole, based on kubu. Rule 330 admits the whole tadpole head only and leaves free-base use, productive reduplication, frog identity/transformation, life stage, water habitat, movement, catching, food, possession, source, and events 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. Exact Patz target search finds only "
    "murraja, in inflected stonefish/poking clauses; the other nine selected heads are absent. Rule 330 takes "
    "every selected fish reading from the dictionary and uses only bare support and past visual perception."
)

TARGET_ORDER = ["bububay", "baban", "kundurr-kundurr", "kurruba", "murrabal", "dukul-barangkal", "jalil-jalil", "kurrubal", "murraja", "kubu-kubu"]
TARGET_LABELS = {
    "bububay": "bububay blacktip shark",
    "baban": "baban angelfish",
    "kundurr-kundurr": "kundurr-kundurr crescent perch",
    "kurruba": "kurruba freshwater fish",
    "murrabal": "murrabal barramundi",
    "dukul-barangkal": "dukul-barangkal flathead fish",
    "jalil-jalil": "jalil-jalil mudskipper",
    "kurrubal": "kurrubal freshwater cod",
    "murraja": "murraja stonefish",
    "kubu-kubu": "kubu-kubu tadpole",
}
TARGET_GLOSSES = {
    "bububay": "bububay.blacktip.shark",
    "baban": "baban.angelfish",
    "kundurr-kundurr": "kundurr.kundurr.crescent.perch",
    "kurruba": "kurruba.freshwater.fish",
    "murrabal": "murrabal.barramundi",
    "dukul-barangkal": "dukul.barangkal.flathead.fish",
    "jalil-jalil": "jalil.jalil.mudskipper",
    "kurrubal": "kurrubal.freshwater.cod",
    "murraja": "murraja.stonefish",
    "kubu-kubu": "kubu.kubu.tadpole",
}
TARGET_CONFIDENCE = {"bububay": "0.90", "baban": "0.92", "kundurr-kundurr": "0.94", "kurruba": "0.88", "murrabal": "0.94", "dukul-barangkal": "0.90", "jalil-jalil": "0.94", "kurrubal": "0.93", "murraja": "0.95", "kubu-kubu": "0.94"}
EXPECTED_TARGET_COVERAGE = {"bububay": 5, "baban": 5, "kundurr-kundurr": 5, "kurruba": 5, "murrabal": 5, "dukul-barangkal": 6, "jalil-jalil": 6, "kurrubal": 6, "murraja": 7, "kubu-kubu": 7}
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",
    "bayilbayil", "kijukum", "yidilnyul", "yidi", "kanyaji", "dalku", "danbal", "ngiwa", "wara",
    "walkan", "walbul-walbul", "walarrji", "kalngkan", "mangkurr-mangkurr", "walarr", "kudi",
    "dalmbal", "kundurr", "jalil", "kubu", "yalay", "yala", "yanyu", "yinya", "yalungku",
    "yaluyngku", "yinyangka", "yinyayngka", "yalamuny", "yinyamuny", "nyajil", "nyaji-l",
    "nyaji-nka", "nyaji-l-nyaji", "milka", "baykal", "jalngkay",
}
DENY_ENGLISH = (
    "whisker", "decompose", "comitative", "proprietive", "naming", "spelling variant", "body part",
    "colour", "pattern", "reef", "free base", "productive reduplication", "crescent shape", "species identity",
    "water habitat", "freshwater habitat", "size", "appearance", "move", "catch", "food", "possess", "source",
    "dialect equivalent", "substitute", "spear", "cook", "eat", "component", "productive compound", "synonym",
    "head shape", "mud habitat", "skip", "amphibious", "potent", "ergative", "instrumental", "locative",
    "poke", "injury", "foot", "danger", "story", "frog", "transform", "life stage", "event", "use", "used", "using",
)


def count_words(db: sqlite3.Connection, words: list[str]) -> dict[str, int]:
    return {word: db.execute("""SELECT COUNT(*) FROM sentences s WHERE s.status IN ('accepted','revised') AND EXISTS (SELECT 1 FROM json_each(s.words_used) WHERE lower(value)=?)""", (word,)).fetchone()[0] for word in words}


def row(seq: int, english: str, kuku: str, analysis: str, frame: str, words: list[str]) -> tuple:
    target = words[1]
    return (seq, english, kuku, analysis, frame, 3, json.dumps(words, ensure_ascii=False), json.dumps([], ensure_ascii=False), f"{TARGET_EVIDENCE[target]} {SUPPORT_EVIDENCE}", TARGET_CONFIDENCE[target])


ROWS = [
    row(1, "We two, not you, saw the bububay blacktip shark here.", "Ngali bububay yaluy nyajin.", "ngali bububay yaluy nyajin | 1du.excl.NOM bububay.blacktip.shark here see.PST", "r330_1du_excl_here_low_fish_saw_bububay", ["ngali", "bububay", "yaluy", "nyajin"]),
    row(2, "We two, not you, saw the baban angelfish here.", "Ngali baban yaluy nyajin.", "ngali baban yaluy nyajin | 1du.excl.NOM baban.angelfish here see.PST", "r330_1du_excl_here_low_fish_saw_baban", ["ngali", "baban", "yaluy", "nyajin"]),
    row(3, "We two, not you, saw the kundurr-kundurr crescent perch here.", "Ngali kundurr-kundurr yaluy nyajin.", "ngali kundurr-kundurr yaluy nyajin | 1du.excl.NOM kundurr.kundurr.crescent.perch here see.PST", "r330_1du_excl_here_low_fish_saw_kundurr_kundurr", ["ngali", "kundurr-kundurr", "yaluy", "nyajin"]),
    row(4, "We two, not you, saw the kurruba freshwater fish here.", "Ngali kurruba yaluy nyajin.", "ngali kurruba yaluy nyajin | 1du.excl.NOM kurruba.freshwater.fish here see.PST", "r330_1du_excl_here_low_fish_saw_kurruba", ["ngali", "kurruba", "yaluy", "nyajin"]),
    row(5, "We two, not you, saw the murrabal barramundi here.", "Ngali murrabal yaluy nyajin.", "ngali murrabal yaluy nyajin | 1du.excl.NOM murrabal.barramundi here see.PST", "r330_1du_excl_here_low_fish_saw_murrabal", ["ngali", "murrabal", "yaluy", "nyajin"]),
    row(6, "We two, not you, saw the dukul-barangkal flathead fish here.", "Ngali dukul-barangkal yaluy nyajin.", "ngali dukul-barangkal yaluy nyajin | 1du.excl.NOM dukul.barangkal.flathead.fish here see.PST", "r330_1du_excl_here_low_fish_saw_dukul_barangkal", ["ngali", "dukul-barangkal", "yaluy", "nyajin"]),
    row(7, "We two, not you, saw the jalil-jalil mudskipper here.", "Ngali jalil-jalil yaluy nyajin.", "ngali jalil-jalil yaluy nyajin | 1du.excl.NOM jalil.jalil.mudskipper here see.PST", "r330_1du_excl_here_low_fish_saw_jalil_jalil", ["ngali", "jalil-jalil", "yaluy", "nyajin"]),
    row(8, "We two, not you, saw the kurrubal freshwater cod here.", "Ngali kurrubal yaluy nyajin.", "ngali kurrubal yaluy nyajin | 1du.excl.NOM kurrubal.freshwater.cod here see.PST", "r330_1du_excl_here_low_fish_saw_kurrubal", ["ngali", "kurrubal", "yaluy", "nyajin"]),
    row(9, "We two, not you, saw the murraja stonefish here.", "Ngali murraja yaluy nyajin.", "ngali murraja yaluy nyajin | 1du.excl.NOM murraja.stonefish here see.PST", "r330_1du_excl_here_low_fish_saw_murraja", ["ngali", "murraja", "yaluy", "nyajin"]),
    row(10, "We two, not you, saw the kubu-kubu tadpole here.", "Ngali kubu-kubu yaluy nyajin.", "ngali kubu-kubu yaluy nyajin | 1du.excl.NOM kubu.kubu.tadpole here see.PST", "r330_1du_excl_here_low_fish_saw_kubu_kubu", ["ngali", "kubu-kubu", "yaluy", "nyajin"]),
    row(11, "You and I saw the bububay blacktip shark there.", "Ngaliny bububay yinyay nyajin.", "ngaliny bububay yinyay nyajin | 1du.incl.NOM bububay.blacktip.shark there see.PST", "r330_1du_incl_there_low_fish_saw_bububay", ["ngaliny", "bububay", "yinyay", "nyajin"]),
    row(12, "You and I saw the baban angelfish there.", "Ngaliny baban yinyay nyajin.", "ngaliny baban yinyay nyajin | 1du.incl.NOM baban.angelfish there see.PST", "r330_1du_incl_there_low_fish_saw_baban", ["ngaliny", "baban", "yinyay", "nyajin"]),
    row(13, "You and I saw the kundurr-kundurr crescent perch there.", "Ngaliny kundurr-kundurr yinyay nyajin.", "ngaliny kundurr-kundurr yinyay nyajin | 1du.incl.NOM kundurr.kundurr.crescent.perch there see.PST", "r330_1du_incl_there_low_fish_saw_kundurr_kundurr", ["ngaliny", "kundurr-kundurr", "yinyay", "nyajin"]),
    row(14, "You and I saw the kurruba freshwater fish there.", "Ngaliny kurruba yinyay nyajin.", "ngaliny kurruba yinyay nyajin | 1du.incl.NOM kurruba.freshwater.fish there see.PST", "r330_1du_incl_there_low_fish_saw_kurruba", ["ngaliny", "kurruba", "yinyay", "nyajin"]),
    row(15, "You and I saw the murrabal barramundi there.", "Ngaliny murrabal yinyay nyajin.", "ngaliny murrabal yinyay nyajin | 1du.incl.NOM murrabal.barramundi there see.PST", "r330_1du_incl_there_low_fish_saw_murrabal", ["ngaliny", "murrabal", "yinyay", "nyajin"]),
    row(16, "You and I saw the dukul-barangkal flathead fish there.", "Ngaliny dukul-barangkal yinyay nyajin.", "ngaliny dukul-barangkal yinyay nyajin | 1du.incl.NOM dukul.barangkal.flathead.fish there see.PST", "r330_1du_incl_there_low_fish_saw_dukul_barangkal", ["ngaliny", "dukul-barangkal", "yinyay", "nyajin"]),
    row(17, "You and I saw the jalil-jalil mudskipper there.", "Ngaliny jalil-jalil yinyay nyajin.", "ngaliny jalil-jalil yinyay nyajin | 1du.incl.NOM jalil.jalil.mudskipper there see.PST", "r330_1du_incl_there_low_fish_saw_jalil_jalil", ["ngaliny", "jalil-jalil", "yinyay", "nyajin"]),
    row(18, "You and I saw the kurrubal freshwater cod there.", "Ngaliny kurrubal yinyay nyajin.", "ngaliny kurrubal yinyay nyajin | 1du.incl.NOM kurrubal.freshwater.cod there see.PST", "r330_1du_incl_there_low_fish_saw_kurrubal", ["ngaliny", "kurrubal", "yinyay", "nyajin"]),
    row(19, "You and I saw the murraja stonefish there.", "Ngaliny murraja yinyay nyajin.", "ngaliny murraja yinyay nyajin | 1du.incl.NOM murraja.stonefish there see.PST", "r330_1du_incl_there_low_fish_saw_murraja", ["ngaliny", "murraja", "yinyay", "nyajin"]),
    row(20, "You and I saw the kubu-kubu tadpole there.", "Ngaliny kubu-kubu yinyay nyajin.", "ngaliny kubu-kubu yinyay nyajin | 1du.incl.NOM kubu.kubu.tadpole there see.PST", "r330_1du_incl_there_low_fish_saw_kubu_kubu", ["ngaliny", "kubu-kubu", "yinyay", "nyajin"]),
    row(21, "You two saw the bububay blacktip shark here.", "Yubal bububay yaluy nyajin.", "yubal bububay yaluy nyajin | 2du.NOM bububay.blacktip.shark here see.PST", "r330_2du_here_low_fish_saw_bububay", ["yubal", "bububay", "yaluy", "nyajin"]),
    row(22, "You two saw the baban angelfish here.", "Yubal baban yaluy nyajin.", "yubal baban yaluy nyajin | 2du.NOM baban.angelfish here see.PST", "r330_2du_here_low_fish_saw_baban", ["yubal", "baban", "yaluy", "nyajin"]),
    row(23, "You two saw the kundurr-kundurr crescent perch here.", "Yubal kundurr-kundurr yaluy nyajin.", "yubal kundurr-kundurr yaluy nyajin | 2du.NOM kundurr.kundurr.crescent.perch here see.PST", "r330_2du_here_low_fish_saw_kundurr_kundurr", ["yubal", "kundurr-kundurr", "yaluy", "nyajin"]),
    row(24, "You two saw the kurruba freshwater fish here.", "Yubal kurruba yaluy nyajin.", "yubal kurruba yaluy nyajin | 2du.NOM kurruba.freshwater.fish here see.PST", "r330_2du_here_low_fish_saw_kurruba", ["yubal", "kurruba", "yaluy", "nyajin"]),
    row(25, "You two saw the murrabal barramundi here.", "Yubal murrabal yaluy nyajin.", "yubal murrabal yaluy nyajin | 2du.NOM murrabal.barramundi here see.PST", "r330_2du_here_low_fish_saw_murrabal", ["yubal", "murrabal", "yaluy", "nyajin"]),
    row(26, "You two saw the dukul-barangkal flathead fish here.", "Yubal dukul-barangkal yaluy nyajin.", "yubal dukul-barangkal yaluy nyajin | 2du.NOM dukul.barangkal.flathead.fish here see.PST", "r330_2du_here_low_fish_saw_dukul_barangkal", ["yubal", "dukul-barangkal", "yaluy", "nyajin"]),
    row(27, "You two saw the jalil-jalil mudskipper here.", "Yubal jalil-jalil yaluy nyajin.", "yubal jalil-jalil yaluy nyajin | 2du.NOM jalil.jalil.mudskipper here see.PST", "r330_2du_here_low_fish_saw_jalil_jalil", ["yubal", "jalil-jalil", "yaluy", "nyajin"]),
    row(28, "You two saw the kurrubal freshwater cod here.", "Yubal kurrubal yaluy nyajin.", "yubal kurrubal yaluy nyajin | 2du.NOM kurrubal.freshwater.cod here see.PST", "r330_2du_here_low_fish_saw_kurrubal", ["yubal", "kurrubal", "yaluy", "nyajin"]),
    row(29, "You two saw the murraja stonefish here.", "Yubal murraja yaluy nyajin.", "yubal murraja yaluy nyajin | 2du.NOM murraja.stonefish here see.PST", "r330_2du_here_low_fish_saw_murraja", ["yubal", "murraja", "yaluy", "nyajin"]),
    row(30, "You two saw the kubu-kubu tadpole here.", "Yubal kubu-kubu yaluy nyajin.", "yubal kubu-kubu yaluy nyajin | 2du.NOM kubu.kubu.tadpole here see.PST", "r330_2du_here_low_fish_saw_kubu_kubu", ["yubal", "kubu-kubu", "yaluy", "nyajin"]),
    row(31, "You all saw the bububay blacktip shark there.", "Yurra bububay yinyay nyajin.", "yurra bububay yinyay nyajin | 2pl.NOM bububay.blacktip.shark there see.PST", "r330_2pl_there_low_fish_saw_bububay", ["yurra", "bububay", "yinyay", "nyajin"]),
    row(32, "You all saw the baban angelfish there.", "Yurra baban yinyay nyajin.", "yurra baban yinyay nyajin | 2pl.NOM baban.angelfish there see.PST", "r330_2pl_there_low_fish_saw_baban", ["yurra", "baban", "yinyay", "nyajin"]),
    row(33, "You all saw the kundurr-kundurr crescent perch there.", "Yurra kundurr-kundurr yinyay nyajin.", "yurra kundurr-kundurr yinyay nyajin | 2pl.NOM kundurr.kundurr.crescent.perch there see.PST", "r330_2pl_there_low_fish_saw_kundurr_kundurr", ["yurra", "kundurr-kundurr", "yinyay", "nyajin"]),
    row(34, "You all saw the kurruba freshwater fish there.", "Yurra kurruba yinyay nyajin.", "yurra kurruba yinyay nyajin | 2pl.NOM kurruba.freshwater.fish there see.PST", "r330_2pl_there_low_fish_saw_kurruba", ["yurra", "kurruba", "yinyay", "nyajin"]),
    row(35, "You all saw the murrabal barramundi there.", "Yurra murrabal yinyay nyajin.", "yurra murrabal yinyay nyajin | 2pl.NOM murrabal.barramundi there see.PST", "r330_2pl_there_low_fish_saw_murrabal", ["yurra", "murrabal", "yinyay", "nyajin"]),
    row(36, "You all saw the dukul-barangkal flathead fish there.", "Yurra dukul-barangkal yinyay nyajin.", "yurra dukul-barangkal yinyay nyajin | 2pl.NOM dukul.barangkal.flathead.fish there see.PST", "r330_2pl_there_low_fish_saw_dukul_barangkal", ["yurra", "dukul-barangkal", "yinyay", "nyajin"]),
    row(37, "You all saw the jalil-jalil mudskipper there.", "Yurra jalil-jalil yinyay nyajin.", "yurra jalil-jalil yinyay nyajin | 2pl.NOM jalil.jalil.mudskipper there see.PST", "r330_2pl_there_low_fish_saw_jalil_jalil", ["yurra", "jalil-jalil", "yinyay", "nyajin"]),
    row(38, "You all saw the kurrubal freshwater cod there.", "Yurra kurrubal yinyay nyajin.", "yurra kurrubal yinyay nyajin | 2pl.NOM kurrubal.freshwater.cod there see.PST", "r330_2pl_there_low_fish_saw_kurrubal", ["yurra", "kurrubal", "yinyay", "nyajin"]),
    row(39, "You all saw the murraja stonefish there.", "Yurra murraja yinyay nyajin.", "yurra murraja yinyay nyajin | 2pl.NOM murraja.stonefish there see.PST", "r330_2pl_there_low_fish_saw_murraja", ["yurra", "murraja", "yinyay", "nyajin"]),
    row(40, "You all saw the kubu-kubu tadpole there.", "Yurra kubu-kubu yinyay nyajin.", "yurra kubu-kubu yinyay nyajin | 2pl.NOM kubu.kubu.tadpole there see.PST", "r330_2pl_there_low_fish_saw_kubu_kubu", ["yurra", "kubu-kubu", "yinyay", "nyajin"]),
    row(41, "We saw the bububay blacktip shark here.", "Ngana bububay yaluy nyajin.", "ngana bububay yaluy nyajin | 1pl.incl.NOM bububay.blacktip.shark here see.PST", "r330_1pl_incl_here_low_fish_saw_bububay", ["ngana", "bububay", "yaluy", "nyajin"]),
    row(42, "We saw the baban angelfish here.", "Ngana baban yaluy nyajin.", "ngana baban yaluy nyajin | 1pl.incl.NOM baban.angelfish here see.PST", "r330_1pl_incl_here_low_fish_saw_baban", ["ngana", "baban", "yaluy", "nyajin"]),
    row(43, "We saw the kundurr-kundurr crescent perch here.", "Ngana kundurr-kundurr yaluy nyajin.", "ngana kundurr-kundurr yaluy nyajin | 1pl.incl.NOM kundurr.kundurr.crescent.perch here see.PST", "r330_1pl_incl_here_low_fish_saw_kundurr_kundurr", ["ngana", "kundurr-kundurr", "yaluy", "nyajin"]),
    row(44, "We saw the kurruba freshwater fish here.", "Ngana kurruba yaluy nyajin.", "ngana kurruba yaluy nyajin | 1pl.incl.NOM kurruba.freshwater.fish here see.PST", "r330_1pl_incl_here_low_fish_saw_kurruba", ["ngana", "kurruba", "yaluy", "nyajin"]),
    row(45, "We saw the murrabal barramundi here.", "Ngana murrabal yaluy nyajin.", "ngana murrabal yaluy nyajin | 1pl.incl.NOM murrabal.barramundi here see.PST", "r330_1pl_incl_here_low_fish_saw_murrabal", ["ngana", "murrabal", "yaluy", "nyajin"]),
    row(46, "We saw the dukul-barangkal flathead fish here.", "Ngana dukul-barangkal yaluy nyajin.", "ngana dukul-barangkal yaluy nyajin | 1pl.incl.NOM dukul.barangkal.flathead.fish here see.PST", "r330_1pl_incl_here_low_fish_saw_dukul_barangkal", ["ngana", "dukul-barangkal", "yaluy", "nyajin"]),
    row(47, "We saw the jalil-jalil mudskipper here.", "Ngana jalil-jalil yaluy nyajin.", "ngana jalil-jalil yaluy nyajin | 1pl.incl.NOM jalil.jalil.mudskipper here see.PST", "r330_1pl_incl_here_low_fish_saw_jalil_jalil", ["ngana", "jalil-jalil", "yaluy", "nyajin"]),
    row(48, "We saw the kurrubal freshwater cod here.", "Ngana kurrubal yaluy nyajin.", "ngana kurrubal yaluy nyajin | 1pl.incl.NOM kurrubal.freshwater.cod here see.PST", "r330_1pl_incl_here_low_fish_saw_kurrubal", ["ngana", "kurrubal", "yaluy", "nyajin"]),
    row(49, "We saw the murraja stonefish here.", "Ngana murraja yaluy nyajin.", "ngana murraja yaluy nyajin | 1pl.incl.NOM murraja.stonefish here see.PST", "r330_1pl_incl_here_low_fish_saw_murraja", ["ngana", "murraja", "yaluy", "nyajin"]),
    row(50, "We saw the kubu-kubu tadpole here.", "Ngana kubu-kubu yaluy nyajin.", "ngana kubu-kubu yaluy nyajin | 1pl.incl.NOM kubu.kubu.tadpole here see.PST", "r330_1pl_incl_here_low_fish_saw_kubu_kubu", ["ngana", "kubu-kubu", "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("r330_"): issues.append(f"{seq}: frame not r330")
        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,["ngali","ngaliny","yubal","yurra","ngana","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 FISH NON-SINGULAR PAST PERCEPTION AFTER RULE 329 (Rule 330). 50 under-review rows over ten 5-7-use noun heads: bububay, baban, kundurr-kundurr, kurruba, murrabal, dukul-barangkal, jalil-jalil, kurrubal, murraja, kubu-kubu. Agreeing duplicate records and one empty-placeholder/complete-record pair were reconciled; final-m, rhotic-palatal, unhyphenated-reduplication, dialect-only, and conflicting polysemous candidates were excluded. Exact referential senses only; no decomposition/productive morphology, dialect substitution, habitat, catching, food, danger, 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 330 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 selected dictionary fish records, including agreeing duplicates for baban and murraja and the empty-placeholder/complete-record pair for bububay; exact Patz search found only inflected murraja in poking clauses; 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="candidate-audit",actor="codex",detail="Structured fish audit excluded final-m kijukum, rhotic-palatal walarrji, linter-invalid unhyphenated bayilbayil, Nyungkul-only yidilnyul/yidi/kanyaji/dalku, and conflicting/polysemous danbal/ngiwa/wara/walkan. Agreeing duplicates were admitted only after forms/senses aligned; bububay relies only on its complete fish record, not its empty placeholder. Selected ten direct non-loan heads at coverage 5-7.",artifact_path=PROCESS_LOG,created_at=NOW)
    record_event(db,batch_label=LABEL,phase="planning",event_type="low-fish-nonsingular-past-scope",actor="codex",detail="Locked ten low-coverage fish heads to bare reference in five sourced non-singular past-perception frames. Duplicate-record prose, decomposition, productive morphology, dialect substitution, habitat, catching, food, danger, source, possession, 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 330 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 fish head each, bare non-singular nominatives, Yalanji demonstratives, final nyajin, no loans, excluded candidates, decomposition, habitat/use, source, case, or support drift.",command="python3 -m py_compile batch_scripts/bank_372.py batch_scripts/close_372.py && AST/static/lint probes",output_excerpt="50 explicit rows; scan_static 0; 50 linter probes 0; collisions 0",artifact_path="batch_scripts/bank_372.py",created_at=NOW)
    record_event(db,batch_label=LABEL,phase="bank",event_type="bank-success",actor="codex",detail=f"Banked 50 Rule 330 rows as under_review. Verified remains {verified_before}; Kuku words remain {words_before}.",command="python3 batch_scripts/bank_372.py",output_excerpt=f"banked batch-372: 50 under_review; verified_before={verified_before}; words_before={words_before}",artifact_path=PROCESS_LOG,created_at=NOW)
    db.commit();print("banked batch-372: 50 rows under_review");return 0


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