#!/usr/bin/env python3
"""Bank Batch 385: Rule 343 complementary sense-qualified reptile-set-C perception."""

from __future__ import annotations

import datetime as dt
import hashlib
import json
import re
import sqlite3

import yaml

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"
DICTIONARY = "/mnt/donto-data/workspace/mobtranslate.com/dictionaries/kuku_yalanji/dictionary.yaml"
GRAMMAR = "/mnt/donto-data/workspace/mobtranslate.com/dictionaries/kuku_yalanji/grammar.md"
LABEL = "batch-385"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-385-complementary-sense-qualified-reptile-set-c-singular-third-past-perception-after-rule342-process.md"

EXPECTED_HASHES = {
    DICTIONARY: "b575ab035ecc60f09f7bfc5537116555f3d290869fe75b2edf0fd8db60fe1b37",
    GRAMMAR: "5f21305f1fca9ee2cb64668e18156d1f322e3bd9e59850fda662bf0673714153",
}
TARGET_ORDER = [
    "kalkamuku", "karrkurr", "jinkalmu", "barka", "yalnga",
    "biwul", "yirku-yirku", "jadi", "walkarr", "bajabaja",
]
RECORD_COUNTS = {
    "kalkamuku": 2, "karrkurr": 1, "jinkalmu": 2, "barka": 3, "yalnga": 1,
    "biwul": 2, "yirku-yirku": 1, "jadi": 1, "walkarr": 1, "bajabaja": 1,
}
TARGET_LABELS = {
    "kalkamuku": "kalkamuku snake", "karrkurr": "karrkurr frog",
    "jinkalmu": "jinkalmu snake", "barka": "barka snake", "yalnga": "yalnga turtle",
    "biwul": "biwul snake", "yirku-yirku": "yirku-yirku frog", "jadi": "jadi goanna",
    "walkarr": "walkarr goanna", "bajabaja": "bajabaja lizard",
}
TARGET_GLOSSES = {
    "kalkamuku": "kalkamuku.snake", "karrkurr": "karrkurr.frog",
    "jinkalmu": "jinkalmu.snake", "barka": "barka.snake", "yalnga": "yalnga.turtle",
    "biwul": "biwul.snake", "yirku-yirku": "yirku-yirku.frog", "jadi": "jadi.goanna",
    "walkarr": "walkarr.goanna", "bajabaja": "bajabaja.lizard",
}
TARGET_CONFIDENCE = {
    "kalkamuku": "0.90", "karrkurr": "0.91", "jinkalmu": "0.83", "barka": "0.80",
    "yalnga": "0.88", "biwul": "0.82", "yirku-yirku": "0.91", "jadi": "0.88",
    "walkarr": "0.90", "bajabaja": "0.85",
}
EXPECTED_TARGET_COVERAGE = {
    "kalkamuku": 10, "karrkurr": 15, "jinkalmu": 16, "barka": 18, "yalnga": 18,
    "biwul": 19, "yirku-yirku": 19, "jadi": 23, "walkarr": 25, "bajabaja": 26,
}
EXPECTED_SUPPORT_COVERAGE = {
    "ngayu": 1471, "yundu": 1067, "nyulu": 742, "bula": 538, "jana": 1243,
    "yaluy": 4462, "yinyay": 4624, "nyajin": 2200,
}
FRAME_SPECS = [
    ("ngayu", "yinyay", "I saw", "there", "1sg"),
    ("yundu", "yaluy", "You saw", "here", "2sg"),
    ("nyulu", "yinyay", "He saw", "there", "3sg"),
    ("bula", "yaluy", "The two of them saw", "here", "3du"),
    ("jana", "yinyay", "They saw", "there", "3pl"),
]
OPPOSITE = {"yaluy": "yinyay", "yinyay": "yaluy"}

