#!/usr/bin/env python3
"""Bank batch-383: Rule 341 complementary reptile lexeme-set-B non-singular past perception."""

from __future__ import annotations

import datetime as dt
import json
import re
import sqlite3

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-383"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-383-complementary-reptile-set-b-nonsingular-past-perception-after-rule340-process.md"

TARGET_EVIDENCE = {
    "banamu": "Dictionary yaml lines 1346-1370 contain two exact noun-typed fauna-reptile banamu records, both licensing snake reference and freshwater classification. Rule 341 uses conservative banamu snake reference without collapsing records or adding habitat, movement, danger, source, possession, or events.",
    "binju": "Dictionary yaml lines 2979-3013 contain a polysemous binju record spanning wrong marriage, poorly made/cooked material, and a poisonous small black snake, plus a separate fauna-reptile light-bellied-black-snake record. Rule 341 uses only conservative binju snake reference; marriage/law, food/cooking/quality, colour/body, size, poison/danger, record identity, source, possession, and events remain closed.",
    "dukul-mukul": "Dictionary yaml lines 6360-6370 give exact hyphenated dukul-mukul as a fauna-reptile small big-headed lizard noun. Rule 341 uses the whole lizard head only; free components, size, head/body property, species resolution, source, possession, and events remain closed.",
    "jirabay": "Dictionary yaml lines 9645-9655 give jirabay as a fauna-reptile ground-lizard noun larger than a blue-tongue lizard. Rule 341 uses conservative jirabay lizard reference only; ground habitat, size/comparison, blue-tongue identity, source, possession, and events remain closed.",
    "junbirr": "Dictionary yaml lines 10826-10839 give junbirr as a small-lizard noun with leaf/grass, wet-season, and reddish-head prose. Patz line 1685 attests junbirr-anka in dative case. Rule 341 uses bare conservative junbirr lizard only; size, habitat, season, colour/head, case, source, possession, and events remain closed.",
    "kabuljaka": "Dictionary yaml lines 11834-11856 contain two exact fauna-reptile kabuljaka records for a striped/zebra water snake; commentary analyses a compound built on kabul. Rule 341 retains exact whole kabuljaka as conservative snake reference without collapsing records, generating components, or adding stripe/colour, water habitat, python identity, source, possession, or events.",
    "kulmba-kulmba": "Dictionary yaml lines 15290-15305 give exact fully reduplicated kulmba-kulmba as a gecko/small-house-lizard noun. Rule 341 uses the whole gecko head only; free kulmba, productive reduplication, size, house habitat, source, possession, and events remain closed.",
    "kurriyala": "Dictionary yaml lines 16420-16442 distinguish homonymous kurriyala grunter fish and carpet-snake/python records. Patz lines 719, 4457, and 4460 add myth/death/place, belt material, and fleeing contexts. Rule 341 selects only the snake noun as bare O; fish, python/species resolution, myth/death/burial/place, material/use, fleeing/behavior, source, possession, case, and events remain closed.",
    "ngawurr-ngawun": "Dictionary yaml lines 22956-22970 give exact partially reduplicated ngawurr-ngawun as a freshwater-crocodile noun; Patz line 7366 contains it only in a bibliography title. Rule 341 uses the whole crocodile head only; free base/productive process, freshwater habitat, bibliography/title import, source, possession, and events remain closed.",
    "ngumbul": "Dictionary yaml lines 23585-23605 contain two exact noun-typed fauna-reptile ngumbul snake records. Rule 341 uses conservative ngumbul snake reference without collapsing records or adding sea habitat, species identity, danger, source, possession, or events.",
}

