#!/usr/bin/env python3
"""Bank batch-267: Rule 225 low-coverage non-tree flora-reference lexical expansion."""

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

TARGET_HEADS = {
    "bindi": "broad leaf",
    "dakil-dakil": "branches",
    "duduy": "bush",
    "jumbay-jumbay": "mushroom",
    "kababina": "fresh water lily",
    "kalal-kalal": "mass of vines",
    "karul-karul": "moss",
    "malari": "fern",
    "waji-waji": "stinging vine",
    "wayul": "seaweed",
}
SUPPORT = {"yinya", "yaluy", "yinyay"}
DENY_KUKU = {
    # Rule 224 named-tree targets and exact earlier tree/flora carry-forward traps.
    "jundul", "kabariji", "kawunjil", "kayjurr", "kingal", "kulbar", "kumin", "marbaji",
    "milbanku", "mujarr", "babajaka", "balmbalka", "baway", "bijin", "dalban", "dingki",
    "dulmbil", "duwar", "kalal", "kumul", "jina-jina", "jarrangkal", "julbin", "kunjarri",
    "kurruy", "malurri", "mawar", "maya", "wangay", "yawarr", "jinjajalka", "kurunkal",
    "madu", "marngkil", "marrabal", "milbarakal", "mungari", "wurmbariji", "wuymbariji",
    "kurrun", "banday", "bijan", "bukunjarra", "bulngkarr", "wanakan", "warka", "wulngkurr",
    "yalngkal", "yarun", "yumba", "buyku", "dakumbar", "jinjay", "jalnji", "ngakun",
    "mirrbangku", "miyilabu", "ngadil", "nyumbil", "marril", "wankar", "yurrunji",
    # Rejected Rule 225 source-risk candidates.
    "bajarr", "bakul", "bangkamu", "bijalabay", "bikarrakal", "binainyji", "dikirr",
    "dukul-dukul", "dukunjaka", "jika-birra", "jidu", "jumul-jumul", "junda", "junjun",
    "kakan", "kakarr", "kalbariji", "kalirrr", "kalkurr", "kangka", "kanunjul",
    "kubirr-kubirr", "kulbawurr", "makaji", "marrku", "mawu", "mawul", "milmarr",
    "muyurr", "nganjirr", "nganka", "ngara", "warrabuka", "warrur", "wubali", "wukay",
    "wulku", "yibuy",
}
DENY_ENGLISH = (
    "food", "edible", "eat", "eating", "eaten", "cook", "cooked", "cooking", "roast", "roasted",
    "medicine", "medicinal", "poison", "poisonous", "tobacco", "leach", "leaching", "root", "yam",
    "fruit", "seed", "nut", "cherry", "sweet potato", "blanket", "year", "place", "harry",
    "rain forest", "rainforest", "country", "story", "season", "storm", "thunder", "bait", "spear",
    "resin", "smoke", "necklace", "dilly bag", "weave", "weaving", "make", "making", "made", "use",
    "used", "cover", "oven", "material", "source", "gather", "gathering", "collect", "collecting",
    "habitat", "ecology", "mangrove", "owner", "ownership", "thunderstorm",
)


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 = {
    "bindi": "Dictionary bindi noun 'broad leaf' / any broad leaf. Patz section 3.1 flora noun and section 3.7 deictic support.",
    "dakil-dakil": "Dictionary dakil-dakil noun 'branches of a tree'; branch-reference only. Patz section 3.1 flora noun and section 3.7 deictic support.",
    "duduy": "Dictionary duduy noun 'bush, weeds, tangled growth'; plain bush reference only. Patz section 3.1 flora noun and section 3.7 deictic support.",
    "jumbay-jumbay": "Dictionary jumbay-jumbay noun 'mushroom'; lexicalized full reduplication only. Patz section 3.1 flora noun and section 3.7 deictic support.",
    "kababina": "Dictionary kababina noun 'fresh water lily'; rain-forest flora/fauna prose not opened. Patz section 3.1 flora noun and section 3.7 deictic support.",
    "kalal-kalal": "Dictionary kalal-kalal noun 'mass of vines'; place-name homographs closed and no productive reduplication opened. Patz section 3.1 flora noun and section 3.7 deictic support.",
    "karul-karul": "Dictionary karul-karul noun 'green scum; moss'; moss reference only and no productive reduplication opened. Patz section 3.1 flora noun and section 3.7 deictic support.",
    "malari": "Dictionary malari noun 'species of fern'. Patz section 3.1 flora noun and section 3.7 deictic support.",
    "waji-waji": "Dictionary waji-waji noun 'stinging vine'; lexical label only, no sting/event predicate. Patz section 3.1 flora noun and section 3.7 deictic support.",
    "wayul": "Dictionary wayul noun 'seaweed'. Patz section 3.1 flora noun and section 3.7 deictic support.",
}