TARGET_EVIDENCE = {
    "kalkamuku": "Fresh dictionary yaml lines 12625-12645 retain two exact green-tree-snake records. Rule 343 preserves generic kalkamuku snake reference without record collapse, colour/tree habitat, movement, diet, danger, source, possession, or events.",
    "karrkurr": "Fresh dictionary yaml lines 13659-13670 retain one green-frog record. Rule 343 preserves generic karrkurr frog reference without colour, habitat, rain/season, sound, feeding, body/touch, water-sign knowledge, source, possession, or events.",
    "jinkalmu": "Fresh dictionary yaml lines 9600-9625 retain two brown-snake/taipan records that explicitly make no distinction; one includes boys/eyes/fierce-fighter prose. Rule 343 preserves generic jinkalmu snake without species resolution, body, cultural, bite, kill, source, possession, or event transfer.",
    "barka": "Fresh dictionary yaml lines 1745-1777 retain two snake records and one Queensland-nut flora record, including one mixed-definition card. Rule 343 selects generic barka snake without nut/tree/fruit/season, record alignment, colour/water habitat, food, source, possession, or events.",
    "yalnga": "Fresh dictionary yaml lines 29117-29129 retain one sea-turtle record with poisonous-sac food-safety prose. Rule 343 preserves generic yalnga turtle without sea habitat, poison/danger, sacs/body, removal/butchery, food, source, possession, or events.",
    "biwul": "Fresh dictionary yaml lines 3300-3325 retain distinct mother-in-law/avoidance and black-snake records. Rule 343 selects generic biwul snake without kinship, avoidance language, colour/size, case, social event, danger, source, or possession transfer.",
    "yirku-yirku": "Fresh dictionary yaml lines 30457-30470 retain exact fully reduplicated/onomatopoeic yirku-yirku as frog. Rule 343 preserves the whole frog head without free base, productive reduplication, sound imitation, habitat, source, possession, or events.",
    "jadi": "Fresh dictionary yaml lines 7015-7026 retain jadi as sand goanna with an old-people food taboo. Rule 343 preserves generic jadi goanna without sand habitat, age/permission, taboo, eating/food, hunting, source, possession, or events.",
    "walkarr": "Fresh dictionary yaml lines 25492-25503 retain walkarr as black scrub goanna; Patz 1616 attests walkarr-angka. Rule 343 preserves generic bare walkarr goanna without colour/scrub habitat, case, size, hunting/food, source, possession, or events.",
    "bajabaja": "Fresh dictionary yaml lines 293-307 retain exact bajabaja as blue-tongue lizard plus spring/place/story-site definition; Patz 719/3932 delimit myth and bite contexts. Rule 343 preserves the whole generic lizard head without free base, story/place, property/body, eggs/river/rocks, bite/fight/kill, source, possession, or events.",
}
SUPPORT_EVIDENCE = (
    "Patz 2577-2584 sources bare nominative ngayu, yundu, nyulu, bula and plural third-person paradigm; "
    "running examples establish jana. Patz 2834-2847 distinguishes Yalanji yaluy/yinyay; 2021-2024, "
    "2568-2571 and 3160-3162 license nyaji-ny; 4256-4265 licenses nominative pronoun A with bare absolutive O "
    "in sensory perception. Dictionary 23876-23883 and 23968-23976 contain running nyajin. Rule 342 supplies "
    "only the opposite distributional cells, not permission to copy target source events or closed senses."
)

DENY_KUKU = {
    "ngali", "ngaliny", "yubal", "yurra", "nganjin", "ngana", "yulu", "iana",
    "yirku", "baja", "yalay", "yala", "yanyu", "yinya", "nyajil", "nyaji-l",
    "nyaji-nka", "nyaji-l-nyaji", "milka", "baykal", "jalngkay",
}
DENY_ENGLISH = (
    "green", "brown", "yellow", "black", "blue-tongue", "tree habitat", "water habitat",
    "sea habitat", "scrub habitat", "sand habitat", "taipan", "nut", "fruit", "july", "october",
    "mother-in-law", "avoidance language", "poison", "danger", "sac", "remove", "butcher", "eyes",
    "boys", "eat", "fierce", "fight", "bite", "kill", "old people", "taboo", "spring", "story",
    "place", "eggs", "hatch", "river", "rocks", "sound", "source", "possess", "event",
    "productive reduplication", "free base",
)


def count_words(db: sqlite3.Connection, words: list[str]) -> dict[str, int]:
    return {
        word: db.execute(
            """SELECT COUNT(*) FROM sentences s
               WHERE s.status IN ('accepted','revised')
                 AND EXISTS (SELECT 1 FROM json_each(s.words_used) WHERE lower(value)=?)""",
            (word,),
        ).fetchone()[0]
        for word in words
    }