SUPPORT_EVIDENCE = (
    "Patz line 1476 includes fauna among noun referents. Lines 2577-2584 source bare nominative ngali, ngaliny, "
    "yubal, yurra, and first-plural-exclusive nganjin; lines 2834-2847 source Yalanji yaluy 'here' and yinyay "
    "'there'. Examples at 2021-2024 and 2568-2571 attest nyaji-ny 'see-PAST'; 3160-3162 define past -ny; and "
    "4256-4265 license nominative pronoun A with bare absolutive O in sensory perception. Dictionary examples "
    "23876-23883 and 23968-23976 contain running nyajin. Fresh Patz target search found junbirr-anka in dative "
    "case, kurriyala in myth/material/ablative contexts, and ngawurr-ngawun in a bibliography title; these verify "
    "lexical forms or delimit exclusions but do not license copying their source events. Rule 341 combines direct "
    "dictionary noun records with independently sourced constructional evidence."
)

TARGET_ORDER = ["banamu", "binju", "dukul-mukul", "jirabay", "junbirr", "kabuljaka", "kulmba-kulmba", "kurriyala", "ngawurr-ngawun", "ngumbul"]
TARGET_LABELS = {"banamu": "banamu snake", "binju": "binju snake", "dukul-mukul": "dukul-mukul lizard", "jirabay": "jirabay lizard", "junbirr": "junbirr lizard", "kabuljaka": "kabuljaka snake", "kulmba-kulmba": "kulmba-kulmba gecko", "kurriyala": "kurriyala snake", "ngawurr-ngawun": "ngawurr-ngawun crocodile", "ngumbul": "ngumbul snake"}
TARGET_GLOSSES = {"banamu": "banamu.snake", "binju": "binju.snake", "dukul-mukul": "dukul-mukul.lizard", "jirabay": "jirabay.lizard", "junbirr": "junbirr.lizard", "kabuljaka": "kabuljaka.snake", "kulmba-kulmba": "kulmba-kulmba.gecko", "kurriyala": "kurriyala.snake", "ngawurr-ngawun": "ngawurr-ngawun.crocodile", "ngumbul": "ngumbul.snake"}
TARGET_CONFIDENCE = {"banamu": "0.90", "binju": "0.83", "dukul-mukul": "0.89", "jirabay": "0.89", "junbirr": "0.89", "kabuljaka": "0.86", "kulmba-kulmba": "0.91", "kurriyala": "0.83", "ngawurr-ngawun": "0.89", "ngumbul": "0.88"}
EXPECTED_TARGET_COVERAGE = {"banamu": 15, "binju": 15, "dukul-mukul": 15, "jirabay": 15, "junbirr": 15, "kabuljaka": 15, "kulmba-kulmba": 15, "kurriyala": 15, "ngawurr-ngawun": 15, "ngumbul": 15}
EXPECTED_SUPPORT_COVERAGE = {"ngali": 643, "ngaliny": 585, "yubal": 595, "yurra": 580, "nganjin": 308, "ngana": 1115, "yaluy": 4412, "yinyay": 4574, "nyajin": 2100}
FRAME_SPECS = [
    ("ngali", "yinyay", "We two, not you, saw", "there", "1du.excl"),
    ("ngaliny", "yaluy", "You and I saw", "here", "1du.incl"),
    ("yubal", "yinyay", "You two saw", "there", "2du"),
    ("yurra", "yaluy", "You all saw", "here", "2pl"),
    ("nganjin", "yinyay", "We, not you, saw", "there", "1pl.excl"),
]

