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

TARGET_EVIDENCE = {
    "kundurr-kundurr": "Dictionary yaml lines 15722-15735 give the full reduplicated noun kundurr-kundurr 'crescent perch'. Rule 318 admits that whole dictionary headword as visible fish reference only; it does not derive a productive reduplication or add behavior, habitat, capture, food, or event propositions.",
    "kurruba": "Dictionary yaml lines 16537-16545 give kurruba as a noun for a species of freshwater fish. Rule 318 admits visible kurruba-fish reference only and leaves species biology, water habitat, catching, food, and event propositions closed.",
    "mangkurr-mangkurr": "Dictionary yaml lines 17775-17807 give two concordant noun entries for full reduplicated mangkurr-mangkurr 'garfish'. Rule 318 admits the whole dictionary headword as visible garfish reference only; it does not derive productive reduplication or add swimming, habitat, capture, food, shape, or event propositions.",
    "murrabal": "Dictionary yaml lines 20970-20980 give murrabal as the Yalanji noun 'barramundi' and identify Nyungkul kudi as the dialect counterpart. Rule 318 selects visible Yalanji murrabal-barramundi reference only and leaves kudi, dialect substitution, habitat, catching, food, and event propositions closed.",
    "ngiwa": "Dictionary yaml lines 23200-23237 separate a place/snake-story entry from fauna entries giving ngiwa 'moray eel', sometimes also applied to sea snake. Patz line 1722 independently has ngiwa-nda 'salt-water eel'. Rule 318 selects the bare moray-eel noun only and leaves place, stones, story site, sea-snake alternative, location, case, and event propositions closed.",
    "dijarr": "Dictionary yaml lines 5552-5577 give dijarr as freshwater fish / freshwater perch, with prose comparing bayi and naming Rossville and Shipton's Flats. Rule 318 selects visible dijarr freshwater-perch reference only and leaves comparison species, distribution, place, habitat, catching, food, and event propositions closed.",
    "dukul-barangkal": "Dictionary yaml lines 6312-6323 give lexicalized noun dukul-barangkal 'flathead fish' with synonym dalmbal. Rule 318 admits that exact dictionary compound as one visible fish headword only; it does not decompose the form or add anatomy, shape, synonym, habitat, camouflage, catching, food, or event propositions.",
    "jalil-jalil": "Dictionary yaml lines 7406-7419 give the full reduplicated noun jalil-jalil 'mudskipper'. Rule 318 admits the whole dictionary headword as visible fish reference only and does not inherit climbing, water, mangrove-root, tide, feeding, habitat, or behavior propositions from its earlier corpus row.",
    "kalu": "Dictionary yaml lines 12886-12905 contain separate noun senses kalu 'garfish' and kalu 'salt water catfish'. Rule 318 selects the established corpus garfish reading only and leaves saltwater-catfish ambiguity, habitat, catching, roasting, eating, food quality, and event propositions closed.",
    "mawul": "Dictionary yaml lines 18775-18796 give mawul 'eel' / small freshwater eel, with prose recording an old-people food restriction. Rule 318 selects visible mawul-eel reference only and leaves size, freshwater habitat, age group, permission, eating, taboo, feeding, body properties, catching, and event propositions closed.",
}

SUPPORT_EVIDENCE = (
    "Patz pronoun table lines 2577-2582 sources bare nominatives ngali, ngaliny, yubal, yurra, and ngana; "
    "lines 2674-2684 support their dual/plural, inclusive/exclusive, and person values. Demonstrative lines "
    "2834-2847 source Yalanji yaluy 'here' and yinyay 'there'. Lines 3043-3049 give nyaji-l as nonpast 'see', "
    "lines 3149-3151 define nonpast present/future function, and lines 4256-4265 license nominative pronoun A "
    "with bare absolutive O for sensory perception. Dictionary lines 24282-24296 independently attest running-form "
    "nyajil as a general l-conjugation perception verb including visual 'see'. Rule 318 uses bare support and the "
    "visual, present/nonpast reading only."
)

