#!/usr/bin/env python3
"""Bank batch-269: Rule 227 low-coverage weather-condition references."""

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-269"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-269-low-coverage-weather-condition-reference-lexical-expansion-after-rule226-process.md"

TARGET_HEADS = {
    "balbay": "lightning",
    "jiri bajaku": "cloudless sky",
    "jirimali": "fine day",
    "jukar-warra": "whirlwind",
    "kumbamu": "trade wind",
    "kurrinkurrin": "mackerel sky",
    "nganyil": "haze",
    "ngurrbal": "fog",
    "wadjal": "cyclone",
    "wurrbal": "river mist",
}
VISUAL_TARGETS = {"balbay", "jiri bajaku", "jirimali", "jukar-warra", "kurrinkurrin", "nganyil", "ngurrbal", "wadjal", "wurrbal"}
HEARD_TARGETS = {"kumbamu"}
SUPPORT = {"yaluy", "yinyay", "nyajil", "nyajin", "ngayu", "ngana", "yundu", "jana"}
DENY_KUKU = {
    "balbay-nja", "balbaynja",
    "kaba", "muyar", "ngurrban", "wungar", "kija", "yiril", "jarramali", "jabulbina",
    "kurrubijal", "wurunurru", "binyu", "nulu", "dalngarri", "minji", "jalungkarr",
    "yira", "wangariji", "kiway", "wujurr",
}
DENY_ENGLISH = (
    "fall", "fell", "falling", "strike", "struck", "storm action", "warning", "warn", "predict",
    "prediction", "omen", "death", "dead", "spirit", "story", "place name", "season", "month",
    "sunrise", "sunset", "rain falls", "rain fell", "wind blows", "wind blew", "comes", "came",
    "flood", "tide", "ashes", "pus", "urine", "fire", "burn", "burning", "source", "control",
    "danger", "safe", "unsafe", "damage", "destroy", "destruction", "river rises", "rising from",
)


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, 2, js(words), js([]), evidence, "0.86")


EVIDENCE = {
    "balbay": "Dictionary balbay noun 'lightning'; blocked strike forms balbay-nja/balbaynja stay closed. Rules 153-154 source weather perception/deictic frames.",
    "jiri bajaku": "Dictionary jiri bajaku noun 'fine day, cloudless sky'; batch uses cloudless-sky/fine-day reference only. Rules 153-154 source weather perception/deictic frames.",
    "jirimali": "Dictionary jirimali noun 'fine day, cloudless sky'; batch uses fine-day reference only. Rules 153-154 source weather perception/deictic frames.",
    "jukar-warra": "Dictionary jukar-warra noun 'whirlwind'; sand component is lexicalized, no sand/source row. Rules 153-154 source weather perception/deictic frames.",
    "kumbamu": "Dictionary kumbamu noun 'trade wind, fair wind'; batch uses trade-wind reference only. Rules 153-154 source weather perception/deictic frames.",
    "kurrinkurrin": "Dictionary kurrinkurrin noun 'mackerel sky', marked reduplicated form; admitted as lexicalized solid headword only. Rules 153-154 source weather perception/deictic frames.",
    "nganyil": "Dictionary nganyil noun 'haze, mist'; batch uses haze reference only. Rules 153-154 source weather perception/deictic frames.",
    "ngurrbal": "Dictionary ngurrbal noun 'fog'. Rules 153-154 source weather perception/deictic frames.",
    "wadjal": "Dictionary wadjal noun 'cyclone'. Rules 153-154 source weather perception/deictic frames; no storm-action or warning row.",
    "wurrbal": "Dictionary wurrbal noun 'fog, mist rising from the river'; batch uses river-mist reference only, no rising/event frame. Rules 153-154 source weather perception/deictic frames.",
}


