#!/usr/bin/env python3
"""Bank batch-304: Rule 262 reptile/amphibian non-singular pronoun perception sweep."""

from __future__ import annotations

import datetime as dt
import json
import sqlite3

from bank_294 import (
    DENY_ENGLISH,
    DENY_KUKU as BASE_DENY_KUKU,
    TARGET_HEADS,
    english_has_denied,
    has_target_morphology,
    has_token,
    js,
    row,
)
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-304"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-304-reptile-amphibian-nonsingular-pronoun-perception-after-rule261-process.md"
SUPPORT = {"ngali", "ngaliny", "yubal", "nganjin", "ngana", "yaluy", "yinyay", "nyajil"}
PRONOUN_SUPPORT = {"ngali", "ngaliny", "yubal", "nganjin", "ngana"}
EXTRA_DENY_KUKU = {
    "ngalingan", "ngalinyan", "yubalan", "nganjinan", "nganangan",
    "ngalininy", "ngalinyiny", "yubaliny", "nganjininy", "ngananiny",
    "ngalinka", "ngalinyanka", "yubalanka", "nganjinanka", "ngananka",
    "ngalinda", "ngalinyanda", "yubalanda", "nganjinanda", "ngananda",
    "ngalindamuny", "ngalinyandamuny", "yubalandamuny", "nganjinandamuny", "nganandamuny",
    "ngalinji", "ngalinyanji", "yubalanji", "nganjinanji", "ngananji",
    "ngalinga", "ngalinyanga", "yubalanga", "nganjinanga", "ngananga",
    "bala", "darrba", "jarrabina", "jayju", "jungarr", "kukur", "mali", "murramu", "ngumbi", "yawa",
    "balarr", "dijaraban", "kalburiji", "mawal", "munudumbun", "munyurri", "nakawarra", "ngalmnbu", "yarrka", "yiljun",
    "baymbay", "darkay", "kaduy", "karraway", "karruku", "kulil", "kuyalin", "marrkabina", "ngarrakaja", "nuwi",
}
DENY_KUKU = set(BASE_DENY_KUKU) | EXTRA_DENY_KUKU

EVIDENCE = {
    "bajuy": "Dictionary lines 559-567 give bajuy as noun 'lizard', definition 'slippery lizard', semantic domain fauna-reptile; Rule 262 selects lizard only. Patz grammar lines 2577-2603 source bare nominative ngali, ngaliny, yubal, nganjin, and ngana; lines 2682-2684 discuss inclusive/exclusive and second-person non-singular forms; lines 2838-2845 source yaluy/yinyay; and lines 3043-3049 source nyaji-l 'see'.",
    "bilngkumu": "Dictionary lines 2575-2585 give bilngkumu as noun 'crocodile' with salt-water source prose; Rule 262 selects crocodile only and leaves saltwater/habitat/danger rows closed. Patz grammar lines 2577-2603, 2682-2684, 2838-2845, and 3043-3049 source support.",
    "binanjal": "Dictionary lines 2726-2734 give binanjal as noun 'frill necked lizard', semantic domain fauna-reptile. Rule 262 selects the animal label only. Patz grammar lines 2577-2603, 2682-2684, 2838-2845, and 3043-3049 source support.",
    "bindimu": "Dictionary lines 2884-2901 give bindimu as black snake and a red-bellied black-snake alternate; Rule 262 selects black snake only and leaves alternate/colour-predicate expansion closed. Patz grammar lines 2577-2603, 2682-2684, 2838-2845, and 3043-3049 source support.",
    "bubal": "Dictionary lines 3397-3417 give bubal as species of tree snake and tree snake; Rule 262 selects tree snake only and leaves tree/habitat/biting prose closed. Patz grammar lines 2577-2603, 2682-2684, 2838-2845, and 3043-3049 source support.",
    "jijirrbay": "Dictionary lines 8955-8972 give jijirrbay as noun 'whip snake', semantic domain fauna-reptile. Rule 262 selects whip snake only. Patz grammar lines 2577-2603, 2682-2684, 2838-2845, and 3043-3049 source support.",
    "kabul": "Dictionary lines 11816-11833 give kabul as noun 'rock python', semantic domain fauna-reptile. Rule 262 selects rock python only and leaves rock/place/action prose closed. Patz grammar lines 2577-2603, 2682-2684, 2838-2845, and 3043-3049 source support.",
    "kalajarr": "Dictionary lines 12243-12251 give kalajarr as noun 'scrub goanna', semantic domain fauna-reptile. Rule 262 selects scrub goanna only and leaves scrub/habitat/food/action prose closed. Patz grammar lines 2577-2603, 2682-2684, 2838-2845, and 3043-3049 source support.",
    "kundurr": "Dictionary lines 15704-15720 give kundurr as noun 'death adder', semantic domain fauna-reptile. Rule 262 selects death adder as a lexical label only and leaves danger/poison/biting prose closed; kundurr-kundurr is not imported. Patz grammar lines 2577-2603, 2682-2684, 2838-2845, and 3043-3049 source support.",
    "yuday": "Dictionary lines 30662-30670 give yuday as noun 'frog' with large/edible source prose; Rule 262 selects frog only and leaves edible/rain/swamp/event rows closed. Patz grammar lines 2577-2603, 2682-2684, 2838-2845, and 3043-3049 source support.",
}

