#!/usr/bin/env python3
"""Bank batch-284: Rule 242 bird-reference perception consolidation."""

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-284"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-284-bird-reference-perception-consolidation-after-rule241-process.md"

TARGET_HEADS = {
    "birmba": "straw-necked ibis",
    "jamarbina": "goose",
    "nili-nili": "duck",
    "mabal": "swallow",
    "wungku": "domestic turkey",
    "kuludu": "dove",
    "kururrungka": "kookaburra",
    "karrambil": "king parrot",
    "yinjul": "parrot",
    "kadanji": "black cockatoo",
}
SUPPORT = {"ngayu", "nyulu", "yurra", "bula", "jana", "yaluy", "yinyay", "nyajil"}
PRONOUN_SUPPORT = {"ngayu", "nyulu", "yurra", "bula", "jana"}
DENY_KUKU = {
    "dikal", "buyi", "yalngkurr", "birrmba", "kumurbina", "diwan", "wabul",
    "bakamu", "birrbirr", "dawa-dawa", "dulku", "jaka", "wandi", "barbarr",
    "bayil-bayil", "biluwarra", "binjul-binjul", "dijarr-dijin", "kurburrubun",
    "kurkumbay", "jarruka", "bajal", "jiwurrmal", "jangkan", "karunkurr",
    "jurriyan", "kurrbal", "baringkan", "bidu-bidu", "diwalngku", "jiral-jiral",
    "karkunbay", "dukunjulu", "kurranday", "nangki", "bujur", "diburr",
    "bayan", "bubu", "bana", "juku", "kurrma", "minya", "mayi", "dungay",
    "janay", "ngaran", "warri", "marra-warri",
    "nganya", "nyunguny", "yurrangan", "yurraniny", "yurranka", "yurranda",
    "yurranji", "yurranga", "bulangan", "bulaniny", "bulanka", "bulanda",
    "bulanji", "bulanga", "ianangan", "iananiny", "iananka", "iananda",
    "iananji", "iananga", "yinyangka", "yinyayngka", "yinyayanka", "yinyamba",
    "yinyayanda", "yinyamuny", "yinyamundu", "yinyanji", "yinyarriny",
    "nyaji-nka", "nyaji-nyaku", "nyaji-l-nyaji", "nyajin", "nyajiny",
    "kubija", "mujarrka", "barrbal", "wuyumbu", "bayil", "dalmbal", "balarri",
    "bilmbin", "jalkay", "jijirr", "bayilbayil", "kijukum", "ngiwa",
    "yidilnyul", "walarrji", "bakarr", "bayan", "bira", "jiji", "kilili",
    "wurun", "jakway", "yulal", "kararr", "bilangkurr", "baya", "jimal",
    "jirramar", "kubu", "kunjin", "miyilkura", "ngalku", "ngaluri", "ngunjil",
    "wula",
}
DENY_ENGLISH = (
    "fly", "flying", "flew", "sing", "singing", "sang", "call", "calling",
    "called", "dance", "dancing", "warning", "warn", "messenger", "message",
    "totem", "moiety", "sacred", "spirit", "storm", "thunder", "story",
    "story-site", "place", "nest", "egg", "feather", "wing", "plumage",
    "food", "eat", "eating", "ate", "hunt", "hunting", "catch", "catching",
    "caught", "water", "river", "sea", "tree", "habitat", "country",
    "ceremony", "myth", "omen", "signal", "scrub turkey", "scrub-turkey",
    "white cockatoo", "cockatoo alternate", "small grey", "bronze wing",
    "bronze-wing", "fig parrot", "nyungkul", "kumurbina", "colour",
    "case", "compound", "productive reduplication", "loan",
)


def js(values: list[str]) -> str:
    return json.dumps(values, ensure_ascii=False)


def row(
    seq: int,
    english: str,
    kuku: str,
    analysis: str,
    frame: str,
    words: list[str],
    evidence: str,
) -> tuple:
    return (seq, english, kuku, analysis, frame, 3, js(words), js([]), evidence, "0.86")


