#!/usr/bin/env python3
"""Bank batch-156: precautionary, successive, and prior-event timing."""

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-156"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-156-precautionary-successive-prior-event-process.md"

DENY = {"yah", "ngawuya", "walnga", "yala-coordination"}
DENY_STANDALONE = {"ba", "ma"}


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


ROWS = [
    (1, "He does not bathe in deep water lest he drown.",
     "Nyulu kari janji-l bana bada-nga, bujil-janji-nyji.",
     "nyulu kari janji-l bana bada-nga, bujil-janji-nyji | he NEG bathe-NONPAST water deep-LOC nose-bathe-PRECAUT",
     "precautionary_s_s_prime", 5, js(["nyulu", "kari", "janji-l", "bana", "bada", "bujil-janji-nyji"]), js([]),
     "Patz ex.432 licenses janji-l plus bujil-janji-nyji; water/deep vocabulary reused from Rule 113.", "0.86"),
    (2, "Do not fool around with the spear lest you hit the child.",
     "Kari kalka-ji nguju-wuri, yundu karrkay kuni-nyji.",
     "kari kalka-ji nguju-wuri-y, yundu karrkay kuni-nyji | NEG spear-COMIT funny-dance-IMP you child hit-PRECAUT",
     "precautionary_imperative_a_s_prime", 5, js(["kari", "kalka", "nguju-wuri-y", "yundu", "karrkay", "kunil"]), js([]),
     "Patz ex.433 source frame; object varied from baby to child to avoid copying.", "0.86"),
    (3, "Do not walk through long grass lest a snake bite you.",
     "Kari jikan-ba kalbay-mba dunga-n-dungay, jarba-bu yununy bayka-nyji.",
     "kari jikan-ba kalbay-mba dunga-n-dunga-y, jarba-bu yununy bayka-nyji | NEG grass-LOC long-LOC go-REDUP-NONPAST snake-ERG you.ACC bite-PRECAUT",
     "precautionary_no_common_np", 5, js(["kari", "jikan", "kalbay", "dungay", "jarba", "yununy", "baykal"]), js([]),
     "Patz ex.434 long-grass snake-bite frame; explicit second-person object retained.", "0.86"),
    (4, "Do not cook the fish lest you spoil it.",
     "Kari kuyu waju, buyun-dama-nyji.",
     "kari kuyu waju, buyun-dama-nyji | NEG fish cook.IMP bad-CAUS-PRECAUT",
     "precautionary_o_o_prime", 5, js(["kari", "kuyu", "wajul", "buyun-dama-l"]), js([]),
     "Patz ex.436 gives mayi waju plus buyun-dama-nyji; object varied to fish.", "0.84"),
    (5, "Do not lift the billycan lest you drop it.",
     "Kari jungkalu kulba, dara-y-mani-nyji.",
     "kari jungkalu kulba, dara-y-mani-nyji | NEG billycan lift.IMP fall-y-CAUS-PRECAUT",
     "precautionary_o_o_prime", 5, js(["kari", "jungkalu", "kulba", "daray-manil"]), js([]),
     "Patz ex.441 egg/drop frame; object varied to Rule 113 jungkalu.", "0.84"),
    (6, "I carry the child lest he cry.",
     "Ngayu karrkay jarrakulba-l, banbadi-nyji.",
     "ngayu karrkay jarrakulba-l, banbadi-nyji | I child carry-NONPAST cry.REDUP-PRECAUT",
     "precautionary_o_s_prime", 5, js(["ngayu", "karrkay", "jarrakulba-l", "banbadi"]), js([]),
     "Patz ex.439 gives carry-baby lest cry; child object varies the source.", "0.84"),
    (7, "Take the bag lest the food fall.",
     "Balji wundi, mayi dara-nyji.",
     "balji wundi, mayi dara-nyji | bag take.IMP food fall-PRECAUT",
     "precautionary_no_common_np", 4, js(["balji", "wundil", "mayi", "daray"]), js([]),
     "Precautionary no-common-NP pattern after Patz ex.443/444; practical container vocabulary.", "0.78"),
    (8, "Close the house lest rain enter.",
     "Bayan nanda, kaba wala-nyji.",
     "bayan nanda, kaba wala-nyji | house close.IMP rain enter-PRECAUT",
     "precautionary_no_common_np", 4, js(["bayan", "nandal", "kaba", "wala-l"]), js([]),
     "Wala-l enter is source-checked; no-common-NP precautionary warning.", "0.78"),
    (9, "Take firewood lest cold come.",
     "Baya wundi, kiway kada-nyji.",
     "baya wundi, kiway kada-nyji | firewood take.IMP cold come-PRECAUT",
     "precautionary_no_common_np", 4, js(["baya", "wundil", "kiway", "kaday"]), js([]),
     "Modeled on Patz ex.443 cold-coming precaution, with take-firewood response.", "0.80"),
    (10, "Take food lest you get hungry.",
     "Mayi wundi, yundu dakuy-ma-nyji.",
     "mayi wundi, yundu dakuy-ma-nyji | food take.IMP you hungry-INCHO-PRECAUT",
     "precautionary_inchoative", 5, js(["mayi", "wundil", "yundu", "dakuy"]), js([]),
     "Patz table at ex.511 gives dakuy-ma-nyji 'lest I get hungry'; person varied.", "0.84"),
    (11, "Take medicinal root lest the child get sick.",
     "Bangkan wundi, karrkay bambay-ma-nyji.",
     "bangkan wundi, karrkay bambay-ma-nyji | medicinal.root take.IMP child sick-INCHO-PRECAUT",
     "precautionary_inchoative", 5, js(["bangkan", "wundil", "karrkay", "bambay"]), js([]),
     "Bambay-ma- is source-checked in Patz; Rule 113 remedy vocabulary supplies bangkan.", "0.82"),
    (12, "Do not touch the snake lest it bite you.",
     "Kari jarba karrba, jarba-bu yununy bayka-nyji.",
     "kari jarba karrba, jarba-bu yununy bayka-nyji | NEG snake touch.IMP snake-ERG you.ACC bite-PRECAUT",
     "precautionary_a_o_retained", 5, js(["kari", "jarba", "karrba", "yununy", "baykal"]), js([]),
     "Patz ex.437 dog-touch frame and ex.434 snake-bite A marking combined conservatively.", "0.84"),
    (13, "Keep the child in the house lest the dog bite him.",
     "Karrkay bayan-ba kuji, kaya-ngka nyunguny bayka-nyji.",
     "karrkay bayan-ba kuji, kaya-ngka nyunguny bayka-nyji | child house-LOC keep.IMP dog-ERG him.ACC bite-PRECAUT",
     "precautionary_a_o_retained", 4, js(["karrkay", "bayan", "kujil", "kaya", "nyunguny", "baykal"]), js([]),
     "Explicit dog A and child O retained to avoid ambiguity, following Patz ex.438 caution.", "0.80"),
    (14, "Do not leave the food there lest the dog eat it.",
     "Kari mayi yinyay bawa, kaya-ngka nuka-nyji.",
     "kari mayi yinyay bawa, kaya-ngka nuka-nyji | NEG food there leave.IMP dog-ERG eat-PRECAUT",
     "precautionary_o_o_prime", 4, js(["kari", "mayi", "yinyay", "bawal", "kaya", "nukal"]), js([]),
     "Common object food is recoverable in the precautionary clause; dog A retained.", "0.78"),
    (15, "Light a fire lest the child be cold.",
     "Baya waju, karrkay kiway-kiway jana-nyji.",
     "baya waju, karrkay kiway-kiway jana-nyji | fire light.IMP child cold be-PRECAUT",
     "precautionary_no_common_np", 4, js(["baya", "wajul", "karrkay", "kiway-kiway", "janay"]), js([]),
     "Rule 113 cold/fire lexicon in Patz ex.443 no-common-NP precautionary shape.", "0.78"),
    (16, "Do not go to the sea lest wind come.",
     "Kari jalun-ba dunga-y, muyar kada-nyji.",
     "kari jalun-ba dunga-y, muyar kada-nyji | NEG sea-LOC go-NONPAST wind come-PRECAUT",
     "precautionary_no_common_np", 4, js(["kari", "jalun", "dungay", "muyar", "kaday"]), js([]),
     "No-common-NP precautionary with weather risk; keeps event as preventable bad outcome.", "0.78"),
    (17, "Take the spear lest a pig come.",
     "Kalka wundi, bikibiki kada-nyji.",
     "kalka wundi, bikibiki kada-nyji | spear take.IMP pig come-PRECAUT",
     "precautionary_no_common_np", 4, js(["kalka", "wundil", "bikibiki", "kaday"]), js([]),
     "Rule 113 animal-risk lexicon in -nyji construction, not kunka/nganganjirrka.", "0.78"),
    (18, "Do not leave the fishing line lest the fish bite.",
     "Kari badur bawa, kuyu-ngku bayka-nyji.",
     "kari badur bawa, kuyu-ngku bayka-nyji | NEG fishing.line leave.IMP fish-ERG bite-PRECAUT",
     "precautionary_no_common_np", 4, js(["kari", "badur", "bawal", "kuyu", "baykal"]), js([]),
     "Practical Rule 113 fishing vocabulary with Patz-style explicit A in risk clause.", "0.78"),

    (19, "I cook food before the children come.",
     "Ngayu mayi wajul, karrkay-karrkay kada-nyjiku.",
     "ngayu mayi waju-l, karrkay-karrkay kada-nyjiku | I food cook-NONPAST children come-SUCC",
     "successive_no_common_np", 5, js(["ngayu", "mayi", "wajul", "karrkay", "kaday"]), js([]),
     "Successive -nyjiku marks the following event as timing point, after Patz ex.455.", "0.82"),
    (20, "We close the house before rain falls.",
     "Ngana bayan nandal, kaba dara-nyjiku.",
     "ngana bayan nanda-l, kaba dara-nyjiku | we house close-NONPAST rain fall-SUCC",
     "successive_no_common_np", 5, js(["ngana", "bayan", "nandal", "kaba", "daray"]), js([]),
     "Patz ex.454 licenses rain falls with dara-nyjiku; main event is prior house-closing.", "0.84"),
    (21, "Grandmother cooks food before the child gets hungry.",
     "Babi-ngka mayi wajul, karrkay dakuy-ma-nyjiku.",
     "babi-ngka mayi waju-l, karrkay dakuy-ma-nyjiku | grandmother-ERG food cook-NONPAST child hungry-INCHO-SUCC",
     "successive_inchoative", 5, js(["babi", "mayi", "wajul", "karrkay", "dakuy"]), js([]),
     "Contrasts successive dakuy-ma-nyjiku with Rule 113 in-case dakuy-ma-nya-mun-ku.", "0.82"),
    (22, "You take a spear before a pig comes.",
     "Yundu kalka wundil, bikibiki kada-nyjiku.",
     "yundu kalka wundi-l, bikibiki kada-nyjiku | you spear take-NONPAST pig come-SUCC",
     "successive_no_common_np", 5, js(["yundu", "kalka", "wundil", "bikibiki", "kaday"]), js([]),
     "Minimal pair with row 17: -nyjiku timing, not -nyji danger prevention.", "0.84"),
    (23, "I take the fishing line before the fish bites.",
     "Ngayu badur wundil, kuyu-ngku bayka-nyjiku.",
     "ngayu badur wundi-l, kuyu-ngku bayka-nyjiku | I fishing.line take-NONPAST fish-ERG bite-SUCC",
     "successive_no_common_np", 5, js(["ngayu", "badur", "wundil", "kuyu", "baykal"]), js([]),
     "Minimal pair with row 18 and Patz ex.445 bite-SUCC logic.", "0.84"),
    (24, "We stay at the camp before wind comes.",
     "Ngana bayan-ba bundanday, muyar kada-nyjiku.",
     "ngana bayan-ba bundanda-y, muyar kada-nyjiku | we camp-LOC stay-NONPAST wind come-SUCC",
     "successive_no_common_np", 4, js(["ngana", "bayan", "bundanday", "muyar", "kaday"]), js([]),
     "No-common-NP successive after Patz ex.455, with Rule 113 wind lexicon.", "0.78"),
    (25, "I sweep the ground before a friend comes.",
     "Ngayu bubu kidal, jawun kada-nyjiku.",
     "ngayu bubu kida-l, jawun kada-nyjiku | I ground sweep-NONPAST friend come-SUCC",
     "successive_no_common_np", 4, js(["ngayu", "bubu", "kidal", "jawun", "kaday"]), js([]),
     "Preparation before following event; keeps -nyjiku temporal rather than hypothetical.", "0.78"),
    (26, "They ate food before father woke up.",
     "Jana mayi nukan, nganjan wandi-nyjiku.",
     "jana mayi nuka-ny, nganjan wandi-nyjiku | they food eat-PAST father wake.up-SUCC",
     "successive_source_wake", 5, js(["jana", "mayi", "nukal", "nganjan", "wandi"]), js([]),
     "Patz ex.165 source frame with simplified surface and same SUCC reference point.", "0.86"),
    (27, "We rested before going for a walk.",
     "Ngana wunanan, jilba-dunga-nyjiku.",
     "ngana wunana-ny, jilba-dunga-nyjiku | we rest.REDUP-PAST walk-go-SUCC",
     "successive_s_s_prime", 5, js(["ngana", "wunana", "jilba-dunga-y"]), js([]),
     "Patz ex.446 source frame; subject varied from singular to plural.", "0.84"),
    (28, "Mother washes her hands before eating.",
     "Ngamu mara julurri-ji, mayi nuka-nyjiku.",
     "ngamu mara julurri-ji-y, mayi nuka-nyjiku | mother hand wash-REF-NONPAST food eat-SUCC",
     "successive_s_a_prime", 5, js(["ngamu", "mara", "julurril", "mayi", "nukal"]), js([]),
     "Patz ex.447 hand-washing before kneading adapted to eating with source-checked nuka-l.", "0.82"),
    (29, "I sweep the ground before setting up camp.",
     "Ngayu bubu kidal, bayan ngara-nyjiku.",
     "ngayu bubu kida-l, bayan ngara-nyjiku | I ground sweep-NONPAST camp set.up-SUCC",
     "successive_a_a_prime", 5, js(["ngayu", "bubu", "kidal", "bayan", "ngara"]), js([]),
     "Patz ex.449 source frame; person varied.", "0.84"),
    (30, "Grandmother roasts the zamia nut before pounding it.",
     "Babi-ngka marra dindal, duda-nyjiku.",
     "babi-ngka marra dinda-l, duda-nyjiku | grandmother-ERG zamia.nut roast-NONPAST pound-SUCC",
     "successive_o_o_prime", 5, js(["babi", "marra", "dindal", "duda-l"]), js([]),
     "Patz ex.450 source frame with actor varied from women to grandmother.", "0.84"),
    (31, "They see the pig before it runs away.",
     "Jana bikibiki nyajin, nyulu warri-nyjiku.",
     "jana bikibiki nyaji-ny, nyulu warri-nyjiku | they pig see-PAST it run-SUCC",
     "successive_o_s_prime", 5, js(["jana", "bikibiki", "nyajil", "nyulu", "warri-y"]), js([]),
     "Patz ex.453 wallaby/run-away frame; object varied to pig.", "0.82"),
    (32, "A bird cries before rain falls.",
     "Dikal banbadi, kaba dara-nyjiku.",
     "dikal banbadi-y, kaba dara-nyjiku | bird cry.REDUP-NONPAST rain fall-SUCC",
     "successive_no_common_np_source", 5, js(["dikal", "banbadi", "kaba", "daray"]), js([]),
     "Patz ex.454 exact construction; retained as canonical source-shaped no-common-NP example if duplicate-clean.", "0.88"),
    (33, "We went along the road before wind came.",
     "Ngana baral-darr dungan, muyar kada-nyjiku.",
     "ngana baral-darr dunga-ny, muyar kada-nyjiku | we road-PERL go-PAST wind come-SUCC",
     "successive_no_common_np", 5, js(["ngana", "baral", "dungay", "muyar", "kaday"]), js([]),
     "Patz ex.455 'I went before wind came' with subject and path varied.", "0.84"),
    (34, "The child slept before the sun rose.",
     "Karrkay warngku-wunan, wungar wandi-nyjiku.",
     "karrkay warngku-wuna-ny, wungar wandi-nyjiku | child sleep-lie-PAST sun rise-SUCC",
     "successive_no_common_np", 4, js(["karrkay", "warngku-wunay", "wungar", "wandi"]), js([]),
     "Simple successive timing row with source-checked wandi-nyjiku wake/rise.", "0.78"),

    (35, "After bathing, they rest at the camp.",
     "Wawu-janji-nya-muny, jana bayan-ba wunana-y.",
     "wawu-janji-nya-muny, jana bayan-ba wunana-y | TEMP4-bathe-SUB-ABL they camp-LOC rest.REDUP-NONPAST",
     "prior_event_s_s_prime", 5, js(["wawu-janji-nya-muny", "jana", "bayan", "wunana"]), js([]),
     "Patz ex.491 prior-event source form, with camp location added.", "0.86"),
    (36, "Mother saw the child after he had entered.",
     "Ngamu-ngku karrkay nyajin, wawu-wala-nya-muny.",
     "ngamu-ngku karrkay nyaji-ny, wawu-wala-nya-muny | mother-ERG child see-PAST TEMP4-enter-SUB-ABL",
     "prior_event_o_s_prime", 5, js(["ngamu", "karrkay", "nyajil", "wawu-wala-nya-muny"]), js([]),
     "Patz ex.492 see-object after entering; actor/object varied.", "0.86"),
    (37, "The man killed the snake after it had bitten him.",
     "Dingkar-angka jarba kunin, wawu-bayka-nya-muny.",
     "dingkar-angka jarba kuni-ny, wawu-bayka-nya-muny | man-ERG snake kill-PAST TEMP4-bite-SUB-ABL",
     "prior_event_o_a_prime", 5, js(["dingkar", "jarba", "kunil", "wawu-bayka-nya-muny"]), js([]),
     "Patz ex.493 bite prior-event source form, with snake lexeme from Rule 113.", "0.86"),
    (38, "Grandmother rested after washing clothes.",
     "Babi wunanan, wawu-kambi-muny julurrin.",
     "babi wunana-ny, wawu-kambi-muny julurri-ny | grandmother rest.REDUP-PAST TEMP4-clothes-ABL wash-PAST",
     "prior_event_object_ablative", 5, js(["babi", "wunana", "wawu-kambi-muny", "julurril"]), js([]),
     "Patz ex.494 object-attracts-ablative prior-event pattern, subject varied.", "0.86"),
    (39, "She went for a walk after feeding the dog.",
     "Nyulu jilba-dungan, wawu-kaya-muny mayi dajin.",
     "nyulu jilba-dunga-ny, wawu-kaya-muny mayi daji-ny | she walk-go-PAST TEMP4-dog-ABL food give-PAST",
     "prior_event_object_ablative", 5, js(["nyulu", "jilba-dunga-y", "wawu-kaya-muny", "mayi", "dajil"]), js([]),
     "Modeled on Patz ex.495 chicken-feeding row; recipient noun attracts ablative.", "0.82"),
    (40, "He drank water after the walk.",
     "Nyulu bana nukan, wawu-jilba-muny.",
     "nyulu bana nuka-ny, wawu-jilba-muny | he water drink-PAST TEMP4-walk-ABL",
     "prior_event_nominal_ablative", 5, js(["nyulu", "bana", "nukal", "wawu-jilba-muny"]), js([]),
     "Patz ex.497 says use wawu-jilba-muny rather than wawu-dunga-nya-muny.", "0.88"),
    (41, "After the meal, the children sleep.",
     "Wawu-mayi-muny, karrkay-karrkay warngku-wunay.",
     "wawu-mayi-muny, karrkay-karrkay warngku-wuna-y | TEMP4-food-ABL children sleep-lie-NONPAST",
     "prior_event_nominal_ablative", 5, js(["wawu-mayi-muny", "karrkay", "warngku-wunay"]), js([]),
     "Patz 3.10.1 gives wawu-mayi-muny 'after the meal'.", "0.84"),
    (42, "After that, we go along the road.",
     "Wawu-yinya-muny, ngana baral-darr dungay.",
     "wawu-yinya-muny, ngana baral-darr dunga-y | TEMP4-that-ABL we road-PERL go-NONPAST",
     "prior_event_general_after_that", 5, js(["wawu-yinya-muny", "ngana", "baral", "dungay"]), js([]),
     "Patz 4.4.4.3 recommends wawu-yinya-muny for general after-that sequence.", "0.84"),
    (43, "The young man grabbed the dog after the barking.",
     "Warru-ngku kaya karrban, wawu-ngangkurr-muny.",
     "warru-ngku kaya karrba-ny, wawu-ngangkurr-muny | young.man-ERG dog grab-PAST TEMP4-barking.noise-ABL",
     "prior_event_nominal_ablative", 5, js(["warru", "kaya", "karrba", "wawu-ngangkurr-muny"]), js([]),
     "Patz ex.496 says use barking noun wawu-ngangkurr-muny, not wawu-ngangkurri-nya-muny.", "0.88"),
    (44, "After the meal, grandmother stays at the camp.",
     "Wawu-mayi-muny, babi bayan-ba bundanday.",
     "wawu-mayi-muny, babi bayan-ba bundanda-y | TEMP4-food-ABL grandmother camp-LOC stay-NONPAST",
     "prior_event_nominal_ablative", 4, js(["wawu-mayi-muny", "babi", "bayan", "bundanday"]), js([]),
     "Second wawu-mayi-muny row varies the main clause and reinforces nominal prior event.", "0.78"),
    (45, "After that, take water.",
     "Wawu-yinya-muny, bana wundi.",
     "wawu-yinya-muny, bana wundi | TEMP4-that-ABL water take.IMP",
     "prior_event_general_after_that", 4, js(["wawu-yinya-muny", "bana", "wundil"]), js([]),
     "General after-that sequence plus imperative response.", "0.78"),
    (46, "After bathing, the children sleep.",
     "Wawu-janji-nya-muny, karrkay-karrkay warngku-wunay.",
     "wawu-janji-nya-muny, karrkay-karrkay warngku-wuna-y | TEMP4-bathe-SUB-ABL children sleep-lie-NONPAST",
     "prior_event_s_s_prime", 5, js(["wawu-janji-nya-muny", "karrkay", "warngku-wunay"]), js([]),
     "Patz ex.491 source prior-event form with new main clause.", "0.84"),
    (47, "We saw the man after he had entered the house.",
     "Ngana dingkar nyajin, wawu-wala-nya-muny bayan-ka.",
     "ngana dingkar nyaji-ny, wawu-wala-nya-muny bayan-ka | we man see-PAST TEMP4-enter-SUB-ABL house-DAT",
     "prior_event_o_s_prime", 5, js(["ngana", "dingkar", "nyajil", "wawu-wala-nya-muny", "bayan"]), js([]),
     "Varies prior Batch 84 woman-entered surface; retains Patz ex.492 construction.", "0.82"),
    (48, "The woman caught the dog after the barking.",
     "Jalbu-ngku kaya karrban, wawu-ngangkurr-muny.",
     "jalbu-ngku kaya karrba-ny, wawu-ngangkurr-muny | woman-ERG dog grab-PAST TEMP4-barking.noise-ABL",
     "prior_event_nominal_ablative", 5, js(["jalbu", "kaya", "karrba", "wawu-ngangkurr-muny"]), js([]),
     "Patz ex.496 nominal prior-event pattern, actor varied.", "0.84"),
    (49, "I drank water after the meal.",
     "Ngayu bana nukan, wawu-mayi-muny.",
     "ngayu bana nuka-ny, wawu-mayi-muny | I water drink-PAST TEMP4-food-ABL",
     "prior_event_nominal_ablative", 4, js(["ngayu", "bana", "nukal", "wawu-mayi-muny"]), js([]),
     "Simple wawu-mayi-muny nominal prior-event row.", "0.78"),
    (50, "After that, we close the house.",
     "Wawu-yinya-muny, ngana bayan nandal.",
     "wawu-yinya-muny, ngana bayan nanda-l | TEMP4-that-ABL we house close-NONPAST",
     "prior_event_general_after_that", 4, js(["wawu-yinya-muny", "ngana", "bayan", "nandal"]), js([]),
     "General after-that sequence closes the batch and contrasts with -nyjiku timing rows.", "0.78"),
]


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.lstrip("'\"")[:1].isupper() or english.rstrip("'\"").rstrip()[-1:] not in ".!?":
            issues.append(f"{label}: English must be capitalized and final-punctuated")
        if not kuku.lstrip("'\"")[:1].isupper():
            issues.append(f"{label}: Kuku surface must start uppercase")
        if " | " not in analysis:
            issues.append(f"{label}: analysis missing gloss separator")
        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()} {evidence.lower()} "
        for word in DENY:
            if re.search(rf"(?<![a-z]){re.escape(word)}(?![a-z])", low):
                issues.append(f"{label}: denied blocked/special token {word!r}")
        for tok in re.sub(r"[.!?,]", " ", kuku.lower()).split():
            if tok.strip("'\"") in DENY_STANDALONE:
                issues.append(f"{label}: denied standalone special interjection {tok!r}")
        if frame.startswith("precautionary"):
            if "-nyji" not in kuku or "PRECAUT" not in analysis:
                issues.append(f"{label}: precautionary row must carry -nyji/PRECAUT")
            if "-nyjiku" in kuku or "SUCC" in analysis:
                issues.append(f"{label}: precautionary row must not use -nyjiku/SUCC")
        if frame.startswith("successive"):
            if "-nyjiku" not in kuku or "SUCC" not in analysis:
                issues.append(f"{label}: successive row must carry -nyjiku/SUCC")
            if "PRECAUT" in analysis:
                issues.append(f"{label}: successive row must not be glossed PRECAUT")
        if frame.startswith("prior_event"):
            if "wawu-" not in kuku.lower() or "-muny" not in kuku.lower() or "TEMP4" not in analysis:
                issues.append(f"{label}: prior-event row must carry wawu-, -muny, and TEMP4")
        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 114 draft: precautionary/successive/prior-event timing", "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

    record_event(
        db,
        batch_label=LABEL,
        phase="source",
        event_type="source-pass",
        actor="claude-main",
        detail=(
            "Rule 114 source pass read Patz 3.8.4.2 suffix table, 4.4.2 precautionary, 4.4.3 successive, "
            "4.4.4.3 prior event, and 3.10.1 wawu- temporal clitic examples. Target contrast: -nyji preventable "
            "bad outcome, -nyjiku following-event timing, and wawu-...-muny completed prior event."
        ),
        command="rg/sed over grammar.md for PRECAUT, SUCC, wawu-, 4.4.2, 4.4.3, 4.4.4.3",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="source",
        event_type="construction-source-check",
        actor="claude-main",
        detail=(
            "Checked source forms: bujil-janji-nyji, kuni-nyji, bayka-nyji, banbadi-nyji, dara-y-mani-nyji, "
            "kada-nyji, dakuy-ma-nyji, bambay-ma-nyji; bayka-nyjiku, jilba-dunga-nyjiku, wandi-nyjiku, "
            "nuka-nyjiku, ngara-nyjiku, duda-nyjiku, warri-nyjiku, dara-nyjiku, kada-nyjiku; "
            "wawu-janji-nya-muny, wawu-wala-nya-muny, wawu-bayka-nya-muny, wawu-kambi-muny, "
            "wawu-jukijuki-muny, wawu-ngangkurr-muny, wawu-jilba-muny, wawu-mayi-muny, wawu-yinya-muny."
        ),
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="preflight",
        event_type="existing-surface-scan",
        actor="claude-main",
        detail=(
            "Scanned existing accepted/revised corpus for -nyji, -nyjiku, PRECAUT, SUCC, TEMP4, and wawu- surfaces. "
            "Known exact surfaces avoided include Baya waju-l-waju, kiway kada-nyji; Kari kaya kuli-ji karrba, "
            "yununy bayka-nyji; Kari diburr kulba, dara-y-mani-nyji; Ngayu dungan, muyar kada-nyjiku; and several "
            "Batch 84/120 wawu- prior-event rows."
        ),
        command="sqlite existing-surface scan for Rule 114 forms",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="scope",
        event_type="risk-controls",
        actor="claude-main",
        detail=(
            "Controls: every precautionary row must carry -nyji/PRECAUT and not -nyjiku; every successive row must "
            "carry -nyjiku/SUCC and not PRECAUT; every prior-event row must carry wawu-, -muny, and TEMP4. "
            "No kunka/nguba substitution is used in this construction batch."
        ),
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    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 114 construction rows under_review after static construction guards and duplicate checks.",
        command="python3 batch_scripts/bank_156.py",
        artifact_path="batch_scripts/bank_156.py",
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="bank",
        event_type="row-inventory",
        actor="claude-main",
        detail=(
            "Rows 1-18 cover precautionary -nyji; rows 19-34 cover successive -nyjiku; rows 35-50 cover prior-event "
            "wawu-...-muny, including both verb + -nya-muny and noun/object-ablative forms."
        ),
        artifact_path="batch_scripts/bank_156.py",
        created_at=NOW,
    )
    db.commit()
    avg_words = sum(len(row[2].replace("!", " !").replace("?", " ?").split()) for row in ROWS) / len(ROWS)
    print(f"banked {LABEL}: 50 rows under_review; avg Kuku words/row={avg_words:.2f}")
    return 0


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