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

TARGET_EVIDENCE = {
    "jalbil": "Dictionary yaml lines 7374-7386 give jalbil a primary noun sense 'black lizard' plus mythological-person/story material involving Snapper Island. Rule 319 selects visible jalbil-lizard reference only and leaves colour, size, mythology, personification, island splitting, cooking story, and event propositions closed.",
    "kalkarrumbarr": "Dictionary yaml lines 12679-12689 give kalkarrumbarr as a species of large lizard that figures in a legend. Rule 319 selects visible kalkarrumbarr-lizard reference only and leaves size, measurement, legend, role, behavior, and event propositions closed.",
    "kurmba-kurmba": "Dictionary yaml lines 16154-16169 give full-reduplicated kurmba-kurmba 'slippery lizard' plus a mythological-person and kin/marriage story. Rule 319 admits the whole dictionary head as visible lizard reference only and leaves productive reduplication, slipperiness, personhood, kinship, marriage, desire, place, story, and event propositions closed.",
    "jimalili": "Dictionary yaml lines 9284-9294 give jimalili 'mountain lizard' and prose that it taught people to use the firestick. Rule 319 selects visible jimalili-lizard reference only and leaves mountain habitat, teaching, people, firestick, etymology, cultural story, and event propositions closed.",
    "yuray": "Dictionary yaml lines 31016-31033 give two concordant noun entries yuray 'sea snake' / species of snake. Rule 319 selects visible yuray-snake reference only and leaves sea habitat, swimming, danger, touching, food, behavior, and event propositions closed.",
    "bakay": "Dictionary yaml lines 635-653 give two concordant water-snake entries, with source colour and size descriptions. Rule 319 selects visible bakay-snake reference only and leaves water habitat, size, colour, swimming, fish-seeking, lagoon/creek, danger, and event propositions closed.",
    "kungkun": "Dictionary yaml lines 15748-15768 give kungkun as carpet snake / North Queensland python and, in a separate entry, brown tree snake. Rule 319 selects the shared visible snake reading only and leaves species resolution, colour, tree/habitat, geography, danger, eating/food, behavior, and event propositions closed.",
    "bilbil-bilbil": "Dictionary yaml lines 2529-2542 give full-reduplicated bilbil-bilbil 'gecko'. Rule 319 admits the whole dictionary head as visible gecko reference only and does not derive productive reduplication or inherit size, bark/shelter, night, sound, feeding, insect, friendship, habitat, or behavior from earlier rows.",
    "bajalji": "Dictionary yaml lines 387-409 give bajalji a rock-python entry with distribution and lore, plus a poisonous-snake entry tied to Rossville/Shipton's Fault. Rule 319 selects the directly attested python reading only and leaves poison, distribution, place, colour/head, chasing/baldness/hat lore, danger, hunting, teaching, habitat, food, and event propositions closed.",
    "jabil": "Dictionary yaml lines 6929-6951 separate transitive verb jabil 'kick' from homophonous noun jabil 'scrub lizard'. Rule 319 selects the noun's visible lizard reading only and leaves the kick verb, scrub habitat, catching, warmth/rock/day, release, prior-row behavior, and event propositions closed. Token coverage includes four verb-sense rows and one earlier noun-sense row, so sense debt is greater than the raw token count suggests.",
}

SUPPORT_EVIDENCE = (
    "Patz pronoun table lines 2577-2586 sources bare nominatives ngayu, yundu, nyulu, bula, and jana; "
    "demonstrative lines 2834-2847 source Yalanji yaluy 'here' and yinyay 'there'. Patz examples at lines 2023 "
    "and 2568-2571 give nyaji-ny 'see-PAST', lines 3160-3162 identify past -ny, and lines 4256-4265 license "
    "nominative pronoun A with bare absolutive O for sensory perception. Dictionary usage lines 23882-23883 and "
    "23975-23976 independently attest running-form nyajin in complete visual-perception clauses. Rule 319 uses "
    "only bare support forms and dictionary-attested nyajin past visual perception."
)