EVIDENCE = {
    "birmba": "Dictionary birmba noun gloss/translation 'straw-necked ibis'; totem/moiety and cockatoo alternate notes stay closed. Rule 242 retains the Rule 241 target and changes only the local demonstrative in a sourced visual-perception frame. Patz 3.1.2, 3.5 Table 3.6, 3.7 Table 3.12, and 3.8.3.2 source the frame.",
    "jamarbina": "Dictionary jamarbina noun gloss/definition/translation 'goose'. Rule 242 retains goose reference/perception only and changes only the local demonstrative band. Patz 3.1.2, 3.5, 3.7, and 3.8.3.2 source the frame.",
    "nili-nili": "Dictionary nili-nili noun gloss/definition/translation 'duck', with reduplication noted as lexical. Rule 242 treats nili-nili as a whole lexical bird label only and changes only the local demonstrative band. Patz 3.1.2, 3.5, 3.7, and 3.8.3.2 source the frame.",
    "mabal": "Dictionary mabal noun gloss/definition/translation 'swallow' with commentary 'Swallow, a bird.' Rule 242 keeps the bird label only, not English verb semantics. Patz 3.1.2, 3.5, 3.7, and 3.8.3.2 source the frame.",
    "wungku": "Dictionary wungku noun gloss 'domestic turkey'/'turkey', with definition distinguishing domestic turkey from scrub turkey. Rule 242 selects domestic turkey only and changes only the local demonstrative band. Patz 3.1.2, 3.5, 3.7, and 3.8.3.2 source the frame.",
    "kuludu": "Dictionary kuludu noun gloss/translation 'dove', with one definition 'small grey'. Rule 242 selects dove reference/perception only and does not open colour or descriptive prose. Patz 3.1.2, 3.5, 3.7, and 3.8.3.2 source the frame.",
    "kururrungka": "Dictionary kururrungka noun gloss/translation 'kookaburra', with definition 'bronze wing kookaburra'. Rule 242 selects kookaburra only and changes only the local demonstrative band. Patz 3.1.2, 3.5, 3.7, and 3.8.3.2 source the frame.",
    "karrambil": "Dictionary karrambil noun gloss/definition/translation 'king parrot'. Rule 242 uses king parrot reference/perception only. Patz 3.1.2, 3.5, 3.7, and 3.8.3.2 source the support forms.",
    "yinjul": "Dictionary yinjul noun gloss 'parrot' with definition 'fig parrot'. Rule 242 selects parrot as the English label and does not open fig/tree/food/habitat prose. Patz 3.1.2, 3.5, 3.7, and 3.8.3.2 source the frame.",
    "kadanji": "Dictionary kadanji noun gloss/translation 'black cockatoo', marked Yalanji in one entry with Nyungkul kumurbina and Dabu totem prose. Rule 242 selects black cockatoo reference/perception only. Patz 3.1.2, 3.5, 3.7, and 3.8.3.2 source the frame.",
}


