#!/usr/bin/env python3
"""Bank batch-142: direct speech, quotation, and reporting frames."""

from __future__ import annotations

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

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

DENY = {
    "nyawa", "jinbi", "jibin", "walba", "julmbu", "wanan", "ngampula",
    "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", "balbay-nja", "bunjurril", "buri",
    "baral", "ngara", "rrunyuji", "jabul", "yukil", "bama-jambul",
    "answer",
}


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


ROWS = [
    (1, 'The old man said to the child: "Sit down!"',
     'Mukul-dingkar-angka karrkay-anda balkan: "Bunda-y!"',
     'mukul-dingkar-angka karrkay-anda balka-ny: "bunda-y" | old-man-ERG child-LOC say-PAST: "sit-IMP"',
     "balka_loc_addressee_direct_quote", 5, js(["mukul-dingkar", "karrkay", "balkal", "bunday"]), js([]),
     "Patz dialogue controls balka-ny before quote; living rule requires LOC:pt addressee.", "0.88"),
    (2, 'Mother said to the child: "Eat the food!"',
     'Ngamu-ngku karrkay-anda balkan: "Mayi nuka!"',
     'ngamu-ngku karrkay-anda balka-ny: "mayi nuka" | mother-ERG child-LOC say-PAST: "food eat.IMP"',
     "balka_loc_addressee_direct_quote", 5, js(["ngamu", "karrkay", "balkal", "mayi", "nukal"]), js([]),
     "LOC addressee follows Rule 100 control; quote uses source-shaped imperative nuka.", "0.86"),
    (3, 'Father said to the young man: "Go to the house!"',
     'Nganjan-angka warru-nda balkan: "Bayan-ba dunga-y!"',
     'nganjan-angka warru-nda balka-ny: "bayan-ba dunga-y" | father-ERG young.man-LOC say-PAST: "house-LOC go-IMP"',
     "balka_loc_addressee_direct_quote", 5, js(["nganjan", "warru", "balkal", "bayan", "dungay"]), js([]),
     "Warru-nda follows the same LOC person-address frame as babaji-y examples.", "0.84"),
    (4, 'Grandmother said to the girl: "Come to the fire!"',
     'Babi-ngka jalbu-karrkay-anda balkan: "Baya-ngundu kada-y!"',
     'babi-ngka jalbu-karrkay-anda balka-ny: "baya-ngundu kada-y" | grandmother-ERG girl-child-LOC say-PAST: "fire-near come-IMP"',
     "balka_loc_addressee_direct_quote", 5, js(["babi", "jalbu-karrkay", "balkal", "baya", "ngundu", "kaday"]), js([]),
     "Direct quote row; addressee is LOC:pt, not bare ABS.", "0.84"),
    (5, 'The old woman said to the children: "Do not shout!"',
     'Mukul-jalbu-ngku karrkay-karra-nda balkan: "Kari yirrka-y!"',
     'mukul-jalbu-ngku karrkay-karra-nda balka-ny: "kari yirrka-y" | old-woman-ERG child-PL-LOC say-PAST: "NEG shout-IMP"',
     "balka_plural_loc_addressee_direct_quote", 5, js(["mukul-jalbu", "karrkay", "-karra", "balkal", "kari", "yirrkay"]), js([]),
     "Patz imperative source has Kari yirrka-y; plural addressee keeps LOC:pt.", "0.88"),
    (6, 'The man said to the woman: "Do not go!"',
     'Dingkar-angka jalbu-ndu balkan: "Kari dunga-y!"',
     'dingkar-angka jalbu-ndu balka-ny: "kari dunga-y" | man-ERG woman-LOC say-PAST: "NEG go-IMP"',
     "balka_loc_addressee_direct_quote", 5, js(["dingkar", "jalbu", "balkal", "kari", "dungay"]), js([]),
     "Negative imperative is carried inside the quote; reporting clause remains ordinary past.", "0.86"),
    (7, 'The woman said to the man: "That is fish."',
     'Jalbu-ngku dingkar-anda balkan: "Yinya kuyu."',
     'jalbu-ngku dingkar-anda balka-ny: "yinya kuyu" | woman-ERG man-LOC say-PAST: "that fish"',
     "balka_loc_addressee_direct_quote", 5, js(["jalbu", "dingkar", "balkal", "yinya", "kuyu"]), js([]),
     "Short nominal quoted clause; addressee is LOC:pt to preserve say-to sense.", "0.84"),
    (8, 'Grandfather said to grandmother: "I know."',
     'Kami-ngka babi-nda balkan: "Ngayu binal."',
     'kami-ngka babi-nda balka-ny: "ngayu binal" | grandfather-ERG grandmother-LOC say-PAST: "I know"',
     "balka_loc_addressee_direct_quote", 5, js(["kami", "babi", "balkal", "ngayu", "binal"]), js([]),
     "Quoted cognition clause; reporting addressee follows Ngayu Chris-anda balka-ny source pattern.", "0.84"),
    (9, 'Grandmother said to grandfather: "I do not know."',
     'Babi-ngka kami-nda balkan: "Ngayu kari binal."',
     'babi-ngka kami-nda balka-ny: "ngayu kari binal" | grandmother-ERG grandfather-LOC say-PAST: "I NEG know"',
     "balka_loc_addressee_direct_quote", 5, js(["babi", "kami", "balkal", "ngayu", "kari", "binal"]), js([]),
     "Negated quoted clause; no complementizer introduced.", "0.84"),
    (10, 'The old man said to the old woman: "That child came."',
     'Mukul-dingkar-angka mukul-jalbu-ndu balkan: "Yinya karrkay kadan."',
     'mukul-dingkar-angka mukul-jalbu-ndu balka-ny: "yinya karrkay kada-ny" | old-man-ERG old-woman-LOC say-PAST: "that child come-PAST"',
     "balka_loc_addressee_direct_quote", 5, js(["mukul-dingkar", "mukul-jalbu", "balkal", "yinya", "karrkay", "kaday"]), js([]),
     "Direct quoted declarative; authored surface normalizes past -ny to -n.", "0.86"),
    (11, 'Mother said: "You two spear it with a digging stick!"',
     'Ngamu-ngku yalaman: "Yubal juwal-da dama!"',
     'ngamu-ngku yalama-ny: "yubal juwal-da dama" | mother-ERG say-PAST: "you.two digging.stick-INST spear.IMP"',
     "yalama_direct_quote_source_frame", 5, js(["ngamu", "yalamal", "yubal", "juwal", "damal"]), js([]),
     "Close to Patz Text 51 source frame Kari ngamu-ngku-lu yalama-ny.", "0.90"),
    (12, 'The wives said: "Go to get fish!"',
     'Manyarr-karra-ngka yalaman: "Dunga-y kuyu mani-nka!"',
     'manyarr-karra-ngka yalama-ny: "dunga-y kuyu mani-nka" | wife-PL-ERG say-PAST: "go-IMP fish get-PURP"',
     "yalama_direct_quote_source_frame", 5, js(["manyarr", "-karra", "yalamal", "dungay", "kuyu", "manil"]), js([]),
     "Patz example controls wives + yalama-ny + quoted dunga-y kuyu mani-nka.", "0.90"),
    (13, 'One person said: "Shall we two climb?"',
     'Yinduy-nju yalaman: "Ngali daka-l?"',
     'yinduy-nju yalama-ny: "ngali daka-l" | one-ERG say-PAST: "we.two climb-NONPAST"',
     "yalama_quoted_question_source_frame", 5, js(["yinduy", "yalamal", "ngali", "dakal"]), js([]),
     "Directly follows appendix text yinduy-nju yalama-ny: Ngali daka-l?", "0.90"),
    (14, 'The old woman said: "Where did you two come from?"',
     'Wulbuman-angka balkan: "Yubal wanja-muny kadan?"',
     'wulbuman-angka balka-ny: "yubal wanja-muny kada-ny" | old.woman-ERG say-PAST: "you.two where-ABL come-PAST"',
     "balka_direct_quote_source_frame", 5, js(["wulbuman", "balkal", "yubal", "wanja", "kaday"]), js([]),
     "Appendix text controls Wulbuman-angka balka-ny with a quoted where-from question.", "0.90"),
    (15, 'He said: "You sit there!"',
     'Nyulu yalaman: "Yundu yinyay bunda-y!"',
     'nyulu yalama-ny: "yundu yinyay bunda-y" | he say-PAST: "you there sit-IMP"',
     "yalama_direct_quote", 5, js(["nyulu", "yalamal", "yundu", "yinyay", "bunday"]), js([]),
     "Pronoun subject plus yalama-ny reporting; quoted command uses attested bunda-y.", "0.84"),
    (16, 'They said: "Yes!"',
     'Jana yalaman: "Yuwu!"',
     'jana yalama-ny: "yuwu" | they say-PAST: "yes"',
     "yalama_short_reply_quote", 5, js(["jana", "yalamal", "yuwu"]), js([]),
     "Appendix text attests quote-only Yuwu/Yuwu! reply material.", "0.88"),
    (17, 'They said: "No."',
     'Jana yalaman: "Kari."',
     'jana yalama-ny: "kari" | they say-PAST: "no"',
     "yalama_short_reply_quote", 5, js(["jana", "yalamal", "kari"]), js([]),
     "Appendix text attests quote-only Kari. reply material.", "0.88"),
    (18, 'The old man said: "Alright."',
     'Mukul-dingkar-angka yalaman: "Yalada."',
     'mukul-dingkar-angka yalama-ny: "yalada" | old-man-ERG say-PAST: "alright/settled"',
     "yalama_discourse_quote", 5, js(["mukul-dingkar", "yalamal", "yalada"]), js([]),
     "Errata identifies yalada as settled/alright discourse material.", "0.84"),
    (19, 'The child asked mother: "Do you want food?"',
     'Karrkay ngamu-ndu babajin: "Yundu mayi-ka wawu?"',
     'karrkay ngamu-ndu babaji-ny: "yundu mayi-ka wawu" | child mother-LOC ask-PAST: "you food-DAT want"',
     "babaji_abs_actor_loc_person_direct_question", 5, js(["karrkay", "ngamu", "babaji", "yundu", "mayi", "wawu"]), js([]),
     "Rule 98/99 living rule: babaji-y actor ABS, person asked LOC, topic DAT.", "0.88"),
    (20, 'The young man asked father: "Did you come back?"',
     'Warru nganjan-anda babajin: "Yundu kada-ny-baja?"',
     'warru nganjan-anda babaji-ny: "yundu kada-ny-baja" | young.man father-LOC ask-PAST: "you come-PAST-again"',
     "babaji_abs_actor_loc_person_direct_question", 5, js(["warru", "nganjan", "babaji", "yundu", "kaday", "baja"]), js([]),
     "Appendix text has Chris-anda babaji-ny: Yundu kada-ny-baja?", "0.88"),
    (21, 'The woman asked grandmother: "Where is the water?"',
     'Jalbu babi-nda babajin: "Bana wanjabu?"',
     'jalbu babi-nda babaji-ny: "bana wanjabu" | woman grandmother-LOC ask-PAST: "water where"',
     "babaji_abs_actor_loc_person_direct_question", 5, js(["jalbu", "babi", "babaji", "bana", "wanjabu"]), js([]),
     "Direct quoted content question; actor stays ABS under babaji-y.", "0.84"),
    (22, 'The man asked the old woman: "What did the dog eat?"',
     'Dingkar mukul-jalbu-ndu babajin: "Wanyu kaya-ngka nukan?"',
     'dingkar mukul-jalbu-ndu babaji-ny: "wanyu kaya-ngka nuka-ny" | man old-woman-LOC ask-PAST: "what dog-ERG eat-PAST"',
     "babaji_abs_actor_loc_person_direct_question", 5, js(["dingkar", "mukul-jalbu", "babaji", "wanyu", "kaya", "nukal"]), js([]),
     "Question word remains inside the quote; report frame has ABS actor and LOC person asked.", "0.84"),
    (23, 'Mother asked the child: "Who saw the fish?"',
     'Ngamu karrkay-anda babajin: "Wanyangka kuyu nyajin?"',
     'ngamu karrkay-anda babaji-ny: "wanyangka kuyu nyaji-ny" | mother child-LOC ask-PAST: "who.ERG fish see-PAST"',
     "babaji_abs_actor_loc_person_direct_question", 5, js(["ngamu", "karrkay", "babaji", "wanya", "kuyu", "nyajil"]), js([]),
     "Who-question retained only as quoted content; not a new interrogative batch.", "0.84"),
    (24, 'Grandfather asked the young woman: "When will you come?"',
     'Kami warru-jalbu-ndu babajin: "Wanjawanja yundu kada-y?"',
     'kami warru-jalbu-ndu babaji-ny: "wanjawanja yundu kada-y" | grandfather young-woman-LOC ask-PAST: "when you come-NONPAST"',
     "babaji_abs_actor_loc_person_direct_question", 5, js(["kami", "warru-jalbu", "babaji", "wanjawanja", "yundu", "kaday"]), js([]),
     "Rule 66 interrogative form appears as direct quoted content; babaji-y frame remains the target.", "0.82"),
    (25, 'The old woman asked the man: "Why did you shout?"',
     'Mukul-jalbu dingkar-anda babajin: "Wanyurringku yundu yirrkan?"',
     'mukul-jalbu dingkar-anda babaji-ny: "wanyurringku yundu yirrka-ny" | old-woman man-LOC ask-PAST: "why you shout-PAST"',
     "babaji_abs_actor_loc_person_direct_question", 5, js(["mukul-jalbu", "dingkar", "babaji", "wanyurringku", "yundu", "yirrkay"]), js([]),
     "Actor is ABS/S despite common noun; this avoids the old Rule 66 ERG drift.", "0.84"),
    (26, 'The boy asked the old man: "What kind of bird called?"',
     'Karrkay mukul-dingkar-anda babajin: "Wanyu-nguy buyi yirrkan?"',
     'karrkay mukul-dingkar-anda babaji-ny: "wanyu-nguy buyi yirrka-ny" | child old-man-LOC ask-PAST: "what-kind bird call-PAST"',
     "babaji_abs_actor_loc_person_direct_question", 5, js(["karrkay", "mukul-dingkar", "babaji", "wanyu-nguy", "buyi", "yirrkay"]), js([]),
     "Question type is inside quote; report construction is the reviewed grammar point.", "0.82"),
    (27, 'The child asked mother: "Do you want food?" Mother said: "Yes."',
     'Karrkay ngamu-ndu babajin: "Yundu mayi-ka wawu?" Ngamu-ngku balkan: "Yuwu."',
     'karrkay ngamu-ndu babaji-ny: "yundu mayi-ka wawu" ngamu-ngku balka-ny: "yuwu" | child mother-LOC ask-PAST: "you food-DAT want" mother-ERG say-PAST: "yes"',
     "direct_question_short_reply_pair", 5, js(["karrkay", "ngamu", "babaji", "yundu", "mayi", "wawu", "balkal", "yuwu"]), js([]),
     "Question-response pairing; reply uses balkan, not a separate answer lexeme.", "0.86"),
    (28, 'The child asked father: "Did the dog come?" Father said: "No."',
     'Karrkay nganjan-anda babajin: "Kaya kadan?" Nganjan-angka balkan: "Kari."',
     'karrkay nganjan-anda babaji-ny: "kaya kada-ny" nganjan-angka balka-ny: "kari" | child father-LOC ask-PAST: "dog come-PAST" father-ERG say-PAST: "no"',
     "direct_question_short_reply_pair", 5, js(["karrkay", "nganjan", "babaji", "kaya", "kaday", "balkal", "kari"]), js([]),
     "Polar question inside quote; no question particle added.", "0.86"),
    (29, 'The young woman asked grandmother: "Did the fire go out?" Grandmother said: "Yes."',
     'Warru-jalbu babi-nda babajin: "Baya wulan?" Babi-ngka balkan: "Yuwu."',
     'warru-jalbu babi-nda babaji-ny: "baya wula-ny" babi-ngka balka-ny: "yuwu" | young-woman grandmother-LOC ask-PAST: "fire die/go.out-PAST" grandmother-ERG say-PAST: "yes"',
     "direct_question_short_reply_pair", 5, js(["warru-jalbu", "babi", "babaji", "baya", "wulay", "balkal", "yuwu"]), js([]),
     "Uses surface past wulan; reply is direct quoted yuwu.", "0.84"),
    (30, 'The man asked the old woman: "Is that fish?" The old woman said: "No."',
     'Dingkar mukul-jalbu-ndu babajin: "Yinya kuyu?" Mukul-jalbu-ngku balkan: "Kari."',
     'dingkar mukul-jalbu-ndu babaji-ny: "yinya kuyu" mukul-jalbu-ngku balka-ny: "kari" | man old-woman-LOC ask-PAST: "that fish" old-woman-ERG say-PAST: "no"',
     "direct_question_short_reply_pair", 5, js(["dingkar", "mukul-jalbu", "babaji", "yinya", "kuyu", "balkal", "kari"]), js([]),
     "Short quoted polar question; response uses source-attested Kari.", "0.84"),
    (31, 'Mother asked the child: "Are you cold?" The child said: "No."',
     'Ngamu karrkay-anda babajin: "Yundu ngiki?" Karrkay-ngku balkan: "Kari."',
     'ngamu karrkay-anda babaji-ny: "yundu ngiki" karrkay-ngku balka-ny: "kari" | mother child-LOC ask-PAST: "you cold" child-ERG say-PAST: "no"',
     "direct_question_short_reply_pair", 5, js(["ngamu", "karrkay", "babaji", "yundu", "ngiki", "balkal", "kari"]), js([]),
     "Babaji actor remains ABS; child is ERG only in the separate balkan reply clause.", "0.84"),
    (32, 'Father asked the young man: "Are you hungry?" The young man said: "Yes."',
     'Nganjan warru-nda babajin: "Yundu dakwuy?" Warru-ngku balkan: "Yuwu."',
     'nganjan warru-nda babaji-ny: "yundu dakwuy" warru-ngku balka-ny: "yuwu" | father young.man-LOC ask-PAST: "you hungry" young.man-ERG say-PAST: "yes"',
     "direct_question_short_reply_pair", 5, js(["nganjan", "warru", "babaji", "yundu", "dakwuy", "balkal", "yuwu"]), js([]),
     "Separate clauses keep babaji-y ABS actor and balkan ERG actor distinct.", "0.82"),
    (33, 'The old man asked the child: "Do you know this story?" The child said: "I know."',
     'Mukul-dingkar karrkay-anda babajin: "Yundu yanyu kuku binal?" Karrkay-ngku balkan: "Ngayu binal."',
     'mukul-dingkar karrkay-anda babaji-ny: "yundu yanyu kuku binal" karrkay-ngku balka-ny: "ngayu binal" | old-man child-LOC ask-PAST: "you this story know" child-ERG say-PAST: "I know"',
     "direct_question_short_reply_pair", 5, js(["mukul-dingkar", "karrkay", "babaji", "yundu", "yanyu", "kuku", "binal", "balkal", "ngayu"]), js([]),
     "Cognition content stays inside the direct quote; no complementizer.", "0.84"),
    (34, 'The old woman asked the child: "Do you see the dog?" The child said: "I see it."',
     'Mukul-jalbu karrkay-anda babajin: "Yundu kaya nyajil?" Karrkay-ngku balkan: "Ngayu nyajil."',
     'mukul-jalbu karrkay-anda babaji-ny: "yundu kaya nyaji-l" karrkay-ngku balka-ny: "ngayu nyaji-l" | old-woman child-LOC ask-PAST: "you dog see-NONPAST" child-ERG say-PAST: "I see-NONPAST"',
     "direct_question_short_reply_pair", 5, js(["mukul-jalbu", "karrkay", "babaji", "yundu", "kaya", "nyajil", "balkal", "ngayu"]), js([]),
     "Short direct Q/A pair; the quoted verb remains inside the quote.", "0.84"),
    (35, 'The child cried out to mother: "Mother, come!"',
     'Karrkay ngamu-ndu yirrkan: "Ngamu, kada-y!"',
     'karrkay ngamu-ndu yirrka-ny: "ngamu kada-y" | child mother-LOC cry.out-PAST: "mother come-IMP"',
     "yirrkay_abs_actor_loc_addressee_quote", 5, js(["karrkay", "ngamu", "yirrkay", "kaday"]), js([]),
     "Appendix text controls yirrka-nya with LOC addressees.", "0.86"),
    (36, 'The child cried out to father and mother: "Come now!"',
     'Karrkay nganjan-anda ngamu-ndu yirrkan: "Yala kada-y!"',
     'karrkay nganjan-anda ngamu-ndu yirrka-ny: "yala kada-y" | child father-LOC mother-LOC cry.out-PAST: "OK/now come-IMP"',
     "yirrkay_abs_actor_two_loc_addressees_quote", 5, js(["karrkay", "nganjan", "ngamu", "yirrkay", "yala", "kaday"]), js([]),
     "Directly modeled on yirrka-nya nganjan-anda ngamu-ndu source shape.", "0.88"),
    (37, 'The old woman cried out to the children: "Do not go!"',
     'Mukul-jalbu karrkay-karra-nda yirrkan: "Kari dunga-y!"',
     'mukul-jalbu karrkay-karra-nda yirrka-ny: "kari dunga-y" | old-woman child-PL-LOC cry.out-PAST: "NEG go-IMP"',
     "yirrkay_abs_actor_plural_loc_addressee_quote", 5, js(["mukul-jalbu", "karrkay", "-karra", "yirrkay", "kari", "dungay"]), js([]),
     "Actor is ABS/S; addressee is LOC plural.", "0.84"),
    (38, 'The man cried out to the young man: "The dog came!"',
     'Dingkar warru-nda yirrkan: "Kaya kadan!"',
     'dingkar warru-nda yirrka-ny: "kaya kada-ny" | man young.man-LOC cry.out-PAST: "dog come-PAST"',
     "yirrkay_abs_actor_loc_addressee_quote", 5, js(["dingkar", "warru", "yirrkay", "kaya", "kaday"]), js([]),
     "Direct quoted declarative after cry-out frame.", "0.82"),
    (39, 'The woman cried out to the old man: "Fire!"',
     'Jalbu mukul-dingkar-anda yirrkan: "Baya!"',
     'jalbu mukul-dingkar-anda yirrka-ny: "baya" | woman old-man-LOC cry.out-PAST: "fire"',
     "yirrkay_abs_actor_loc_addressee_quote", 5, js(["jalbu", "mukul-dingkar", "yirrkay", "baya"]), js([]),
     "One-word quote tests call-out punctuation without adding new lexicon.", "0.84"),
    (40, 'Grandfather cried out: "Yes!"',
     'Kami yirrkan: "Yuwu!"',
     'kami yirrka-ny: "yuwu" | grandfather cry.out-PAST: "yes"',
     "yirrkay_short_quote", 5, js(["kami", "yirrkay", "yuwu"]), js([]),
     "Short yuwu quote with yirrkay; no addressee required.", "0.84"),
    (41, 'Mother called the child: "Come!"',
     'Ngamu-ngku karrkay kunjan: "Kada-y!"',
     'ngamu-ngku karrkay kunja-ny: "kada-y" | mother-ERG child call-PAST: "come-IMP"',
     "kunjal_transitive_call_quote", 5, js(["ngamu", "karrkay", "kunjal", "kaday"]), js([]),
     "Dictionary/living rule controls kunja-l call/summon; quote supplies the call.", "0.86"),
    (42, 'Father called the young man: "Go!"',
     'Nganjan-angka warru kunjan: "Dunga-y!"',
     'nganjan-angka warru kunja-ny: "dunga-y" | father-ERG young.man call-PAST: "go-IMP"',
     "kunjal_transitive_call_quote", 5, js(["nganjan", "warru", "kunjal", "dungay"]), js([]),
     "Transitive call frame with A in ERG and called person as object.", "0.84"),
    (43, 'The old woman called the children: "Sit down!"',
     'Mukul-jalbu-ngku karrkay-karra kunjan: "Bunda-y!"',
     'mukul-jalbu-ngku karrkay-karra kunja-ny: "bunda-y" | old-woman-ERG child-PL call-PAST: "sit-IMP"',
     "kunjal_transitive_call_quote", 5, js(["mukul-jalbu", "karrkay", "-karra", "kunjal", "bunday"]), js([]),
     "Jana kunja-nya source supports call plus following quote; plural object varied.", "0.84"),
    (44, 'The man called the dog: "Come!"',
     'Dingkar-angka kaya kunjan: "Kada-y!"',
     'dingkar-angka kaya kunja-ny: "kada-y" | man-ERG dog call-PAST: "come-IMP"',
     "kunjal_transitive_call_quote", 5, js(["dingkar", "kaya", "kunjal", "kaday"]), js([]),
     "Call/summon frame with animal object; no LOC addressee because this is kunja-l, not balka-l.", "0.84"),
    (45, 'Grandmother called the girl: "Eat!"',
     'Babi-ngka jalbu-karrkay kunjan: "Nuka!"',
     'babi-ngka jalbu-karrkay kunja-ny: "nuka" | grandmother-ERG girl-child call-PAST: "eat.IMP"',
     "kunjal_transitive_call_quote", 5, js(["babi", "jalbu-karrkay", "kunjal", "nukal"]), js([]),
     "Short imperative call; lexical content kept simple and source-controlled.", "0.84"),
    (46, 'They called the old man: "Old man!"',
     'Jana mukul-dingkar kunjan: "Mukul-dingkar!"',
     'jana mukul-dingkar kunja-ny: "mukul-dingkar" | they old-man call-PAST: "old-man"',
     "kunjal_pronoun_actor_call_quote", 5, js(["jana", "mukul-dingkar", "kunjal"]), js([]),
     "Pronoun actor does not take ERG; called person is the object of kunja-l.", "0.84"),
    (47, '"Sit," someone said, "you two sit there!"',
     '"Bunda-y," yalaman, "yubal, yinyay bunda-y!"',
     '"bunda-y" yalama-ny "yubal yinyay bunda-y" | "sit-IMP" say-PAST "you.two there sit-IMP"',
     "medial_yalama_quote_continuation", 5, js(["bunday", "yalamal", "yubal", "yinyay"]), js([]),
     "Appendix text controls quote, yalama-ny, quote-continuation structure.", "0.90"),
    (48, '"No," the child said, "I do not know."',
     '"Kari," karrkay-ngku balkan, "ngayu kari binal."',
     '"kari" karrkay-ngku balka-ny "ngayu kari binal" | "no" child-ERG say-PAST "I NEG know"',
     "medial_balka_quote_continuation", 5, js(["kari", "karrkay", "balkal", "ngayu", "binal"]), js([]),
     "Medial report with explicit ERG speaker because quote is the object of balka-l.", "0.84"),
    (49, '"Yes," the old man said, "the child came."',
     '"Yuwu," mukul-dingkar-angka balkan, "karrkay kadan."',
     '"yuwu" mukul-dingkar-angka balka-ny "karrkay kada-ny" | "yes" old-man-ERG say-PAST "child come-PAST"',
     "medial_balka_quote_continuation", 5, js(["yuwu", "mukul-dingkar", "balkal", "karrkay", "kaday"]), js([]),
     "Medial quote continuation; surface past normalized to kadan.", "0.84"),
    (50, '"Alright," mother said, "you go."',
     '"Yalada," ngamu-ngku balkan, "yundu dunga-y."',
     '"yalada" ngamu-ngku balka-ny "yundu dunga-y" | "alright" mother-ERG say-PAST "you go-IMP"',
     "medial_balka_quote_continuation", 5, js(["yalada", "ngamu", "balkal", "yundu", "dungay"]), js([]),
     "Yalada short discourse quote plus medial reporting frame.", "0.84"),
]


