#!/usr/bin/env python3
"""Bank batch-342: Rule 300 complementary insect 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-342"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-342-complementary-insect-nonsingular-past-perception-after-rule299-process.md"

TARGET_EVIDENCE = {
    "balarr": "Dictionary yaml line 833 gives balarr as noun 'flea'. Rule 300 selects visible flea reference only and leaves body, bite, sickness, pest-control, and event rows closed.",
    "dijaraban": "Dictionary yaml line 5542 gives dijaraban as noun 'mayfly' with a mayfly/dragonfly definition. Rule 300 retains the established mayfly label only and leaves dragonfly expansion and ecology rows closed.",
    "kalburiji": "Dictionary yaml line 12474 gives kalburiji as a species of bee. Rule 300 selects visible bee-label reference only and leaves honey, nest, egg, larvae, collecting, edible, and source-prose rows closed.",
    "mawal": "Dictionary yaml line 18743 gives mawal as a species of bee. Rule 300 selects visible bee-label reference only and leaves honey, nest, egg, larvae, collecting, edible, and source-prose rows closed.",
    "munudumbun": "Dictionary yaml line 20816 gives munudumbun as 'scorpion' with synonym munukurru. Rule 300 selects visible scorpion reference only and leaves synonym, sting, poison, danger, sickness, and event rows closed.",
    "munyurri": "Dictionary yaml line 20868 gives munyurri as 'sandfly' with synonym diri-diri. Rule 300 selects visible sandfly reference only and leaves synonym, biting, sickness, pest-control, and event rows closed.",
    "nakawarra": "Dictionary yaml line 21461 gives nakawarra as a species of bee. Rule 300 selects visible bee-label reference only and leaves honey, nest, collecting, edible, and source-prose rows closed.",
    "ngalmnbu": "Dictionary yaml line 21972 gives ngalmnbu as 'jumper ant'. Rule 300 selects visible ant-label reference only and leaves jumping, bite, sting, antbed, and event rows closed.",
    "yarrka": "Dictionary yaml line 29551 gives yarrka as 'bee, the smallest bee in the bush'. Rule 300 selects visible bee-label reference only and leaves smallest, bush, honey, nest, collecting, and source-prose rows closed.",
    "yiljun": "Dictionary yaml line 30019 gives yiljun as 'grasshopper' and a singing/yam-readiness usage. Rule 300 selects visible grasshopper reference only and leaves singing, yam-readiness, seasonal-signal, movement, and event rows closed.",
}

SUPPORT_EVIDENCE = (
    "Living grammar pronoun tables source bare nominative ngali, ngaliny, yubal, yurra, and ngana, with clusivity "
    "notes for ngali/ngaliny/ngana; demonstrative notes source yaluy 'here' and yinyay 'there'; Patz examples "
    "and living grammar source nyaji-ny / nyajin as past visual perception. Rule 300 uses only bare support forms."
)

TARGET_ORDER = ["balarr", "dijaraban", "kalburiji", "mawal", "munudumbun", "munyurri", "nakawarra", "ngalmnbu", "yarrka", "yiljun"]
FRAME_SPECS = [
    ("ngali", "yinyay"),
    ("ngaliny", "yaluy"),
    ("yubal", "yinyay"),
    ("yurra", "yaluy"),
    ("ngana", "yinyay"),
]

DENY_KUKU = {
    "munukurru", "diri-diri", "dabu", "wunba", "kuja", "yangka", "nyirran", "karrkil", "murma",
    "wurrbu", "dabadaba", "dujandujan", "kalkamal", "kuran", "kurrmaja", "nyumbil", "malal",
    "ngalingan", "ngalinka", "ngalinda", "ngalindamuny", "ngalinji", "ngalinga",
    "ngalinyan", "ngalinyanka", "ngalinyanda", "ngalinyandamuny", "ngalinyanji", "ngalinyanga",
    "yubalan", "yubalanka", "yubalanda", "yubalandamuny", "yubalanji", "yubalanga",
    "yurrangan", "yurranka", "yurranda", "yurrandamuny", "yurranji", "yurranga",
    "nganangan", "ngananka", "ngananda", "nganandamuny", "ngananji", "ngananga",
    "nganjin", "nganjinan", "nganjinanka", "nganjinanda", "nganjinandamuny", "nganjinanji",
    "nganya", "yununy", "nyunguny", "bulangan", "janangan", "yalungku", "yaluyngku",
    "yinyangka", "yinyayngka", "yalamuny", "yinyamuny",
    "nyajil", "nyaji-l", "nyaji-nka", "nyaji-l-nyaji", "milka", "baykal", "jalngkay",
}
DENY_ENGLISH = (
    "bite", "biting", "bitten", "sting", "stinging", "poison", "danger", "dangerous", "sick", "sickness",
    "vomit", "vomiting", "larvae", "larva", "egg", "eggs", "honey", "nest", "collect", "collecting",
    "edible", "food", "medicine", "season", "seasonal", "sing", "singing", "jump", "jumping", "antbed",
    "pest", "body", "human", "tree", "wood", "habitat", "ecology", "movement", "event", "yam", "readiness",
    "smallest", "bush", "dragonfly",
)


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


ROWS = [
    row(1, "We two, not you, saw the flea there.", "Ngali balarr yinyay nyajin.", "ngali balarr yinyay nyajin | 1du.EXCL.NOM flea there see.PAST", "r300_1du_excl_there_insect_saw_balarr", ["ngali", "balarr", "yinyay", "nyajin"]),
    row(2, "We two, not you, saw the mayfly there.", "Ngali dijaraban yinyay nyajin.", "ngali dijaraban yinyay nyajin | 1du.EXCL.NOM mayfly there see.PAST", "r300_1du_excl_there_insect_saw_dijaraban", ["ngali", "dijaraban", "yinyay", "nyajin"]),
    row(3, "We two, not you, saw the kalburiji bee there.", "Ngali kalburiji yinyay nyajin.", "ngali kalburiji yinyay nyajin | 1du.EXCL.NOM kalburiji.bee there see.PAST", "r300_1du_excl_there_insect_saw_kalburiji", ["ngali", "kalburiji", "yinyay", "nyajin"]),
    row(4, "We two, not you, saw the mawal bee there.", "Ngali mawal yinyay nyajin.", "ngali mawal yinyay nyajin | 1du.EXCL.NOM mawal.bee there see.PAST", "r300_1du_excl_there_insect_saw_mawal", ["ngali", "mawal", "yinyay", "nyajin"]),
    row(5, "We two, not you, saw the scorpion there.", "Ngali munudumbun yinyay nyajin.", "ngali munudumbun yinyay nyajin | 1du.EXCL.NOM scorpion there see.PAST", "r300_1du_excl_there_insect_saw_munudumbun", ["ngali", "munudumbun", "yinyay", "nyajin"]),
    row(6, "We two, not you, saw the sandfly there.", "Ngali munyurri yinyay nyajin.", "ngali munyurri yinyay nyajin | 1du.EXCL.NOM sandfly there see.PAST", "r300_1du_excl_there_insect_saw_munyurri", ["ngali", "munyurri", "yinyay", "nyajin"]),
    row(7, "We two, not you, saw the nakawarra bee there.", "Ngali nakawarra yinyay nyajin.", "ngali nakawarra yinyay nyajin | 1du.EXCL.NOM nakawarra.bee there see.PAST", "r300_1du_excl_there_insect_saw_nakawarra", ["ngali", "nakawarra", "yinyay", "nyajin"]),
    row(8, "We two, not you, saw the jumper ant there.", "Ngali ngalmnbu yinyay nyajin.", "ngali ngalmnbu yinyay nyajin | 1du.EXCL.NOM jumper.ant there see.PAST", "r300_1du_excl_there_insect_saw_ngalmnbu", ["ngali", "ngalmnbu", "yinyay", "nyajin"]),
    row(9, "We two, not you, saw the yarrka bee there.", "Ngali yarrka yinyay nyajin.", "ngali yarrka yinyay nyajin | 1du.EXCL.NOM yarrka.bee there see.PAST", "r300_1du_excl_there_insect_saw_yarrka", ["ngali", "yarrka", "yinyay", "nyajin"]),
    row(10, "We two, not you, saw the grasshopper there.", "Ngali yiljun yinyay nyajin.", "ngali yiljun yinyay nyajin | 1du.EXCL.NOM grasshopper there see.PAST", "r300_1du_excl_there_insect_saw_yiljun", ["ngali", "yiljun", "yinyay", "nyajin"]),
    row(11, "You and I saw the flea here.", "Ngaliny balarr yaluy nyajin.", "ngaliny balarr yaluy nyajin | 1du.INCL.NOM flea here see.PAST", "r300_1du_incl_here_insect_saw_balarr", ["ngaliny", "balarr", "yaluy", "nyajin"]),
    row(12, "You and I saw the mayfly here.", "Ngaliny dijaraban yaluy nyajin.", "ngaliny dijaraban yaluy nyajin | 1du.INCL.NOM mayfly here see.PAST", "r300_1du_incl_here_insect_saw_dijaraban", ["ngaliny", "dijaraban", "yaluy", "nyajin"]),
    row(13, "You and I saw the kalburiji bee here.", "Ngaliny kalburiji yaluy nyajin.", "ngaliny kalburiji yaluy nyajin | 1du.INCL.NOM kalburiji.bee here see.PAST", "r300_1du_incl_here_insect_saw_kalburiji", ["ngaliny", "kalburiji", "yaluy", "nyajin"]),
    row(14, "You and I saw the mawal bee here.", "Ngaliny mawal yaluy nyajin.", "ngaliny mawal yaluy nyajin | 1du.INCL.NOM mawal.bee here see.PAST", "r300_1du_incl_here_insect_saw_mawal", ["ngaliny", "mawal", "yaluy", "nyajin"]),
    row(15, "You and I saw the scorpion here.", "Ngaliny munudumbun yaluy nyajin.", "ngaliny munudumbun yaluy nyajin | 1du.INCL.NOM scorpion here see.PAST", "r300_1du_incl_here_insect_saw_munudumbun", ["ngaliny", "munudumbun", "yaluy", "nyajin"]),
    row(16, "You and I saw the sandfly here.", "Ngaliny munyurri yaluy nyajin.", "ngaliny munyurri yaluy nyajin | 1du.INCL.NOM sandfly here see.PAST", "r300_1du_incl_here_insect_saw_munyurri", ["ngaliny", "munyurri", "yaluy", "nyajin"]),
    row(17, "You and I saw the nakawarra bee here.", "Ngaliny nakawarra yaluy nyajin.", "ngaliny nakawarra yaluy nyajin | 1du.INCL.NOM nakawarra.bee here see.PAST", "r300_1du_incl_here_insect_saw_nakawarra", ["ngaliny", "nakawarra", "yaluy", "nyajin"]),
    row(18, "You and I saw the jumper ant here.", "Ngaliny ngalmnbu yaluy nyajin.", "ngaliny ngalmnbu yaluy nyajin | 1du.INCL.NOM jumper.ant here see.PAST", "r300_1du_incl_here_insect_saw_ngalmnbu", ["ngaliny", "ngalmnbu", "yaluy", "nyajin"]),
    row(19, "You and I saw the yarrka bee here.", "Ngaliny yarrka yaluy nyajin.", "ngaliny yarrka yaluy nyajin | 1du.INCL.NOM yarrka.bee here see.PAST", "r300_1du_incl_here_insect_saw_yarrka", ["ngaliny", "yarrka", "yaluy", "nyajin"]),
    row(20, "You and I saw the grasshopper here.", "Ngaliny yiljun yaluy nyajin.", "ngaliny yiljun yaluy nyajin | 1du.INCL.NOM grasshopper here see.PAST", "r300_1du_incl_here_insect_saw_yiljun", ["ngaliny", "yiljun", "yaluy", "nyajin"]),
    row(21, "You two saw the flea there.", "Yubal balarr yinyay nyajin.", "yubal balarr yinyay nyajin | 2du.NOM flea there see.PAST", "r300_2du_there_insect_saw_balarr", ["yubal", "balarr", "yinyay", "nyajin"]),
    row(22, "You two saw the mayfly there.", "Yubal dijaraban yinyay nyajin.", "yubal dijaraban yinyay nyajin | 2du.NOM mayfly there see.PAST", "r300_2du_there_insect_saw_dijaraban", ["yubal", "dijaraban", "yinyay", "nyajin"]),
    row(23, "You two saw the kalburiji bee there.", "Yubal kalburiji yinyay nyajin.", "yubal kalburiji yinyay nyajin | 2du.NOM kalburiji.bee there see.PAST", "r300_2du_there_insect_saw_kalburiji", ["yubal", "kalburiji", "yinyay", "nyajin"]),
    row(24, "You two saw the mawal bee there.", "Yubal mawal yinyay nyajin.", "yubal mawal yinyay nyajin | 2du.NOM mawal.bee there see.PAST", "r300_2du_there_insect_saw_mawal", ["yubal", "mawal", "yinyay", "nyajin"]),
    row(25, "You two saw the scorpion there.", "Yubal munudumbun yinyay nyajin.", "yubal munudumbun yinyay nyajin | 2du.NOM scorpion there see.PAST", "r300_2du_there_insect_saw_munudumbun", ["yubal", "munudumbun", "yinyay", "nyajin"]),
    row(26, "You two saw the sandfly there.", "Yubal munyurri yinyay nyajin.", "yubal munyurri yinyay nyajin | 2du.NOM sandfly there see.PAST", "r300_2du_there_insect_saw_munyurri", ["yubal", "munyurri", "yinyay", "nyajin"]),
    row(27, "You two saw the nakawarra bee there.", "Yubal nakawarra yinyay nyajin.", "yubal nakawarra yinyay nyajin | 2du.NOM nakawarra.bee there see.PAST", "r300_2du_there_insect_saw_nakawarra", ["yubal", "nakawarra", "yinyay", "nyajin"]),
    row(28, "You two saw the jumper ant there.", "Yubal ngalmnbu yinyay nyajin.", "yubal ngalmnbu yinyay nyajin | 2du.NOM jumper.ant there see.PAST", "r300_2du_there_insect_saw_ngalmnbu", ["yubal", "ngalmnbu", "yinyay", "nyajin"]),
    row(29, "You two saw the yarrka bee there.", "Yubal yarrka yinyay nyajin.", "yubal yarrka yinyay nyajin | 2du.NOM yarrka.bee there see.PAST", "r300_2du_there_insect_saw_yarrka", ["yubal", "yarrka", "yinyay", "nyajin"]),
    row(30, "You two saw the grasshopper there.", "Yubal yiljun yinyay nyajin.", "yubal yiljun yinyay nyajin | 2du.NOM grasshopper there see.PAST", "r300_2du_there_insect_saw_yiljun", ["yubal", "yiljun", "yinyay", "nyajin"]),
    row(31, "You all saw the flea here.", "Yurra balarr yaluy nyajin.", "yurra balarr yaluy nyajin | 2pl.NOM flea here see.PAST", "r300_2pl_here_insect_saw_balarr", ["yurra", "balarr", "yaluy", "nyajin"]),
    row(32, "You all saw the mayfly here.", "Yurra dijaraban yaluy nyajin.", "yurra dijaraban yaluy nyajin | 2pl.NOM mayfly here see.PAST", "r300_2pl_here_insect_saw_dijaraban", ["yurra", "dijaraban", "yaluy", "nyajin"]),
    row(33, "You all saw the kalburiji bee here.", "Yurra kalburiji yaluy nyajin.", "yurra kalburiji yaluy nyajin | 2pl.NOM kalburiji.bee here see.PAST", "r300_2pl_here_insect_saw_kalburiji", ["yurra", "kalburiji", "yaluy", "nyajin"]),
    row(34, "You all saw the mawal bee here.", "Yurra mawal yaluy nyajin.", "yurra mawal yaluy nyajin | 2pl.NOM mawal.bee here see.PAST", "r300_2pl_here_insect_saw_mawal", ["yurra", "mawal", "yaluy", "nyajin"]),
    row(35, "You all saw the scorpion here.", "Yurra munudumbun yaluy nyajin.", "yurra munudumbun yaluy nyajin | 2pl.NOM scorpion here see.PAST", "r300_2pl_here_insect_saw_munudumbun", ["yurra", "munudumbun", "yaluy", "nyajin"]),
    row(36, "You all saw the sandfly here.", "Yurra munyurri yaluy nyajin.", "yurra munyurri yaluy nyajin | 2pl.NOM sandfly here see.PAST", "r300_2pl_here_insect_saw_munyurri", ["yurra", "munyurri", "yaluy", "nyajin"]),
    row(37, "You all saw the nakawarra bee here.", "Yurra nakawarra yaluy nyajin.", "yurra nakawarra yaluy nyajin | 2pl.NOM nakawarra.bee here see.PAST", "r300_2pl_here_insect_saw_nakawarra", ["yurra", "nakawarra", "yaluy", "nyajin"]),
    row(38, "You all saw the jumper ant here.", "Yurra ngalmnbu yaluy nyajin.", "yurra ngalmnbu yaluy nyajin | 2pl.NOM jumper.ant here see.PAST", "r300_2pl_here_insect_saw_ngalmnbu", ["yurra", "ngalmnbu", "yaluy", "nyajin"]),
    row(39, "You all saw the yarrka bee here.", "Yurra yarrka yaluy nyajin.", "yurra yarrka yaluy nyajin | 2pl.NOM yarrka.bee here see.PAST", "r300_2pl_here_insect_saw_yarrka", ["yurra", "yarrka", "yaluy", "nyajin"]),
    row(40, "You all saw the grasshopper here.", "Yurra yiljun yaluy nyajin.", "yurra yiljun yaluy nyajin | 2pl.NOM grasshopper here see.PAST", "r300_2pl_here_insect_saw_yiljun", ["yurra", "yiljun", "yaluy", "nyajin"]),
    row(41, "We saw the flea there.", "Ngana balarr yinyay nyajin.", "ngana balarr yinyay nyajin | 1pl.INCL.NOM flea there see.PAST", "r300_1pl_incl_there_insect_saw_balarr", ["ngana", "balarr", "yinyay", "nyajin"]),
    row(42, "We saw the mayfly there.", "Ngana dijaraban yinyay nyajin.", "ngana dijaraban yinyay nyajin | 1pl.INCL.NOM mayfly there see.PAST", "r300_1pl_incl_there_insect_saw_dijaraban", ["ngana", "dijaraban", "yinyay", "nyajin"]),
    row(43, "We saw the kalburiji bee there.", "Ngana kalburiji yinyay nyajin.", "ngana kalburiji yinyay nyajin | 1pl.INCL.NOM kalburiji.bee there see.PAST", "r300_1pl_incl_there_insect_saw_kalburiji", ["ngana", "kalburiji", "yinyay", "nyajin"]),
    row(44, "We saw the mawal bee there.", "Ngana mawal yinyay nyajin.", "ngana mawal yinyay nyajin | 1pl.INCL.NOM mawal.bee there see.PAST", "r300_1pl_incl_there_insect_saw_mawal", ["ngana", "mawal", "yinyay", "nyajin"]),
    row(45, "We saw the scorpion there.", "Ngana munudumbun yinyay nyajin.", "ngana munudumbun yinyay nyajin | 1pl.INCL.NOM scorpion there see.PAST", "r300_1pl_incl_there_insect_saw_munudumbun", ["ngana", "munudumbun", "yinyay", "nyajin"]),
    row(46, "We saw the sandfly there.", "Ngana munyurri yinyay nyajin.", "ngana munyurri yinyay nyajin | 1pl.INCL.NOM sandfly there see.PAST", "r300_1pl_incl_there_insect_saw_munyurri", ["ngana", "munyurri", "yinyay", "nyajin"]),
    row(47, "We saw the nakawarra bee there.", "Ngana nakawarra yinyay nyajin.", "ngana nakawarra yinyay nyajin | 1pl.INCL.NOM nakawarra.bee there see.PAST", "r300_1pl_incl_there_insect_saw_nakawarra", ["ngana", "nakawarra", "yinyay", "nyajin"]),
    row(48, "We saw the jumper ant there.", "Ngana ngalmnbu yinyay nyajin.", "ngana ngalmnbu yinyay nyajin | 1pl.INCL.NOM jumper.ant there see.PAST", "r300_1pl_incl_there_insect_saw_ngalmnbu", ["ngana", "ngalmnbu", "yinyay", "nyajin"]),
    row(49, "We saw the yarrka bee there.", "Ngana yarrka yinyay nyajin.", "ngana yarrka yinyay nyajin | 1pl.INCL.NOM yarrka.bee there see.PAST", "r300_1pl_incl_there_insect_saw_yarrka", ["ngana", "yarrka", "yinyay", "nyajin"]),
    row(50, "We saw the grasshopper there.", "Ngana yiljun yinyay nyajin.", "ngana yiljun yinyay nyajin | 1pl.INCL.NOM grasshopper there see.PAST", "r300_1pl_incl_there_insect_saw_yiljun", ["ngana", "yiljun", "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")
    kukus = [r[2] for r in ROWS]
    if len(set(kukus)) != len(kukus):
        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)
        lower_kuku = kuku.lower()
        lower_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\.]|$)", lower_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.strip())}\b", lower_english)]
        if denied_english:
            issues.append(f"{seq}: denied English drift {denied_english}")
        target_hits = [w for w in TARGET_ORDER if w in words]
        if len(target_hits) != 1:
            issues.append(f"{seq}: target hits {target_hits}")
        if len(words) != 4:
            issues.append(f"{seq}: expected 4 words, got {words}")
        if "nyajin" not in words or not lower_kuku.endswith(" nyajin."):
            issues.append(f"{seq}: missing final nyajin")
        if "nyajil" in lower_kuku:
            issues.append(f"{seq}: nonpast nyajil leakage")
        if len([w for w in ("yaluy", "yinyay") if w in words]) != 1:
            issues.append(f"{seq}: demonstrative problem {words}")
        expected_pronoun, expected_demo = FRAME_SPECS[(seq - 1) // 10]
        if words[0] != expected_pronoun:
            issues.append(f"{seq}: expected pronoun {expected_pronoun}, got {words[0]}")
        if words[2] != expected_demo:
            issues.append(f"{seq}: expected demonstrative {expected_demo}, got {words[2]}")
        if words[1] != TARGET_ORDER[(seq - 1) % 10]:
            issues.append(f"{seq}: target order mismatch {words[1]}")
        if words[3] != "nyajin":
            issues.append(f"{seq}: word 4 is not nyajin {words[3]}")
        if lower_kuku.rstrip(".") != " ".join(words):
            issues.append(f"{seq}: Kuku does not match words_used {words}")
        if not frame.startswith("r300_"):
            issues.append(f"{seq}: frame not r300 {frame}")
    return issues


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 value=?)
            """,
            (word,),
        ).fetchone()[0]
        for word in words
    }