ROWS = [
    row(1, "The broad leaf is here.", "Bindi yaluy.", "bindi yaluy | broad.leaf here", "r225_non_tree_flora_ref_here_bindi", ["bindi", "yaluy"], EVIDENCE["bindi"]),
    row(2, "The branches are here.", "Dakil-dakil yaluy.", "dakil-dakil yaluy | branches here", "r225_non_tree_flora_ref_here_dakil_dakil", ["dakil-dakil", "yaluy"], EVIDENCE["dakil-dakil"]),
    row(3, "The bush is here.", "Duduy yaluy.", "duduy yaluy | bush here", "r225_non_tree_flora_ref_here_duduy", ["duduy", "yaluy"], EVIDENCE["duduy"]),
    row(4, "The mushroom is here.", "Jumbay-jumbay yaluy.", "jumbay-jumbay yaluy | mushroom here", "r225_non_tree_flora_ref_here_jumbay_jumbay", ["jumbay-jumbay", "yaluy"], EVIDENCE["jumbay-jumbay"]),
    row(5, "The fresh water lily is here.", "Kababina yaluy.", "kababina yaluy | fresh.water.lily here", "r225_non_tree_flora_ref_here_kababina", ["kababina", "yaluy"], EVIDENCE["kababina"]),
    row(6, "The mass of vines is here.", "Kalal-kalal yaluy.", "kalal-kalal yaluy | mass.of.vines here", "r225_non_tree_flora_ref_here_kalal_kalal", ["kalal-kalal", "yaluy"], EVIDENCE["kalal-kalal"]),
    row(7, "The moss is here.", "Karul-karul yaluy.", "karul-karul yaluy | moss here", "r225_non_tree_flora_ref_here_karul_karul", ["karul-karul", "yaluy"], EVIDENCE["karul-karul"]),
    row(8, "The fern is here.", "Malari yaluy.", "malari yaluy | fern here", "r225_non_tree_flora_ref_here_malari", ["malari", "yaluy"], EVIDENCE["malari"]),
    row(9, "The stinging vine is here.", "Waji-waji yaluy.", "waji-waji yaluy | stinging.vine here", "r225_non_tree_flora_ref_here_waji_waji", ["waji-waji", "yaluy"], EVIDENCE["waji-waji"]),
    row(10, "The seaweed is here.", "Wayul yaluy.", "wayul yaluy | seaweed here", "r225_non_tree_flora_ref_here_wayul", ["wayul", "yaluy"], EVIDENCE["wayul"]),
    row(11, "The broad leaf is there.", "Bindi yinyay.", "bindi yinyay | broad.leaf there", "r225_non_tree_flora_ref_there_bindi", ["bindi", "yinyay"], EVIDENCE["bindi"]),
    row(12, "The branches are there.", "Dakil-dakil yinyay.", "dakil-dakil yinyay | branches there", "r225_non_tree_flora_ref_there_dakil_dakil", ["dakil-dakil", "yinyay"], EVIDENCE["dakil-dakil"]),
    row(13, "The bush is there.", "Duduy yinyay.", "duduy yinyay | bush there", "r225_non_tree_flora_ref_there_duduy", ["duduy", "yinyay"], EVIDENCE["duduy"]),
    row(14, "The mushroom is there.", "Jumbay-jumbay yinyay.", "jumbay-jumbay yinyay | mushroom there", "r225_non_tree_flora_ref_there_jumbay_jumbay", ["jumbay-jumbay", "yinyay"], EVIDENCE["jumbay-jumbay"]),
    row(15, "The fresh water lily is there.", "Kababina yinyay.", "kababina yinyay | fresh.water.lily there", "r225_non_tree_flora_ref_there_kababina", ["kababina", "yinyay"], EVIDENCE["kababina"]),
    row(16, "The mass of vines is there.", "Kalal-kalal yinyay.", "kalal-kalal yinyay | mass.of.vines there", "r225_non_tree_flora_ref_there_kalal_kalal", ["kalal-kalal", "yinyay"], EVIDENCE["kalal-kalal"]),
    row(17, "The moss is there.", "Karul-karul yinyay.", "karul-karul yinyay | moss there", "r225_non_tree_flora_ref_there_karul_karul", ["karul-karul", "yinyay"], EVIDENCE["karul-karul"]),
    row(18, "The fern is there.", "Malari yinyay.", "malari yinyay | fern there", "r225_non_tree_flora_ref_there_malari", ["malari", "yinyay"], EVIDENCE["malari"]),
    row(19, "The stinging vine is there.", "Waji-waji yinyay.", "waji-waji yinyay | stinging.vine there", "r225_non_tree_flora_ref_there_waji_waji", ["waji-waji", "yinyay"], EVIDENCE["waji-waji"]),
    row(20, "The seaweed is there.", "Wayul yinyay.", "wayul yinyay | seaweed there", "r225_non_tree_flora_ref_there_wayul", ["wayul", "yinyay"], EVIDENCE["wayul"]),
    row(21, "That broad leaf is there.", "Yinya bindi yinyay.", "yinya bindi yinyay | that broad.leaf there", "r225_that_non_tree_flora_ref_there_bindi", ["yinya", "bindi", "yinyay"], EVIDENCE["bindi"]),
    row(22, "Those branches are there.", "Yinya dakil-dakil yinyay.", "yinya dakil-dakil yinyay | those branches there", "r225_that_non_tree_flora_ref_there_dakil_dakil", ["yinya", "dakil-dakil", "yinyay"], EVIDENCE["dakil-dakil"]),
    row(23, "That bush is there.", "Yinya duduy yinyay.", "yinya duduy yinyay | that bush there", "r225_that_non_tree_flora_ref_there_duduy", ["yinya", "duduy", "yinyay"], EVIDENCE["duduy"]),
    row(24, "That mushroom is there.", "Yinya jumbay-jumbay yinyay.", "yinya jumbay-jumbay yinyay | that mushroom there", "r225_that_non_tree_flora_ref_there_jumbay_jumbay", ["yinya", "jumbay-jumbay", "yinyay"], EVIDENCE["jumbay-jumbay"]),
    row(25, "That fresh water lily is there.", "Yinya kababina yinyay.", "yinya kababina yinyay | that fresh.water.lily there", "r225_that_non_tree_flora_ref_there_kababina", ["yinya", "kababina", "yinyay"], EVIDENCE["kababina"]),
    row(26, "That mass of vines is there.", "Yinya kalal-kalal yinyay.", "yinya kalal-kalal yinyay | that mass.of.vines there", "r225_that_non_tree_flora_ref_there_kalal_kalal", ["yinya", "kalal-kalal", "yinyay"], EVIDENCE["kalal-kalal"]),
    row(27, "That moss is there.", "Yinya karul-karul yinyay.", "yinya karul-karul yinyay | that moss there", "r225_that_non_tree_flora_ref_there_karul_karul", ["yinya", "karul-karul", "yinyay"], EVIDENCE["karul-karul"]),
    row(28, "That fern is there.", "Yinya malari yinyay.", "yinya malari yinyay | that fern there", "r225_that_non_tree_flora_ref_there_malari", ["yinya", "malari", "yinyay"], EVIDENCE["malari"]),
    row(29, "That stinging vine is there.", "Yinya waji-waji yinyay.", "yinya waji-waji yinyay | that stinging.vine there", "r225_that_non_tree_flora_ref_there_waji_waji", ["yinya", "waji-waji", "yinyay"], EVIDENCE["waji-waji"]),
    row(30, "That seaweed is there.", "Yinya wayul yinyay.", "yinya wayul yinyay | that seaweed there", "r225_that_non_tree_flora_ref_there_wayul", ["yinya", "wayul", "yinyay"], EVIDENCE["wayul"]),
    row(31, "That broad leaf is there.", "Bindi yinya yinyay.", "bindi yinya yinyay | that broad.leaf there", "r225_non_tree_flora_that_there_bindi", ["bindi", "yinya", "yinyay"], EVIDENCE["bindi"]),
    row(32, "Those branches are there.", "Dakil-dakil yinya yinyay.", "dakil-dakil yinya yinyay | those branches there", "r225_non_tree_flora_that_there_dakil_dakil", ["dakil-dakil", "yinya", "yinyay"], EVIDENCE["dakil-dakil"]),
    row(33, "That bush is there.", "Duduy yinya yinyay.", "duduy yinya yinyay | that bush there", "r225_non_tree_flora_that_there_duduy", ["duduy", "yinya", "yinyay"], EVIDENCE["duduy"]),
    row(34, "That mushroom is there.", "Jumbay-jumbay yinya yinyay.", "jumbay-jumbay yinya yinyay | that mushroom there", "r225_non_tree_flora_that_there_jumbay_jumbay", ["jumbay-jumbay", "yinya", "yinyay"], EVIDENCE["jumbay-jumbay"]),
    row(35, "That fresh water lily is there.", "Kababina yinya yinyay.", "kababina yinya yinyay | that fresh.water.lily there", "r225_non_tree_flora_that_there_kababina", ["kababina", "yinya", "yinyay"], EVIDENCE["kababina"]),
    row(36, "That mass of vines is there.", "Kalal-kalal yinya yinyay.", "kalal-kalal yinya yinyay | that mass.of.vines there", "r225_non_tree_flora_that_there_kalal_kalal", ["kalal-kalal", "yinya", "yinyay"], EVIDENCE["kalal-kalal"]),
    row(37, "That moss is there.", "Karul-karul yinya yinyay.", "karul-karul yinya yinyay | that moss there", "r225_non_tree_flora_that_there_karul_karul", ["karul-karul", "yinya", "yinyay"], EVIDENCE["karul-karul"]),
    row(38, "That fern is there.", "Malari yinya yinyay.", "malari yinya yinyay | that fern there", "r225_non_tree_flora_that_there_malari", ["malari", "yinya", "yinyay"], EVIDENCE["malari"]),
    row(39, "That stinging vine is there.", "Waji-waji yinya yinyay.", "waji-waji yinya yinyay | that stinging.vine there", "r225_non_tree_flora_that_there_waji_waji", ["waji-waji", "yinya", "yinyay"], EVIDENCE["waji-waji"]),
    row(40, "That seaweed is there.", "Wayul yinya yinyay.", "wayul yinya yinyay | that seaweed there", "r225_non_tree_flora_that_there_wayul", ["wayul", "yinya", "yinyay"], EVIDENCE["wayul"]),
    row(41, "That broad leaf is here.", "Yinya bindi yaluy.", "yinya bindi yaluy | that broad.leaf here", "r225_that_non_tree_flora_ref_here_bindi", ["yinya", "bindi", "yaluy"], EVIDENCE["bindi"]),
    row(42, "Those branches are here.", "Yinya dakil-dakil yaluy.", "yinya dakil-dakil yaluy | those branches here", "r225_that_non_tree_flora_ref_here_dakil_dakil", ["yinya", "dakil-dakil", "yaluy"], EVIDENCE["dakil-dakil"]),
    row(43, "That bush is here.", "Yinya duduy yaluy.", "yinya duduy yaluy | that bush here", "r225_that_non_tree_flora_ref_here_duduy", ["yinya", "duduy", "yaluy"], EVIDENCE["duduy"]),
    row(44, "That mushroom is here.", "Yinya jumbay-jumbay yaluy.", "yinya jumbay-jumbay yaluy | that mushroom here", "r225_that_non_tree_flora_ref_here_jumbay_jumbay", ["yinya", "jumbay-jumbay", "yaluy"], EVIDENCE["jumbay-jumbay"]),
    row(45, "That fresh water lily is here.", "Yinya kababina yaluy.", "yinya kababina yaluy | that fresh.water.lily here", "r225_that_non_tree_flora_ref_here_kababina", ["yinya", "kababina", "yaluy"], EVIDENCE["kababina"]),
    row(46, "That mass of vines is here.", "Yinya kalal-kalal yaluy.", "yinya kalal-kalal yaluy | that mass.of.vines here", "r225_that_non_tree_flora_ref_here_kalal_kalal", ["yinya", "kalal-kalal", "yaluy"], EVIDENCE["kalal-kalal"]),
    row(47, "That moss is here.", "Yinya karul-karul yaluy.", "yinya karul-karul yaluy | that moss here", "r225_that_non_tree_flora_ref_here_karul_karul", ["yinya", "karul-karul", "yaluy"], EVIDENCE["karul-karul"]),
    row(48, "That fern is here.", "Yinya malari yaluy.", "yinya malari yaluy | that fern here", "r225_that_non_tree_flora_ref_here_malari", ["yinya", "malari", "yaluy"], EVIDENCE["malari"]),
    row(49, "That stinging vine is here.", "Yinya waji-waji yaluy.", "yinya waji-waji yaluy | that stinging.vine here", "r225_that_non_tree_flora_ref_here_waji_waji", ["yinya", "waji-waji", "yaluy"], EVIDENCE["waji-waji"]),
    row(50, "That seaweed is here.", "Yinya wayul yaluy.", "yinya wayul yaluy | that seaweed here", "r225_that_non_tree_flora_ref_here_wayul", ["yinya", "wayul", "yaluy"], EVIDENCE["wayul"]),
]


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"
    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("r225_"):
            issues.append(f"{label}: Rule 225 frame must start with r225_")
        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 225")
        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 225 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")
        for support in SUPPORT:
            if has_token(low, support) and support not in words:
                issues.append(f"{label}: support {support} missing from words_used")
        if 1 <= seq <= 10 and (has_token(low, "yinya") or has_token(low, "yinyay") or not low.endswith(" yaluy.") or len(low.split()) != 2):
            issues.append(f"{label}: rows 1-10 require TARGET yaluy")
        if 11 <= seq <= 20 and (has_token(low, "yinya") or has_token(low, "yaluy") or not low.endswith(" yinyay.") or len(low.split()) != 2):
            issues.append(f"{label}: rows 11-20 require TARGET yinyay")
        if 21 <= seq <= 30 and (not low.startswith("yinya ") or has_token(low, "yaluy") or not low.endswith(" yinyay.") or len(low.split()) != 3):
            issues.append(f"{label}: rows 21-30 require Yinya TARGET yinyay")
        if 31 <= seq <= 40 and (not has_token(low, "yinya") or has_token(low, "yaluy") or not low.endswith(" yinyay.") or len(low.split()) != 3 or low.startswith("yinya ")):
            issues.append(f"{label}: rows 31-40 require TARGET yinya yinyay")
        if 41 <= seq <= 50 and (not low.startswith("yinya ") or has_token(low, "yinyay") or not low.endswith(" yaluy.") or len(low.split()) != 3):
            issues.append(f"{label}: rows 41-50 require Yinya TARGET yaluy")
        if any(english_has_denied(english_low, bad) for bad in DENY_ENGLISH):
            issues.append(f"{label}: denied plant-use/food/material/place/source-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 sentences WHERE batch_id=?", (batch_id,))
    else:
        db.execute(
            "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
            (LABEL, "Rule 225 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 Patz section 3.1 noun/flora basis, Patz section 3.7 yinya/yaluy/yinyay support, and dictionary entries for bindi, dakil-dakil, duduy, jumbay-jumbay, kababina, kalal-kalal, karul-karul, malari, waji-waji, and wayul. Admitted only selected bare non-tree flora-reference labels.",
        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 non-tree flora-reference field after excluding food/edible/root/yam/fruit/nut/seed candidates, medicine/poison/tobacco/resin/storm-control candidates, material/use/manufacture candidates, homograph-heavy kakarr, and all Rule 224 named-tree targets. Kalal-kalal admitted only in its mass-of-vines sense; place-name homographs closed.",
        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 225 Kuku surfaces returned no accepted, revised, or under-review collisions.",
        artifact_path="batch_scripts/bank_267.py",
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="preflight",
        event_type="static-guard-pass",
        actor="claude-main",
        detail="bank_267.py static guards passed: 50 explicit hand-authored rows, exactly one non-tree flora-reference target noun per row, no loans, no target morphology, no plant-use/food/material/place/source-prose English, and only the five sourced deictic frame bands.",
        artifact_path="batch_scripts/bank_267.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_used, loans_used, evidence, "under_review", confidence, NOW, NOW)
            for seq, english, kuku, analysis, frame, tier, words_used, loans_used, evidence, confidence in ROWS
        ],
    )
    db.commit()

    n = db.execute("SELECT COUNT(*) FROM sentences WHERE batch_id=? AND status='under_review'", (batch_id,)).fetchone()[0]
    print(f"banked {LABEL}: {n} under_review rows")
    return 0


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