def scan_static() -> 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, loans_used, _evidence, _confidence = row
        label = f"{LABEL}.{seq:02d}"
        e_start = english.lstrip("'\"")
        e_end = english.rstrip("'\"").rstrip()
        if not e_start[:1].isupper() or e_end[-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")
        k_start = kuku.lstrip("'\"")
        if not k_start[:1].isupper():
            issues.append(f"{label}: Kuku surface must start uppercase or with a quote before uppercase")
        for field_name, payload in (("words_used", words_used), ("loans_used", loans_used)):
            try:
                json.loads(payload)
            except Exception as exc:
                issues.append(f"{label}: {field_name} 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/blocked 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_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 100 draft: direct speech and report framing", "operator-guide-2026-07-07", "under_review", NOW),
        )
        batch_id = cur.lastrowid

    dupes = []
    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, rights_status, author,
            created_at, updated_at
        ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
        """,
        [
            (
                batch_id, seq, english, kuku, analysis, frame, tier, words_used,
                loans_used, evidence, "under_review", confidence,
                "project_approved_synthetic_pending_elder_verification",
                "claude-main", NOW, NOW,
            )
            for seq, english, kuku, analysis, frame, tier, words_used, loans_used, evidence, confidence in ROWS
        ],
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="bank",
        event_type="bank-success",
        actor="claude-main",
        detail="Banked 50 hand-authored Rule 100 direct-speech/reporting rows under_review after static and duplicate checks.",
        command="python3 batch_scripts/bank_142.py",
        artifact_path="batch_scripts/bank_142.py",
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="bank",
        event_type="row-inventory",
        actor="claude-main",
        detail="Rows cover balka-l with LOC:pt addressee, yalama-l direct quotes, babaji-y quoted questions, short reply pairs, yirrka-y cry-outs, kunja-l call frames, and medial report clauses.",
        artifact_path="process_logs/batch-142-direct-speech-process.md",
        created_at=NOW,
    )
    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())
