#!/usr/bin/env python3
"""Bank batch-255: Rule 213 low-coverage shellfish 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-255"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-255-low-coverage-shellfish-reference-lexical-expansion-after-rule212-process.md"

TARGET_HEADS = {
    "baymbay": "large mud clam",
    "darkay": "clam",
    "kaduy": "snail",
    "karraway": "snail",
    "karruku": "ghost crab",
    "kulil": "jellyfish",
    "kuyalin": "small conical shellfish",
    "marrkabina": "oyster",
    "ngarrakaja": "shell fish",
    "nuwi": "squid",
}
SUPPORT = {"yinya", "yaluy", "yinyay"}
DENY_KUKU = {
    "kari", "yala", "yanyu", "nyaji-l", "nyajil", "nyajin",
    "nuka", "nukal", "nukan", "mani", "manil", "manin", "muja", "mujal", "mujan",
    "dunga", "dungay", "dungan", "kada", "kaday", "kadan", "wuna", "wunay", "wunan",
    "bawa", "bawal", "bawan", "waju", "wajul", "wajun", "karrba", "karrbal", "karrban",
    "kuni", "kunil", "kunin", "daya", "dayal", "yirrka", "yirrkal", "yirrkan",
    "baja", "bajaku", "bana", "baral", "bubu", "juku", "kuku", "mayi", "mukirr",
    "bilngkumu", "wubul", "karrkay", "jalbu", "bama", "ngayu", "nyulu", "yundu",
    "balarr", "dijaraban", "kalburiji", "mawal", "munudumbun", "munyurri", "nakawarra",
    "ngalmnbu", "yarrka", "yiljun", "dakaldakal", "dakal-dakal", "jalan", "kajarrbi",
}
DENY_ENGLISH = (
    "edible", "bait", "food", "eat", "eating", "eaten", "cook", "cooking", "cooked", "fry", "frying",
    "fried", "roast", "roasting", "boil", "boiling", "gather", "gathering", "collect", "collecting",
    "catch", "catching", "caught", "fishing", "spear", "spearing", "net", "netting", "hook", "line",
    "reef", "sea", "seashore", "shore", "beach", "rock", "rocks", "night", "nocturnal", "habitat",
    "water", "river", "tide", "swim", "swimming", "cling", "clinging", "move", "moving", "sting",
    "stinging", "burn", "burning", "body", "shell body", "shell-body", "prickle", "danger", "use",
    "used", "clean", "cleaning", "prepare", "preparation", "small one around here at night",
)


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")


ROWS = [
    row(1, "The large mud clam is here.", "Baymbay yaluy.", "baymbay yaluy | large.mud.clam here", "r213_deictic_here_baymbay", ["baymbay", "yaluy"], "Dictionary baymbay noun 'large mud clam'; Patz section 3.7 yaluy 'here'."),
    row(2, "The clam is here.", "Darkay yaluy.", "darkay yaluy | clam here", "r213_deictic_here_darkay", ["darkay", "yaluy"], "Dictionary darkay noun 'clam', definition 'small mud clam'; Patz section 3.7 yaluy 'here'."),
    row(3, "The snail is here.", "Kaduy yaluy.", "kaduy yaluy | snail here", "r213_deictic_here_kaduy", ["kaduy", "yaluy"], "Dictionary kaduy noun 'snail'; night/nocturnal detail closed; Patz section 3.7 yaluy."),
    row(4, "The karraway snail is here.", "Karraway yaluy.", "karraway yaluy | karraway.snail here", "r213_deictic_here_karraway", ["karraway", "yaluy"], "Dictionary karraway noun 'edible snail'; selected snail label only; edible reading closed; Patz section 3.7 yaluy."),
    row(5, "The ghost crab is here.", "Karruku yaluy.", "karruku yaluy | ghost.crab here", "r213_deictic_here_karruku", ["karruku", "yaluy"], "Dictionary karruku noun 'ghost crab, fiddler crab'; selected ghost crab label only; Patz section 3.7 yaluy."),
    row(6, "The jellyfish is here.", "Kulil yaluy.", "kulil yaluy | jellyfish here", "r213_deictic_here_kulil", ["kulil", "yaluy"], "Dictionary kulil noun 'jellyfish'; stinging/burning prose from other entries closed; Patz section 3.7 yaluy."),
    row(7, "The small conical shellfish is here.", "Kuyalin yaluy.", "kuyalin yaluy | small.conical.shellfish here", "r213_deictic_here_kuyalin", ["kuyalin", "yaluy"], "Dictionary kuyalin noun 'small conical shellfish'; bait/use reading closed; Patz section 3.7 yaluy."),
    row(8, "The oyster is here.", "Marrkabina yaluy.", "marrkabina yaluy | oyster here", "r213_deictic_here_marrkabina", ["marrkabina", "yaluy"], "Dictionary marrkabina noun 'oyster'; edible detail closed; Patz section 3.7 yaluy."),
    row(9, "The shell fish is here.", "Ngarrakaja yaluy.", "ngarrakaja yaluy | shell.fish here", "r213_deictic_here_ngarrakaja", ["ngarrakaja", "yaluy"], "Dictionary ngarrakaja noun 'shell fish'; edible/species detail closed; Patz section 3.7 yaluy."),
    row(10, "The squid is here.", "Nuwi yaluy.", "nuwi yaluy | squid here", "r213_deictic_here_nuwi", ["nuwi", "yaluy"], "Dictionary nuwi noun 'squid'; Patz section 3.7 yaluy 'here'."),
    row(11, "The large mud clam is there.", "Baymbay yinyay.", "baymbay yinyay | large.mud.clam there", "r213_deictic_there_baymbay", ["baymbay", "yinyay"], "Dictionary baymbay noun 'large mud clam'; Patz section 3.7 yinyay 'there'."),
    row(12, "The clam is there.", "Darkay yinyay.", "darkay yinyay | clam there", "r213_deictic_there_darkay", ["darkay", "yinyay"], "Dictionary darkay noun 'clam', definition 'small mud clam'; Patz section 3.7 yinyay 'there'."),
    row(13, "The snail is there.", "Kaduy yinyay.", "kaduy yinyay | snail there", "r213_deictic_there_kaduy", ["kaduy", "yinyay"], "Dictionary kaduy noun 'snail'; nocturnal source prose closed; Patz section 3.7 yinyay."),
    row(14, "The karraway snail is there.", "Karraway yinyay.", "karraway yinyay | karraway.snail there", "r213_deictic_there_karraway", ["karraway", "yinyay"], "Dictionary karraway noun 'edible snail'; selected snail label only; Patz section 3.7 yinyay."),
    row(15, "The ghost crab is there.", "Karruku yinyay.", "karruku yinyay | ghost.crab there", "r213_deictic_there_karruku", ["karruku", "yinyay"], "Dictionary karruku noun 'ghost crab, fiddler crab'; selected ghost crab label; Patz section 3.7 yinyay."),
    row(16, "The jellyfish is there.", "Kulil yinyay.", "kulil yinyay | jellyfish there", "r213_deictic_there_kulil", ["kulil", "yinyay"], "Dictionary kulil noun 'jellyfish'; sting/burn event readings closed; Patz section 3.7 yinyay."),
    row(17, "The small conical shellfish is there.", "Kuyalin yinyay.", "kuyalin yinyay | small.conical.shellfish there", "r213_deictic_there_kuyalin", ["kuyalin", "yinyay"], "Dictionary kuyalin noun 'small conical shellfish'; bait reading closed; Patz section 3.7 yinyay."),
    row(18, "The oyster is there.", "Marrkabina yinyay.", "marrkabina yinyay | oyster there", "r213_deictic_there_marrkabina", ["marrkabina", "yinyay"], "Dictionary marrkabina noun 'oyster'; edible detail closed; Patz section 3.7 yinyay."),
    row(19, "The shell fish is there.", "Ngarrakaja yinyay.", "ngarrakaja yinyay | shell.fish there", "r213_deictic_there_ngarrakaja", ["ngarrakaja", "yinyay"], "Dictionary ngarrakaja noun 'shell fish'; edible/species detail closed; Patz section 3.7 yinyay."),
    row(20, "The squid is there.", "Nuwi yinyay.", "nuwi yinyay | squid there", "r213_deictic_there_nuwi", ["nuwi", "yinyay"], "Dictionary nuwi noun 'squid'; Patz section 3.7 yinyay 'there'."),
    row(21, "That large mud clam is there.", "Yinya baymbay yinyay.", "yinya baymbay yinyay | that large.mud.clam there", "r213_initial_that_there_baymbay", ["yinya", "baymbay", "yinyay"], "Patz section 3.7 yinya can co-occur with a noun; baymbay large mud clam; yinyay there."),
    row(22, "That clam is there.", "Yinya darkay yinyay.", "yinya darkay yinyay | that clam there", "r213_initial_that_there_darkay", ["yinya", "darkay", "yinyay"], "Patz section 3.7 yinya can co-occur with a noun; darkay clam; yinyay there."),
    row(23, "That snail is there.", "Yinya kaduy yinyay.", "yinya kaduy yinyay | that snail there", "r213_initial_that_there_kaduy", ["yinya", "kaduy", "yinyay"], "Patz section 3.7 yinya can co-occur with a noun; kaduy snail; yinyay there."),
    row(24, "That karraway snail is there.", "Yinya karraway yinyay.", "yinya karraway yinyay | that karraway.snail there", "r213_initial_that_there_karraway", ["yinya", "karraway", "yinyay"], "Patz section 3.7 yinya can co-occur with a noun; karraway snail label; edible reading closed."),
    row(25, "That ghost crab is there.", "Yinya karruku yinyay.", "yinya karruku yinyay | that ghost.crab there", "r213_initial_that_there_karruku", ["yinya", "karruku", "yinyay"], "Patz section 3.7 yinya can co-occur with a noun; karruku ghost crab; yinyay there."),
    row(26, "That jellyfish is there.", "Yinya kulil yinyay.", "yinya kulil yinyay | that jellyfish there", "r213_initial_that_there_kulil", ["yinya", "kulil", "yinyay"], "Patz section 3.7 yinya can co-occur with a noun; kulil jellyfish; yinyay there."),
    row(27, "That small conical shellfish is there.", "Yinya kuyalin yinyay.", "yinya kuyalin yinyay | that small.conical.shellfish there", "r213_initial_that_there_kuyalin", ["yinya", "kuyalin", "yinyay"], "Patz section 3.7 yinya can co-occur with a noun; kuyalin small conical shellfish; bait closed."),
    row(28, "That oyster is there.", "Yinya marrkabina yinyay.", "yinya marrkabina yinyay | that oyster there", "r213_initial_that_there_marrkabina", ["yinya", "marrkabina", "yinyay"], "Patz section 3.7 yinya can co-occur with a noun; marrkabina oyster; edible detail closed."),
    row(29, "That shell fish is there.", "Yinya ngarrakaja yinyay.", "yinya ngarrakaja yinyay | that shell.fish there", "r213_initial_that_there_ngarrakaja", ["yinya", "ngarrakaja", "yinyay"], "Patz section 3.7 yinya can co-occur with a noun; ngarrakaja shell fish; edible detail closed."),
    row(30, "That squid is there.", "Yinya nuwi yinyay.", "yinya nuwi yinyay | that squid there", "r213_initial_that_there_nuwi", ["yinya", "nuwi", "yinyay"], "Patz section 3.7 yinya can co-occur with a noun; nuwi squid; yinyay there."),
    row(31, "That large mud clam is there.", "Baymbay yinya yinyay.", "baymbay yinya yinyay | large.mud.clam that there", "r213_postposed_that_there_baymbay", ["baymbay", "yinya", "yinyay"], "Patz section 3.7 permits yinya after a noun; baymbay large mud clam; yinyay there."),
    row(32, "That clam is there.", "Darkay yinya yinyay.", "darkay yinya yinyay | clam that there", "r213_postposed_that_there_darkay", ["darkay", "yinya", "yinyay"], "Patz section 3.7 permits yinya after a noun; darkay clam; yinyay there."),
    row(33, "That snail is there.", "Kaduy yinya yinyay.", "kaduy yinya yinyay | snail that there", "r213_postposed_that_there_kaduy", ["kaduy", "yinya", "yinyay"], "Patz section 3.7 permits yinya after a noun; kaduy snail; yinyay there."),
    row(34, "That karraway snail is there.", "Karraway yinya yinyay.", "karraway yinya yinyay | karraway.snail that there", "r213_postposed_that_there_karraway", ["karraway", "yinya", "yinyay"], "Patz section 3.7 permits yinya after a noun; karraway snail label; edible reading closed."),
    row(35, "That ghost crab is there.", "Karruku yinya yinyay.", "karruku yinya yinyay | ghost.crab that there", "r213_postposed_that_there_karruku", ["karruku", "yinya", "yinyay"], "Patz section 3.7 permits yinya after a noun; karruku ghost crab; yinyay there."),
    row(36, "That jellyfish is there.", "Kulil yinya yinyay.", "kulil yinya yinyay | jellyfish that there", "r213_postposed_that_there_kulil", ["kulil", "yinya", "yinyay"], "Patz section 3.7 permits yinya after a noun; kulil jellyfish; sting/burn event closed."),
    row(37, "That small conical shellfish is there.", "Kuyalin yinya yinyay.", "kuyalin yinya yinyay | small.conical.shellfish that there", "r213_postposed_that_there_kuyalin", ["kuyalin", "yinya", "yinyay"], "Patz section 3.7 permits yinya after a noun; kuyalin small conical shellfish; bait closed."),
    row(38, "That oyster is there.", "Marrkabina yinya yinyay.", "marrkabina yinya yinyay | oyster that there", "r213_postposed_that_there_marrkabina", ["marrkabina", "yinya", "yinyay"], "Patz section 3.7 permits yinya after a noun; marrkabina oyster; edible detail closed."),
    row(39, "That shell fish is there.", "Ngarrakaja yinya yinyay.", "ngarrakaja yinya yinyay | shell.fish that there", "r213_postposed_that_there_ngarrakaja", ["ngarrakaja", "yinya", "yinyay"], "Patz section 3.7 permits yinya after a noun; ngarrakaja shell fish; edible detail closed."),
    row(40, "That squid is there.", "Nuwi yinya yinyay.", "nuwi yinya yinyay | squid that there", "r213_postposed_that_there_nuwi", ["nuwi", "yinya", "yinyay"], "Patz section 3.7 permits yinya after a noun; nuwi squid; yinyay there."),
    row(41, "That large mud clam is here.", "Yinya baymbay yaluy.", "yinya baymbay yaluy | that large.mud.clam here", "r213_initial_that_here_baymbay", ["yinya", "baymbay", "yaluy"], "Patz section 3.7 yinya can co-occur with a noun; baymbay large mud clam; yaluy here."),
    row(42, "That clam is here.", "Yinya darkay yaluy.", "yinya darkay yaluy | that clam here", "r213_initial_that_here_darkay", ["yinya", "darkay", "yaluy"], "Patz section 3.7 yinya can co-occur with a noun; darkay clam; yaluy here."),
    row(43, "That snail is here.", "Yinya kaduy yaluy.", "yinya kaduy yaluy | that snail here", "r213_initial_that_here_kaduy", ["yinya", "kaduy", "yaluy"], "Patz section 3.7 yinya can co-occur with a noun; kaduy snail; yaluy here."),
    row(44, "That karraway snail is here.", "Yinya karraway yaluy.", "yinya karraway yaluy | that karraway.snail here", "r213_initial_that_here_karraway", ["yinya", "karraway", "yaluy"], "Patz section 3.7 yinya can co-occur with a noun; karraway snail label; edible reading closed."),
    row(45, "That ghost crab is here.", "Yinya karruku yaluy.", "yinya karruku yaluy | that ghost.crab here", "r213_initial_that_here_karruku", ["yinya", "karruku", "yaluy"], "Patz section 3.7 yinya can co-occur with a noun; karruku ghost crab; yaluy here."),
    row(46, "That jellyfish is here.", "Yinya kulil yaluy.", "yinya kulil yaluy | that jellyfish here", "r213_initial_that_here_kulil", ["yinya", "kulil", "yaluy"], "Patz section 3.7 yinya can co-occur with a noun; kulil jellyfish; yaluy here."),
    row(47, "That small conical shellfish is here.", "Yinya kuyalin yaluy.", "yinya kuyalin yaluy | that small.conical.shellfish here", "r213_initial_that_here_kuyalin", ["yinya", "kuyalin", "yaluy"], "Patz section 3.7 yinya can co-occur with a noun; kuyalin small conical shellfish; bait closed."),
    row(48, "That oyster is here.", "Yinya marrkabina yaluy.", "yinya marrkabina yaluy | that oyster here", "r213_initial_that_here_marrkabina", ["yinya", "marrkabina", "yaluy"], "Patz section 3.7 yinya can co-occur with a noun; marrkabina oyster; yaluy here."),
    row(49, "That shell fish is here.", "Yinya ngarrakaja yaluy.", "yinya ngarrakaja yaluy | that shell.fish here", "r213_initial_that_here_ngarrakaja", ["yinya", "ngarrakaja", "yaluy"], "Patz section 3.7 yinya can co-occur with a noun; ngarrakaja shell fish; yaluy here."),
    row(50, "That squid is here.", "Yinya nuwi yaluy.", "yinya nuwi yaluy | that squid here", "r213_initial_that_here_nuwi", ["yinya", "nuwi", "yaluy"], "Patz section 3.7 yinya can co-occur with a noun; nuwi squid; yaluy here."),
]


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)}\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("r213_"):
            issues.append(f"{label}: Rule 213 frame must start with r213_")
        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 213")
        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 213 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.")):
            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.")):
            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.")):
            issues.append(f"{label}: rows 21-30 require Yinya TARGET yinyay")
        if 31 <= seq <= 40 and (has_token(low, "yaluy") or not has_token(low, "yinya") or not low.endswith(" yinyay.") 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.")):
            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 shellfish-use/food/habitat/body/event 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,))
        db.execute("UPDATE batches SET notes=?, created_at=? WHERE id=?", ("rebanked under_review", NOW, batch_id))
    else:
        cur = db.execute(
            "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
            (
                LABEL,
                "Rule 213 draft: low-coverage shellfish reference lexical expansion after Rule 212",
                "operator-guide-2026-07-08",
                "under_review",
                NOW,
            ),
        )
        batch_id = cur.lastrowid

    dupes: list[str] = []
    for seq, _english, kuku, *_rest in ROWS:
        hit = db.execute(
            """
            SELECT b.label, s.seq
            FROM sentences s JOIN batches b ON b.id=s.batch_id
            WHERE lower(trim(s.kuku))=lower(trim(?))
              AND s.status!='rejected'
              AND s.batch_id!=?
            """,
            (kuku, batch_id),
        ).fetchone()
        if hit:
            dupes.append(f"{LABEL}.{seq:02d} duplicates {hit[0]}.{hit[1]:02d}: {kuku}")
    if dupes:
        db.rollback()
        print("cross-corpus duplicate check failed:")
        for dupe in dupes:
            print(f"  - {dupe}")
        return 1

    db.executemany(
        """
        INSERT INTO sentences(
          batch_id, seq, english, kuku, analysis, frame, tier, words_used,
          loans_used, evidence, status, confidence, author, created_at
        )
        VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)
        """,
        [
            (batch_id, *row_data[:-1], "under_review", row_data[-1], "claude", NOW)
            for row_data in ROWS
        ],
    )
    verified_before, words_before = db.execute(
        """
        SELECT COUNT(*), SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1)
        FROM sentences
        WHERE status IN ('accepted','revised')
        """
    ).fetchone()
    record_event(
        db,
        batch_label=LABEL,
        phase="source",
        event_type="source-pass",
        actor="claude-main",
        detail="Checked Patz section 3.7 demonstrative frames plus dictionary fauna-shellfish-crustacean entries for baymbay, darkay, kaduy, karraway, karruku, kulil, kuyalin, marrkabina, ngarrakaja, and nuwi. Selected only bare shellfish/crustacean-reference readings.",
        command="rg readback over dictionary.yaml plus grammar.md Patz section 3.7 checks",
        output_excerpt="baymbay large mud clam; darkay clam/small mud clam; kaduy snail; karraway edible snail/snail; karruku ghost crab, fiddler crab; kulil jellyfish; kuyalin small conical shellfish; marrkabina oyster; ngarrakaja shell fish; nuwi squid.",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="scope",
        event_type="candidate-rejection",
        actor="claude-main",
        detail="Chose shellfish/crustacean after a fresh source pass but closed edible, bait, frying, cooking, eating, gathering, catching, fishing, sea/reef/rock/night/habitat, shell/body-part, sting/burn, and use prose. Deferred unhyphenated reduplication and ambiguous shell/body-part candidates.",
        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 213 Kuku surfaces returned no accepted, revised, or under-review collisions.",
        command="bank_255.py cross-corpus duplicate check before insert",
        output_excerpt="No collisions.",
        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_255.py static guards passed: 50 explicit hand-authored rows, exactly one shellfish target noun per row, support words recorded, correct five frame bands, no target morphology, no loans, and no denied shellfish-use/food/habitat/body/event English/Kuku fields.",
        artifact_path="batch_scripts/bank_255.py",
        created_at=NOW,
    )
    db.commit()
    print(f"banked {LABEL}: rows=50, under_review=50, verified_before_close={verified_before}, words_before={words_before}")
    return 0


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