#!/usr/bin/env python3
"""Bank batch-132: clitics and discourse highlighting.

Rows are hand-authored in the main loop from Patz §3.10, §5.2.2, §5.4,
and related examples. The script only stores the rows.
"""

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-132"
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", "balbay-nja",
    "bunjurril",
}


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


ROWS = [
    (1, "They came, got food, and then went.",
     "Jana kadan, mayi manin, dungan-da.",
     "jana kada-ny, mayi mani-ny, dunga-ny-da | they come-PAST food get-PAST go-PAST-TEMP1",
     "clitic_temp1_sequence_close", 4, js(["jana", "kaday", "mayi", "manil", "dungay", "-da"]), js([]),
     "Patz §3.10.1/-da closes a sequence; controlled from ex.209 and text 3 line 1.", "0.86"),
    (2, "We came to the river, ate food, and then lay down.",
     "Nganjin wawubaja-nga kadan, mayi nukan, wunan-da.",
     "nganjin wawubaja-nga kada-ny, mayi nuka-ny, wuna-ny-da | we.excl river-LOC come-PAST food eat-PAST lie-PAST-TEMP1",
     "clitic_temp1_attested_frame", 5, js(["nganjin", "wawubaja", "kaday", "mayi", "nukal", "wunay", "-da"]), js([]),
     "Controlled reduction of Patz ex.631: sequence ending in wuna-ny-da.", "0.88"),
    (3, "Mother cooked fish, ate, and then sat down.",
     "Ngamu-ngku kuyu wajun, nukan, bundan-da.",
     "ngamu-ngku kuyu waju-ny, nuka-ny, bunda-ny-da | mother-ERG fish cook-PAST eat-PAST sit-PAST-TEMP1",
     "clitic_temp1_same_actor_sequence", 4, js(["ngamu", "kuyu", "wajul", "nukal", "bunday", "-da"]), js([]),
     "-da marks the final action in a same-actor sequence.", "0.84"),
    (4, "The child came to camp, ate food, and then slept.",
     "Karrkay bayan-ba kadan, mayi nukan, warngku wunan-da.",
     "karrkay bayan-ba kada-ny, mayi nuka-ny, warngku wuna-ny-da | child camp-LOC come-PAST food eat-PAST sleep lie-PAST-TEMP1",
     "clitic_temp1_daily_sequence", 4, js(["karrkay", "bayan", "kaday", "mayi", "nukal", "warngku", "wunay", "-da"]), js([]),
     "Uses the Patz -da closing pattern with verified daily-life lexemes.", "0.84"),
    (5, "The man got meat, cooked it, and then ate it.",
     "Dingkar-ngku minya manin, wajun, nukan-da.",
     "dingkar-ngku minya mani-ny, waju-ny, nuka-ny-da | man-ERG meat get-PAST cook-PAST eat-PAST-TEMP1",
     "clitic_temp1_transitive_sequence", 4, js(["dingkar", "minya", "manil", "wajul", "nukal", "-da"]), js([]),
     "Parallel to ex.209 but with meat instead of fish.", "0.84"),
    (6, "Grandmother cooked food, the children ate, and then they slept.",
     "Babi-ngku mayi wajun, karrkay-karrkay nukan, wunan-da.",
     "babi-ngku mayi waju-ny, karrkay-karrkay nuka-ny, wuna-ny-da | grandmother-ERG food cook-PAST child-REDUP eat-PAST lie-PAST-TEMP1",
     "clitic_temp1_actor_switch", 4, js(["babi", "mayi", "wajul", "karrkay", "nukal", "wunay", "-da"]), js([]),
     "-da closes a multi-part household sequence after an actor switch.", "0.83"),
    (7, "The two came and then went to the river.",
     "Bula kadan, wawubaja-nga dungan-da.",
     "bula kada-ny, wawubaja-nga dunga-ny-da | they.two come-PAST river-LOC go-PAST-TEMP1",
     "clitic_temp1_dual_motion", 4, js(["bula", "kaday", "wawubaja", "dungay", "-da"]), js([]),
     "Controlled from text 51 movement perspective plus -da sequencing.", "0.84"),
    (8, "I bathed in the water and then came to camp.",
     "Ngayu bana-nga janin, bayan-ba kadan-da.",
     "ngayu bana-nga janji-ny, bayan-ba kada-ny-da | I water-LOC bathe-PAST camp-LOC come-PAST-TEMP1",
     "clitic_temp1_after_bathing", 4, js(["ngayu", "bana", "janjil", "bayan", "kaday", "-da"]), js([]),
     "Uses verified janji-l bathe/swim and -da for the following arrival.", "0.83"),
    (9, "The young man got a spear and then went to the sea.",
     "Warru-ngku kalka manin, jalun-bu dungan-da.",
     "warru-ngku kalka mani-ny, jalun-bu dunga-ny-da | young.man-ERG spear get-PAST sea-LOC go-PAST-TEMP1",
     "clitic_temp1_hunting_departure", 4, js(["warru", "kalka", "manil", "jalun", "dungay", "-da"]), js([]),
     "-da marks departure after preparation.", "0.84"),
    (10, "They ate food and then slept.",
     "Jana mayi nukan, warngku wunan-da.",
     "jana mayi nuka-ny, warngku wuna-ny-da | they food eat-PAST sleep lie-PAST-TEMP1",
     "clitic_temp1_simple_close", 3, js(["jana", "mayi", "nukal", "warngku", "wunay", "-da"]), js([]),
     "Minimal -da sequence close; useful contrast with bare past clauses.", "0.84"),

    (11, "He caught a fish first, then speared a turtle.",
     "Nyulu kuyu-ngurr manin, ngawuya daman-da.",
     "nyulu kuyu-ngurr mani-ny, ngawuya dama-ny-da | he fish-TEMP3 get-PAST turtle spear-PAST-TEMP1",
     "clitic_temp3_attested_object_first", 5, js(["nyulu", "kuyu", "manil", "ngawuya", "damal", "-ngurr", "-da"]), js([]),
     "Patz ex.210: object host kuyu-ngurr plus final -da.", "0.90"),
    (12, "I first cook the fish and then take it.",
     "Ngayu kuyu waju-l-urr wundil-da.",
     "ngayu kuyu waju-l-urr wundi-l-da | I fish cook-NONPAST-TEMP3 take-NONPAST-TEMP1",
     "clitic_temp3_attested_verb_first", 5, js(["ngayu", "kuyu", "wajul", "wundil", "-urr", "-da"]), js([]),
     "Patz ex.633: verb-host TEMP3 plus final -da.", "0.90"),
    (13, "You eat the food straight away!",
     "Yundu mayi-ngarr nuka!",
     "yundu mayi-ngarr nuka | you food-TEMP3 eat.IMP",
     "clitic_temp3_imperative_np_host", 5, js(["yundu", "mayi", "nukal", "-ngarr"]), js([]),
     "Patz ex.573 has Mayi-ngarr nuka; subject added to avoid exact duplicate.", "0.88"),
    (14, "Eat the meat straight away!",
     "Minya nuka-ngarr!",
     "minya nuka-ngarr | meat eat.IMP-TEMP3",
     "clitic_temp3_imperative_verb_host", 5, js(["minya", "nukal", "-ngarr"]), js([]),
     "Patz ex.573 has Nuka-ngarr; object added to avoid exact duplicate.", "0.88"),
    (15, "Give the meat first!",
     "Minya daya-rr!",
     "minya daya-rr | meat give.IMP-TEMP3",
     "clitic_temp3_suppletive_imperative", 5, js(["minya", "dajil", "daya", "-rr"]), js([]),
     "Patz §3.10.1 notes daya-rr with suppletive imperative forms.", "0.88"),
    (16, "Wash the clothes first!",
     "Kambi julurri-ka-rr!",
     "kambi julurri-ka-rr | clothes wash-IMP-TEMP3",
     "clitic_temp3_trisyllabic_imperative", 5, js(["kambi", "julurril", "-ka", "-rr"]), js([]),
     "Patz §3.10.1 notes julurri-ka-rr with trisyllabic imperative.", "0.88"),
    (17, "Mother was the first to get the egg.",
     "Ngamu-ngku nyulu-ngurr diburr manin.",
     "ngamu-ngku nyulu-ngurr diburr mani-ny | mother-ERG she-TEMP3 egg get-PAST",
     "clitic_temp3_pronoun_first", 5, js(["ngamu", "nyulu", "diburr", "manil", "-ngurr"]), js([]),
     "Controlled from Patz ex.634 Queenie-ngka nyulu-ngurr diburr mani-ny.", "0.88"),
    (18, "The child was the first to get food.",
     "Karrkay-ngku nyulu-ngurr mayi manin.",
     "karrkay-ngku nyulu-ngurr mayi mani-ny | child-ERG he/she-TEMP3 food get-PAST",
     "clitic_temp3_pronoun_first_variant", 4, js(["karrkay", "nyulu", "mayi", "manil", "-ngurr"]), js([]),
     "Same pronoun-host TEMP3 construction with verified child/food lexemes.", "0.84"),
    (19, "I went first, and then you came.",
     "Ngayu-ngurr dungan, yundu kadan-da.",
     "ngayu-ngurr dunga-ny, yundu kada-ny-da | I-TEMP3 go-PAST you come-PAST-TEMP1",
     "clitic_temp3_first_participant", 4, js(["ngayu", "dungay", "yundu", "kaday", "-ngurr", "-da"]), js([]),
     "TEMP3 marks the first participant in a two-person sequence.", "0.83"),
    (20, "You sit first, and then I will sweep the ground.",
     "Yundu-ngurr bunda-y, ngayu bubu kidal-da.",
     "yundu-ngurr bunda-y, ngayu bubu kida-l-da | you-TEMP3 sit-IMP I ground sweep-NONPAST-TEMP1",
     "clitic_temp3_first_addressee", 4, js(["yundu", "bunday", "ngayu", "bubu", "kidal", "-ngurr", "-da"]), js([]),
     "Combines first/addressee TEMP3 with later action marked by -da.", "0.83"),

    (21, "He got a really big stone.",
     "Nyulu kulji yalbay-ku manin.",
     "nyulu kulji yalbay-ku mani-ny | he stone big-EMPH1 get-PAST",
     "clitic_emph1_attested_adjective", 5, js(["nyulu", "kulji", "yalbay", "manil", "-ku"]), js([]),
     "Patz text 12/ex.641: yalbay-ku on adjective.", "0.90"),
    (22, "He pushed the really big stone and set it up.",
     "Kulji yalbay-ku jurrngan, yijarrin.",
     "kulji yalbay-ku jurrnga-ny, yijarri-ny | stone big-EMPH1 push-PAST set.up-PAST",
     "clitic_emph1_attested_fronted_object", 5, js(["kulji", "yalbay", "jurrngal", "yijarril", "-ku"]), js([]),
     "Patz text 12/ex.641 line 41 with fronted object and -ku.", "0.90"),
    (23, "Right at the camp he set the big stone.",
     "Bayan-ba-ku yijarrin kulji yalbay.",
     "bayan-ba-ku yijarri-ny kulji yalbay | camp-LOC-EMPH1 set.up-PAST stone big",
     "clitic_emph1_locative_host", 4, js(["bayan", "yijarril", "kulji", "yalbay", "-ku"]), js([]),
     "Patz line 42 has baral-ba-ku; this safer variant uses verified bayan-ba locative host.", "0.84"),
    (24, "There were really many clouds in the sky.",
     "Ngurrban wubul-ku jiri-nga.",
     "ngurrban wubul-ku jiri-nga | cloud many-EMPH1 sky-LOC",
     "clitic_emph1_quantifier_host", 4, js(["ngurrban", "wubul", "jiri", "-ku"]), js([]),
     "Patz §3.10.2 gives wubul-ku as an EMPH1 example.", "0.86"),
    (25, "In the rain, the ground was unexpectedly slippery.",
     "Kaba-nga-ku bubu julbarr-bi.",
     "kaba-nga-ku bubu julbarr-bi | rain-LOC-EMPH1 ground slippery-EMPH3",
     "clitic_emph1_emph3_weather", 5, js(["kaba", "bubu", "julbarr", "-ku", "-bi"]), js([]),
     "Text 3 has kaba-nga-ku and bubu julbarr-bi; row combines the two attested surfaces without duplicating an old row.", "0.88"),
    (26, "That one was from the dream!",
     "Yinya-bi bijarr-muny.",
     "yinya-bi bijarr-muny | that-EMPH3 dream-ABL",
     "clitic_emph3_attested_surprise", 5, js(["yinya", "bijarr", "-bi"]), js([]),
     "Patz ex.647/text 36 line 37: yinya-bi bijarr-muny.", "0.90"),
    (27, "It was just like the dream!",
     "Yala bijarr-bi.",
     "yala bijarr-bi | like dream-EMPH3",
     "clitic_emph3_attested_dream_match", 5, js(["yala", "bijarr", "-bi"]), js([]),
     "Patz ex.648/text 36 line 53: yala bijarr-bi.", "0.90"),
    (28, "No, Aboriginal people, pay attention!",
     "Kari, bama-lu!",
     "kari, bama-lu | no person-EMPH2",
     "clitic_emph2_attested_attention", 5, js(["kari", "bama", "-lu"]), js([]),
     "Patz §5.4.2 conversation example bamalu, with kari no.", "0.90"),
    (29, "It got up, the dog did; pay attention!",
     "Nyulu warndin kaya-la.",
     "nyulu warndi-ny kaya-la | it get.up-PAST dog-EMPH2.Nyungkul",
     "clitic_emph2_nyungkul_attention", 5, js(["nyulu", "warndil", "kaya", "-la"]), js([]),
     "Patz ex.646: Nyulu warndiny kayala.", "0.90"),
    (30, "We really could not keep following.",
     "Nganjin-ku-lu murruji wukurril-wukurrin.",
     "nganjin-ku-lu murruji wukurri-l-wukurri-ny | we.excl-EMPH1-EMPH2 unable follow-l-REDUP-PAST",
     "clitic_emph1_emph2_attested_stack", 5, js(["nganjin", "murruji", "wukurril", "-ku", "-lu"]), js([]),
     "Patz ex.654 has Nganjin-ku-lu murruji wukurri-l-wukurri-ny.", "0.90"),

    (31, "The girl washed all the clothes thoroughly.",
     "Maral-angka kambi julurrin-arrku.",
     "maral-angka kambi julurri-ny-arrku | girl-ERG clothes wash-PAST-EMPH4",
     "clitic_emph4_attested_verb_total", 5, js(["maral", "kambi", "julurril", "-arrku"]), js([]),
     "Patz ex.211: verb-host EMPH4 total/thorough action.", "0.90"),
    (32, "You sweep the whole house thoroughly!",
     "Yundu bayan kida-rrku!",
     "yundu bayan kida-rrku | you house sweep.IMP-EMPH4",
     "clitic_emph4_imperative_total", 5, js(["yundu", "bayan", "kidal", "-rrku"]), js([]),
     "Patz ex.212 is Bayan kida-rrku; subject added to avoid exact duplicate.", "0.88"),
    (33, "I want to speak only to you.",
     "Ngayu wawu balka-nka yunu-ndu-rrku.",
     "ngayu wawu balka-nka yunu-ndu-rrku | I want speak-PURP you-LOC-EMPH4",
     "clitic_emph4_attested_pronoun_exclusive", 5, js(["ngayu", "wawu", "balkal", "yunu", "-rrku"]), js([]),
     "Patz ex.213: pronoun-host EMPH4 exclusivity.", "0.90"),
    (34, "Only he lives at the camp.",
     "Bayan-ba nyulu-rrku bundanday.",
     "bayan-ba nyulu-rrku bunda-nda-y | camp-LOC he-EMPH4 sit-REDUP-NONPAST",
     "clitic_emph4_pronoun_only", 4, js(["bayan", "nyulu", "bunday", "-rrku"]), js([]),
     "Controlled from Patz ex.215 Ngayu-rrku bundanda-y.", "0.86"),
    (35, "I live by myself.",
     "Ngayu-rrku bundanday.",
     "ngayu-rrku bunda-nda-y | I-EMPH4 sit-REDUP-NONPAST",
     "clitic_emph4_attested_first_person_only", 5, js(["ngayu", "bunday", "-rrku"]), js([]),
     "Patz ex.215: Ngayu-rrku bundanda-y.", "0.90"),
    (36, "I did not really sleep.",
     "Ngayu kari-rrku warngku wunan.",
     "ngayu kari-rrku warngku wuna-ny | I NEG-EMPH4 sleep lie-PAST",
     "clitic_emph4_neg_particle", 5, js(["ngayu", "kari", "warngku", "wunay", "-rrku"]), js([]),
     "Patz ex.208: kari-rrku with negation particle.", "0.90"),
    (37, "Some places nearby are just the same.",
     "Kanbal bubu yala-rrku ngundu.",
     "kanbal bubu yala-rrku ngundu | some place same-EMPH4 close",
     "clitic_emph4_comparison_particle", 5, js(["kanbal", "bubu", "yala", "ngundu", "-rrku"]), js([]),
     "Patz ex.206 has Kanbal bubu yala-rrku; ngundu added to avoid exact duplicate.", "0.88"),
    (38, "The old man also cried for his wife.",
     "Wulman yala-rrku manyarr-anka badin.",
     "wulman yala-rrku manyarr-anka badi-ny | old.man also-EMPH4 wife-DAT cry-PAST",
     "clitic_emph4_also_particle", 5, js(["wulman", "yala", "manyarr", "badil", "-rrku"]), js([]),
     "Patz ex.207: yala-rrku as also/just the same.", "0.90"),
    (39, "The two went right on west and came to the mountain top.",
     "Bula kuwa dungan-arrku, kuwa dungan-arrku, wuburr-bu kadan.",
     "bula kuwa dunga-ny-arrku, kuwa dunga-ny-arrku, wuburr-bu kada-ny | they.two west go-PAST-EMPH4 west go-PAST-EMPH4 mountain.top-LOC come-PAST",
     "clitic_emph4_attested_motion_total", 5, js(["bula", "kuwa", "dungay", "wuburr", "kaday", "-arrku"]), js([]),
     "Patz text 51 line 46 has repeated dunga-ny-arrku.", "0.90"),
    (40, "It was all finished; it had taken him.",
     "Kunban-arrku, wundin.",
     "kunba-ny-arrku, wundi-ny | finish-PAST-EMPH4 take-PAST",
     "clitic_emph4_attested_completion", 5, js(["kunbal", "wundil", "-arrku"]), js([]),
     "Patz text 36 line 52: Kunba-ny-arrku, wundi-ny.", "0.90"),

    (41, "Meanwhile, the pair of young men took off and ran west toward camp.",
     "Bula warru-bulal jalaman-kuda, jalaman yarra-kuda bayan-ba kuwa warrin.",
     "bula warru-bulal jalama-ny-kuda, jalama-ny yarra-kuda bayan-ba kuwa warri-ny | they.two young.man-pair jump-PAST-TEMP2 jump-PAST that.way-TEMP2 camp-LOC west run-PAST",
     "clitic_temp2_attested_overlap_motion", 5, js(["bula", "warru", "-bulal", "jalama", "yarra", "bayan", "kuwa", "warri", "-kuda"]), js([]),
     "Patz text 51 lines 38-39: -kuda in overlapping motion sequence.", "0.90"),
    (42, "They wanted to go on; meanwhile they were no longer afraid.",
     "Jana wawu dunga-nka, kari yinilman-kuda.",
     "jana wawu dunga-nka, kari yinil-ma-ny-kuda | they want go-PURP NEG afraid-INCHO-PAST-TEMP2",
     "clitic_temp2_attested_state_overlap", 5, js(["jana", "wawu", "dungay", "kari", "yinil", "-kuda"]), js([]),
     "Patz text 3 line 18: kari yinil-ma-ny-kuda.", "0.90"),
    (43, "With the knife, I kept chopping wrongly in the water meanwhile.",
     "Ngayu naybu-bu-ku bana-nga-kuda wadu-kuda nyandan.",
     "ngayu naybu-bu-ku bana-nga-kuda wadu-kuda nyanda-ny | I knife-INST-EMPH1 water-LOC-TEMP2 wrong-TEMP2 chop-PAST",
     "clitic_temp2_emph_stack_attested", 5, js(["ngayu", "naybu", "bana", "wadu", "nyandal", "-ku", "-kuda"]), js(["naybu"]),
     "Patz ex.630: naybu-bu-ku, bana-nga-kuda, wadu-kuda.", "0.90"),
    (44, "I want to come back again.",
     "Ngayu wawu kada-nka-baja.",
     "ngayu wawu kada-nka-baja | I want come-PURP-again",
     "clitic_baja_attested_verb_again", 5, js(["ngayu", "wawu", "kaday", "-baja"]), js([]),
     "Patz ex.218: verbal -baja means again/back.", "0.90"),
    (45, "He is getting quite sick.",
     "Nyulu bambay-mal-baja.",
     "nyulu bambay-ma-l-baja | he sick-INCHO-NONPAST-DEGREE",
     "clitic_baja_attested_state_degree", 5, js(["nyulu", "bambay", "-mal", "-baja"]), js([]),
     "Patz ex.216: state-verb -baja expresses high degree.", "0.90"),
    (46, "The blue-tongue lizard bit the taipan again.",
     "Bajabaja-ngka jinkalmu baykan-baja.",
     "bajabaja-ngka jinkalmu bayka-ny-baja | blue.tongue-ERG taipan bite-PAST-again",
     "clitic_baja_attested_action_again", 5, js(["bajabaja", "jinkalmu", "baykal", "-baja"]), js([]),
     "Patz ex.217: action/motion verb -baja means again.", "0.90"),
    (47, "I give you money, and you in turn give me meat.",
     "Ngayu yunu mani dajil, yundu-ji ngayku minya daya.",
     "ngayu yunu mani daji-l, yundu-ji ngayku minya daya | I your money give-NONPAST you-in.turn my meat give.IMP",
     "clitic_turn_attested_exchange", 5, js(["ngayu", "yunu", "mani", "dajil", "yundu", "ngayku", "minya", "daya", "-ji"]), js([]),
     "Patz ex.219: yundu-ji marks in-turn exchange.", "0.90"),
    (48, "It is your turn to sit; I will sweep the ground.",
     "Yundu-ji bunda-y, ngayu bubu kidal.",
     "yundu-ji bunda-y, ngayu bubu kida-l | you-in.turn sit-IMP I ground sweep-NONPAST",
     "clitic_turn_attested_task", 5, js(["yundu", "bunday", "ngayu", "bubu", "kidal", "-ji"]), js([]),
     "Patz ex.221: yundu-ji with turn-taking obligation.", "0.90"),
    (49, "The next day it was my turn to go to camp to cook food.",
     "Wunkuny yindu ngayu-ji bayan-ba dungan mayi waju-nku.",
     "wunkuny yindu ngayu-ji bayan-ba dunga-ny mayi waju-nku | next.day other I-in.turn camp-LOC go-PAST food cook-PURP",
     "clitic_turn_controlled_task", 4, js(["wunkuny", "yindu", "ngayu", "bayan", "dungay", "mayi", "wajul", "-ji"]), js([]),
     "Controlled from Patz ex.220 Monday yindu ngayu-ji ... dunga-ny mayi waju-nku.", "0.86"),
    (50, "It is up to you.",
     "Yundu-ku-baja.",
     "yundu-ku-baja | you-EMPH1-again/idiom",
     "clitic_baja_attested_idiom", 5, js(["yundu", "-ku", "-baja"]), js([]),
     "Patz §3.10.3 notes idiomatic yundu-ku-baja 'it is up to you'.", "0.90"),
]


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}"
        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")
        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 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")
    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 90 draft: clitics and discourse highlighting", "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
        ],
    )
    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())
