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

TARGET_HEADS = {
    "baringkan": "baringkan small bird",
    "bidu-bidu": "bank bird",
    "diwalngku": "diwalngku migratory bird",
    "jiral-jiral": "night bird",
    "karkunbay": "stockwhip bird",
    "dukunjulu": "golden whistler",
    "kurranday": "seagull",
    "yinjul": "fig parrot",
    "milman": "azure kingfisher",
    "nili-nili": "duck",
}
SUPPORT = {"yinya", "yaluy", "yinyay"}
DENY_KUKU = {
    # Rule 173/174 bird targets.
    "barbarr", "bayil-bayil", "biluwarra", "binjul-binjul", "dijarr-dijin",
    "kurburrubun", "kurkumbay", "kurungka", "munwingkul", "yindili",
    # Rule 211 bird targets.
    "barinkan", "bilu-warra", "bujil-yiran", "kalmbangarr", "dijarrdijin",
    "dukunjuju", "jiwal-jiwal", "karrmbil", "kujuway", "yiki",
    # Rule 221 bird targets.
    "bajal", "jiwurrmal", "jangkan", "karunkurr", "jurriyan", "kuludu",
    "kurrbal", "jaka", "kalkuy", "wakuka",
    # High-risk or rejected bird candidates for this pass.
    "babarr", "burrkul", "buyku", "dabway", "dakwul-dakwul", "dakwurr-dakwun",
    "dirrmbay", "jiway", "juku-juku", "jukujuku", "kadanji", "kalin-kalin",
    "kurri-kurri", "kurrujuwa", "kuyir", "mulumu", "ngurrku", "wandi",
    "walu-dalbaji", "yalngkurr",
}
DENY_ENGLISH = (
    "fly", "flying", "flew", "taking off", "migrate", "migration", "call", "called",
    "calling", "cry", "cries", "sing", "sang", "singing", "song", "sound", "warning",
    "warn", "message", "messenger", "totem", "moiety", "sacred", "story", "spirit",
    "death", "dead", "omen", "portent", "nest", "egg", "feather", "wing", "food",
    "eat", "eating", "hunt", "hunting", "catch", "catching", "dance", "dancing",
    "corroboree", "storm", "weather", "place", "country", "river", "sea", "water",
    "habitat", "tree", "body", "colour", "color", "loan", "domestic", "post-contact",
)


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 = {
    "baringkan": "Dictionary baringkan noun 'species of small bird' with translation 'baringkan (small bird)'. Patz section 3.1 includes fauna among nouns; section 3.7 supports yinya/yaluy/yinyay.",
    "bidu-bidu": "Dictionary bidu-bidu noun 'bank bird', a lexicalized hyphenated reduplicated bird name. Patz section 3.1 fauna noun and section 3.7 deictic support.",
    "diwalngku": "Dictionary diwalngku noun 'migratory bird', English name unknown. Batch uses reference label only, not migration event. Patz section 3.1 fauna noun and section 3.7 deictic support.",
    "jiral-jiral": "Dictionary jiral-jiral noun 'night bird', a lexicalized hyphenated reduplicated bird name. Patz section 3.1 fauna noun and section 3.7 deictic support.",
    "karkunbay": "Dictionary karkunbay noun 'stockwhip bird'. Batch uses reference label only, not sound or whip-event prose. Patz section 3.1 fauna noun and section 3.7 deictic support.",
    "dukunjulu": "Dictionary dukunjulu noun 'golden whistler'. Distinct from earlier dukunjulu/dukunjuju source variants; batch opens no whistling event. Patz section 3.1 fauna noun and section 3.7 deictic support.",
    "kurranday": "Dictionary kurranday noun 'seagull'. Batch uses simple seagull reference only and does not import dirrmbay storm-warning/death-message senses. Patz section 3.1 fauna noun and section 3.7 deictic support.",
    "yinjul": "Dictionary yinjul noun 'fig parrot'. Batch uses reference label only, no tree/fig feeding or colour claim. Patz section 3.1 fauna noun and section 3.7 deictic support.",
    "milman": "Dictionary milman noun 'azure kingfisher'. Batch uses reference label only, no colour predicate or fishing event. Patz section 3.1 fauna noun and section 3.7 deictic support.",
    "nili-nili": "Dictionary nili-nili noun 'duck', a lexicalized hyphenated reduplicated bird name. Patz section 3.1 fauna noun and section 3.7 deictic support.",
}