ROWS = [
    row(1, "The lightning is here.", "Balbay yaluy.", "balbay yaluy | lightning here", "r227_weather_ref_here_balbay", ["balbay", "yaluy"], EVIDENCE["balbay"]),
    row(2, "The cloudless sky is here.", "Jiri bajaku yaluy.", "jiri bajaku yaluy | cloudless.sky here", "r227_weather_ref_here_jiri_bajaku", ["jiri bajaku", "yaluy"], EVIDENCE["jiri bajaku"]),
    row(3, "The fine day is here.", "Jirimali yaluy.", "jirimali yaluy | fine.day here", "r227_weather_ref_here_jirimali", ["jirimali", "yaluy"], EVIDENCE["jirimali"]),
    row(4, "The whirlwind is here.", "Jukar-warra yaluy.", "jukar-warra yaluy | whirlwind here", "r227_weather_ref_here_jukar_warra", ["jukar-warra", "yaluy"], EVIDENCE["jukar-warra"]),
    row(5, "The trade wind is here.", "Kumbamu yaluy.", "kumbamu yaluy | trade.wind here", "r227_weather_ref_here_kumbamu", ["kumbamu", "yaluy"], EVIDENCE["kumbamu"]),
    row(6, "The mackerel sky is here.", "Kurrinkurrin yaluy.", "kurrinkurrin yaluy | mackerel.sky here", "r227_weather_ref_here_kurrinkurrin", ["kurrinkurrin", "yaluy"], EVIDENCE["kurrinkurrin"]),
    row(7, "The haze is here.", "Nganyil yaluy.", "nganyil yaluy | haze here", "r227_weather_ref_here_nganyil", ["nganyil", "yaluy"], EVIDENCE["nganyil"]),
    row(8, "The fog is here.", "Ngurrbal yaluy.", "ngurrbal yaluy | fog here", "r227_weather_ref_here_ngurrbal", ["ngurrbal", "yaluy"], EVIDENCE["ngurrbal"]),
    row(9, "The cyclone is here.", "Wadjal yaluy.", "wadjal yaluy | cyclone here", "r227_weather_ref_here_wadjal", ["wadjal", "yaluy"], EVIDENCE["wadjal"]),
    row(10, "The river mist is here.", "Wurrbal yaluy.", "wurrbal yaluy | river.mist here", "r227_weather_ref_here_wurrbal", ["wurrbal", "yaluy"], EVIDENCE["wurrbal"]),
    row(11, "I see the lightning there.", "Ngayu balbay yinyay nyajil.", "ngayu balbay yinyay nyajil | I lightning there perceive.NONPAST", "r227_1sg_weather_ref_there_balbay", ["ngayu", "balbay", "yinyay", "nyajil"], EVIDENCE["balbay"]),
    row(12, "I see the cloudless sky there.", "Ngayu jiri bajaku yinyay nyajil.", "ngayu jiri bajaku yinyay nyajil | I cloudless.sky there perceive.NONPAST", "r227_1sg_weather_ref_there_jiri_bajaku", ["ngayu", "jiri bajaku", "yinyay", "nyajil"], EVIDENCE["jiri bajaku"]),
    row(13, "I see the fine day there.", "Ngayu jirimali yinyay nyajil.", "ngayu jirimali yinyay nyajil | I fine.day there perceive.NONPAST", "r227_1sg_weather_ref_there_jirimali", ["ngayu", "jirimali", "yinyay", "nyajil"], EVIDENCE["jirimali"]),
    row(14, "I see the whirlwind there.", "Ngayu jukar-warra yinyay nyajil.", "ngayu jukar-warra yinyay nyajil | I whirlwind there perceive.NONPAST", "r227_1sg_weather_ref_there_jukar_warra", ["ngayu", "jukar-warra", "yinyay", "nyajil"], EVIDENCE["jukar-warra"]),
    row(15, "I hear the trade wind there.", "Ngayu kumbamu yinyay nyajil.", "ngayu kumbamu yinyay nyajil | I trade.wind there perceive.NONPAST", "r227_1sg_weather_ref_there_kumbamu", ["ngayu", "kumbamu", "yinyay", "nyajil"], EVIDENCE["kumbamu"]),
    row(16, "I see the mackerel sky there.", "Ngayu kurrinkurrin yinyay nyajil.", "ngayu kurrinkurrin yinyay nyajil | I mackerel.sky there perceive.NONPAST", "r227_1sg_weather_ref_there_kurrinkurrin", ["ngayu", "kurrinkurrin", "yinyay", "nyajil"], EVIDENCE["kurrinkurrin"]),
    row(17, "I see the haze there.", "Ngayu nganyil yinyay nyajil.", "ngayu nganyil yinyay nyajil | I haze there perceive.NONPAST", "r227_1sg_weather_ref_there_nganyil", ["ngayu", "nganyil", "yinyay", "nyajil"], EVIDENCE["nganyil"]),
    row(18, "I see the fog there.", "Ngayu ngurrbal yinyay nyajil.", "ngayu ngurrbal yinyay nyajil | I fog there perceive.NONPAST", "r227_1sg_weather_ref_there_ngurrbal", ["ngayu", "ngurrbal", "yinyay", "nyajil"], EVIDENCE["ngurrbal"]),
    row(19, "I see the cyclone there.", "Ngayu wadjal yinyay nyajil.", "ngayu wadjal yinyay nyajil | I cyclone there perceive.NONPAST", "r227_1sg_weather_ref_there_wadjal", ["ngayu", "wadjal", "yinyay", "nyajil"], EVIDENCE["wadjal"]),
    row(20, "I see the river mist there.", "Ngayu wurrbal yinyay nyajil.", "ngayu wurrbal yinyay nyajil | I river.mist there perceive.NONPAST", "r227_1sg_weather_ref_there_wurrbal", ["ngayu", "wurrbal", "yinyay", "nyajil"], EVIDENCE["wurrbal"]),
    row(21, "We see the lightning there.", "Ngana balbay yinyay nyajil.", "ngana balbay yinyay nyajil | we lightning there perceive.NONPAST", "r227_1pl_weather_ref_there_balbay", ["ngana", "balbay", "yinyay", "nyajil"], EVIDENCE["balbay"]),
    row(22, "We see the cloudless sky there.", "Ngana jiri bajaku yinyay nyajil.", "ngana jiri bajaku yinyay nyajil | we cloudless.sky there perceive.NONPAST", "r227_1pl_weather_ref_there_jiri_bajaku", ["ngana", "jiri bajaku", "yinyay", "nyajil"], EVIDENCE["jiri bajaku"]),
    row(23, "We see the fine day there.", "Ngana jirimali yinyay nyajil.", "ngana jirimali yinyay nyajil | we fine.day there perceive.NONPAST", "r227_1pl_weather_ref_there_jirimali", ["ngana", "jirimali", "yinyay", "nyajil"], EVIDENCE["jirimali"]),
    row(24, "We see the whirlwind there.", "Ngana jukar-warra yinyay nyajil.", "ngana jukar-warra yinyay nyajil | we whirlwind there perceive.NONPAST", "r227_1pl_weather_ref_there_jukar_warra", ["ngana", "jukar-warra", "yinyay", "nyajil"], EVIDENCE["jukar-warra"]),
    row(25, "We hear the trade wind there.", "Ngana kumbamu yinyay nyajil.", "ngana kumbamu yinyay nyajil | we trade.wind there perceive.NONPAST", "r227_1pl_weather_ref_there_kumbamu", ["ngana", "kumbamu", "yinyay", "nyajil"], EVIDENCE["kumbamu"]),
    row(26, "We see the mackerel sky there.", "Ngana kurrinkurrin yinyay nyajil.", "ngana kurrinkurrin yinyay nyajil | we mackerel.sky there perceive.NONPAST", "r227_1pl_weather_ref_there_kurrinkurrin", ["ngana", "kurrinkurrin", "yinyay", "nyajil"], EVIDENCE["kurrinkurrin"]),
    row(27, "We see the haze there.", "Ngana nganyil yinyay nyajil.", "ngana nganyil yinyay nyajil | we haze there perceive.NONPAST", "r227_1pl_weather_ref_there_nganyil", ["ngana", "nganyil", "yinyay", "nyajil"], EVIDENCE["nganyil"]),
    row(28, "We see the fog there.", "Ngana ngurrbal yinyay nyajil.", "ngana ngurrbal yinyay nyajil | we fog there perceive.NONPAST", "r227_1pl_weather_ref_there_ngurrbal", ["ngana", "ngurrbal", "yinyay", "nyajil"], EVIDENCE["ngurrbal"]),
    row(29, "We see the cyclone there.", "Ngana wadjal yinyay nyajil.", "ngana wadjal yinyay nyajil | we cyclone there perceive.NONPAST", "r227_1pl_weather_ref_there_wadjal", ["ngana", "wadjal", "yinyay", "nyajil"], EVIDENCE["wadjal"]),
    row(30, "We see the river mist there.", "Ngana wurrbal yinyay nyajil.", "ngana wurrbal yinyay nyajil | we river.mist there perceive.NONPAST", "r227_1pl_weather_ref_there_wurrbal", ["ngana", "wurrbal", "yinyay", "nyajil"], EVIDENCE["wurrbal"]),
    row(31, "You see the lightning here.", "Yundu balbay yaluy nyajil.", "yundu balbay yaluy nyajil | you lightning here perceive.NONPAST", "r227_2sg_weather_ref_here_balbay", ["yundu", "balbay", "yaluy", "nyajil"], EVIDENCE["balbay"]),
    row(32, "You see the cloudless sky here.", "Yundu jiri bajaku yaluy nyajil.", "yundu jiri bajaku yaluy nyajil | you cloudless.sky here perceive.NONPAST", "r227_2sg_weather_ref_here_jiri_bajaku", ["yundu", "jiri bajaku", "yaluy", "nyajil"], EVIDENCE["jiri bajaku"]),
    row(33, "You see the fine day here.", "Yundu jirimali yaluy nyajil.", "yundu jirimali yaluy nyajil | you fine.day here perceive.NONPAST", "r227_2sg_weather_ref_here_jirimali", ["yundu", "jirimali", "yaluy", "nyajil"], EVIDENCE["jirimali"]),
    row(34, "You see the whirlwind here.", "Yundu jukar-warra yaluy nyajil.", "yundu jukar-warra yaluy nyajil | you whirlwind here perceive.NONPAST", "r227_2sg_weather_ref_here_jukar_warra", ["yundu", "jukar-warra", "yaluy", "nyajil"], EVIDENCE["jukar-warra"]),
    row(35, "You hear the trade wind here.", "Yundu kumbamu yaluy nyajil.", "yundu kumbamu yaluy nyajil | you trade.wind here perceive.NONPAST", "r227_2sg_weather_ref_here_kumbamu", ["yundu", "kumbamu", "yaluy", "nyajil"], EVIDENCE["kumbamu"]),
    row(36, "You see the mackerel sky here.", "Yundu kurrinkurrin yaluy nyajil.", "yundu kurrinkurrin yaluy nyajil | you mackerel.sky here perceive.NONPAST", "r227_2sg_weather_ref_here_kurrinkurrin", ["yundu", "kurrinkurrin", "yaluy", "nyajil"], EVIDENCE["kurrinkurrin"]),
    row(37, "You see the haze here.", "Yundu nganyil yaluy nyajil.", "yundu nganyil yaluy nyajil | you haze here perceive.NONPAST", "r227_2sg_weather_ref_here_nganyil", ["yundu", "nganyil", "yaluy", "nyajil"], EVIDENCE["nganyil"]),
    row(38, "You see the fog here.", "Yundu ngurrbal yaluy nyajil.", "yundu ngurrbal yaluy nyajil | you fog here perceive.NONPAST", "r227_2sg_weather_ref_here_ngurrbal", ["yundu", "ngurrbal", "yaluy", "nyajil"], EVIDENCE["ngurrbal"]),
    row(39, "You see the cyclone here.", "Yundu wadjal yaluy nyajil.", "yundu wadjal yaluy nyajil | you cyclone here perceive.NONPAST", "r227_2sg_weather_ref_here_wadjal", ["yundu", "wadjal", "yaluy", "nyajil"], EVIDENCE["wadjal"]),
    row(40, "You see the river mist here.", "Yundu wurrbal yaluy nyajil.", "yundu wurrbal yaluy nyajil | you river.mist here perceive.NONPAST", "r227_2sg_weather_ref_here_wurrbal", ["yundu", "wurrbal", "yaluy", "nyajil"], EVIDENCE["wurrbal"]),
    row(41, "They saw the lightning here.", "Jana balbay yaluy nyajin.", "jana balbay yaluy nyajin | they lightning here perceive.PAST", "r227_3pl_weather_ref_here_balbay", ["jana", "balbay", "yaluy", "nyajin"], EVIDENCE["balbay"]),
    row(42, "They saw the cloudless sky here.", "Jana jiri bajaku yaluy nyajin.", "jana jiri bajaku yaluy nyajin | they cloudless.sky here perceive.PAST", "r227_3pl_weather_ref_here_jiri_bajaku", ["jana", "jiri bajaku", "yaluy", "nyajin"], EVIDENCE["jiri bajaku"]),
    row(43, "They saw the fine day here.", "Jana jirimali yaluy nyajin.", "jana jirimali yaluy nyajin | they fine.day here perceive.PAST", "r227_3pl_weather_ref_here_jirimali", ["jana", "jirimali", "yaluy", "nyajin"], EVIDENCE["jirimali"]),
    row(44, "They saw the whirlwind here.", "Jana jukar-warra yaluy nyajin.", "jana jukar-warra yaluy nyajin | they whirlwind here perceive.PAST", "r227_3pl_weather_ref_here_jukar_warra", ["jana", "jukar-warra", "yaluy", "nyajin"], EVIDENCE["jukar-warra"]),
    row(45, "They heard the trade wind here.", "Jana kumbamu yaluy nyajin.", "jana kumbamu yaluy nyajin | they trade.wind here perceive.PAST", "r227_3pl_weather_ref_here_kumbamu", ["jana", "kumbamu", "yaluy", "nyajin"], EVIDENCE["kumbamu"]),
    row(46, "They saw the mackerel sky here.", "Jana kurrinkurrin yaluy nyajin.", "jana kurrinkurrin yaluy nyajin | they mackerel.sky here perceive.PAST", "r227_3pl_weather_ref_here_kurrinkurrin", ["jana", "kurrinkurrin", "yaluy", "nyajin"], EVIDENCE["kurrinkurrin"]),
    row(47, "They saw the haze here.", "Jana nganyil yaluy nyajin.", "jana nganyil yaluy nyajin | they haze here perceive.PAST", "r227_3pl_weather_ref_here_nganyil", ["jana", "nganyil", "yaluy", "nyajin"], EVIDENCE["nganyil"]),
    row(48, "They saw the fog here.", "Jana ngurrbal yaluy nyajin.", "jana ngurrbal yaluy nyajin | they fog here perceive.PAST", "r227_3pl_weather_ref_here_ngurrbal", ["jana", "ngurrbal", "yaluy", "nyajin"], EVIDENCE["ngurrbal"]),
    row(49, "They saw the cyclone here.", "Jana wadjal yaluy nyajin.", "jana wadjal yaluy nyajin | they cyclone here perceive.PAST", "r227_3pl_weather_ref_here_wadjal", ["jana", "wadjal", "yaluy", "nyajin"], EVIDENCE["wadjal"]),
    row(50, "They saw the river mist here.", "Jana wurrbal yaluy nyajin.", "jana wurrbal yaluy nyajin | they river.mist here perceive.PAST", "r227_3pl_weather_ref_here_wurrbal", ["jana", "wurrbal", "yaluy", "nyajin"], EVIDENCE["wurrbal"]),
]