ROWS = [
    row(1, "I see the straw-necked ibis here.", "Ngayu birmba yaluy nyajil.", "ngayu birmba yaluy nyajil | 1sg.NOM straw.necked.ibis here see.NPST", "r242_1sg_target_here_see_birmba", ["ngayu", "birmba", "yaluy", "nyajil"], EVIDENCE["birmba"]),
    row(2, "I see the goose here.", "Ngayu jamarbina yaluy nyajil.", "ngayu jamarbina yaluy nyajil | 1sg.NOM goose here see.NPST", "r242_1sg_target_here_see_jamarbina", ["ngayu", "jamarbina", "yaluy", "nyajil"], EVIDENCE["jamarbina"]),
    row(3, "I see the duck here.", "Ngayu nili-nili yaluy nyajil.", "ngayu nili-nili yaluy nyajil | 1sg.NOM duck here see.NPST", "r242_1sg_target_here_see_nili_nili", ["ngayu", "nili-nili", "yaluy", "nyajil"], EVIDENCE["nili-nili"]),
    row(4, "I see the swallow here.", "Ngayu mabal yaluy nyajil.", "ngayu mabal yaluy nyajil | 1sg.NOM swallow here see.NPST", "r242_1sg_target_here_see_mabal", ["ngayu", "mabal", "yaluy", "nyajil"], EVIDENCE["mabal"]),
    row(5, "I see the domestic turkey here.", "Ngayu wungku yaluy nyajil.", "ngayu wungku yaluy nyajil | 1sg.NOM domestic.turkey here see.NPST", "r242_1sg_target_here_see_wungku", ["ngayu", "wungku", "yaluy", "nyajil"], EVIDENCE["wungku"]),
    row(6, "I see the dove here.", "Ngayu kuludu yaluy nyajil.", "ngayu kuludu yaluy nyajil | 1sg.NOM dove here see.NPST", "r242_1sg_target_here_see_kuludu", ["ngayu", "kuludu", "yaluy", "nyajil"], EVIDENCE["kuludu"]),
    row(7, "I see the kookaburra here.", "Ngayu kururrungka yaluy nyajil.", "ngayu kururrungka yaluy nyajil | 1sg.NOM kookaburra here see.NPST", "r242_1sg_target_here_see_kururrungka", ["ngayu", "kururrungka", "yaluy", "nyajil"], EVIDENCE["kururrungka"]),
    row(8, "I see the king parrot here.", "Ngayu karrambil yaluy nyajil.", "ngayu karrambil yaluy nyajil | 1sg.NOM king.parrot here see.NPST", "r242_1sg_target_here_see_karrambil", ["ngayu", "karrambil", "yaluy", "nyajil"], EVIDENCE["karrambil"]),
    row(9, "I see the parrot here.", "Ngayu yinjul yaluy nyajil.", "ngayu yinjul yaluy nyajil | 1sg.NOM parrot here see.NPST", "r242_1sg_target_here_see_yinjul", ["ngayu", "yinjul", "yaluy", "nyajil"], EVIDENCE["yinjul"]),
    row(10, "I see the black cockatoo here.", "Ngayu kadanji yaluy nyajil.", "ngayu kadanji yaluy nyajil | 1sg.NOM black.cockatoo here see.NPST", "r242_1sg_target_here_see_kadanji", ["ngayu", "kadanji", "yaluy", "nyajil"], EVIDENCE["kadanji"]),
    row(11, "He sees the straw-necked ibis there.", "Nyulu birmba yinyay nyajil.", "nyulu birmba yinyay nyajil | 3sg.NOM straw.necked.ibis there see.NPST", "r242_3sg_target_there_see_birmba", ["nyulu", "birmba", "yinyay", "nyajil"], EVIDENCE["birmba"]),
    row(12, "He sees the goose there.", "Nyulu jamarbina yinyay nyajil.", "nyulu jamarbina yinyay nyajil | 3sg.NOM goose there see.NPST", "r242_3sg_target_there_see_jamarbina", ["nyulu", "jamarbina", "yinyay", "nyajil"], EVIDENCE["jamarbina"]),
    row(13, "He sees the duck there.", "Nyulu nili-nili yinyay nyajil.", "nyulu nili-nili yinyay nyajil | 3sg.NOM duck there see.NPST", "r242_3sg_target_there_see_nili_nili", ["nyulu", "nili-nili", "yinyay", "nyajil"], EVIDENCE["nili-nili"]),
    row(14, "He sees the swallow there.", "Nyulu mabal yinyay nyajil.", "nyulu mabal yinyay nyajil | 3sg.NOM swallow there see.NPST", "r242_3sg_target_there_see_mabal", ["nyulu", "mabal", "yinyay", "nyajil"], EVIDENCE["mabal"]),
    row(15, "He sees the domestic turkey there.", "Nyulu wungku yinyay nyajil.", "nyulu wungku yinyay nyajil | 3sg.NOM domestic.turkey there see.NPST", "r242_3sg_target_there_see_wungku", ["nyulu", "wungku", "yinyay", "nyajil"], EVIDENCE["wungku"]),
    row(16, "He sees the dove there.", "Nyulu kuludu yinyay nyajil.", "nyulu kuludu yinyay nyajil | 3sg.NOM dove there see.NPST", "r242_3sg_target_there_see_kuludu", ["nyulu", "kuludu", "yinyay", "nyajil"], EVIDENCE["kuludu"]),
    row(17, "He sees the kookaburra there.", "Nyulu kururrungka yinyay nyajil.", "nyulu kururrungka yinyay nyajil | 3sg.NOM kookaburra there see.NPST", "r242_3sg_target_there_see_kururrungka", ["nyulu", "kururrungka", "yinyay", "nyajil"], EVIDENCE["kururrungka"]),
    row(18, "He sees the king parrot there.", "Nyulu karrambil yinyay nyajil.", "nyulu karrambil yinyay nyajil | 3sg.NOM king.parrot there see.NPST", "r242_3sg_target_there_see_karrambil", ["nyulu", "karrambil", "yinyay", "nyajil"], EVIDENCE["karrambil"]),
    row(19, "He sees the parrot there.", "Nyulu yinjul yinyay nyajil.", "nyulu yinjul yinyay nyajil | 3sg.NOM parrot there see.NPST", "r242_3sg_target_there_see_yinjul", ["nyulu", "yinjul", "yinyay", "nyajil"], EVIDENCE["yinjul"]),
    row(20, "He sees the black cockatoo there.", "Nyulu kadanji yinyay nyajil.", "nyulu kadanji yinyay nyajil | 3sg.NOM black.cockatoo there see.NPST", "r242_3sg_target_there_see_kadanji", ["nyulu", "kadanji", "yinyay", "nyajil"], EVIDENCE["kadanji"]),
    row(21, "You all see the straw-necked ibis here.", "Yurra birmba yaluy nyajil.", "yurra birmba yaluy nyajil | 2pl.NOM straw.necked.ibis here see.NPST", "r242_2pl_target_here_see_birmba", ["yurra", "birmba", "yaluy", "nyajil"], EVIDENCE["birmba"]),
    row(22, "You all see the goose here.", "Yurra jamarbina yaluy nyajil.", "yurra jamarbina yaluy nyajil | 2pl.NOM goose here see.NPST", "r242_2pl_target_here_see_jamarbina", ["yurra", "jamarbina", "yaluy", "nyajil"], EVIDENCE["jamarbina"]),
    row(23, "You all see the duck here.", "Yurra nili-nili yaluy nyajil.", "yurra nili-nili yaluy nyajil | 2pl.NOM duck here see.NPST", "r242_2pl_target_here_see_nili_nili", ["yurra", "nili-nili", "yaluy", "nyajil"], EVIDENCE["nili-nili"]),
    row(24, "You all see the swallow here.", "Yurra mabal yaluy nyajil.", "yurra mabal yaluy nyajil | 2pl.NOM swallow here see.NPST", "r242_2pl_target_here_see_mabal", ["yurra", "mabal", "yaluy", "nyajil"], EVIDENCE["mabal"]),
    row(25, "You all see the domestic turkey here.", "Yurra wungku yaluy nyajil.", "yurra wungku yaluy nyajil | 2pl.NOM domestic.turkey here see.NPST", "r242_2pl_target_here_see_wungku", ["yurra", "wungku", "yaluy", "nyajil"], EVIDENCE["wungku"]),
    row(26, "You all see the dove here.", "Yurra kuludu yaluy nyajil.", "yurra kuludu yaluy nyajil | 2pl.NOM dove here see.NPST", "r242_2pl_target_here_see_kuludu", ["yurra", "kuludu", "yaluy", "nyajil"], EVIDENCE["kuludu"]),
    row(27, "You all see the kookaburra here.", "Yurra kururrungka yaluy nyajil.", "yurra kururrungka yaluy nyajil | 2pl.NOM kookaburra here see.NPST", "r242_2pl_target_here_see_kururrungka", ["yurra", "kururrungka", "yaluy", "nyajil"], EVIDENCE["kururrungka"]),
    row(28, "You all see the king parrot here.", "Yurra karrambil yaluy nyajil.", "yurra karrambil yaluy nyajil | 2pl.NOM king.parrot here see.NPST", "r242_2pl_target_here_see_karrambil", ["yurra", "karrambil", "yaluy", "nyajil"], EVIDENCE["karrambil"]),
    row(29, "You all see the parrot here.", "Yurra yinjul yaluy nyajil.", "yurra yinjul yaluy nyajil | 2pl.NOM parrot here see.NPST", "r242_2pl_target_here_see_yinjul", ["yurra", "yinjul", "yaluy", "nyajil"], EVIDENCE["yinjul"]),
    row(30, "You all see the black cockatoo here.", "Yurra kadanji yaluy nyajil.", "yurra kadanji yaluy nyajil | 2pl.NOM black.cockatoo here see.NPST", "r242_2pl_target_here_see_kadanji", ["yurra", "kadanji", "yaluy", "nyajil"], EVIDENCE["kadanji"]),
    row(31, "The two of them see the straw-necked ibis there.", "Bula birmba yinyay nyajil.", "bula birmba yinyay nyajil | 3du.NOM straw.necked.ibis there see.NPST", "r242_3du_target_there_see_birmba", ["bula", "birmba", "yinyay", "nyajil"], EVIDENCE["birmba"]),
    row(32, "The two of them see the goose there.", "Bula jamarbina yinyay nyajil.", "bula jamarbina yinyay nyajil | 3du.NOM goose there see.NPST", "r242_3du_target_there_see_jamarbina", ["bula", "jamarbina", "yinyay", "nyajil"], EVIDENCE["jamarbina"]),
    row(33, "The two of them see the duck there.", "Bula nili-nili yinyay nyajil.", "bula nili-nili yinyay nyajil | 3du.NOM duck there see.NPST", "r242_3du_target_there_see_nili_nili", ["bula", "nili-nili", "yinyay", "nyajil"], EVIDENCE["nili-nili"]),
    row(34, "The two of them see the swallow there.", "Bula mabal yinyay nyajil.", "bula mabal yinyay nyajil | 3du.NOM swallow there see.NPST", "r242_3du_target_there_see_mabal", ["bula", "mabal", "yinyay", "nyajil"], EVIDENCE["mabal"]),
    row(35, "The two of them see the domestic turkey there.", "Bula wungku yinyay nyajil.", "bula wungku yinyay nyajil | 3du.NOM domestic.turkey there see.NPST", "r242_3du_target_there_see_wungku", ["bula", "wungku", "yinyay", "nyajil"], EVIDENCE["wungku"]),
    row(36, "The two of them see the dove there.", "Bula kuludu yinyay nyajil.", "bula kuludu yinyay nyajil | 3du.NOM dove there see.NPST", "r242_3du_target_there_see_kuludu", ["bula", "kuludu", "yinyay", "nyajil"], EVIDENCE["kuludu"]),
    row(37, "The two of them see the kookaburra there.", "Bula kururrungka yinyay nyajil.", "bula kururrungka yinyay nyajil | 3du.NOM kookaburra there see.NPST", "r242_3du_target_there_see_kururrungka", ["bula", "kururrungka", "yinyay", "nyajil"], EVIDENCE["kururrungka"]),
    row(38, "The two of them see the king parrot there.", "Bula karrambil yinyay nyajil.", "bula karrambil yinyay nyajil | 3du.NOM king.parrot there see.NPST", "r242_3du_target_there_see_karrambil", ["bula", "karrambil", "yinyay", "nyajil"], EVIDENCE["karrambil"]),
    row(39, "The two of them see the parrot there.", "Bula yinjul yinyay nyajil.", "bula yinjul yinyay nyajil | 3du.NOM parrot there see.NPST", "r242_3du_target_there_see_yinjul", ["bula", "yinjul", "yinyay", "nyajil"], EVIDENCE["yinjul"]),
    row(40, "The two of them see the black cockatoo there.", "Bula kadanji yinyay nyajil.", "bula kadanji yinyay nyajil | 3du.NOM black.cockatoo there see.NPST", "r242_3du_target_there_see_kadanji", ["bula", "kadanji", "yinyay", "nyajil"], EVIDENCE["kadanji"]),
    row(41, "They see the straw-necked ibis here.", "Jana birmba yaluy nyajil.", "jana birmba yaluy nyajil | 3pl.NOM straw.necked.ibis here see.NPST", "r242_3pl_target_here_see_birmba", ["jana", "birmba", "yaluy", "nyajil"], EVIDENCE["birmba"]),
    row(42, "They see the goose here.", "Jana jamarbina yaluy nyajil.", "jana jamarbina yaluy nyajil | 3pl.NOM goose here see.NPST", "r242_3pl_target_here_see_jamarbina", ["jana", "jamarbina", "yaluy", "nyajil"], EVIDENCE["jamarbina"]),
    row(43, "They see the duck here.", "Jana nili-nili yaluy nyajil.", "jana nili-nili yaluy nyajil | 3pl.NOM duck here see.NPST", "r242_3pl_target_here_see_nili_nili", ["jana", "nili-nili", "yaluy", "nyajil"], EVIDENCE["nili-nili"]),
    row(44, "They see the swallow here.", "Jana mabal yaluy nyajil.", "jana mabal yaluy nyajil | 3pl.NOM swallow here see.NPST", "r242_3pl_target_here_see_mabal", ["jana", "mabal", "yaluy", "nyajil"], EVIDENCE["mabal"]),
    row(45, "They see the domestic turkey here.", "Jana wungku yaluy nyajil.", "jana wungku yaluy nyajil | 3pl.NOM domestic.turkey here see.NPST", "r242_3pl_target_here_see_wungku", ["jana", "wungku", "yaluy", "nyajil"], EVIDENCE["wungku"]),
    row(46, "They see the dove here.", "Jana kuludu yaluy nyajil.", "jana kuludu yaluy nyajil | 3pl.NOM dove here see.NPST", "r242_3pl_target_here_see_kuludu", ["jana", "kuludu", "yaluy", "nyajil"], EVIDENCE["kuludu"]),
    row(47, "They see the kookaburra here.", "Jana kururrungka yaluy nyajil.", "jana kururrungka yaluy nyajil | 3pl.NOM kookaburra here see.NPST", "r242_3pl_target_here_see_kururrungka", ["jana", "kururrungka", "yaluy", "nyajil"], EVIDENCE["kururrungka"]),
    row(48, "They see the king parrot here.", "Jana karrambil yaluy nyajil.", "jana karrambil yaluy nyajil | 3pl.NOM king.parrot here see.NPST", "r242_3pl_target_here_see_karrambil", ["jana", "karrambil", "yaluy", "nyajil"], EVIDENCE["karrambil"]),
    row(49, "They see the parrot here.", "Jana yinjul yaluy nyajil.", "jana yinjul yaluy nyajil | 3pl.NOM parrot here see.NPST", "r242_3pl_target_here_see_yinjul", ["jana", "yinjul", "yaluy", "nyajil"], EVIDENCE["yinjul"]),
    row(50, "They see the black cockatoo here.", "Jana kadanji yaluy nyajil.", "jana kadanji yaluy nyajil | 3pl.NOM black.cockatoo here see.NPST", "r242_3pl_target_here_see_kadanji", ["jana", "kadanji", "yaluy", "nyajil"], EVIDENCE["kadanji"]),
]