def row(seq: int, english: str, kuku: str, analysis: str, frame: str, words: list[str]) -> tuple:
    target = words[1]
    return (
        seq, english, kuku, analysis, frame, 3,
        json.dumps(words, ensure_ascii=False), json.dumps([], ensure_ascii=False),
        f"{TARGET_EVIDENCE[target]} {SUPPORT_EVIDENCE}", TARGET_CONFIDENCE[target],
    )


ROWS = [
    row(1, "I saw the kalkamuku snake there.", "Ngayu kalkamuku yinyay nyajin.", "ngayu kalkamuku yinyay nyajin | 1sg.NOM kalkamuku.snake there see.PST", "r343_1sg_there_reptile_c_saw_kalkamuku", ["ngayu", "kalkamuku", "yinyay", "nyajin"]),
    row(2, "I saw the karrkurr frog there.", "Ngayu karrkurr yinyay nyajin.", "ngayu karrkurr yinyay nyajin | 1sg.NOM karrkurr.frog there see.PST", "r343_1sg_there_reptile_c_saw_karrkurr", ["ngayu", "karrkurr", "yinyay", "nyajin"]),
    row(3, "I saw the jinkalmu snake there.", "Ngayu jinkalmu yinyay nyajin.", "ngayu jinkalmu yinyay nyajin | 1sg.NOM jinkalmu.snake there see.PST", "r343_1sg_there_reptile_c_saw_jinkalmu", ["ngayu", "jinkalmu", "yinyay", "nyajin"]),
    row(4, "I saw the barka snake there.", "Ngayu barka yinyay nyajin.", "ngayu barka yinyay nyajin | 1sg.NOM barka.snake there see.PST", "r343_1sg_there_reptile_c_saw_barka", ["ngayu", "barka", "yinyay", "nyajin"]),
    row(5, "I saw the yalnga turtle there.", "Ngayu yalnga yinyay nyajin.", "ngayu yalnga yinyay nyajin | 1sg.NOM yalnga.turtle there see.PST", "r343_1sg_there_reptile_c_saw_yalnga", ["ngayu", "yalnga", "yinyay", "nyajin"]),
    row(6, "I saw the biwul snake there.", "Ngayu biwul yinyay nyajin.", "ngayu biwul yinyay nyajin | 1sg.NOM biwul.snake there see.PST", "r343_1sg_there_reptile_c_saw_biwul", ["ngayu", "biwul", "yinyay", "nyajin"]),
    row(7, "I saw the yirku-yirku frog there.", "Ngayu yirku-yirku yinyay nyajin.", "ngayu yirku-yirku yinyay nyajin | 1sg.NOM yirku-yirku.frog there see.PST", "r343_1sg_there_reptile_c_saw_yirku_yirku", ["ngayu", "yirku-yirku", "yinyay", "nyajin"]),
    row(8, "I saw the jadi goanna there.", "Ngayu jadi yinyay nyajin.", "ngayu jadi yinyay nyajin | 1sg.NOM jadi.goanna there see.PST", "r343_1sg_there_reptile_c_saw_jadi", ["ngayu", "jadi", "yinyay", "nyajin"]),
    row(9, "I saw the walkarr goanna there.", "Ngayu walkarr yinyay nyajin.", "ngayu walkarr yinyay nyajin | 1sg.NOM walkarr.goanna there see.PST", "r343_1sg_there_reptile_c_saw_walkarr", ["ngayu", "walkarr", "yinyay", "nyajin"]),
    row(10, "I saw the bajabaja lizard there.", "Ngayu bajabaja yinyay nyajin.", "ngayu bajabaja yinyay nyajin | 1sg.NOM bajabaja.lizard there see.PST", "r343_1sg_there_reptile_c_saw_bajabaja", ["ngayu", "bajabaja", "yinyay", "nyajin"]),
    row(11, "You saw the kalkamuku snake here.", "Yundu kalkamuku yaluy nyajin.", "yundu kalkamuku yaluy nyajin | 2sg.NOM kalkamuku.snake here see.PST", "r343_2sg_here_reptile_c_saw_kalkamuku", ["yundu", "kalkamuku", "yaluy", "nyajin"]),
    row(12, "You saw the karrkurr frog here.", "Yundu karrkurr yaluy nyajin.", "yundu karrkurr yaluy nyajin | 2sg.NOM karrkurr.frog here see.PST", "r343_2sg_here_reptile_c_saw_karrkurr", ["yundu", "karrkurr", "yaluy", "nyajin"]),
    row(13, "You saw the jinkalmu snake here.", "Yundu jinkalmu yaluy nyajin.", "yundu jinkalmu yaluy nyajin | 2sg.NOM jinkalmu.snake here see.PST", "r343_2sg_here_reptile_c_saw_jinkalmu", ["yundu", "jinkalmu", "yaluy", "nyajin"]),
    row(14, "You saw the barka snake here.", "Yundu barka yaluy nyajin.", "yundu barka yaluy nyajin | 2sg.NOM barka.snake here see.PST", "r343_2sg_here_reptile_c_saw_barka", ["yundu", "barka", "yaluy", "nyajin"]),
    row(15, "You saw the yalnga turtle here.", "Yundu yalnga yaluy nyajin.", "yundu yalnga yaluy nyajin | 2sg.NOM yalnga.turtle here see.PST", "r343_2sg_here_reptile_c_saw_yalnga", ["yundu", "yalnga", "yaluy", "nyajin"]),
    row(16, "You saw the biwul snake here.", "Yundu biwul yaluy nyajin.", "yundu biwul yaluy nyajin | 2sg.NOM biwul.snake here see.PST", "r343_2sg_here_reptile_c_saw_biwul", ["yundu", "biwul", "yaluy", "nyajin"]),
    row(17, "You saw the yirku-yirku frog here.", "Yundu yirku-yirku yaluy nyajin.", "yundu yirku-yirku yaluy nyajin | 2sg.NOM yirku-yirku.frog here see.PST", "r343_2sg_here_reptile_c_saw_yirku_yirku", ["yundu", "yirku-yirku", "yaluy", "nyajin"]),
    row(18, "You saw the jadi goanna here.", "Yundu jadi yaluy nyajin.", "yundu jadi yaluy nyajin | 2sg.NOM jadi.goanna here see.PST", "r343_2sg_here_reptile_c_saw_jadi", ["yundu", "jadi", "yaluy", "nyajin"]),
    row(19, "You saw the walkarr goanna here.", "Yundu walkarr yaluy nyajin.", "yundu walkarr yaluy nyajin | 2sg.NOM walkarr.goanna here see.PST", "r343_2sg_here_reptile_c_saw_walkarr", ["yundu", "walkarr", "yaluy", "nyajin"]),
    row(20, "You saw the bajabaja lizard here.", "Yundu bajabaja yaluy nyajin.", "yundu bajabaja yaluy nyajin | 2sg.NOM bajabaja.lizard here see.PST", "r343_2sg_here_reptile_c_saw_bajabaja", ["yundu", "bajabaja", "yaluy", "nyajin"]),
    row(21, "He saw the kalkamuku snake there.", "Nyulu kalkamuku yinyay nyajin.", "nyulu kalkamuku yinyay nyajin | 3sg.NOM kalkamuku.snake there see.PST", "r343_3sg_there_reptile_c_saw_kalkamuku", ["nyulu", "kalkamuku", "yinyay", "nyajin"]),
    row(22, "He saw the karrkurr frog there.", "Nyulu karrkurr yinyay nyajin.", "nyulu karrkurr yinyay nyajin | 3sg.NOM karrkurr.frog there see.PST", "r343_3sg_there_reptile_c_saw_karrkurr", ["nyulu", "karrkurr", "yinyay", "nyajin"]),
    row(23, "He saw the jinkalmu snake there.", "Nyulu jinkalmu yinyay nyajin.", "nyulu jinkalmu yinyay nyajin | 3sg.NOM jinkalmu.snake there see.PST", "r343_3sg_there_reptile_c_saw_jinkalmu", ["nyulu", "jinkalmu", "yinyay", "nyajin"]),
    row(24, "He saw the barka snake there.", "Nyulu barka yinyay nyajin.", "nyulu barka yinyay nyajin | 3sg.NOM barka.snake there see.PST", "r343_3sg_there_reptile_c_saw_barka", ["nyulu", "barka", "yinyay", "nyajin"]),
    row(25, "He saw the yalnga turtle there.", "Nyulu yalnga yinyay nyajin.", "nyulu yalnga yinyay nyajin | 3sg.NOM yalnga.turtle there see.PST", "r343_3sg_there_reptile_c_saw_yalnga", ["nyulu", "yalnga", "yinyay", "nyajin"]),
    row(26, "He saw the biwul snake there.", "Nyulu biwul yinyay nyajin.", "nyulu biwul yinyay nyajin | 3sg.NOM biwul.snake there see.PST", "r343_3sg_there_reptile_c_saw_biwul", ["nyulu", "biwul", "yinyay", "nyajin"]),
    row(27, "He saw the yirku-yirku frog there.", "Nyulu yirku-yirku yinyay nyajin.", "nyulu yirku-yirku yinyay nyajin | 3sg.NOM yirku-yirku.frog there see.PST", "r343_3sg_there_reptile_c_saw_yirku_yirku", ["nyulu", "yirku-yirku", "yinyay", "nyajin"]),
    row(28, "He saw the jadi goanna there.", "Nyulu jadi yinyay nyajin.", "nyulu jadi yinyay nyajin | 3sg.NOM jadi.goanna there see.PST", "r343_3sg_there_reptile_c_saw_jadi", ["nyulu", "jadi", "yinyay", "nyajin"]),
    row(29, "He saw the walkarr goanna there.", "Nyulu walkarr yinyay nyajin.", "nyulu walkarr yinyay nyajin | 3sg.NOM walkarr.goanna there see.PST", "r343_3sg_there_reptile_c_saw_walkarr", ["nyulu", "walkarr", "yinyay", "nyajin"]),
    row(30, "He saw the bajabaja lizard there.", "Nyulu bajabaja yinyay nyajin.", "nyulu bajabaja yinyay nyajin | 3sg.NOM bajabaja.lizard there see.PST", "r343_3sg_there_reptile_c_saw_bajabaja", ["nyulu", "bajabaja", "yinyay", "nyajin"]),
    row(31, "The two of them saw the kalkamuku snake here.", "Bula kalkamuku yaluy nyajin.", "bula kalkamuku yaluy nyajin | 3du.NOM kalkamuku.snake here see.PST", "r343_3du_here_reptile_c_saw_kalkamuku", ["bula", "kalkamuku", "yaluy", "nyajin"]),
    row(32, "The two of them saw the karrkurr frog here.", "Bula karrkurr yaluy nyajin.", "bula karrkurr yaluy nyajin | 3du.NOM karrkurr.frog here see.PST", "r343_3du_here_reptile_c_saw_karrkurr", ["bula", "karrkurr", "yaluy", "nyajin"]),
    row(33, "The two of them saw the jinkalmu snake here.", "Bula jinkalmu yaluy nyajin.", "bula jinkalmu yaluy nyajin | 3du.NOM jinkalmu.snake here see.PST", "r343_3du_here_reptile_c_saw_jinkalmu", ["bula", "jinkalmu", "yaluy", "nyajin"]),
    row(34, "The two of them saw the barka snake here.", "Bula barka yaluy nyajin.", "bula barka yaluy nyajin | 3du.NOM barka.snake here see.PST", "r343_3du_here_reptile_c_saw_barka", ["bula", "barka", "yaluy", "nyajin"]),
    row(35, "The two of them saw the yalnga turtle here.", "Bula yalnga yaluy nyajin.", "bula yalnga yaluy nyajin | 3du.NOM yalnga.turtle here see.PST", "r343_3du_here_reptile_c_saw_yalnga", ["bula", "yalnga", "yaluy", "nyajin"]),
    row(36, "The two of them saw the biwul snake here.", "Bula biwul yaluy nyajin.", "bula biwul yaluy nyajin | 3du.NOM biwul.snake here see.PST", "r343_3du_here_reptile_c_saw_biwul", ["bula", "biwul", "yaluy", "nyajin"]),
    row(37, "The two of them saw the yirku-yirku frog here.", "Bula yirku-yirku yaluy nyajin.", "bula yirku-yirku yaluy nyajin | 3du.NOM yirku-yirku.frog here see.PST", "r343_3du_here_reptile_c_saw_yirku_yirku", ["bula", "yirku-yirku", "yaluy", "nyajin"]),
    row(38, "The two of them saw the jadi goanna here.", "Bula jadi yaluy nyajin.", "bula jadi yaluy nyajin | 3du.NOM jadi.goanna here see.PST", "r343_3du_here_reptile_c_saw_jadi", ["bula", "jadi", "yaluy", "nyajin"]),
    row(39, "The two of them saw the walkarr goanna here.", "Bula walkarr yaluy nyajin.", "bula walkarr yaluy nyajin | 3du.NOM walkarr.goanna here see.PST", "r343_3du_here_reptile_c_saw_walkarr", ["bula", "walkarr", "yaluy", "nyajin"]),
    row(40, "The two of them saw the bajabaja lizard here.", "Bula bajabaja yaluy nyajin.", "bula bajabaja yaluy nyajin | 3du.NOM bajabaja.lizard here see.PST", "r343_3du_here_reptile_c_saw_bajabaja", ["bula", "bajabaja", "yaluy", "nyajin"]),
    row(41, "They saw the kalkamuku snake there.", "Jana kalkamuku yinyay nyajin.", "jana kalkamuku yinyay nyajin | 3pl.NOM kalkamuku.snake there see.PST", "r343_3pl_there_reptile_c_saw_kalkamuku", ["jana", "kalkamuku", "yinyay", "nyajin"]),
    row(42, "They saw the karrkurr frog there.", "Jana karrkurr yinyay nyajin.", "jana karrkurr yinyay nyajin | 3pl.NOM karrkurr.frog there see.PST", "r343_3pl_there_reptile_c_saw_karrkurr", ["jana", "karrkurr", "yinyay", "nyajin"]),
    row(43, "They saw the jinkalmu snake there.", "Jana jinkalmu yinyay nyajin.", "jana jinkalmu yinyay nyajin | 3pl.NOM jinkalmu.snake there see.PST", "r343_3pl_there_reptile_c_saw_jinkalmu", ["jana", "jinkalmu", "yinyay", "nyajin"]),
    row(44, "They saw the barka snake there.", "Jana barka yinyay nyajin.", "jana barka yinyay nyajin | 3pl.NOM barka.snake there see.PST", "r343_3pl_there_reptile_c_saw_barka", ["jana", "barka", "yinyay", "nyajin"]),
    row(45, "They saw the yalnga turtle there.", "Jana yalnga yinyay nyajin.", "jana yalnga yinyay nyajin | 3pl.NOM yalnga.turtle there see.PST", "r343_3pl_there_reptile_c_saw_yalnga", ["jana", "yalnga", "yinyay", "nyajin"]),
    row(46, "They saw the biwul snake there.", "Jana biwul yinyay nyajin.", "jana biwul yinyay nyajin | 3pl.NOM biwul.snake there see.PST", "r343_3pl_there_reptile_c_saw_biwul", ["jana", "biwul", "yinyay", "nyajin"]),
    row(47, "They saw the yirku-yirku frog there.", "Jana yirku-yirku yinyay nyajin.", "jana yirku-yirku yinyay nyajin | 3pl.NOM yirku-yirku.frog there see.PST", "r343_3pl_there_reptile_c_saw_yirku_yirku", ["jana", "yirku-yirku", "yinyay", "nyajin"]),
    row(48, "They saw the jadi goanna there.", "Jana jadi yinyay nyajin.", "jana jadi yinyay nyajin | 3pl.NOM jadi.goanna there see.PST", "r343_3pl_there_reptile_c_saw_jadi", ["jana", "jadi", "yinyay", "nyajin"]),
    row(49, "They saw the walkarr goanna there.", "Jana walkarr yinyay nyajin.", "jana walkarr yinyay nyajin | 3pl.NOM walkarr.goanna there see.PST", "r343_3pl_there_reptile_c_saw_walkarr", ["jana", "walkarr", "yinyay", "nyajin"]),
    row(50, "They saw the bajabaja lizard there.", "Jana bajabaja yinyay nyajin.", "jana bajabaja yinyay nyajin | 3pl.NOM bajabaja.lizard there see.PST", "r343_3pl_there_reptile_c_saw_bajabaja", ["jana", "bajabaja", "yinyay", "nyajin"]),
]