DENY_KUKU = {"ngayu", "yundu", "nyulu", "yulu", "bula", "jana", "iana", "ngana", "dukul", "mukul", "kabul", "kulmba", "ngawurr", "yalay", "yala", "yanyu", "yinya", "nyajil", "nyaji-l", "nyaji-nka", "nyaji-l-nyaji", "milka", "baykal", "jalngkay"}
DENY_ENGLISH = ("freshwater habitat", "sea habitat", "water habitat", "wrong marriage", "tribal law", "poorly made", "poorly cooked", "poison", "danger", "light belly", "black", "reddish", "striped", "zebra", "big head", "larger", "blue-tongue", "leaf", "grass", "wet season", "house", "grunter", "fish", "python", "myth", "death", "burial", "place", "belt", "material", "chicken", "flee", "bibliography", "title", "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, "We two, not you, saw the banamu snake there.", "Ngali banamu yinyay nyajin.", "ngali banamu yinyay nyajin | 1du.excl.NOM banamu.snake there see.PST", "r341_1du_excl_there_reptile_b_saw_banamu", ["ngali", "banamu", "yinyay", "nyajin"]),
    row(2, "We two, not you, saw the binju snake there.", "Ngali binju yinyay nyajin.", "ngali binju yinyay nyajin | 1du.excl.NOM binju.snake there see.PST", "r341_1du_excl_there_reptile_b_saw_binju", ["ngali", "binju", "yinyay", "nyajin"]),
    row(3, "We two, not you, saw the dukul-mukul lizard there.", "Ngali dukul-mukul yinyay nyajin.", "ngali dukul-mukul yinyay nyajin | 1du.excl.NOM dukul-mukul.lizard there see.PST", "r341_1du_excl_there_reptile_b_saw_dukul_mukul", ["ngali", "dukul-mukul", "yinyay", "nyajin"]),
    row(4, "We two, not you, saw the jirabay lizard there.", "Ngali jirabay yinyay nyajin.", "ngali jirabay yinyay nyajin | 1du.excl.NOM jirabay.lizard there see.PST", "r341_1du_excl_there_reptile_b_saw_jirabay", ["ngali", "jirabay", "yinyay", "nyajin"]),
    row(5, "We two, not you, saw the junbirr lizard there.", "Ngali junbirr yinyay nyajin.", "ngali junbirr yinyay nyajin | 1du.excl.NOM junbirr.lizard there see.PST", "r341_1du_excl_there_reptile_b_saw_junbirr", ["ngali", "junbirr", "yinyay", "nyajin"]),
    row(6, "We two, not you, saw the kabuljaka snake there.", "Ngali kabuljaka yinyay nyajin.", "ngali kabuljaka yinyay nyajin | 1du.excl.NOM kabuljaka.snake there see.PST", "r341_1du_excl_there_reptile_b_saw_kabuljaka", ["ngali", "kabuljaka", "yinyay", "nyajin"]),
    row(7, "We two, not you, saw the kulmba-kulmba gecko there.", "Ngali kulmba-kulmba yinyay nyajin.", "ngali kulmba-kulmba yinyay nyajin | 1du.excl.NOM kulmba-kulmba.gecko there see.PST", "r341_1du_excl_there_reptile_b_saw_kulmba_kulmba", ["ngali", "kulmba-kulmba", "yinyay", "nyajin"]),
    row(8, "We two, not you, saw the kurriyala snake there.", "Ngali kurriyala yinyay nyajin.", "ngali kurriyala yinyay nyajin | 1du.excl.NOM kurriyala.snake there see.PST", "r341_1du_excl_there_reptile_b_saw_kurriyala", ["ngali", "kurriyala", "yinyay", "nyajin"]),
    row(9, "We two, not you, saw the ngawurr-ngawun crocodile there.", "Ngali ngawurr-ngawun yinyay nyajin.", "ngali ngawurr-ngawun yinyay nyajin | 1du.excl.NOM ngawurr-ngawun.crocodile there see.PST", "r341_1du_excl_there_reptile_b_saw_ngawurr_ngawun", ["ngali", "ngawurr-ngawun", "yinyay", "nyajin"]),
    row(10, "We two, not you, saw the ngumbul snake there.", "Ngali ngumbul yinyay nyajin.", "ngali ngumbul yinyay nyajin | 1du.excl.NOM ngumbul.snake there see.PST", "r341_1du_excl_there_reptile_b_saw_ngumbul", ["ngali", "ngumbul", "yinyay", "nyajin"]),
    row(11, "You and I saw the banamu snake here.", "Ngaliny banamu yaluy nyajin.", "ngaliny banamu yaluy nyajin | 1du.incl.NOM banamu.snake here see.PST", "r341_1du_incl_here_reptile_b_saw_banamu", ["ngaliny", "banamu", "yaluy", "nyajin"]),
    row(12, "You and I saw the binju snake here.", "Ngaliny binju yaluy nyajin.", "ngaliny binju yaluy nyajin | 1du.incl.NOM binju.snake here see.PST", "r341_1du_incl_here_reptile_b_saw_binju", ["ngaliny", "binju", "yaluy", "nyajin"]),
    row(13, "You and I saw the dukul-mukul lizard here.", "Ngaliny dukul-mukul yaluy nyajin.", "ngaliny dukul-mukul yaluy nyajin | 1du.incl.NOM dukul-mukul.lizard here see.PST", "r341_1du_incl_here_reptile_b_saw_dukul_mukul", ["ngaliny", "dukul-mukul", "yaluy", "nyajin"]),
    row(14, "You and I saw the jirabay lizard here.", "Ngaliny jirabay yaluy nyajin.", "ngaliny jirabay yaluy nyajin | 1du.incl.NOM jirabay.lizard here see.PST", "r341_1du_incl_here_reptile_b_saw_jirabay", ["ngaliny", "jirabay", "yaluy", "nyajin"]),
    row(15, "You and I saw the junbirr lizard here.", "Ngaliny junbirr yaluy nyajin.", "ngaliny junbirr yaluy nyajin | 1du.incl.NOM junbirr.lizard here see.PST", "r341_1du_incl_here_reptile_b_saw_junbirr", ["ngaliny", "junbirr", "yaluy", "nyajin"]),
    row(16, "You and I saw the kabuljaka snake here.", "Ngaliny kabuljaka yaluy nyajin.", "ngaliny kabuljaka yaluy nyajin | 1du.incl.NOM kabuljaka.snake here see.PST", "r341_1du_incl_here_reptile_b_saw_kabuljaka", ["ngaliny", "kabuljaka", "yaluy", "nyajin"]),
    row(17, "You and I saw the kulmba-kulmba gecko here.", "Ngaliny kulmba-kulmba yaluy nyajin.", "ngaliny kulmba-kulmba yaluy nyajin | 1du.incl.NOM kulmba-kulmba.gecko here see.PST", "r341_1du_incl_here_reptile_b_saw_kulmba_kulmba", ["ngaliny", "kulmba-kulmba", "yaluy", "nyajin"]),
    row(18, "You and I saw the kurriyala snake here.", "Ngaliny kurriyala yaluy nyajin.", "ngaliny kurriyala yaluy nyajin | 1du.incl.NOM kurriyala.snake here see.PST", "r341_1du_incl_here_reptile_b_saw_kurriyala", ["ngaliny", "kurriyala", "yaluy", "nyajin"]),
    row(19, "You and I saw the ngawurr-ngawun crocodile here.", "Ngaliny ngawurr-ngawun yaluy nyajin.", "ngaliny ngawurr-ngawun yaluy nyajin | 1du.incl.NOM ngawurr-ngawun.crocodile here see.PST", "r341_1du_incl_here_reptile_b_saw_ngawurr_ngawun", ["ngaliny", "ngawurr-ngawun", "yaluy", "nyajin"]),
    row(20, "You and I saw the ngumbul snake here.", "Ngaliny ngumbul yaluy nyajin.", "ngaliny ngumbul yaluy nyajin | 1du.incl.NOM ngumbul.snake here see.PST", "r341_1du_incl_here_reptile_b_saw_ngumbul", ["ngaliny", "ngumbul", "yaluy", "nyajin"]),
    row(21, "You two saw the banamu snake there.", "Yubal banamu yinyay nyajin.", "yubal banamu yinyay nyajin | 2du.NOM banamu.snake there see.PST", "r341_2du_there_reptile_b_saw_banamu", ["yubal", "banamu", "yinyay", "nyajin"]),
    row(22, "You two saw the binju snake there.", "Yubal binju yinyay nyajin.", "yubal binju yinyay nyajin | 2du.NOM binju.snake there see.PST", "r341_2du_there_reptile_b_saw_binju", ["yubal", "binju", "yinyay", "nyajin"]),
    row(23, "You two saw the dukul-mukul lizard there.", "Yubal dukul-mukul yinyay nyajin.", "yubal dukul-mukul yinyay nyajin | 2du.NOM dukul-mukul.lizard there see.PST", "r341_2du_there_reptile_b_saw_dukul_mukul", ["yubal", "dukul-mukul", "yinyay", "nyajin"]),
    row(24, "You two saw the jirabay lizard there.", "Yubal jirabay yinyay nyajin.", "yubal jirabay yinyay nyajin | 2du.NOM jirabay.lizard there see.PST", "r341_2du_there_reptile_b_saw_jirabay", ["yubal", "jirabay", "yinyay", "nyajin"]),
    row(25, "You two saw the junbirr lizard there.", "Yubal junbirr yinyay nyajin.", "yubal junbirr yinyay nyajin | 2du.NOM junbirr.lizard there see.PST", "r341_2du_there_reptile_b_saw_junbirr", ["yubal", "junbirr", "yinyay", "nyajin"]),
    row(26, "You two saw the kabuljaka snake there.", "Yubal kabuljaka yinyay nyajin.", "yubal kabuljaka yinyay nyajin | 2du.NOM kabuljaka.snake there see.PST", "r341_2du_there_reptile_b_saw_kabuljaka", ["yubal", "kabuljaka", "yinyay", "nyajin"]),
    row(27, "You two saw the kulmba-kulmba gecko there.", "Yubal kulmba-kulmba yinyay nyajin.", "yubal kulmba-kulmba yinyay nyajin | 2du.NOM kulmba-kulmba.gecko there see.PST", "r341_2du_there_reptile_b_saw_kulmba_kulmba", ["yubal", "kulmba-kulmba", "yinyay", "nyajin"]),
    row(28, "You two saw the kurriyala snake there.", "Yubal kurriyala yinyay nyajin.", "yubal kurriyala yinyay nyajin | 2du.NOM kurriyala.snake there see.PST", "r341_2du_there_reptile_b_saw_kurriyala", ["yubal", "kurriyala", "yinyay", "nyajin"]),
    row(29, "You two saw the ngawurr-ngawun crocodile there.", "Yubal ngawurr-ngawun yinyay nyajin.", "yubal ngawurr-ngawun yinyay nyajin | 2du.NOM ngawurr-ngawun.crocodile there see.PST", "r341_2du_there_reptile_b_saw_ngawurr_ngawun", ["yubal", "ngawurr-ngawun", "yinyay", "nyajin"]),
    row(30, "You two saw the ngumbul snake there.", "Yubal ngumbul yinyay nyajin.", "yubal ngumbul yinyay nyajin | 2du.NOM ngumbul.snake there see.PST", "r341_2du_there_reptile_b_saw_ngumbul", ["yubal", "ngumbul", "yinyay", "nyajin"]),
    row(31, "You all saw the banamu snake here.", "Yurra banamu yaluy nyajin.", "yurra banamu yaluy nyajin | 2pl.NOM banamu.snake here see.PST", "r341_2pl_here_reptile_b_saw_banamu", ["yurra", "banamu", "yaluy", "nyajin"]),
    row(32, "You all saw the binju snake here.", "Yurra binju yaluy nyajin.", "yurra binju yaluy nyajin | 2pl.NOM binju.snake here see.PST", "r341_2pl_here_reptile_b_saw_binju", ["yurra", "binju", "yaluy", "nyajin"]),
    row(33, "You all saw the dukul-mukul lizard here.", "Yurra dukul-mukul yaluy nyajin.", "yurra dukul-mukul yaluy nyajin | 2pl.NOM dukul-mukul.lizard here see.PST", "r341_2pl_here_reptile_b_saw_dukul_mukul", ["yurra", "dukul-mukul", "yaluy", "nyajin"]),
    row(34, "You all saw the jirabay lizard here.", "Yurra jirabay yaluy nyajin.", "yurra jirabay yaluy nyajin | 2pl.NOM jirabay.lizard here see.PST", "r341_2pl_here_reptile_b_saw_jirabay", ["yurra", "jirabay", "yaluy", "nyajin"]),
    row(35, "You all saw the junbirr lizard here.", "Yurra junbirr yaluy nyajin.", "yurra junbirr yaluy nyajin | 2pl.NOM junbirr.lizard here see.PST", "r341_2pl_here_reptile_b_saw_junbirr", ["yurra", "junbirr", "yaluy", "nyajin"]),
    row(36, "You all saw the kabuljaka snake here.", "Yurra kabuljaka yaluy nyajin.", "yurra kabuljaka yaluy nyajin | 2pl.NOM kabuljaka.snake here see.PST", "r341_2pl_here_reptile_b_saw_kabuljaka", ["yurra", "kabuljaka", "yaluy", "nyajin"]),
    row(37, "You all saw the kulmba-kulmba gecko here.", "Yurra kulmba-kulmba yaluy nyajin.", "yurra kulmba-kulmba yaluy nyajin | 2pl.NOM kulmba-kulmba.gecko here see.PST", "r341_2pl_here_reptile_b_saw_kulmba_kulmba", ["yurra", "kulmba-kulmba", "yaluy", "nyajin"]),
    row(38, "You all saw the kurriyala snake here.", "Yurra kurriyala yaluy nyajin.", "yurra kurriyala yaluy nyajin | 2pl.NOM kurriyala.snake here see.PST", "r341_2pl_here_reptile_b_saw_kurriyala", ["yurra", "kurriyala", "yaluy", "nyajin"]),
    row(39, "You all saw the ngawurr-ngawun crocodile here.", "Yurra ngawurr-ngawun yaluy nyajin.", "yurra ngawurr-ngawun yaluy nyajin | 2pl.NOM ngawurr-ngawun.crocodile here see.PST", "r341_2pl_here_reptile_b_saw_ngawurr_ngawun", ["yurra", "ngawurr-ngawun", "yaluy", "nyajin"]),
    row(40, "You all saw the ngumbul snake here.", "Yurra ngumbul yaluy nyajin.", "yurra ngumbul yaluy nyajin | 2pl.NOM ngumbul.snake here see.PST", "r341_2pl_here_reptile_b_saw_ngumbul", ["yurra", "ngumbul", "yaluy", "nyajin"]),
    row(41, "We, not you, saw the banamu snake there.", "Nganjin banamu yinyay nyajin.", "nganjin banamu yinyay nyajin | 1pl.excl.NOM banamu.snake there see.PST", "r341_1pl_excl_there_reptile_b_saw_banamu", ["nganjin", "banamu", "yinyay", "nyajin"]),
    row(42, "We, not you, saw the binju snake there.", "Nganjin binju yinyay nyajin.", "nganjin binju yinyay nyajin | 1pl.excl.NOM binju.snake there see.PST", "r341_1pl_excl_there_reptile_b_saw_binju", ["nganjin", "binju", "yinyay", "nyajin"]),
    row(43, "We, not you, saw the dukul-mukul lizard there.", "Nganjin dukul-mukul yinyay nyajin.", "nganjin dukul-mukul yinyay nyajin | 1pl.excl.NOM dukul-mukul.lizard there see.PST", "r341_1pl_excl_there_reptile_b_saw_dukul_mukul", ["nganjin", "dukul-mukul", "yinyay", "nyajin"]),
    row(44, "We, not you, saw the jirabay lizard there.", "Nganjin jirabay yinyay nyajin.", "nganjin jirabay yinyay nyajin | 1pl.excl.NOM jirabay.lizard there see.PST", "r341_1pl_excl_there_reptile_b_saw_jirabay", ["nganjin", "jirabay", "yinyay", "nyajin"]),
    row(45, "We, not you, saw the junbirr lizard there.", "Nganjin junbirr yinyay nyajin.", "nganjin junbirr yinyay nyajin | 1pl.excl.NOM junbirr.lizard there see.PST", "r341_1pl_excl_there_reptile_b_saw_junbirr", ["nganjin", "junbirr", "yinyay", "nyajin"]),
    row(46, "We, not you, saw the kabuljaka snake there.", "Nganjin kabuljaka yinyay nyajin.", "nganjin kabuljaka yinyay nyajin | 1pl.excl.NOM kabuljaka.snake there see.PST", "r341_1pl_excl_there_reptile_b_saw_kabuljaka", ["nganjin", "kabuljaka", "yinyay", "nyajin"]),
    row(47, "We, not you, saw the kulmba-kulmba gecko there.", "Nganjin kulmba-kulmba yinyay nyajin.", "nganjin kulmba-kulmba yinyay nyajin | 1pl.excl.NOM kulmba-kulmba.gecko there see.PST", "r341_1pl_excl_there_reptile_b_saw_kulmba_kulmba", ["nganjin", "kulmba-kulmba", "yinyay", "nyajin"]),
    row(48, "We, not you, saw the kurriyala snake there.", "Nganjin kurriyala yinyay nyajin.", "nganjin kurriyala yinyay nyajin | 1pl.excl.NOM kurriyala.snake there see.PST", "r341_1pl_excl_there_reptile_b_saw_kurriyala", ["nganjin", "kurriyala", "yinyay", "nyajin"]),
    row(49, "We, not you, saw the ngawurr-ngawun crocodile there.", "Nganjin ngawurr-ngawun yinyay nyajin.", "nganjin ngawurr-ngawun yinyay nyajin | 1pl.excl.NOM ngawurr-ngawun.crocodile there see.PST", "r341_1pl_excl_there_reptile_b_saw_ngawurr_ngawun", ["nganjin", "ngawurr-ngawun", "yinyay", "nyajin"]),
    row(50, "We, not you, saw the ngumbul snake there.", "Nganjin ngumbul yinyay nyajin.", "nganjin ngumbul yinyay nyajin | 1pl.excl.NOM ngumbul.snake there see.PST", "r341_1pl_excl_there_reptile_b_saw_ngumbul", ["nganjin", "ngumbul", "yinyay", "nyajin"]),
]