ROWS = [
    row(1, "We two, not you, see the lizard there.", "Ngali bajuy yinyay nyajil.", "ngali bajuy yinyay nyajil | 1du.EXCL.NOM lizard there see.NPST", "r262_1du_excl_target_there_see_bajuy", ["ngali", "bajuy", "yinyay", "nyajil"], EVIDENCE["bajuy"]),
    row(2, "We two, not you, see the crocodile there.", "Ngali bilngkumu yinyay nyajil.", "ngali bilngkumu yinyay nyajil | 1du.EXCL.NOM crocodile there see.NPST", "r262_1du_excl_target_there_see_bilngkumu", ["ngali", "bilngkumu", "yinyay", "nyajil"], EVIDENCE["bilngkumu"]),
    row(3, "We two, not you, see the frill necked lizard there.", "Ngali binanjal yinyay nyajil.", "ngali binanjal yinyay nyajil | 1du.EXCL.NOM frill.necked.lizard there see.NPST", "r262_1du_excl_target_there_see_binanjal", ["ngali", "binanjal", "yinyay", "nyajil"], EVIDENCE["binanjal"]),
    row(4, "We two, not you, see the black snake there.", "Ngali bindimu yinyay nyajil.", "ngali bindimu yinyay nyajil | 1du.EXCL.NOM black.snake there see.NPST", "r262_1du_excl_target_there_see_bindimu", ["ngali", "bindimu", "yinyay", "nyajil"], EVIDENCE["bindimu"]),
    row(5, "We two, not you, see the tree snake there.", "Ngali bubal yinyay nyajil.", "ngali bubal yinyay nyajil | 1du.EXCL.NOM tree.snake there see.NPST", "r262_1du_excl_target_there_see_bubal", ["ngali", "bubal", "yinyay", "nyajil"], EVIDENCE["bubal"]),
    row(6, "We two, not you, see the whip snake there.", "Ngali jijirrbay yinyay nyajil.", "ngali jijirrbay yinyay nyajil | 1du.EXCL.NOM whip.snake there see.NPST", "r262_1du_excl_target_there_see_jijirrbay", ["ngali", "jijirrbay", "yinyay", "nyajil"], EVIDENCE["jijirrbay"]),
    row(7, "We two, not you, see the rock python there.", "Ngali kabul yinyay nyajil.", "ngali kabul yinyay nyajil | 1du.EXCL.NOM rock.python there see.NPST", "r262_1du_excl_target_there_see_kabul", ["ngali", "kabul", "yinyay", "nyajil"], EVIDENCE["kabul"]),
    row(8, "We two, not you, see the scrub goanna there.", "Ngali kalajarr yinyay nyajil.", "ngali kalajarr yinyay nyajil | 1du.EXCL.NOM scrub.goanna there see.NPST", "r262_1du_excl_target_there_see_kalajarr", ["ngali", "kalajarr", "yinyay", "nyajil"], EVIDENCE["kalajarr"]),
    row(9, "We two, not you, see the death adder there.", "Ngali kundurr yinyay nyajil.", "ngali kundurr yinyay nyajil | 1du.EXCL.NOM death.adder there see.NPST", "r262_1du_excl_target_there_see_kundurr", ["ngali", "kundurr", "yinyay", "nyajil"], EVIDENCE["kundurr"]),
    row(10, "We two, not you, see the frog there.", "Ngali yuday yinyay nyajil.", "ngali yuday yinyay nyajil | 1du.EXCL.NOM frog there see.NPST", "r262_1du_excl_target_there_see_yuday", ["ngali", "yuday", "yinyay", "nyajil"], EVIDENCE["yuday"]),
    row(11, "You and I see the lizard here.", "Ngaliny bajuy yaluy nyajil.", "ngaliny bajuy yaluy nyajil | 1du.INCL.NOM lizard here see.NPST", "r262_1du_incl_target_here_see_bajuy", ["ngaliny", "bajuy", "yaluy", "nyajil"], EVIDENCE["bajuy"]),
    row(12, "You and I see the crocodile here.", "Ngaliny bilngkumu yaluy nyajil.", "ngaliny bilngkumu yaluy nyajil | 1du.INCL.NOM crocodile here see.NPST", "r262_1du_incl_target_here_see_bilngkumu", ["ngaliny", "bilngkumu", "yaluy", "nyajil"], EVIDENCE["bilngkumu"]),
    row(13, "You and I see the frill necked lizard here.", "Ngaliny binanjal yaluy nyajil.", "ngaliny binanjal yaluy nyajil | 1du.INCL.NOM frill.necked.lizard here see.NPST", "r262_1du_incl_target_here_see_binanjal", ["ngaliny", "binanjal", "yaluy", "nyajil"], EVIDENCE["binanjal"]),
    row(14, "You and I see the black snake here.", "Ngaliny bindimu yaluy nyajil.", "ngaliny bindimu yaluy nyajil | 1du.INCL.NOM black.snake here see.NPST", "r262_1du_incl_target_here_see_bindimu", ["ngaliny", "bindimu", "yaluy", "nyajil"], EVIDENCE["bindimu"]),
    row(15, "You and I see the tree snake here.", "Ngaliny bubal yaluy nyajil.", "ngaliny bubal yaluy nyajil | 1du.INCL.NOM tree.snake here see.NPST", "r262_1du_incl_target_here_see_bubal", ["ngaliny", "bubal", "yaluy", "nyajil"], EVIDENCE["bubal"]),
    row(16, "You and I see the whip snake here.", "Ngaliny jijirrbay yaluy nyajil.", "ngaliny jijirrbay yaluy nyajil | 1du.INCL.NOM whip.snake here see.NPST", "r262_1du_incl_target_here_see_jijirrbay", ["ngaliny", "jijirrbay", "yaluy", "nyajil"], EVIDENCE["jijirrbay"]),
    row(17, "You and I see the rock python here.", "Ngaliny kabul yaluy nyajil.", "ngaliny kabul yaluy nyajil | 1du.INCL.NOM rock.python here see.NPST", "r262_1du_incl_target_here_see_kabul", ["ngaliny", "kabul", "yaluy", "nyajil"], EVIDENCE["kabul"]),
    row(18, "You and I see the scrub goanna here.", "Ngaliny kalajarr yaluy nyajil.", "ngaliny kalajarr yaluy nyajil | 1du.INCL.NOM scrub.goanna here see.NPST", "r262_1du_incl_target_here_see_kalajarr", ["ngaliny", "kalajarr", "yaluy", "nyajil"], EVIDENCE["kalajarr"]),
    row(19, "You and I see the death adder here.", "Ngaliny kundurr yaluy nyajil.", "ngaliny kundurr yaluy nyajil | 1du.INCL.NOM death.adder here see.NPST", "r262_1du_incl_target_here_see_kundurr", ["ngaliny", "kundurr", "yaluy", "nyajil"], EVIDENCE["kundurr"]),
    row(20, "You and I see the frog here.", "Ngaliny yuday yaluy nyajil.", "ngaliny yuday yaluy nyajil | 1du.INCL.NOM frog here see.NPST", "r262_1du_incl_target_here_see_yuday", ["ngaliny", "yuday", "yaluy", "nyajil"], EVIDENCE["yuday"]),
    row(21, "You two see the lizard there.", "Yubal bajuy yinyay nyajil.", "yubal bajuy yinyay nyajil | 2du.NOM lizard there see.NPST", "r262_2du_target_there_see_bajuy", ["yubal", "bajuy", "yinyay", "nyajil"], EVIDENCE["bajuy"]),
    row(22, "You two see the crocodile there.", "Yubal bilngkumu yinyay nyajil.", "yubal bilngkumu yinyay nyajil | 2du.NOM crocodile there see.NPST", "r262_2du_target_there_see_bilngkumu", ["yubal", "bilngkumu", "yinyay", "nyajil"], EVIDENCE["bilngkumu"]),
    row(23, "You two see the frill necked lizard there.", "Yubal binanjal yinyay nyajil.", "yubal binanjal yinyay nyajil | 2du.NOM frill.necked.lizard there see.NPST", "r262_2du_target_there_see_binanjal", ["yubal", "binanjal", "yinyay", "nyajil"], EVIDENCE["binanjal"]),
    row(24, "You two see the black snake there.", "Yubal bindimu yinyay nyajil.", "yubal bindimu yinyay nyajil | 2du.NOM black.snake there see.NPST", "r262_2du_target_there_see_bindimu", ["yubal", "bindimu", "yinyay", "nyajil"], EVIDENCE["bindimu"]),
    row(25, "You two see the tree snake there.", "Yubal bubal yinyay nyajil.", "yubal bubal yinyay nyajil | 2du.NOM tree.snake there see.NPST", "r262_2du_target_there_see_bubal", ["yubal", "bubal", "yinyay", "nyajil"], EVIDENCE["bubal"]),
    row(26, "You two see the whip snake there.", "Yubal jijirrbay yinyay nyajil.", "yubal jijirrbay yinyay nyajil | 2du.NOM whip.snake there see.NPST", "r262_2du_target_there_see_jijirrbay", ["yubal", "jijirrbay", "yinyay", "nyajil"], EVIDENCE["jijirrbay"]),
    row(27, "You two see the rock python there.", "Yubal kabul yinyay nyajil.", "yubal kabul yinyay nyajil | 2du.NOM rock.python there see.NPST", "r262_2du_target_there_see_kabul", ["yubal", "kabul", "yinyay", "nyajil"], EVIDENCE["kabul"]),
    row(28, "You two see the scrub goanna there.", "Yubal kalajarr yinyay nyajil.", "yubal kalajarr yinyay nyajil | 2du.NOM scrub.goanna there see.NPST", "r262_2du_target_there_see_kalajarr", ["yubal", "kalajarr", "yinyay", "nyajil"], EVIDENCE["kalajarr"]),
    row(29, "You two see the death adder there.", "Yubal kundurr yinyay nyajil.", "yubal kundurr yinyay nyajil | 2du.NOM death.adder there see.NPST", "r262_2du_target_there_see_kundurr", ["yubal", "kundurr", "yinyay", "nyajil"], EVIDENCE["kundurr"]),
    row(30, "You two see the frog there.", "Yubal yuday yinyay nyajil.", "yubal yuday yinyay nyajil | 2du.NOM frog there see.NPST", "r262_2du_target_there_see_yuday", ["yubal", "yuday", "yinyay", "nyajil"], EVIDENCE["yuday"]),
    row(31, "We all, not you, see the lizard here.", "Nganjin bajuy yaluy nyajil.", "nganjin bajuy yaluy nyajil | 1pl.EXCL.NOM lizard here see.NPST", "r262_1pl_excl_target_here_see_bajuy", ["nganjin", "bajuy", "yaluy", "nyajil"], EVIDENCE["bajuy"]),
    row(32, "We all, not you, see the crocodile here.", "Nganjin bilngkumu yaluy nyajil.", "nganjin bilngkumu yaluy nyajil | 1pl.EXCL.NOM crocodile here see.NPST", "r262_1pl_excl_target_here_see_bilngkumu", ["nganjin", "bilngkumu", "yaluy", "nyajil"], EVIDENCE["bilngkumu"]),
    row(33, "We all, not you, see the frill necked lizard here.", "Nganjin binanjal yaluy nyajil.", "nganjin binanjal yaluy nyajil | 1pl.EXCL.NOM frill.necked.lizard here see.NPST", "r262_1pl_excl_target_here_see_binanjal", ["nganjin", "binanjal", "yaluy", "nyajil"], EVIDENCE["binanjal"]),
    row(34, "We all, not you, see the black snake here.", "Nganjin bindimu yaluy nyajil.", "nganjin bindimu yaluy nyajil | 1pl.EXCL.NOM black.snake here see.NPST", "r262_1pl_excl_target_here_see_bindimu", ["nganjin", "bindimu", "yaluy", "nyajil"], EVIDENCE["bindimu"]),
    row(35, "We all, not you, see the tree snake here.", "Nganjin bubal yaluy nyajil.", "nganjin bubal yaluy nyajil | 1pl.EXCL.NOM tree.snake here see.NPST", "r262_1pl_excl_target_here_see_bubal", ["nganjin", "bubal", "yaluy", "nyajil"], EVIDENCE["bubal"]),
    row(36, "We all, not you, see the whip snake here.", "Nganjin jijirrbay yaluy nyajil.", "nganjin jijirrbay yaluy nyajil | 1pl.EXCL.NOM whip.snake here see.NPST", "r262_1pl_excl_target_here_see_jijirrbay", ["nganjin", "jijirrbay", "yaluy", "nyajil"], EVIDENCE["jijirrbay"]),
    row(37, "We all, not you, see the rock python here.", "Nganjin kabul yaluy nyajil.", "nganjin kabul yaluy nyajil | 1pl.EXCL.NOM rock.python here see.NPST", "r262_1pl_excl_target_here_see_kabul", ["nganjin", "kabul", "yaluy", "nyajil"], EVIDENCE["kabul"]),
    row(38, "We all, not you, see the scrub goanna here.", "Nganjin kalajarr yaluy nyajil.", "nganjin kalajarr yaluy nyajil | 1pl.EXCL.NOM scrub.goanna here see.NPST", "r262_1pl_excl_target_here_see_kalajarr", ["nganjin", "kalajarr", "yaluy", "nyajil"], EVIDENCE["kalajarr"]),
    row(39, "We all, not you, see the death adder here.", "Nganjin kundurr yaluy nyajil.", "nganjin kundurr yaluy nyajil | 1pl.EXCL.NOM death.adder here see.NPST", "r262_1pl_excl_target_here_see_kundurr", ["nganjin", "kundurr", "yaluy", "nyajil"], EVIDENCE["kundurr"]),
    row(40, "We all, not you, see the frog here.", "Nganjin yuday yaluy nyajil.", "nganjin yuday yaluy nyajil | 1pl.EXCL.NOM frog here see.NPST", "r262_1pl_excl_target_here_see_yuday", ["nganjin", "yuday", "yaluy", "nyajil"], EVIDENCE["yuday"]),
    row(41, "We see the lizard there.", "Ngana bajuy yinyay nyajil.", "ngana bajuy yinyay nyajil | 1pl.INC.NOM lizard there see.NPST", "r262_1pl_incl_target_there_see_bajuy", ["ngana", "bajuy", "yinyay", "nyajil"], EVIDENCE["bajuy"]),
    row(42, "We see the crocodile there.", "Ngana bilngkumu yinyay nyajil.", "ngana bilngkumu yinyay nyajil | 1pl.INC.NOM crocodile there see.NPST", "r262_1pl_incl_target_there_see_bilngkumu", ["ngana", "bilngkumu", "yinyay", "nyajil"], EVIDENCE["bilngkumu"]),
    row(43, "We see the frill necked lizard there.", "Ngana binanjal yinyay nyajil.", "ngana binanjal yinyay nyajil | 1pl.INC.NOM frill.necked.lizard there see.NPST", "r262_1pl_incl_target_there_see_binanjal", ["ngana", "binanjal", "yinyay", "nyajil"], EVIDENCE["binanjal"]),
    row(44, "We see the black snake there.", "Ngana bindimu yinyay nyajil.", "ngana bindimu yinyay nyajil | 1pl.INC.NOM black.snake there see.NPST", "r262_1pl_incl_target_there_see_bindimu", ["ngana", "bindimu", "yinyay", "nyajil"], EVIDENCE["bindimu"]),
    row(45, "We see the tree snake there.", "Ngana bubal yinyay nyajil.", "ngana bubal yinyay nyajil | 1pl.INC.NOM tree.snake there see.NPST", "r262_1pl_incl_target_there_see_bubal", ["ngana", "bubal", "yinyay", "nyajil"], EVIDENCE["bubal"]),
    row(46, "We see the whip snake there.", "Ngana jijirrbay yinyay nyajil.", "ngana jijirrbay yinyay nyajil | 1pl.INC.NOM whip.snake there see.NPST", "r262_1pl_incl_target_there_see_jijirrbay", ["ngana", "jijirrbay", "yinyay", "nyajil"], EVIDENCE["jijirrbay"]),
    row(47, "We see the rock python there.", "Ngana kabul yinyay nyajil.", "ngana kabul yinyay nyajil | 1pl.INC.NOM rock.python there see.NPST", "r262_1pl_incl_target_there_see_kabul", ["ngana", "kabul", "yinyay", "nyajil"], EVIDENCE["kabul"]),
    row(48, "We see the scrub goanna there.", "Ngana kalajarr yinyay nyajil.", "ngana kalajarr yinyay nyajil | 1pl.INC.NOM scrub.goanna there see.NPST", "r262_1pl_incl_target_there_see_kalajarr", ["ngana", "kalajarr", "yinyay", "nyajil"], EVIDENCE["kalajarr"]),
    row(49, "We see the death adder there.", "Ngana kundurr yinyay nyajil.", "ngana kundurr yinyay nyajil | 1pl.INC.NOM death.adder there see.NPST", "r262_1pl_incl_target_there_see_kundurr", ["ngana", "kundurr", "yinyay", "nyajil"], EVIDENCE["kundurr"]),
    row(50, "We see the frog there.", "Ngana yuday yinyay nyajil.", "ngana yuday yinyay nyajil | 1pl.INC.NOM frog there see.NPST", "r262_1pl_incl_target_there_see_yuday", ["ngana", "yuday", "yinyay", "nyajil"], EVIDENCE["yuday"]),
]