def source_audit() -> dict[str, int]:
    hashes = {path: hashlib.sha256(open(path, "rb").read()).hexdigest() for path in EXPECTED_HASHES}
    if hashes != EXPECTED_HASHES:
        raise SystemExit(f"source hash changed: {hashes}")
    entries = yaml.safe_load(open(DICTIONARY, encoding="utf-8"))["words"]
    counts = {target: sum(entry.get("word") == target for entry in entries) for target in TARGET_ORDER}
    if counts != RECORD_COUNTS:
        raise SystemExit(f"record inventory changed: {counts}")
    for target in TARGET_ORDER:
        records = [entry for entry in entries if entry.get("word") == target]
        if not any(entry.get("type") == "noun" and entry.get("semantic_domain") == "fauna-reptile" for entry in records):
            raise SystemExit(f"no fauna-reptile noun record for {target}")
    return counts


def scan_static() -> list[str]:
    issues: list[str] = []
    if len(ROWS) != 50:
        issues.append(f"row count {len(ROWS)} != 50")
    if [item[0] for item in ROWS] != list(range(1, 51)):
        issues.append("sequence is not 1..50")
    if len({item[1] for item in ROWS}) != 50:
        issues.append("duplicate English surface")
    if len({item[2] for item in ROWS}) != 50:
        issues.append("duplicate Kuku surface")
    for seq, english, kuku, analysis, frame, _tier, words_json, loans_json, evidence, confidence in ROWS:
        words = json.loads(words_json)
        loans = json.loads(loans_json)
        band = (seq - 1) // 10
        target = TARGET_ORDER[(seq - 1) % 10]
        pronoun, demo, prefix, location, person = FRAME_SPECS[band]
        expected_kuku = f"{pronoun.capitalize()} {target} {demo} nyajin."
        expected_english = f"{prefix} the {TARGET_LABELS[target]} {location}."
        expected_analysis = f"{pronoun} {target} {demo} nyajin | {person}.NOM {TARGET_GLOSSES[target]} {location} see.PST"
        if loans:
            issues.append(f"{seq}: loans {loans}")
        denied = sorted(word for word in DENY_KUKU if re.search(rf"(^|\s){re.escape(word)}([\s\.]|$)", kuku.lower()))
        if denied:
            issues.append(f"{seq}: denied Kuku {denied}")
        drift = [term for term in DENY_ENGLISH if re.search(rf"\b{re.escape(term)}\b", english.lower())]
        if drift:
            issues.append(f"{seq}: English drift {drift}")
        if kuku != expected_kuku:
            issues.append(f"{seq}: Kuku mismatch")
        if english != expected_english:
            issues.append(f"{seq}: English mismatch")
        if analysis != expected_analysis:
            issues.append(f"{seq}: analysis mismatch")
        if words != [pronoun, target, demo, "nyajin"]:
            issues.append(f"{seq}: words mismatch")
        if kuku.lower().rstrip(".") != " ".join(words):
            issues.append(f"{seq}: surface/words mismatch")
        if not frame.startswith("r343_"):
            issues.append(f"{seq}: frame mismatch")
        if TARGET_EVIDENCE[target] not in evidence or SUPPORT_EVIDENCE not in evidence:
            issues.append(f"{seq}: evidence mismatch")
        if confidence != TARGET_CONFIDENCE[target]:
            issues.append(f"{seq}: confidence mismatch")
    return issues