TARGET_ORDER = [
    "kundurr-kundurr", "kurruba", "mangkurr-mangkurr", "murrabal", "ngiwa",
    "dijarr", "dukul-barangkal", "jalil-jalil", "kalu", "mawul",
]
TARGET_LABELS = {
    "kundurr-kundurr": "kundurr-kundurr crescent perch",
    "kurruba": "kurruba freshwater fish",
    "mangkurr-mangkurr": "mangkurr-mangkurr garfish",
    "murrabal": "murrabal barramundi",
    "ngiwa": "ngiwa moray eel",
    "dijarr": "dijarr freshwater perch",
    "dukul-barangkal": "dukul-barangkal flathead fish",
    "jalil-jalil": "jalil-jalil mudskipper",
    "kalu": "kalu garfish",
    "mawul": "mawul eel",
}
FRAME_SPECS = [
    ("ngali", "yaluy", "We two, not you, see", "here"),
    ("ngaliny", "yinyay", "You and I see", "there"),
    ("yubal", "yaluy", "You two see", "here"),
    ("yurra", "yinyay", "You all see", "there"),
    ("ngana", "yaluy", "We see", "here"),
]

DENY_KUKU = {
    "ngayu", "yundu", "nyulu", "yulu", "bula", "jana", "nganjin", "iana",
    "ngalingan", "ngalinyan", "yubalan", "ngalininy", "ngalinyiny", "yubaliny",
    "ngalinka", "ngalinyanka", "yubalanka", "ngalinda", "ngalinyanda", "yubalanda",
    "ngalindamuny", "ngalinyandamuny", "yubalandamuny", "ngalinji", "ngalinyanji", "yubalanji",
    "ngalinga", "ngalinyanga", "yubalanga", "yurrangan", "yurraniny", "yurranka", "yurranda",
    "yurrandamuny", "yurranji", "yurranga", "nganangan", "ngananiny", "ngananka", "ngananda",
    "nganandamuny", "ngananji", "ngananga",
    "yidi", "yidilnyul", "dalku", "kanyaji", "mujarrka", "julaji", "yalnganji", "kudi",
    "bayi", "dalmbal", "walarrji", "bayilbayil", "kijukum",
    "yalay", "yalungku", "yaluyngku", "yinyangka", "yinyayngka", "yalamuny", "yinyamuny",
    "nyajin", "nyajiny", "nyaji-ny", "nyaji-nka", "nyaji-l-nyaji", "milka", "baykal", "jalngkay",
}
DENY_ENGLISH = (
    "species", "jungle", "bayi", "rossville", "shipton", "flats", "distribution", "synonym", "dalmbal",
    "yalanji", "nyungkul", "kudi", "place", "stone", "stones", "snake", "story", "site", "between",
    "kangkiji", "kaway", "saltwater", "catfish", "small", "old", "people", "permission", "eat", "eating",
    "food", "taboo", "climb", "climbing", "water", "mangrove", "root", "roots", "tide", "feed", "feeding",
    "long", "deep", "waterhole", "night", "scale", "scales", "smooth", "soft", "body", "strong", "hold",
    "spear", "bottom", "net", "creek", "heavy", "roast", "roasted", "catch", "catching", "swim", "swimming",
    "habitat", "behavior", "event", "camouflage", "shape", "anatomy",
)


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}", "0.86",
    )