def main() -> int:
    issues = scan_static()
    if issues:
        for issue in issues:
            print(issue)
        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:
        existing = 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 existing:
            collisions.append((kuku, existing))
    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", "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 = (
        "COMPLEMENTARY INSECT NON-SINGULAR PAST PERCEPTION SWEEP AFTER RULE 299 (Rule 300). "
        "50 under-review rows over the same ten checked insect target heads: balarr flea, dijaraban mayfly, "
        "kalburiji bee, mawal bee, munudumbun scorpion, munyurri sandfly, nakawarra bee, ngalmnbu jumper ant, "
        "yarrka bee, and yiljun grasshopper. SUPPORT: bare nominative ngali, ngaliny, yubal, yurra, and ngana, "
        "plus complementary yaluy/yinyay and nyajin. Only bare visible object past perception/reference rows are "
        "opened; biting, stinging, poison, sickness, vomiting, honey, nest, eggs, larvae, collecting, edible/food/"
        "medicine, seasonal-signal, singing, jumping, antbed, body/human-body, tree/wood, ecology, movement, danger, "
        "event, target case, pronoun case, demonstrative case, compounds, productive reduplication, nonpast/"
        "purposive/reduplicated perception drift, and support inflection remain closed."
    )
    cur = db.execute(
        "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
        (LABEL, "Rule 300 under review", "operator-guide-2026-07-09", 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, english, kuku, analysis, frame, tier, words_used, loans_used,
                evidence, "under_review", confidence,
                "project_approved_synthetic_pending_elder_verification", "claude", NOW, NOW,
            )
            for seq, english, kuku, analysis, frame, tier, words_used, loans_used, evidence, confidence in ROWS
        ],
    )
    record_event(db, batch_label=LABEL, phase="source", event_type="source-readback", actor="claude-main", detail="Reread direct dictionary yaml entries for ten Rule 300 insect targets and living grammar pronoun, demonstrative, and nyaji-ny/nyajin past support before authoring Rule 300.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="complementary-insect-nonsingular-past-scope", actor="claude-main", detail="Selected the complementary here/there half of the Rule 299 insect non-singular past perception field. The batch uses ngali, ngaliny, yubal, yurra, and ngana with nyajin, reversing the demonstrative slot and opening no insect action, danger, honey, nest, medicine, ecology, event, or source-prose semantics.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="coverage-audit", actor="claude-main", detail=f"Token-aware accepted/revised coverage before banking from words_used JSON: 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="claude-main", detail="Final 50 Rule 300 complementary insect non-singular past surfaces returned no accepted, revised, or under-review collisions over the Rule 299 target set.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="static-guard-pass", actor="claude-main", detail="Static guard passed: 50 explicit hand-authored rows, one target each, bare non-singular nominative pronoun bands, complementary bare yaluy/yinyay, final nyajin, no loans, no denied Kuku forms, and no bite/sting/honey/nest/larvae/medicine/ecology/case/compound drift.", command="python3 -m py_compile batch_scripts/bank_342.py && python3 -c \"import sys; sys.path.insert(0,'batch_scripts'); import bank_342; print(bank_342.scan_static())\"", output_excerpt="issues 0", artifact_path="batch_scripts/bank_342.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="claude-main", detail=f"Banked 50 Rule 300 rows as under_review. Verified total remains {verified_before}; Kuku word count remains {words_before}.", command="python3 batch_scripts/bank_342.py", output_excerpt=f"banked batch-342: 50 rows under_review; verified_before={verified_before}; kuku_words_before={words_before}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit()
    print("banked batch-342: 50 rows under_review")
    return 0


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