#!/usr/bin/env python3
"""Bank batch-125: fire and cooking lexical domain.

Rows are hand-authored from the current operator guide, grammar cheatsheet,
dictionary errata, and direct Patz examples around fire-making, earth ovens,
grinding, and food sharing. The script only validates and banks the rows as
under_review; it does not generate sentence content.
"""

from __future__ import annotations

import datetime as dt
import json
import re
import sqlite3
import sys

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-125"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")

DENY = {
    "nyawa", "jinbi", "jibin", "walba", "julmbu", "wanan", "ngampula",
    "yalama", "ngana-jinji", "jubuny", "wural", "bigan", "jiwuny",
    "warngkul", "wanaba", "jarrkunji", "munjal", "murku", "buni",
    "kunya", "milkan", "kulur-jambul", "janyji", "buburr", "jarrmba",
    "jinji", "daga", "wanka", "yumbul", "kuku-yumbul", "jubi",
    "yilbay", "jarrakay", "janka-yukil", "jukarr", "kunkul",
    "bubu-jandu", "bubu-warral", "jani-warra", "dungkarr", "jimba",
    "bujal", "wanyjarr", "ngudan", "jimirr", "jangan", "ganggal",
    "bukul", "jalany", "nyunun", "yinkar", "jiba", "bibi",
    # Fire/cooking batch traps: baya is the fire/firewood headword, not buri.
    # duna/yaru are wet; kambar is white clay; jinbal is fast.
    "buri", "bibiny", "dalku", "kubarr", "jubaji", "nyalbu", "kuka",
    "balmba", "milbin", "kindu",
}


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


