#!/usr/bin/env python3
"""Bank batch-155: practical contingency lexicon for condition/reason clauses."""

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-155"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-155-practical-contingency-lexicon-process.md"

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


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


ROWS = [
    (1, "If rain comes, we will close the house.",
     "Kaki kaba kaday, ngana bayan nandal.",
     "kaki kaba kada-y, ngana bayan nanda-l | if rain come-NONPAST we house close-NONPAST",
     "weather_contingency_kaki", 4, js(["kaki", "kaba", "kaday", "ngana", "bayan", "nandal"]), js([]),
     "Kaba rain, kaday come, bayan house/camp, nandal close; non-past kaki guard from Patz 4.3.2.", "0.80"),
    (2, "We will stay at the camp if a strong wind comes.",
     "Ngana bayan-ba bundanday, kaki muyar junkurrji kaday.",
     "ngana bayan-ba bundanda-y, kaki muyar junkurr-ji kada-y | we camp-LOC stay-NONPAST if wind strength-COMIT come-NONPAST",
     "weather_contingency_kaki_second", 4, js(["ngana", "bayan", "bundanday", "kaki", "muyar", "junkurrji", "kaday"]), js([]),
     "Second-position kaki after Patz 4.3.2; muyar and junkurrji source-checked.", "0.80"),
    (3, "I take firewood just in case cold comes.",
     "Ngayu baya wundil, nganganjirrka kiway kada-nya-mun-ku.",
     "ngayu baya wundi-l, nganganjirrka kiway kada-nya-mun-ku | I firewood take-NONPAST just.in.case cold come-SUB-mun-DAT",
     "weather_incase_nganganjirrka", 5, js(["ngayu", "baya", "wundil", "nganganjirrka", "kiway", "kaday"]), js([]),
     "Baya includes fire/firewood; kiway cold; nganganjirrka just-in-case plus source-shaped -nya-mun-ku.", "0.84"),
    (4, "I light a fire; perhaps the fire will be hot.",
     "Ngayu baya wajul, nguba baya wumbul.",
     "ngayu baya waju-l, nguba baya wumbul | I fire light-NONPAST perhaps fire hot",
     "fire_nguba_possibility", 4, js(["ngayu", "baya", "wajul", "nguba", "wumbul"]), js([]),
     "Waju-l cook/burn/light fire; nguba precedes the possibility per Patz 4.9.3.", "0.78"),
    (5, "If the sun is hot, the children stay in the house.",
     "Kaki wungar wumbul, karrkay-karrkay bayan-ba bundanday.",
     "kaki wungar wumbul, karrkay-karrkay bayan-ba bundanda-y | if sun hot children house-LOC stay-NONPAST",
     "weather_heat_kaki", 4, js(["kaki", "wungar", "wumbul", "karrkay", "bayan", "bundanday"]), js([]),
     "Wungar sun/day and wumbul hot are dictionary-checked; keeps kaki non-past/stative.", "0.78"),
    (6, "If the water is deep, you will not swim.",
     "Kaki bana bada, yundu kari maraji.",
     "kaki bana bada, yundu kari maraji | if water deep you NEG swim",
     "water_contingency_kaki", 4, js(["kaki", "bana", "bada", "yundu", "kari", "maraji"]), js([]),
     "Practical water-depth contingency; varies Batch 154 water-depth row by subject.", "0.76"),
    (7, "If there is no water along the road, take the billycan.",
     "Kaki bana kari baral-darr, jungkalu wundi.",
     "kaki bana kari baral-darr, jungkalu wundi | if water NEG road-PERL billycan take.IMP",
     "road_water_contingency", 5, js(["kaki", "bana", "kari", "baral", "jungkalu", "wundil"]), js([]),
     "Builds on Patz ex.397/398 no-water-on-road lexicon with an imperative response.", "0.82"),
    (8, "If the road is good, we will go tomorrow.",
     "Kaki baral ngulkurr, ngana wunkuny dungay.",
     "kaki baral ngulkurr, ngana wunkuny dunga-y | if road good we tomorrow go-NONPAST",
     "road_condition_kaki", 4, js(["kaki", "baral", "ngulkurr", "ngana", "wunkuny", "dungay"]), js([]),
     "Baral road and ngulkurr good are source-checked; wunkuny tomorrow from Rule 111/lexicon.", "0.78"),
    (9, "If the road is bad, we will stay at the camp.",
     "Kaki baral buyun, ngana bayan-ba bundanday.",
     "kaki baral buyun, ngana bayan-ba bundanda-y | if road bad we camp-LOC stay-NONPAST",
     "road_condition_kaki", 4, js(["kaki", "baral", "buyun", "ngana", "bayan", "bundanday"]), js([]),
     "Buyun bad is source-checked; practical contingency for travel decisions.", "0.78"),
    (10, "I take water; perhaps the sun is hot.",
     "Ngayu bana wundil, nguba wungar wumbul.",
     "ngayu bana wundi-l, nguba wungar wumbul | I water take-NONPAST perhaps sun hot",
     "water_nguba_possibility", 4, js(["ngayu", "bana", "wundil", "nguba", "wungar", "wumbul"]), js([]),
     "Independent nguba possibility as reason, per Patz 4.4.4.4 ex.503 strategy.", "0.80"),

    (11, "If the child is hungry, grandmother will cook food.",
     "Kaki karrkay dakuy, babi-ngka mayi wajul.",
     "kaki karrkay dakuy, babi-ngka mayi waju-l | if child hungry grandmother-ERG food cook-NONPAST",
     "hunger_contingency_kaki", 4, js(["kaki", "karrkay", "dakuy", "babi", "mayi", "wajul"]), js([]),
     "Dakuy is the common corpus/Patz surface for dictionary dakwuy hungry; source decision logged.", "0.80"),
    (12, "I cook food in case I get hungry.",
     "Ngayu mayi wajul, kunka ngayu dakuy-ma-nya-mun-ku.",
     "ngayu mayi waju-l, kunka ngayu dakuy-ma-nya-mun-ku | I food cook-NONPAST in.case I hungry-INCHO-SUB-mun-DAT",
     "hunger_incase_kunka", 5, js(["ngayu", "mayi", "wajul", "kunka", "dakuy"]), js([]),
     "Patz 4.4.4.4 lists dakuy-ma-nya-mun-ku 'in case I get hungry'.", "0.88"),
    (13, "If the child has a cold, grandmother gives green ants to the child.",
     "Kaki karrkay ngiki-ji, babi-ngka yangka dajil karrkay-anda.",
     "kaki karrkay ngiki-ji, babi-ngka yangka daji-l karrkay-anda | if child cold-COMIT grandmother-ERG green.ant give-NONPAST child-LOC:pt",
     "health_remedy_kaki", 5, js(["kaki", "karrkay", "ngiki", "babi", "yangka", "dajil"]), js([]),
     "Patz ex.545 gives grandmother, green ants, and child-with-cold frame.", "0.86"),
    (14, "If grandfather is sick, he takes medicinal root for the road.",
     "Kaki ngaji bambay, nyulu bangkan wundil baral-ka.",
     "kaki ngaji bambay, nyulu bangkan wundi-l baral-ka | if grandfather sick he medicinal.root take-NONPAST road-DAT",
     "health_road_kaki", 4, js(["kaki", "ngaji", "bambay", "nyulu", "bangkan", "wundil", "baral"]), js([]),
     "Bangkan medicinal root and Patz ex.500 medicine-for-road frame, avoiding English medicine.", "0.82"),
    (15, "If the child's body is tired, he sleeps.",
     "Kaki karrkay bangkarr bajaburray, nyulu warngku-wunay.",
     "kaki karrkay bangkarr bajaburray, nyulu warngku-wuna-y | if child body tired he sleep-lie-NONPAST",
     "tired_contingency_kaki", 4, js(["kaki", "karrkay", "bangkarr", "bajaburray", "nyulu", "warngku-wunay"]), js([]),
     "Bangkarr bajaburray is source-shaped from Patz ex.395; subject varied from Batch 154.", "0.82"),
    (16, "I take medicinal root in case the child gets sick.",
     "Ngayu bangkan wundil, kunka karrkay bambay-ma-nya-mun-ku.",
     "ngayu bangkan wundi-l, kunka karrkay bambay-ma-nya-mun-ku | I medicinal.root take-NONPAST in.case child sick-INCHO-SUB-mun-DAT",
     "health_incase_kunka", 5, js(["ngayu", "bangkan", "wundil", "kunka", "karrkay", "bambay"]), js([]),
     "Extends Patz ex.500 with the same bambay-ma-nya-mun-ku dependent form.", "0.84"),
    (17, "We will stay at the camp; perhaps the child is tired.",
     "Ngana bayan-ba bundanday, nguba karrkay bajaburray.",
     "ngana bayan-ba bundanda-y, nguba karrkay bajaburray | we camp-LOC stay-NONPAST perhaps child tired",
     "tired_nguba_possibility", 4, js(["ngana", "bayan", "bundanday", "nguba", "karrkay", "bajaburray"]), js([]),
     "Nguba independent possibility supplies the reason without a cumbersome dependent clause.", "0.78"),
    (18, "I cook fish; perhaps the child is hungry.",
     "Ngayu kuyu wajul, nguba karrkay dakuy.",
     "ngayu kuyu waju-l, nguba karrkay dakuy | I fish cook-NONPAST perhaps child hungry",
     "hunger_nguba_possibility", 4, js(["ngayu", "kuyu", "wajul", "nguba", "karrkay", "dakuy"]), js([]),
     "Practical food/hunger row using independent nguba possibility.", "0.78"),
    (19, "No, the child is not hungry; he is tired.",
     "Kari, karrkay kari dakuy, nyulu bajaburray.",
     "kari, karrkay kari dakuy, nyulu bajaburray | no child NEG hungry he tired",
     "answer_health_contrast", 4, js(["kari", "karrkay", "dakuy", "nyulu", "bajaburray"]), js([]),
     "Answer-word kari plus ordinary negation; distinguishes hungry from tired.", "0.80"),
    (20, "If I have no cold, I am well.",
     "Kaki ngayu ngiki-kari, ngayu ngulkurr.",
     "kaki ngayu ngiki-kari, ngayu ngulkurr | if I cold-PRIV I good",
     "health_recovery_kaki", 4, js(["kaki", "ngayu", "ngiki-kari", "ngulkurr"]), js([]),
     "Patz ex.556 gives ngiki-kari plus ngulkurr-ma-ny; this row keeps a conservative stative frame.", "0.78"),

    (21, "If a dog bites a child, tell me.",
     "Kaki kaya-ngka karrkay baykal, nganya balka.",
     "kaki kaya-ngka karrkay bayka-l, nganya balka | if dog-ERG child bite-NONPAST me.ACC tell.IMP",
     "animal_risk_kaki", 4, js(["kaki", "kaya", "karrkay", "baykal", "nganya", "balkal"]), js([]),
     "Dog-bites-child frame is Patz-attested; imperative tell-me response.", "0.82"),
    (22, "Do not touch the vicious dog, lest it bite the child.",
     "Kari kaya kuli-ji karrba, karrkay bayka-nyji.",
     "kari kaya kuli-ji karrba, karrkay bayka-nyji | NEG dog anger-COMIT touch.IMP child bite-PRECAUT",
     "animal_precautionary", 5, js(["kari", "kaya", "kuli", "karrba", "karrkay", "baykal"]), js([]),
     "Patz ex.437 gives the vicious-dog precautionary frame; dog-bites-child is independently Patz-attested.", "0.86"),
    (23, "If you see a snake on the road, leave the road.",
     "Kaki yundu jarba nyajil baral-ba, baral bawa.",
     "kaki yundu jarba nyaji-l baral-ba, baral bawa | if you snake see-NONPAST road-LOC road leave.IMP",
     "snake_road_kaki", 4, js(["kaki", "yundu", "jarba", "nyajil", "baral", "bawal"]), js([]),
     "Jarba snake, baral road, and bawal leave are source-checked.", "0.78"),
    (24, "You take a spear just in case a pig comes.",
     "Yundu kalka wundil, nganganjirrka bikibiki kada-nya-mun-ku.",
     "yundu kalka wundi-l, nganganjirrka bikibiki kada-nya-mun-ku | you spear take-NONPAST just.in.case pig come-SUB-mun-DAT",
     "animal_incase_nganganjirrka", 5, js(["yundu", "kalka", "wundil", "nganganjirrka", "bikibiki", "kaday"]), js([]),
     "Varies the Batch 154 just-in-case pig row by subject; keeps source-shaped dependent form.", "0.84"),
    (25, "If the day is good, the young men go for pigs with a dog.",
     "Kaki wungar ngulkurr, warru-warru bikibiki-nga dungay kaya-nji.",
     "kaki wungar ngulkurr, warru-warru bikibiki-nga dunga-y kaya-nji | if day good young.men pig-LOC go-NONPAST dog-COMIT",
     "hunting_condition_kaki", 5, js(["kaki", "wungar", "ngulkurr", "warru", "bikibiki", "dungay", "kaya"]), js([]),
     "Patz ex.548 gives warru-warru bikibiki-nga dungay kaya-nji.", "0.86"),
    (26, "If the fish do not bite, I leave the fishing line.",
     "Kaki kuyu-ngku kari baykal, ngayu badur bawal.",
     "kaki kuyu-ngku kari bayka-l, ngayu badur bawa-l | if fish-ERG NEG bite-NONPAST I fishing.line leave-NONPAST",
     "fishing_condition_kaki", 4, js(["kaki", "kuyu", "kari", "baykal", "ngayu", "badur", "bawal"]), js([]),
     "Dictionary bawal example has fish not biting and quitting fishing; adapted into non-past condition.", "0.82"),
    (27, "If a snake is close by, the children stay in the house.",
     "Kaki jarba ngundu janay, karrkay-karrkay bayan-ba bundanday.",
     "kaki jarba ngundu jana-y, karrkay-karrkay bayan-ba bundanda-y | if snake close.by stand/be-NONPAST children house-LOC stay-NONPAST",
     "snake_nearby_kaki", 4, js(["kaki", "jarba", "ngundu", "janay", "karrkay", "bayan", "bundanday"]), js([]),
     "Ngundu janay is source-shaped from Patz locational examples; practical danger contingency.", "0.78"),
    (28, "I take a stick in case a dog bites the child.",
     "Ngayu juku wundil, kunka kaya-ngka karrkay bayka-nya-mun-ku.",
     "ngayu juku wundi-l, kunka kaya-ngka karrkay bayka-nya-mun-ku | I stick take-NONPAST in.case dog-ERG child bite-SUB-mun-DAT",
     "animal_incase_kunka", 5, js(["ngayu", "juku", "wundil", "kunka", "kaya", "karrkay", "baykal"]), js([]),
     "Patz ex.502 dog-bite hypothetical reason, with object varied from pronoun to child.", "0.84"),
    (29, "Perhaps a pig will come to the water; take a spear.",
     "Nguba bikibiki bana-ka kaday, yundu kalka wundi.",
     "nguba bikibiki bana-ka kada-y, yundu kalka wundi | perhaps pig water-DAT come-NONPAST you spear take.IMP",
     "animal_nguba_possibility", 4, js(["nguba", "bikibiki", "bana", "kaday", "yundu", "kalka", "wundil"]), js([]),
     "Nguba precedes the possibility; practical response uses source-checked kalka/wundi.", "0.78"),
    (30, "If a snake bites me, I am sick.",
     "Kaki jarba-bu nganya baykal, ngayu bambay.",
     "kaki jarba-bu nganya bayka-l, ngayu bambay | if snake-ERG me.ACC bite-NONPAST I sick",
     "snake_bite_health_kaki", 4, js(["kaki", "jarba", "nganya", "baykal", "ngayu", "bambay"]), js([]),
     "Patz licenses jarba-bu for snake as biting A; bambay sick is dictionary/grammar checked.", "0.80"),

    (31, "If the road is bad, leave the billycan at the camp.",
     "Kaki baral buyun, jungkalu bayan-ba bawa.",
     "kaki baral buyun, jungkalu bayan-ba bawa | if road bad billycan camp-LOC leave.IMP",
     "road_tool_kaki", 4, js(["kaki", "baral", "buyun", "jungkalu", "bayan", "bawal"]), js([]),
     "Combines road condition with source-checked billycan and leave verb.", "0.78"),
    (32, "I take the billycan with water in case there is no water along the road.",
     "Ngayu jungkalu bana-ji wundil, kunka bana kari baral-darr.",
     "ngayu jungkalu bana-ji wundi-l, kunka bana kari baral-darr | I billycan water-COMIT take-NONPAST in.case water NEG road-PERL",
     "container_water_kunka", 5, js(["ngayu", "jungkalu", "bana", "wundil", "kunka", "kari", "baral"]), js([]),
     "Uses the Patz ex.397 no-water road frame with a container lexeme.", "0.82"),
    (33, "If the house is bad, I sweep the ground and clean it.",
     "Kaki bayan buyun, ngayu bubu kidal, dayirr-bungal.",
     "kaki bayan buyun, ngayu bubu kida-l, dayirr-bunga-l | if house bad I ground sweep-NONPAST clean-CAUS-NONPAST",
     "camp_cleaning_kaki", 5, js(["kaki", "bayan", "buyun", "ngayu", "bubu", "kidal", "dayirr-bungal"]), js([]),
     "Patz ex.499 source-checks kidal plus dayirr-bungal as sweep/clean house work.", "0.84"),
    (34, "If the bag is bad, take the billycan.",
     "Kaki balji buyun, jungkalu wundi.",
     "kaki balji buyun, jungkalu wundi | if bag bad billycan take.IMP",
     "container_choice_kaki", 4, js(["kaki", "balji", "buyun", "jungkalu", "wundil"]), js([]),
     "Balji bag/dillybag and jungkalu billycan are source-checked container nouns.", "0.78"),
    (35, "Take a bag; perhaps food is there.",
     "Balji wundi, nguba mayi yinyay.",
     "balji wundi, nguba mayi yinyay | bag take.IMP perhaps food there",
     "container_nguba_possibility", 4, js(["balji", "wundil", "nguba", "mayi", "yinyay"]), js([]),
     "Nguba independent possibility used as practical reason; mayi/yinyay source-checked.", "0.78"),
    (36, "If we stay at the camp, we close the house.",
     "Kaki ngana bayan-ba bundanday, ngana bayan nandal.",
     "kaki ngana bayan-ba bundanda-y, ngana bayan nanda-l | if we camp-LOC stay-NONPAST we house close-NONPAST",
     "camp_closure_kaki", 4, js(["kaki", "ngana", "bayan", "bundanday", "nandal"]), js([]),
     "Bundanday stay and nandal close are source-checked practical camp verbs.", "0.78"),
    (37, "If the child hides in the scrub, mother sees him.",
     "Kaki karrkay madja-nga ngaki-ji, ngamu-ngku nyunguny nyajil.",
     "kaki karrkay madja-nga ngaki-ji-y, ngamu-ngku nyunguny nyaji-l | if child scrub-LOC hide-REF-NONPAST mother-ERG him see-NONPAST",
     "scrub_search_kaki", 4, js(["kaki", "karrkay", "madja", "ngakiji", "ngamu", "nyunguny", "nyajil"]), js([]),
     "Madja scrub and ngaki-ji hide are source-checked; varies Batch 154 nguba row into kaki condition.", "0.78"),
    (38, "If a friend comes, I cook food and sweep the house.",
     "Kaki jawun kaday, ngayu mayi wajul, bayan kidal.",
     "kaki jawun kada-y, ngayu mayi waju-l, bayan kida-l | if friend come-NONPAST I food cook-NONPAST house sweep-NONPAST",
     "visitor_preparation_kaki", 5, js(["kaki", "jawun", "kaday", "ngayu", "mayi", "wajul", "bayan", "kidal"]), js([]),
     "Jawun friend plus Patz ex.499 preparation vocabulary.", "0.82"),
    (39, "We stay at the water; perhaps the road is bad.",
     "Ngana bana-nga bundanday, nguba baral buyun.",
     "ngana bana-nga bundanda-y, nguba baral buyun | we water-LOC stay-NONPAST perhaps road bad",
     "camp_nguba_possibility", 4, js(["ngana", "bana", "bundanday", "nguba", "baral", "buyun"]), js([]),
     "Independent nguba possibility supplies a reason for staying by water.", "0.76"),
    (40, "If you go tomorrow, take water.",
     "Kaki yundu wunkuny dungay, bana wundi.",
     "kaki yundu wunkuny dunga-y, bana wundi | if you tomorrow go-NONPAST water take.IMP",
     "travel_preparation_kaki", 4, js(["kaki", "yundu", "wunkuny", "dungay", "bana", "wundil"]), js([]),
     "Simple lexical contingency with wunkuny tomorrow and water-taking.", "0.78"),

    (41, "If the child is cold, light a fire.",
     "Kaki karrkay kiway-kiway, baya waju.",
     "kaki karrkay kiway-kiway, baya waju | if child cold fire light.IMP",
     "cold_fire_kaki", 4, js(["kaki", "karrkay", "kiway-kiway", "baya", "wajul"]), js([]),
     "Kiway-kiway cold and baya waju fire-lighting are source-checked.", "0.78"),
    (42, "If the sun is hot, take water for the road.",
     "Kaki wungar wumbul, bana wundi baral-ka.",
     "kaki wungar wumbul, bana wundi baral-ka | if sun hot water take.IMP road-DAT",
     "heat_road_preparation", 4, js(["kaki", "wungar", "wumbul", "bana", "wundil", "baral"]), js([]),
     "Adds practical road-preparation lexicon without changing Rule 112 grammar.", "0.78"),
    (43, "If rain comes tomorrow, we leave the road and stay at the camp.",
     "Kaki kaba wunkuny kaday, ngana baral bawal, bayan-ba bundanday.",
     "kaki kaba wunkuny kada-y, ngana baral bawa-l, bayan-ba bundanda-y | if rain tomorrow come-NONPAST we road leave-NONPAST camp-LOC stay-NONPAST",
     "weather_travel_response", 4, js(["kaki", "kaba", "wunkuny", "kaday", "ngana", "baral", "bawal", "bayan", "bundanday"]), js([]),
     "Combines weather, road, leave, and camp-stay vocabulary.", "0.78"),
    (44, "You take a fishing line; perhaps the fish will bite.",
     "Yundu badur wundil, nguba kuyu-ngku baykal.",
     "yundu badur wundi-l, nguba kuyu-ngku bayka-l | you fishing.line take-NONPAST perhaps fish-ERG bite-NONPAST",
     "fishing_nguba_possibility", 4, js(["yundu", "badur", "wundil", "nguba", "kuyu", "baykal"]), js([]),
     "Varies the Batch 154 badur/nguba/fish-bite row by subject.", "0.78"),
    (45, "If food is there, take the bag.",
     "Kaki mayi yinyay, balji wundi.",
     "kaki mayi yinyay, balji wundi | if food there bag take.IMP",
     "food_container_kaki", 4, js(["kaki", "mayi", "yinyay", "balji", "wundil"]), js([]),
     "Practical container choice with source-checked mayi/yinyay/balji.", "0.76"),
    (46, "If the child is hungry, mother gives food.",
     "Kaki karrkay dakuy, ngamu-ngku mayi dajil.",
     "kaki karrkay dakuy, ngamu-ngku mayi daji-l | if child hungry mother-ERG food give-NONPAST",
     "hunger_giving_kaki", 4, js(["kaki", "karrkay", "dakuy", "ngamu", "mayi", "dajil"]), js([]),
     "Varies the Batch 154 grandmother-gives-food row by actor; keeps dakuy source note.", "0.78"),
    (47, "I sweep the house; perhaps a friend will come.",
     "Ngayu bayan kidal, nguba jawun kaday.",
     "ngayu bayan kida-l, nguba jawun kada-y | I house sweep-NONPAST perhaps friend come-NONPAST",
     "visitor_nguba_preparation", 4, js(["ngayu", "bayan", "kidal", "nguba", "jawun", "kaday"]), js([]),
     "Preparation vocabulary with the preferred independent nguba possibility strategy.", "0.78"),
    (48, "Settled then, if the road is good, we will go.",
     "Yalada, kaki baral ngulkurr, ngana dungay.",
     "yalada, kaki baral ngulkurr, ngana dunga-y | settled.then if road good we go-NONPAST",
     "interjection_road_kaki", 4, js(["yalada", "kaki", "baral", "ngulkurr", "ngana", "dungay"]), js([]),
     "Rule 111 interjection plus Rule 112 kaki frame; lexical focus is road condition.", "0.78"),
    (49, "Never mind, we will stay at the camp; perhaps rain is coming.",
     "Wumba, ngana bayan-ba bundanday, nguba kaba kaday.",
     "wumba, ngana bayan-ba bundanda-y, nguba kaba kada-y | never.mind we camp-LOC stay-NONPAST perhaps rain come-NONPAST",
     "interjection_weather_nguba", 4, js(["wumba", "ngana", "bayan", "bundanday", "nguba", "kaba", "kaday"]), js([]),
     "Interjection plus weather possibility; nguba stays preposed.", "0.78"),
    (50, "Wait for me, take the billycan in case there is no water along the road.",
     "Kaku, jungkalu wundi, kunka bana kari baral-darr.",
     "kaku, jungkalu wundi, kunka bana kari baral-darr | wait.for.me billycan take.IMP in.case water NEG road-PERL",
     "interjection_container_kunka", 5, js(["kaku", "jungkalu", "wundil", "kunka", "bana", "kari", "baral"]), js([]),
     "Kaku interjection plus Patz ex.397 no-water-road in-case frame.", "0.82"),
]


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()} {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 "yala coordination" in english.lower() or " yala-coordination " in low:
            issues.append(f"{label}: yala coordination is excluded by Patz 4.9.3 evidence note")
        if frame.endswith("_kaki") or "_kaki" in frame:
            if re.search(r"(?<!NON)PAST", analysis) or "-ny |" in analysis:
                issues.append(f"{label}: kaki row must not use past-tense conditional structure")
        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 113 draft: practical contingency lexicon for condition/reason clauses", "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 113 source pass reread Rules 108-112, Patz 4.3.2 and 4.4.4.4 as construction guardrails, "
            "and targeted dictionary/grammar entries for practical contingency vocabulary: weather/cold/fire, "
            "health/hunger/remedy, dog/snake/pig/fish risk, road/water/camp, containers/tools, and take/leave/stay/"
            "close/give/cook/sweep support verbs."
        ),
        command="rg/sed over dictionary.yaml and grammar.md for Rule 113 practical contingency inventory",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="source",
        event_type="lexeme-source-check",
        actor="claude-main",
        detail=(
            "Checked source entries for kaba, muyar, junkurrji/junkuji, wumbul, kiway/kiway-kiway, baya, wungar, "
            "bambay, dakwuy/dakuy, ngiki, baja-burray/bajaburray, bangkan, bangkarr, yangka, kaya, jarba, bikibiki, "
            "kuyu, baral, bana, bayan, bubu, madja, jungkalu, balji, kalka, juku, badur, wundil, bawal, bundanday, "
            "nandal, dajil, waju-l/wajul, kidal, dayirr-bungal, dungay, kaday, nyajil, baykal, kunil, and balkal."
        ),
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="scope",
        event_type="risk-controls",
        actor="claude-main",
        detail=(
            "Rule 113 is lexical, not a new construction rule. It reuses Rule 112 frames only to give them practical "
            "lexical fuel. Controls: no yala coordination; no past-tense kaki; kunka/nganganjirrka only for in-case "
            "relations; nguba only as preposed possibility; balu not used as plain negation; exact Batch 154 surfaces "
            "avoided where possible before duplicate preflight."
        ),
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="preflight",
        event_type="candidate-risk-notes",
        actor="claude-main",
        detail=(
            "Candidate design deliberately varied high-risk recent surfaces including Batch 154 badur/nguba fish-bite, "
            "bikibiki just-in-case, no-water-road, sleep-if-tired, and grandmother-gives-food rows. The exact-surface "
            "bank check remains authoritative and will roll back before insertion if any collision remains."
        ),
        command="sqlite exact-surface probes over sentences joined to batches",
        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 113 practical contingency lexicon rows under_review after static and duplicate checks.",
        command="python3 batch_scripts/bank_155.py",
        artifact_path="batch_scripts/bank_155.py",
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="bank",
        event_type="row-inventory",
        actor="claude-main",
        detail=(
            "Rows 1-10 cover weather, cold, fire, road, and water contingencies; 11-20 health, hunger, tiredness, "
            "medicine, and green-ant remedy vocabulary; 21-30 dog/snake/pig/fish risk frames; 31-40 road, camp, "
            "container, house-cleaning, hiding, visitor, and travel-preparation vocabulary; 41-50 fire, hot sun, "
            "rain travel response, fishing line, food/bag, mother-gives-food, sweeping for visitors, and interjection "
            "frames."
        ),
        artifact_path="batch_scripts/bank_155.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())