ROWS = [
    row(1, "We two, not you, see the kundurr-kundurr crescent perch here.", "Ngali kundurr-kundurr yaluy nyajil.", "ngali kundurr-kundurr yaluy nyajil | 1du.excl.NOM kundurr-kundurr.crescent.perch here see.NPST", "r318_1du_excl_here_low_fish_see_kundurr_kundurr", ["ngali", "kundurr-kundurr", "yaluy", "nyajil"]),
    row(2, "We two, not you, see the kurruba freshwater fish here.", "Ngali kurruba yaluy nyajil.", "ngali kurruba yaluy nyajil | 1du.excl.NOM kurruba.freshwater.fish here see.NPST", "r318_1du_excl_here_low_fish_see_kurruba", ["ngali", "kurruba", "yaluy", "nyajil"]),
    row(3, "We two, not you, see the mangkurr-mangkurr garfish here.", "Ngali mangkurr-mangkurr yaluy nyajil.", "ngali mangkurr-mangkurr yaluy nyajil | 1du.excl.NOM mangkurr-mangkurr.garfish here see.NPST", "r318_1du_excl_here_low_fish_see_mangkurr_mangkurr", ["ngali", "mangkurr-mangkurr", "yaluy", "nyajil"]),
    row(4, "We two, not you, see the murrabal barramundi here.", "Ngali murrabal yaluy nyajil.", "ngali murrabal yaluy nyajil | 1du.excl.NOM murrabal.barramundi here see.NPST", "r318_1du_excl_here_low_fish_see_murrabal", ["ngali", "murrabal", "yaluy", "nyajil"]),
    row(5, "We two, not you, see the ngiwa moray eel here.", "Ngali ngiwa yaluy nyajil.", "ngali ngiwa yaluy nyajil | 1du.excl.NOM ngiwa.moray.eel here see.NPST", "r318_1du_excl_here_low_fish_see_ngiwa", ["ngali", "ngiwa", "yaluy", "nyajil"]),
    row(6, "We two, not you, see the dijarr freshwater perch here.", "Ngali dijarr yaluy nyajil.", "ngali dijarr yaluy nyajil | 1du.excl.NOM dijarr.freshwater.perch here see.NPST", "r318_1du_excl_here_low_fish_see_dijarr", ["ngali", "dijarr", "yaluy", "nyajil"]),
    row(7, "We two, not you, see the dukul-barangkal flathead fish here.", "Ngali dukul-barangkal yaluy nyajil.", "ngali dukul-barangkal yaluy nyajil | 1du.excl.NOM dukul-barangkal.flathead.fish here see.NPST", "r318_1du_excl_here_low_fish_see_dukul_barangkal", ["ngali", "dukul-barangkal", "yaluy", "nyajil"]),
    row(8, "We two, not you, see the jalil-jalil mudskipper here.", "Ngali jalil-jalil yaluy nyajil.", "ngali jalil-jalil yaluy nyajil | 1du.excl.NOM jalil-jalil.mudskipper here see.NPST", "r318_1du_excl_here_low_fish_see_jalil_jalil", ["ngali", "jalil-jalil", "yaluy", "nyajil"]),
    row(9, "We two, not you, see the kalu garfish here.", "Ngali kalu yaluy nyajil.", "ngali kalu yaluy nyajil | 1du.excl.NOM kalu.garfish here see.NPST", "r318_1du_excl_here_low_fish_see_kalu", ["ngali", "kalu", "yaluy", "nyajil"]),
    row(10, "We two, not you, see the mawul eel here.", "Ngali mawul yaluy nyajil.", "ngali mawul yaluy nyajil | 1du.excl.NOM mawul.eel here see.NPST", "r318_1du_excl_here_low_fish_see_mawul", ["ngali", "mawul", "yaluy", "nyajil"]),
    row(11, "You and I see the kundurr-kundurr crescent perch there.", "Ngaliny kundurr-kundurr yinyay nyajil.", "ngaliny kundurr-kundurr yinyay nyajil | 1du.incl.NOM kundurr-kundurr.crescent.perch there see.NPST", "r318_1du_incl_there_low_fish_see_kundurr_kundurr", ["ngaliny", "kundurr-kundurr", "yinyay", "nyajil"]),
    row(12, "You and I see the kurruba freshwater fish there.", "Ngaliny kurruba yinyay nyajil.", "ngaliny kurruba yinyay nyajil | 1du.incl.NOM kurruba.freshwater.fish there see.NPST", "r318_1du_incl_there_low_fish_see_kurruba", ["ngaliny", "kurruba", "yinyay", "nyajil"]),
    row(13, "You and I see the mangkurr-mangkurr garfish there.", "Ngaliny mangkurr-mangkurr yinyay nyajil.", "ngaliny mangkurr-mangkurr yinyay nyajil | 1du.incl.NOM mangkurr-mangkurr.garfish there see.NPST", "r318_1du_incl_there_low_fish_see_mangkurr_mangkurr", ["ngaliny", "mangkurr-mangkurr", "yinyay", "nyajil"]),
    row(14, "You and I see the murrabal barramundi there.", "Ngaliny murrabal yinyay nyajil.", "ngaliny murrabal yinyay nyajil | 1du.incl.NOM murrabal.barramundi there see.NPST", "r318_1du_incl_there_low_fish_see_murrabal", ["ngaliny", "murrabal", "yinyay", "nyajil"]),
    row(15, "You and I see the ngiwa moray eel there.", "Ngaliny ngiwa yinyay nyajil.", "ngaliny ngiwa yinyay nyajil | 1du.incl.NOM ngiwa.moray.eel there see.NPST", "r318_1du_incl_there_low_fish_see_ngiwa", ["ngaliny", "ngiwa", "yinyay", "nyajil"]),
    row(16, "You and I see the dijarr freshwater perch there.", "Ngaliny dijarr yinyay nyajil.", "ngaliny dijarr yinyay nyajil | 1du.incl.NOM dijarr.freshwater.perch there see.NPST", "r318_1du_incl_there_low_fish_see_dijarr", ["ngaliny", "dijarr", "yinyay", "nyajil"]),
    row(17, "You and I see the dukul-barangkal flathead fish there.", "Ngaliny dukul-barangkal yinyay nyajil.", "ngaliny dukul-barangkal yinyay nyajil | 1du.incl.NOM dukul-barangkal.flathead.fish there see.NPST", "r318_1du_incl_there_low_fish_see_dukul_barangkal", ["ngaliny", "dukul-barangkal", "yinyay", "nyajil"]),
    row(18, "You and I see the jalil-jalil mudskipper there.", "Ngaliny jalil-jalil yinyay nyajil.", "ngaliny jalil-jalil yinyay nyajil | 1du.incl.NOM jalil-jalil.mudskipper there see.NPST", "r318_1du_incl_there_low_fish_see_jalil_jalil", ["ngaliny", "jalil-jalil", "yinyay", "nyajil"]),
    row(19, "You and I see the kalu garfish there.", "Ngaliny kalu yinyay nyajil.", "ngaliny kalu yinyay nyajil | 1du.incl.NOM kalu.garfish there see.NPST", "r318_1du_incl_there_low_fish_see_kalu", ["ngaliny", "kalu", "yinyay", "nyajil"]),
    row(20, "You and I see the mawul eel there.", "Ngaliny mawul yinyay nyajil.", "ngaliny mawul yinyay nyajil | 1du.incl.NOM mawul.eel there see.NPST", "r318_1du_incl_there_low_fish_see_mawul", ["ngaliny", "mawul", "yinyay", "nyajil"]),
    row(21, "You two see the kundurr-kundurr crescent perch here.", "Yubal kundurr-kundurr yaluy nyajil.", "yubal kundurr-kundurr yaluy nyajil | 2du.NOM kundurr-kundurr.crescent.perch here see.NPST", "r318_2du_here_low_fish_see_kundurr_kundurr", ["yubal", "kundurr-kundurr", "yaluy", "nyajil"]),
    row(22, "You two see the kurruba freshwater fish here.", "Yubal kurruba yaluy nyajil.", "yubal kurruba yaluy nyajil | 2du.NOM kurruba.freshwater.fish here see.NPST", "r318_2du_here_low_fish_see_kurruba", ["yubal", "kurruba", "yaluy", "nyajil"]),
    row(23, "You two see the mangkurr-mangkurr garfish here.", "Yubal mangkurr-mangkurr yaluy nyajil.", "yubal mangkurr-mangkurr yaluy nyajil | 2du.NOM mangkurr-mangkurr.garfish here see.NPST", "r318_2du_here_low_fish_see_mangkurr_mangkurr", ["yubal", "mangkurr-mangkurr", "yaluy", "nyajil"]),
    row(24, "You two see the murrabal barramundi here.", "Yubal murrabal yaluy nyajil.", "yubal murrabal yaluy nyajil | 2du.NOM murrabal.barramundi here see.NPST", "r318_2du_here_low_fish_see_murrabal", ["yubal", "murrabal", "yaluy", "nyajil"]),
    row(25, "You two see the ngiwa moray eel here.", "Yubal ngiwa yaluy nyajil.", "yubal ngiwa yaluy nyajil | 2du.NOM ngiwa.moray.eel here see.NPST", "r318_2du_here_low_fish_see_ngiwa", ["yubal", "ngiwa", "yaluy", "nyajil"]),
    row(26, "You two see the dijarr freshwater perch here.", "Yubal dijarr yaluy nyajil.", "yubal dijarr yaluy nyajil | 2du.NOM dijarr.freshwater.perch here see.NPST", "r318_2du_here_low_fish_see_dijarr", ["yubal", "dijarr", "yaluy", "nyajil"]),
    row(27, "You two see the dukul-barangkal flathead fish here.", "Yubal dukul-barangkal yaluy nyajil.", "yubal dukul-barangkal yaluy nyajil | 2du.NOM dukul-barangkal.flathead.fish here see.NPST", "r318_2du_here_low_fish_see_dukul_barangkal", ["yubal", "dukul-barangkal", "yaluy", "nyajil"]),
    row(28, "You two see the jalil-jalil mudskipper here.", "Yubal jalil-jalil yaluy nyajil.", "yubal jalil-jalil yaluy nyajil | 2du.NOM jalil-jalil.mudskipper here see.NPST", "r318_2du_here_low_fish_see_jalil_jalil", ["yubal", "jalil-jalil", "yaluy", "nyajil"]),
    row(29, "You two see the kalu garfish here.", "Yubal kalu yaluy nyajil.", "yubal kalu yaluy nyajil | 2du.NOM kalu.garfish here see.NPST", "r318_2du_here_low_fish_see_kalu", ["yubal", "kalu", "yaluy", "nyajil"]),
    row(30, "You two see the mawul eel here.", "Yubal mawul yaluy nyajil.", "yubal mawul yaluy nyajil | 2du.NOM mawul.eel here see.NPST", "r318_2du_here_low_fish_see_mawul", ["yubal", "mawul", "yaluy", "nyajil"]),
    row(31, "You all see the kundurr-kundurr crescent perch there.", "Yurra kundurr-kundurr yinyay nyajil.", "yurra kundurr-kundurr yinyay nyajil | 2pl.NOM kundurr-kundurr.crescent.perch there see.NPST", "r318_2pl_there_low_fish_see_kundurr_kundurr", ["yurra", "kundurr-kundurr", "yinyay", "nyajil"]),
    row(32, "You all see the kurruba freshwater fish there.", "Yurra kurruba yinyay nyajil.", "yurra kurruba yinyay nyajil | 2pl.NOM kurruba.freshwater.fish there see.NPST", "r318_2pl_there_low_fish_see_kurruba", ["yurra", "kurruba", "yinyay", "nyajil"]),
    row(33, "You all see the mangkurr-mangkurr garfish there.", "Yurra mangkurr-mangkurr yinyay nyajil.", "yurra mangkurr-mangkurr yinyay nyajil | 2pl.NOM mangkurr-mangkurr.garfish there see.NPST", "r318_2pl_there_low_fish_see_mangkurr_mangkurr", ["yurra", "mangkurr-mangkurr", "yinyay", "nyajil"]),
    row(34, "You all see the murrabal barramundi there.", "Yurra murrabal yinyay nyajil.", "yurra murrabal yinyay nyajil | 2pl.NOM murrabal.barramundi there see.NPST", "r318_2pl_there_low_fish_see_murrabal", ["yurra", "murrabal", "yinyay", "nyajil"]),
    row(35, "You all see the ngiwa moray eel there.", "Yurra ngiwa yinyay nyajil.", "yurra ngiwa yinyay nyajil | 2pl.NOM ngiwa.moray.eel there see.NPST", "r318_2pl_there_low_fish_see_ngiwa", ["yurra", "ngiwa", "yinyay", "nyajil"]),
    row(36, "You all see the dijarr freshwater perch there.", "Yurra dijarr yinyay nyajil.", "yurra dijarr yinyay nyajil | 2pl.NOM dijarr.freshwater.perch there see.NPST", "r318_2pl_there_low_fish_see_dijarr", ["yurra", "dijarr", "yinyay", "nyajil"]),
    row(37, "You all see the dukul-barangkal flathead fish there.", "Yurra dukul-barangkal yinyay nyajil.", "yurra dukul-barangkal yinyay nyajil | 2pl.NOM dukul-barangkal.flathead.fish there see.NPST", "r318_2pl_there_low_fish_see_dukul_barangkal", ["yurra", "dukul-barangkal", "yinyay", "nyajil"]),
    row(38, "You all see the jalil-jalil mudskipper there.", "Yurra jalil-jalil yinyay nyajil.", "yurra jalil-jalil yinyay nyajil | 2pl.NOM jalil-jalil.mudskipper there see.NPST", "r318_2pl_there_low_fish_see_jalil_jalil", ["yurra", "jalil-jalil", "yinyay", "nyajil"]),
    row(39, "You all see the kalu garfish there.", "Yurra kalu yinyay nyajil.", "yurra kalu yinyay nyajil | 2pl.NOM kalu.garfish there see.NPST", "r318_2pl_there_low_fish_see_kalu", ["yurra", "kalu", "yinyay", "nyajil"]),
    row(40, "You all see the mawul eel there.", "Yurra mawul yinyay nyajil.", "yurra mawul yinyay nyajil | 2pl.NOM mawul.eel there see.NPST", "r318_2pl_there_low_fish_see_mawul", ["yurra", "mawul", "yinyay", "nyajil"]),
    row(41, "We see the kundurr-kundurr crescent perch here.", "Ngana kundurr-kundurr yaluy nyajil.", "ngana kundurr-kundurr yaluy nyajil | 1pl.incl.NOM kundurr-kundurr.crescent.perch here see.NPST", "r318_1pl_incl_here_low_fish_see_kundurr_kundurr", ["ngana", "kundurr-kundurr", "yaluy", "nyajil"]),
    row(42, "We see the kurruba freshwater fish here.", "Ngana kurruba yaluy nyajil.", "ngana kurruba yaluy nyajil | 1pl.incl.NOM kurruba.freshwater.fish here see.NPST", "r318_1pl_incl_here_low_fish_see_kurruba", ["ngana", "kurruba", "yaluy", "nyajil"]),
    row(43, "We see the mangkurr-mangkurr garfish here.", "Ngana mangkurr-mangkurr yaluy nyajil.", "ngana mangkurr-mangkurr yaluy nyajil | 1pl.incl.NOM mangkurr-mangkurr.garfish here see.NPST", "r318_1pl_incl_here_low_fish_see_mangkurr_mangkurr", ["ngana", "mangkurr-mangkurr", "yaluy", "nyajil"]),
    row(44, "We see the murrabal barramundi here.", "Ngana murrabal yaluy nyajil.", "ngana murrabal yaluy nyajil | 1pl.incl.NOM murrabal.barramundi here see.NPST", "r318_1pl_incl_here_low_fish_see_murrabal", ["ngana", "murrabal", "yaluy", "nyajil"]),
    row(45, "We see the ngiwa moray eel here.", "Ngana ngiwa yaluy nyajil.", "ngana ngiwa yaluy nyajil | 1pl.incl.NOM ngiwa.moray.eel here see.NPST", "r318_1pl_incl_here_low_fish_see_ngiwa", ["ngana", "ngiwa", "yaluy", "nyajil"]),
    row(46, "We see the dijarr freshwater perch here.", "Ngana dijarr yaluy nyajil.", "ngana dijarr yaluy nyajil | 1pl.incl.NOM dijarr.freshwater.perch here see.NPST", "r318_1pl_incl_here_low_fish_see_dijarr", ["ngana", "dijarr", "yaluy", "nyajil"]),
    row(47, "We see the dukul-barangkal flathead fish here.", "Ngana dukul-barangkal yaluy nyajil.", "ngana dukul-barangkal yaluy nyajil | 1pl.incl.NOM dukul-barangkal.flathead.fish here see.NPST", "r318_1pl_incl_here_low_fish_see_dukul_barangkal", ["ngana", "dukul-barangkal", "yaluy", "nyajil"]),
    row(48, "We see the jalil-jalil mudskipper here.", "Ngana jalil-jalil yaluy nyajil.", "ngana jalil-jalil yaluy nyajil | 1pl.incl.NOM jalil-jalil.mudskipper here see.NPST", "r318_1pl_incl_here_low_fish_see_jalil_jalil", ["ngana", "jalil-jalil", "yaluy", "nyajil"]),
    row(49, "We see the kalu garfish here.", "Ngana kalu yaluy nyajil.", "ngana kalu yaluy nyajil | 1pl.incl.NOM kalu.garfish here see.NPST", "r318_1pl_incl_here_low_fish_see_kalu", ["ngana", "kalu", "yaluy", "nyajil"]),
    row(50, "We see the mawul eel here.", "Ngana mawul yaluy nyajil.", "ngana mawul yaluy nyajil | 1pl.incl.NOM mawul.eel here see.NPST", "r318_1pl_incl_here_low_fish_see_mawul", ["ngana", "mawul", "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 = FRAME_SPECS[band]
        expected_kuku = f"{pronoun.capitalize()} {target} {demo} nyajil."
        expected_english = f"{prefix} the {TARGET_LABELS[target]} {location}."
        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 expected {expected_kuku!r}, got {kuku!r}")
        if english != expected_english:
            issues.append(f"{seq}: English mismatch expected {expected_english!r}, got {english!r}")
        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("r318_"):
            issues.append(f"{seq}: frame not r318 {frame}")
    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")
    collisions = []
    for _seq, _english, kuku, *_rest in ROWS:
        hit = 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 hit:
            collisions.append((kuku, hit))
    if collisions:
        raise SystemExit(f"duplicate preflight failed: {collisions}")
    target_counts = count_words(db, TARGET_ORDER)
    support_counts = count_words(db, ["ngali", "ngaliny", "yubal", "yurra", "ngana", "yaluy", "yinyay", "nyajil"])
    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 NONPAST PERCEPTION SWEEP AFTER RULE 317 (Rule 318). 50 under-review "
        "rows over five zero-use, three one-use, one two-use, and one three-use direct-dictionary fish heads: "
        "kundurr-kundurr, kurruba, mangkurr-mangkurr, murrabal, ngiwa, dijarr, dukul-barangkal, jalil-jalil, "
        "kalu, and mawul. SUPPORT: bare nominative ngali, ngaliny, yubal, yurra, ngana, Yalanji yaluy/yinyay, "
        "and dictionary-attested nonpast nyajil. Exact dictionary reduplicated/compound headwords are treated as "
        "indivisible lexemes. Only bare visible-fish perception is opened; dialect alternatives, homographs, story/"
        "place, habitat, capture, food/taboo, behavior, source-prose, case, new compounds/reduplication, past/"
        "purposive/reduplicated perception, and support inflection remain closed."
    )
    cur = db.execute(
        "INSERT INTO batches(label,cheatsheet_version,guide_version,notes,created_at) VALUES(?,?,?,?,?)",
        (LABEL, "Rule 318 under review", "operator-guide-2026-07-10", notes, NOW),
    )
    batch_id = 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(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
        [
            (batch_id, 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 direct dictionary fish entries, checked every target against Patz (only ngiwa occurs, as ngiwa-nda salt-water eel), and reread Patz pronoun, demonstrative, nonpast, sensory-perception A/O, plus dictionary running-form nyajil evidence before authoring Rule 318.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="low-coverage-fish-nonsingular-nonpast-scope", actor="codex", detail="Selected five zero-use, three one-use, one two-use, and one three-use lint-safe fish nouns for bare non-singular nonpast visual perception. Excluded Nyungkul-only candidates and linter-invalid spellings; treated three reduplicated and one compound dictionary heads as indivisible lexemes; closed dialect, homograph, story/place, habitat, capture, food/taboo, behavior, case, new word-formation, tense, and support-inflection semantics.", 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="Final 50 Rule 318 fish non-singular nonpast surfaces returned no accepted, revised, or under-review 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 Kuku/English contracts, one selected fish head each, bare non-singular pronouns and Yalanji demonstratives, final nyajil, no loans, no denied forms, and no source-prose/prior-row drift.", command="python3 -m py_compile batch_scripts/bank_360.py && python3 -c \"import sys;sys.path.insert(0,'batch_scripts');import bank_360;print(bank_360.scan_static())\"", output_excerpt="issues 0", artifact_path="batch_scripts/bank_360.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="codex", detail=f"Banked 50 Rule 318 rows as under_review. Verified remains {verified_before}; Kuku words remain {words_before}.", command="python3 batch_scripts/bank_360.py", output_excerpt=f"banked batch-360: 50 under_review; verified_before={verified_before}; kuku_words_before={words_before}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit()
    print("banked batch-360: 50 rows under_review")
    return 0


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