def has_token(low: str, token: str) -> bool:
    return re.search(rf"(?<![a-z-]){re.escape(token)}(?![a-z-])", low) is not None


def has_target_morphology(low: str, head: str) -> bool:
    suffixes = "ngka|ngku|angka|nga|ngu|ba|mba|mbu|muny|darr|burr|bu|ka|nka|nku|ji|jirr|ku|mundu|amu|mu|iji|nda|ndu|anda|undu|unji|nji|kari|baka|baja|bungal|bungan|mal|man|rriny|karra|manda|bulal"
    return re.search(rf"(?<![a-z-]){re.escape(head)}-(?:{suffixes})\b", low) is not None


def english_has_denied(english_low: str, denied: str) -> bool:
    return denied in english_low if " " in denied else re.search(rf"\b{re.escape(denied.strip())}\b", english_low) is not None


def scan_static() -> list[str]:
    issues: list[str] = []
    if len(ROWS) != 50:
        issues.append(f"{LABEL}: expected 50 rows, found {len(ROWS)}")
    seen_ku: set[str] = set()
    for expected, row_data in enumerate(ROWS, start=1):
        seq, english, kuku, analysis, frame, _tier, words_used, loans_used, evidence, confidence = row_data
        label = f"{LABEL}.{seq:02d}"
        low = kuku.lower()
        english_low = english.lower()
        words = json.loads(words_used)
        if seq != expected:
            issues.append(f"{label}: sequence mismatch; expected {expected}")
        if not english[:1].isupper() or english[-1:] not in ".!?":
            issues.append(f"{label}: English punctuation/capitalization failure")
        if " | " not in analysis:
            issues.append(f"{label}: analysis missing gloss separator")
        if not frame.startswith("r242_"):
            issues.append(f"{label}: Rule 242 frame must start with r242_")
        if low in seen_ku:
            issues.append(f"{label}: duplicate Kuku surface within batch")
        seen_ku.add(low)
        if json.loads(loans_used):
            issues.append(f"{label}: no loans are admitted in Rule 242")
        for denied in DENY_KUKU:
            if has_token(low, denied):
                issues.append(f"{label}: denied carry-forward token {denied!r}")
        targets = [head for head in TARGET_HEADS if has_token(low, head)]
        if len(targets) != 1:
            issues.append(f"{label}: expected exactly one Rule 242 target bird noun, found {targets}")
        for head in targets:
            selected = TARGET_HEADS[head]
            dotted = selected.replace("-", ".").replace(" ", ".")
            if head not in words:
                issues.append(f"{label}: target head {head} missing from words_used")
            if selected not in english_low:
                issues.append(f"{label}: English must include selected sense {selected!r}")
            if selected not in analysis and dotted not in analysis:
                issues.append(f"{label}: analysis must gloss {head} as {selected}")
            if has_target_morphology(low, head):
                issues.append(f"{label}: target head {head} has forbidden morphology")
        for support in SUPPORT:
            if has_token(low, support) and support not in words:
                issues.append(f"{label}: support {support} missing from words_used")
        pronouns = [pronoun for pronoun in PRONOUN_SUPPORT if has_token(low, pronoun)]
        if len(pronouns) != 1:
            issues.append(f"{label}: rows require exactly one bare nominative pronoun, found {pronouns}")
        if 1 <= seq <= 10 and (not low.startswith("ngayu ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 1-10 require Ngayu TARGET yaluy nyajil")
        if 11 <= seq <= 20 and (not low.startswith("nyulu ") or not low.endswith(" yinyay nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 11-20 require Nyulu TARGET yinyay nyajil")
        if 21 <= seq <= 30 and (not low.startswith("yurra ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 21-30 require Yurra TARGET yaluy nyajil")
        if 31 <= seq <= 40 and (not low.startswith("bula ") or not low.endswith(" yinyay nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 31-40 require Bula TARGET yinyay nyajil")
        if 41 <= seq <= 50 and (not low.startswith("jana ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 41-50 require Jana TARGET yaluy nyajil")
        if any(english_has_denied(english_low, bad) for bad in DENY_ENGLISH):
            issues.append(f"{label}: denied bird behaviour/use/prose field in English")
        if not evidence or not confidence:
            issues.append(f"{label}: missing evidence/confidence")
    return issues


def main() -> int:
    issues = scan_static()
    if issues:
        print("pre-bank scan failed:")
        for issue in issues:
            print(f"  - {issue}")
        return 1

    db = sqlite3.connect(DB)
    db.execute("PRAGMA foreign_keys = ON")
    db.execute("BEGIN")
    ensure_schema(db)
    existing = db.execute("SELECT id FROM batches WHERE label=?", (LABEL,)).fetchone()
    if existing:
        batch_id = existing[0]
        accepted = db.execute(
            "SELECT COUNT(*) FROM sentences WHERE batch_id=? AND status IN ('accepted','revised')",
            (batch_id,),
        ).fetchone()[0]
        if accepted:
            raise SystemExit(f"{LABEL} already has accepted/revised rows; refusing to overwrite")
        db.execute("DELETE FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)", (batch_id,))
        db.execute("DELETE FROM lessons WHERE batch_id=?", (batch_id,))
        db.execute("DELETE FROM sentences WHERE batch_id=?", (batch_id,))
    else:
        db.execute(
            "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
            (LABEL, "Rule 242 draft", "operator-guide-2026-07-09", "draft under review", NOW),
        )
        batch_id = db.execute("SELECT id FROM batches WHERE label=?", (LABEL,)).fetchone()[0]

    collisions: list[str] = []
    for seq, _english, kuku, *_rest in ROWS:
        found = 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 IN ('accepted','revised','under_review')
            """,
            (kuku,),
        ).fetchall()
        if found:
            collisions.append(f"{seq}: {kuku} -> {found}")
    if collisions:
        raise SystemExit("collision scan failed:\n" + "\n".join(collisions))

    db.executemany(
        """
        INSERT INTO sentences(
          batch_id, seq, english, kuku, analysis, frame, tier, words_used,
          loans_used, evidence, status, confidence, created_at
        )
        VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)
        """,
        [
            (
                batch_id,
                seq,
                english,
                kuku,
                analysis,
                frame,
                tier,
                words_used,
                loans_used,
                evidence,
                "under_review",
                confidence,
                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="Rule 242 source pass retained dictionary entries for birmba straw-necked ibis, jamarbina goose, nili-nili duck, mabal swallow, wungku domestic turkey, kuludu dove, kururrungka kookaburra, karrambil king parrot, yinjul parrot, and kadanji black cockatoo; Patz 3.1.2 for fauna nouns; Patz 3.5 Table 3.6 for bare nominative pronouns; Patz 3.7 Table 3.12 for yaluy/yinyay; and Patz 3.8.3.2 for nyaji-l.",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="planning",
        event_type="construction-scope",
        actor="claude-main",
        detail="Selected Rule 242 bird-reference perception construction consolidation after Rule 241: same ten bird labels, same nonpast visual-perception skeleton, complementary yaluy/yinyay bands. Rejected bare-deictic grid before banking because exact surfaces collided for kuludu, nili-nili, and yinjul.",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="preflight",
        event_type="coverage-audit",
        actor="claude-main",
        detail="Pre-batch token-boundary coverage among accepted/revised rows after Rule 241: wungku 7, mabal 10, yinjul 12, birmba 13, kuludu 15, kadanji 16, kururrungka 16, jamarbina 19, karrambil 19, and nili-nili 27.",
        command="sqlite3 synthetic.db coverage audit",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="preflight",
        event_type="duplicate-preflight",
        actor="claude-main",
        detail="Exact duplicate preflight over all 50 planned Rule 242 complementary perception surfaces returned zero accepted, revised, or under-review collisions.",
        command="python3 batch_scripts/bank_284.py internal collision scan",
        output_excerpt="0",
        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 guards passed: 50 rows, exactly one Rule 242 target bird noun per row, exactly one bare nominative pronoun per row, no loans, no target suffixes, no excluded bird candidate, no behaviour/use/omen/totem/story/place/habitat/colour/secondary-sense drift, no pronoun case, no perception compound, and five complementary perception bands only.",
        command="python3 batch_scripts/bank_284.py",
        artifact_path="batch_scripts/bank_284.py",
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="bank",
        event_type="bank-success",
        actor="claude-main",
        detail="Banked 50 hand-authored Rule 242 bird-reference perception consolidation rows as under_review.",
        command="python3 batch_scripts/bank_284.py",
        artifact_path="batch_scripts/bank_284.py",
        created_at=NOW,
    )
    db.commit()
    print(f"banked {LABEL}: 50 under_review rows")
    return 0


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