#!/usr/bin/env python3
"""Bank batch-330: Rule 288 complementary artefact/tool 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-330"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-330-visible-artefact-tool-nonsingular-complementary-past-pronoun-perception-after-rule287-process.md"

TARGET_EVIDENCE = {
    "badur": "Dictionary lines 256-268 give badur as noun 'hook', with definition 'hook and line'. Rule 288 selects visible hook reference only and leaves fishing action closed.",
    "balji": "Dictionary lines 963-974 give balji as noun 'bag/dilly bag', specifically a woman's dilly bag made from grass or black palm. Rule 288 selects visible bag reference only and leaves making/material rows closed.",
    "balur": "Dictionary lines 1154-1170 give balur as noun 'spear thrower' and mark a duplicate empty entry as the same noun. Rule 288 selects visible woomera/spear-thrower reference only.",
    "kaljan": "Dictionary lines 12560-12568 give kaljan as noun 'outrigger canoe'. Rule 288 selects visible canoe reference only and leaves travel/rowing/use rows closed.",
    "dajal": "Dictionary lines 4499-4509 give dajal as noun 'spear', specifically fighting spear. Rule 288 selects visible spear reference only and leaves fighting/spearing action closed.",
    "dakilji": "Dictionary lines 4665-4676 give dakilji as noun 'cup', also pannikin only rarely used now. Rule 288 selects visible cup reference only.",
    "jidi": "Dictionary lines 8842-8851 give jidi as noun 'torch', a paperbark-tree-bark torch. Rule 288 selects visible torch reference only and leaves fire/burning/making rows closed.",
    "jindal": "Dictionary lines 9423-9433 give jindal as noun 'spear with three prongs' and warn it is homophonous with jindal 'bite'. Rule 288 selects the noun only and leaves the biting verb closed.",
    "jundi": "Dictionary lines 10846-10857 give jundi as noun 'pumice stone/carborundum stone'. Rule 288 selects visible stone/tool reference only and leaves sharpening/rubbing use closed.",
    "karra": "Dictionary lines 13534-13544 give karra as noun 'rope, cord, string', with synonym ngarra. Rule 288 selects visible rope reference only and leaves tying/use rows closed.",
}

SUPPORT_EVIDENCE = (
    "Patz lines 2577-2603 source bare non-singular nominative pronouns; lines 2674-2686 source non-singular "
    "contrasts; lines 2838-2845 source yaluy/yinyay; and lines 2568-2571 source nyaji-ny 'see-PAST'."
)

TARGET_ORDER = ["badur", "balji", "balur", "kaljan", "dajal", "dakilji", "jidi", "jindal", "jundi", "karra"]
FRAME_SPECS = [
    ("ngali", "yaluy"),
    ("ngaliny", "yinyay"),
    ("yubal", "yaluy"),
    ("yurra", "yinyay"),
    ("jana", "yaluy"),
]

DENY_KUKU = {
    "birungubay", "biruwybay", "birubay", "badurriji", "baluriji", "dama-l", "dama-ny",
    "damal", "damany", "daman", "damba", "jindal-ny", "jindalny", "jindal-ji", "jarrjal",
    "jarrkal", "milbayarr", "mingu", "marrakan", "knife", "pipe", "blanket", "hat",
    "ngalingan", "ngalinyan", "yubalan", "yurrangan", "janangan", "ngalininy", "ngalinyiny",
    "yubaliny", "yurraniny", "jananiny", "ngalinka", "ngalinyanka", "yubalanka", "yurranka",
    "jananka", "ngalinda", "ngalinyanda", "yubalanda", "yurranda", "jananda", "ngalinji",
    "ngalinyanji", "yubalanji", "yurranji", "jananji", "ngalinga", "ngalinyanga", "yubalanga",
    "yurranga", "jananga", "nyajil", "nyaji-l", "nyaji-nka", "nyaji-l-nyaji", "yinyangka",
    "yinyayngka", "yinyamba", "yinyamuny", "yalungku", "yaluyngku", "yaluymbu", "yaluyundu",
    "yalamuny",
}
DENY_ENGLISH = (
    "fishing", "fish with", "row", "paddle with", "oar", "made", "make", "used", "use",
    "throwing", "threw", "thrown", "fighting with", "fight with", "kill", "killed", "bite",
    "bit", "bad news", "message", "euphemism", "penis", "fire", "burn", "burned", "cooking",
    "travel", "route", "went in", "place", "story", "ceremony", "mortuary", "coffin",
)


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) saw the hook here.", "Ngali badur yaluy nyajin.", "ngali badur yaluy nyajin | 1du.EXCL.NOM hook here see.PAST", "r288_1du_excl_here_artefact_tool_see_past_badur", ["ngali", "badur", "yaluy", "nyajin"]),
    row(2, "We two (not you) saw the dilly bag here.", "Ngali balji yaluy nyajin.", "ngali balji yaluy nyajin | 1du.EXCL.NOM dilly.bag here see.PAST", "r288_1du_excl_here_artefact_tool_see_past_balji", ["ngali", "balji", "yaluy", "nyajin"]),
    row(3, "We two (not you) saw the spear thrower here.", "Ngali balur yaluy nyajin.", "ngali balur yaluy nyajin | 1du.EXCL.NOM spear.thrower here see.PAST", "r288_1du_excl_here_artefact_tool_see_past_balur", ["ngali", "balur", "yaluy", "nyajin"]),
    row(4, "We two (not you) saw the outrigger canoe here.", "Ngali kaljan yaluy nyajin.", "ngali kaljan yaluy nyajin | 1du.EXCL.NOM outrigger.canoe here see.PAST", "r288_1du_excl_here_artefact_tool_see_past_kaljan", ["ngali", "kaljan", "yaluy", "nyajin"]),
    row(5, "We two (not you) saw the fighting spear here.", "Ngali dajal yaluy nyajin.", "ngali dajal yaluy nyajin | 1du.EXCL.NOM fighting.spear here see.PAST", "r288_1du_excl_here_artefact_tool_see_past_dajal", ["ngali", "dajal", "yaluy", "nyajin"]),
    row(6, "We two (not you) saw the cup here.", "Ngali dakilji yaluy nyajin.", "ngali dakilji yaluy nyajin | 1du.EXCL.NOM cup here see.PAST", "r288_1du_excl_here_artefact_tool_see_past_dakilji", ["ngali", "dakilji", "yaluy", "nyajin"]),
    row(7, "We two (not you) saw the torch here.", "Ngali jidi yaluy nyajin.", "ngali jidi yaluy nyajin | 1du.EXCL.NOM torch here see.PAST", "r288_1du_excl_here_artefact_tool_see_past_jidi", ["ngali", "jidi", "yaluy", "nyajin"]),
    row(8, "We two (not you) saw the three-pronged spear here.", "Ngali jindal yaluy nyajin.", "ngali jindal yaluy nyajin | 1du.EXCL.NOM three.pronged.spear here see.PAST", "r288_1du_excl_here_artefact_tool_see_past_jindal", ["ngali", "jindal", "yaluy", "nyajin"]),
    row(9, "We two (not you) saw the pumice stone here.", "Ngali jundi yaluy nyajin.", "ngali jundi yaluy nyajin | 1du.EXCL.NOM pumice.stone here see.PAST", "r288_1du_excl_here_artefact_tool_see_past_jundi", ["ngali", "jundi", "yaluy", "nyajin"]),
    row(10, "We two (not you) saw the rope here.", "Ngali karra yaluy nyajin.", "ngali karra yaluy nyajin | 1du.EXCL.NOM rope here see.PAST", "r288_1du_excl_here_artefact_tool_see_past_karra", ["ngali", "karra", "yaluy", "nyajin"]),
    row(11, "You and I saw the hook there.", "Ngaliny badur yinyay nyajin.", "ngaliny badur yinyay nyajin | 1du.INCL.NOM hook there see.PAST", "r288_1du_incl_there_artefact_tool_see_past_badur", ["ngaliny", "badur", "yinyay", "nyajin"]),
    row(12, "You and I saw the dilly bag there.", "Ngaliny balji yinyay nyajin.", "ngaliny balji yinyay nyajin | 1du.INCL.NOM dilly.bag there see.PAST", "r288_1du_incl_there_artefact_tool_see_past_balji", ["ngaliny", "balji", "yinyay", "nyajin"]),
    row(13, "You and I saw the spear thrower there.", "Ngaliny balur yinyay nyajin.", "ngaliny balur yinyay nyajin | 1du.INCL.NOM spear.thrower there see.PAST", "r288_1du_incl_there_artefact_tool_see_past_balur", ["ngaliny", "balur", "yinyay", "nyajin"]),
    row(14, "You and I saw the outrigger canoe there.", "Ngaliny kaljan yinyay nyajin.", "ngaliny kaljan yinyay nyajin | 1du.INCL.NOM outrigger.canoe there see.PAST", "r288_1du_incl_there_artefact_tool_see_past_kaljan", ["ngaliny", "kaljan", "yinyay", "nyajin"]),
    row(15, "You and I saw the fighting spear there.", "Ngaliny dajal yinyay nyajin.", "ngaliny dajal yinyay nyajin | 1du.INCL.NOM fighting.spear there see.PAST", "r288_1du_incl_there_artefact_tool_see_past_dajal", ["ngaliny", "dajal", "yinyay", "nyajin"]),
    row(16, "You and I saw the cup there.", "Ngaliny dakilji yinyay nyajin.", "ngaliny dakilji yinyay nyajin | 1du.INCL.NOM cup there see.PAST", "r288_1du_incl_there_artefact_tool_see_past_dakilji", ["ngaliny", "dakilji", "yinyay", "nyajin"]),
    row(17, "You and I saw the torch there.", "Ngaliny jidi yinyay nyajin.", "ngaliny jidi yinyay nyajin | 1du.INCL.NOM torch there see.PAST", "r288_1du_incl_there_artefact_tool_see_past_jidi", ["ngaliny", "jidi", "yinyay", "nyajin"]),
    row(18, "You and I saw the three-pronged spear there.", "Ngaliny jindal yinyay nyajin.", "ngaliny jindal yinyay nyajin | 1du.INCL.NOM three.pronged.spear there see.PAST", "r288_1du_incl_there_artefact_tool_see_past_jindal", ["ngaliny", "jindal", "yinyay", "nyajin"]),
    row(19, "You and I saw the pumice stone there.", "Ngaliny jundi yinyay nyajin.", "ngaliny jundi yinyay nyajin | 1du.INCL.NOM pumice.stone there see.PAST", "r288_1du_incl_there_artefact_tool_see_past_jundi", ["ngaliny", "jundi", "yinyay", "nyajin"]),
    row(20, "You and I saw the rope there.", "Ngaliny karra yinyay nyajin.", "ngaliny karra yinyay nyajin | 1du.INCL.NOM rope there see.PAST", "r288_1du_incl_there_artefact_tool_see_past_karra", ["ngaliny", "karra", "yinyay", "nyajin"]),
    row(21, "You two saw the hook here.", "Yubal badur yaluy nyajin.", "yubal badur yaluy nyajin | 2du.NOM hook here see.PAST", "r288_2du_here_artefact_tool_see_past_badur", ["yubal", "badur", "yaluy", "nyajin"]),
    row(22, "You two saw the dilly bag here.", "Yubal balji yaluy nyajin.", "yubal balji yaluy nyajin | 2du.NOM dilly.bag here see.PAST", "r288_2du_here_artefact_tool_see_past_balji", ["yubal", "balji", "yaluy", "nyajin"]),
    row(23, "You two saw the spear thrower here.", "Yubal balur yaluy nyajin.", "yubal balur yaluy nyajin | 2du.NOM spear.thrower here see.PAST", "r288_2du_here_artefact_tool_see_past_balur", ["yubal", "balur", "yaluy", "nyajin"]),
    row(24, "You two saw the outrigger canoe here.", "Yubal kaljan yaluy nyajin.", "yubal kaljan yaluy nyajin | 2du.NOM outrigger.canoe here see.PAST", "r288_2du_here_artefact_tool_see_past_kaljan", ["yubal", "kaljan", "yaluy", "nyajin"]),
    row(25, "You two saw the fighting spear here.", "Yubal dajal yaluy nyajin.", "yubal dajal yaluy nyajin | 2du.NOM fighting.spear here see.PAST", "r288_2du_here_artefact_tool_see_past_dajal", ["yubal", "dajal", "yaluy", "nyajin"]),
    row(26, "You two saw the cup here.", "Yubal dakilji yaluy nyajin.", "yubal dakilji yaluy nyajin | 2du.NOM cup here see.PAST", "r288_2du_here_artefact_tool_see_past_dakilji", ["yubal", "dakilji", "yaluy", "nyajin"]),
    row(27, "You two saw the torch here.", "Yubal jidi yaluy nyajin.", "yubal jidi yaluy nyajin | 2du.NOM torch here see.PAST", "r288_2du_here_artefact_tool_see_past_jidi", ["yubal", "jidi", "yaluy", "nyajin"]),
    row(28, "You two saw the three-pronged spear here.", "Yubal jindal yaluy nyajin.", "yubal jindal yaluy nyajin | 2du.NOM three.pronged.spear here see.PAST", "r288_2du_here_artefact_tool_see_past_jindal", ["yubal", "jindal", "yaluy", "nyajin"]),
    row(29, "You two saw the pumice stone here.", "Yubal jundi yaluy nyajin.", "yubal jundi yaluy nyajin | 2du.NOM pumice.stone here see.PAST", "r288_2du_here_artefact_tool_see_past_jundi", ["yubal", "jundi", "yaluy", "nyajin"]),
    row(30, "You two saw the rope here.", "Yubal karra yaluy nyajin.", "yubal karra yaluy nyajin | 2du.NOM rope here see.PAST", "r288_2du_here_artefact_tool_see_past_karra", ["yubal", "karra", "yaluy", "nyajin"]),
    row(31, "You all saw the hook there.", "Yurra badur yinyay nyajin.", "yurra badur yinyay nyajin | 2pl.NOM hook there see.PAST", "r288_2pl_there_artefact_tool_see_past_badur", ["yurra", "badur", "yinyay", "nyajin"]),
    row(32, "You all saw the dilly bag there.", "Yurra balji yinyay nyajin.", "yurra balji yinyay nyajin | 2pl.NOM dilly.bag there see.PAST", "r288_2pl_there_artefact_tool_see_past_balji", ["yurra", "balji", "yinyay", "nyajin"]),
    row(33, "You all saw the spear thrower there.", "Yurra balur yinyay nyajin.", "yurra balur yinyay nyajin | 2pl.NOM spear.thrower there see.PAST", "r288_2pl_there_artefact_tool_see_past_balur", ["yurra", "balur", "yinyay", "nyajin"]),
    row(34, "You all saw the outrigger canoe there.", "Yurra kaljan yinyay nyajin.", "yurra kaljan yinyay nyajin | 2pl.NOM outrigger.canoe there see.PAST", "r288_2pl_there_artefact_tool_see_past_kaljan", ["yurra", "kaljan", "yinyay", "nyajin"]),
    row(35, "You all saw the fighting spear there.", "Yurra dajal yinyay nyajin.", "yurra dajal yinyay nyajin | 2pl.NOM fighting.spear there see.PAST", "r288_2pl_there_artefact_tool_see_past_dajal", ["yurra", "dajal", "yinyay", "nyajin"]),
    row(36, "You all saw the cup there.", "Yurra dakilji yinyay nyajin.", "yurra dakilji yinyay nyajin | 2pl.NOM cup there see.PAST", "r288_2pl_there_artefact_tool_see_past_dakilji", ["yurra", "dakilji", "yinyay", "nyajin"]),
    row(37, "You all saw the torch there.", "Yurra jidi yinyay nyajin.", "yurra jidi yinyay nyajin | 2pl.NOM torch there see.PAST", "r288_2pl_there_artefact_tool_see_past_jidi", ["yurra", "jidi", "yinyay", "nyajin"]),
    row(38, "You all saw the three-pronged spear there.", "Yurra jindal yinyay nyajin.", "yurra jindal yinyay nyajin | 2pl.NOM three.pronged.spear there see.PAST", "r288_2pl_there_artefact_tool_see_past_jindal", ["yurra", "jindal", "yinyay", "nyajin"]),
    row(39, "You all saw the pumice stone there.", "Yurra jundi yinyay nyajin.", "yurra jundi yinyay nyajin | 2pl.NOM pumice.stone there see.PAST", "r288_2pl_there_artefact_tool_see_past_jundi", ["yurra", "jundi", "yinyay", "nyajin"]),
    row(40, "You all saw the rope there.", "Yurra karra yinyay nyajin.", "yurra karra yinyay nyajin | 2pl.NOM rope there see.PAST", "r288_2pl_there_artefact_tool_see_past_karra", ["yurra", "karra", "yinyay", "nyajin"]),
    row(41, "They saw the hook here.", "Jana badur yaluy nyajin.", "jana badur yaluy nyajin | 3pl.NOM hook here see.PAST", "r288_3pl_here_artefact_tool_see_past_badur", ["jana", "badur", "yaluy", "nyajin"]),
    row(42, "They saw the dilly bag here.", "Jana balji yaluy nyajin.", "jana balji yaluy nyajin | 3pl.NOM dilly.bag here see.PAST", "r288_3pl_here_artefact_tool_see_past_balji", ["jana", "balji", "yaluy", "nyajin"]),
    row(43, "They saw the spear thrower here.", "Jana balur yaluy nyajin.", "jana balur yaluy nyajin | 3pl.NOM spear.thrower here see.PAST", "r288_3pl_here_artefact_tool_see_past_balur", ["jana", "balur", "yaluy", "nyajin"]),
    row(44, "They saw the outrigger canoe here.", "Jana kaljan yaluy nyajin.", "jana kaljan yaluy nyajin | 3pl.NOM outrigger.canoe here see.PAST", "r288_3pl_here_artefact_tool_see_past_kaljan", ["jana", "kaljan", "yaluy", "nyajin"]),
    row(45, "They saw the fighting spear here.", "Jana dajal yaluy nyajin.", "jana dajal yaluy nyajin | 3pl.NOM fighting.spear here see.PAST", "r288_3pl_here_artefact_tool_see_past_dajal", ["jana", "dajal", "yaluy", "nyajin"]),
    row(46, "They saw the cup here.", "Jana dakilji yaluy nyajin.", "jana dakilji yaluy nyajin | 3pl.NOM cup here see.PAST", "r288_3pl_here_artefact_tool_see_past_dakilji", ["jana", "dakilji", "yaluy", "nyajin"]),
    row(47, "They saw the torch here.", "Jana jidi yaluy nyajin.", "jana jidi yaluy nyajin | 3pl.NOM torch here see.PAST", "r288_3pl_here_artefact_tool_see_past_jidi", ["jana", "jidi", "yaluy", "nyajin"]),
    row(48, "They saw the three-pronged spear here.", "Jana jindal yaluy nyajin.", "jana jindal yaluy nyajin | 3pl.NOM three.pronged.spear here see.PAST", "r288_3pl_here_artefact_tool_see_past_jindal", ["jana", "jindal", "yaluy", "nyajin"]),
    row(49, "They saw the pumice stone here.", "Jana jundi yaluy nyajin.", "jana jundi yaluy nyajin | 3pl.NOM pumice.stone here see.PAST", "r288_3pl_here_artefact_tool_see_past_jundi", ["jana", "jundi", "yaluy", "nyajin"]),
    row(50, "They saw the rope here.", "Jana karra yaluy nyajin.", "jana karra yaluy nyajin | 3pl.NOM rope here see.PAST", "r288_3pl_here_artefact_tool_see_past_karra", ["jana", "karra", "yaluy", "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")
    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 "nyajin" not in words or not lower_kuku.endswith(" nyajin."):
            issues.append(f"{seq}: missing final nyajin")
        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] not in TARGET_ORDER:
            issues.append(f"{seq}: word 2 is not a target {words[1]}")
        if words[3] != "nyajin":
            issues.append(f"{seq}: word 4 is not nyajin {words[3]}")
        if lower_kuku.rstrip(".") != " ".join(words):
            issues.append(f"{seq}: Kuku does not match words_used {words}")
        if not frame.startswith("r288_"):
            issues.append(f"{seq}: frame not r288 {frame}")
    return issues


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 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", "jana", "yaluy", "yinyay", "nyajin"])
    verified_before, words_before = db.execute(
        """
        SELECT COUNT(*), SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1)
        FROM sentences
        WHERE status IN ('accepted','revised')
        """
    ).fetchone()

    notes = (
        "VISIBLE ARTEFACT/TOOL NON-SINGULAR COMPLEMENTARY PAST PRONOUN PERCEPTION SWEEP AFTER RULE 287 "
        "(Rule 288). 50 under-review rows over badur hook, balji dilly bag, balur spear thrower, kaljan "
        "outrigger canoe, dajal fighting spear, dakilji cup, jidi torch, jindal three-pronged spear, jundi "
        "pumice stone, and karra rope. SUPPORT: bare nominative ngali, ngaliny, yubal, yurra, and jana, plus "
        "yaluy/yinyay and nyajin. FRAMES: Ngali TARGET yaluy nyajin, Ngaliny TARGET yinyay nyajin, Yubal TARGET "
        "yaluy nyajin, Yurra TARGET yinyay nyajin, and Jana TARGET yaluy nyajin. Only bare visible object past "
        "perception/reference rows are opened; fishing, making, material-source, canoe travel, rowing/paddling, "
        "spear throwing, fighting, biting, sharpening/rubbing, tying, fire/burning, post-contact loan objects, "
        "target case, pronoun case, demonstrative case, compounds, productive reduplication, nonpast/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 288 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 dictionary source lines for visible artefact/tool targets and Patz pronoun, non-singular, demonstrative, and nyaji-ny past support before authoring Rule 288.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="planning", event_type="construction-consolidation-scope", actor="claude-main", detail="Selected complementary past consolidation of the Rule 287 visible artefact/tool field: Ngali/Yubal/Jana remain yaluy and Ngaliny/Yurra remain yinyay, now with past nyajin. Birungubay remains excluded.", 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 288 complementary past surfaces over the Rule 285-287 artefact/tool target set 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, complementary bare non-singular nominative pronoun/demonstrative bands, final nyajin, no loans, no denied Kuku forms, no fishing/making/canoe-travel/spear-action/fire/use/case/compound drift.", command="python3 -m py_compile batch_scripts/bank_330.py && python3 -c \"import sys; sys.path.insert(0,'batch_scripts'); import bank_330; print(bank_330.scan_static())\"", output_excerpt="issues 0", artifact_path="batch_scripts/bank_330.py", created_at=NOW)
    record_event(db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="claude-main", detail=f"Banked 50 Rule 288 rows as under_review. Verified total remains {verified_before}; Kuku word count remains {words_before}.", command="python3 batch_scripts/bank_330.py", output_excerpt=f"banked batch-330: 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-330: 50 rows under_review")
    return 0


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