TARGET_ORDER = [
    "jalbil", "kalkarrumbarr", "kurmba-kurmba", "jimalili", "yuray",
    "bakay", "kungkun", "bilbil-bilbil", "bajalji", "jabil",
]
TARGET_LABELS = {
    "jalbil": "jalbil lizard",
    "kalkarrumbarr": "kalkarrumbarr lizard",
    "kurmba-kurmba": "kurmba-kurmba lizard",
    "jimalili": "jimalili lizard",
    "yuray": "yuray snake",
    "bakay": "bakay snake",
    "kungkun": "kungkun snake",
    "bilbil-bilbil": "bilbil-bilbil gecko",
    "bajalji": "bajalji python",
    "jabil": "jabil lizard",
}
FRAME_SPECS = [
    ("ngayu", "yinyay", "I saw", "there"),
    ("yundu", "yaluy", "You saw", "here"),
    ("nyulu", "yinyay", "He saw", "there"),
    ("bula", "yaluy", "The two of them saw", "here"),
    ("jana", "yinyay", "They saw", "there"),
]

DENY_KUKU = {
    "nganya", "yununy", "nyunguny", "yununiny", "nyunguniny", "ngaykunku", "yununku", "nyungunku",
    "ngaykundu", "yunundu", "nyungundu", "ngaykundumuny", "yunundumuny", "nyungundumuny",
    "ngaykunji", "yununji", "nyungunji", "ngayku", "yunu", "nyunju", "yulu", "iana",
    "ngali", "ngaliny", "yubal", "yurra", "ngana", "nganjin",
    "jarba", "kalkamuku", "bajalji-nga", "jabi-nya", "jabil-jabil",
    "yalay", "yalungku", "yaluyngku", "yinyangka", "yinyayngka", "yalamuny", "yinyamuny",
    "nyajil", "nyaji-l", "nyaji-nka", "nyaji-l-nyaji", "milka", "baykal", "jalngkay",
}
DENY_ENGLISH = (
    "black", "greenish", "brown", "yellow", "white", "short", "long", "inch", "inches", "foot", "feet",
    "large", "size", "mountain", "sea", "water", "tree", "scrub", "slippery", "rock", "carpet",
    "north", "queensland", "species", "myth", "mythological", "legend", "story", "snapper", "island",
    "mainland", "split", "splitting", "cook", "cooking", "teach", "teaching", "taught", "people",
    "firestick", "husband", "wife", "sister", "marriage", "desire", "bloomfield", "helenvale", "rossville",
    "shipton", "fault", "head", "chase", "chasing", "bald", "hat", "poison", "poisonous", "danger",
    "dangerous", "kick", "kicked", "kicking", "swim", "swimming", "fish", "lagoon", "creek", "touch",
    "eating", "food", "catch", "caught", "warm", "day", "release", "bark", "shelter", "night", "sound",
    "feeding", "insect", "friend", "friendship", "hunt", "hunting", "habitat", "behavior", "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}", "0.86",
    )