def scan_static() -> list[str]:
    issues: list[str] = []
    if len(ROWS) != 50: issues.append(f"row count {len(ROWS)} != 50")
    if [r[0] for r in ROWS] != list(range(1, 51)): issues.append("sequence is not 1..50")
    if len({r[1] for r in ROWS}) != 50: issues.append("duplicate English surface")
    if len({r[2] for r 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]
        ek=f"{pronoun.capitalize()} {target} {demo} nyajin."; ee=f"{prefix} the {TARGET_LABELS[target]} {location}."; ea=f"{pronoun} {target} {demo} nyajin | {person}.NOM {TARGET_GLOSSES[target]} {location} see.PST"
        if loans: issues.append(f"{seq}: loans {loans}")
        denied=sorted({w for w in DENY_KUKU if re.search(rf"(^|\s){re.escape(w)}([\s\.]|$)",kuku.lower())})
        if denied: issues.append(f"{seq}: denied Kuku {denied}")
        de=[x for x in DENY_ENGLISH if re.search(rf"\b{re.escape(x)}\b",english.lower())]
        if de: issues.append(f"{seq}: English drift {de}")
        if kuku!=ek: issues.append(f"{seq}: Kuku mismatch")
        if english!=ee: issues.append(f"{seq}: English mismatch")
        if analysis!=ea: 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("r341_"): 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:
    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")
    tc=count_words(db,TARGET_ORDER); sc=count_words(db,list(EXPECTED_SUPPORT_COVERAGE))
    if tc!=EXPECTED_TARGET_COVERAGE: raise SystemExit(f"target coverage changed: {tc}")
    if sc!=EXPECTED_SUPPORT_COVERAGE: raise SystemExit(f"support coverage changed: {sc}")
    selected=[]
    selected_specs=[("ngali","yinyay"),("ngaliny","yaluy"),("yubal","yinyay"),("yurra","yaluy"),("nganjin","yinyay")]
    for p,de in selected_specs:
        for t in TARGET_ORDER:
            surf=f"{p.capitalize()} {t} {de} nyajin."
            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.label,s.seq",(surf,)).fetchall()
            if hits: selected.append((surf,hits))
    if selected: raise SystemExit(f"selected collisions: {selected}")
    inverse_mismatches=[]
    inverse_specs=[("ngali","yaluy"),("ngaliny","yinyay"),("yubal","yaluy"),("yurra","yinyay"),("nganjin","yaluy")]
    for band,(p,de) in enumerate(inverse_specs):
        for offset,t in enumerate(TARGET_ORDER):
            surf=f"{p.capitalize()} {t} {de} nyajin."
            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.label,s.seq",(surf,)).fetchall()
            expected=[("batch-382",band*10+offset+1)]
            if hits!=expected: inverse_mismatches.append((surf,hits,expected))
    if inverse_mismatches: raise SystemExit(f"inverse complement changed: {inverse_mismatches}")
    verified,words=db.execute("SELECT COUNT(*),SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1) FROM sentences WHERE status IN ('accepted','revised')").fetchone()
    if (verified,words)!=(19197,132147): raise SystemExit(f"baseline changed {verified}/{words}")
    notes=("COMPLEMENTARY REPTILE LEXEME-SET-B NON-SINGULAR PAST PERCEPTION AFTER RULE 340 (Rule 341). 50 under-review rows over banamu, binju, dukul-mukul, jirabay, junbirr, kabuljaka, kulmba-kulmba, kurriyala, ngawurr-ngawun, and ngumbul. The selected orientation is empty and exactly complements Batch 382. Duplicate records, binju polysemy, kurriyala fish/snake homonymy and source contexts, whole echo/reduplicated heads, properties, habitat, poison/danger, source, possession, case, and events remain closed. Two-here/three-there completes the paradigm and changes current deictic gap 162->172; lower-gap inverse duplicates Batch 382.")
    cur=db.execute("INSERT INTO batches(label,cheatsheet_version,guide_version,notes,created_at) VALUES(?,?,?,?,?)",(LABEL,"Rule 341 under review","operator-guide-2026-07-10",notes,NOW));bid=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(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",[(bid,seq,en,ku,an,fr,ti,wo,lo,ev,"under_review",co,"project_approved_synthetic_pending_elder_verification","codex-main",NOW,NOW) for seq,en,ku,an,fr,ti,wo,lo,ev,co in ROWS])
    events=[
        ("source","source-readback","Reread every exact target record, including binju polysemy and kurriyala fish/snake homonymy; Patz junbirr/kurriyala/ngawurr-ngawun hits; fauna/non-singular-pronoun/local/past/perception passages; and dictionary running nyajin."),
        ("planning","record-sense-audit","Recorded duplicate banamu/kabuljaka/ngumbul records, binju polysemy, kurriyala fish/snake homonymy and source contexts, whole dukul-mukul/kulmba-kulmba/ngawurr-ngawun heads, and all property/habitat/danger/event exclusions."),
        ("planning","construction-gap-audit","Exact matrix has 50 occupied inverse cells, all exactly Batch 382 / Rule 340, and 50 empty selected complementary cells."),
        ("planning","deictic-balance-audit","Before banking yaluy=4412 and yinyay=4574, gap 162; selected two-here/three-there projects 172; lower-gap inverse projects 152 but exactly duplicates Batch 382."),
        ("preflight","coverage-audit",f"Coverage before banking: targets={tc}; support={sc}."),
        ("preflight","duplicate-preflight","Selected 50 surfaces are internally unique and collision-free; inverse 50 map one-for-one to Batch 382 and are excluded."),
        ("preflight","static-guard-pass","50 explicit complementary rows; exact number/clusivity; conservative labels; no Batch 382 duplication, record/polysemy/homonym/component/source-context/property/habitat/danger/event, loan, case, or support drift."),
    ]
    for phase,etype,detail in events: record_event(db,batch_label=LABEL,phase=phase,event_type=etype,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 341 rows under_review; verified remains {verified}; words {words}.",command="python3 batch_scripts/bank_383.py",output_excerpt="50 under_review",artifact_path=PROCESS_LOG,created_at=NOW)
    db.commit();print("banked batch-383: 50 rows under_review");return 0


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