def scan_static() -> list[str]:
    issues: list[str] = []
    if len(ROWS) != 50:
        issues.append(f"{LABEL}: expected 50 rows, found {len(ROWS)}")
    seen_ku: set[str] = set()
    for expected, row_data in enumerate(ROWS, start=1):
        seq, english, kuku, analysis, frame, _tier, words_used, loans_used, evidence, confidence = row_data
        label = f"{LABEL}.{seq:02d}"
        low = kuku.lower()
        english_low = english.lower()
        words = json.loads(words_used)
        if seq != expected:
            issues.append(f"{label}: sequence mismatch; expected {expected}")
        if not english[:1].isupper() or english[-1:] not in ".!?":
            issues.append(f"{label}: English punctuation/capitalization failure")
        if " | " not in analysis:
            issues.append(f"{label}: analysis missing gloss separator")
        if not frame.startswith("r262_"):
            issues.append(f"{label}: Rule 262 frame must start with r262_")
        if low in seen_ku:
            issues.append(f"{label}: duplicate Kuku surface within batch")
        seen_ku.add(low)
        if json.loads(loans_used):
            issues.append(f"{label}: no loans are admitted in Rule 262")
        for denied in DENY_KUKU:
            if has_token(low, denied):
                issues.append(f"{label}: denied carry-forward token {denied!r}")
        targets = [head for head in TARGET_HEADS if has_token(low, head)]
        if len(targets) != 1:
            issues.append(f"{label}: expected exactly one Rule 262 target reptile/amphibian noun, found {targets}")
        for head in targets:
            selected = TARGET_HEADS[head]
            dotted = selected.replace("-", ".").replace(" ", ".")
            if head not in words:
                issues.append(f"{label}: target head {head} missing from words_used")
            if selected not in english_low:
                issues.append(f"{label}: English must include selected sense {selected!r}")
            if selected not in analysis and dotted not in analysis:
                issues.append(f"{label}: analysis must gloss {head} as {selected}")
            if has_target_morphology(low, head):
                issues.append(f"{label}: target head {head} has forbidden morphology")
        for support in SUPPORT:
            if has_token(low, support) and support not in words:
                issues.append(f"{label}: support {support} missing from words_used")
        pronouns = [pronoun for pronoun in PRONOUN_SUPPORT if has_token(low, pronoun)]
        if len(pronouns) != 1:
            issues.append(f"{label}: rows require exactly one bare nominative non-singular pronoun, found {pronouns}")
        if 1 <= seq <= 10 and (not low.startswith("ngali ") or not low.endswith(" yinyay nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 1-10 require Ngali TARGET yinyay nyajil")
        if 11 <= seq <= 20 and (not low.startswith("ngaliny ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 11-20 require Ngaliny TARGET yaluy nyajil")
        if 21 <= seq <= 30 and (not low.startswith("yubal ") or not low.endswith(" yinyay nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 21-30 require Yubal TARGET yinyay nyajil")
        if 31 <= seq <= 40 and (not low.startswith("nganjin ") or not low.endswith(" yaluy nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 31-40 require Nganjin TARGET yaluy nyajil")
        if 41 <= seq <= 50 and (not low.startswith("ngana ") or not low.endswith(" yinyay nyajil.") or len(low.split()) != 4):
            issues.append(f"{label}: rows 41-50 require Ngana TARGET yinyay nyajil")
        if any(english_has_denied(english_low, bad) for bad in DENY_ENGLISH):
            issues.append(f"{label}: denied reptile/amphibian behavior/use/habitat/story/body-part/source-prose field in English")
        if not evidence or not confidence:
            issues.append(f"{label}: missing evidence/confidence")
    return issues


def main() -> int:
    issues = scan_static()
    if issues:
        print("pre-bank scan failed:")
        for issue in issues:
            print(f"  - {issue}")
        return 1

    db = sqlite3.connect(DB)
    db.execute("PRAGMA foreign_keys = ON")
    db.execute("BEGIN")
    ensure_schema(db)
    existing = db.execute("SELECT id FROM batches WHERE label=?", (LABEL,)).fetchone()
    if existing:
        batch_id = existing[0]
        accepted = db.execute(
            "SELECT COUNT(*) FROM sentences WHERE batch_id=? AND status IN ('accepted','revised')",
            (batch_id,),
        ).fetchone()[0]
        if accepted:
            raise SystemExit(f"{LABEL} already has accepted/revised rows; refusing to overwrite")
        db.execute("DELETE FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)", (batch_id,))
        db.execute("DELETE FROM lessons WHERE batch_id=?", (batch_id,))
        db.execute("DELETE FROM sentences WHERE batch_id=?", (batch_id,))
        db.execute("UPDATE batches SET notes=?, created_at=? WHERE id=?", ("rebanked under_review", NOW, batch_id))
    else:
        db.execute(
            "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
            (LABEL, "Rule 262 draft", "operator-guide-2026-07-09", "draft under review", NOW),
        )
        batch_id = db.execute("SELECT id FROM batches WHERE label=?", (LABEL,)).fetchone()[0]

    collisions: list[str] = []
    for seq, _english, kuku, *_rest in ROWS:
        found = 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 IN ('accepted','revised','under_review')
            """,
            (kuku,),
        ).fetchall()
        if found:
            collisions.append(f"{seq}: {kuku} -> {found}")
    if collisions:
        raise SystemExit("collision scan failed:\n" + "\n".join(collisions))

    db.executemany(
        """
        INSERT INTO sentences(
          batch_id, seq, english, kuku, analysis, frame, tier, words_used,
          loans_used, evidence, status, confidence, created_at
        )
        VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)
        """,
        [
            (
                batch_id,
                seq,
                english,
                kuku,
                analysis,
                frame,
                tier,
                words_used,
                loans_used,
                evidence,
                "under_review",
                confidence,
                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="Rule 262 source pass checked dictionary lines for bajuy lizard, bilngkumu crocodile, binanjal frill necked lizard, bindimu black snake, bubal tree snake, jijirrbay whip snake, kabul rock python, kalajarr scrub goanna, kundurr death adder, and yuday frog; Patz grammar lines 2577-2603 for bare nominative ngali, ngaliny, yubal, nganjin, and ngana; lines 2682-2684 for inclusive/exclusive and second-person non-singular discussion; lines 2838-2845 for yaluy/yinyay; and lines 3043-3049 for nyaji-l.",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="planning",
        event_type="debt-sweep-scope",
        actor="claude-main",
        detail="Selected Rule 262 reptile/amphibian non-singular pronoun perception sweep after Rule 261: same ten checked Rule 252 reptile/amphibian labels in zero-collision nominative-pronoun perception bands using ngali, ngaliny, yubal, nganjin, and ngana. All reptile behavior/use/habitat/story/body-part/source-prose, target-case, pronoun-case, demonstrative-case, and perception-compound semantics remain closed.",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="preflight",
        event_type="coverage-audit",
        actor="claude-main",
        detail="Pre-batch token-aware target coverage among accepted/revised rows after Rule 261: bajuy 23, bilngkumu 69, binanjal 19, bindimu 20, bubal 17, jijirrbay 16, kabul 22, kalajarr 19, kundurr 18, and yuday 21. Support coverage: ngali 179, ngaliny 114, yubal 125, nganjin 131, ngana 879, yaluy 2403, yinyay 2646, nyajil 2917.",
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="preflight",
        event_type="duplicate-preflight",
        actor="claude-main",
        detail="Exact duplicate preflight over the final 50 Rule 262 Kuku surfaces returned zero accepted, revised, or under-review collisions before banking.",
        command="sqlite3 synthetic.db planned surface collision query",
        output_excerpt="0 rows",
        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 rows, one checked target per row, one bare nominative non-singular pronoun per row, correct yaluy/yinyay band, no loans, no denied Kuku tokens, no denied English behavior/use/habitat/story/body-part/source-prose fields, no target morphology, no support inflection.",
        command="python3 batch_scripts/bank_304.py scan_static",
        output_excerpt="static guard passed before insert",
        artifact_path="batch_scripts/bank_304.py",
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="bank",
        event_type="bank-success",
        actor="claude-main",
        detail="Banked 50 hand-authored Rule 262 reptile/amphibian non-singular pronoun perception rows as under_review.",
        command="python3 batch_scripts/bank_304.py",
        artifact_path="batch_scripts/bank_304.py",
        created_at=NOW,
    )
    db.commit()
    count = db.execute("SELECT COUNT(*) FROM sentences WHERE batch_id=?", (batch_id,)).fetchone()[0]
    print(f"banked {LABEL}: {count} rows under_review")
    return 0


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