ROWS = [
    row(1, "I saw the jalbil lizard there.", "Ngayu jalbil yinyay nyajin.", "ngayu jalbil yinyay nyajin | 1sg.NOM jalbil.lizard there see.PST", "r319_1sg_there_low_reptile_saw_jalbil", ["ngayu", "jalbil", "yinyay", "nyajin"]),
    row(2, "I saw the kalkarrumbarr lizard there.", "Ngayu kalkarrumbarr yinyay nyajin.", "ngayu kalkarrumbarr yinyay nyajin | 1sg.NOM kalkarrumbarr.lizard there see.PST", "r319_1sg_there_low_reptile_saw_kalkarrumbarr", ["ngayu", "kalkarrumbarr", "yinyay", "nyajin"]),
    row(3, "I saw the kurmba-kurmba lizard there.", "Ngayu kurmba-kurmba yinyay nyajin.", "ngayu kurmba-kurmba yinyay nyajin | 1sg.NOM kurmba-kurmba.lizard there see.PST", "r319_1sg_there_low_reptile_saw_kurmba_kurmba", ["ngayu", "kurmba-kurmba", "yinyay", "nyajin"]),
    row(4, "I saw the jimalili lizard there.", "Ngayu jimalili yinyay nyajin.", "ngayu jimalili yinyay nyajin | 1sg.NOM jimalili.lizard there see.PST", "r319_1sg_there_low_reptile_saw_jimalili", ["ngayu", "jimalili", "yinyay", "nyajin"]),
    row(5, "I saw the yuray snake there.", "Ngayu yuray yinyay nyajin.", "ngayu yuray yinyay nyajin | 1sg.NOM yuray.snake there see.PST", "r319_1sg_there_low_reptile_saw_yuray", ["ngayu", "yuray", "yinyay", "nyajin"]),
    row(6, "I saw the bakay snake there.", "Ngayu bakay yinyay nyajin.", "ngayu bakay yinyay nyajin | 1sg.NOM bakay.snake there see.PST", "r319_1sg_there_low_reptile_saw_bakay", ["ngayu", "bakay", "yinyay", "nyajin"]),
    row(7, "I saw the kungkun snake there.", "Ngayu kungkun yinyay nyajin.", "ngayu kungkun yinyay nyajin | 1sg.NOM kungkun.snake there see.PST", "r319_1sg_there_low_reptile_saw_kungkun", ["ngayu", "kungkun", "yinyay", "nyajin"]),
    row(8, "I saw the bilbil-bilbil gecko there.", "Ngayu bilbil-bilbil yinyay nyajin.", "ngayu bilbil-bilbil yinyay nyajin | 1sg.NOM bilbil-bilbil.gecko there see.PST", "r319_1sg_there_low_reptile_saw_bilbil_bilbil", ["ngayu", "bilbil-bilbil", "yinyay", "nyajin"]),
    row(9, "I saw the bajalji python there.", "Ngayu bajalji yinyay nyajin.", "ngayu bajalji yinyay nyajin | 1sg.NOM bajalji.python there see.PST", "r319_1sg_there_low_reptile_saw_bajalji", ["ngayu", "bajalji", "yinyay", "nyajin"]),
    row(10, "I saw the jabil lizard there.", "Ngayu jabil yinyay nyajin.", "ngayu jabil yinyay nyajin | 1sg.NOM jabil.lizard there see.PST", "r319_1sg_there_low_reptile_saw_jabil", ["ngayu", "jabil", "yinyay", "nyajin"]),
    row(11, "You saw the jalbil lizard here.", "Yundu jalbil yaluy nyajin.", "yundu jalbil yaluy nyajin | 2sg.NOM jalbil.lizard here see.PST", "r319_2sg_here_low_reptile_saw_jalbil", ["yundu", "jalbil", "yaluy", "nyajin"]),
    row(12, "You saw the kalkarrumbarr lizard here.", "Yundu kalkarrumbarr yaluy nyajin.", "yundu kalkarrumbarr yaluy nyajin | 2sg.NOM kalkarrumbarr.lizard here see.PST", "r319_2sg_here_low_reptile_saw_kalkarrumbarr", ["yundu", "kalkarrumbarr", "yaluy", "nyajin"]),
    row(13, "You saw the kurmba-kurmba lizard here.", "Yundu kurmba-kurmba yaluy nyajin.", "yundu kurmba-kurmba yaluy nyajin | 2sg.NOM kurmba-kurmba.lizard here see.PST", "r319_2sg_here_low_reptile_saw_kurmba_kurmba", ["yundu", "kurmba-kurmba", "yaluy", "nyajin"]),
    row(14, "You saw the jimalili lizard here.", "Yundu jimalili yaluy nyajin.", "yundu jimalili yaluy nyajin | 2sg.NOM jimalili.lizard here see.PST", "r319_2sg_here_low_reptile_saw_jimalili", ["yundu", "jimalili", "yaluy", "nyajin"]),
    row(15, "You saw the yuray snake here.", "Yundu yuray yaluy nyajin.", "yundu yuray yaluy nyajin | 2sg.NOM yuray.snake here see.PST", "r319_2sg_here_low_reptile_saw_yuray", ["yundu", "yuray", "yaluy", "nyajin"]),
    row(16, "You saw the bakay snake here.", "Yundu bakay yaluy nyajin.", "yundu bakay yaluy nyajin | 2sg.NOM bakay.snake here see.PST", "r319_2sg_here_low_reptile_saw_bakay", ["yundu", "bakay", "yaluy", "nyajin"]),
    row(17, "You saw the kungkun snake here.", "Yundu kungkun yaluy nyajin.", "yundu kungkun yaluy nyajin | 2sg.NOM kungkun.snake here see.PST", "r319_2sg_here_low_reptile_saw_kungkun", ["yundu", "kungkun", "yaluy", "nyajin"]),
    row(18, "You saw the bilbil-bilbil gecko here.", "Yundu bilbil-bilbil yaluy nyajin.", "yundu bilbil-bilbil yaluy nyajin | 2sg.NOM bilbil-bilbil.gecko here see.PST", "r319_2sg_here_low_reptile_saw_bilbil_bilbil", ["yundu", "bilbil-bilbil", "yaluy", "nyajin"]),
    row(19, "You saw the bajalji python here.", "Yundu bajalji yaluy nyajin.", "yundu bajalji yaluy nyajin | 2sg.NOM bajalji.python here see.PST", "r319_2sg_here_low_reptile_saw_bajalji", ["yundu", "bajalji", "yaluy", "nyajin"]),
    row(20, "You saw the jabil lizard here.", "Yundu jabil yaluy nyajin.", "yundu jabil yaluy nyajin | 2sg.NOM jabil.lizard here see.PST", "r319_2sg_here_low_reptile_saw_jabil", ["yundu", "jabil", "yaluy", "nyajin"]),
    row(21, "He saw the jalbil lizard there.", "Nyulu jalbil yinyay nyajin.", "nyulu jalbil yinyay nyajin | 3sg.NOM jalbil.lizard there see.PST", "r319_3sg_there_low_reptile_saw_jalbil", ["nyulu", "jalbil", "yinyay", "nyajin"]),
    row(22, "He saw the kalkarrumbarr lizard there.", "Nyulu kalkarrumbarr yinyay nyajin.", "nyulu kalkarrumbarr yinyay nyajin | 3sg.NOM kalkarrumbarr.lizard there see.PST", "r319_3sg_there_low_reptile_saw_kalkarrumbarr", ["nyulu", "kalkarrumbarr", "yinyay", "nyajin"]),
    row(23, "He saw the kurmba-kurmba lizard there.", "Nyulu kurmba-kurmba yinyay nyajin.", "nyulu kurmba-kurmba yinyay nyajin | 3sg.NOM kurmba-kurmba.lizard there see.PST", "r319_3sg_there_low_reptile_saw_kurmba_kurmba", ["nyulu", "kurmba-kurmba", "yinyay", "nyajin"]),
    row(24, "He saw the jimalili lizard there.", "Nyulu jimalili yinyay nyajin.", "nyulu jimalili yinyay nyajin | 3sg.NOM jimalili.lizard there see.PST", "r319_3sg_there_low_reptile_saw_jimalili", ["nyulu", "jimalili", "yinyay", "nyajin"]),
    row(25, "He saw the yuray snake there.", "Nyulu yuray yinyay nyajin.", "nyulu yuray yinyay nyajin | 3sg.NOM yuray.snake there see.PST", "r319_3sg_there_low_reptile_saw_yuray", ["nyulu", "yuray", "yinyay", "nyajin"]),
    row(26, "He saw the bakay snake there.", "Nyulu bakay yinyay nyajin.", "nyulu bakay yinyay nyajin | 3sg.NOM bakay.snake there see.PST", "r319_3sg_there_low_reptile_saw_bakay", ["nyulu", "bakay", "yinyay", "nyajin"]),
    row(27, "He saw the kungkun snake there.", "Nyulu kungkun yinyay nyajin.", "nyulu kungkun yinyay nyajin | 3sg.NOM kungkun.snake there see.PST", "r319_3sg_there_low_reptile_saw_kungkun", ["nyulu", "kungkun", "yinyay", "nyajin"]),
    row(28, "He saw the bilbil-bilbil gecko there.", "Nyulu bilbil-bilbil yinyay nyajin.", "nyulu bilbil-bilbil yinyay nyajin | 3sg.NOM bilbil-bilbil.gecko there see.PST", "r319_3sg_there_low_reptile_saw_bilbil_bilbil", ["nyulu", "bilbil-bilbil", "yinyay", "nyajin"]),
    row(29, "He saw the bajalji python there.", "Nyulu bajalji yinyay nyajin.", "nyulu bajalji yinyay nyajin | 3sg.NOM bajalji.python there see.PST", "r319_3sg_there_low_reptile_saw_bajalji", ["nyulu", "bajalji", "yinyay", "nyajin"]),
    row(30, "He saw the jabil lizard there.", "Nyulu jabil yinyay nyajin.", "nyulu jabil yinyay nyajin | 3sg.NOM jabil.lizard there see.PST", "r319_3sg_there_low_reptile_saw_jabil", ["nyulu", "jabil", "yinyay", "nyajin"]),
    row(31, "The two of them saw the jalbil lizard here.", "Bula jalbil yaluy nyajin.", "bula jalbil yaluy nyajin | 3du.NOM jalbil.lizard here see.PST", "r319_3du_here_low_reptile_saw_jalbil", ["bula", "jalbil", "yaluy", "nyajin"]),
    row(32, "The two of them saw the kalkarrumbarr lizard here.", "Bula kalkarrumbarr yaluy nyajin.", "bula kalkarrumbarr yaluy nyajin | 3du.NOM kalkarrumbarr.lizard here see.PST", "r319_3du_here_low_reptile_saw_kalkarrumbarr", ["bula", "kalkarrumbarr", "yaluy", "nyajin"]),
    row(33, "The two of them saw the kurmba-kurmba lizard here.", "Bula kurmba-kurmba yaluy nyajin.", "bula kurmba-kurmba yaluy nyajin | 3du.NOM kurmba-kurmba.lizard here see.PST", "r319_3du_here_low_reptile_saw_kurmba_kurmba", ["bula", "kurmba-kurmba", "yaluy", "nyajin"]),
    row(34, "The two of them saw the jimalili lizard here.", "Bula jimalili yaluy nyajin.", "bula jimalili yaluy nyajin | 3du.NOM jimalili.lizard here see.PST", "r319_3du_here_low_reptile_saw_jimalili", ["bula", "jimalili", "yaluy", "nyajin"]),
    row(35, "The two of them saw the yuray snake here.", "Bula yuray yaluy nyajin.", "bula yuray yaluy nyajin | 3du.NOM yuray.snake here see.PST", "r319_3du_here_low_reptile_saw_yuray", ["bula", "yuray", "yaluy", "nyajin"]),
    row(36, "The two of them saw the bakay snake here.", "Bula bakay yaluy nyajin.", "bula bakay yaluy nyajin | 3du.NOM bakay.snake here see.PST", "r319_3du_here_low_reptile_saw_bakay", ["bula", "bakay", "yaluy", "nyajin"]),
    row(37, "The two of them saw the kungkun snake here.", "Bula kungkun yaluy nyajin.", "bula kungkun yaluy nyajin | 3du.NOM kungkun.snake here see.PST", "r319_3du_here_low_reptile_saw_kungkun", ["bula", "kungkun", "yaluy", "nyajin"]),
    row(38, "The two of them saw the bilbil-bilbil gecko here.", "Bula bilbil-bilbil yaluy nyajin.", "bula bilbil-bilbil yaluy nyajin | 3du.NOM bilbil-bilbil.gecko here see.PST", "r319_3du_here_low_reptile_saw_bilbil_bilbil", ["bula", "bilbil-bilbil", "yaluy", "nyajin"]),
    row(39, "The two of them saw the bajalji python here.", "Bula bajalji yaluy nyajin.", "bula bajalji yaluy nyajin | 3du.NOM bajalji.python here see.PST", "r319_3du_here_low_reptile_saw_bajalji", ["bula", "bajalji", "yaluy", "nyajin"]),
    row(40, "The two of them saw the jabil lizard here.", "Bula jabil yaluy nyajin.", "bula jabil yaluy nyajin | 3du.NOM jabil.lizard here see.PST", "r319_3du_here_low_reptile_saw_jabil", ["bula", "jabil", "yaluy", "nyajin"]),
    row(41, "They saw the jalbil lizard there.", "Jana jalbil yinyay nyajin.", "jana jalbil yinyay nyajin | 3pl.NOM jalbil.lizard there see.PST", "r319_3pl_there_low_reptile_saw_jalbil", ["jana", "jalbil", "yinyay", "nyajin"]),
    row(42, "They saw the kalkarrumbarr lizard there.", "Jana kalkarrumbarr yinyay nyajin.", "jana kalkarrumbarr yinyay nyajin | 3pl.NOM kalkarrumbarr.lizard there see.PST", "r319_3pl_there_low_reptile_saw_kalkarrumbarr", ["jana", "kalkarrumbarr", "yinyay", "nyajin"]),
    row(43, "They saw the kurmba-kurmba lizard there.", "Jana kurmba-kurmba yinyay nyajin.", "jana kurmba-kurmba yinyay nyajin | 3pl.NOM kurmba-kurmba.lizard there see.PST", "r319_3pl_there_low_reptile_saw_kurmba_kurmba", ["jana", "kurmba-kurmba", "yinyay", "nyajin"]),
    row(44, "They saw the jimalili lizard there.", "Jana jimalili yinyay nyajin.", "jana jimalili yinyay nyajin | 3pl.NOM jimalili.lizard there see.PST", "r319_3pl_there_low_reptile_saw_jimalili", ["jana", "jimalili", "yinyay", "nyajin"]),
    row(45, "They saw the yuray snake there.", "Jana yuray yinyay nyajin.", "jana yuray yinyay nyajin | 3pl.NOM yuray.snake there see.PST", "r319_3pl_there_low_reptile_saw_yuray", ["jana", "yuray", "yinyay", "nyajin"]),
    row(46, "They saw the bakay snake there.", "Jana bakay yinyay nyajin.", "jana bakay yinyay nyajin | 3pl.NOM bakay.snake there see.PST", "r319_3pl_there_low_reptile_saw_bakay", ["jana", "bakay", "yinyay", "nyajin"]),
    row(47, "They saw the kungkun snake there.", "Jana kungkun yinyay nyajin.", "jana kungkun yinyay nyajin | 3pl.NOM kungkun.snake there see.PST", "r319_3pl_there_low_reptile_saw_kungkun", ["jana", "kungkun", "yinyay", "nyajin"]),
    row(48, "They saw the bilbil-bilbil gecko there.", "Jana bilbil-bilbil yinyay nyajin.", "jana bilbil-bilbil yinyay nyajin | 3pl.NOM bilbil-bilbil.gecko there see.PST", "r319_3pl_there_low_reptile_saw_bilbil_bilbil", ["jana", "bilbil-bilbil", "yinyay", "nyajin"]),
    row(49, "They saw the bajalji python there.", "Jana bajalji yinyay nyajin.", "jana bajalji yinyay nyajin | 3pl.NOM bajalji.python there see.PST", "r319_3pl_there_low_reptile_saw_bajalji", ["jana", "bajalji", "yinyay", "nyajin"]),
    row(50, "They saw the jabil lizard there.", "Jana jabil yinyay nyajin.", "jana jabil yinyay nyajin | 3pl.NOM jabil.lizard there see.PST", "r319_3pl_there_low_reptile_saw_jabil", ["jana", "jabil", "yinyay", "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 = FRAME_SPECS[band]
        expected_kuku = f"{pronoun.capitalize()} {target} {demo} nyajin."
        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, "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("r319_"):
            issues.append(f"{seq}: frame not r319 {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, ["ngayu", "yundu", "nyulu", "bula", "jana", "yaluy", "yinyay", "nyajin"])
    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 REPTILE SINGULAR/THIRD-PERSON PAST PERCEPTION SWEEP AFTER RULE 318 (Rule 319). 50 "
        "under-review rows over three zero-use, two one-use, two two-use, one three-use, one four-use, and one "
        "five-use direct-dictionary reptile heads: jalbil, kalkarrumbarr, kurmba-kurmba, jimalili, yuray, bakay, "
        "kungkun, bilbil-bilbil, bajalji, and jabil. SUPPORT: bare nominative ngayu, yundu, nyulu, bula, jana, "
        "Yalanji yaluy/yinyay, and dictionary-attested past nyajin. Basic creature labels suppress source colour/"
        "habitat properties; bilbil-bilbil is an indivisible dictionary reduplication; noun jabil is separated from "
        "homophonous 'kick'. No mythology/story, size/colour/habitat, species ambiguity, danger/poison, behavior, "
        "prior-row proposition, case, new word formation, nonpast/purposive/reduplicated perception, or support "
        "inflection is opened."
    )
    cur = db.execute(
        "INSERT INTO batches(label,cheatsheet_version,guide_version,notes,created_at) VALUES(?,?,?,?,?)",
        (LABEL, "Rule 319 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 reptile entries, checked every target against Patz (none occurs as a lexical target), and reread Patz pronoun, demonstrative, past, sensory-perception A/O, plus dictionary running-form nyajin evidence before authoring Rule 319.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="low-coverage-reptile-singular-third-past-scope", actor="codex", detail="Selected ten zero-to-five-use lint-safe reptile nouns for bare singular/third-person past visual perception. Reduced English to basic creature labels; treated bilbil-bilbil as an indivisible dictionary head and noun jabil separately from the kick homograph; closed mythology, story, colour, size, habitat, species ambiguity, poison/danger, 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}. Jabil's five token rows comprise four verb-sense uses and one noun-sense use.", 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 319 reptile singular/third past 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 reptile head each, bare pronouns and Yalanji demonstratives, final nyajin, no loans, no denied forms, and no source-prose/prior-row drift.", command="python3 -m py_compile batch_scripts/bank_361.py && python3 -c \"import sys;sys.path.insert(0,'batch_scripts');import bank_361;print(bank_361.scan_static())\"", output_excerpt="issues 0", artifact_path="batch_scripts/bank_361.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="codex", detail=f"Banked 50 Rule 319 rows as under_review. Verified remains {verified_before}; Kuku words remain {words_before}.", command="python3 batch_scripts/bank_361.py", output_excerpt=f"banked batch-361: 50 under_review; verified_before={verified_before}; kuku_words_before={words_before}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit()
    print("banked batch-361: 50 rows under_review")
    return 0


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