ROWS = [
    (1, "I gathered firewood before dawn.",
     "Ngayu baya mujan muduwajuny.",
     "ngayu baya muja-ny muduwajuny | I firewood gather-PAST dawn",
     "firewood_gathering", 3, js(["ngayu", "baya", "mujal", "muduwajuny"]),
     "Dictionary/errata: baya covers fire/firewood; Patz firewood examples use muja-l with baya.", "0.86"),
    (2, "Grandmother took the child to gather firewood.",
     "Babi-ngka karrkay wundin baya muja-nka.",
     "babi-ngka karrkay wundi-ny baya muja-nka | grandmother-ERG child take-PAST firewood gather-PURP",
     "firewood_gathering_purpose", 4, js(["babi", "karrkay", "wundil", "baya", "mujal"]),
     "Patz purpose model: Kami-ngka karrkay wundi-l, baya muja-nka.", "0.87"),
    (3, "The old man made fire with a fire-stick.",
     "Mukul-dingkar-angka jimal daman.",
     "mukul-dingkar-angka jimal dama-ny | old-man-ERG fire-stick make.fire-PAST",
     "firestick_making_fire", 4, js(["mukul-dingkar", "jimal", "damal"]),
     "Dictionary jimal / jimal dama-l: fire-stick and make fire with a fire-stick.", "0.86"),
    (4, "They twirled the fire-drill, and smoke came.",
     "Jana dama-murnin, kubu kadan.",
     "jana dama-murni-ny, kubu kada-ny | they fire.drill-twirl-PAST smoke come-PAST",
     "fire_drill_smoke", 4, js(["jana", "dama-murnil", "kubu", "kaday"]),
     "Errata fire list: dama-murni-l 'twirl a fire-drill'; kubu 'smoke'.", "0.84"),
    (5, "The woman started the fire before cooking food.",
     "Jalbu-ngku baya jakalamban, mayi waju-nyjiku.",
     "jalbu-ngku baya jakalamba-ny, mayi waju-nyjiku | woman-ERG fire start-PAST food cook-SUCC",
     "fire_before_cooking", 4, js(["jalbu", "baya", "jakalambal", "mayi", "wajul"]),
     "Errata confirms jakalamba-l 'start a fire' and waju-l 'cook/burn'.", "0.86"),
    (6, "I light a fire so that you get warm.",
     "Ngayu baya waju-l, yundu wumbul-ma-nka.",
     "ngayu baya waju-l, yundu wumbul-ma-nka | I fire light-NONPAST you hot-INCH-PURP",
     "fire_warm_purpose", 4, js(["ngayu", "baya", "wajul", "yundu", "wumbul"]),
     "Patz direct model: Ngayu baya waju-l ... yundu wumbul-ma-nka.", "0.88"),
    (7, "Keep the fire burning lest cold come.",
     "Baya waju-l-waju, kiway kada-nyji.",
     "baya waju-l-waju, kiway kada-nyji | fire burn-REDUP-IMP cold come-PRECAUT",
     "precaution_fire_cold", 4, js(["baya", "wajul", "kiway", "kaday"]),
     "Patz direct precautionary model: Baya waju-l-waju, kiway kada-nyji.", "0.88"),
    (8, "Burn ironwood lest thunder come.",
     "Jujubala waju, jarramali kada-nyji.",
     "jujubala waju, jarramali kada-nyji | ironwood burn.IMP thunder come-PRECAUT",
     "precaution_thunder_firewood", 4, js(["jujubala", "wajul", "jarramali", "kaday"]),
     "Patz precautionary fire line: Jujubala waju, jarramali kada-nyji; errata glosses jarramali as thunder.", "0.87"),
    (9, "The children became warm near the big fire.",
     "Karrkay-karrkay wumbulmanin baya yalbay ngundu-ba.",
     "karrkay-karrkay wumbul-ma-ny baya yalbay ngundu-ba | child-REDUP hot-INCH-PAST fire big near-LOC",
     "fire_warm_location", 4, js(["karrkay", "wumbul", "baya", "yalbay", "ngundu"]),
     "Patz fire-warm model plus regular ngundu-ba 'near'.", "0.84"),
    (10, "The flames rose high, and smoke went through the camp.",
     "Wula wangkar-a wandin, kubu bayan-burr dungan.",
     "wula wangkar-a wandi-ny, kubu bayan-burr dunga-ny | flame high-LOC rise-PAST smoke camp-PERL go-PAST",
     "flame_smoke_perlative", 4, js(["wula", "wangkar", "wandil", "kubu", "bayan", "dungay"]),
     "Errata fire list: wula flames, kubu smoke; Patz PERL -burr for through/along.", "0.83"),
    (11, "The coals were hot, but the ash was cool.",
     "Ngunjil wumbul, yamba bajar ngiki.",
     "ngunjil wumbul, yamba bajar ngiki | coals hot, but ash cool",
     "fire_residue_contrast", 3, js(["ngunjil", "wumbul", "yamba", "bajar", "ngiki"]),
     "Errata fire list: ngunjil charcoal/coals, bajar ash, wumbul hot.", "0.85"),
    (12, "The children sat near the fire while rain fell.",
     "Karrkay-karrkay baya ngundu-ba bundan, kaba daran.",
     "karrkay-karrkay baya ngundu-ba bunda-ny, kaba dara-ny | child-REDUP fire near-LOC sit-PAST, rain fall-PAST",
     "fire_rain_setting", 4, js(["karrkay", "baya", "ngundu", "bundal", "kaba", "daray"]),
     "Common corpus/Patz locative frame baya ngundu-ba; attested kaba dara-ny rain-fell.", "0.84"),
    (13, "The wet wood did not burn.",
     "Juku duna kari wajun.",
     "juku duna kari waju-ny | wood wet NEG burn-PAST",
     "wet_wood_negative", 3, js(["juku", "duna", "kari", "wajul"]),
     "Errata: duna/yaru are the wet terms; waju-l covers intransitive burn.", "0.85"),
    (14, "Dry wood burns well.",
     "Juku marral ngulkurr waju-l.",
     "juku marral ngulkurr waju-l | wood dry good burn-NONPAST",
     "dry_wood_burns", 3, js(["juku", "marral", "ngulkurr", "wajul"]),
     "Dictionary/errata: marral dry; waju-l burn/cook.", "0.84"),
    (15, "They covered the fire with sand before they left.",
     "Jana baya nandan jukar-bu, dunga-nyjiku.",
     "jana baya nanda-ny jukar-bu, dunga-nyjiku | they fire cover-PAST sand-INST go-SUCC",
     "fire_cover_before_leaving", 4, js(["jana", "baya", "nandal", "jukar", "dungay"]),
     "Existing corpus fire-safety model: baya nanda-ny jukar-bu before departure.", "0.84"),
    (16, "The women dug a ground oven near the camp.",
     "Jalbu-jalbu-ngku kurrma bakan bayan ngundu-ba.",
     "jalbu-jalbu-ngku kurrma baka-ny bayan ngundu-ba | woman-REDUP-ERG ground.oven dig-PAST camp near-LOC",
     "earth_oven_digging", 4, js(["jalbu", "kurrma", "bakal", "bayan", "ngundu"]),
     "Patz earth-oven sequence and existing corpus kurrma baka-ny pattern.", "0.86"),
    (17, "They lit the ground oven and put the meat in it.",
     "Jana kurrma wajun, minya kurrma-nga yijarrin.",
     "jana kurrma waju-ny, minya kurrma-nga yijarri-ny | they ground.oven light-PAST meat ground.oven-LOC put-PAST",
     "earth_oven_light_put", 4, js(["jana", "kurrma", "wajul", "minya", "yijarril"]),
     "Patz lines 64-65: kurrma waju-nyu; kurrma-nga yijarri-nya minya.", "0.88"),
    (18, "They roasted the meat in the ground oven.",
     "Jana minya dindan kurrma-nga.",
     "jana minya dinda-ny kurrma-nga | they meat roast-PAST ground.oven-LOC",
     "earth_oven_roasting", 4, js(["jana", "minya", "dindal", "kurrma"]),
     "Patz earth-oven narrative: minya, kurrma-nga dinda-ny.", "0.88"),
    (19, "They put paperbark on top of the meat.",
     "Jana buyku yijarrin minya wangkar-a.",
     "jana buyku yijarri-ny minya wangkar-a | they paperbark put-PAST meat top-LOC",
     "paperbark_cover", 4, js(["jana", "buyku", "yijarril", "minya", "wangkar"]),
     "Patz line 66: buyku covers/sits on top of the meat in the oven.", "0.84"),
    (20, "They left the ground oven in the ground for a long time.",
     "Jana kurrma bawan bubu-ngu wungar kalbay.",
     "jana kurrma bawa-ny bubu-ngu wungar kalbay | they ground.oven leave-PAST ground-LOC time long",
     "earth_oven_left", 4, js(["jana", "kurrma", "bawal", "bubu", "wungar", "kalbay"]),
     "Patz line 67: Bubu-ngu bundanda-nya, bawa-nya.", "0.85"),
    (21, "When the meat was cooked, they took the meat out.",
     "Minya wajun, jana minya walngan.",
     "minya waju-ny, jana minya walnga-ny | meat cook-PAST, they meat take.out-PAST",
     "cooked_meat_removed", 4, js(["minya", "wajul", "jana", "walngal"]),
     "Patz line 69: minya waju-ny, walnga-ny.", "0.88"),
    (22, "They dug the ground oven open again, and a good smell came.",
     "Jana kurrma bakan baja, nganja ngulkurr kadan.",
     "jana kurrma baka-ny baja, nganja ngulkurr kada-ny | they ground.oven dig-PAST again smell good come-PAST",
     "earth_oven_open_smell", 4, js(["jana", "kurrma", "bakal", "baja", "nganja", "ngulkurr", "kaday"]),
     "Existing kurrma baka-ny baja model; errata confirms nganja taste/smell.", "0.84"),
    (23, "The fish cooked well in the hot coals.",
     "Kuyu ngulkurr wajun ngunjil wumbul-ba.",
     "kuyu ngulkurr waju-ny ngunjil wumbul-ba | fish good cook-PAST coals hot-LOC",
     "coals_cooking", 4, js(["kuyu", "ngulkurr", "wajul", "ngunjil", "wumbul"]),
     "Errata: ngunjil coals, wumbul hot; waju-l cook/burn.", "0.85"),
    (24, "The old woman roasted the zamia nuts before pounding them.",
     "Mukul-jalbu-ngku marra dindan, duda-nyjiku.",
     "mukul-jalbu-ngku marra dinda-ny, duda-nyjiku | old-woman-ERG zamia.nut roast-PAST pound-SUCC",
     "roast_before_pound", 4, js(["mukul-jalbu", "marra", "dindal", "dudal"]),
     "Patz direct model: marra dinda-l, duda-nyjiku.", "0.87"),
    (25, "Maybe they boil the fish, maybe they roast it.",
     "Nguba jana kuyu nyama-l, nguba dinda-l.",
     "nguba jana kuyu nyama-l, nguba dinda-l | maybe they fish boil-NONPAST, maybe roast-NONPAST",
     "cooking_alternatives", 4, js(["nguba", "jana", "kuyu", "nyamal", "dindal"]),
     "Patz direct model: Nguba ... kuyu nyama-l, nguba dinda-l.", "0.87"),
    (26, "I cook the fish first and then take it.",
     "Ngayu kuyu waju-l-urr wundi-l-da.",
     "ngayu kuyu waju-l-urr wundi-l-da | I fish cook-NONPAST-FIRST take-NONPAST-THEN",
     "first_cook_then_take", 4, js(["ngayu", "kuyu", "wajul", "wundil"]),
     "Patz direct sequencing line: Ngayu kuyu waju-l-urr wundi-l-da.", "0.88"),
    (27, "The ground oven was still hot in the ground.",
     "Kurrma bubu-ngu wumbul warngku.",
     "kurrma bubu-ngu wumbul warngku | ground.oven ground-LOC hot still",
     "earth_oven_still_hot", 3, js(["kurrma", "bubu", "wumbul", "warngku"]),
     "Earth-oven sequence leaves kurrma in bubu-ngu; wumbul 'hot'.", "0.83"),
    (28, "The meat in the ground oven was not burnt.",
     "Minya kurrma-nga kari jirra.",
     "minya kurrma-nga kari jirra | meat ground.oven-LOC NEG burnt",
     "not_burnt", 3, js(["minya", "kurrma", "kari", "jirra"]),
     "Errata fire list: jirra 'burnt'; ordinary kari negation.", "0.84"),
    (29, "The food in the ground oven was well cooked.",
     "Mayi kurrma-nga jani.",
     "mayi kurrma-nga jani | food ground.oven-LOC well.cooked",
     "well_cooked_food", 3, js(["mayi", "kurrma", "jani"]),
     "Errata: jani is legitimate only in the cooking sense 'well cooked/done'.", "0.86"),
    (30, "The children sat near the ground oven to eat.",
     "Karrkay-karrkay kurrma ngundu-ba bundan, nuka-nka.",
     "karrkay-karrkay kurrma ngundu-ba bunda-ny, nuka-nka | child-REDUP ground.oven near-LOC sit-PAST eat-PURP",
     "sit_to_eat", 4, js(["karrkay", "kurrma", "ngundu", "bundal", "nukal"]),
     "Errata warns that 'wait' has no clean single verb; use bunda-l 'sit' with purpose -nka.", "0.84"),
    (31, "The women ground the seeds for damper.",
     "Jalbu-jalbu-ngku diburr nyurrban damba-ka.",
     "jalbu-jalbu-ngku diburr nyurrba-ny damba-ka | woman-REDUP-ERG seed grind-PAST damper-DAT",
     "grind_for_damper", 4, js(["jalbu", "diburr", "nyurrbal", "damba"]),
     "Existing accepted model: diburr nyurrba-ny damba-ka.", "0.86"),
    (32, "The girl ground yams with a stone.",
     "Maral-ngku wukay nyurrban kulji-bu.",
     "maral-ngku wukay nyurrba-ny kulji-bu | girl-ERG yam grind-PAST stone-INST",
     "grind_with_stone", 4, js(["maral", "wukay", "nyurrbal", "kulji"]),
     "Dictionary/errata: nyurrba-l grind; ordinary instrumental -bu.", "0.84"),
    (33, "The woman kneaded the damper.",
     "Jalbu-ngku damba dingkan.",
     "jalbu-ngku damba dingka-ny | woman-ERG damper knead-PAST",
     "knead_damper", 4, js(["jalbu", "damba", "dingkal"]),
     "Patz line 5431 uses mayi damba dingka-nyjiku 'before kneading damper'.", "0.85"),
    (34, "Mother stirred the honey bread, and the honey bread had a good taste.",
     "Ngamu-ngku kawar murnin, kawar nganja ngulkurr.",
     "ngamu-ngku kawar murni-ny, kawar nganja ngulkurr | mother-ERG honey.bread stir-PAST, honey.bread taste good",
     "stir_honey_bread", 4, js(["ngamu", "kawar", "murnil", "nganja", "ngulkurr"]),
     "Errata cooking list includes kawar honey bread, murni-l stir/rub/twist, nganja taste/smell.", "0.84"),
    (35, "The honey was good, and the honey bread was good.",
     "Wunba ngulkurr, kawar ngulkurr.",
     "wunba ngulkurr, kawar ngulkurr | honey good, honey.bread good",
     "honey_bread_quality", 2, js(["wunba", "ngulkurr", "kawar"]),
     "Dictionary/errata: wunba honey; kawar honey bread.", "0.85"),
    (36, "The cooked meat with fat was good.",
     "Minya jani wandul-ji ngulkurr.",
     "minya jani wandul-ji ngulkurr | meat well.cooked fat-COMIT good",
     "fat_cooked_meat", 3, js(["minya", "jani", "wandul", "ngulkurr"]),
     "Errata: wandul fat, jani well cooked; comitative -ji is productive.", "0.84"),
    (37, "The ripe yams cooked well.",
     "Wukay kulbul ngulkurr wajun.",
     "wukay kulbul ngulkurr waju-ny | yam ripe good cook-PAST",
     "ripe_yams_cook", 3, js(["wukay", "kulbul", "ngulkurr", "wajul"]),
     "Errata cooking list: kulbul ripe, wukay yam; waju-l cook.", "0.84"),
    (38, "They ground ripe yams and made damper.",
     "Jana wukay kulbul nyurrban, damba bungan.",
     "jana wukay kulbul nyurrba-ny, damba bunga-ny | they yam ripe grind-PAST, damper make-PAST",
     "grind_make_damper", 4, js(["jana", "wukay", "kulbul", "nyurrbal", "damba", "bungal"]),
     "Nyurrba-l grind plus bunga-l make; food terms from errata.", "0.84"),
    (39, "The old woman ground again; the children were hungry.",
     "Mukul-jalbu nyurrban baja, karrkay-karrkay dakwuy.",
     "mukul-jalbu nyurrba-ny baja, karrkay-karrkay dakwuy | old-woman grind-PAST again, child-REDUP hungry",
     "grind_again_hungry_children", 4, js(["mukul-jalbu", "nyurrbal", "baja", "karrkay", "dakwuy"]),
     "Errata: dakwuy hungry; baja as separate 'again' clitic.", "0.83"),
    (40, "They ground the seeds, made damper, and cooked it on the fire.",
     "Jana diburr nyurrban, damba bungan, baya-nga wajun.",
     "jana diburr nyurrba-ny, damba bunga-ny, baya-nga waju-ny | they seed grind-PAST, damper make-PAST, fire-LOC cook-PAST",
     "grind_make_cook", 4, js(["jana", "diburr", "nyurrbal", "damba", "bungal", "baya", "wajul"]),
     "Combines attested grinding/damper terms with baya-nga cooking location.", "0.84"),
    (41, "Mother shared out all the cooked fish.",
     "Ngamu kuyu jani-nga wambi-jin.",
     "ngamu kuyu jani-nga wambi-ji-ny | mother fish well.cooked-LOC share.out-APASS-PAST",
     "share_cooked_fish", 4, js(["ngamu", "kuyu", "jani", "wambil"]),
     "Patz wambi-ji-ny total-distribution antipassive; jani only in cooking sense.", "0.84"),
    (42, "The hungry children ate near the fire.",
     "Karrkay-karrkay dakwuy nukan baya ngundu-ba.",
     "karrkay-karrkay dakwuy nuka-ny baya ngundu-ba | child-REDUP hungry eat-PAST fire near-LOC",
     "hungry_children_eat", 3, js(["karrkay", "dakwuy", "nukal", "baya", "ngundu"]),
     "Errata: dakwuy hungry; common fire-location frame baya ngundu-ba.", "0.84"),
    (43, "The old person ate, and then everyone ate.",
     "Mukul-bama nukan, baja bama wubulku nukan.",
     "mukul-bama nuka-ny, baja bama wubul-ku nuka-ny | old-person eat-PAST, then person all-EMPH eat-PAST",
     "meal_order_respect", 3, js(["mukul-bama", "nukal", "baja", "bama", "wubul"]),
     "Moral-register note in Rule 83: old/guest fed before general eating.", "0.82"),
    (44, "One child was not left hungry.",
     "Karrkay nyubun kari dakwuy bundan.",
     "karrkay nyubun kari dakwuy bunda-ny | child one NEG hungry sit-PAST",
     "no_child_left_hungry", 3, js(["karrkay", "nyubun", "kari", "dakwuy", "bundal"]),
     "Moral-register note: no one should sit/watch hungry while others eat.", "0.82"),
    (45, "The old woman gave food to the hungry child.",
     "Mukul-jalbu-ngku mayi dajin karrkay dakwuy-nka.",
     "mukul-jalbu-ngku mayi daji-ny karrkay dakwuy-nka | old-woman-ERG food give-PAST child hungry-DAT",
     "feed_hungry_child", 4, js(["mukul-jalbu", "mayi", "dajil", "karrkay", "dakwuy"]),
     "Food-sharing frame with dative recipient; dakwuy hungry from errata.", "0.84"),
    (46, "We ate fish, damper, and honey by the fire.",
     "Ngana kuyu damba wunba nukan baya-nga.",
     "ngana kuyu damba wunba nuka-ny baya-nga | we fish damper honey eat-PAST fire-LOC",
     "meal_by_fire", 3, js(["ngana", "kuyu", "damba", "wunba", "nukal", "baya"]),
     "Existing meal-by-fire model expanded with verified wunba honey.", "0.84"),
    (47, "The cooked meat had a good taste.",
     "Minya jani nganja ngulkurr.",
     "minya jani nganja ngulkurr | meat well.cooked taste good",
     "good_taste", 3, js(["minya", "jani", "nganja", "ngulkurr"]),
     "Errata: jani well cooked, nganja taste/smell.", "0.85"),
    (48, "Everyone became full after the meal.",
     "Bama wubulku yajinmanin mayi-muny.",
     "bama wubul-ku yajin-ma-ny mayi-muny | person all-EMPH full-INCH-PAST food-ABL",
     "full_after_food", 3, js(["bama", "wubul", "yajin", "mayi"]),
     "Errata: yajin full from eating; ordinary ABL -muny.", "0.83"),
    (49, "The children did not spoil the food.",
     "Karrkay-karrkay mayi kari buyun-daman.",
     "karrkay-karrkay mayi kari buyun-dama-ny | child-REDUP food NEG bad-make-PAST",
     "do_not_spoil_food", 4, js(["karrkay", "mayi", "kari", "buyun-damal"]),
     "Patz warning model: Mayi kari waju, buyun-dama-nyji.", "0.84"),
    (50, "The old man said, cook the food well and give it to the children.",
     "Mukul-dingkar balkan, mayi ngulkurr waju, karrkay-karrkay-nka daji.",
     "mukul-dingkar balka-ny, mayi ngulkurr waju, karrkay-karrkay-nka daji | old-man say-PAST, food good cook.IMP, child-REDUP-DAT give.IMP",
     "meal_instruction", 4, js(["mukul-dingkar", "balkal", "mayi", "ngulkurr", "wajul", "karrkay", "dajil"]),
     "Direct-speech imperative pattern constrained to attested waju and daji stems.", "0.83"),
]


