#!/usr/bin/env python3
"""Bank batch-347: Rule 305 complementary visible flora/tree non-singular nonpast 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-347"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-347-complementary-flora-tree-nonsingular-nonpast-perception-after-rule304-process.md"

TARGET_EVIDENCE = {
    "bujabay": "Dictionary yaml lines 3572-3577 give bujabay as noun 'tree', a species with edible fruit needing leaching in water. Rule 305 selects visible bujabay-tree reference only and leaves fruit, edibility, leaching, water, and preparation rows closed.",
    "jingajalka": "Dictionary yaml lines 9465-9470 give jingajalka as noun 'tree' with source prose about fruit, bark baskets, cooking, hot stones, and bones. Rule 305 selects visible jingajalka-tree reference only and leaves all use, food, bark, fire, cooking, and death/bone source prose closed.",
    "jirimandi": "Dictionary yaml lines 9765-9770 give jirimandi as noun 'tree' with definition 'coconut'. Rule 305 selects visible jirimandi/coconut-tree reference only and leaves coconut food, introduced plant history, and use rows closed.",
    "julbal": "Dictionary yaml lines 10479-10494 give julbal as noun 'tree', with small edible green apple fruit and wet-season ripening source prose. Rule 305 selects visible julbal-tree reference only and leaves fruit, food, season, and ripening rows closed.",
    "jungka": "Dictionary yaml lines 10893-10906 give jungka as noun 'tree', wild cherry tree and fruit. Rule 305 selects visible jungka/wild-cherry-tree reference only and leaves fruit, food, gathering, and ecology rows closed.",
    "karranda": "Dictionary yaml lines 13556-13567 give karranda as noun 'tree', species of tree with English name unknown. Rule 305 selects visible karranda-tree reference only.",
    "karrandal": "Dictionary yaml lines 13568-13579 give karrandal as noun 'tree' with source prose about white-under leaves and crushed leaves good for boils. Rule 305 selects visible karrandal-tree reference only and leaves leaves, colour, crushing, boil, remedy, medicine, and cooking-leaf translation drift closed.",
    "kawarr": "Dictionary yaml lines 13872-13894 give kawarr as noun 'tree' / 'bloodwood tree'. Rule 305 selects visible kawarr/bloodwood-tree reference only and leaves timber, wood, sap, firewood, and source-use rows closed.",
    "marril": "Dictionary yaml lines 18574-18597 give marril as noun 'tree' / 'mangrove', including ti tree and mangrove source prose with hard wood used for oars. Rule 305 selects visible marril/ti-tree reference only and leaves mangrove expansion, seed, hardwood, oar, wood, water, and use rows closed.",
    "ngurrkul": "Dictionary yaml lines 23921-23942 give ngurrkul as noun 'tree', species with edible fig / edible fruit in deep scrub. Rule 305 selects visible ngurrkul/fig-tree reference only and leaves fruit, edible, deep-scrub, food, and ecology rows closed.",
}

SUPPORT_EVIDENCE = (
    "Living grammar pronoun table lines 2577-2582 source bare nominative ngali, ngaliny, yubal, yurra, and ngana, "
    "with non-nominative case forms separated in the same table; lines 2674-2684 discuss non-singular roots and "
    "state ngali is dual exclusive, ngaliny dual inclusive, and ngana plural inclusive; demonstrative lines "
    "2834-2845 source yaluy 'here' and yinyay 'there'; verb lines 3043-3051 source nyaji-l and surface nyajil as "
    "nonpast perception. Rule 305 uses only bare support forms."
)

TARGET_ORDER = ["bujabay", "jingajalka", "jirimandi", "julbal", "jungka", "karranda", "karrandal", "kawarr", "marril", "ngurrkul"]
TARGET_LABELS = {
    "bujabay": "bujabay tree",
    "jingajalka": "jingajalka tree",
    "jirimandi": "jirimandi coconut tree",
    "julbal": "julbal tree",
    "jungka": "jungka wild cherry tree",
    "karranda": "karranda tree",
    "karrandal": "karrandal tree",
    "kawarr": "kawarr bloodwood tree",
    "marril": "marril ti tree",
    "ngurrkul": "ngurrkul fig tree",
}
FRAME_SPECS = [
    ("ngali", "yaluy"),
    ("ngaliny", "yinyay"),
    ("yubal", "yaluy"),
    ("yurra", "yinyay"),
    ("ngana", "yaluy"),
]

DENY_KUKU = {
    "ngalingan", "ngalinyan", "yubalan", "yurrangan", "nganangan", "nganjinan",
    "ngalininy", "ngalinyiny", "yubaliny", "yurraniny", "ngananiny", "nganjininy",
    "ngalinka", "ngalinyanka", "yubalanka", "yurranka", "ngananka", "nganjinanka",
    "ngalinda", "ngalinyanda", "yubalanda", "yurranda", "ngananda", "nganjinanda",
    "ngalindamuny", "ngalinyandamuny", "yubalandamuny", "yurrandamuny", "nganandamuny",
    "nganjinandamuny", "ngalinji", "ngalinyanji", "yubalanji", "yurranji", "ngananji",
    "nganjinanji", "ngalinga", "ngalinyanga", "yubalanga", "yurranga", "ngananga",
    "nganjinanga", "nganjin",
    "yalungku", "yaluyngku", "yinyangka", "yinyayngka", "yalamuny", "yinyamuny",
    "nyajin", "nyaji-ny", "nyaji-nka", "nyaji-l-nyaji", "milka", "baykal", "jalngkay",
}
DENY_ENGLISH = (
    "fruit", "seed", "seeds", "edible", "food", "leach", "leached", "leaching", "soak", "soaked", "soaking",
    "water", "preparation", "prepare", "bark", "basket", "baskets", "cook", "cooking", "stone", "stones",
    "bone", "bones", "dead", "death", "blind", "old woman", "season", "wet season", "ripe", "ripening",
    "leaf", "leaves", "white", "crush", "crushed", "boil", "boils", "remedy", "medicine", "hardwood",
    "oar", "oars", "mangrove", "timber", "wood", "firewood", "scrub", "ecology", "place", "story",
    "use", "used", "gather", "gathering",
)


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 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]
    evidence = f"{TARGET_EVIDENCE[target]} {SUPPORT_EVIDENCE}"
    return (seq, english, kuku, analysis, frame, 3, json.dumps(words, ensure_ascii=False), json.dumps([], ensure_ascii=False), evidence, "0.86")


ROWS = [
    row(1, "We two, not you, see the bujabay tree here.", "Ngali bujabay yaluy nyajil.", "ngali bujabay yaluy nyajil | 1du.EXCL.NOM bujabay.tree here see.NPST", "r305_1du_excl_here_flora_see_bujabay", ["ngali", "bujabay", "yaluy", "nyajil"]),
    row(2, "We two, not you, see the jingajalka tree here.", "Ngali jingajalka yaluy nyajil.", "ngali jingajalka yaluy nyajil | 1du.EXCL.NOM jingajalka.tree here see.NPST", "r305_1du_excl_here_flora_see_jingajalka", ["ngali", "jingajalka", "yaluy", "nyajil"]),
    row(3, "We two, not you, see the jirimandi coconut tree here.", "Ngali jirimandi yaluy nyajil.", "ngali jirimandi yaluy nyajil | 1du.EXCL.NOM jirimandi.coconut.tree here see.NPST", "r305_1du_excl_here_flora_see_jirimandi", ["ngali", "jirimandi", "yaluy", "nyajil"]),
    row(4, "We two, not you, see the julbal tree here.", "Ngali julbal yaluy nyajil.", "ngali julbal yaluy nyajil | 1du.EXCL.NOM julbal.tree here see.NPST", "r305_1du_excl_here_flora_see_julbal", ["ngali", "julbal", "yaluy", "nyajil"]),
    row(5, "We two, not you, see the jungka wild cherry tree here.", "Ngali jungka yaluy nyajil.", "ngali jungka yaluy nyajil | 1du.EXCL.NOM jungka.wild.cherry.tree here see.NPST", "r305_1du_excl_here_flora_see_jungka", ["ngali", "jungka", "yaluy", "nyajil"]),
    row(6, "We two, not you, see the karranda tree here.", "Ngali karranda yaluy nyajil.", "ngali karranda yaluy nyajil | 1du.EXCL.NOM karranda.tree here see.NPST", "r305_1du_excl_here_flora_see_karranda", ["ngali", "karranda", "yaluy", "nyajil"]),
    row(7, "We two, not you, see the karrandal tree here.", "Ngali karrandal yaluy nyajil.", "ngali karrandal yaluy nyajil | 1du.EXCL.NOM karrandal.tree here see.NPST", "r305_1du_excl_here_flora_see_karrandal", ["ngali", "karrandal", "yaluy", "nyajil"]),
    row(8, "We two, not you, see the kawarr bloodwood tree here.", "Ngali kawarr yaluy nyajil.", "ngali kawarr yaluy nyajil | 1du.EXCL.NOM kawarr.bloodwood.tree here see.NPST", "r305_1du_excl_here_flora_see_kawarr", ["ngali", "kawarr", "yaluy", "nyajil"]),
    row(9, "We two, not you, see the marril ti tree here.", "Ngali marril yaluy nyajil.", "ngali marril yaluy nyajil | 1du.EXCL.NOM marril.ti.tree here see.NPST", "r305_1du_excl_here_flora_see_marril", ["ngali", "marril", "yaluy", "nyajil"]),
    row(10, "We two, not you, see the ngurrkul fig tree here.", "Ngali ngurrkul yaluy nyajil.", "ngali ngurrkul yaluy nyajil | 1du.EXCL.NOM ngurrkul.fig.tree here see.NPST", "r305_1du_excl_here_flora_see_ngurrkul", ["ngali", "ngurrkul", "yaluy", "nyajil"]),
    row(11, "You and I see the bujabay tree there.", "Ngaliny bujabay yinyay nyajil.", "ngaliny bujabay yinyay nyajil | 1du.INCL.NOM bujabay.tree there see.NPST", "r305_1du_incl_there_flora_see_bujabay", ["ngaliny", "bujabay", "yinyay", "nyajil"]),
    row(12, "You and I see the jingajalka tree there.", "Ngaliny jingajalka yinyay nyajil.", "ngaliny jingajalka yinyay nyajil | 1du.INCL.NOM jingajalka.tree there see.NPST", "r305_1du_incl_there_flora_see_jingajalka", ["ngaliny", "jingajalka", "yinyay", "nyajil"]),
    row(13, "You and I see the jirimandi coconut tree there.", "Ngaliny jirimandi yinyay nyajil.", "ngaliny jirimandi yinyay nyajil | 1du.INCL.NOM jirimandi.coconut.tree there see.NPST", "r305_1du_incl_there_flora_see_jirimandi", ["ngaliny", "jirimandi", "yinyay", "nyajil"]),
    row(14, "You and I see the julbal tree there.", "Ngaliny julbal yinyay nyajil.", "ngaliny julbal yinyay nyajil | 1du.INCL.NOM julbal.tree there see.NPST", "r305_1du_incl_there_flora_see_julbal", ["ngaliny", "julbal", "yinyay", "nyajil"]),
    row(15, "You and I see the jungka wild cherry tree there.", "Ngaliny jungka yinyay nyajil.", "ngaliny jungka yinyay nyajil | 1du.INCL.NOM jungka.wild.cherry.tree there see.NPST", "r305_1du_incl_there_flora_see_jungka", ["ngaliny", "jungka", "yinyay", "nyajil"]),
    row(16, "You and I see the karranda tree there.", "Ngaliny karranda yinyay nyajil.", "ngaliny karranda yinyay nyajil | 1du.INCL.NOM karranda.tree there see.NPST", "r305_1du_incl_there_flora_see_karranda", ["ngaliny", "karranda", "yinyay", "nyajil"]),
    row(17, "You and I see the karrandal tree there.", "Ngaliny karrandal yinyay nyajil.", "ngaliny karrandal yinyay nyajil | 1du.INCL.NOM karrandal.tree there see.NPST", "r305_1du_incl_there_flora_see_karrandal", ["ngaliny", "karrandal", "yinyay", "nyajil"]),
    row(18, "You and I see the kawarr bloodwood tree there.", "Ngaliny kawarr yinyay nyajil.", "ngaliny kawarr yinyay nyajil | 1du.INCL.NOM kawarr.bloodwood.tree there see.NPST", "r305_1du_incl_there_flora_see_kawarr", ["ngaliny", "kawarr", "yinyay", "nyajil"]),
    row(19, "You and I see the marril ti tree there.", "Ngaliny marril yinyay nyajil.", "ngaliny marril yinyay nyajil | 1du.INCL.NOM marril.ti.tree there see.NPST", "r305_1du_incl_there_flora_see_marril", ["ngaliny", "marril", "yinyay", "nyajil"]),
    row(20, "You and I see the ngurrkul fig tree there.", "Ngaliny ngurrkul yinyay nyajil.", "ngaliny ngurrkul yinyay nyajil | 1du.INCL.NOM ngurrkul.fig.tree there see.NPST", "r305_1du_incl_there_flora_see_ngurrkul", ["ngaliny", "ngurrkul", "yinyay", "nyajil"]),
    row(21, "You two see the bujabay tree here.", "Yubal bujabay yaluy nyajil.", "yubal bujabay yaluy nyajil | 2du.NOM bujabay.tree here see.NPST", "r305_2du_here_flora_see_bujabay", ["yubal", "bujabay", "yaluy", "nyajil"]),
    row(22, "You two see the jingajalka tree here.", "Yubal jingajalka yaluy nyajil.", "yubal jingajalka yaluy nyajil | 2du.NOM jingajalka.tree here see.NPST", "r305_2du_here_flora_see_jingajalka", ["yubal", "jingajalka", "yaluy", "nyajil"]),
    row(23, "You two see the jirimandi coconut tree here.", "Yubal jirimandi yaluy nyajil.", "yubal jirimandi yaluy nyajil | 2du.NOM jirimandi.coconut.tree here see.NPST", "r305_2du_here_flora_see_jirimandi", ["yubal", "jirimandi", "yaluy", "nyajil"]),
    row(24, "You two see the julbal tree here.", "Yubal julbal yaluy nyajil.", "yubal julbal yaluy nyajil | 2du.NOM julbal.tree here see.NPST", "r305_2du_here_flora_see_julbal", ["yubal", "julbal", "yaluy", "nyajil"]),
    row(25, "You two see the jungka wild cherry tree here.", "Yubal jungka yaluy nyajil.", "yubal jungka yaluy nyajil | 2du.NOM jungka.wild.cherry.tree here see.NPST", "r305_2du_here_flora_see_jungka", ["yubal", "jungka", "yaluy", "nyajil"]),
    row(26, "You two see the karranda tree here.", "Yubal karranda yaluy nyajil.", "yubal karranda yaluy nyajil | 2du.NOM karranda.tree here see.NPST", "r305_2du_here_flora_see_karranda", ["yubal", "karranda", "yaluy", "nyajil"]),
    row(27, "You two see the karrandal tree here.", "Yubal karrandal yaluy nyajil.", "yubal karrandal yaluy nyajil | 2du.NOM karrandal.tree here see.NPST", "r305_2du_here_flora_see_karrandal", ["yubal", "karrandal", "yaluy", "nyajil"]),
    row(28, "You two see the kawarr bloodwood tree here.", "Yubal kawarr yaluy nyajil.", "yubal kawarr yaluy nyajil | 2du.NOM kawarr.bloodwood.tree here see.NPST", "r305_2du_here_flora_see_kawarr", ["yubal", "kawarr", "yaluy", "nyajil"]),
    row(29, "You two see the marril ti tree here.", "Yubal marril yaluy nyajil.", "yubal marril yaluy nyajil | 2du.NOM marril.ti.tree here see.NPST", "r305_2du_here_flora_see_marril", ["yubal", "marril", "yaluy", "nyajil"]),
    row(30, "You two see the ngurrkul fig tree here.", "Yubal ngurrkul yaluy nyajil.", "yubal ngurrkul yaluy nyajil | 2du.NOM ngurrkul.fig.tree here see.NPST", "r305_2du_here_flora_see_ngurrkul", ["yubal", "ngurrkul", "yaluy", "nyajil"]),
    row(31, "You all see the bujabay tree there.", "Yurra bujabay yinyay nyajil.", "yurra bujabay yinyay nyajil | 2pl.NOM bujabay.tree there see.NPST", "r305_2pl_there_flora_see_bujabay", ["yurra", "bujabay", "yinyay", "nyajil"]),
    row(32, "You all see the jingajalka tree there.", "Yurra jingajalka yinyay nyajil.", "yurra jingajalka yinyay nyajil | 2pl.NOM jingajalka.tree there see.NPST", "r305_2pl_there_flora_see_jingajalka", ["yurra", "jingajalka", "yinyay", "nyajil"]),
    row(33, "You all see the jirimandi coconut tree there.", "Yurra jirimandi yinyay nyajil.", "yurra jirimandi yinyay nyajil | 2pl.NOM jirimandi.coconut.tree there see.NPST", "r305_2pl_there_flora_see_jirimandi", ["yurra", "jirimandi", "yinyay", "nyajil"]),
    row(34, "You all see the julbal tree there.", "Yurra julbal yinyay nyajil.", "yurra julbal yinyay nyajil | 2pl.NOM julbal.tree there see.NPST", "r305_2pl_there_flora_see_julbal", ["yurra", "julbal", "yinyay", "nyajil"]),
    row(35, "You all see the jungka wild cherry tree there.", "Yurra jungka yinyay nyajil.", "yurra jungka yinyay nyajil | 2pl.NOM jungka.wild.cherry.tree there see.NPST", "r305_2pl_there_flora_see_jungka", ["yurra", "jungka", "yinyay", "nyajil"]),
    row(36, "You all see the karranda tree there.", "Yurra karranda yinyay nyajil.", "yurra karranda yinyay nyajil | 2pl.NOM karranda.tree there see.NPST", "r305_2pl_there_flora_see_karranda", ["yurra", "karranda", "yinyay", "nyajil"]),
    row(37, "You all see the karrandal tree there.", "Yurra karrandal yinyay nyajil.", "yurra karrandal yinyay nyajil | 2pl.NOM karrandal.tree there see.NPST", "r305_2pl_there_flora_see_karrandal", ["yurra", "karrandal", "yinyay", "nyajil"]),
    row(38, "You all see the kawarr bloodwood tree there.", "Yurra kawarr yinyay nyajil.", "yurra kawarr yinyay nyajil | 2pl.NOM kawarr.bloodwood.tree there see.NPST", "r305_2pl_there_flora_see_kawarr", ["yurra", "kawarr", "yinyay", "nyajil"]),
    row(39, "You all see the marril ti tree there.", "Yurra marril yinyay nyajil.", "yurra marril yinyay nyajil | 2pl.NOM marril.ti.tree there see.NPST", "r305_2pl_there_flora_see_marril", ["yurra", "marril", "yinyay", "nyajil"]),
    row(40, "You all see the ngurrkul fig tree there.", "Yurra ngurrkul yinyay nyajil.", "yurra ngurrkul yinyay nyajil | 2pl.NOM ngurrkul.fig.tree there see.NPST", "r305_2pl_there_flora_see_ngurrkul", ["yurra", "ngurrkul", "yinyay", "nyajil"]),
    row(41, "We see the bujabay tree here.", "Ngana bujabay yaluy nyajil.", "ngana bujabay yaluy nyajil | 1pl.INCL.NOM bujabay.tree here see.NPST", "r305_1pl_incl_here_flora_see_bujabay", ["ngana", "bujabay", "yaluy", "nyajil"]),
    row(42, "We see the jingajalka tree here.", "Ngana jingajalka yaluy nyajil.", "ngana jingajalka yaluy nyajil | 1pl.INCL.NOM jingajalka.tree here see.NPST", "r305_1pl_incl_here_flora_see_jingajalka", ["ngana", "jingajalka", "yaluy", "nyajil"]),
    row(43, "We see the jirimandi coconut tree here.", "Ngana jirimandi yaluy nyajil.", "ngana jirimandi yaluy nyajil | 1pl.INCL.NOM jirimandi.coconut.tree here see.NPST", "r305_1pl_incl_here_flora_see_jirimandi", ["ngana", "jirimandi", "yaluy", "nyajil"]),
    row(44, "We see the julbal tree here.", "Ngana julbal yaluy nyajil.", "ngana julbal yaluy nyajil | 1pl.INCL.NOM julbal.tree here see.NPST", "r305_1pl_incl_here_flora_see_julbal", ["ngana", "julbal", "yaluy", "nyajil"]),
    row(45, "We see the jungka wild cherry tree here.", "Ngana jungka yaluy nyajil.", "ngana jungka yaluy nyajil | 1pl.INCL.NOM jungka.wild.cherry.tree here see.NPST", "r305_1pl_incl_here_flora_see_jungka", ["ngana", "jungka", "yaluy", "nyajil"]),
    row(46, "We see the karranda tree here.", "Ngana karranda yaluy nyajil.", "ngana karranda yaluy nyajil | 1pl.INCL.NOM karranda.tree here see.NPST", "r305_1pl_incl_here_flora_see_karranda", ["ngana", "karranda", "yaluy", "nyajil"]),
    row(47, "We see the karrandal tree here.", "Ngana karrandal yaluy nyajil.", "ngana karrandal yaluy nyajil | 1pl.INCL.NOM karrandal.tree here see.NPST", "r305_1pl_incl_here_flora_see_karrandal", ["ngana", "karrandal", "yaluy", "nyajil"]),
    row(48, "We see the kawarr bloodwood tree here.", "Ngana kawarr yaluy nyajil.", "ngana kawarr yaluy nyajil | 1pl.INCL.NOM kawarr.bloodwood.tree here see.NPST", "r305_1pl_incl_here_flora_see_kawarr", ["ngana", "kawarr", "yaluy", "nyajil"]),
    row(49, "We see the marril ti tree here.", "Ngana marril yaluy nyajil.", "ngana marril yaluy nyajil | 1pl.INCL.NOM marril.ti.tree here see.NPST", "r305_1pl_incl_here_flora_see_marril", ["ngana", "marril", "yaluy", "nyajil"]),
    row(50, "We see the ngurrkul fig tree here.", "Ngana ngurrkul yaluy nyajil.", "ngana ngurrkul yaluy nyajil | 1pl.INCL.NOM ngurrkul.fig.tree here see.NPST", "r305_1pl_incl_here_flora_see_ngurrkul", ["ngana", "ngurrkul", "yaluy", "nyajil"]),
]


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")
    kukus = [r[2] for r in ROWS]
    if len(set(kukus)) != len(kukus):
        issues.append("duplicate Kuku surface inside batch")
    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)
        lower_kuku = kuku.lower()
        lower_english = english.lower()
        if loans:
            issues.append(f"{seq}: loans used {loans}")
        denied = sorted({w for w in DENY_KUKU if re.search(rf"(^|\s){re.escape(w)}([\s\.]|$)", lower_kuku)})
        if denied:
            issues.append(f"{seq}: denied Kuku forms {denied}")
        denied_english = [term for term in DENY_ENGLISH if re.search(rf"\b{re.escape(term.strip())}\b", lower_english)]
        if denied_english:
            issues.append(f"{seq}: denied English drift {denied_english}")
        target_hits = [w for w in TARGET_ORDER if w in words]
        if len(target_hits) != 1:
            issues.append(f"{seq}: target hits {target_hits}")
        if len(words) != 4:
            issues.append(f"{seq}: expected 4 words, got {words}")
        if "nyajil" not in words or not lower_kuku.endswith(" nyajil."):
            issues.append(f"{seq}: missing final nyajil")
        if "nyajin" in lower_kuku:
            issues.append(f"{seq}: past nyajin leakage")
        if len([w for w in ("yaluy", "yinyay") if w in words]) != 1:
            issues.append(f"{seq}: demonstrative problem {words}")
        expected_pronoun, expected_demo = FRAME_SPECS[(seq - 1) // 10]
        if words[0] != expected_pronoun:
            issues.append(f"{seq}: expected pronoun {expected_pronoun}, got {words[0]}")
        if words[2] != expected_demo:
            issues.append(f"{seq}: expected demonstrative {expected_demo}, got {words[2]}")
        if words[1] != TARGET_ORDER[(seq - 1) % 10]:
            issues.append(f"{seq}: target order mismatch {words[1]}")
        if words[3] != "nyajil":
            issues.append(f"{seq}: word 4 is not nyajil {words[3]}")
        if lower_kuku.rstrip(".") != " ".join(words):
            issues.append(f"{seq}: Kuku does not match words_used {words}")
        if not frame.startswith("r305_"):
            issues.append(f"{seq}: frame not r305 {frame}")
    return issues


def main() -> int:
    issues = scan_static()
    if issues:
        for issue in issues:
            print(issue)
        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} already exists")
    collisions = []
    for _seq, _english, kuku, *_rest in ROWS:
        existing = db.execute(
            """
            SELECT b.label, s.seq, s.status
            FROM sentences s
            JOIN batches b ON b.id=s.batch_id
            WHERE lower(s.kuku)=lower(?) AND s.status!='rejected'
            """,
            (kuku,),
        ).fetchall()
        if existing:
            collisions.append((kuku, existing))
    if collisions:
        raise SystemExit(f"duplicate preflight failed: {collisions}")

    target_counts = count_words(db, TARGET_ORDER)
    support_counts = count_words(db, ["ngali", "ngaliny", "yubal", "yurra", "ngana", "yaluy", "yinyay", "nyajil"])
    verified_before, words_before = db.execute(
        """
        SELECT COUNT(*), SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1)
        FROM sentences
        WHERE status IN ('accepted','revised')
        """
    ).fetchone()

    notes = (
        "COMPLEMENTARY VISIBLE FLORA/TREE NON-SINGULAR NONPAST PERCEPTION SWEEP AFTER RULE 304 (Rule 305). "
        "50 under-review rows over ten checked flora/tree target heads: bujabay tree, jingajalka tree, jirimandi "
        "coconut tree, julbal tree, jungka wild cherry tree, karranda tree, karrandal tree, kawarr bloodwood tree, "
        "marril ti tree, and ngurrkul fig tree. SUPPORT: bare nominative ngali, ngaliny, yubal, yurra, and ngana, "
        "plus yaluy/yinyay and nyajil. Only bare visible object nonpast perception/reference rows are opened; fruit, "
        "seed, edible/food, leaching, soaking, water preparation, bark, basket-making, cooking, hot stones, "
        "bones/death, wet-season/ripening, leaves, colour, crushed leaves, cooking-leaf translation drift, boils, "
        "remedies, medicine, hardwood, oars, mangrove/water expansion, timber, firewood, deep-scrub ecology, "
        "place/story, target case, pronoun case, demonstrative case, compounds, productive reduplication, "
        "past/purposive/reduplicated perception drift, and support inflection remain closed."
    )
    cur = db.execute(
        "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
        (LABEL, "Rule 305 under review", "operator-guide-2026-07-09", 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_used, loans_used,
                evidence, "under_review", confidence,
                "project_approved_synthetic_pending_elder_verification", "claude", NOW, NOW,
            )
            for seq, english, kuku, analysis, frame, tier, words_used, loans_used, evidence, confidence in ROWS
        ],
    )
    record_event(db, batch_label=LABEL, phase="source", event_type="source-readback", actor="claude-main", detail="Reread direct dictionary yaml entries for ten Rule 305 flora/tree targets and living grammar non-singular pronoun, demonstrative, and nyaji-l/nyajil nonpast support before authoring Rule 305.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="complementary-flora-tree-nonsingular-nonpast-scope", actor="claude-main", detail="Selected the complementary visible flora/tree non-singular nonpast perception field after Rule 304 by reversing the local-demonstrative slot. The batch uses ngali, ngaliny, yubal, yurra, and ngana with nyajil and opens no plant use, fruit, food, bark, cooking, medicine, ecology, place/story, case, compound, past, purposive, reduplicated perception, or support-inflection semantics.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="coverage-audit", actor="claude-main", detail=f"Token-aware accepted/revised coverage before banking from words_used JSON: targets={target_counts}; support={support_counts}.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="duplicate-preflight", actor="claude-main", detail="Final 50 Rule 305 visible flora/tree non-singular nonpast surfaces returned no accepted, revised, or under-review collisions.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="preflight", event_type="static-guard-pass", actor="claude-main", detail="Static guard passed: 50 explicit hand-authored rows, one target each, bare non-singular nominative pronoun bands, bare yaluy/yinyay, final nyajil, no loans, no denied Kuku forms, and no fruit/seed/food/bark/cooking/medicine/ecology/place-story/source-prose drift.", command="python3 -m py_compile batch_scripts/bank_347.py && python3 -c \"import sys; sys.path.insert(0,'batch_scripts'); import bank_347; print(bank_347.scan_static())\"", output_excerpt="issues 0", artifact_path="batch_scripts/bank_347.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="claude-main", detail=f"Banked 50 Rule 305 rows as under_review. Verified total remains {verified_before}; Kuku word count remains {words_before}.", command="python3 batch_scripts/bank_347.py", output_excerpt=f"banked batch-347: 50 rows under_review; verified_before={verified_before}; kuku_words_before={words_before}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit()
    print("banked batch-347: 50 rows under_review")
    return 0


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