def main() -> int:
    record_counts = source_audit()
    issues = scan_static()
    if issues:
        print("\n".join(issues))
        raise SystemExit(1)

    db = sqlite3.connect(DB)
    db.execute("PRAGMA foreign_keys=ON")
    db.execute("BEGIN")
    ensure_schema(db)
    if db.execute("SELECT 1 FROM batches WHERE label=?", (LABEL,)).fetchone():
        raise SystemExit(f"{LABEL} exists")
    if db.execute("SELECT COUNT(*) FROM sentences WHERE status='under_review'").fetchone()[0]:
        raise SystemExit("another batch is under review")

    target_coverage = count_words(db, TARGET_ORDER)
    support_coverage = count_words(db, list(EXPECTED_SUPPORT_COVERAGE))
    if target_coverage != EXPECTED_TARGET_COVERAGE:
        raise SystemExit(f"target coverage changed: {target_coverage}")
    if support_coverage != EXPECTED_SUPPORT_COVERAGE:
        raise SystemExit(f"support coverage changed: {support_coverage}")

    for seq, _english, kuku, _analysis, _frame, _tier, words_json, _loans, _evidence, _confidence in ROWS:
        words = json.loads(words_json)
        candidate_hits = db.execute(
            """SELECT b.label,s.seq FROM sentences s JOIN batches b ON b.id=s.batch_id
               WHERE lower(s.kuku)=lower(?) AND s.status!='rejected' ORDER BY b.id,s.seq""",
            (kuku,),
        ).fetchall()
        if candidate_hits:
            raise SystemExit(f"candidate collision {seq}: {candidate_hits}")
        opposite_surface = f"{words[0].capitalize()} {words[1]} {OPPOSITE[words[2]]} nyajin."
        opposite_hits = db.execute(
            """SELECT b.label,s.seq FROM sentences s JOIN batches b ON b.id=s.batch_id
               WHERE lower(s.kuku)=lower(?) AND s.status!='rejected' ORDER BY b.id,s.seq""",
            (opposite_surface,),
        ).fetchall()
        if opposite_hits != [("batch-384", seq)]:
            raise SystemExit(f"opposite mismatch {seq}: {opposite_hits}")

    verified, words = db.execute(
        """SELECT COUNT(*),SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1)
           FROM sentences WHERE status IN ('accepted','revised')"""
    ).fetchone()
    if (verified, words) != (19297, 132547):
        raise SystemExit(f"baseline changed {verified}/{words}")

    notes = (
        "COMPLEMENTARY SENSE-QUALIFIED REPTILE LEXEME-SET-C SINGULAR/THIRD PAST PERCEPTION AFTER RULE 342 "
        "(Rule 343). 50 under-review rows over the ten Rule 342 heads. Fresh source hashes and 2/1/2/3/1/2/1/1/1/1 "
        "record inventory unchanged; every candidate empty and every opposite exactly Batch 384 seq 1-50. Generic "
        "labels preserve duplicate, barka flora, biwul kinship, jinkalmu taxonomy/culture, food safety/taboo, myth/place, "
        "whole-head, property/habitat, source/case/event boundaries. Completion necessarily changes gap 162->172."
    )
    cur = db.execute(
        "INSERT INTO batches(label,cheatsheet_version,guide_version,notes,created_at) VALUES(?,?,?,?,?)",
        (LABEL, "Rule 343 under review", "operator-guide-2026-07-10", notes, NOW),
    )
    batch_id = cur.lastrowid
    db.executemany(
        """INSERT INTO sentences(
             batch_id,seq,english,kuku,analysis,frame,tier,words_used,loans_used,evidence,status,confidence,
             rights_status,author,created_at,updated_at
           ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
        [
            (
                batch_id, seq, english, kuku, analysis, frame, tier, words_json, loans_json, evidence,
                "under_review", confidence, "project_approved_synthetic_pending_elder_verification",
                "codex-main", NOW, NOW,
            )
            for seq, english, kuku, analysis, frame, tier, words_json, loans_json, evidence, confidence in ROWS
        ],
    )
    events = [
        ("source", "source-hash-pass", f"Dictionary and Patz hashes match fixed Rule 343 expectations: {EXPECTED_HASHES}."),
        ("source", "source-readback", f"Fresh parsed exact-record inventory passed: {record_counts}; support and target source passages reread."),
        ("planning", "sense-preservation-audit", "Rule 342 generic labels retained; duplicate, flora, kinship, taxonomy/culture, food safety/taboo, myth/place, whole-head, property/habitat, source/case/event boundaries remain closed."),
        ("planning", "complement-map-audit", "All 50 candidate cells absent; every opposite maps exactly to Batch 384 sequences 1-50; complete 100-cell matrix accounted for."),
        ("planning", "deictic-balance-audit", "Before banking yaluy=4462 and yinyay=4624, gap 162; completion projects 172. The apparent 152-gap inverse is exactly Batch 384 and inadmissible duplication."),
        ("preflight", "coverage-audit", f"Coverage before banking: targets={target_coverage}; support={support_coverage}."),
        ("preflight", "duplicate-preflight", "All 50 candidate Kuku and English surfaces are internally unique and absent from the active corpus; opposites proved rather than regenerated."),
        ("preflight", "static-guard-pass", "50 explicit Rule 343 rows; source, sense, morphology, frame, words, gloss, evidence, confidence, loan, and exclusion contracts passed."),
    ]
    for phase, event_type, detail in events:
        record_event(
            db, batch_label=LABEL, phase=phase, event_type=event_type, actor="codex",
            detail=detail, artifact_path=PROCESS_LOG, created_at=NOW,
        )
    record_event(
        db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="codex",
        detail=f"Banked 50 Rule 343 complementary rows under_review; verified remains {verified}; words {words}.",
        command="python3 batch_scripts/bank_385.py", output_excerpt="50 under_review",
        artifact_path=PROCESS_LOG, created_at=NOW,
    )
    db.commit()
    print("banked batch-385: 50 rows under_review")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