def scan() -> list[str]:
    issues: list[str] = []
    if len(ROWS) != 50:
        issues.append(f"expected 50 rows, got {len(ROWS)}")
    seqs = [r[0] for r in ROWS]
    if seqs != list(range(1, 51)):
        issues.append(f"seqs must be 1..50, got {seqs[:5]}...{seqs[-5:]}")
    seen_ku: set[str] = set()
    for row in ROWS:
        seq, english, kuku, analysis, frame, tier, words_used, evidence, confidence = row
        label = f"{LABEL}.{seq:02d}"
        if not english[:1].isupper() or english.rstrip("'\"").rstrip()[-1:] not in ".!?":
            issues.append(f"{label}: English must be capitalized and final-punctuated")
        if " | " not in analysis:
            issues.append(f"{label}: analysis missing gloss separator")
        if not kuku[:1].isupper():
            issues.append(f"{label}: Kuku surface must start uppercase")
        try:
            json.loads(words_used)
        except Exception as exc:
            issues.append(f"{label}: words_used is not JSON: {exc}")
        low = f" {kuku.lower()} {analysis.lower()} "
        for word in DENY:
            if re.search(rf"(?<![a-z]){re.escape(word)}(?![a-z])", low):
                issues.append(f"{label}: denied phantom/wrong-sense token {word!r}")
        if kuku.lower() in seen_ku:
            issues.append(f"{label}: duplicate Kuku surface within batch")
        seen_ku.add(kuku.lower())
    return issues