ROWS = [
    row(1, "The baringkan small bird is here.", "Baringkan yaluy.", "baringkan yaluy | baringkan.small.bird here", "r229_bird_ref_here_baringkan", ["baringkan", "yaluy"], EVIDENCE["baringkan"]),
    row(2, "The bank bird is here.", "Bidu-bidu yaluy.", "bidu-bidu yaluy | bank.bird here", "r229_bird_ref_here_bidu_bidu", ["bidu-bidu", "yaluy"], EVIDENCE["bidu-bidu"]),
    row(3, "The diwalngku migratory bird is here.", "Diwalngku yaluy.", "diwalngku yaluy | diwalngku.migratory.bird here", "r229_bird_ref_here_diwalngku", ["diwalngku", "yaluy"], EVIDENCE["diwalngku"]),
    row(4, "The night bird is here.", "Jiral-jiral yaluy.", "jiral-jiral yaluy | night.bird here", "r229_bird_ref_here_jiral_jiral", ["jiral-jiral", "yaluy"], EVIDENCE["jiral-jiral"]),
    row(5, "The stockwhip bird is here.", "Karkunbay yaluy.", "karkunbay yaluy | stockwhip.bird here", "r229_bird_ref_here_karkunbay", ["karkunbay", "yaluy"], EVIDENCE["karkunbay"]),
    row(6, "The golden whistler is here.", "Dukunjulu yaluy.", "dukunjulu yaluy | golden.whistler here", "r229_bird_ref_here_dukunjulu", ["dukunjulu", "yaluy"], EVIDENCE["dukunjulu"]),
    row(7, "The seagull is here.", "Kurranday yaluy.", "kurranday yaluy | seagull here", "r229_bird_ref_here_kurranday", ["kurranday", "yaluy"], EVIDENCE["kurranday"]),
    row(8, "The fig parrot is here.", "Yinjul yaluy.", "yinjul yaluy | fig.parrot here", "r229_bird_ref_here_yinjul", ["yinjul", "yaluy"], EVIDENCE["yinjul"]),
    row(9, "The azure kingfisher is here.", "Milman yaluy.", "milman yaluy | azure.kingfisher here", "r229_bird_ref_here_milman", ["milman", "yaluy"], EVIDENCE["milman"]),
    row(10, "The duck is here.", "Nili-nili yaluy.", "nili-nili yaluy | duck here", "r229_bird_ref_here_nili_nili", ["nili-nili", "yaluy"], EVIDENCE["nili-nili"]),
    row(11, "The baringkan small bird is there.", "Baringkan yinyay.", "baringkan yinyay | baringkan.small.bird there", "r229_bird_ref_there_baringkan", ["baringkan", "yinyay"], EVIDENCE["baringkan"]),
    row(12, "The bank bird is there.", "Bidu-bidu yinyay.", "bidu-bidu yinyay | bank.bird there", "r229_bird_ref_there_bidu_bidu", ["bidu-bidu", "yinyay"], EVIDENCE["bidu-bidu"]),
    row(13, "The diwalngku migratory bird is there.", "Diwalngku yinyay.", "diwalngku yinyay | diwalngku.migratory.bird there", "r229_bird_ref_there_diwalngku", ["diwalngku", "yinyay"], EVIDENCE["diwalngku"]),
    row(14, "The night bird is there.", "Jiral-jiral yinyay.", "jiral-jiral yinyay | night.bird there", "r229_bird_ref_there_jiral_jiral", ["jiral-jiral", "yinyay"], EVIDENCE["jiral-jiral"]),
    row(15, "The stockwhip bird is there.", "Karkunbay yinyay.", "karkunbay yinyay | stockwhip.bird there", "r229_bird_ref_there_karkunbay", ["karkunbay", "yinyay"], EVIDENCE["karkunbay"]),
    row(16, "The golden whistler is there.", "Dukunjulu yinyay.", "dukunjulu yinyay | golden.whistler there", "r229_bird_ref_there_dukunjulu", ["dukunjulu", "yinyay"], EVIDENCE["dukunjulu"]),
    row(17, "The seagull is there.", "Kurranday yinyay.", "kurranday yinyay | seagull there", "r229_bird_ref_there_kurranday", ["kurranday", "yinyay"], EVIDENCE["kurranday"]),
    row(18, "The fig parrot is there.", "Yinjul yinyay.", "yinjul yinyay | fig.parrot there", "r229_bird_ref_there_yinjul", ["yinjul", "yinyay"], EVIDENCE["yinjul"]),
    row(19, "The azure kingfisher is there.", "Milman yinyay.", "milman yinyay | azure.kingfisher there", "r229_bird_ref_there_milman", ["milman", "yinyay"], EVIDENCE["milman"]),
    row(20, "The duck is there.", "Nili-nili yinyay.", "nili-nili yinyay | duck there", "r229_bird_ref_there_nili_nili", ["nili-nili", "yinyay"], EVIDENCE["nili-nili"]),
    row(21, "That baringkan small bird is there.", "Yinya baringkan yinyay.", "yinya baringkan yinyay | that baringkan.small.bird there", "r229_that_bird_ref_there_baringkan", ["yinya", "baringkan", "yinyay"], EVIDENCE["baringkan"]),
    row(22, "That bank bird is there.", "Yinya bidu-bidu yinyay.", "yinya bidu-bidu yinyay | that bank.bird there", "r229_that_bird_ref_there_bidu_bidu", ["yinya", "bidu-bidu", "yinyay"], EVIDENCE["bidu-bidu"]),
    row(23, "That diwalngku migratory bird is there.", "Yinya diwalngku yinyay.", "yinya diwalngku yinyay | that diwalngku.migratory.bird there", "r229_that_bird_ref_there_diwalngku", ["yinya", "diwalngku", "yinyay"], EVIDENCE["diwalngku"]),
    row(24, "That night bird is there.", "Yinya jiral-jiral yinyay.", "yinya jiral-jiral yinyay | that night.bird there", "r229_that_bird_ref_there_jiral_jiral", ["yinya", "jiral-jiral", "yinyay"], EVIDENCE["jiral-jiral"]),
    row(25, "That stockwhip bird is there.", "Yinya karkunbay yinyay.", "yinya karkunbay yinyay | that stockwhip.bird there", "r229_that_bird_ref_there_karkunbay", ["yinya", "karkunbay", "yinyay"], EVIDENCE["karkunbay"]),
    row(26, "That golden whistler is there.", "Yinya dukunjulu yinyay.", "yinya dukunjulu yinyay | that golden.whistler there", "r229_that_bird_ref_there_dukunjulu", ["yinya", "dukunjulu", "yinyay"], EVIDENCE["dukunjulu"]),
    row(27, "That seagull is there.", "Yinya kurranday yinyay.", "yinya kurranday yinyay | that seagull there", "r229_that_bird_ref_there_kurranday", ["yinya", "kurranday", "yinyay"], EVIDENCE["kurranday"]),
    row(28, "That fig parrot is there.", "Yinya yinjul yinyay.", "yinya yinjul yinyay | that fig.parrot there", "r229_that_bird_ref_there_yinjul", ["yinya", "yinjul", "yinyay"], EVIDENCE["yinjul"]),
    row(29, "That azure kingfisher is there.", "Yinya milman yinyay.", "yinya milman yinyay | that azure.kingfisher there", "r229_that_bird_ref_there_milman", ["yinya", "milman", "yinyay"], EVIDENCE["milman"]),
    row(30, "That duck is there.", "Yinya nili-nili yinyay.", "yinya nili-nili yinyay | that duck there", "r229_that_bird_ref_there_nili_nili", ["yinya", "nili-nili", "yinyay"], EVIDENCE["nili-nili"]),
    row(31, "That baringkan small bird is there.", "Baringkan yinya yinyay.", "baringkan yinya yinyay | that baringkan.small.bird there", "r229_bird_that_there_baringkan", ["baringkan", "yinya", "yinyay"], EVIDENCE["baringkan"]),
    row(32, "That bank bird is there.", "Bidu-bidu yinya yinyay.", "bidu-bidu yinya yinyay | that bank.bird there", "r229_bird_that_there_bidu_bidu", ["bidu-bidu", "yinya", "yinyay"], EVIDENCE["bidu-bidu"]),
    row(33, "That diwalngku migratory bird is there.", "Diwalngku yinya yinyay.", "diwalngku yinya yinyay | that diwalngku.migratory.bird there", "r229_bird_that_there_diwalngku", ["diwalngku", "yinya", "yinyay"], EVIDENCE["diwalngku"]),
    row(34, "That night bird is there.", "Jiral-jiral yinya yinyay.", "jiral-jiral yinya yinyay | that night.bird there", "r229_bird_that_there_jiral_jiral", ["jiral-jiral", "yinya", "yinyay"], EVIDENCE["jiral-jiral"]),
    row(35, "That stockwhip bird is there.", "Karkunbay yinya yinyay.", "karkunbay yinya yinyay | that stockwhip.bird there", "r229_bird_that_there_karkunbay", ["karkunbay", "yinya", "yinyay"], EVIDENCE["karkunbay"]),
    row(36, "That golden whistler is there.", "Dukunjulu yinya yinyay.", "dukunjulu yinya yinyay | that golden.whistler there", "r229_bird_that_there_dukunjulu", ["dukunjulu", "yinya", "yinyay"], EVIDENCE["dukunjulu"]),
    row(37, "That seagull is there.", "Kurranday yinya yinyay.", "kurranday yinya yinyay | that seagull there", "r229_bird_that_there_kurranday", ["kurranday", "yinya", "yinyay"], EVIDENCE["kurranday"]),
    row(38, "That fig parrot is there.", "Yinjul yinya yinyay.", "yinjul yinya yinyay | that fig.parrot there", "r229_bird_that_there_yinjul", ["yinjul", "yinya", "yinyay"], EVIDENCE["yinjul"]),
    row(39, "That azure kingfisher is there.", "Milman yinya yinyay.", "milman yinya yinyay | that azure.kingfisher there", "r229_bird_that_there_milman", ["milman", "yinya", "yinyay"], EVIDENCE["milman"]),
    row(40, "That duck is there.", "Nili-nili yinya yinyay.", "nili-nili yinya yinyay | that duck there", "r229_bird_that_there_nili_nili", ["nili-nili", "yinya", "yinyay"], EVIDENCE["nili-nili"]),
    row(41, "That baringkan small bird is here.", "Yinya baringkan yaluy.", "yinya baringkan yaluy | that baringkan.small.bird here", "r229_that_bird_ref_here_baringkan", ["yinya", "baringkan", "yaluy"], EVIDENCE["baringkan"]),
    row(42, "That bank bird is here.", "Yinya bidu-bidu yaluy.", "yinya bidu-bidu yaluy | that bank.bird here", "r229_that_bird_ref_here_bidu_bidu", ["yinya", "bidu-bidu", "yaluy"], EVIDENCE["bidu-bidu"]),
    row(43, "That diwalngku migratory bird is here.", "Yinya diwalngku yaluy.", "yinya diwalngku yaluy | that diwalngku.migratory.bird here", "r229_that_bird_ref_here_diwalngku", ["yinya", "diwalngku", "yaluy"], EVIDENCE["diwalngku"]),
    row(44, "That night bird is here.", "Yinya jiral-jiral yaluy.", "yinya jiral-jiral yaluy | that night.bird here", "r229_that_bird_ref_here_jiral_jiral", ["yinya", "jiral-jiral", "yaluy"], EVIDENCE["jiral-jiral"]),
    row(45, "That stockwhip bird is here.", "Yinya karkunbay yaluy.", "yinya karkunbay yaluy | that stockwhip.bird here", "r229_that_bird_ref_here_karkunbay", ["yinya", "karkunbay", "yaluy"], EVIDENCE["karkunbay"]),
    row(46, "That golden whistler is here.", "Yinya dukunjulu yaluy.", "yinya dukunjulu yaluy | that golden.whistler here", "r229_that_bird_ref_here_dukunjulu", ["yinya", "dukunjulu", "yaluy"], EVIDENCE["dukunjulu"]),
    row(47, "That seagull is here.", "Yinya kurranday yaluy.", "yinya kurranday yaluy | that seagull here", "r229_that_bird_ref_here_kurranday", ["yinya", "kurranday", "yaluy"], EVIDENCE["kurranday"]),
    row(48, "That fig parrot is here.", "Yinya yinjul yaluy.", "yinya yinjul yaluy | that fig.parrot here", "r229_that_bird_ref_here_yinjul", ["yinya", "yinjul", "yaluy"], EVIDENCE["yinjul"]),
    row(49, "That azure kingfisher is here.", "Yinya milman yaluy.", "yinya milman yaluy | that azure.kingfisher here", "r229_that_bird_ref_here_milman", ["yinya", "milman", "yaluy"], EVIDENCE["milman"]),
    row(50, "That duck is here.", "Yinya nili-nili yaluy.", "yinya nili-nili yaluy | that duck here", "r229_that_bird_ref_here_nili_nili", ["yinya", "nili-nili", "yaluy"], EVIDENCE["nili-nili"]),
]


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("r229_"):
            issues.append(f"{label}: Rule 229 frame must start with r229_")
        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 229")
        for denied in DENY_KUKU:
            if has_token(low, denied):
                issues.append(f"{label}: denied bird/homograph 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 229 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 bird-event/use/cultural 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 229 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 fauna-noun basis, Patz section 3.7 yinya/yaluy/yinyay support, Rules 211 and 221 bird-reference law, and dictionary entries for baringkan, bidu-bidu, diwalngku, jiral-jiral, karkunbay, dukunjulu, kurranday, yinjul, milman, and nili-nili.",
        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 third bounded bird-reference field after excluding Rule 173/211/221 exact targets, unhyphenated reduplication variants, overt messenger/storm/death/totem/story birds, loan/domestic birds, homograph-heavy kulbal/wandi/waja, and entries whose source prose would import event, food, habitat, colour, or cultural claims.",
        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 229 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_271.py static guards passed: 50 explicit hand-authored rows, exactly one third-bird-reference target noun per row, no loans, no target morphology, no prior bird exact-target token, no bird event/use/cultural English, and only five sourced deictic frame bands.",
        artifact_path="batch_scripts/bank_271.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())