def has_expr(low: str, expr: str) -> bool:
    return re.search(rf"(?<![a-z-]){re.escape(expr)}(?![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"
    last = head.split()[-1]
    return re.search(rf"(?<![a-z-]){re.escape(last)}-(?:{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("r227_"):
            issues.append(f"{label}: Rule 227 frame must start with r227_")
        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 227")
        for denied in DENY_KUKU:
            if has_expr(low, denied):
                issues.append(f"{label}: denied carry-forward token {denied!r}")
        targets = [head for head in TARGET_HEADS if has_expr(low, head)]
        if len(targets) != 1:
            issues.append(f"{label}: expected exactly one Rule 227 target 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")
            if head in HEARD_TARGETS and "hear" not in english_low and seq > 10:
                issues.append(f"{label}: trade-wind perception rows should use hear/heard English")
            if head in VISUAL_TARGETS and seq > 10 and not ("see" in english_low or "saw" in english_low):
                issues.append(f"{label}: visual weather rows should use see/saw English")
        for support in SUPPORT:
            if has_expr(low, support) and support not in words:
                issues.append(f"{label}: support {support} missing from words_used")
        if 1 <= seq <= 10 and (not low.endswith(" yaluy.") or has_expr(low, "nyajil") or has_expr(low, "nyajin")):
            issues.append(f"{label}: rows 1-10 require TARGET yaluy")
        if 11 <= seq <= 20 and (not low.startswith("ngayu ") or not low.endswith(" yinyay nyajil.") or has_expr(low, "yaluy")):
            issues.append(f"{label}: rows 11-20 require Ngayu TARGET yinyay nyajil")
        if 21 <= seq <= 30 and (not low.startswith("ngana ") or not low.endswith(" yinyay nyajil.") or has_expr(low, "yaluy")):
            issues.append(f"{label}: rows 21-30 require Ngana TARGET yinyay nyajil")
        if 31 <= seq <= 40 and (not low.startswith("yundu ") or not low.endswith(" yaluy nyajil.") or has_expr(low, "yinyay")):
            issues.append(f"{label}: rows 31-40 require Yundu TARGET yaluy nyajil")
        if 41 <= seq <= 50 and (not low.startswith("jana ") or not low.endswith(" yaluy nyajin.") or has_expr(low, "yinyay")):
            issues.append(f"{label}: rows 41-50 require Jana TARGET yaluy nyajin")
        if any(english_has_denied(english_low, bad) for bad in DENY_ENGLISH):
            issues.append(f"{label}: denied weather-event/omen/story/season/source 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 sentences WHERE batch_id=?", (batch_id,))
    else:
        db.execute(
            "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
            (LABEL, "Rule 227 draft", "operator-guide-2026-07-08", "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:02d} {kuku}: {found}")
    if collisions:
        raise SystemExit("duplicate preflight failed:\n" + "\n".join(collisions))

    record_event(
        db,
        batch_label=LABEL,
        phase="source",
        event_type="source-pass",
        actor="claude-main",
        detail="Checked Rules 153-154 weather/sky perception and deictic support, Patz section 3.7 yaluy/yinyay support, nyaji-l perception law, and dictionary entries for balbay, jiri bajaku, jirimali, jukar-warra, kumbamu, kurrinkurrin, nganyil, ngurrbal, wadjal, and wurrbal.",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="scope",
        event_type="candidate-rejection",
        actor="claude-main",
        detail="Selected a low-coverage weather-condition reference field after excluding Rule 153 exact targets, death/spirit/omen entries, moon/place/story entries, polysemous thunder/praying-mantis/stingray entries, fire/pus/urine entries, flood/tide/season/cold/darkness entries, and exact planned-surface collisions for wurunurru.",
        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 227 Kuku surfaces returned no accepted, revised, or under-review collisions.",
        command="sqlite3 exact lower(kuku) collision scan for 50 planned surfaces",
        output_excerpt="collisions=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="bank_269.py static guards passed: 50 explicit hand-authored rows, exactly one weather-condition target per row, no loans, no target morphology, no weather-event/omen/story/season/source English, and only the five sourced deictic/perception frame bands.",
        artifact_path="batch_scripts/bank_269.py",
        created_at=NOW,
    )

    db.executemany(
        """
        INSERT INTO sentences(
          batch_id, seq, english, kuku, analysis, frame, tier, words_used,
          loans_used, evidence, status, confidence, created_at, updated_at
        )
        VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)
        """,
        [
            (batch_id, seq, english, kuku, analysis, frame, tier, words, loans, evidence, "under_review", confidence, NOW, NOW)
            for seq, english, kuku, analysis, frame, tier, words, loans, evidence, confidence in ROWS
        ],
    )
    db.commit()
    print(f"banked {LABEL}: {len(ROWS)} under_review rows")
    return 0


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