def main() -> int:
    issues = scan()
    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")
    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 83 draft: fire and cooking lexical domain", "operator-guide-2026-07-07", "under_review", NOW),
        )
        batch_id = cur.lastrowid

    db.executemany(
        """
        INSERT INTO sentences(
            batch_id, seq, english, kuku, analysis, frame, tier, words_used,
            loans_used, evidence, status, confidence, rights_status, author,
            created_at, updated_at
        ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
        """,
        [
            (
                batch_id, seq, english, kuku, analysis, frame, tier, words_used,
                "[]", evidence, "under_review", confidence,
                "project_approved_synthetic_pending_elder_verification",
                "claude-main", NOW, NOW,
            )
            for seq, english, kuku, analysis, frame, tier, words_used, evidence, confidence in ROWS
        ],
    )
    db.commit()
    count = db.execute("SELECT COUNT(*) FROM sentences WHERE batch_id=?", (batch_id,)).fetchone()[0]
    avg_words = db.execute(
        "SELECT AVG(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1.0) FROM sentences WHERE batch_id=?",
        (batch_id,),
    ).fetchone()[0]
    print(f"banked {LABEL}: {count} rows under_review; avg Kuku words/row={avg_words:.2f}")
    return 0


if __name__ == "__main__":
    sys.exit(main())
